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