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.ColorLong; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.Size; 25 import android.graphics.fonts.Font; 26 import android.graphics.text.MeasuredText; 27 import android.text.GraphicsOperations; 28 import android.text.MeasuredParagraph; 29 import android.text.PrecomputedText; 30 import android.text.SpannableString; 31 import android.text.SpannedString; 32 import android.text.TextUtils; 33 34 import com.android.internal.util.Preconditions; 35 36 import dalvik.annotation.optimization.FastNative; 37 38 import java.util.Objects; 39 40 /** 41 * This class is a base class for canvases that defer drawing operations, so all 42 * the draw operations can be marked @FastNative. It contains a re-implementation of 43 * all the methods in {@link BaseCanvas}. 44 * 45 * @hide 46 */ 47 @android.ravenwood.annotation.RavenwoodKeepWholeClass 48 public class BaseRecordingCanvas extends Canvas { 49 BaseRecordingCanvas(long nativeCanvas)50 public BaseRecordingCanvas(long nativeCanvas) { 51 super(nativeCanvas); 52 } 53 54 @Override drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)55 public final void drawArc(float left, float top, float right, float bottom, float startAngle, 56 float sweepAngle, boolean useCenter, @NonNull Paint paint) { 57 nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle, 58 useCenter, paint.getNativeInstance()); 59 } 60 61 @Override drawArc(@onNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)62 public final void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, 63 boolean useCenter, @NonNull Paint paint) { 64 drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter, 65 paint); 66 } 67 68 @Override drawARGB(int a, int r, int g, int b)69 public final void drawARGB(int a, int r, int g, int b) { 70 drawColor(Color.argb(a, r, g, b)); 71 } 72 73 @Override drawBitmap(@onNull Bitmap bitmap, float left, float top, @Nullable Paint paint)74 public final void drawBitmap(@NonNull Bitmap bitmap, float left, float top, 75 @Nullable Paint paint) { 76 throwIfCannotDraw(bitmap); 77 nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top, 78 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, 79 bitmap.mDensity); 80 } 81 82 @Override drawBitmap(@onNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)83 public final void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, 84 @Nullable Paint paint) { 85 nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getNativeInstance(), matrix.ni(), 86 paint != null ? paint.getNativeInstance() : 0); 87 } 88 89 @Override drawBitmap(@onNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint)90 public final void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, 91 @Nullable Paint paint) { 92 if (dst == null) { 93 throw new NullPointerException(); 94 } 95 throwIfCannotDraw(bitmap); 96 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 97 98 int left, top, right, bottom; 99 if (src == null) { 100 left = top = 0; 101 right = bitmap.getWidth(); 102 bottom = bitmap.getHeight(); 103 } else { 104 left = src.left; 105 right = src.right; 106 top = src.top; 107 bottom = src.bottom; 108 } 109 110 nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top, right, bottom, 111 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, 112 bitmap.mDensity); 113 } 114 115 @Override drawBitmap(@onNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint)116 public final void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, 117 @Nullable Paint paint) { 118 if (dst == null) { 119 throw new NullPointerException(); 120 } 121 throwIfCannotDraw(bitmap); 122 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 123 124 float 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.getNativeInstance(), left, top, right, bottom, 137 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, 138 bitmap.mDensity); 139 } 140 141 /** @deprecated checkstyle */ 142 @Override 143 @Deprecated drawBitmap(@onNull int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, @Nullable Paint paint)144 public final void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y, 145 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 146 // check for valid input 147 if (width < 0) { 148 throw new IllegalArgumentException("width must be >= 0"); 149 } 150 if (height < 0) { 151 throw new IllegalArgumentException("height must be >= 0"); 152 } 153 if (Math.abs(stride) < width) { 154 throw new IllegalArgumentException("abs(stride) must be >= width"); 155 } 156 int lastScanline = offset + (height - 1) * stride; 157 int length = colors.length; 158 if (offset < 0 || (offset + width > length) || lastScanline < 0 159 || (lastScanline + width > length)) { 160 throw new ArrayIndexOutOfBoundsException(); 161 } 162 // quick escape if there's nothing to draw 163 if (width == 0 || height == 0) { 164 return; 165 } 166 // punch down to native for the actual draw 167 nDrawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha, 168 paint != null ? paint.getNativeInstance() : 0); 169 } 170 171 /** @deprecated checkstyle */ 172 @Override 173 @Deprecated drawBitmap(@onNull int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, @Nullable Paint paint)174 public final void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y, 175 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 176 // call through to the common float version 177 drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, 178 hasAlpha, paint); 179 } 180 181 @Override drawBitmapMesh(@onNull Bitmap bitmap, int meshWidth, int meshHeight, @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, @Nullable Paint paint)182 public final void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight, 183 @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, 184 @Nullable Paint paint) { 185 if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) { 186 throw new ArrayIndexOutOfBoundsException(); 187 } 188 if (meshWidth == 0 || meshHeight == 0) { 189 return; 190 } 191 int count = (meshWidth + 1) * (meshHeight + 1); 192 // we mul by 2 since we need two floats per vertex 193 checkRange(verts.length, vertOffset, count * 2); 194 if (colors != null) { 195 // no mul by 2, since we need only 1 color per vertex 196 checkRange(colors.length, colorOffset, count); 197 } 198 nDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getNativeInstance(), meshWidth, meshHeight, 199 verts, vertOffset, colors, colorOffset, 200 paint != null ? paint.getNativeInstance() : 0); 201 } 202 203 @Override drawCircle(float cx, float cy, float radius, @NonNull Paint paint)204 public final void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) { 205 nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance()); 206 } 207 208 @Override drawColor(@olorInt int color)209 public final void drawColor(@ColorInt int color) { 210 nDrawColor(mNativeCanvasWrapper, color, BlendMode.SRC_OVER.getXfermode().porterDuffMode); 211 } 212 213 @Override drawColor(@olorInt int color, @NonNull PorterDuff.Mode mode)214 public final void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { 215 nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt); 216 } 217 218 @Override drawColor(@olorInt int color, @NonNull BlendMode mode)219 public final void drawColor(@ColorInt int color, @NonNull BlendMode mode) { 220 nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode); 221 } 222 223 @Override drawColor(@olorLong long color, @NonNull BlendMode mode)224 public final void drawColor(@ColorLong long color, @NonNull BlendMode mode) { 225 ColorSpace cs = Color.colorSpace(color); 226 nDrawColor(mNativeCanvasWrapper, cs.getNativeInstance(), color, 227 mode.getXfermode().porterDuffMode); 228 } 229 230 @Override drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint)231 public final void drawLine(float startX, float startY, float stopX, float stopY, 232 @NonNull Paint paint) { 233 nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); 234 } 235 236 @Override drawLines(@izemultiple = 4) @onNull float[] pts, int offset, int count, @NonNull Paint paint)237 public final void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count, 238 @NonNull Paint paint) { 239 nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); 240 } 241 242 @Override drawLines(@izemultiple = 4) @onNull float[] pts, @NonNull Paint paint)243 public final void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) { 244 drawLines(pts, 0, pts.length, paint); 245 } 246 247 @Override drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)248 public final void drawOval(float left, float top, float right, float bottom, 249 @NonNull Paint paint) { 250 nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); 251 } 252 253 @Override drawOval(@onNull RectF oval, @NonNull Paint paint)254 public final void drawOval(@NonNull RectF oval, @NonNull Paint paint) { 255 if (oval == null) { 256 throw new NullPointerException(); 257 } 258 drawOval(oval.left, oval.top, oval.right, oval.bottom, paint); 259 } 260 261 @Override drawPaint(@onNull Paint paint)262 public final void drawPaint(@NonNull Paint paint) { 263 nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance()); 264 } 265 266 @Override drawPatch(@onNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint)267 public final void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, 268 @Nullable Paint paint) { 269 Bitmap bitmap = patch.getBitmap(); 270 throwIfCannotDraw(bitmap); 271 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 272 nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk, 273 dst.left, dst.top, dst.right, dst.bottom, nativePaint, 274 mDensity, patch.getDensity()); 275 } 276 277 @Override drawPatch(@onNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint)278 public final void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, 279 @Nullable Paint paint) { 280 Bitmap bitmap = patch.getBitmap(); 281 throwIfCannotDraw(bitmap); 282 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 283 nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk, 284 dst.left, dst.top, dst.right, dst.bottom, nativePaint, 285 mDensity, patch.getDensity()); 286 } 287 288 @Override drawPath(@onNull Path path, @NonNull Paint paint)289 public final void drawPath(@NonNull Path path, @NonNull Paint paint) { 290 nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance()); 291 } 292 293 @Override drawRegion(@onNull Region region, @NonNull Paint paint)294 public void drawRegion(@NonNull Region region, @NonNull Paint paint) { 295 nDrawRegion(mNativeCanvasWrapper, region.mNativeRegion, paint.getNativeInstance()); 296 } 297 298 @Override drawPicture(@onNull Picture picture)299 public final void drawPicture(@NonNull Picture picture) { 300 picture.endRecording(); 301 int restoreCount = save(); 302 picture.draw(this); 303 restoreToCount(restoreCount); 304 } 305 306 @Override drawPicture(@onNull Picture picture, @NonNull Rect dst)307 public final void drawPicture(@NonNull Picture picture, @NonNull Rect dst) { 308 save(); 309 translate(dst.left, dst.top); 310 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 311 scale((float) dst.width() / picture.getWidth(), 312 (float) dst.height() / picture.getHeight()); 313 } 314 drawPicture(picture); 315 restore(); 316 } 317 318 @Override drawPicture(@onNull Picture picture, @NonNull RectF dst)319 public final void drawPicture(@NonNull Picture picture, @NonNull RectF dst) { 320 save(); 321 translate(dst.left, dst.top); 322 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 323 scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); 324 } 325 drawPicture(picture); 326 restore(); 327 } 328 329 @Override drawPoint(float x, float y, @NonNull Paint paint)330 public final void drawPoint(float x, float y, @NonNull Paint paint) { 331 nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance()); 332 } 333 334 @Override drawPoints(@izemultiple = 2) float[] pts, int offset, int count, @NonNull Paint paint)335 public final void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count, 336 @NonNull Paint paint) { 337 nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); 338 } 339 340 @Override drawPoints(@izemultiple = 2) @onNull float[] pts, @NonNull Paint paint)341 public final void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) { 342 drawPoints(pts, 0, pts.length, paint); 343 } 344 345 /** @deprecated checkstyle */ 346 @Override 347 @Deprecated drawPosText(@onNull char[] text, int index, int count, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)348 public final void drawPosText(@NonNull char[] text, int index, int count, 349 @NonNull @Size(multiple = 2) float[] pos, 350 @NonNull Paint paint) { 351 if (index < 0 || index + count > text.length || count * 2 > pos.length) { 352 throw new IndexOutOfBoundsException(); 353 } 354 for (int i = 0; i < count; i++) { 355 drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint); 356 } 357 } 358 359 /** @deprecated checkstyle */ 360 @Override 361 @Deprecated drawPosText(@onNull String text, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)362 public final void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos, 363 @NonNull Paint paint) { 364 drawPosText(text.toCharArray(), 0, text.length(), pos, paint); 365 } 366 367 @Override drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)368 public final void drawRect(float left, float top, float right, float bottom, 369 @NonNull Paint paint) { 370 nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); 371 } 372 373 @Override drawRect(@onNull Rect r, @NonNull Paint paint)374 public final void drawRect(@NonNull Rect r, @NonNull Paint paint) { 375 drawRect(r.left, r.top, r.right, r.bottom, paint); 376 } 377 378 @Override drawRect(@onNull RectF rect, @NonNull Paint paint)379 public final void drawRect(@NonNull RectF rect, @NonNull Paint paint) { 380 nDrawRect(mNativeCanvasWrapper, 381 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance()); 382 } 383 384 @Override drawRGB(int r, int g, int b)385 public final void drawRGB(int r, int g, int b) { 386 drawColor(Color.rgb(r, g, b)); 387 } 388 389 @Override drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)390 public final void drawRoundRect(float left, float top, float right, float bottom, 391 float rx, float ry, @NonNull Paint paint) { 392 nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, 393 paint.getNativeInstance()); 394 } 395 396 @Override drawRoundRect(@onNull RectF rect, float rx, float ry, @NonNull Paint paint)397 public final void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { 398 drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint); 399 } 400 401 @Override drawDoubleRoundRect(@onNull RectF outer, float outerRx, float outerRy, @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint)402 public final void drawDoubleRoundRect(@NonNull RectF outer, float outerRx, float outerRy, 403 @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint) { 404 nDrawDoubleRoundRect(mNativeCanvasWrapper, 405 outer.left, outer.top, outer.right, outer.bottom, outerRx, outerRy, 406 inner.left, inner.top, inner.right, inner.bottom, innerRx, innerRy, 407 paint.getNativeInstance()); 408 } 409 410 @Override drawDoubleRoundRect(@onNull RectF outer, @NonNull float[] outerRadii, @NonNull RectF inner, @NonNull float[] innerRadii, @NonNull Paint paint)411 public final void drawDoubleRoundRect(@NonNull RectF outer, @NonNull float[] outerRadii, 412 @NonNull RectF inner, @NonNull float[] innerRadii, @NonNull Paint paint) { 413 nDrawDoubleRoundRect(mNativeCanvasWrapper, 414 outer.left, outer.top, outer.right, outer.bottom, outerRadii, 415 inner.left, inner.top, inner.right, inner.bottom, innerRadii, 416 paint.getNativeInstance()); 417 } 418 419 @Override drawGlyphs( @onNull int[] glyphIds, @IntRange(from = 0) int glyphIdOffset, @NonNull float[] positions, @IntRange(from = 0) int positionOffset, @IntRange(from = 0) int glyphCount, @NonNull Font font, @NonNull Paint paint)420 public void drawGlyphs( 421 @NonNull int[] glyphIds, 422 @IntRange(from = 0) int glyphIdOffset, 423 @NonNull float[] positions, 424 @IntRange(from = 0) int positionOffset, 425 @IntRange(from = 0) int glyphCount, 426 @NonNull Font font, 427 @NonNull Paint paint) { 428 Objects.requireNonNull(glyphIds, "glyphIds must not be null."); 429 Objects.requireNonNull(positions, "positions must not be null."); 430 Objects.requireNonNull(font, "font must not be null."); 431 Objects.requireNonNull(paint, "paint must not be null."); 432 Preconditions.checkArgumentNonnegative(glyphCount); 433 434 if (glyphIdOffset < 0 || glyphIdOffset + glyphCount > glyphIds.length) { 435 throw new IndexOutOfBoundsException( 436 "glyphIds must have at least " + (glyphIdOffset + glyphCount) + " of elements"); 437 } 438 if (positionOffset < 0 || positionOffset + glyphCount * 2 > positions.length) { 439 throw new IndexOutOfBoundsException( 440 "positions must have at least " + (positionOffset + glyphCount * 2) 441 + " of elements"); 442 } 443 nDrawGlyphs(mNativeCanvasWrapper, glyphIds, positions, glyphIdOffset, positionOffset, 444 glyphCount, font.getNativePtr(), paint.getNativeInstance()); 445 } 446 447 @Override drawText(@onNull char[] text, int index, int count, float x, float y, @NonNull Paint paint)448 public final void drawText(@NonNull char[] text, int index, int count, float x, float y, 449 @NonNull Paint paint) { 450 if ((index | count | (index + count) 451 | (text.length - index - count)) < 0) { 452 throw new IndexOutOfBoundsException(); 453 } 454 nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags, 455 paint.getNativeInstance()); 456 } 457 458 @Override drawText(@onNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint)459 public final void drawText(@NonNull CharSequence text, int start, int end, float x, float y, 460 @NonNull Paint paint) { 461 if ((start | end | (end - start) | (text.length() - end)) < 0) { 462 throw new IndexOutOfBoundsException(); 463 } 464 if (text instanceof String || text instanceof SpannedString 465 || text instanceof SpannableString) { 466 nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y, 467 paint.mBidiFlags, paint.getNativeInstance()); 468 } else if (text instanceof GraphicsOperations) { 469 ((GraphicsOperations) text).drawText(this, start, end, x, y, 470 paint); 471 } else { 472 char[] buf = TemporaryBuffer.obtain(end - start); 473 TextUtils.getChars(text, start, end, buf, 0); 474 nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y, 475 paint.mBidiFlags, paint.getNativeInstance()); 476 TemporaryBuffer.recycle(buf); 477 } 478 } 479 480 @Override drawText(@onNull String text, float x, float y, @NonNull Paint paint)481 public final void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { 482 nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags, 483 paint.getNativeInstance()); 484 } 485 486 @Override drawText(@onNull String text, int start, int end, float x, float y, @NonNull Paint paint)487 public final void drawText(@NonNull String text, int start, int end, float x, float y, 488 @NonNull Paint paint) { 489 if ((start | end | (end - start) | (text.length() - end)) < 0) { 490 throw new IndexOutOfBoundsException(); 491 } 492 nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags, 493 paint.getNativeInstance()); 494 } 495 496 @Override drawTextOnPath(@onNull char[] text, int index, int count, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)497 public final void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path, 498 float hOffset, float vOffset, @NonNull Paint paint) { 499 if (index < 0 || index + count > text.length) { 500 throw new ArrayIndexOutOfBoundsException(); 501 } 502 nDrawTextOnPath(mNativeCanvasWrapper, text, index, count, 503 path.readOnlyNI(), hOffset, vOffset, 504 paint.mBidiFlags, paint.getNativeInstance()); 505 } 506 507 @Override drawTextOnPath(@onNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)508 public final void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, 509 float vOffset, @NonNull Paint paint) { 510 if (text.length() > 0) { 511 nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset, 512 paint.mBidiFlags, paint.getNativeInstance()); 513 } 514 } 515 516 @Override drawTextRun(@onNull char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint)517 public final void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, 518 int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) { 519 520 if (text == null) { 521 throw new NullPointerException("text is null"); 522 } 523 if (paint == null) { 524 throw new NullPointerException("paint is null"); 525 } 526 if ((index | count | contextIndex | contextCount | index - contextIndex 527 | (contextIndex + contextCount) - (index + count) 528 | text.length - (contextIndex + contextCount)) < 0) { 529 throw new IndexOutOfBoundsException(); 530 } 531 532 nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount, 533 x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */); 534 } 535 536 @Override drawTextRun(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)537 public final void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, 538 int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { 539 540 if (text == null) { 541 throw new NullPointerException("text is null"); 542 } 543 if (paint == null) { 544 throw new NullPointerException("paint is null"); 545 } 546 if ((start | end | contextStart | contextEnd | start - contextStart | end - start 547 | contextEnd - end | text.length() - contextEnd) < 0) { 548 throw new IndexOutOfBoundsException(); 549 } 550 551 if (text instanceof String || text instanceof SpannedString 552 || text instanceof SpannableString) { 553 nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart, 554 contextEnd, x, y, isRtl, paint.getNativeInstance()); 555 } else if (text instanceof GraphicsOperations) { 556 ((GraphicsOperations) text).drawTextRun(this, start, end, 557 contextStart, contextEnd, x, y, isRtl, paint); 558 } else { 559 if (text instanceof PrecomputedText) { 560 final PrecomputedText pt = (PrecomputedText) text; 561 final int paraIndex = pt.findParaIndex(start); 562 if (end <= pt.getParagraphEnd(paraIndex)) { 563 final int paraStart = pt.getParagraphStart(paraIndex); 564 final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex); 565 // Only support if the target is in the same paragraph. 566 drawTextRun(mp.getMeasuredText(), 567 start - paraStart, 568 end - paraStart, 569 contextStart - paraStart, 570 contextEnd - paraStart, 571 x, y, isRtl, paint); 572 return; 573 } 574 } 575 int contextLen = contextEnd - contextStart; 576 int len = end - start; 577 char[] buf = TemporaryBuffer.obtain(contextLen); 578 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 579 nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, 580 0, contextLen, x, y, isRtl, paint.getNativeInstance(), 581 0 /* measured paragraph pointer */); 582 TemporaryBuffer.recycle(buf); 583 } 584 } 585 586 @Override drawTextRun(@onNull MeasuredText measuredText, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)587 public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end, 588 int contextStart, int contextEnd, float x, float y, boolean isRtl, 589 @NonNull Paint paint) { 590 nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start, 591 contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(), 592 measuredText.getNativePtr()); 593 } 594 595 @Override 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)596 public final void drawVertices(@NonNull VertexMode mode, int vertexCount, 597 @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, 598 @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset, 599 int indexCount, @NonNull Paint paint) { 600 checkRange(verts.length, vertOffset, vertexCount); 601 if (texs != null) { 602 checkRange(texs.length, texOffset, vertexCount); 603 } 604 if (colors != null) { 605 checkRange(colors.length, colorOffset, vertexCount / 2); 606 } 607 if (indices != null) { 608 checkRange(indices.length, indexOffset, indexCount); 609 } 610 nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts, 611 vertOffset, texs, texOffset, colors, colorOffset, 612 indices, indexOffset, indexCount, paint.getNativeInstance()); 613 } 614 615 @Override drawMesh(@onNull Mesh mesh, @Nullable BlendMode blendMode, @NonNull Paint paint)616 public final void drawMesh(@NonNull Mesh mesh, @Nullable BlendMode blendMode, 617 @NonNull Paint paint) { 618 if (blendMode == null) { 619 blendMode = BlendMode.MODULATE; 620 } 621 nDrawMesh(mNativeCanvasWrapper, mesh.getNativeWrapperInstance(), 622 blendMode.getXfermode().porterDuffMode, paint.getNativeInstance()); 623 } 624 625 /** 626 * @hide 627 */ 628 @Override punchHole(float left, float top, float right, float bottom, float rx, float ry, float alpha)629 public void punchHole(float left, float top, float right, float bottom, float rx, float ry, 630 float alpha) { 631 nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha); 632 } 633 634 @FastNative nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)635 private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, 636 float top, long nativePaintOrZero, int canvasDensity, int screenDensity, 637 int bitmapDensity); 638 639 @FastNative nDrawBitmap(long nativeCanvas, long bitmapHandle, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)640 private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, 641 float srcLeft, float srcTop, float srcRight, float srcBottom, 642 float dstLeft, float dstTop, float dstRight, float dstBottom, 643 long nativePaintOrZero, int screenDensity, int bitmapDensity); 644 645 @FastNative nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)646 private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, 647 float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero); 648 649 @FastNative nDrawColor(long nativeCanvas, int color, int mode)650 private static native void nDrawColor(long nativeCanvas, int color, int mode); 651 652 @FastNative nDrawColor(long nativeCanvas, long nativeColorSpace, @ColorLong long color, int mode)653 private static native void nDrawColor(long nativeCanvas, long nativeColorSpace, 654 @ColorLong long color, int mode); 655 656 @FastNative nDrawPaint(long nativeCanvas, long nativePaint)657 private static native void nDrawPaint(long nativeCanvas, long nativePaint); 658 659 @FastNative nDrawPoint(long canvasHandle, float x, float y, long paintHandle)660 private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle); 661 662 @FastNative nDrawPoints(long canvasHandle, float[] pts, int offset, int count, long paintHandle)663 private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count, 664 long paintHandle); 665 666 @FastNative nDrawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long nativePaint)667 private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX, 668 float stopY, long nativePaint); 669 670 @FastNative nDrawLines(long canvasHandle, float[] pts, int offset, int count, long paintHandle)671 private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count, 672 long paintHandle); 673 674 @FastNative nDrawRect(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)675 private static native void nDrawRect(long nativeCanvas, float left, float top, float right, 676 float bottom, long nativePaint); 677 678 @FastNative nDrawOval(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)679 private static native void nDrawOval(long nativeCanvas, float left, float top, float right, 680 float bottom, long nativePaint); 681 682 @FastNative nDrawCircle(long nativeCanvas, float cx, float cy, float radius, long nativePaint)683 private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius, 684 long nativePaint); 685 686 @FastNative nDrawArc(long nativeCanvas, float left, float top, float right, float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint)687 private static native void nDrawArc(long nativeCanvas, float left, float top, float right, 688 float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint); 689 690 @FastNative nDrawRoundRect(long nativeCanvas, float left, float top, float right, float bottom, float rx, float ry, long nativePaint)691 private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right, 692 float bottom, float rx, float ry, long nativePaint); 693 694 @FastNative nDrawDoubleRoundRect(long nativeCanvas, float outerLeft, float outerTop, float outerRight, float outerBottom, float outerRx, float outerRy, float innerLeft, float innerTop, float innerRight, float innerBottom, float innerRx, float innerRy, long nativePaint)695 private static native void nDrawDoubleRoundRect(long nativeCanvas, 696 float outerLeft, float outerTop, float outerRight, float outerBottom, 697 float outerRx, float outerRy, float innerLeft, float innerTop, float innerRight, 698 float innerBottom, float innerRx, float innerRy, long nativePaint); 699 700 @FastNative nDrawDoubleRoundRect(long nativeCanvas, float outerLeft, float outerTop, float outerRight, float outerBottom, float[] outerRadii, float innerLeft, float innerTop, float innerRight, float innerBottom, float[] innerRadii, long nativePaint)701 private static native void nDrawDoubleRoundRect(long nativeCanvas, float outerLeft, 702 float outerTop, float outerRight, float outerBottom, float[] outerRadii, 703 float innerLeft, float innerTop, float innerRight, float innerBottom, 704 float[] innerRadii, long nativePaint); 705 706 @FastNative nDrawPath(long nativeCanvas, long nativePath, long nativePaint)707 private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint); 708 709 @FastNative nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint)710 private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint); 711 712 @FastNative nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)713 private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, 714 float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, 715 int screenDensity, int bitmapDensity); 716 717 @FastNative nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle, long nativeMatrix, long nativePaint)718 private static native void nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle, 719 long nativeMatrix, long nativePaint); 720 721 @FastNative nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nativePaint)722 private static native void nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth, 723 int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, 724 long nativePaint); 725 726 @FastNative nDrawMesh( long canvasHandle, long nativeMesh, int mode, long nativePaint)727 private static native void nDrawMesh( 728 long canvasHandle, long nativeMesh, int mode, long nativePaint); 729 730 @FastNative 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)731 private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts, 732 int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, 733 short[] indices, int indexOffset, int indexCount, long nativePaint); 734 735 @FastNative nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint)736 private static native void nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, 737 int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint); 738 739 @FastNative nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint)740 private static native void nDrawText(long nativeCanvas, char[] text, int index, int count, 741 float x, float y, int flags, long nativePaint); 742 743 @FastNative nDrawText(long nativeCanvas, String text, int start, int end, float x, float y, int flags, long nativePaint)744 private static native void nDrawText(long nativeCanvas, String text, int start, int end, 745 float x, float y, int flags, long nativePaint); 746 747 @FastNative nDrawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint)748 private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end, 749 int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint); 750 751 @FastNative nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativePrecomputedText)752 private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, 753 int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, 754 long nativePrecomputedText); 755 756 @FastNative nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint)757 private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, 758 long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint); 759 760 @FastNative nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint)761 private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, 762 float hOffset, float vOffset, int flags, long nativePaint); 763 764 @FastNative nPunchHole(long renderer, float left, float top, float right, float bottom, float rx, float ry, float alpha)765 private static native void nPunchHole(long renderer, float left, float top, float right, 766 float bottom, float rx, float ry, float alpha); 767 } 768