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