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