1 /* 2 * Copyright (C) 2006 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.IntDef; 22 import android.annotation.IntRange; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.Size; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.graphics.fonts.Font; 28 import android.graphics.text.MeasuredText; 29 import android.graphics.text.TextRunShaper; 30 import android.os.Build; 31 import android.text.TextShaper; 32 33 import dalvik.annotation.optimization.CriticalNative; 34 import dalvik.annotation.optimization.FastNative; 35 36 import libcore.util.NativeAllocationRegistry; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.RetentionPolicy; 40 41 /** 42 * The Canvas class holds the "draw" calls. To draw something, you need 43 * 4 basic components: A Bitmap to hold the pixels, a Canvas to host 44 * the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, 45 * Path, text, Bitmap), and a paint (to describe the colors and styles for the 46 * drawing). 47 * 48 * <div class="special reference"> 49 * <h3>Developer Guides</h3> 50 * <p>For more information about how to use Canvas, read the 51 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html"> 52 * Canvas and Drawables</a> developer guide.</p></div> 53 */ 54 public class Canvas extends BaseCanvas { 55 private static int sCompatiblityVersion = 0; 56 private static boolean sCompatibilityRestore = false; 57 private static boolean sCompatibilitySetBitmap = false; 58 59 /** @hide */ 60 @UnsupportedAppUsage getNativeCanvasWrapper()61 public long getNativeCanvasWrapper() { 62 return mNativeCanvasWrapper; 63 } 64 65 // may be null 66 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117521088) 67 private Bitmap mBitmap; 68 69 // optional field set by the caller 70 private DrawFilter mDrawFilter; 71 72 // Maximum bitmap size as defined in Skia's native code 73 // (see SkCanvas.cpp, SkDraw.cpp) 74 private static final int MAXMIMUM_BITMAP_SIZE = 32766; 75 76 // Use a Holder to allow static initialization of Canvas in the boot image. 77 private static class NoImagePreloadHolder { 78 public static final NativeAllocationRegistry sRegistry = 79 NativeAllocationRegistry.createMalloced( 80 Canvas.class.getClassLoader(), nGetNativeFinalizer()); 81 } 82 83 // This field is used to finalize the native Canvas properly 84 private Runnable mFinalizer; 85 86 /** 87 * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to 88 * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; 89 * this will typically be replaced when a target bitmap is set for the 90 * canvas. 91 */ Canvas()92 public Canvas() { 93 if (!isHardwareAccelerated()) { 94 // 0 means no native bitmap 95 mNativeCanvasWrapper = nInitRaster(0); 96 mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( 97 this, mNativeCanvasWrapper); 98 } else { 99 mFinalizer = null; 100 } 101 } 102 103 /** 104 * Construct a canvas with the specified bitmap to draw into. The bitmap 105 * must be mutable. 106 * 107 * <p>The initial target density of the canvas is the same as the given 108 * bitmap's density. 109 * 110 * @param bitmap Specifies a mutable bitmap for the canvas to draw into. 111 */ Canvas(@onNull Bitmap bitmap)112 public Canvas(@NonNull Bitmap bitmap) { 113 if (!bitmap.isMutable()) { 114 throw new IllegalStateException("Immutable bitmap passed to Canvas constructor"); 115 } 116 throwIfCannotDraw(bitmap); 117 mNativeCanvasWrapper = nInitRaster(bitmap.getNativeInstance()); 118 mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( 119 this, mNativeCanvasWrapper); 120 mBitmap = bitmap; 121 mDensity = bitmap.mDensity; 122 } 123 124 /** 125 * @hide Needed by android.graphics.pdf.PdfDocument, but should not be called from 126 * outside the UI rendering module. 127 */ Canvas(long nativeCanvas)128 public Canvas(long nativeCanvas) { 129 if (nativeCanvas == 0) { 130 throw new IllegalStateException(); 131 } 132 mNativeCanvasWrapper = nativeCanvas; 133 mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation( 134 this, mNativeCanvasWrapper); 135 mDensity = Bitmap.getDefaultDensity(); 136 } 137 138 /** 139 * Indicates whether this Canvas uses hardware acceleration. 140 * 141 * Note that this method does not define what type of hardware acceleration 142 * may or may not be used. 143 * 144 * @return True if drawing operations are hardware accelerated, 145 * false otherwise. 146 */ isHardwareAccelerated()147 public boolean isHardwareAccelerated() { 148 return false; 149 } 150 151 /** 152 * Specify a bitmap for the canvas to draw into. All canvas state such as 153 * layers, filters, and the save/restore stack are reset. Additionally, 154 * the canvas' target density is updated to match that of the bitmap. 155 * 156 * Prior to API level {@value Build.VERSION_CODES#O} the current matrix and 157 * clip stack were preserved. 158 * 159 * @param bitmap Specifies a mutable bitmap for the canvas to draw into. 160 * @see #setDensity(int) 161 * @see #getDensity() 162 */ setBitmap(@ullable Bitmap bitmap)163 public void setBitmap(@Nullable Bitmap bitmap) { 164 if (isHardwareAccelerated()) { 165 throw new RuntimeException("Can't set a bitmap device on a HW accelerated canvas"); 166 } 167 168 Matrix preservedMatrix = null; 169 if (bitmap != null && sCompatibilitySetBitmap) { 170 preservedMatrix = getMatrix(); 171 } 172 173 if (bitmap == null) { 174 nSetBitmap(mNativeCanvasWrapper, 0); 175 mDensity = Bitmap.DENSITY_NONE; 176 } else { 177 if (!bitmap.isMutable()) { 178 throw new IllegalStateException(); 179 } 180 throwIfCannotDraw(bitmap); 181 182 nSetBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance()); 183 mDensity = bitmap.mDensity; 184 } 185 186 if (preservedMatrix != null) { 187 setMatrix(preservedMatrix); 188 } 189 190 mBitmap = bitmap; 191 } 192 193 /** 194 * <p>Enables Z support which defaults to disabled. This allows for RenderNodes drawn with 195 * {@link #drawRenderNode(RenderNode)} to be re-arranged based off of their 196 * {@link RenderNode#getElevation()} and {@link RenderNode#getTranslationZ()} 197 * values. It also enables rendering of shadows for RenderNodes with an elevation or 198 * translationZ.</p> 199 * 200 * <p>Any draw reordering will not be moved before this call. A typical usage of this might 201 * look something like: 202 * 203 * <pre class="prettyprint"> 204 * void draw(Canvas canvas) { 205 * // Draw any background content 206 * canvas.drawColor(backgroundColor); 207 * 208 * // Begin drawing that may be reordered based off of Z 209 * canvas.enableZ(); 210 * for (RenderNode child : children) { 211 * canvas.drawRenderNode(child); 212 * } 213 * // End drawing that may be reordered based off of Z 214 * canvas.disableZ(); 215 * 216 * // Draw any overlays 217 * canvas.drawText("I'm on top of everything!", 0, 0, paint); 218 * } 219 * </pre> 220 * </p> 221 * 222 * Note: This is not impacted by any {@link #save()} or {@link #restore()} calls as it is not 223 * considered to be part of the current matrix or clip. 224 * 225 * See {@link #disableZ()} 226 */ enableZ()227 public void enableZ() { 228 } 229 230 /** 231 * Disables Z support, preventing any RenderNodes drawn after this point from being 232 * visually reordered or having shadows rendered. 233 * 234 * Note: This is not impacted by any {@link #save()} or {@link #restore()} calls as it is not 235 * considered to be part of the current matrix or clip. 236 * 237 * See {@link #enableZ()} 238 */ disableZ()239 public void disableZ() { 240 } 241 242 /** 243 * Return true if the device that the current layer draws into is opaque 244 * (i.e. does not support per-pixel alpha). 245 * 246 * @return true if the device that the current layer draws into is opaque 247 */ isOpaque()248 public boolean isOpaque() { 249 return nIsOpaque(mNativeCanvasWrapper); 250 } 251 252 /** 253 * Returns the width of the current drawing layer 254 * 255 * @return the width of the current drawing layer 256 */ getWidth()257 public int getWidth() { 258 return nGetWidth(mNativeCanvasWrapper); 259 } 260 261 /** 262 * Returns the height of the current drawing layer 263 * 264 * @return the height of the current drawing layer 265 */ getHeight()266 public int getHeight() { 267 return nGetHeight(mNativeCanvasWrapper); 268 } 269 270 /** 271 * <p>Returns the target density of the canvas. The default density is 272 * derived from the density of its backing bitmap, or 273 * {@link Bitmap#DENSITY_NONE} if there is not one.</p> 274 * 275 * @return Returns the current target density of the canvas, which is used 276 * to determine the scaling factor when drawing a bitmap into it. 277 * 278 * @see #setDensity(int) 279 * @see Bitmap#getDensity() 280 */ getDensity()281 public int getDensity() { 282 return mDensity; 283 } 284 285 /** 286 * <p>Specifies the density for this Canvas' backing bitmap. This modifies 287 * the target density of the canvas itself, as well as the density of its 288 * backing bitmap via {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}. 289 * 290 * @param density The new target density of the canvas, which is used 291 * to determine the scaling factor when drawing a bitmap into it. Use 292 * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling. 293 * 294 * @see #getDensity() 295 * @see Bitmap#setDensity(int) 296 */ setDensity(int density)297 public void setDensity(int density) { 298 if (mBitmap != null) { 299 mBitmap.setDensity(density); 300 } 301 mDensity = density; 302 } 303 304 /** @hide */ 305 @UnsupportedAppUsage setScreenDensity(int density)306 public void setScreenDensity(int density) { 307 mScreenDensity = density; 308 } 309 310 /** 311 * Returns the maximum allowed width for bitmaps drawn with this canvas. 312 * Attempting to draw with a bitmap wider than this value will result 313 * in an error. 314 * 315 * @see #getMaximumBitmapHeight() 316 */ getMaximumBitmapWidth()317 public int getMaximumBitmapWidth() { 318 return MAXMIMUM_BITMAP_SIZE; 319 } 320 321 /** 322 * Returns the maximum allowed height for bitmaps drawn with this canvas. 323 * Attempting to draw with a bitmap taller than this value will result 324 * in an error. 325 * 326 * @see #getMaximumBitmapWidth() 327 */ getMaximumBitmapHeight()328 public int getMaximumBitmapHeight() { 329 return MAXMIMUM_BITMAP_SIZE; 330 } 331 332 // the SAVE_FLAG constants must match their native equivalents 333 334 /** @hide */ 335 @IntDef(flag = true, 336 value = { 337 ALL_SAVE_FLAG 338 }) 339 @Retention(RetentionPolicy.SOURCE) 340 public @interface Saveflags {} 341 342 /** 343 * Restore the current matrix when restore() is called. 344 * @removed 345 * @deprecated Use the flagless version of {@link #save()}, {@link #saveLayer(RectF, Paint)} or 346 * {@link #saveLayerAlpha(RectF, int)}. For saveLayer() calls the matrix 347 * was always restored for {@link #isHardwareAccelerated() Hardware accelerated} 348 * canvases and as of API level {@value Build.VERSION_CODES#O} that is the default 349 * behavior for all canvas types. 350 */ 351 public static final int MATRIX_SAVE_FLAG = 0x01; 352 353 /** 354 * Restore the current clip when restore() is called. 355 * 356 * @removed 357 * @deprecated Use the flagless version of {@link #save()}, {@link #saveLayer(RectF, Paint)} or 358 * {@link #saveLayerAlpha(RectF, int)}. For saveLayer() calls the clip 359 * was always restored for {@link #isHardwareAccelerated() Hardware accelerated} 360 * canvases and as of API level {@value Build.VERSION_CODES#O} that is the default 361 * behavior for all canvas types. 362 */ 363 public static final int CLIP_SAVE_FLAG = 0x02; 364 365 /** 366 * The layer requires a per-pixel alpha channel. 367 * 368 * @removed 369 * @deprecated This flag is ignored. Use the flagless version of {@link #saveLayer(RectF, Paint)} 370 * {@link #saveLayerAlpha(RectF, int)}. 371 */ 372 public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04; 373 374 /** 375 * The layer requires full 8-bit precision for each color channel. 376 * 377 * @removed 378 * @deprecated This flag is ignored. Use the flagless version of {@link #saveLayer(RectF, Paint)} 379 * {@link #saveLayerAlpha(RectF, int)}. 380 */ 381 public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08; 382 383 /** 384 * Clip drawing to the bounds of the offscreen layer, omit at your own peril. 385 * <p class="note"><strong>Note:</strong> it is strongly recommended to not 386 * omit this flag for any call to <code>saveLayer()</code> and 387 * <code>saveLayerAlpha()</code> variants. Not passing this flag generally 388 * triggers extremely poor performance with hardware accelerated rendering. 389 * 390 * @removed 391 * @deprecated This flag results in poor performance and the same effect can be achieved with 392 * a single layer or multiple draw commands with different clips. 393 * 394 */ 395 public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10; 396 397 /** 398 * Restore everything when restore() is called (standard save flags). 399 * <p class="note"><strong>Note:</strong> for performance reasons, it is 400 * strongly recommended to pass this - the complete set of flags - to any 401 * call to <code>saveLayer()</code> and <code>saveLayerAlpha()</code> 402 * variants. 403 * 404 * <p class="note"><strong>Note:</strong> all methods that accept this flag 405 * have flagless versions that are equivalent to passing this flag. 406 */ 407 public static final int ALL_SAVE_FLAG = 0x1F; 408 checkValidSaveFlags(int saveFlags)409 private static void checkValidSaveFlags(int saveFlags) { 410 if (sCompatiblityVersion >= Build.VERSION_CODES.P 411 && saveFlags != ALL_SAVE_FLAG) { 412 throw new IllegalArgumentException( 413 "Invalid Layer Save Flag - only ALL_SAVE_FLAGS is allowed"); 414 } 415 } 416 417 /** 418 * Saves the current matrix and clip onto a private stack. 419 * <p> 420 * Subsequent calls to translate,scale,rotate,skew,concat or clipRect, 421 * clipPath will all operate as usual, but when the balancing call to 422 * restore() is made, those calls will be forgotten, and the settings that 423 * existed before the save() will be reinstated. 424 * 425 * @return The value to pass to restoreToCount() to balance this save() 426 */ save()427 public int save() { 428 return nSave(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); 429 } 430 431 /** 432 * Based on saveFlags, can save the current matrix and clip onto a private 433 * stack. 434 * <p class="note"><strong>Note:</strong> if possible, use the 435 * parameter-less save(). It is simpler and faster than individually 436 * disabling the saving of matrix or clip with this method. 437 * <p> 438 * Subsequent calls to translate,scale,rotate,skew,concat or clipRect, 439 * clipPath will all operate as usual, but when the balancing call to 440 * restore() is made, those calls will be forgotten, and the settings that 441 * existed before the save() will be reinstated. 442 * 443 * @removed 444 * @deprecated Use {@link #save()} instead. 445 * @param saveFlags flag bits that specify which parts of the Canvas state 446 * to save/restore 447 * @return The value to pass to restoreToCount() to balance this save() 448 */ save(@aveflags int saveFlags)449 public int save(@Saveflags int saveFlags) { 450 return nSave(mNativeCanvasWrapper, saveFlags); 451 } 452 453 /** 454 * This behaves the same as save(), but in addition it allocates and 455 * redirects drawing to an offscreen bitmap. 456 * <p class="note"><strong>Note:</strong> this method is very expensive, 457 * incurring more than double rendering cost for contained content. Avoid 458 * using this method, especially if the bounds provided are large. It is 459 * recommended to use a {@link android.view.View#LAYER_TYPE_HARDWARE hardware layer} on a View 460 * to apply an xfermode, color filter, or alpha, as it will perform much 461 * better than this method. 462 * <p> 463 * All drawing calls are directed to a newly allocated offscreen bitmap. 464 * Only when the balancing call to restore() is made, is that offscreen 465 * buffer drawn back to the current target of the Canvas (either the 466 * screen, it's target Bitmap, or the previous layer). 467 * <p> 468 * Attributes of the Paint - {@link Paint#getAlpha() alpha}, 469 * {@link Paint#getXfermode() Xfermode}, and 470 * {@link Paint#getColorFilter() ColorFilter} are applied when the 471 * offscreen bitmap is drawn back when restore() is called. 472 * 473 * As of API Level API level {@value Build.VERSION_CODES#P} the only valid 474 * {@code saveFlags} is {@link #ALL_SAVE_FLAG}. All other flags are ignored. 475 * 476 * @deprecated Use {@link #saveLayer(RectF, Paint)} instead. 477 * @param bounds May be null. The maximum size the offscreen bitmap 478 * needs to be (in local coordinates) 479 * @param paint This is copied, and is applied to the offscreen when 480 * restore() is called. 481 * @param saveFlags see _SAVE_FLAG constants, generally {@link #ALL_SAVE_FLAG} is recommended 482 * for performance reasons. 483 * @return value to pass to restoreToCount() to balance this save() 484 */ saveLayer(@ullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags)485 public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags) { 486 if (bounds == null) { 487 bounds = new RectF(getClipBounds()); 488 } 489 checkValidSaveFlags(saveFlags); 490 return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, 491 ALL_SAVE_FLAG); 492 } 493 494 /** 495 * This behaves the same as save(), but in addition it allocates and 496 * redirects drawing to an offscreen rendering target. 497 * <p class="note"><strong>Note:</strong> this method is very expensive, 498 * incurring more than double rendering cost for contained content. Avoid 499 * using this method when possible and instead use a 500 * {@link android.view.View#LAYER_TYPE_HARDWARE hardware layer} on a View 501 * to apply an xfermode, color filter, or alpha, as it will perform much 502 * better than this method. 503 * <p> 504 * All drawing calls are directed to a newly allocated offscreen rendering target. 505 * Only when the balancing call to restore() is made, is that offscreen 506 * buffer drawn back to the current target of the Canvas (which can potentially be a previous 507 * layer if these calls are nested). 508 * <p> 509 * Attributes of the Paint - {@link Paint#getAlpha() alpha}, 510 * {@link Paint#getXfermode() Xfermode}, and 511 * {@link Paint#getColorFilter() ColorFilter} are applied when the 512 * offscreen rendering target is drawn back when restore() is called. 513 * 514 * @param bounds May be null. The maximum size the offscreen render target 515 * needs to be (in local coordinates) 516 * @param paint This is copied, and is applied to the offscreen when 517 * restore() is called. 518 * @return value to pass to restoreToCount() to balance this save() 519 */ saveLayer(@ullable RectF bounds, @Nullable Paint paint)520 public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) { 521 return saveLayer(bounds, paint, ALL_SAVE_FLAG); 522 } 523 524 /** 525 * @hide 526 */ saveUnclippedLayer(int left, int top, int right, int bottom)527 public int saveUnclippedLayer(int left, int top, int right, int bottom) { 528 return nSaveUnclippedLayer(mNativeCanvasWrapper, left, top, right, bottom); 529 } 530 531 /** 532 * @hide 533 * @param saveCount The save level to restore to. 534 * @param paint This is copied and is applied to the area within the unclipped layer's 535 * bounds (i.e. equivalent to a drawPaint()) before restore() is called. 536 */ restoreUnclippedLayer(int saveCount, Paint paint)537 public void restoreUnclippedLayer(int saveCount, Paint paint) { 538 nRestoreUnclippedLayer(mNativeCanvasWrapper, saveCount, paint.getNativeInstance()); 539 } 540 541 /** 542 * Helper version of saveLayer() that takes 4 values rather than a RectF. 543 * 544 * As of API Level API level {@value Build.VERSION_CODES#P} the only valid 545 * {@code saveFlags} is {@link #ALL_SAVE_FLAG}. All other flags are ignored. 546 * 547 * @deprecated Use {@link #saveLayer(float, float, float, float, Paint)} instead. 548 */ saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint, @Saveflags int saveFlags)549 public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint, 550 @Saveflags int saveFlags) { 551 checkValidSaveFlags(saveFlags); 552 return nSaveLayer(mNativeCanvasWrapper, left, top, right, bottom, 553 paint != null ? paint.getNativeInstance() : 0); 554 } 555 556 /** 557 * Convenience for {@link #saveLayer(RectF, Paint)} that takes the four float coordinates of the 558 * bounds rectangle. 559 */ saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint)560 public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint) { 561 return saveLayer(left, top, right, bottom, paint, ALL_SAVE_FLAG); 562 } 563 564 /** 565 * This behaves the same as save(), but in addition it allocates and 566 * redirects drawing to an offscreen bitmap. 567 * <p class="note"><strong>Note:</strong> this method is very expensive, 568 * incurring more than double rendering cost for contained content. Avoid 569 * using this method, especially if the bounds provided are large. It is 570 * recommended to use a {@link android.view.View#LAYER_TYPE_HARDWARE hardware layer} on a View 571 * to apply an xfermode, color filter, or alpha, as it will perform much 572 * better than this method. 573 * <p> 574 * All drawing calls are directed to a newly allocated offscreen bitmap. 575 * Only when the balancing call to restore() is made, is that offscreen 576 * buffer drawn back to the current target of the Canvas (either the 577 * screen, it's target Bitmap, or the previous layer). 578 * <p> 579 * The {@code alpha} parameter is applied when the offscreen bitmap is 580 * drawn back when restore() is called. 581 * 582 * As of API Level API level {@value Build.VERSION_CODES#P} the only valid 583 * {@code saveFlags} is {@link #ALL_SAVE_FLAG}. All other flags are ignored. 584 * 585 * @deprecated Use {@link #saveLayerAlpha(RectF, int)} instead. 586 * @param bounds The maximum size the offscreen bitmap needs to be 587 * (in local coordinates) 588 * @param alpha The alpha to apply to the offscreen when it is 589 drawn during restore() 590 * @param saveFlags see _SAVE_FLAG constants, generally {@link #ALL_SAVE_FLAG} is recommended 591 * for performance reasons. 592 * @return value to pass to restoreToCount() to balance this call 593 */ saveLayerAlpha(@ullable RectF bounds, int alpha, @Saveflags int saveFlags)594 public int saveLayerAlpha(@Nullable RectF bounds, int alpha, @Saveflags int saveFlags) { 595 if (bounds == null) { 596 bounds = new RectF(getClipBounds()); 597 } 598 checkValidSaveFlags(saveFlags); 599 return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, alpha, 600 ALL_SAVE_FLAG); 601 } 602 603 /** 604 * Convenience for {@link #saveLayer(RectF, Paint)} but instead of taking a entire Paint object 605 * it takes only the {@code alpha} parameter. 606 * 607 * @param bounds The maximum size the offscreen bitmap needs to be 608 * (in local coordinates) 609 * @param alpha The alpha to apply to the offscreen when it is 610 drawn during restore() 611 */ saveLayerAlpha(@ullable RectF bounds, int alpha)612 public int saveLayerAlpha(@Nullable RectF bounds, int alpha) { 613 return saveLayerAlpha(bounds, alpha, ALL_SAVE_FLAG); 614 } 615 616 /** 617 * Helper for saveLayerAlpha() that takes 4 values instead of a RectF. 618 * 619 * As of API Level API level {@value Build.VERSION_CODES#P} the only valid 620 * {@code saveFlags} is {@link #ALL_SAVE_FLAG}. All other flags are ignored. 621 * 622 * @deprecated Use {@link #saveLayerAlpha(float, float, float, float, int)} instead. 623 */ saveLayerAlpha(float left, float top, float right, float bottom, int alpha, @Saveflags int saveFlags)624 public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, 625 @Saveflags int saveFlags) { 626 checkValidSaveFlags(saveFlags); 627 alpha = Math.min(255, Math.max(0, alpha)); 628 return nSaveLayerAlpha(mNativeCanvasWrapper, left, top, right, bottom, alpha); 629 } 630 631 /** 632 * Convenience for {@link #saveLayerAlpha(RectF, int)} that takes the four float coordinates of 633 * the bounds rectangle. 634 */ saveLayerAlpha(float left, float top, float right, float bottom, int alpha)635 public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) { 636 return saveLayerAlpha(left, top, right, bottom, alpha, ALL_SAVE_FLAG); 637 } 638 639 /** 640 * This call balances a previous call to save(), and is used to remove all 641 * modifications to the matrix/clip state since the last save call. It is 642 * an error to call restore() more times than save() was called. 643 */ restore()644 public void restore() { 645 if (!nRestore(mNativeCanvasWrapper) 646 && (!sCompatibilityRestore || !isHardwareAccelerated())) { 647 throw new IllegalStateException("Underflow in restore - more restores than saves"); 648 } 649 } 650 651 /** 652 * Returns the number of matrix/clip states on the Canvas' private stack. 653 * This will equal # save() calls - # restore() calls. 654 */ getSaveCount()655 public int getSaveCount() { 656 return nGetSaveCount(mNativeCanvasWrapper); 657 } 658 659 /** 660 * Efficient way to pop any calls to save() that happened after the save 661 * count reached saveCount. It is an error for saveCount to be less than 1. 662 * 663 * Example: 664 * int count = canvas.save(); 665 * ... // more calls potentially to save() 666 * canvas.restoreToCount(count); 667 * // now the canvas is back in the same state it was before the initial 668 * // call to save(). 669 * 670 * @param saveCount The save level to restore to. 671 */ restoreToCount(int saveCount)672 public void restoreToCount(int saveCount) { 673 if (saveCount < 1) { 674 if (!sCompatibilityRestore || !isHardwareAccelerated()) { 675 // do nothing and throw without restoring 676 throw new IllegalArgumentException( 677 "Underflow in restoreToCount - more restores than saves"); 678 } 679 // compat behavior - restore as far as possible 680 saveCount = 1; 681 } 682 nRestoreToCount(mNativeCanvasWrapper, saveCount); 683 } 684 685 /** 686 * Preconcat the current matrix with the specified translation 687 * 688 * @param dx The distance to translate in X 689 * @param dy The distance to translate in Y 690 */ translate(float dx, float dy)691 public void translate(float dx, float dy) { 692 if (dx == 0.0f && dy == 0.0f) return; 693 nTranslate(mNativeCanvasWrapper, dx, dy); 694 } 695 696 /** 697 * Preconcat the current matrix with the specified scale. 698 * 699 * @param sx The amount to scale in X 700 * @param sy The amount to scale in Y 701 */ scale(float sx, float sy)702 public void scale(float sx, float sy) { 703 if (sx == 1.0f && sy == 1.0f) return; 704 nScale(mNativeCanvasWrapper, sx, sy); 705 } 706 707 /** 708 * Preconcat the current matrix with the specified scale. 709 * 710 * @param sx The amount to scale in X 711 * @param sy The amount to scale in Y 712 * @param px The x-coord for the pivot point (unchanged by the scale) 713 * @param py The y-coord for the pivot point (unchanged by the scale) 714 */ scale(float sx, float sy, float px, float py)715 public final void scale(float sx, float sy, float px, float py) { 716 if (sx == 1.0f && sy == 1.0f) return; 717 translate(px, py); 718 scale(sx, sy); 719 translate(-px, -py); 720 } 721 722 /** 723 * Preconcat the current matrix with the specified rotation. 724 * 725 * @param degrees The amount to rotate, in degrees 726 */ rotate(float degrees)727 public void rotate(float degrees) { 728 if (degrees == 0.0f) return; 729 nRotate(mNativeCanvasWrapper, degrees); 730 } 731 732 /** 733 * Preconcat the current matrix with the specified rotation. 734 * 735 * @param degrees The amount to rotate, in degrees 736 * @param px The x-coord for the pivot point (unchanged by the rotation) 737 * @param py The y-coord for the pivot point (unchanged by the rotation) 738 */ rotate(float degrees, float px, float py)739 public final void rotate(float degrees, float px, float py) { 740 if (degrees == 0.0f) return; 741 translate(px, py); 742 rotate(degrees); 743 translate(-px, -py); 744 } 745 746 /** 747 * Preconcat the current matrix with the specified skew. 748 * 749 * @param sx The amount to skew in X 750 * @param sy The amount to skew in Y 751 */ skew(float sx, float sy)752 public void skew(float sx, float sy) { 753 if (sx == 0.0f && sy == 0.0f) return; 754 nSkew(mNativeCanvasWrapper, sx, sy); 755 } 756 757 /** 758 * Preconcat the current matrix with the specified matrix. If the specified 759 * matrix is null, this method does nothing. 760 * 761 * @param matrix The matrix to preconcatenate with the current matrix 762 */ concat(@ullable Matrix matrix)763 public void concat(@Nullable Matrix matrix) { 764 if (matrix != null) nConcat(mNativeCanvasWrapper, matrix.ni()); 765 } 766 767 /** 768 * Completely replace the current matrix with the specified matrix. If the 769 * matrix parameter is null, then the current matrix is reset to identity. 770 * 771 * <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)}, 772 * {@link #scale(float, float)}, {@link #translate(float, float)} and 773 * {@link #rotate(float)} instead of this method. 774 * 775 * @param matrix The matrix to replace the current matrix with. If it is 776 * null, set the current matrix to identity. 777 * 778 * @see #concat(Matrix) 779 */ setMatrix(@ullable Matrix matrix)780 public void setMatrix(@Nullable Matrix matrix) { 781 nSetMatrix(mNativeCanvasWrapper, 782 matrix == null ? 0 : matrix.ni()); 783 } 784 785 /** 786 * Return, in ctm, the current transformation matrix. This does not alter 787 * the matrix in the canvas, but just returns a copy of it. 788 * 789 * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any 790 * matrix when passed to a View or Drawable, as it is implementation defined where in the 791 * hierarchy such canvases are created. It is recommended in such cases to either draw contents 792 * irrespective of the current matrix, or to track relevant transform state outside of the 793 * canvas. 794 */ 795 @Deprecated getMatrix(@onNull Matrix ctm)796 public void getMatrix(@NonNull Matrix ctm) { 797 nGetMatrix(mNativeCanvasWrapper, ctm.ni()); 798 } 799 800 /** 801 * Return a new matrix with a copy of the canvas' current transformation 802 * matrix. 803 * 804 * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any 805 * matrix when passed to a View or Drawable, as it is implementation defined where in the 806 * hierarchy such canvases are created. It is recommended in such cases to either draw contents 807 * irrespective of the current matrix, or to track relevant transform state outside of the 808 * canvas. 809 */ 810 @Deprecated getMatrix()811 public final @NonNull Matrix getMatrix() { 812 Matrix m = new Matrix(); 813 //noinspection deprecation 814 getMatrix(m); 815 return m; 816 } 817 checkValidClipOp(@onNull Region.Op op)818 private static void checkValidClipOp(@NonNull Region.Op op) { 819 if (sCompatiblityVersion >= Build.VERSION_CODES.P 820 && op != Region.Op.INTERSECT && op != Region.Op.DIFFERENCE) { 821 throw new IllegalArgumentException( 822 "Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed"); 823 } 824 } 825 826 /** 827 * Modify the current clip with the specified rectangle. 828 * 829 * @param rect The rect to intersect with the current clip 830 * @param op How the clip is modified 831 * @return true if the resulting clip is non-empty 832 * 833 * @deprecated Region.Op values other than {@link Region.Op#INTERSECT} and 834 * {@link Region.Op#DIFFERENCE} have the ability to expand the clip. The canvas clipping APIs 835 * are intended to only expand the clip as a result of a restore operation. This enables a view 836 * parent to clip a canvas to clearly define the maximal drawing area of its children. The 837 * recommended alternative calls are {@link #clipRect(RectF)} and {@link #clipOutRect(RectF)}; 838 * 839 * As of API Level API level {@value Build.VERSION_CODES#P} only {@link Region.Op#INTERSECT} and 840 * {@link Region.Op#DIFFERENCE} are valid Region.Op parameters. 841 */ 842 @Deprecated clipRect(@onNull RectF rect, @NonNull Region.Op op)843 public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) { 844 checkValidClipOp(op); 845 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 846 op.nativeInt); 847 } 848 849 /** 850 * Modify the current clip with the specified rectangle, which is 851 * expressed in local coordinates. 852 * 853 * @param rect The rectangle to intersect with the current clip. 854 * @param op How the clip is modified 855 * @return true if the resulting clip is non-empty 856 * 857 * @deprecated Region.Op values other than {@link Region.Op#INTERSECT} and 858 * {@link Region.Op#DIFFERENCE} have the ability to expand the clip. The canvas clipping APIs 859 * are intended to only expand the clip as a result of a restore operation. This enables a view 860 * parent to clip a canvas to clearly define the maximal drawing area of its children. The 861 * recommended alternative calls are {@link #clipRect(Rect)} and {@link #clipOutRect(Rect)}; 862 * 863 * As of API Level API level {@value Build.VERSION_CODES#P} only {@link Region.Op#INTERSECT} and 864 * {@link Region.Op#DIFFERENCE} are valid Region.Op parameters. 865 */ 866 @Deprecated clipRect(@onNull Rect rect, @NonNull Region.Op op)867 public boolean clipRect(@NonNull Rect rect, @NonNull Region.Op op) { 868 checkValidClipOp(op); 869 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 870 op.nativeInt); 871 } 872 873 /** 874 * DON'T USE THIS METHOD. It exists only to support a particular legacy behavior in 875 * the view system and will be removed as soon as that code is refactored to no longer 876 * depend on this behavior. 877 * @hide 878 */ clipRectUnion(@onNull Rect rect)879 public boolean clipRectUnion(@NonNull Rect rect) { 880 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 881 Region.Op.UNION.nativeInt); 882 } 883 884 /** 885 * Intersect the current clip with the specified rectangle, which is 886 * expressed in local coordinates. 887 * 888 * @param rect The rectangle to intersect with the current clip. 889 * @return true if the resulting clip is non-empty 890 */ clipRect(@onNull RectF rect)891 public boolean clipRect(@NonNull RectF rect) { 892 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 893 Region.Op.INTERSECT.nativeInt); 894 } 895 896 /** 897 * Set the clip to the difference of the current clip and the specified rectangle, which is 898 * expressed in local coordinates. 899 * 900 * @param rect The rectangle to perform a difference op with the current clip. 901 * @return true if the resulting clip is non-empty 902 */ clipOutRect(@onNull RectF rect)903 public boolean clipOutRect(@NonNull RectF rect) { 904 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 905 Region.Op.DIFFERENCE.nativeInt); 906 } 907 908 /** 909 * Intersect the current clip with the specified rectangle, which is 910 * expressed in local coordinates. 911 * 912 * @param rect The rectangle to intersect with the current clip. 913 * @return true if the resulting clip is non-empty 914 */ clipRect(@onNull Rect rect)915 public boolean clipRect(@NonNull Rect rect) { 916 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 917 Region.Op.INTERSECT.nativeInt); 918 } 919 920 /** 921 * Set the clip to the difference of the current clip and the specified rectangle, which is 922 * expressed in local coordinates. 923 * 924 * @param rect The rectangle to perform a difference op with the current clip. 925 * @return true if the resulting clip is non-empty 926 */ clipOutRect(@onNull Rect rect)927 public boolean clipOutRect(@NonNull Rect rect) { 928 return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 929 Region.Op.DIFFERENCE.nativeInt); 930 } 931 932 /** 933 * Modify the current clip with the specified rectangle, which is 934 * expressed in local coordinates. 935 * 936 * @param left The left side of the rectangle to intersect with the 937 * current clip 938 * @param top The top of the rectangle to intersect with the current 939 * clip 940 * @param right The right side of the rectangle to intersect with the 941 * current clip 942 * @param bottom The bottom of the rectangle to intersect with the current 943 * clip 944 * @param op How the clip is modified 945 * @return true if the resulting clip is non-empty 946 * 947 * @deprecated Region.Op values other than {@link Region.Op#INTERSECT} and 948 * {@link Region.Op#DIFFERENCE} have the ability to expand the clip. The canvas clipping APIs 949 * are intended to only expand the clip as a result of a restore operation. This enables a view 950 * parent to clip a canvas to clearly define the maximal drawing area of its children. The 951 * recommended alternative calls are {@link #clipRect(float,float,float,float)} and 952 * {@link #clipOutRect(float,float,float,float)}; 953 * 954 * As of API Level API level {@value Build.VERSION_CODES#P} only {@link Region.Op#INTERSECT} and 955 * {@link Region.Op#DIFFERENCE} are valid Region.Op parameters. 956 */ 957 @Deprecated clipRect(float left, float top, float right, float bottom, @NonNull Region.Op op)958 public boolean clipRect(float left, float top, float right, float bottom, 959 @NonNull Region.Op op) { 960 checkValidClipOp(op); 961 return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, op.nativeInt); 962 } 963 964 /** 965 * Intersect the current clip with the specified rectangle, which is 966 * expressed in local coordinates. 967 * 968 * @param left The left side of the rectangle to intersect with the 969 * current clip 970 * @param top The top of the rectangle to intersect with the current clip 971 * @param right The right side of the rectangle to intersect with the 972 * current clip 973 * @param bottom The bottom of the rectangle to intersect with the current 974 * clip 975 * @return true if the resulting clip is non-empty 976 */ clipRect(float left, float top, float right, float bottom)977 public boolean clipRect(float left, float top, float right, float bottom) { 978 return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, 979 Region.Op.INTERSECT.nativeInt); 980 } 981 982 /** 983 * Set the clip to the difference of the current clip and the specified rectangle, which is 984 * expressed in local coordinates. 985 * 986 * @param left The left side of the rectangle used in the difference operation 987 * @param top The top of the rectangle used in the difference operation 988 * @param right The right side of the rectangle used in the difference operation 989 * @param bottom The bottom of the rectangle used in the difference operation 990 * @return true if the resulting clip is non-empty 991 */ clipOutRect(float left, float top, float right, float bottom)992 public boolean clipOutRect(float left, float top, float right, float bottom) { 993 return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, 994 Region.Op.DIFFERENCE.nativeInt); 995 } 996 997 /** 998 * Intersect the current clip with the specified rectangle, which is 999 * expressed in local coordinates. 1000 * 1001 * @param left The left side of the rectangle to intersect with the 1002 * current clip 1003 * @param top The top of the rectangle to intersect with the current clip 1004 * @param right The right side of the rectangle to intersect with the 1005 * current clip 1006 * @param bottom The bottom of the rectangle to intersect with the current 1007 * clip 1008 * @return true if the resulting clip is non-empty 1009 */ clipRect(int left, int top, int right, int bottom)1010 public boolean clipRect(int left, int top, int right, int bottom) { 1011 return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, 1012 Region.Op.INTERSECT.nativeInt); 1013 } 1014 1015 /** 1016 * Set the clip to the difference of the current clip and the specified rectangle, which is 1017 * expressed in local coordinates. 1018 * 1019 * @param left The left side of the rectangle used in the difference operation 1020 * @param top The top of the rectangle used in the difference operation 1021 * @param right The right side of the rectangle used in the difference operation 1022 * @param bottom The bottom of the rectangle used in the difference operation 1023 * @return true if the resulting clip is non-empty 1024 */ clipOutRect(int left, int top, int right, int bottom)1025 public boolean clipOutRect(int left, int top, int right, int bottom) { 1026 return nClipRect(mNativeCanvasWrapper, left, top, right, bottom, 1027 Region.Op.DIFFERENCE.nativeInt); 1028 } 1029 1030 /** 1031 * Modify the current clip with the specified path. 1032 * 1033 * @param path The path to operate on the current clip 1034 * @param op How the clip is modified 1035 * @return true if the resulting is non-empty 1036 * 1037 * @deprecated Region.Op values other than {@link Region.Op#INTERSECT} and 1038 * {@link Region.Op#DIFFERENCE} have the ability to expand the clip. The canvas clipping APIs 1039 * are intended to only expand the clip as a result of a restore operation. This enables a view 1040 * parent to clip a canvas to clearly define the maximal drawing area of its children. The 1041 * recommended alternative calls are {@link #clipPath(Path)} and 1042 * {@link #clipOutPath(Path)}; 1043 * 1044 * As of API Level API level {@value Build.VERSION_CODES#P} only {@link Region.Op#INTERSECT} and 1045 * {@link Region.Op#DIFFERENCE} are valid Region.Op parameters. 1046 */ 1047 @Deprecated clipPath(@onNull Path path, @NonNull Region.Op op)1048 public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) { 1049 checkValidClipOp(op); 1050 return nClipPath(mNativeCanvasWrapper, path.readOnlyNI(), op.nativeInt); 1051 } 1052 1053 /** 1054 * Intersect the current clip with the specified path. 1055 * 1056 * @param path The path to intersect with the current clip 1057 * @return true if the resulting clip is non-empty 1058 */ clipPath(@onNull Path path)1059 public boolean clipPath(@NonNull Path path) { 1060 return clipPath(path, Region.Op.INTERSECT); 1061 } 1062 1063 /** 1064 * Set the clip to the difference of the current clip and the specified path. 1065 * 1066 * @param path The path used in the difference operation 1067 * @return true if the resulting clip is non-empty 1068 */ clipOutPath(@onNull Path path)1069 public boolean clipOutPath(@NonNull Path path) { 1070 return clipPath(path, Region.Op.DIFFERENCE); 1071 } 1072 1073 /** 1074 * Modify the current clip with the specified region. Note that unlike 1075 * clipRect() and clipPath() which transform their arguments by the 1076 * current matrix, clipRegion() assumes its argument is already in the 1077 * coordinate system of the current layer's bitmap, and so not 1078 * transformation is performed. 1079 * 1080 * @param region The region to operate on the current clip, based on op 1081 * @param op How the clip is modified 1082 * @return true if the resulting is non-empty 1083 * 1084 * @removed 1085 * @deprecated Unlike all other clip calls this API does not respect the 1086 * current matrix. Use {@link #clipRect(Rect)} as an alternative. 1087 */ 1088 @Deprecated clipRegion(@onNull Region region, @NonNull Region.Op op)1089 public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) { 1090 return false; 1091 } 1092 1093 /** 1094 * Intersect the current clip with the specified region. Note that unlike 1095 * clipRect() and clipPath() which transform their arguments by the 1096 * current matrix, clipRegion() assumes its argument is already in the 1097 * coordinate system of the current layer's bitmap, and so not 1098 * transformation is performed. 1099 * 1100 * @param region The region to operate on the current clip, based on op 1101 * @return true if the resulting is non-empty 1102 * 1103 * @removed 1104 * @deprecated Unlike all other clip calls this API does not respect the 1105 * current matrix. Use {@link #clipRect(Rect)} as an alternative. 1106 */ 1107 @Deprecated clipRegion(@onNull Region region)1108 public boolean clipRegion(@NonNull Region region) { 1109 return false; 1110 } 1111 getDrawFilter()1112 public @Nullable DrawFilter getDrawFilter() { 1113 return mDrawFilter; 1114 } 1115 setDrawFilter(@ullable DrawFilter filter)1116 public void setDrawFilter(@Nullable DrawFilter filter) { 1117 long nativeFilter = 0; 1118 if (filter != null) { 1119 nativeFilter = filter.mNativeInt; 1120 } 1121 mDrawFilter = filter; 1122 nSetDrawFilter(mNativeCanvasWrapper, nativeFilter); 1123 } 1124 1125 /** 1126 * Constant values used as parameters to {@code quickReject()} calls. These values 1127 * specify how much space around the shape should be accounted for, depending on whether 1128 * the shaped area is antialiased or not. 1129 * 1130 * @see #quickReject(float, float, float, float, EdgeType) 1131 * @see #quickReject(Path, EdgeType) 1132 * @see #quickReject(RectF, EdgeType) 1133 * @deprecated quickReject no longer uses this. 1134 */ 1135 public enum EdgeType { 1136 1137 /** 1138 * Black-and-White: Treat edges by just rounding to nearest pixel boundary 1139 */ 1140 BW, 1141 1142 /** 1143 * Antialiased: Treat edges by rounding-out, since they may be antialiased 1144 */ 1145 AA; 1146 } 1147 1148 /** 1149 * Return true if the specified rectangle, after being transformed by the 1150 * current matrix, would lie completely outside of the current clip. Call 1151 * this to check if an area you intend to draw into is clipped out (and 1152 * therefore you can skip making the draw calls). 1153 * 1154 * @param rect the rect to compare with the current clip 1155 * @param type {@link Canvas.EdgeType#AA} if the path should be considered antialiased, 1156 * since that means it may affect a larger area (more pixels) than 1157 * non-antialiased ({@link Canvas.EdgeType#BW}). 1158 * @return true if the rect (transformed by the canvas' matrix) 1159 * does not intersect with the canvas' clip 1160 * @deprecated The EdgeType is ignored. Use {@link #quickReject(RectF)} instead. 1161 */ 1162 @Deprecated quickReject(@onNull RectF rect, @NonNull EdgeType type)1163 public boolean quickReject(@NonNull RectF rect, @NonNull EdgeType type) { 1164 return nQuickReject(mNativeCanvasWrapper, 1165 rect.left, rect.top, rect.right, rect.bottom); 1166 } 1167 1168 /** 1169 * Return true if the specified rectangle, after being transformed by the 1170 * current matrix, would lie completely outside of the current clip. Call 1171 * this to check if an area you intend to draw into is clipped out (and 1172 * therefore you can skip making the draw calls). 1173 * 1174 * @param rect the rect to compare with the current clip 1175 * @return true if the rect (transformed by the canvas' matrix) 1176 * does not intersect with the canvas' clip 1177 */ quickReject(@onNull RectF rect)1178 public boolean quickReject(@NonNull RectF rect) { 1179 return nQuickReject(mNativeCanvasWrapper, 1180 rect.left, rect.top, rect.right, rect.bottom); 1181 } 1182 1183 /** 1184 * Return true if the specified path, after being transformed by the 1185 * current matrix, would lie completely outside of the current clip. Call 1186 * this to check if an area you intend to draw into is clipped out (and 1187 * therefore you can skip making the draw calls). Note: for speed it may 1188 * return false even if the path itself might not intersect the clip 1189 * (i.e. the bounds of the path intersects, but the path does not). 1190 * 1191 * @param path The path to compare with the current clip 1192 * @param type {@link Canvas.EdgeType#AA} if the path should be considered antialiased, 1193 * since that means it may affect a larger area (more pixels) than 1194 * non-antialiased ({@link Canvas.EdgeType#BW}). 1195 * @return true if the path (transformed by the canvas' matrix) 1196 * does not intersect with the canvas' clip 1197 * @deprecated The EdgeType is ignored. Use {@link #quickReject(Path)} instead. 1198 */ 1199 @Deprecated quickReject(@onNull Path path, @NonNull EdgeType type)1200 public boolean quickReject(@NonNull Path path, @NonNull EdgeType type) { 1201 return nQuickReject(mNativeCanvasWrapper, path.readOnlyNI()); 1202 } 1203 1204 /** 1205 * Return true if the specified path, after being transformed by the 1206 * current matrix, would lie completely outside of the current clip. Call 1207 * this to check if an area you intend to draw into is clipped out (and 1208 * therefore you can skip making the draw calls). Note: for speed it may 1209 * return false even if the path itself might not intersect the clip 1210 * (i.e. the bounds of the path intersects, but the path does not). 1211 * 1212 * @param path The path to compare with the current clip 1213 * @return true if the path (transformed by the canvas' matrix) 1214 * does not intersect with the canvas' clip 1215 */ quickReject(@onNull Path path)1216 public boolean quickReject(@NonNull Path path) { 1217 return nQuickReject(mNativeCanvasWrapper, path.readOnlyNI()); 1218 } 1219 1220 /** 1221 * Return true if the specified rectangle, after being transformed by the 1222 * current matrix, would lie completely outside of the current clip. Call 1223 * this to check if an area you intend to draw into is clipped out (and 1224 * therefore you can skip making the draw calls). 1225 * 1226 * @param left The left side of the rectangle to compare with the 1227 * current clip 1228 * @param top The top of the rectangle to compare with the current 1229 * clip 1230 * @param right The right side of the rectangle to compare with the 1231 * current clip 1232 * @param bottom The bottom of the rectangle to compare with the 1233 * current clip 1234 * @param type {@link Canvas.EdgeType#AA} if the path should be considered antialiased, 1235 * since that means it may affect a larger area (more pixels) than 1236 * non-antialiased ({@link Canvas.EdgeType#BW}). 1237 * @return true if the rect (transformed by the canvas' matrix) 1238 * does not intersect with the canvas' clip 1239 * @deprecated The EdgeType is ignored. Use {@link #quickReject(float, float, float, float)} 1240 * instead. 1241 */ 1242 @Deprecated quickReject(float left, float top, float right, float bottom, @NonNull EdgeType type)1243 public boolean quickReject(float left, float top, float right, float bottom, 1244 @NonNull EdgeType type) { 1245 return nQuickReject(mNativeCanvasWrapper, left, top, right, bottom); 1246 } 1247 1248 /** 1249 * Return true if the specified rectangle, after being transformed by the 1250 * current matrix, would lie completely outside of the current clip. Call 1251 * this to check if an area you intend to draw into is clipped out (and 1252 * therefore you can skip making the draw calls). 1253 * 1254 * @param left The left side of the rectangle to compare with the 1255 * current clip 1256 * @param top The top of the rectangle to compare with the current 1257 * clip 1258 * @param right The right side of the rectangle to compare with the 1259 * current clip 1260 * @param bottom The bottom of the rectangle to compare with the 1261 * current clip 1262 * @return true if the rect (transformed by the canvas' matrix) 1263 * does not intersect with the canvas' clip 1264 */ quickReject(float left, float top, float right, float bottom)1265 public boolean quickReject(float left, float top, float right, float bottom) { 1266 return nQuickReject(mNativeCanvasWrapper, left, top, right, bottom); 1267 } 1268 1269 /** 1270 * Return the bounds of the current clip (in local coordinates) in the 1271 * bounds parameter, and return true if it is non-empty. This can be useful 1272 * in a way similar to quickReject, in that it tells you that drawing 1273 * outside of these bounds will be clipped out. 1274 * 1275 * @param bounds Return the clip bounds here. If it is null, ignore it but 1276 * still return true if the current clip is non-empty. 1277 * @return true if the current clip is non-empty. 1278 */ getClipBounds(@ullable Rect bounds)1279 public boolean getClipBounds(@Nullable Rect bounds) { 1280 return nGetClipBounds(mNativeCanvasWrapper, bounds); 1281 } 1282 1283 /** 1284 * Retrieve the bounds of the current clip (in local coordinates). 1285 * 1286 * @return the clip bounds, or [0, 0, 0, 0] if the clip is empty. 1287 */ getClipBounds()1288 public final @NonNull Rect getClipBounds() { 1289 Rect r = new Rect(); 1290 getClipBounds(r); 1291 return r; 1292 } 1293 1294 /** 1295 * Save the canvas state, draw the picture, and restore the canvas state. 1296 * This differs from picture.draw(canvas), which does not perform any 1297 * save/restore. 1298 * 1299 * <p> 1300 * <strong>Note:</strong> This forces the picture to internally call 1301 * {@link Picture#endRecording} in order to prepare for playback. 1302 * 1303 * @param picture The picture to be drawn 1304 */ drawPicture(@onNull Picture picture)1305 public void drawPicture(@NonNull Picture picture) { 1306 picture.endRecording(); 1307 int restoreCount = save(); 1308 picture.draw(this); 1309 restoreToCount(restoreCount); 1310 } 1311 1312 /** 1313 * Draw the picture, stretched to fit into the dst rectangle. 1314 */ drawPicture(@onNull Picture picture, @NonNull RectF dst)1315 public void drawPicture(@NonNull Picture picture, @NonNull RectF dst) { 1316 save(); 1317 translate(dst.left, dst.top); 1318 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 1319 scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); 1320 } 1321 drawPicture(picture); 1322 restore(); 1323 } 1324 1325 /** 1326 * Draw the picture, stretched to fit into the dst rectangle. 1327 */ drawPicture(@onNull Picture picture, @NonNull Rect dst)1328 public void drawPicture(@NonNull Picture picture, @NonNull Rect dst) { 1329 save(); 1330 translate(dst.left, dst.top); 1331 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 1332 scale((float) dst.width() / picture.getWidth(), 1333 (float) dst.height() / picture.getHeight()); 1334 } 1335 drawPicture(picture); 1336 restore(); 1337 } 1338 1339 public enum VertexMode { 1340 TRIANGLES(0), 1341 TRIANGLE_STRIP(1), 1342 TRIANGLE_FAN(2); 1343 VertexMode(int nativeInt)1344 VertexMode(int nativeInt) { 1345 this.nativeInt = nativeInt; 1346 } 1347 1348 /*package*/ final int nativeInt; 1349 } 1350 1351 /** 1352 * Releases the resources associated with this canvas. 1353 * 1354 * @hide 1355 */ 1356 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) release()1357 public void release() { 1358 mNativeCanvasWrapper = 0; 1359 if (mFinalizer != null) { 1360 mFinalizer.run(); 1361 mFinalizer = null; 1362 } 1363 } 1364 1365 /** 1366 * Free up as much memory as possible from private caches (e.g. fonts, images) 1367 * 1368 * @hide 1369 */ 1370 @UnsupportedAppUsage freeCaches()1371 public static void freeCaches() { 1372 nFreeCaches(); 1373 } 1374 1375 /** 1376 * Free up text layout caches 1377 * 1378 * @hide 1379 */ 1380 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) freeTextLayoutCaches()1381 public static void freeTextLayoutCaches() { 1382 nFreeTextLayoutCaches(); 1383 } 1384 setCompatibilityVersion(int apiLevel)1385 /*package*/ static void setCompatibilityVersion(int apiLevel) { 1386 sCompatiblityVersion = apiLevel; 1387 sCompatibilityRestore = apiLevel < Build.VERSION_CODES.M; 1388 sCompatibilitySetBitmap = apiLevel < Build.VERSION_CODES.O; 1389 nSetCompatibilityVersion(apiLevel); 1390 } 1391 1392 private static native void nFreeCaches(); 1393 private static native void nFreeTextLayoutCaches(); 1394 private static native long nGetNativeFinalizer(); 1395 private static native void nSetCompatibilityVersion(int apiLevel); 1396 1397 // ---------------- @FastNative ------------------- 1398 1399 @FastNative 1400 private static native long nInitRaster(long bitmapHandle); 1401 1402 @FastNative 1403 private static native void nSetBitmap(long canvasHandle, long bitmapHandle); 1404 1405 @FastNative 1406 private static native boolean nGetClipBounds(long nativeCanvas, Rect bounds); 1407 1408 // ---------------- @CriticalNative ------------------- 1409 1410 @CriticalNative 1411 private static native boolean nIsOpaque(long canvasHandle); 1412 @CriticalNative 1413 private static native int nGetWidth(long canvasHandle); 1414 @CriticalNative 1415 private static native int nGetHeight(long canvasHandle); 1416 1417 @CriticalNative 1418 private static native int nSave(long canvasHandle, int saveFlags); 1419 @CriticalNative 1420 private static native int nSaveLayer(long nativeCanvas, float l, float t, float r, float b, 1421 long nativePaint); 1422 @CriticalNative 1423 private static native int nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, 1424 int alpha); 1425 @CriticalNative 1426 private static native int nSaveUnclippedLayer(long nativeCanvas, int l, int t, int r, int b); 1427 @CriticalNative 1428 private static native void nRestoreUnclippedLayer(long nativeCanvas, int saveCount, 1429 long nativePaint); 1430 @CriticalNative 1431 private static native boolean nRestore(long canvasHandle); 1432 @CriticalNative 1433 private static native void nRestoreToCount(long canvasHandle, int saveCount); 1434 @CriticalNative 1435 private static native int nGetSaveCount(long canvasHandle); 1436 1437 @CriticalNative 1438 private static native void nTranslate(long canvasHandle, float dx, float dy); 1439 @CriticalNative 1440 private static native void nScale(long canvasHandle, float sx, float sy); 1441 @CriticalNative 1442 private static native void nRotate(long canvasHandle, float degrees); 1443 @CriticalNative 1444 private static native void nSkew(long canvasHandle, float sx, float sy); 1445 @CriticalNative 1446 private static native void nConcat(long nativeCanvas, long nativeMatrix); 1447 @CriticalNative 1448 private static native void nSetMatrix(long nativeCanvas, long nativeMatrix); 1449 @CriticalNative 1450 private static native boolean nClipRect(long nativeCanvas, 1451 float left, float top, float right, float bottom, int regionOp); 1452 @CriticalNative 1453 private static native boolean nClipPath(long nativeCanvas, long nativePath, int regionOp); 1454 @CriticalNative 1455 private static native void nSetDrawFilter(long nativeCanvas, long nativeFilter); 1456 @CriticalNative 1457 private static native void nGetMatrix(long nativeCanvas, long nativeMatrix); 1458 @CriticalNative 1459 private static native boolean nQuickReject(long nativeCanvas, long nativePath); 1460 @CriticalNative 1461 private static native boolean nQuickReject(long nativeCanvas, float left, float top, 1462 float right, float bottom); 1463 1464 1465 // ---------------- Draw Methods ------------------- 1466 1467 /** 1468 * <p> 1469 * Draw the specified arc, which will be scaled to fit inside the specified oval. 1470 * </p> 1471 * <p> 1472 * If the start angle is negative or >= 360, the start angle is treated as start angle modulo 1473 * 360. 1474 * </p> 1475 * <p> 1476 * If the sweep angle is >= 360, then the oval is drawn completely. Note that this differs 1477 * slightly from SkPath::arcTo, which treats the sweep angle modulo 360. If the sweep angle is 1478 * negative, the sweep angle is treated as sweep angle modulo 360 1479 * </p> 1480 * <p> 1481 * The arc is drawn clockwise. An angle of 0 degrees correspond to the geometric angle of 0 1482 * degrees (3 o'clock on a watch.) 1483 * </p> 1484 * 1485 * @param oval The bounds of oval used to define the shape and size of the arc 1486 * @param startAngle Starting angle (in degrees) where the arc begins 1487 * @param sweepAngle Sweep angle (in degrees) measured clockwise 1488 * @param useCenter If true, include the center of the oval in the arc, and close it if it is 1489 * being stroked. This will draw a wedge 1490 * @param paint The paint used to draw the arc 1491 */ 1492 public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, 1493 @NonNull Paint paint) { 1494 super.drawArc(oval, startAngle, sweepAngle, useCenter, paint); 1495 } 1496 1497 /** 1498 * <p> 1499 * Draw the specified arc, which will be scaled to fit inside the specified oval. 1500 * </p> 1501 * <p> 1502 * If the start angle is negative or >= 360, the start angle is treated as start angle modulo 1503 * 360. 1504 * </p> 1505 * <p> 1506 * If the sweep angle is >= 360, then the oval is drawn completely. Note that this differs 1507 * slightly from SkPath::arcTo, which treats the sweep angle modulo 360. If the sweep angle is 1508 * negative, the sweep angle is treated as sweep angle modulo 360 1509 * </p> 1510 * <p> 1511 * The arc is drawn clockwise. An angle of 0 degrees correspond to the geometric angle of 0 1512 * degrees (3 o'clock on a watch.) 1513 * </p> 1514 * 1515 * @param startAngle Starting angle (in degrees) where the arc begins 1516 * @param sweepAngle Sweep angle (in degrees) measured clockwise 1517 * @param useCenter If true, include the center of the oval in the arc, and close it if it is 1518 * being stroked. This will draw a wedge 1519 * @param paint The paint used to draw the arc 1520 */ 1521 public void drawArc(float left, float top, float right, float bottom, float startAngle, 1522 float sweepAngle, boolean useCenter, @NonNull Paint paint) { 1523 super.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint); 1524 } 1525 1526 /** 1527 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified ARGB 1528 * color, using srcover porterduff mode. 1529 * 1530 * @param a alpha component (0..255) of the color to draw onto the canvas 1531 * @param r red component (0..255) of the color to draw onto the canvas 1532 * @param g green component (0..255) of the color to draw onto the canvas 1533 * @param b blue component (0..255) of the color to draw onto the canvas 1534 */ 1535 public void drawARGB(int a, int r, int g, int b) { 1536 super.drawARGB(a, r, g, b); 1537 } 1538 1539 /** 1540 * Draw the specified bitmap, with its top/left corner at (x,y), using the specified paint, 1541 * transformed by the current matrix. 1542 * <p> 1543 * Note: if the paint contains a maskfilter that generates a mask which extends beyond the 1544 * bitmap's original width/height (e.g. BlurMaskFilter), then the bitmap will be drawn as if it 1545 * were in a Shader with CLAMP mode. Thus the color outside of the original width/height will be 1546 * the edge color replicated. 1547 * <p> 1548 * If the bitmap and canvas have different densities, this function will take care of 1549 * automatically scaling the bitmap to draw at the same density as the canvas. 1550 * 1551 * @param bitmap The bitmap to be drawn 1552 * @param left The position of the left side of the bitmap being drawn 1553 * @param top The position of the top side of the bitmap being drawn 1554 * @param paint The paint used to draw the bitmap (may be null) 1555 */ 1556 public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) { 1557 super.drawBitmap(bitmap, left, top, paint); 1558 } 1559 1560 /** 1561 * Draw the specified bitmap, scaling/translating automatically to fill the destination 1562 * rectangle. If the source rectangle is not null, it specifies the subset of the bitmap to 1563 * draw. 1564 * <p> 1565 * Note: if the paint contains a maskfilter that generates a mask which extends beyond the 1566 * bitmap's original width/height (e.g. BlurMaskFilter), then the bitmap will be drawn as if it 1567 * were in a Shader with CLAMP mode. Thus the color outside of the original width/height will be 1568 * the edge color replicated. 1569 * <p> 1570 * This function <em>ignores the density associated with the bitmap</em>. This is because the 1571 * source and destination rectangle coordinate spaces are in their respective densities, so must 1572 * already have the appropriate scaling factor applied. 1573 * 1574 * @param bitmap The bitmap to be drawn 1575 * @param src May be null. The subset of the bitmap to be drawn 1576 * @param dst The rectangle that the bitmap will be scaled/translated to fit into 1577 * @param paint May be null. The paint used to draw the bitmap 1578 */ 1579 public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, 1580 @Nullable Paint paint) { 1581 super.drawBitmap(bitmap, src, dst, paint); 1582 } 1583 1584 /** 1585 * Draw the specified bitmap, scaling/translating automatically to fill the destination 1586 * rectangle. If the source rectangle is not null, it specifies the subset of the bitmap to 1587 * draw. 1588 * <p> 1589 * Note: if the paint contains a maskfilter that generates a mask which extends beyond the 1590 * bitmap's original width/height (e.g. BlurMaskFilter), then the bitmap will be drawn as if it 1591 * were in a Shader with CLAMP mode. Thus the color outside of the original width/height will be 1592 * the edge color replicated. 1593 * <p> 1594 * This function <em>ignores the density associated with the bitmap</em>. This is because the 1595 * source and destination rectangle coordinate spaces are in their respective densities, so must 1596 * already have the appropriate scaling factor applied. 1597 * 1598 * @param bitmap The bitmap to be drawn 1599 * @param src May be null. The subset of the bitmap to be drawn 1600 * @param dst The rectangle that the bitmap will be scaled/translated to fit into 1601 * @param paint May be null. The paint used to draw the bitmap 1602 */ 1603 public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, 1604 @Nullable Paint paint) { 1605 super.drawBitmap(bitmap, src, dst, paint); 1606 } 1607 1608 /** 1609 * Treat the specified array of colors as a bitmap, and draw it. This gives the same result as 1610 * first creating a bitmap from the array, and then drawing it, but this method avoids 1611 * explicitly creating a bitmap object which can be more efficient if the colors are changing 1612 * often. 1613 * 1614 * @param colors Array of colors representing the pixels of the bitmap 1615 * @param offset Offset into the array of colors for the first pixel 1616 * @param stride The number of colors in the array between rows (must be >= width or <= -width). 1617 * @param x The X coordinate for where to draw the bitmap 1618 * @param y The Y coordinate for where to draw the bitmap 1619 * @param width The width of the bitmap 1620 * @param height The height of the bitmap 1621 * @param hasAlpha True if the alpha channel of the colors contains valid values. If false, the 1622 * alpha byte is ignored (assumed to be 0xFF for every pixel). 1623 * @param paint May be null. The paint used to draw the bitmap 1624 * @deprecated Usage with a {@link #isHardwareAccelerated() hardware accelerated} canvas 1625 * requires an internal copy of color buffer contents every time this method is 1626 * called. Using a Bitmap avoids this copy, and allows the application to more 1627 * explicitly control the lifetime and copies of pixel data. 1628 */ 1629 @Deprecated 1630 public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y, 1631 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 1632 super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint); 1633 } 1634 1635 /** 1636 * Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y 1637 * 1638 * @deprecated Usage with a {@link #isHardwareAccelerated() hardware accelerated} canvas 1639 * requires an internal copy of color buffer contents every time this method is 1640 * called. Using a Bitmap avoids this copy, and allows the application to more 1641 * explicitly control the lifetime and copies of pixel data. 1642 */ 1643 @Deprecated 1644 public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y, 1645 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 1646 super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint); 1647 } 1648 1649 /** 1650 * Draw the bitmap using the specified matrix. 1651 * 1652 * @param bitmap The bitmap to draw 1653 * @param matrix The matrix used to transform the bitmap when it is drawn 1654 * @param paint May be null. The paint used to draw the bitmap 1655 */ 1656 public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) { 1657 super.drawBitmap(bitmap, matrix, paint); 1658 } 1659 1660 /** 1661 * Draw the bitmap through the mesh, where mesh vertices are evenly distributed across the 1662 * bitmap. There are meshWidth+1 vertices across, and meshHeight+1 vertices down. The verts 1663 * array is accessed in row-major order, so that the first meshWidth+1 vertices are distributed 1664 * across the top of the bitmap from left to right. A more general version of this method is 1665 * drawVertices(). 1666 * 1667 * Prior to API level {@value Build.VERSION_CODES#P} vertOffset and colorOffset were ignored, 1668 * effectively treating them as zeros. In API level {@value Build.VERSION_CODES#P} and above 1669 * these parameters will be respected. 1670 * 1671 * @param bitmap The bitmap to draw using the mesh 1672 * @param meshWidth The number of columns in the mesh. Nothing is drawn if this is 0 1673 * @param meshHeight The number of rows in the mesh. Nothing is drawn if this is 0 1674 * @param verts Array of x,y pairs, specifying where the mesh should be drawn. There must be at 1675 * least (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values in the array 1676 * @param vertOffset Number of verts elements to skip before drawing 1677 * @param colors May be null. Specifies a color at each vertex, which is interpolated across the 1678 * cell, and whose values are multiplied by the corresponding bitmap colors. If not 1679 * null, there must be at least (meshWidth+1) * (meshHeight+1) + colorOffset values 1680 * in the array. 1681 * @param colorOffset Number of color elements to skip before drawing 1682 * @param paint May be null. The paint used to draw the bitmap 1683 */ 1684 public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight, 1685 @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, 1686 @Nullable Paint paint) { 1687 super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, 1688 paint); 1689 } 1690 1691 /** 1692 * Draw the specified circle using the specified paint. If radius is <= 0, then nothing will be 1693 * drawn. The circle will be filled or framed based on the Style in the paint. 1694 * 1695 * @param cx The x-coordinate of the center of the circle to be drawn 1696 * @param cy The y-coordinate of the center of the circle to be drawn 1697 * @param radius The radius of the circle to be drawn 1698 * @param paint The paint used to draw the circle 1699 */ 1700 public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) { 1701 super.drawCircle(cx, cy, radius, paint); 1702 } 1703 1704 /** 1705 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color, 1706 * using srcover porterduff mode. 1707 * 1708 * @param color the color to draw onto the canvas 1709 */ 1710 public void drawColor(@ColorInt int color) { 1711 super.drawColor(color); 1712 } 1713 1714 /** 1715 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color, 1716 * using srcover porterduff mode. 1717 * 1718 * @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color} 1719 * class for details about {@code ColorLong}s. 1720 * @throws IllegalArgumentException if the color space encoded in the {@code ColorLong} 1721 * is invalid or unknown. 1722 */ 1723 public void drawColor(@ColorLong long color) { 1724 super.drawColor(color, BlendMode.SRC_OVER); 1725 } 1726 1727 /** 1728 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and 1729 * porter-duff xfermode. 1730 * 1731 * @param color the color to draw onto the canvas 1732 * @param mode the porter-duff mode to apply to the color 1733 */ 1734 public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { 1735 super.drawColor(color, mode); 1736 } 1737 1738 /** 1739 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and 1740 * blendmode. 1741 * 1742 * @param color the color to draw onto the canvas 1743 * @param mode the blendmode to apply to the color 1744 */ 1745 public void drawColor(@ColorInt int color, @NonNull BlendMode mode) { 1746 super.drawColor(color, mode); 1747 } 1748 1749 /** 1750 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and 1751 * blendmode. 1752 * 1753 * @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color} 1754 * class for details about {@code ColorLong}s. 1755 * @param mode the blendmode to apply to the color 1756 * @throws IllegalArgumentException if the color space encoded in the {@code ColorLong} 1757 * is invalid or unknown. 1758 */ 1759 public void drawColor(@ColorLong long color, @NonNull BlendMode mode) { 1760 super.drawColor(color, mode); 1761 } 1762 1763 /** 1764 * Draw a line segment with the specified start and stop x,y coordinates, using the specified 1765 * paint. 1766 * <p> 1767 * Note that since a line is always "framed", the Style is ignored in the paint. 1768 * </p> 1769 * <p> 1770 * Degenerate lines (length is 0) will not be drawn. 1771 * </p> 1772 * 1773 * @param startX The x-coordinate of the start point of the line 1774 * @param startY The y-coordinate of the start point of the line 1775 * @param paint The paint used to draw the line 1776 */ 1777 public void drawLine(float startX, float startY, float stopX, float stopY, 1778 @NonNull Paint paint) { 1779 super.drawLine(startX, startY, stopX, stopY, paint); 1780 } 1781 1782 /** 1783 * Draw a series of lines. Each line is taken from 4 consecutive values in the pts array. Thus 1784 * to draw 1 line, the array must contain at least 4 values. This is logically the same as 1785 * drawing the array as follows: drawLine(pts[0], pts[1], pts[2], pts[3]) followed by 1786 * drawLine(pts[4], pts[5], pts[6], pts[7]) and so on. 1787 * 1788 * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...] 1789 * @param offset Number of values in the array to skip before drawing. 1790 * @param count The number of values in the array to process, after skipping "offset" of them. 1791 * Since each line uses 4 values, the number of "lines" that are drawn is really 1792 * (count >> 2). 1793 * @param paint The paint used to draw the points 1794 */ 1795 public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count, 1796 @NonNull Paint paint) { 1797 super.drawLines(pts, offset, count, paint); 1798 } 1799 1800 public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) { 1801 super.drawLines(pts, paint); 1802 } 1803 1804 /** 1805 * Draw the specified oval using the specified paint. The oval will be filled or framed based on 1806 * the Style in the paint. 1807 * 1808 * @param oval The rectangle bounds of the oval to be drawn 1809 */ 1810 public void drawOval(@NonNull RectF oval, @NonNull Paint paint) { 1811 super.drawOval(oval, paint); 1812 } 1813 1814 /** 1815 * Draw the specified oval using the specified paint. The oval will be filled or framed based on 1816 * the Style in the paint. 1817 */ 1818 public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) { 1819 super.drawOval(left, top, right, bottom, paint); 1820 } 1821 1822 /** 1823 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified paint. 1824 * This is equivalent (but faster) to drawing an infinitely large rectangle with the specified 1825 * paint. 1826 * 1827 * @param paint The paint used to draw onto the canvas 1828 */ 1829 public void drawPaint(@NonNull Paint paint) { 1830 super.drawPaint(paint); 1831 } 1832 1833 /** 1834 * Draws the specified bitmap as an N-patch (most often, a 9-patch.) 1835 * 1836 * @param patch The ninepatch object to render 1837 * @param dst The destination rectangle. 1838 * @param paint The paint to draw the bitmap with. may be null 1839 */ 1840 public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) { 1841 super.drawPatch(patch, dst, paint); 1842 } 1843 1844 /** 1845 * Draws the specified bitmap as an N-patch (most often, a 9-patch.) 1846 * 1847 * @param patch The ninepatch object to render 1848 * @param dst The destination rectangle. 1849 * @param paint The paint to draw the bitmap with. may be null 1850 */ 1851 public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) { 1852 super.drawPatch(patch, dst, paint); 1853 } 1854 1855 /** 1856 * Draw the specified path using the specified paint. The path will be filled or framed based on 1857 * the Style in the paint. 1858 * 1859 * @param path The path to be drawn 1860 * @param paint The paint used to draw the path 1861 */ 1862 public void drawPath(@NonNull Path path, @NonNull Paint paint) { 1863 super.drawPath(path, paint); 1864 } 1865 1866 /** 1867 * Helper for drawPoints() for drawing a single point. 1868 */ 1869 public void drawPoint(float x, float y, @NonNull Paint paint) { 1870 super.drawPoint(x, y, paint); 1871 } 1872 1873 /** 1874 * Draw a series of points. Each point is centered at the coordinate specified by pts[], and its 1875 * diameter is specified by the paint's stroke width (as transformed by the canvas' CTM), with 1876 * special treatment for a stroke width of 0, which always draws exactly 1 pixel (or at most 4 1877 * if antialiasing is enabled). The shape of the point is controlled by the paint's Cap type. 1878 * The shape is a square, unless the cap type is Round, in which case the shape is a circle. 1879 * 1880 * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...] 1881 * @param offset Number of values to skip before starting to draw. 1882 * @param count The number of values to process, after skipping offset of them. Since one point 1883 * uses two values, the number of "points" that are drawn is really (count >> 1). 1884 * @param paint The paint used to draw the points 1885 */ 1886 public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count, 1887 @NonNull Paint paint) { 1888 super.drawPoints(pts, offset, count, paint); 1889 } 1890 1891 /** 1892 * Helper for drawPoints() that assumes you want to draw the entire array 1893 */ 1894 public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) { 1895 super.drawPoints(pts, paint); 1896 } 1897 1898 /** 1899 * Draw the text in the array, with each character's origin specified by the pos array. 1900 * 1901 * @param text The text to be drawn 1902 * @param index The index of the first character to draw 1903 * @param count The number of characters to draw, starting from index. 1904 * @param pos Array of [x,y] positions, used to position each character 1905 * @param paint The paint used for the text (e.g. color, size, style) 1906 * @deprecated This method does not support glyph composition and decomposition and should 1907 * therefore not be used to render complex scripts. It also doesn't handle 1908 * supplementary characters (eg emoji). 1909 */ 1910 @Deprecated 1911 public void drawPosText(@NonNull char[] text, int index, int count, 1912 @NonNull @Size(multiple = 2) float[] pos, 1913 @NonNull Paint paint) { 1914 super.drawPosText(text, index, count, pos, paint); 1915 } 1916 1917 /** 1918 * Draw the text in the array, with each character's origin specified by the pos array. 1919 * 1920 * @param text The text to be drawn 1921 * @param pos Array of [x,y] positions, used to position each character 1922 * @param paint The paint used for the text (e.g. color, size, style) 1923 * @deprecated This method does not support glyph composition and decomposition and should 1924 * therefore not be used to render complex scripts. It also doesn't handle 1925 * supplementary characters (eg emoji). 1926 */ 1927 @Deprecated 1928 public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos, 1929 @NonNull Paint paint) { 1930 super.drawPosText(text, pos, paint); 1931 } 1932 1933 /** 1934 * Draw the specified Rect using the specified paint. The rectangle will be filled or framed 1935 * based on the Style in the paint. 1936 * 1937 * @param rect The rect to be drawn 1938 * @param paint The paint used to draw the rect 1939 */ 1940 public void drawRect(@NonNull RectF rect, @NonNull Paint paint) { 1941 super.drawRect(rect, paint); 1942 } 1943 1944 /** 1945 * Draw the specified Rect using the specified Paint. The rectangle will be filled or framed 1946 * based on the Style in the paint. 1947 * 1948 * @param r The rectangle to be drawn. 1949 * @param paint The paint used to draw the rectangle 1950 */ 1951 public void drawRect(@NonNull Rect r, @NonNull Paint paint) { 1952 super.drawRect(r, paint); 1953 } 1954 1955 /** 1956 * Draw the specified Rect using the specified paint. The rectangle will be filled or framed 1957 * based on the Style in the paint. 1958 * 1959 * @param left The left side of the rectangle to be drawn 1960 * @param top The top side of the rectangle to be drawn 1961 * @param right The right side of the rectangle to be drawn 1962 * @param bottom The bottom side of the rectangle to be drawn 1963 * @param paint The paint used to draw the rect 1964 */ 1965 public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) { 1966 super.drawRect(left, top, right, bottom, paint); 1967 } 1968 1969 /** 1970 * Fill the entire canvas' bitmap (restricted to the current clip) with the specified RGB color, 1971 * using srcover porterduff mode. 1972 * 1973 * @param r red component (0..255) of the color to draw onto the canvas 1974 * @param g green component (0..255) of the color to draw onto the canvas 1975 * @param b blue component (0..255) of the color to draw onto the canvas 1976 */ 1977 public void drawRGB(int r, int g, int b) { 1978 super.drawRGB(r, g, b); 1979 } 1980 1981 /** 1982 * Draw the specified round-rect using the specified paint. The roundrect will be filled or 1983 * framed based on the Style in the paint. 1984 * 1985 * @param rect The rectangular bounds of the roundRect to be drawn 1986 * @param rx The x-radius of the oval used to round the corners 1987 * @param ry The y-radius of the oval used to round the corners 1988 * @param paint The paint used to draw the roundRect 1989 */ 1990 public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { 1991 super.drawRoundRect(rect, rx, ry, paint); 1992 } 1993 1994 /** 1995 * Draw the specified round-rect using the specified paint. The roundrect will be filled or 1996 * framed based on the Style in the paint. 1997 * 1998 * @param rx The x-radius of the oval used to round the corners 1999 * @param ry The y-radius of the oval used to round the corners 2000 * @param paint The paint used to draw the roundRect 2001 */ 2002 public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, 2003 @NonNull Paint paint) { 2004 super.drawRoundRect(left, top, right, bottom, rx, ry, paint); 2005 } 2006 2007 /** 2008 * Draws a double rounded rectangle using the specified paint. The resultant round rect 2009 * will be filled in the area defined between the outer and inner rectangular bounds if 2010 * the {@link Paint} configured with {@link Paint.Style#FILL}. 2011 * Otherwise if {@link Paint.Style#STROKE} is used, then 2 rounded rect strokes will 2012 * be drawn at the outer and inner rounded rectangles 2013 * 2014 * @param outer The outer rectangular bounds of the roundRect to be drawn 2015 * @param outerRx The x-radius of the oval used to round the corners on the outer rectangle 2016 * @param outerRy The y-radius of the oval used to round the corners on the outer rectangle 2017 * @param inner The inner rectangular bounds of the roundRect to be drawn 2018 * @param innerRx The x-radius of the oval used to round the corners on the inner rectangle 2019 * @param innerRy The y-radius of the oval used to round the corners on the outer rectangle 2020 * @param paint The paint used to draw the double roundRect 2021 */ 2022 @Override 2023 public void drawDoubleRoundRect(@NonNull RectF outer, float outerRx, float outerRy, 2024 @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint) { 2025 super.drawDoubleRoundRect(outer, outerRx, outerRy, inner, innerRx, innerRy, paint); 2026 } 2027 2028 /** 2029 * Draws a double rounded rectangle using the specified paint. The resultant round rect 2030 * will be filled in the area defined between the outer and inner rectangular bounds if 2031 * the {@link Paint} configured with {@link Paint.Style#FILL}. 2032 * Otherwise if {@link Paint.Style#STROKE} is used, then 2 rounded rect strokes will 2033 * be drawn at the outer and inner rounded rectangles 2034 * 2035 * @param outer The outer rectangular bounds of the roundRect to be drawn 2036 * @param outerRadii Array of 8 float representing the x, y corner radii for top left, 2037 * top right, bottom right, bottom left corners respectively on the outer 2038 * rounded rectangle 2039 * 2040 * @param inner The inner rectangular bounds of the roundRect to be drawn 2041 * @param innerRadii Array of 8 float representing the x, y corner radii for top left, 2042 * top right, bottom right, bottom left corners respectively on the 2043 * outer rounded rectangle 2044 * @param paint The paint used to draw the double roundRect 2045 */ 2046 @Override 2047 public void drawDoubleRoundRect(@NonNull RectF outer, @NonNull float[] outerRadii, 2048 @NonNull RectF inner, @NonNull float[] innerRadii, @NonNull Paint paint) { 2049 super.drawDoubleRoundRect(outer, outerRadii, inner, innerRadii, paint); 2050 } 2051 2052 /** 2053 * Draw array of glyphs with specified font. 2054 * 2055 * @param glyphIds Array of glyph IDs. The length of array must be greater than or equal to 2056 * {@code glyphIdOffset + glyphCount}. 2057 * @param glyphIdOffset Number of elements to skip before drawing in <code>glyphIds</code> 2058 * array. 2059 * @param positions A flattened X and Y position array. The first glyph X position must be 2060 * stored at {@code positionOffset}. The first glyph Y position must be stored 2061 * at {@code positionOffset + 1}, then the second glyph X position must be 2062 * stored at {@code positionOffset + 2}. 2063 * The length of array must be greater than or equal to 2064 * {@code positionOffset + glyphCount * 2}. 2065 * @param positionOffset Number of elements to skip before drawing in {@code positions}. 2066 * The first glyph X position must be stored at {@code positionOffset}. 2067 * The first glyph Y position must be stored at 2068 * {@code positionOffset + 1}, then the second glyph X position must be 2069 * stored at {@code positionOffset + 2}. 2070 * @param glyphCount Number of glyphs to be drawn. 2071 * @param font Font used for drawing. 2072 * @param paint Paint used for drawing. The typeface set to this paint is ignored. 2073 * 2074 * @see TextRunShaper 2075 * @see TextShaper 2076 */ 2077 public void drawGlyphs( 2078 @NonNull int[] glyphIds, 2079 @IntRange(from = 0) int glyphIdOffset, 2080 @NonNull float[] positions, 2081 @IntRange(from = 0) int positionOffset, 2082 @IntRange(from = 0) int glyphCount, 2083 @NonNull Font font, 2084 @NonNull Paint paint) { 2085 super.drawGlyphs(glyphIds, glyphIdOffset, positions, positionOffset, glyphCount, font, 2086 paint); 2087 } 2088 2089 /** 2090 * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted 2091 * based on the Align setting in the paint. 2092 * 2093 * @param text The text to be drawn 2094 * @param x The x-coordinate of the origin of the text being drawn 2095 * @param y The y-coordinate of the baseline of the text being drawn 2096 * @param paint The paint used for the text (e.g. color, size, style) 2097 */ 2098 public void drawText(@NonNull char[] text, int index, int count, float x, float y, 2099 @NonNull Paint paint) { 2100 super.drawText(text, index, count, x, y, paint); 2101 } 2102 2103 /** 2104 * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted 2105 * based on the Align setting in the paint. 2106 * 2107 * @param text The text to be drawn 2108 * @param x The x-coordinate of the origin of the text being drawn 2109 * @param y The y-coordinate of the baseline of the text being drawn 2110 * @param paint The paint used for the text (e.g. color, size, style) 2111 */ 2112 public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { 2113 super.drawText(text, x, y, paint); 2114 } 2115 2116 /** 2117 * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted 2118 * based on the Align setting in the paint. 2119 * 2120 * @param text The text to be drawn 2121 * @param start The index of the first character in text to draw 2122 * @param end (end - 1) is the index of the last character in text to draw 2123 * @param x The x-coordinate of the origin of the text being drawn 2124 * @param y The y-coordinate of the baseline of the text being drawn 2125 * @param paint The paint used for the text (e.g. color, size, style) 2126 */ 2127 public void drawText(@NonNull String text, int start, int end, float x, float y, 2128 @NonNull Paint paint) { 2129 super.drawText(text, start, end, x, y, paint); 2130 } 2131 2132 /** 2133 * Draw the specified range of text, specified by start/end, with its origin at (x,y), in the 2134 * specified Paint. The origin is interpreted based on the Align setting in the Paint. 2135 * 2136 * @param text The text to be drawn 2137 * @param start The index of the first character in text to draw 2138 * @param end (end - 1) is the index of the last character in text to draw 2139 * @param x The x-coordinate of origin for where to draw the text 2140 * @param y The y-coordinate of origin for where to draw the text 2141 * @param paint The paint used for the text (e.g. color, size, style) 2142 */ 2143 public void drawText(@NonNull CharSequence text, int start, int end, float x, float y, 2144 @NonNull Paint paint) { 2145 super.drawText(text, start, end, x, y, paint); 2146 } 2147 2148 /** 2149 * Draw the text, with origin at (x,y), using the specified paint, along the specified path. The 2150 * paint's Align setting determines where along the path to start the text. 2151 * 2152 * @param text The text to be drawn 2153 * @param index The starting index within the text to be drawn 2154 * @param count Starting from index, the number of characters to draw 2155 * @param path The path the text should follow for its baseline 2156 * @param hOffset The distance along the path to add to the text's starting position 2157 * @param vOffset The distance above(-) or below(+) the path to position the text 2158 * @param paint The paint used for the text (e.g. color, size, style) 2159 */ 2160 public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path, 2161 float hOffset, float vOffset, @NonNull Paint paint) { 2162 super.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint); 2163 } 2164 2165 /** 2166 * Draw the text, with origin at (x,y), using the specified paint, along the specified path. The 2167 * paint's Align setting determines where along the path to start the text. 2168 * 2169 * @param text The text to be drawn 2170 * @param path The path the text should follow for its baseline 2171 * @param hOffset The distance along the path to add to the text's starting position 2172 * @param vOffset The distance above(-) or below(+) the path to position the text 2173 * @param paint The paint used for the text (e.g. color, size, style) 2174 */ 2175 public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, 2176 float vOffset, @NonNull Paint paint) { 2177 super.drawTextOnPath(text, path, hOffset, vOffset, paint); 2178 } 2179 2180 /** 2181 * Draw a run of text, all in a single direction, with optional context for complex text 2182 * shaping. 2183 * <p> 2184 * See {@link #drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} for 2185 * more details. This method uses a character array rather than CharSequence to represent the 2186 * string. Also, to be consistent with the pattern established in {@link #drawText}, in this 2187 * method {@code count} and {@code contextCount} are used rather than offsets of the end 2188 * position; {@code count = end - start, contextCount = contextEnd - 2189 * contextStart}. 2190 * 2191 * @param text the text to render 2192 * @param index the start of the text to render 2193 * @param count the count of chars to render 2194 * @param contextIndex the start of the context for shaping. Must be no greater than index. 2195 * @param contextCount the number of characters in the context for shaping. contexIndex + 2196 * contextCount must be no less than index + count. 2197 * @param x the x position at which to draw the text 2198 * @param y the y position at which to draw the text 2199 * @param isRtl whether the run is in RTL direction 2200 * @param paint the paint 2201 */ 2202 public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, 2203 int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) { 2204 super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, isRtl, paint); 2205 } 2206 2207 /** 2208 * Draw a run of text, all in a single direction, with optional context for complex text 2209 * shaping. 2210 * <p> 2211 * The run of text includes the characters from {@code start} to {@code end} in the text. In 2212 * addition, the range {@code contextStart} to {@code contextEnd} is used as context for the 2213 * purpose of complex text shaping, such as Arabic text potentially shaped differently based on 2214 * the text next to it. 2215 * <p> 2216 * All text outside the range {@code contextStart..contextEnd} is ignored. The text between 2217 * {@code start} and {@code end} will be laid out and drawn. The context range is useful for 2218 * contextual shaping, e.g. Kerning, Arabic contextural form. 2219 * <p> 2220 * The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is 2221 * suitable only for runs of a single direction. Alignment of the text is as determined by the 2222 * Paint's TextAlign value. Further, {@code 0 <= contextStart <= start <= end <= contextEnd 2223 * <= text.length} must hold on entry. 2224 * <p> 2225 * Also see {@link android.graphics.Paint#getRunAdvance} for a corresponding method to measure 2226 * the text; the advance width of the text drawn matches the value obtained from that method. 2227 * 2228 * @param text the text to render 2229 * @param start the start of the text to render. Data before this position can be used for 2230 * shaping context. 2231 * @param end the end of the text to render. Data at or after this position can be used for 2232 * shaping context. 2233 * @param contextStart the index of the start of the shaping context 2234 * @param contextEnd the index of the end of the shaping context 2235 * @param x the x position at which to draw the text 2236 * @param y the y position at which to draw the text 2237 * @param isRtl whether the run is in RTL direction 2238 * @param paint the paint 2239 * @see #drawTextRun(char[], int, int, int, int, float, float, boolean, Paint) 2240 */ 2241 public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, 2242 int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { 2243 super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, isRtl, paint); 2244 } 2245 2246 /** 2247 * Draw a run of text, all in a single direction, with optional context for complex text 2248 * shaping. 2249 * <p> 2250 * See {@link #drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} for 2251 * more details. This method uses a {@link MeasuredText} rather than CharSequence to represent 2252 * the string. 2253 * 2254 * @param text the text to render 2255 * @param start the start of the text to render. Data before this position can be used for 2256 * shaping context. 2257 * @param end the end of the text to render. Data at or after this position can be used for 2258 * shaping context. 2259 * @param contextStart the index of the start of the shaping context 2260 * @param contextEnd the index of the end of the shaping context 2261 * @param x the x position at which to draw the text 2262 * @param y the y position at which to draw the text 2263 * @param isRtl whether the run is in RTL direction 2264 * @param paint the paint 2265 */ 2266 public void drawTextRun(@NonNull MeasuredText text, int start, int end, int contextStart, 2267 int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { 2268 super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, isRtl, paint); 2269 } 2270 2271 /** 2272 * Draw the array of vertices, interpreted as triangles (based on mode). The verts array is 2273 * required, and specifies the x,y pairs for each vertex. If texs is non-null, then it is used 2274 * to specify the coordinate in shader coordinates to use at each vertex (the paint must have a 2275 * shader in this case). If there is no texs array, but there is a color array, then each color 2276 * is interpolated across its corresponding triangle in a gradient. If both texs and colors 2277 * arrays are present, then they behave as before, but the resulting color at each pixels is the 2278 * result of multiplying the colors from the shader and the color-gradient together. The indices 2279 * array is optional, but if it is present, then it is used to specify the index of each 2280 * triangle, rather than just walking through the arrays in order. 2281 * 2282 * @param mode How to interpret the array of vertices 2283 * @param vertexCount The number of values in the vertices array (and corresponding texs and 2284 * colors arrays if non-null). Each logical vertex is two values (x, y), vertexCount 2285 * must be a multiple of 2. 2286 * @param verts Array of vertices for the mesh 2287 * @param vertOffset Number of values in the verts to skip before drawing. 2288 * @param texs May be null. If not null, specifies the coordinates to sample into the current 2289 * shader (e.g. bitmap tile or gradient) 2290 * @param texOffset Number of values in texs to skip before drawing. 2291 * @param colors May be null. If not null, specifies a color for each vertex, to be interpolated 2292 * across the triangle. 2293 * @param colorOffset Number of values in colors to skip before drawing. 2294 * @param indices If not null, array of indices to reference into the vertex (texs, colors) 2295 * array. 2296 * @param indexCount number of entries in the indices array (if not null). 2297 * @param paint Specifies the shader to use if the texs array is non-null. 2298 */ 2299 public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts, 2300 int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, 2301 int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, 2302 @NonNull Paint paint) { 2303 super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, 2304 colors, colorOffset, indices, indexOffset, indexCount, paint); 2305 } 2306 2307 /** 2308 * Draws the given RenderNode. This is only supported in hardware rendering, which can be 2309 * verified by asserting that {@link #isHardwareAccelerated()} is true. If 2310 * {@link #isHardwareAccelerated()} is false then this throws an exception. 2311 * 2312 * See {@link RenderNode} for more information on what a RenderNode is and how to use it. 2313 * 2314 * @param renderNode The RenderNode to draw, must be non-null. 2315 */ 2316 public void drawRenderNode(@NonNull RenderNode renderNode) { 2317 throw new IllegalArgumentException("Software rendering doesn't support drawRenderNode"); 2318 } 2319 } 2320