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 drawPicture(@onNull Picture picture)293 public final void drawPicture(@NonNull Picture picture) { 294 picture.endRecording(); 295 int restoreCount = save(); 296 picture.draw(this); 297 restoreToCount(restoreCount); 298 } 299 300 @Override drawPicture(@onNull Picture picture, @NonNull Rect dst)301 public final void drawPicture(@NonNull Picture picture, @NonNull Rect dst) { 302 save(); 303 translate(dst.left, dst.top); 304 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 305 scale((float) dst.width() / picture.getWidth(), 306 (float) dst.height() / picture.getHeight()); 307 } 308 drawPicture(picture); 309 restore(); 310 } 311 312 @Override drawPicture(@onNull Picture picture, @NonNull RectF dst)313 public final void drawPicture(@NonNull Picture picture, @NonNull RectF dst) { 314 save(); 315 translate(dst.left, dst.top); 316 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 317 scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); 318 } 319 drawPicture(picture); 320 restore(); 321 } 322 323 @Override drawPoint(float x, float y, @NonNull Paint paint)324 public final void drawPoint(float x, float y, @NonNull Paint paint) { 325 nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance()); 326 } 327 328 @Override drawPoints(@izemultiple = 2) float[] pts, int offset, int count, @NonNull Paint paint)329 public final void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count, 330 @NonNull Paint paint) { 331 nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); 332 } 333 334 @Override drawPoints(@izemultiple = 2) @onNull float[] pts, @NonNull Paint paint)335 public final void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) { 336 drawPoints(pts, 0, pts.length, paint); 337 } 338 339 /** @deprecated checkstyle */ 340 @Override 341 @Deprecated drawPosText(@onNull char[] text, int index, int count, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)342 public final void drawPosText(@NonNull char[] text, int index, int count, 343 @NonNull @Size(multiple = 2) float[] pos, 344 @NonNull Paint paint) { 345 if (index < 0 || index + count > text.length || count * 2 > pos.length) { 346 throw new IndexOutOfBoundsException(); 347 } 348 for (int i = 0; i < count; i++) { 349 drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint); 350 } 351 } 352 353 /** @deprecated checkstyle */ 354 @Override 355 @Deprecated drawPosText(@onNull String text, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)356 public final void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos, 357 @NonNull Paint paint) { 358 drawPosText(text.toCharArray(), 0, text.length(), pos, paint); 359 } 360 361 @Override drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)362 public final void drawRect(float left, float top, float right, float bottom, 363 @NonNull Paint paint) { 364 nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance()); 365 } 366 367 @Override drawRect(@onNull Rect r, @NonNull Paint paint)368 public final void drawRect(@NonNull Rect r, @NonNull Paint paint) { 369 drawRect(r.left, r.top, r.right, r.bottom, paint); 370 } 371 372 @Override drawRect(@onNull RectF rect, @NonNull Paint paint)373 public final void drawRect(@NonNull RectF rect, @NonNull Paint paint) { 374 nDrawRect(mNativeCanvasWrapper, 375 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance()); 376 } 377 378 @Override drawRGB(int r, int g, int b)379 public final void drawRGB(int r, int g, int b) { 380 drawColor(Color.rgb(r, g, b)); 381 } 382 383 @Override drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)384 public final void drawRoundRect(float left, float top, float right, float bottom, 385 float rx, float ry, @NonNull Paint paint) { 386 nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, 387 paint.getNativeInstance()); 388 } 389 390 @Override drawRoundRect(@onNull RectF rect, float rx, float ry, @NonNull Paint paint)391 public final void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { 392 drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint); 393 } 394 395 @Override drawDoubleRoundRect(@onNull RectF outer, float outerRx, float outerRy, @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint)396 public final void drawDoubleRoundRect(@NonNull RectF outer, float outerRx, float outerRy, 397 @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint) { 398 nDrawDoubleRoundRect(mNativeCanvasWrapper, 399 outer.left, outer.top, outer.right, outer.bottom, outerRx, outerRy, 400 inner.left, inner.top, inner.right, inner.bottom, innerRx, innerRy, 401 paint.getNativeInstance()); 402 } 403 404 @Override drawDoubleRoundRect(@onNull RectF outer, float[] outerRadii, @NonNull RectF inner, float[] innerRadii, @NonNull Paint paint)405 public final void drawDoubleRoundRect(@NonNull RectF outer, float[] outerRadii, 406 @NonNull RectF inner, float[] innerRadii, @NonNull Paint paint) { 407 nDrawDoubleRoundRect(mNativeCanvasWrapper, 408 outer.left, outer.top, outer.right, outer.bottom, outerRadii, 409 inner.left, inner.top, inner.right, inner.bottom, innerRadii, 410 paint.getNativeInstance()); 411 } 412 413 @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)414 public void drawGlyphs( 415 @NonNull int[] glyphIds, 416 @IntRange(from = 0) int glyphIdOffset, 417 @NonNull float[] positions, 418 @IntRange(from = 0) int positionOffset, 419 @IntRange(from = 0) int glyphCount, 420 @NonNull Font font, 421 @NonNull Paint paint) { 422 Objects.requireNonNull(glyphIds, "glyphIds must not be null."); 423 Objects.requireNonNull(positions, "positions must not be null."); 424 Objects.requireNonNull(font, "font must not be null."); 425 Objects.requireNonNull(paint, "paint must not be null."); 426 Preconditions.checkArgumentNonnegative(glyphCount); 427 428 if (glyphIdOffset < 0 || glyphIdOffset + glyphCount > glyphIds.length) { 429 throw new IndexOutOfBoundsException( 430 "glyphIds must have at least " + (glyphIdOffset + glyphCount) + " of elements"); 431 } 432 if (positionOffset < 0 || positionOffset + glyphCount * 2 > positions.length) { 433 throw new IndexOutOfBoundsException( 434 "positions must have at least " + (positionOffset + glyphCount * 2) 435 + " of elements"); 436 } 437 nDrawGlyphs(mNativeCanvasWrapper, glyphIds, positions, glyphIdOffset, positionOffset, 438 glyphCount, font.getNativePtr(), paint.getNativeInstance()); 439 } 440 441 @Override drawText(@onNull char[] text, int index, int count, float x, float y, @NonNull Paint paint)442 public final void drawText(@NonNull char[] text, int index, int count, float x, float y, 443 @NonNull Paint paint) { 444 if ((index | count | (index + count) 445 | (text.length - index - count)) < 0) { 446 throw new IndexOutOfBoundsException(); 447 } 448 nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags, 449 paint.getNativeInstance()); 450 } 451 452 @Override drawText(@onNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint)453 public final void drawText(@NonNull CharSequence text, int start, int end, float x, float y, 454 @NonNull Paint paint) { 455 if ((start | end | (end - start) | (text.length() - end)) < 0) { 456 throw new IndexOutOfBoundsException(); 457 } 458 if (text instanceof String || text instanceof SpannedString 459 || text instanceof SpannableString) { 460 nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y, 461 paint.mBidiFlags, paint.getNativeInstance()); 462 } else if (text instanceof GraphicsOperations) { 463 ((GraphicsOperations) text).drawText(this, start, end, x, y, 464 paint); 465 } else { 466 char[] buf = TemporaryBuffer.obtain(end - start); 467 TextUtils.getChars(text, start, end, buf, 0); 468 nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y, 469 paint.mBidiFlags, paint.getNativeInstance()); 470 TemporaryBuffer.recycle(buf); 471 } 472 } 473 474 @Override drawText(@onNull String text, float x, float y, @NonNull Paint paint)475 public final void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { 476 nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags, 477 paint.getNativeInstance()); 478 } 479 480 @Override drawText(@onNull String text, int start, int end, float x, float y, @NonNull Paint paint)481 public final void drawText(@NonNull String text, int start, int end, float x, float y, 482 @NonNull Paint paint) { 483 if ((start | end | (end - start) | (text.length() - end)) < 0) { 484 throw new IndexOutOfBoundsException(); 485 } 486 nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags, 487 paint.getNativeInstance()); 488 } 489 490 @Override drawTextOnPath(@onNull char[] text, int index, int count, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)491 public final void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path, 492 float hOffset, float vOffset, @NonNull Paint paint) { 493 if (index < 0 || index + count > text.length) { 494 throw new ArrayIndexOutOfBoundsException(); 495 } 496 nDrawTextOnPath(mNativeCanvasWrapper, text, index, count, 497 path.readOnlyNI(), hOffset, vOffset, 498 paint.mBidiFlags, paint.getNativeInstance()); 499 } 500 501 @Override drawTextOnPath(@onNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)502 public final void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, 503 float vOffset, @NonNull Paint paint) { 504 if (text.length() > 0) { 505 nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset, 506 paint.mBidiFlags, paint.getNativeInstance()); 507 } 508 } 509 510 @Override drawTextRun(@onNull char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint)511 public final void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, 512 int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) { 513 514 if (text == null) { 515 throw new NullPointerException("text is null"); 516 } 517 if (paint == null) { 518 throw new NullPointerException("paint is null"); 519 } 520 if ((index | count | contextIndex | contextCount | index - contextIndex 521 | (contextIndex + contextCount) - (index + count) 522 | text.length - (contextIndex + contextCount)) < 0) { 523 throw new IndexOutOfBoundsException(); 524 } 525 526 nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount, 527 x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */); 528 } 529 530 @Override drawTextRun(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)531 public final void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, 532 int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { 533 534 if (text == null) { 535 throw new NullPointerException("text is null"); 536 } 537 if (paint == null) { 538 throw new NullPointerException("paint is null"); 539 } 540 if ((start | end | contextStart | contextEnd | start - contextStart | end - start 541 | contextEnd - end | text.length() - contextEnd) < 0) { 542 throw new IndexOutOfBoundsException(); 543 } 544 545 if (text instanceof String || text instanceof SpannedString 546 || text instanceof SpannableString) { 547 nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart, 548 contextEnd, x, y, isRtl, paint.getNativeInstance()); 549 } else if (text instanceof GraphicsOperations) { 550 ((GraphicsOperations) text).drawTextRun(this, start, end, 551 contextStart, contextEnd, x, y, isRtl, paint); 552 } else { 553 if (text instanceof PrecomputedText) { 554 final PrecomputedText pt = (PrecomputedText) text; 555 final int paraIndex = pt.findParaIndex(start); 556 if (end <= pt.getParagraphEnd(paraIndex)) { 557 final int paraStart = pt.getParagraphStart(paraIndex); 558 final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex); 559 // Only support if the target is in the same paragraph. 560 drawTextRun(mp.getMeasuredText(), 561 start - paraStart, 562 end - paraStart, 563 contextStart - paraStart, 564 contextEnd - paraStart, 565 x, y, isRtl, paint); 566 return; 567 } 568 } 569 int contextLen = contextEnd - contextStart; 570 int len = end - start; 571 char[] buf = TemporaryBuffer.obtain(contextLen); 572 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 573 nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, 574 0, contextLen, x, y, isRtl, paint.getNativeInstance(), 575 0 /* measured paragraph pointer */); 576 TemporaryBuffer.recycle(buf); 577 } 578 } 579 580 @Override drawTextRun(@onNull MeasuredText measuredText, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)581 public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end, 582 int contextStart, int contextEnd, float x, float y, boolean isRtl, 583 @NonNull Paint paint) { 584 nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start, 585 contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(), 586 measuredText.getNativePtr()); 587 } 588 589 @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)590 public final void drawVertices(@NonNull VertexMode mode, int vertexCount, 591 @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, 592 @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset, 593 int indexCount, @NonNull Paint paint) { 594 checkRange(verts.length, vertOffset, vertexCount); 595 if (texs != null) { 596 checkRange(texs.length, texOffset, vertexCount); 597 } 598 if (colors != null) { 599 checkRange(colors.length, colorOffset, vertexCount / 2); 600 } 601 if (indices != null) { 602 checkRange(indices.length, indexOffset, indexCount); 603 } 604 nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts, 605 vertOffset, texs, texOffset, colors, colorOffset, 606 indices, indexOffset, indexCount, paint.getNativeInstance()); 607 } 608 609 @Override drawMesh(@onNull Mesh mesh, BlendMode blendMode, @NonNull Paint paint)610 public final void drawMesh(@NonNull Mesh mesh, BlendMode blendMode, @NonNull Paint paint) { 611 if (blendMode == null) { 612 blendMode = BlendMode.MODULATE; 613 } 614 nDrawMesh(mNativeCanvasWrapper, mesh.getNativeWrapperInstance(), 615 blendMode.getXfermode().porterDuffMode, paint.getNativeInstance()); 616 } 617 618 /** 619 * @hide 620 */ 621 @Override punchHole(float left, float top, float right, float bottom, float rx, float ry, float alpha)622 public void punchHole(float left, float top, float right, float bottom, float rx, float ry, 623 float alpha) { 624 nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha); 625 } 626 627 @FastNative nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)628 private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, 629 float top, long nativePaintOrZero, int canvasDensity, int screenDensity, 630 int bitmapDensity); 631 632 @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)633 private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, 634 float srcLeft, float srcTop, float srcRight, float srcBottom, 635 float dstLeft, float dstTop, float dstRight, float dstBottom, 636 long nativePaintOrZero, int screenDensity, int bitmapDensity); 637 638 @FastNative nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)639 private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, 640 float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero); 641 642 @FastNative nDrawColor(long nativeCanvas, int color, int mode)643 private static native void nDrawColor(long nativeCanvas, int color, int mode); 644 645 @FastNative nDrawColor(long nativeCanvas, long nativeColorSpace, @ColorLong long color, int mode)646 private static native void nDrawColor(long nativeCanvas, long nativeColorSpace, 647 @ColorLong long color, int mode); 648 649 @FastNative nDrawPaint(long nativeCanvas, long nativePaint)650 private static native void nDrawPaint(long nativeCanvas, long nativePaint); 651 652 @FastNative nDrawPoint(long canvasHandle, float x, float y, long paintHandle)653 private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle); 654 655 @FastNative nDrawPoints(long canvasHandle, float[] pts, int offset, int count, long paintHandle)656 private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count, 657 long paintHandle); 658 659 @FastNative nDrawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long nativePaint)660 private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX, 661 float stopY, long nativePaint); 662 663 @FastNative nDrawLines(long canvasHandle, float[] pts, int offset, int count, long paintHandle)664 private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count, 665 long paintHandle); 666 667 @FastNative nDrawRect(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)668 private static native void nDrawRect(long nativeCanvas, float left, float top, float right, 669 float bottom, long nativePaint); 670 671 @FastNative nDrawOval(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)672 private static native void nDrawOval(long nativeCanvas, float left, float top, float right, 673 float bottom, long nativePaint); 674 675 @FastNative nDrawCircle(long nativeCanvas, float cx, float cy, float radius, long nativePaint)676 private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius, 677 long nativePaint); 678 679 @FastNative nDrawArc(long nativeCanvas, float left, float top, float right, float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint)680 private static native void nDrawArc(long nativeCanvas, float left, float top, float right, 681 float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint); 682 683 @FastNative nDrawRoundRect(long nativeCanvas, float left, float top, float right, float bottom, float rx, float ry, long nativePaint)684 private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right, 685 float bottom, float rx, float ry, long nativePaint); 686 687 @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)688 private static native void nDrawDoubleRoundRect(long nativeCanvas, 689 float outerLeft, float outerTop, float outerRight, float outerBottom, 690 float outerRx, float outerRy, float innerLeft, float innerTop, float innerRight, 691 float innerBottom, float innerRx, float innerRy, long nativePaint); 692 693 @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)694 private static native void nDrawDoubleRoundRect(long nativeCanvas, float outerLeft, 695 float outerTop, float outerRight, float outerBottom, float[] outerRadii, 696 float innerLeft, float innerTop, float innerRight, float innerBottom, 697 float[] innerRadii, long nativePaint); 698 699 @FastNative nDrawPath(long nativeCanvas, long nativePath, long nativePaint)700 private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint); 701 702 @FastNative nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint)703 private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint); 704 705 @FastNative nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)706 private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, 707 float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, 708 int screenDensity, int bitmapDensity); 709 710 @FastNative nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle, long nativeMatrix, long nativePaint)711 private static native void nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle, 712 long nativeMatrix, long nativePaint); 713 714 @FastNative nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nativePaint)715 private static native void nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth, 716 int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, 717 long nativePaint); 718 719 @FastNative nDrawMesh( long canvasHandle, long nativeMesh, int mode, long nativePaint)720 private static native void nDrawMesh( 721 long canvasHandle, long nativeMesh, int mode, long nativePaint); 722 723 @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)724 private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts, 725 int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, 726 short[] indices, int indexOffset, int indexCount, long nativePaint); 727 728 @FastNative nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint)729 private static native void nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, 730 int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint); 731 732 @FastNative nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint)733 private static native void nDrawText(long nativeCanvas, char[] text, int index, int count, 734 float x, float y, int flags, long nativePaint); 735 736 @FastNative nDrawText(long nativeCanvas, String text, int start, int end, float x, float y, int flags, long nativePaint)737 private static native void nDrawText(long nativeCanvas, String text, int start, int end, 738 float x, float y, int flags, long nativePaint); 739 740 @FastNative nDrawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint)741 private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end, 742 int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint); 743 744 @FastNative nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativePrecomputedText)745 private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, 746 int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, 747 long nativePrecomputedText); 748 749 @FastNative nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint)750 private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, 751 long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint); 752 753 @FastNative nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint)754 private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, 755 float hOffset, float vOffset, int flags, long nativePaint); 756 757 @FastNative nPunchHole(long renderer, float left, float top, float right, float bottom, float rx, float ry, float alpha)758 private static native void nPunchHole(long renderer, float left, float top, float right, 759 float bottom, float rx, float ry, float alpha); 760 } 761