1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics; 18 19 import android.annotation.ColorInt; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.Size; 23 import android.graphics.Canvas.VertexMode; 24 import android.text.GraphicsOperations; 25 import android.text.SpannableString; 26 import android.text.SpannedString; 27 import android.text.TextUtils; 28 import android.view.RecordingCanvas; 29 30 /** 31 * This class is a base class for Canvas's drawing operations. Any modifications here 32 * should be accompanied by a similar modification to {@link RecordingCanvas}. 33 * 34 * The purpose of this class is to minimize the cost of deciding between regular JNI 35 * and @FastNative JNI to just the virtual call that Canvas already has. 36 * 37 * @hide 38 */ 39 public abstract class BaseCanvas { 40 /** 41 * Should only be assigned in constructors (or setBitmap if software canvas), 42 * freed by NativeAllocation. 43 */ 44 protected long mNativeCanvasWrapper; 45 46 /** 47 * Used to determine when compatibility scaling is in effect. 48 */ 49 protected int mScreenDensity = Bitmap.DENSITY_NONE; 50 protected int mDensity = Bitmap.DENSITY_NONE; 51 private boolean mAllowHwBitmapsInSwMode = false; 52 throwIfCannotDraw(Bitmap bitmap)53 protected void throwIfCannotDraw(Bitmap bitmap) { 54 if (bitmap.isRecycled()) { 55 throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap); 56 } 57 if (!bitmap.isPremultiplied() && bitmap.getConfig() == Bitmap.Config.ARGB_8888 && 58 bitmap.hasAlpha()) { 59 throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap " 60 + bitmap); 61 } 62 throwIfHwBitmapInSwMode(bitmap); 63 } 64 checkRange(int length, int offset, int count)65 protected final static void checkRange(int length, int offset, int count) { 66 if ((offset | count) < 0 || offset + count > length) { 67 throw new ArrayIndexOutOfBoundsException(); 68 } 69 } 70 isHardwareAccelerated()71 public boolean isHardwareAccelerated() { 72 return false; 73 } 74 75 // --------------------------------------------------------------------------- 76 // Drawing methods 77 // These are also implemented in DisplayListCanvas so that we can 78 // selectively apply on them 79 // Everything below here is copy/pasted from Canvas.java 80 // The JNI registration is handled by android_view_Canvas.cpp 81 // --------------------------------------------------------------------------- 82 drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)83 public void drawArc(float left, float top, float right, float bottom, float startAngle, 84 float sweepAngle, boolean useCenter, @NonNull Paint paint) { 85 throwIfHasHwBitmapInSwMode(paint); 86 nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle, 87 useCenter, paint.getNativeInstance()); 88 } 89 drawArc(@onNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)90 public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, 91 @NonNull Paint paint) { 92 throwIfHasHwBitmapInSwMode(paint); 93 drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter, 94 paint); 95 } 96 drawARGB(int a, int r, int g, int b)97 public void drawARGB(int a, int r, int g, int b) { 98 drawColor(Color.argb(a, r, g, b)); 99 } 100 drawBitmap(@onNull Bitmap bitmap, float left, float top, @Nullable Paint paint)101 public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) { 102 throwIfCannotDraw(bitmap); 103 throwIfHasHwBitmapInSwMode(paint); 104 nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, 105 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, 106 bitmap.mDensity); 107 } 108 drawBitmap(@onNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)109 public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) { 110 throwIfHasHwBitmapInSwMode(paint); 111 nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(), 112 paint != null ? paint.getNativeInstance() : 0); 113 } 114 drawBitmap(@onNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint)115 public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, 116 @Nullable Paint paint) { 117 if (dst == null) { 118 throw new NullPointerException(); 119 } 120 throwIfCannotDraw(bitmap); 121 throwIfHasHwBitmapInSwMode(paint); 122 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 123 124 int left, top, right, bottom; 125 if (src == null) { 126 left = top = 0; 127 right = bitmap.getWidth(); 128 bottom = bitmap.getHeight(); 129 } else { 130 left = src.left; 131 right = src.right; 132 top = src.top; 133 bottom = src.bottom; 134 } 135 136 nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom, 137 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, 138 bitmap.mDensity); 139 } 140 drawBitmap(@onNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint)141 public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, 142 @Nullable Paint paint) { 143 if (dst == null) { 144 throw new NullPointerException(); 145 } 146 throwIfCannotDraw(bitmap); 147 throwIfHasHwBitmapInSwMode(paint); 148 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 149 150 float left, top, right, bottom; 151 if (src == null) { 152 left = top = 0; 153 right = bitmap.getWidth(); 154 bottom = bitmap.getHeight(); 155 } else { 156 left = src.left; 157 right = src.right; 158 top = src.top; 159 bottom = src.bottom; 160 } 161 162 nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom, 163 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, 164 bitmap.mDensity); 165 } 166 167 @Deprecated drawBitmap(@onNull int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, @Nullable Paint paint)168 public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y, 169 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 170 // check for valid input 171 if (width < 0) { 172 throw new IllegalArgumentException("width must be >= 0"); 173 } 174 if (height < 0) { 175 throw new IllegalArgumentException("height must be >= 0"); 176 } 177 if (Math.abs(stride) < width) { 178 throw new IllegalArgumentException("abs(stride) must be >= width"); 179 } 180 int lastScanline = offset + (height - 1) * stride; 181 int length = colors.length; 182 if (offset < 0 || (offset + width > length) || lastScanline < 0 183 || (lastScanline + width > length)) { 184 throw new ArrayIndexOutOfBoundsException(); 185 } 186 throwIfHasHwBitmapInSwMode(paint); 187 // quick escape if there's nothing to draw 188 if (width == 0 || height == 0) { 189 return; 190 } 191 // punch down to native for the actual draw 192 nDrawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha, 193 paint != null ? paint.getNativeInstance() : 0); 194 } 195 196 @Deprecated drawBitmap(@onNull int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, @Nullable Paint paint)197 public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y, 198 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 199 // call through to the common float version 200 drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, 201 hasAlpha, paint); 202 } 203 drawBitmapMesh(@onNull Bitmap bitmap, int meshWidth, int meshHeight, @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, @Nullable Paint paint)204 public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight, 205 @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, 206 @Nullable Paint paint) { 207 if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) { 208 throw new ArrayIndexOutOfBoundsException(); 209 } 210 throwIfHasHwBitmapInSwMode(paint); 211 if (meshWidth == 0 || meshHeight == 0) { 212 return; 213 } 214 int count = (meshWidth + 1) * (meshHeight + 1); 215 // we mul by 2 since we need two floats per vertex 216 checkRange(verts.length, vertOffset, count * 2); 217 if (colors != null) { 218 // no mul by 2, since we need only 1 color per vertex 219 checkRange(colors.length, colorOffset, count); 220 } 221 nDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight, 222 verts, vertOffset, colors, colorOffset, 223 paint != null ? paint.getNativeInstance() : 0); 224 } 225 drawCircle(float cx, float cy, float radius, @NonNull Paint paint)226 public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) { 227 throwIfHasHwBitmapInSwMode(paint); 228 nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance()); 229 } 230 drawColor(@olorInt int color)231 public void drawColor(@ColorInt int color) { 232 nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); 233 } 234 drawColor(@olorInt int color, @NonNull PorterDuff.Mode mode)235 public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { 236 nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt); 237 } 238 drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint)239 public void drawLine(float startX, float startY, float stopX, float stopY, 240 @NonNull Paint paint) { 241 throwIfHasHwBitmapInSwMode(paint); 242 nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); 243 } 244 drawLines(@izemultiple = 4) @onNull float[] pts, int offset, int count, @NonNull Paint paint)245 public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count, 246 @NonNull Paint paint) { 247 throwIfHasHwBitmapInSwMode(paint); 248 nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); 249 } 250 drawLines(@izemultiple = 4) @onNull float[] pts, @NonNull Paint paint)251 public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) { 252 throwIfHasHwBitmapInSwMode(paint); 253 drawLines(pts, 0, pts.length, paint); 254 } 255 drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)256 public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) { 257 throwIfHasHwBitmapInSwMode(paint); 258 nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); 259 } 260 drawOval(@onNull RectF oval, @NonNull Paint paint)261 public void drawOval(@NonNull RectF oval, @NonNull Paint paint) { 262 if (oval == null) { 263 throw new NullPointerException(); 264 } 265 throwIfHasHwBitmapInSwMode(paint); 266 drawOval(oval.left, oval.top, oval.right, oval.bottom, paint); 267 } 268 drawPaint(@onNull Paint paint)269 public void drawPaint(@NonNull Paint paint) { 270 nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance()); 271 } 272 drawPatch(@onNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint)273 public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) { 274 Bitmap bitmap = patch.getBitmap(); 275 throwIfCannotDraw(bitmap); 276 throwIfHasHwBitmapInSwMode(paint); 277 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 278 nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk, 279 dst.left, dst.top, dst.right, dst.bottom, nativePaint, 280 mDensity, patch.getDensity()); 281 } 282 drawPatch(@onNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint)283 public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) { 284 Bitmap bitmap = patch.getBitmap(); 285 throwIfCannotDraw(bitmap); 286 throwIfHasHwBitmapInSwMode(paint); 287 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 288 nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk, 289 dst.left, dst.top, dst.right, dst.bottom, nativePaint, 290 mDensity, patch.getDensity()); 291 } 292 drawPath(@onNull Path path, @NonNull Paint paint)293 public void drawPath(@NonNull Path path, @NonNull Paint paint) { 294 throwIfHasHwBitmapInSwMode(paint); 295 if (path.isSimplePath && path.rects != null) { 296 nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance()); 297 } else { 298 nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance()); 299 } 300 } 301 drawPoint(float x, float y, @NonNull Paint paint)302 public void drawPoint(float x, float y, @NonNull Paint paint) { 303 throwIfHasHwBitmapInSwMode(paint); 304 nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance()); 305 } 306 drawPoints(@izemultiple = 2) float[] pts, int offset, int count, @NonNull Paint paint)307 public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count, 308 @NonNull Paint paint) { 309 throwIfHasHwBitmapInSwMode(paint); 310 nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); 311 } 312 drawPoints(@izemultiple = 2) @onNull float[] pts, @NonNull Paint paint)313 public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) { 314 throwIfHasHwBitmapInSwMode(paint); 315 drawPoints(pts, 0, pts.length, paint); 316 } 317 318 @Deprecated drawPosText(@onNull char[] text, int index, int count, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)319 public void drawPosText(@NonNull char[] text, int index, int count, 320 @NonNull @Size(multiple = 2) float[] pos, 321 @NonNull Paint paint) { 322 if (index < 0 || index + count > text.length || count * 2 > pos.length) { 323 throw new IndexOutOfBoundsException(); 324 } 325 throwIfHasHwBitmapInSwMode(paint); 326 for (int i = 0; i < count; i++) { 327 drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint); 328 } 329 } 330 331 @Deprecated drawPosText(@onNull String text, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)332 public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos, 333 @NonNull Paint paint) { 334 throwIfHasHwBitmapInSwMode(paint); 335 drawPosText(text.toCharArray(), 0, text.length(), pos, paint); 336 } 337 drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)338 public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) { 339 throwIfHasHwBitmapInSwMode(paint); 340 nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); 341 } 342 drawRect(@onNull Rect r, @NonNull Paint paint)343 public void drawRect(@NonNull Rect r, @NonNull Paint paint) { 344 throwIfHasHwBitmapInSwMode(paint); 345 drawRect(r.left, r.top, r.right, r.bottom, paint); 346 } 347 drawRect(@onNull RectF rect, @NonNull Paint paint)348 public void drawRect(@NonNull RectF rect, @NonNull Paint paint) { 349 throwIfHasHwBitmapInSwMode(paint); 350 nDrawRect(mNativeCanvasWrapper, 351 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance()); 352 } 353 drawRGB(int r, int g, int b)354 public void drawRGB(int r, int g, int b) { 355 drawColor(Color.rgb(r, g, b)); 356 } 357 drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)358 public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, 359 @NonNull Paint paint) { 360 throwIfHasHwBitmapInSwMode(paint); 361 nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, 362 paint.getNativeInstance()); 363 } 364 drawRoundRect(@onNull RectF rect, float rx, float ry, @NonNull Paint paint)365 public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { 366 throwIfHasHwBitmapInSwMode(paint); 367 drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint); 368 } 369 drawText(@onNull char[] text, int index, int count, float x, float y, @NonNull Paint paint)370 public void drawText(@NonNull char[] text, int index, int count, float x, float y, 371 @NonNull Paint paint) { 372 if ((index | count | (index + count) | 373 (text.length - index - count)) < 0) { 374 throw new IndexOutOfBoundsException(); 375 } 376 throwIfHasHwBitmapInSwMode(paint); 377 nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags, 378 paint.getNativeInstance(), paint.mNativeTypeface); 379 } 380 drawText(@onNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint)381 public void drawText(@NonNull CharSequence text, int start, int end, float x, float y, 382 @NonNull Paint paint) { 383 if ((start | end | (end - start) | (text.length() - end)) < 0) { 384 throw new IndexOutOfBoundsException(); 385 } 386 throwIfHasHwBitmapInSwMode(paint); 387 if (text instanceof String || text instanceof SpannedString || 388 text instanceof SpannableString) { 389 nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y, 390 paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); 391 } else if (text instanceof GraphicsOperations) { 392 ((GraphicsOperations) text).drawText(this, start, end, x, y, 393 paint); 394 } else { 395 char[] buf = TemporaryBuffer.obtain(end - start); 396 TextUtils.getChars(text, start, end, buf, 0); 397 nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y, 398 paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); 399 TemporaryBuffer.recycle(buf); 400 } 401 } 402 drawText(@onNull String text, float x, float y, @NonNull Paint paint)403 public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { 404 throwIfHasHwBitmapInSwMode(paint); 405 nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags, 406 paint.getNativeInstance(), paint.mNativeTypeface); 407 } 408 drawText(@onNull String text, int start, int end, float x, float y, @NonNull Paint paint)409 public void drawText(@NonNull String text, int start, int end, float x, float y, 410 @NonNull Paint paint) { 411 if ((start | end | (end - start) | (text.length() - end)) < 0) { 412 throw new IndexOutOfBoundsException(); 413 } 414 throwIfHasHwBitmapInSwMode(paint); 415 nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags, 416 paint.getNativeInstance(), paint.mNativeTypeface); 417 } 418 drawTextOnPath(@onNull char[] text, int index, int count, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)419 public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path, 420 float hOffset, float vOffset, @NonNull Paint paint) { 421 if (index < 0 || index + count > text.length) { 422 throw new ArrayIndexOutOfBoundsException(); 423 } 424 throwIfHasHwBitmapInSwMode(paint); 425 nDrawTextOnPath(mNativeCanvasWrapper, text, index, count, 426 path.readOnlyNI(), hOffset, vOffset, 427 paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); 428 } 429 drawTextOnPath(@onNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)430 public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, 431 float vOffset, @NonNull Paint paint) { 432 if (text.length() > 0) { 433 throwIfHasHwBitmapInSwMode(paint); 434 nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset, 435 paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface); 436 } 437 } 438 drawTextRun(@onNull char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint)439 public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, 440 int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) { 441 442 if (text == null) { 443 throw new NullPointerException("text is null"); 444 } 445 if (paint == null) { 446 throw new NullPointerException("paint is null"); 447 } 448 if ((index | count | contextIndex | contextCount | index - contextIndex 449 | (contextIndex + contextCount) - (index + count) 450 | text.length - (contextIndex + contextCount)) < 0) { 451 throw new IndexOutOfBoundsException(); 452 } 453 454 throwIfHasHwBitmapInSwMode(paint); 455 nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount, 456 x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface); 457 } 458 drawTextRun(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)459 public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, 460 int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { 461 462 if (text == null) { 463 throw new NullPointerException("text is null"); 464 } 465 if (paint == null) { 466 throw new NullPointerException("paint is null"); 467 } 468 if ((start | end | contextStart | contextEnd | start - contextStart | end - start 469 | contextEnd - end | text.length() - contextEnd) < 0) { 470 throw new IndexOutOfBoundsException(); 471 } 472 473 throwIfHasHwBitmapInSwMode(paint); 474 if (text instanceof String || text instanceof SpannedString || 475 text instanceof SpannableString) { 476 nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart, 477 contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface); 478 } else if (text instanceof GraphicsOperations) { 479 ((GraphicsOperations) text).drawTextRun(this, start, end, 480 contextStart, contextEnd, x, y, isRtl, paint); 481 } else { 482 int contextLen = contextEnd - contextStart; 483 int len = end - start; 484 char[] buf = TemporaryBuffer.obtain(contextLen); 485 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 486 nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, 487 0, contextLen, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface); 488 TemporaryBuffer.recycle(buf); 489 } 490 } 491 drawVertices(@onNull VertexMode mode, int vertexCount, @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, @NonNull Paint paint)492 public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts, 493 int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, 494 int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, 495 @NonNull Paint paint) { 496 checkRange(verts.length, vertOffset, vertexCount); 497 if (isHardwareAccelerated()) { 498 return; 499 } 500 if (texs != null) { 501 checkRange(texs.length, texOffset, vertexCount); 502 } 503 if (colors != null) { 504 checkRange(colors.length, colorOffset, vertexCount / 2); 505 } 506 if (indices != null) { 507 checkRange(indices.length, indexOffset, indexCount); 508 } 509 throwIfHasHwBitmapInSwMode(paint); 510 nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts, 511 vertOffset, texs, texOffset, colors, colorOffset, 512 indices, indexOffset, indexCount, paint.getNativeInstance()); 513 } 514 515 /** 516 * @hide 517 */ setHwBitmapsInSwModeEnabled(boolean enabled)518 public void setHwBitmapsInSwModeEnabled(boolean enabled) { 519 mAllowHwBitmapsInSwMode = enabled; 520 } 521 522 /** 523 * @hide 524 */ isHwBitmapsInSwModeEnabled()525 public boolean isHwBitmapsInSwModeEnabled() { 526 return mAllowHwBitmapsInSwMode; 527 } 528 throwIfHwBitmapInSwMode(Bitmap bitmap)529 private void throwIfHwBitmapInSwMode(Bitmap bitmap) { 530 if (!mAllowHwBitmapsInSwMode && !isHardwareAccelerated() 531 && bitmap.getConfig() == Bitmap.Config.HARDWARE) { 532 throw new IllegalStateException("Software rendering doesn't support hardware bitmaps"); 533 } 534 } 535 throwIfHasHwBitmapInSwMode(Paint p)536 private void throwIfHasHwBitmapInSwMode(Paint p) { 537 if (isHardwareAccelerated() || p == null) { 538 return; 539 } 540 throwIfHasHwBitmapInSwMode(p.getShader()); 541 } 542 throwIfHasHwBitmapInSwMode(Shader shader)543 private void throwIfHasHwBitmapInSwMode(Shader shader) { 544 if (shader == null) { 545 return; 546 } 547 if (shader instanceof BitmapShader) { 548 throwIfHwBitmapInSwMode(((BitmapShader) shader).mBitmap); 549 } 550 if (shader instanceof ComposeShader) { 551 throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderA); 552 throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderB); 553 } 554 } 555 nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)556 private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top, 557 long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity); 558 nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)559 private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft, 560 float srcTop, 561 float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, 562 float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity); 563 nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)564 private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, 565 float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero); 566 nDrawColor(long nativeCanvas, int color, int mode)567 private static native void nDrawColor(long nativeCanvas, int color, int mode); 568 nDrawPaint(long nativeCanvas, long nativePaint)569 private static native void nDrawPaint(long nativeCanvas, long nativePaint); 570 nDrawPoint(long canvasHandle, float x, float y, long paintHandle)571 private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle); 572 nDrawPoints(long canvasHandle, float[] pts, int offset, int count, long paintHandle)573 private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count, 574 long paintHandle); 575 nDrawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long nativePaint)576 private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX, 577 float stopY, long nativePaint); 578 nDrawLines(long canvasHandle, float[] pts, int offset, int count, long paintHandle)579 private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count, 580 long paintHandle); 581 nDrawRect(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)582 private static native void nDrawRect(long nativeCanvas, float left, float top, float right, 583 float bottom, long nativePaint); 584 nDrawOval(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)585 private static native void nDrawOval(long nativeCanvas, float left, float top, float right, 586 float bottom, long nativePaint); 587 nDrawCircle(long nativeCanvas, float cx, float cy, float radius, long nativePaint)588 private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius, 589 long nativePaint); 590 nDrawArc(long nativeCanvas, float left, float top, float right, float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint)591 private static native void nDrawArc(long nativeCanvas, float left, float top, float right, 592 float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint); 593 nDrawRoundRect(long nativeCanvas, float left, float top, float right, float bottom, float rx, float ry, long nativePaint)594 private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right, 595 float bottom, float rx, float ry, long nativePaint); 596 nDrawPath(long nativeCanvas, long nativePath, long nativePaint)597 private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint); 598 nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint)599 private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint); 600 nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)601 private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, 602 float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, 603 int screenDensity, int bitmapDensity); 604 nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap, long nativeMatrix, long nativePaint)605 private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap, 606 long nativeMatrix, long nativePaint); 607 nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nativePaint)608 private static native void nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth, 609 int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, 610 long nativePaint); 611 nDrawVertices(long nativeCanvas, int mode, int n, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, long nativePaint)612 private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts, 613 int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, 614 short[] indices, int indexOffset, int indexCount, long nativePaint); 615 nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint, long nativeTypeface)616 private static native void nDrawText(long nativeCanvas, char[] text, int index, int count, 617 float x, float y, int flags, long nativePaint, long nativeTypeface); 618 nDrawText(long nativeCanvas, String text, int start, int end, float x, float y, int flags, long nativePaint, long nativeTypeface)619 private static native void nDrawText(long nativeCanvas, String text, int start, int end, 620 float x, float y, int flags, long nativePaint, long nativeTypeface); 621 nDrawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface)622 private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end, 623 int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, 624 long nativeTypeface); 625 nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface)626 private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, 627 int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, 628 long nativeTypeface); 629 nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint, long nativeTypeface)630 private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, 631 long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint, 632 long nativeTypeface); 633 nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint, long nativeTypeface)634 private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, 635 float hOffset, float vOffset, int flags, long nativePaint, long nativeTypeface); 636 } 637