Canvas.java revision 96890564bdbd2f2a41dfc323fc8b3938fb335639
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 17package android.graphics; 18 19import android.annotation.IntDef; 20import android.annotation.NonNull; 21import android.annotation.Nullable; 22import android.text.GraphicsOperations; 23import android.text.SpannableString; 24import android.text.SpannedString; 25import android.text.TextUtils; 26 27import java.lang.annotation.Retention; 28import java.lang.annotation.RetentionPolicy; 29 30import javax.microedition.khronos.opengles.GL; 31 32/** 33 * The Canvas class holds the "draw" calls. To draw something, you need 34 * 4 basic components: A Bitmap to hold the pixels, a Canvas to host 35 * the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, 36 * Path, text, Bitmap), and a paint (to describe the colors and styles for the 37 * drawing). 38 * 39 * <div class="special reference"> 40 * <h3>Developer Guides</h3> 41 * <p>For more information about how to use Canvas, read the 42 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html"> 43 * Canvas and Drawables</a> developer guide.</p></div> 44 */ 45public class Canvas { 46 47 // assigned in constructors or setBitmap, freed in finalizer 48 private long mNativeCanvasWrapper; 49 50 /** @hide */ 51 public long getNativeCanvasWrapper() { 52 return mNativeCanvasWrapper; 53 } 54 55 /** @hide */ 56 public boolean isRecordingFor(Object o) { return false; } 57 58 // may be null 59 private Bitmap mBitmap; 60 61 // optional field set by the caller 62 private DrawFilter mDrawFilter; 63 64 /** 65 * @hide 66 */ 67 protected int mDensity = Bitmap.DENSITY_NONE; 68 69 /** 70 * Used to determine when compatibility scaling is in effect. 71 * 72 * @hide 73 */ 74 protected int mScreenDensity = Bitmap.DENSITY_NONE; 75 76 // Used by native code 77 @SuppressWarnings("UnusedDeclaration") 78 private int mSurfaceFormat; 79 80 /** 81 * Flag for drawTextRun indicating left-to-right run direction. 82 * @hide 83 */ 84 public static final int DIRECTION_LTR = 0; 85 86 /** 87 * Flag for drawTextRun indicating right-to-left run direction. 88 * @hide 89 */ 90 public static final int DIRECTION_RTL = 1; 91 92 // Maximum bitmap size as defined in Skia's native code 93 // (see SkCanvas.cpp, SkDraw.cpp) 94 private static final int MAXMIMUM_BITMAP_SIZE = 32766; 95 96 // This field is used to finalize the native Canvas properly 97 private final CanvasFinalizer mFinalizer; 98 99 private static final class CanvasFinalizer { 100 private long mNativeCanvasWrapper; 101 102 public CanvasFinalizer(long nativeCanvas) { 103 mNativeCanvasWrapper = nativeCanvas; 104 } 105 106 @Override 107 protected void finalize() throws Throwable { 108 try { 109 dispose(); 110 } finally { 111 super.finalize(); 112 } 113 } 114 115 public void dispose() { 116 if (mNativeCanvasWrapper != 0) { 117 finalizer(mNativeCanvasWrapper); 118 mNativeCanvasWrapper = 0; 119 } 120 } 121 } 122 123 /** 124 * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to 125 * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; 126 * this will typically be replaced when a target bitmap is set for the 127 * canvas. 128 */ 129 public Canvas() { 130 if (!isHardwareAccelerated()) { 131 // 0 means no native bitmap 132 mNativeCanvasWrapper = initRaster(0); 133 mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper); 134 } else { 135 mFinalizer = null; 136 } 137 } 138 139 /** 140 * Construct a canvas with the specified bitmap to draw into. The bitmap 141 * must be mutable. 142 * 143 * <p>The initial target density of the canvas is the same as the given 144 * bitmap's density. 145 * 146 * @param bitmap Specifies a mutable bitmap for the canvas to draw into. 147 */ 148 public Canvas(@NonNull Bitmap bitmap) { 149 if (!bitmap.isMutable()) { 150 throw new IllegalStateException("Immutable bitmap passed to Canvas constructor"); 151 } 152 throwIfCannotDraw(bitmap); 153 mNativeCanvasWrapper = initRaster(bitmap.ni()); 154 mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper); 155 mBitmap = bitmap; 156 mDensity = bitmap.mDensity; 157 } 158 159 /** @hide */ 160 public Canvas(long nativeCanvas) { 161 if (nativeCanvas == 0) { 162 throw new IllegalStateException(); 163 } 164 mNativeCanvasWrapper = nativeCanvas; 165 mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper); 166 mDensity = Bitmap.getDefaultDensity(); 167 } 168 169 /** 170 * Returns null. 171 * 172 * @deprecated This method is not supported and should not be invoked. 173 * 174 * @hide 175 */ 176 @Deprecated 177 protected GL getGL() { 178 return null; 179 } 180 181 /** 182 * Indicates whether this Canvas uses hardware acceleration. 183 * 184 * Note that this method does not define what type of hardware acceleration 185 * may or may not be used. 186 * 187 * @return True if drawing operations are hardware accelerated, 188 * false otherwise. 189 */ 190 public boolean isHardwareAccelerated() { 191 return false; 192 } 193 194 /** 195 * Specify a bitmap for the canvas to draw into. All canvas state such as 196 * layers, filters, and the save/restore stack are reset with the exception 197 * of the current matrix and clip stack. Additionally, as a side-effect 198 * the canvas' target density is updated to match that of the bitmap. 199 * 200 * @param bitmap Specifies a mutable bitmap for the canvas to draw into. 201 * @see #setDensity(int) 202 * @see #getDensity() 203 */ 204 public void setBitmap(@Nullable Bitmap bitmap) { 205 if (isHardwareAccelerated()) { 206 throw new RuntimeException("Can't set a bitmap device on a HW accelerated canvas"); 207 } 208 209 if (bitmap == null) { 210 native_setBitmap(mNativeCanvasWrapper, 0, false); 211 mDensity = Bitmap.DENSITY_NONE; 212 } else { 213 if (!bitmap.isMutable()) { 214 throw new IllegalStateException(); 215 } 216 throwIfCannotDraw(bitmap); 217 218 native_setBitmap(mNativeCanvasWrapper, bitmap.ni(), true); 219 mDensity = bitmap.mDensity; 220 } 221 222 mBitmap = bitmap; 223 } 224 225 /** 226 * setBitmap() variant for native callers with a raw bitmap handle. 227 */ 228 private void setNativeBitmap(long bitmapHandle) { 229 native_setBitmap(mNativeCanvasWrapper, bitmapHandle, false); 230 } 231 232 /** 233 * Set the viewport dimensions if this canvas is GL based. If it is not, 234 * this method is ignored and no exception is thrown. 235 * 236 * @param width The width of the viewport 237 * @param height The height of the viewport 238 * 239 * @hide 240 */ 241 public void setViewport(int width, int height) {} 242 243 /** @hide */ 244 public void setHighContrastText(boolean highContrastText) {} 245 246 /** @hide */ 247 public void insertReorderBarrier() {} 248 249 /** @hide */ 250 public void insertInorderBarrier() {} 251 252 /** 253 * @hide 254 */ 255 public void initializeLight(float lightX, float lightY, float lightZ, float lightRadius) {} 256 257 /** 258 * Return true if the device that the current layer draws into is opaque 259 * (i.e. does not support per-pixel alpha). 260 * 261 * @return true if the device that the current layer draws into is opaque 262 */ 263 public boolean isOpaque() { 264 return native_isOpaque(mNativeCanvasWrapper); 265 } 266 267 /** 268 * Returns the width of the current drawing layer 269 * 270 * @return the width of the current drawing layer 271 */ 272 public int getWidth() { 273 return native_getWidth(mNativeCanvasWrapper); 274 } 275 276 /** 277 * Returns the height of the current drawing layer 278 * 279 * @return the height of the current drawing layer 280 */ 281 public int getHeight() { 282 return native_getHeight(mNativeCanvasWrapper); 283 } 284 285 /** 286 * <p>Returns the target density of the canvas. The default density is 287 * derived from the density of its backing bitmap, or 288 * {@link Bitmap#DENSITY_NONE} if there is not one.</p> 289 * 290 * @return Returns the current target density of the canvas, which is used 291 * to determine the scaling factor when drawing a bitmap into it. 292 * 293 * @see #setDensity(int) 294 * @see Bitmap#getDensity() 295 */ 296 public int getDensity() { 297 return mDensity; 298 } 299 300 /** 301 * <p>Specifies the density for this Canvas' backing bitmap. This modifies 302 * the target density of the canvas itself, as well as the density of its 303 * backing bitmap via {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}. 304 * 305 * @param density The new target density of the canvas, which is used 306 * to determine the scaling factor when drawing a bitmap into it. Use 307 * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling. 308 * 309 * @see #getDensity() 310 * @see Bitmap#setDensity(int) 311 */ 312 public void setDensity(int density) { 313 if (mBitmap != null) { 314 mBitmap.setDensity(density); 315 } 316 mDensity = density; 317 } 318 319 /** @hide */ 320 public void setScreenDensity(int density) { 321 mScreenDensity = density; 322 } 323 324 /** 325 * Returns the maximum allowed width for bitmaps drawn with this canvas. 326 * Attempting to draw with a bitmap wider than this value will result 327 * in an error. 328 * 329 * @see #getMaximumBitmapHeight() 330 */ 331 public int getMaximumBitmapWidth() { 332 return MAXMIMUM_BITMAP_SIZE; 333 } 334 335 /** 336 * Returns the maximum allowed height for bitmaps drawn with this canvas. 337 * Attempting to draw with a bitmap taller than this value will result 338 * in an error. 339 * 340 * @see #getMaximumBitmapWidth() 341 */ 342 public int getMaximumBitmapHeight() { 343 return MAXMIMUM_BITMAP_SIZE; 344 } 345 346 // the SAVE_FLAG constants must match their native equivalents 347 348 /** @hide */ 349 @IntDef(flag = true, 350 value = { 351 MATRIX_SAVE_FLAG, 352 CLIP_SAVE_FLAG, 353 HAS_ALPHA_LAYER_SAVE_FLAG, 354 FULL_COLOR_LAYER_SAVE_FLAG, 355 CLIP_TO_LAYER_SAVE_FLAG, 356 ALL_SAVE_FLAG 357 }) 358 @Retention(RetentionPolicy.SOURCE) 359 public @interface Saveflags {} 360 361 /** restore the current matrix when restore() is called */ 362 public static final int MATRIX_SAVE_FLAG = 0x01; 363 /** restore the current clip when restore() is called */ 364 public static final int CLIP_SAVE_FLAG = 0x02; 365 /** the layer needs to per-pixel alpha */ 366 public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04; 367 /** the layer needs to 8-bits per color component */ 368 public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08; 369 /** clip against the layer's bounds */ 370 public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10; 371 /** restore everything when restore() is called */ 372 public static final int ALL_SAVE_FLAG = 0x1F; 373 374 /** 375 * Saves the current matrix and clip onto a private stack. Subsequent 376 * calls to translate,scale,rotate,skew,concat or clipRect,clipPath 377 * will all operate as usual, but when the balancing call to restore() 378 * is made, those calls will be forgotten, and the settings that existed 379 * before the save() will be reinstated. 380 * 381 * @return The value to pass to restoreToCount() to balance this save() 382 */ 383 public int save() { 384 return native_save(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); 385 } 386 387 /** 388 * Based on saveFlags, can save the current matrix and clip onto a private 389 * stack. Subsequent calls to translate,scale,rotate,skew,concat or 390 * clipRect,clipPath will all operate as usual, but when the balancing 391 * call to restore() is made, those calls will be forgotten, and the 392 * settings that existed before the save() will be reinstated. 393 * 394 * @param saveFlags flag bits that specify which parts of the Canvas state 395 * to save/restore 396 * @return The value to pass to restoreToCount() to balance this save() 397 */ 398 public int save(@Saveflags int saveFlags) { 399 return native_save(mNativeCanvasWrapper, saveFlags); 400 } 401 402 /** 403 * This behaves the same as save(), but in addition it allocates an 404 * offscreen bitmap. All drawing calls are directed there, and only when 405 * the balancing call to restore() is made is that offscreen transfered to 406 * the canvas (or the previous layer). Subsequent calls to translate, 407 * scale, rotate, skew, concat or clipRect, clipPath all operate on this 408 * copy. When the balancing call to restore() is made, this copy is 409 * deleted and the previous matrix/clip state is restored. 410 * 411 * @param bounds May be null. The maximum size the offscreen bitmap 412 * needs to be (in local coordinates) 413 * @param paint This is copied, and is applied to the offscreen when 414 * restore() is called. 415 * @param saveFlags see _SAVE_FLAG constants 416 * @return value to pass to restoreToCount() to balance this save() 417 */ 418 public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags) { 419 return native_saveLayer(mNativeCanvasWrapper, 420 bounds.left, bounds.top, bounds.right, bounds.bottom, 421 paint != null ? paint.mNativePaint : 0, 422 saveFlags); 423 } 424 425 /** 426 * Convenience for saveLayer(bounds, paint, {@link #ALL_SAVE_FLAG}) 427 */ 428 public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) { 429 return saveLayer(bounds, paint, ALL_SAVE_FLAG); 430 } 431 432 /** 433 * Helper version of saveLayer() that takes 4 values rather than a RectF. 434 */ 435 public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint, 436 @Saveflags int saveFlags) { 437 return native_saveLayer(mNativeCanvasWrapper, left, top, right, bottom, 438 paint != null ? paint.mNativePaint : 0, 439 saveFlags); 440 } 441 442 /** 443 * Convenience for saveLayer(left, top, right, bottom, paint, {@link #ALL_SAVE_FLAG}) 444 */ 445 public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint) { 446 return saveLayer(left, top, right, bottom, paint, ALL_SAVE_FLAG); 447 } 448 449 /** 450 * This behaves the same as save(), but in addition it allocates an 451 * offscreen bitmap. All drawing calls are directed there, and only when 452 * the balancing call to restore() is made is that offscreen transfered to 453 * the canvas (or the previous layer). Subsequent calls to translate, 454 * scale, rotate, skew, concat or clipRect, clipPath all operate on this 455 * copy. When the balancing call to restore() is made, this copy is 456 * deleted and the previous matrix/clip state is restored. 457 * 458 * @param bounds The maximum size the offscreen bitmap needs to be 459 * (in local coordinates) 460 * @param alpha The alpha to apply to the offscreen when when it is 461 drawn during restore() 462 * @param saveFlags see _SAVE_FLAG constants 463 * @return value to pass to restoreToCount() to balance this call 464 */ 465 public int saveLayerAlpha(@NonNull RectF bounds, int alpha, @Saveflags int saveFlags) { 466 alpha = Math.min(255, Math.max(0, alpha)); 467 return native_saveLayerAlpha(mNativeCanvasWrapper, 468 bounds.left, bounds.top, bounds.right, bounds.bottom, 469 alpha, saveFlags); 470 } 471 472 /** 473 * Convenience for saveLayerAlpha(bounds, alpha, {@link #ALL_SAVE_FLAG}) 474 */ 475 public int saveLayerAlpha(@NonNull RectF bounds, int alpha) { 476 return saveLayerAlpha(bounds, alpha, ALL_SAVE_FLAG); 477 } 478 479 /** 480 * Helper for saveLayerAlpha() that takes 4 values instead of a RectF. 481 */ 482 public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, 483 @Saveflags int saveFlags) { 484 return native_saveLayerAlpha(mNativeCanvasWrapper, left, top, right, bottom, 485 alpha, saveFlags); 486 } 487 488 /** 489 * Helper for saveLayerAlpha(left, top, right, bottom, alpha, {@link #ALL_SAVE_FLAG}) 490 */ 491 public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) { 492 return saveLayerAlpha(left, top, right, bottom, alpha, ALL_SAVE_FLAG); 493 } 494 495 /** 496 * This call balances a previous call to save(), and is used to remove all 497 * modifications to the matrix/clip state since the last save call. It is 498 * an error to call restore() more times than save() was called. 499 */ 500 public void restore() { 501 native_restore(mNativeCanvasWrapper); 502 } 503 504 /** 505 * Returns the number of matrix/clip states on the Canvas' private stack. 506 * This will equal # save() calls - # restore() calls. 507 */ 508 public int getSaveCount() { 509 return native_getSaveCount(mNativeCanvasWrapper); 510 } 511 512 /** 513 * Efficient way to pop any calls to save() that happened after the save 514 * count reached saveCount. It is an error for saveCount to be less than 1. 515 * 516 * Example: 517 * int count = canvas.save(); 518 * ... // more calls potentially to save() 519 * canvas.restoreToCount(count); 520 * // now the canvas is back in the same state it was before the initial 521 * // call to save(). 522 * 523 * @param saveCount The save level to restore to. 524 */ 525 public void restoreToCount(int saveCount) { 526 native_restoreToCount(mNativeCanvasWrapper, saveCount); 527 } 528 529 /** 530 * Preconcat the current matrix with the specified translation 531 * 532 * @param dx The distance to translate in X 533 * @param dy The distance to translate in Y 534 */ 535 public void translate(float dx, float dy) { 536 native_translate(mNativeCanvasWrapper, dx, dy); 537 } 538 539 /** 540 * Preconcat the current matrix with the specified scale. 541 * 542 * @param sx The amount to scale in X 543 * @param sy The amount to scale in Y 544 */ 545 public void scale(float sx, float sy) { 546 native_scale(mNativeCanvasWrapper, sx, sy); 547 } 548 549 /** 550 * Preconcat the current matrix with the specified scale. 551 * 552 * @param sx The amount to scale in X 553 * @param sy The amount to scale in Y 554 * @param px The x-coord for the pivot point (unchanged by the scale) 555 * @param py The y-coord for the pivot point (unchanged by the scale) 556 */ 557 public final void scale(float sx, float sy, float px, float py) { 558 translate(px, py); 559 scale(sx, sy); 560 translate(-px, -py); 561 } 562 563 /** 564 * Preconcat the current matrix with the specified rotation. 565 * 566 * @param degrees The amount to rotate, in degrees 567 */ 568 public void rotate(float degrees) { 569 native_rotate(mNativeCanvasWrapper, degrees); 570 } 571 572 /** 573 * Preconcat the current matrix with the specified rotation. 574 * 575 * @param degrees The amount to rotate, in degrees 576 * @param px The x-coord for the pivot point (unchanged by the rotation) 577 * @param py The y-coord for the pivot point (unchanged by the rotation) 578 */ 579 public final void rotate(float degrees, float px, float py) { 580 translate(px, py); 581 rotate(degrees); 582 translate(-px, -py); 583 } 584 585 /** 586 * Preconcat the current matrix with the specified skew. 587 * 588 * @param sx The amount to skew in X 589 * @param sy The amount to skew in Y 590 */ 591 public void skew(float sx, float sy) { 592 native_skew(mNativeCanvasWrapper, sx, sy); 593 } 594 595 /** 596 * Preconcat the current matrix with the specified matrix. If the specified 597 * matrix is null, this method does nothing. 598 * 599 * @param matrix The matrix to preconcatenate with the current matrix 600 */ 601 public void concat(@Nullable Matrix matrix) { 602 if (matrix != null) native_concat(mNativeCanvasWrapper, matrix.native_instance); 603 } 604 605 /** 606 * Completely replace the current matrix with the specified matrix. If the 607 * matrix parameter is null, then the current matrix is reset to identity. 608 * 609 * <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)}, 610 * {@link #scale(float, float)}, {@link #translate(float, float)} and 611 * {@link #rotate(float)} instead of this method. 612 * 613 * @param matrix The matrix to replace the current matrix with. If it is 614 * null, set the current matrix to identity. 615 * 616 * @see #concat(Matrix) 617 */ 618 public void setMatrix(@Nullable Matrix matrix) { 619 native_setMatrix(mNativeCanvasWrapper, 620 matrix == null ? 0 : matrix.native_instance); 621 } 622 623 /** 624 * Return, in ctm, the current transformation matrix. This does not alter 625 * the matrix in the canvas, but just returns a copy of it. 626 */ 627 @Deprecated 628 public void getMatrix(@NonNull Matrix ctm) { 629 native_getCTM(mNativeCanvasWrapper, ctm.native_instance); 630 } 631 632 /** 633 * Return a new matrix with a copy of the canvas' current transformation 634 * matrix. 635 */ 636 @Deprecated 637 public final @NonNull Matrix getMatrix() { 638 Matrix m = new Matrix(); 639 //noinspection deprecation 640 getMatrix(m); 641 return m; 642 } 643 644 /** 645 * Modify the current clip with the specified rectangle. 646 * 647 * @param rect The rect to intersect with the current clip 648 * @param op How the clip is modified 649 * @return true if the resulting clip is non-empty 650 */ 651 public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) { 652 return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 653 op.nativeInt); 654 } 655 656 /** 657 * Modify the current clip with the specified rectangle, which is 658 * expressed in local coordinates. 659 * 660 * @param rect The rectangle to intersect with the current clip. 661 * @param op How the clip is modified 662 * @return true if the resulting clip is non-empty 663 */ 664 public boolean clipRect(@NonNull Rect rect, @NonNull Region.Op op) { 665 return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 666 op.nativeInt); 667 } 668 669 /** 670 * Intersect the current clip with the specified rectangle, which is 671 * expressed in local coordinates. 672 * 673 * @param rect The rectangle to intersect with the current clip. 674 * @return true if the resulting clip is non-empty 675 */ 676 public boolean clipRect(@NonNull RectF rect) { 677 return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 678 Region.Op.INTERSECT.nativeInt); 679 } 680 681 /** 682 * Intersect the current clip with the specified rectangle, which is 683 * expressed in local coordinates. 684 * 685 * @param rect The rectangle to intersect with the current clip. 686 * @return true if the resulting clip is non-empty 687 */ 688 public boolean clipRect(@NonNull Rect rect) { 689 return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, 690 Region.Op.INTERSECT.nativeInt); 691 } 692 693 /** 694 * Modify the current clip with the specified rectangle, which is 695 * expressed in local coordinates. 696 * 697 * @param left The left side of the rectangle to intersect with the 698 * current clip 699 * @param top The top of the rectangle to intersect with the current 700 * clip 701 * @param right The right side of the rectangle to intersect with the 702 * current clip 703 * @param bottom The bottom of the rectangle to intersect with the current 704 * clip 705 * @param op How the clip is modified 706 * @return true if the resulting clip is non-empty 707 */ 708 public boolean clipRect(float left, float top, float right, float bottom, 709 @NonNull Region.Op op) { 710 return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom, op.nativeInt); 711 } 712 713 /** 714 * Intersect the current clip with the specified rectangle, which is 715 * expressed in local coordinates. 716 * 717 * @param left The left side of the rectangle to intersect with the 718 * current clip 719 * @param top The top of the rectangle to intersect with the current clip 720 * @param right The right side of the rectangle to intersect with the 721 * current clip 722 * @param bottom The bottom of the rectangle to intersect with the current 723 * clip 724 * @return true if the resulting clip is non-empty 725 */ 726 public boolean clipRect(float left, float top, float right, float bottom) { 727 return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom, 728 Region.Op.INTERSECT.nativeInt); 729 } 730 731 /** 732 * Intersect the current clip with the specified rectangle, which is 733 * expressed in local coordinates. 734 * 735 * @param left The left side of the rectangle to intersect with the 736 * current clip 737 * @param top The top of the rectangle to intersect with the current clip 738 * @param right The right side of the rectangle to intersect with the 739 * current clip 740 * @param bottom The bottom of the rectangle to intersect with the current 741 * clip 742 * @return true if the resulting clip is non-empty 743 */ 744 public boolean clipRect(int left, int top, int right, int bottom) { 745 return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom, 746 Region.Op.INTERSECT.nativeInt); 747 } 748 749 /** 750 * Modify the current clip with the specified path. 751 * 752 * @param path The path to operate on the current clip 753 * @param op How the clip is modified 754 * @return true if the resulting is non-empty 755 */ 756 public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) { 757 return native_clipPath(mNativeCanvasWrapper, path.ni(), op.nativeInt); 758 } 759 760 /** 761 * Intersect the current clip with the specified path. 762 * 763 * @param path The path to intersect with the current clip 764 * @return true if the resulting is non-empty 765 */ 766 public boolean clipPath(@NonNull Path path) { 767 return clipPath(path, Region.Op.INTERSECT); 768 } 769 770 /** 771 * Modify the current clip with the specified region. Note that unlike 772 * clipRect() and clipPath() which transform their arguments by the 773 * current matrix, clipRegion() assumes its argument is already in the 774 * coordinate system of the current layer's bitmap, and so not 775 * transformation is performed. 776 * 777 * @param region The region to operate on the current clip, based on op 778 * @param op How the clip is modified 779 * @return true if the resulting is non-empty 780 * 781 * @deprecated Unlike all other clip calls this API does not respect the 782 * current matrix. Use {@link #clipRect(Rect)} as an alternative. 783 */ 784 public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) { 785 return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt); 786 } 787 788 /** 789 * Intersect the current clip with the specified region. Note that unlike 790 * clipRect() and clipPath() which transform their arguments by the 791 * current matrix, clipRegion() assumes its argument is already in the 792 * coordinate system of the current layer's bitmap, and so not 793 * transformation is performed. 794 * 795 * @param region The region to operate on the current clip, based on op 796 * @return true if the resulting is non-empty 797 * 798 * @deprecated Unlike all other clip calls this API does not respect the 799 * current matrix. Use {@link #clipRect(Rect)} as an alternative. 800 */ 801 public boolean clipRegion(@NonNull Region region) { 802 return clipRegion(region, Region.Op.INTERSECT); 803 } 804 805 public @Nullable DrawFilter getDrawFilter() { 806 return mDrawFilter; 807 } 808 809 public void setDrawFilter(@Nullable DrawFilter filter) { 810 long nativeFilter = 0; 811 if (filter != null) { 812 nativeFilter = filter.mNativeInt; 813 } 814 mDrawFilter = filter; 815 nativeSetDrawFilter(mNativeCanvasWrapper, nativeFilter); 816 } 817 818 public enum EdgeType { 819 820 /** 821 * Black-and-White: Treat edges by just rounding to nearest pixel boundary 822 */ 823 BW(0), //!< treat edges by just rounding to nearest pixel boundary 824 825 /** 826 * Antialiased: Treat edges by rounding-out, since they may be antialiased 827 */ 828 AA(1); 829 830 EdgeType(int nativeInt) { 831 this.nativeInt = nativeInt; 832 } 833 834 /** 835 * @hide 836 */ 837 public final int nativeInt; 838 } 839 840 /** 841 * Return true if the specified rectangle, after being transformed by the 842 * current matrix, would lie completely outside of the current clip. Call 843 * this to check if an area you intend to draw into is clipped out (and 844 * therefore you can skip making the draw calls). 845 * 846 * @param rect the rect to compare with the current clip 847 * @param type {@link Canvas.EdgeType#AA} if the path should be considered antialiased, 848 * since that means it may affect a larger area (more pixels) than 849 * non-antialiased ({@link Canvas.EdgeType#BW}). 850 * @return true if the rect (transformed by the canvas' matrix) 851 * does not intersect with the canvas' clip 852 */ 853 public boolean quickReject(@NonNull RectF rect, @NonNull EdgeType type) { 854 return native_quickReject(mNativeCanvasWrapper, 855 rect.left, rect.top, rect.right, rect.bottom); 856 } 857 858 /** 859 * Return true if the specified path, after being transformed by the 860 * current matrix, would lie completely outside of the current clip. Call 861 * this to check if an area you intend to draw into is clipped out (and 862 * therefore you can skip making the draw calls). Note: for speed it may 863 * return false even if the path itself might not intersect the clip 864 * (i.e. the bounds of the path intersects, but the path does not). 865 * 866 * @param path The path to compare with the current clip 867 * @param type {@link Canvas.EdgeType#AA} if the path should be considered antialiased, 868 * since that means it may affect a larger area (more pixels) than 869 * non-antialiased ({@link Canvas.EdgeType#BW}). 870 * @return true if the path (transformed by the canvas' matrix) 871 * does not intersect with the canvas' clip 872 */ 873 public boolean quickReject(@NonNull Path path, @NonNull EdgeType type) { 874 return native_quickReject(mNativeCanvasWrapper, path.ni()); 875 } 876 877 /** 878 * Return true if the specified rectangle, after being transformed by the 879 * current matrix, would lie completely outside of the current clip. Call 880 * this to check if an area you intend to draw into is clipped out (and 881 * therefore you can skip making the draw calls). 882 * 883 * @param left The left side of the rectangle to compare with the 884 * current clip 885 * @param top The top of the rectangle to compare with the current 886 * clip 887 * @param right The right side of the rectangle to compare with the 888 * current clip 889 * @param bottom The bottom of the rectangle to compare with the 890 * current clip 891 * @param type {@link Canvas.EdgeType#AA} if the path should be considered antialiased, 892 * since that means it may affect a larger area (more pixels) than 893 * non-antialiased ({@link Canvas.EdgeType#BW}). 894 * @return true if the rect (transformed by the canvas' matrix) 895 * does not intersect with the canvas' clip 896 */ 897 public boolean quickReject(float left, float top, float right, float bottom, 898 @NonNull EdgeType type) { 899 return native_quickReject(mNativeCanvasWrapper, left, top, right, bottom); 900 } 901 902 /** 903 * Return the bounds of the current clip (in local coordinates) in the 904 * bounds parameter, and return true if it is non-empty. This can be useful 905 * in a way similar to quickReject, in that it tells you that drawing 906 * outside of these bounds will be clipped out. 907 * 908 * @param bounds Return the clip bounds here. If it is null, ignore it but 909 * still return true if the current clip is non-empty. 910 * @return true if the current clip is non-empty. 911 */ 912 public boolean getClipBounds(@Nullable Rect bounds) { 913 return native_getClipBounds(mNativeCanvasWrapper, bounds); 914 } 915 916 /** 917 * Retrieve the bounds of the current clip (in local coordinates). 918 * 919 * @return the clip bounds, or [0, 0, 0, 0] if the clip is empty. 920 */ 921 public final @NonNull Rect getClipBounds() { 922 Rect r = new Rect(); 923 getClipBounds(r); 924 return r; 925 } 926 927 /** 928 * Fill the entire canvas' bitmap (restricted to the current clip) with the 929 * specified RGB color, using srcover porterduff mode. 930 * 931 * @param r red component (0..255) of the color to draw onto the canvas 932 * @param g green component (0..255) of the color to draw onto the canvas 933 * @param b blue component (0..255) of the color to draw onto the canvas 934 */ 935 public void drawRGB(int r, int g, int b) { 936 drawColor(Color.rgb(r, g, b)); 937 } 938 939 /** 940 * Fill the entire canvas' bitmap (restricted to the current clip) with the 941 * specified ARGB color, using srcover porterduff mode. 942 * 943 * @param a alpha component (0..255) of the color to draw onto the canvas 944 * @param r red component (0..255) of the color to draw onto the canvas 945 * @param g green component (0..255) of the color to draw onto the canvas 946 * @param b blue component (0..255) of the color to draw onto the canvas 947 */ 948 public void drawARGB(int a, int r, int g, int b) { 949 drawColor(Color.argb(a, r, g, b)); 950 } 951 952 /** 953 * Fill the entire canvas' bitmap (restricted to the current clip) with the 954 * specified color, using srcover porterduff mode. 955 * 956 * @param color the color to draw onto the canvas 957 */ 958 public void drawColor(int color) { 959 native_drawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); 960 } 961 962 /** 963 * Fill the entire canvas' bitmap (restricted to the current clip) with the 964 * specified color and porter-duff xfermode. 965 * 966 * @param color the color to draw with 967 * @param mode the porter-duff mode to apply to the color 968 */ 969 public void drawColor(int color, @NonNull PorterDuff.Mode mode) { 970 native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt); 971 } 972 973 /** 974 * Fill the entire canvas' bitmap (restricted to the current clip) with 975 * the specified paint. This is equivalent (but faster) to drawing an 976 * infinitely large rectangle with the specified paint. 977 * 978 * @param paint The paint used to draw onto the canvas 979 */ 980 public void drawPaint(@NonNull Paint paint) { 981 native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint); 982 } 983 984 /** 985 * Draw a series of points. Each point is centered at the coordinate 986 * specified by pts[], and its diameter is specified by the paint's stroke 987 * width (as transformed by the canvas' CTM), with special treatment for 988 * a stroke width of 0, which always draws exactly 1 pixel (or at most 4 989 * if antialiasing is enabled). The shape of the point is controlled by 990 * the paint's Cap type. The shape is a square, unless the cap type is 991 * Round, in which case the shape is a circle. 992 * 993 * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...] 994 * @param offset Number of values to skip before starting to draw. 995 * @param count The number of values to process, after skipping offset 996 * of them. Since one point uses two values, the number of 997 * "points" that are drawn is really (count >> 1). 998 * @param paint The paint used to draw the points 999 */ 1000 public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) { 1001 native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint); 1002 } 1003 1004 /** 1005 * Helper for drawPoints() that assumes you want to draw the entire array 1006 */ 1007 public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) { 1008 drawPoints(pts, 0, pts.length, paint); 1009 } 1010 1011 /** 1012 * Helper for drawPoints() for drawing a single point. 1013 */ 1014 public void drawPoint(float x, float y, @NonNull Paint paint) { 1015 native_drawPoint(mNativeCanvasWrapper, x, y, paint.mNativePaint); 1016 } 1017 1018 /** 1019 * Draw a line segment with the specified start and stop x,y coordinates, 1020 * using the specified paint. 1021 * 1022 * <p>Note that since a line is always "framed", the Style is ignored in the paint.</p> 1023 * 1024 * <p>Degenerate lines (length is 0) will not be drawn.</p> 1025 * 1026 * @param startX The x-coordinate of the start point of the line 1027 * @param startY The y-coordinate of the start point of the line 1028 * @param paint The paint used to draw the line 1029 */ 1030 public void drawLine(float startX, float startY, float stopX, float stopY, 1031 @NonNull Paint paint) { 1032 native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.mNativePaint); 1033 } 1034 1035 /** 1036 * Draw a series of lines. Each line is taken from 4 consecutive values 1037 * in the pts array. Thus to draw 1 line, the array must contain at least 4 1038 * values. This is logically the same as drawing the array as follows: 1039 * drawLine(pts[0], pts[1], pts[2], pts[3]) followed by 1040 * drawLine(pts[4], pts[5], pts[6], pts[7]) and so on. 1041 * 1042 * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...] 1043 * @param offset Number of values in the array to skip before drawing. 1044 * @param count The number of values in the array to process, after 1045 * skipping "offset" of them. Since each line uses 4 values, 1046 * the number of "lines" that are drawn is really 1047 * (count >> 2). 1048 * @param paint The paint used to draw the points 1049 */ 1050 public void drawLines(float[] pts, int offset, int count, Paint paint) { 1051 native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint); 1052 } 1053 1054 public void drawLines(@NonNull float[] pts, @NonNull Paint paint) { 1055 drawLines(pts, 0, pts.length, paint); 1056 } 1057 1058 /** 1059 * Draw the specified Rect using the specified paint. The rectangle will 1060 * be filled or framed based on the Style in the paint. 1061 * 1062 * @param rect The rect to be drawn 1063 * @param paint The paint used to draw the rect 1064 */ 1065 public void drawRect(@NonNull RectF rect, @NonNull Paint paint) { 1066 native_drawRect(mNativeCanvasWrapper, 1067 rect.left, rect.top, rect.right, rect.bottom, paint.mNativePaint); 1068 } 1069 1070 /** 1071 * Draw the specified Rect using the specified Paint. The rectangle 1072 * will be filled or framed based on the Style in the paint. 1073 * 1074 * @param r The rectangle to be drawn. 1075 * @param paint The paint used to draw the rectangle 1076 */ 1077 public void drawRect(@NonNull Rect r, @NonNull Paint paint) { 1078 drawRect(r.left, r.top, r.right, r.bottom, paint); 1079 } 1080 1081 1082 /** 1083 * Draw the specified Rect using the specified paint. The rectangle will 1084 * be filled or framed based on the Style in the paint. 1085 * 1086 * @param left The left side of the rectangle to be drawn 1087 * @param top The top side of the rectangle to be drawn 1088 * @param right The right side of the rectangle to be drawn 1089 * @param bottom The bottom side of the rectangle to be drawn 1090 * @param paint The paint used to draw the rect 1091 */ 1092 public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) { 1093 native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint); 1094 } 1095 1096 /** 1097 * Draw the specified oval using the specified paint. The oval will be 1098 * filled or framed based on the Style in the paint. 1099 * 1100 * @param oval The rectangle bounds of the oval to be drawn 1101 */ 1102 public void drawOval(@NonNull RectF oval, @NonNull Paint paint) { 1103 if (oval == null) { 1104 throw new NullPointerException(); 1105 } 1106 drawOval(oval.left, oval.top, oval.right, oval.bottom, paint); 1107 } 1108 1109 /** 1110 * Draw the specified oval using the specified paint. The oval will be 1111 * filled or framed based on the Style in the paint. 1112 */ 1113 public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) { 1114 native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint); 1115 } 1116 1117 /** 1118 * Draw the specified circle using the specified paint. If radius is <= 0, 1119 * then nothing will be drawn. The circle will be filled or framed based 1120 * on the Style in the paint. 1121 * 1122 * @param cx The x-coordinate of the center of the cirle to be drawn 1123 * @param cy The y-coordinate of the center of the cirle to be drawn 1124 * @param radius The radius of the cirle to be drawn 1125 * @param paint The paint used to draw the circle 1126 */ 1127 public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) { 1128 native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.mNativePaint); 1129 } 1130 1131 /** 1132 * <p>Draw the specified arc, which will be scaled to fit inside the 1133 * specified oval.</p> 1134 * 1135 * <p>If the start angle is negative or >= 360, the start angle is treated 1136 * as start angle modulo 360.</p> 1137 * 1138 * <p>If the sweep angle is >= 360, then the oval is drawn 1139 * completely. Note that this differs slightly from SkPath::arcTo, which 1140 * treats the sweep angle modulo 360. If the sweep angle is negative, 1141 * the sweep angle is treated as sweep angle modulo 360</p> 1142 * 1143 * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the 1144 * geometric angle of 0 degrees (3 o'clock on a watch.)</p> 1145 * 1146 * @param oval The bounds of oval used to define the shape and size 1147 * of the arc 1148 * @param startAngle Starting angle (in degrees) where the arc begins 1149 * @param sweepAngle Sweep angle (in degrees) measured clockwise 1150 * @param useCenter If true, include the center of the oval in the arc, and 1151 close it if it is being stroked. This will draw a wedge 1152 * @param paint The paint used to draw the arc 1153 */ 1154 public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, 1155 @NonNull Paint paint) { 1156 drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter, 1157 paint); 1158 } 1159 1160 /** 1161 * <p>Draw the specified arc, which will be scaled to fit inside the 1162 * specified oval.</p> 1163 * 1164 * <p>If the start angle is negative or >= 360, the start angle is treated 1165 * as start angle modulo 360.</p> 1166 * 1167 * <p>If the sweep angle is >= 360, then the oval is drawn 1168 * completely. Note that this differs slightly from SkPath::arcTo, which 1169 * treats the sweep angle modulo 360. If the sweep angle is negative, 1170 * the sweep angle is treated as sweep angle modulo 360</p> 1171 * 1172 * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the 1173 * geometric angle of 0 degrees (3 o'clock on a watch.)</p> 1174 * 1175 * @param startAngle Starting angle (in degrees) where the arc begins 1176 * @param sweepAngle Sweep angle (in degrees) measured clockwise 1177 * @param useCenter If true, include the center of the oval in the arc, and 1178 close it if it is being stroked. This will draw a wedge 1179 * @param paint The paint used to draw the arc 1180 */ 1181 public void drawArc(float left, float top, float right, float bottom, float startAngle, 1182 float sweepAngle, boolean useCenter, @NonNull Paint paint) { 1183 native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle, 1184 useCenter, paint.mNativePaint); 1185 } 1186 1187 /** 1188 * Draw the specified round-rect using the specified paint. The roundrect 1189 * will be filled or framed based on the Style in the paint. 1190 * 1191 * @param rect The rectangular bounds of the roundRect to be drawn 1192 * @param rx The x-radius of the oval used to round the corners 1193 * @param ry The y-radius of the oval used to round the corners 1194 * @param paint The paint used to draw the roundRect 1195 */ 1196 public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { 1197 drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint); 1198 } 1199 1200 /** 1201 * Draw the specified round-rect using the specified paint. The roundrect 1202 * will be filled or framed based on the Style in the paint. 1203 * 1204 * @param rx The x-radius of the oval used to round the corners 1205 * @param ry The y-radius of the oval used to round the corners 1206 * @param paint The paint used to draw the roundRect 1207 */ 1208 public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, 1209 @NonNull Paint paint) { 1210 native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.mNativePaint); 1211 } 1212 1213 /** 1214 * Draw the specified path using the specified paint. The path will be 1215 * filled or framed based on the Style in the paint. 1216 * 1217 * @param path The path to be drawn 1218 * @param paint The paint used to draw the path 1219 */ 1220 public void drawPath(@NonNull Path path, @NonNull Paint paint) { 1221 native_drawPath(mNativeCanvasWrapper, path.ni(), paint.mNativePaint); 1222 } 1223 1224 /** 1225 * @hide 1226 */ 1227 protected static void throwIfCannotDraw(Bitmap bitmap) { 1228 if (bitmap.isRecycled()) { 1229 throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap); 1230 } 1231 if (!bitmap.isPremultiplied() && bitmap.getConfig() == Bitmap.Config.ARGB_8888 && 1232 bitmap.hasAlpha()) { 1233 throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap " 1234 + bitmap); 1235 } 1236 } 1237 1238 /** 1239 * Draws the specified bitmap as an N-patch (most often, a 9-patches.) 1240 * 1241 * @param patch The ninepatch object to render 1242 * @param dst The destination rectangle. 1243 * @param paint The paint to draw the bitmap with. may be null 1244 * 1245 * @hide 1246 */ 1247 public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) { 1248 patch.drawSoftware(this, dst, paint); 1249 } 1250 1251 /** 1252 * Draws the specified bitmap as an N-patch (most often, a 9-patches.) 1253 * 1254 * @param patch The ninepatch object to render 1255 * @param dst The destination rectangle. 1256 * @param paint The paint to draw the bitmap with. may be null 1257 * 1258 * @hide 1259 */ 1260 public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) { 1261 patch.drawSoftware(this, dst, paint); 1262 } 1263 1264 /** 1265 * Draw the specified bitmap, with its top/left corner at (x,y), using 1266 * the specified paint, transformed by the current matrix. 1267 * 1268 * <p>Note: if the paint contains a maskfilter that generates a mask which 1269 * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), 1270 * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. 1271 * Thus the color outside of the original width/height will be the edge 1272 * color replicated. 1273 * 1274 * <p>If the bitmap and canvas have different densities, this function 1275 * will take care of automatically scaling the bitmap to draw at the 1276 * same density as the canvas. 1277 * 1278 * @param bitmap The bitmap to be drawn 1279 * @param left The position of the left side of the bitmap being drawn 1280 * @param top The position of the top side of the bitmap being drawn 1281 * @param paint The paint used to draw the bitmap (may be null) 1282 */ 1283 public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) { 1284 throwIfCannotDraw(bitmap); 1285 native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, 1286 paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity); 1287 } 1288 1289 /** 1290 * Draw the specified bitmap, scaling/translating automatically to fill 1291 * the destination rectangle. If the source rectangle is not null, it 1292 * specifies the subset of the bitmap to draw. 1293 * 1294 * <p>Note: if the paint contains a maskfilter that generates a mask which 1295 * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), 1296 * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. 1297 * Thus the color outside of the original width/height will be the edge 1298 * color replicated. 1299 * 1300 * <p>This function <em>ignores the density associated with the bitmap</em>. 1301 * This is because the source and destination rectangle coordinate 1302 * spaces are in their respective densities, so must already have the 1303 * appropriate scaling factor applied. 1304 * 1305 * @param bitmap The bitmap to be drawn 1306 * @param src May be null. The subset of the bitmap to be drawn 1307 * @param dst The rectangle that the bitmap will be scaled/translated 1308 * to fit into 1309 * @param paint May be null. The paint used to draw the bitmap 1310 */ 1311 public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, 1312 @Nullable Paint paint) { 1313 if (dst == null) { 1314 throw new NullPointerException(); 1315 } 1316 throwIfCannotDraw(bitmap); 1317 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 1318 1319 float left, top, right, bottom; 1320 if (src == null) { 1321 left = top = 0; 1322 right = bitmap.getWidth(); 1323 bottom = bitmap.getHeight(); 1324 } else { 1325 left = src.left; 1326 right = src.right; 1327 top = src.top; 1328 bottom = src.bottom; 1329 } 1330 1331 native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom, 1332 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, 1333 bitmap.mDensity); 1334 } 1335 1336 /** 1337 * Draw the specified bitmap, scaling/translating automatically to fill 1338 * the destination rectangle. If the source rectangle is not null, it 1339 * specifies the subset of the bitmap to draw. 1340 * 1341 * <p>Note: if the paint contains a maskfilter that generates a mask which 1342 * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), 1343 * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. 1344 * Thus the color outside of the original width/height will be the edge 1345 * color replicated. 1346 * 1347 * <p>This function <em>ignores the density associated with the bitmap</em>. 1348 * This is because the source and destination rectangle coordinate 1349 * spaces are in their respective densities, so must already have the 1350 * appropriate scaling factor applied. 1351 * 1352 * @param bitmap The bitmap to be drawn 1353 * @param src May be null. The subset of the bitmap to be drawn 1354 * @param dst The rectangle that the bitmap will be scaled/translated 1355 * to fit into 1356 * @param paint May be null. The paint used to draw the bitmap 1357 */ 1358 public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, 1359 @Nullable Paint paint) { 1360 if (dst == null) { 1361 throw new NullPointerException(); 1362 } 1363 throwIfCannotDraw(bitmap); 1364 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 1365 1366 int left, top, right, bottom; 1367 if (src == null) { 1368 left = top = 0; 1369 right = bitmap.getWidth(); 1370 bottom = bitmap.getHeight(); 1371 } else { 1372 left = src.left; 1373 right = src.right; 1374 top = src.top; 1375 bottom = src.bottom; 1376 } 1377 1378 native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom, 1379 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, 1380 bitmap.mDensity); 1381 } 1382 1383 /** 1384 * Treat the specified array of colors as a bitmap, and draw it. This gives 1385 * the same result as first creating a bitmap from the array, and then 1386 * drawing it, but this method avoids explicitly creating a bitmap object 1387 * which can be more efficient if the colors are changing often. 1388 * 1389 * @param colors Array of colors representing the pixels of the bitmap 1390 * @param offset Offset into the array of colors for the first pixel 1391 * @param stride The number of colors in the array between rows (must be 1392 * >= width or <= -width). 1393 * @param x The X coordinate for where to draw the bitmap 1394 * @param y The Y coordinate for where to draw the bitmap 1395 * @param width The width of the bitmap 1396 * @param height The height of the bitmap 1397 * @param hasAlpha True if the alpha channel of the colors contains valid 1398 * values. If false, the alpha byte is ignored (assumed to 1399 * be 0xFF for every pixel). 1400 * @param paint May be null. The paint used to draw the bitmap 1401 * 1402 * @deprecated Usage with a {@link #isHardwareAccelerated() hardware accelerated} canvas 1403 * requires an internal copy of color buffer contents every time this method is called. Using a 1404 * Bitmap avoids this copy, and allows the application to more explicitly control the lifetime 1405 * and copies of pixel data. 1406 */ 1407 @Deprecated 1408 public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y, 1409 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 1410 // check for valid input 1411 if (width < 0) { 1412 throw new IllegalArgumentException("width must be >= 0"); 1413 } 1414 if (height < 0) { 1415 throw new IllegalArgumentException("height must be >= 0"); 1416 } 1417 if (Math.abs(stride) < width) { 1418 throw new IllegalArgumentException("abs(stride) must be >= width"); 1419 } 1420 int lastScanline = offset + (height - 1) * stride; 1421 int length = colors.length; 1422 if (offset < 0 || (offset + width > length) || lastScanline < 0 1423 || (lastScanline + width > length)) { 1424 throw new ArrayIndexOutOfBoundsException(); 1425 } 1426 // quick escape if there's nothing to draw 1427 if (width == 0 || height == 0) { 1428 return; 1429 } 1430 // punch down to native for the actual draw 1431 native_drawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha, 1432 paint != null ? paint.mNativePaint : 0); 1433 } 1434 1435 /** 1436 * Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y 1437 * 1438 * @deprecated Usage with a {@link #isHardwareAccelerated() hardware accelerated} canvas 1439 * requires an internal copy of color buffer contents every time this method is called. Using a 1440 * Bitmap avoids this copy, and allows the application to more explicitly control the lifetime 1441 * and copies of pixel data. 1442 */ 1443 @Deprecated 1444 public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y, 1445 int width, int height, boolean hasAlpha, @Nullable Paint paint) { 1446 // call through to the common float version 1447 drawBitmap(colors, offset, stride, (float)x, (float)y, width, height, 1448 hasAlpha, paint); 1449 } 1450 1451 /** 1452 * Draw the bitmap using the specified matrix. 1453 * 1454 * @param bitmap The bitmap to draw 1455 * @param matrix The matrix used to transform the bitmap when it is drawn 1456 * @param paint May be null. The paint used to draw the bitmap 1457 */ 1458 public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) { 1459 nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(), 1460 paint != null ? paint.mNativePaint : 0); 1461 } 1462 1463 /** 1464 * @hide 1465 */ 1466 protected static void checkRange(int length, int offset, int count) { 1467 if ((offset | count) < 0 || offset + count > length) { 1468 throw new ArrayIndexOutOfBoundsException(); 1469 } 1470 } 1471 1472 /** 1473 * Draw the bitmap through the mesh, where mesh vertices are evenly 1474 * distributed across the bitmap. There are meshWidth+1 vertices across, and 1475 * meshHeight+1 vertices down. The verts array is accessed in row-major 1476 * order, so that the first meshWidth+1 vertices are distributed across the 1477 * top of the bitmap from left to right. A more general version of this 1478 * method is drawVertices(). 1479 * 1480 * @param bitmap The bitmap to draw using the mesh 1481 * @param meshWidth The number of columns in the mesh. Nothing is drawn if 1482 * this is 0 1483 * @param meshHeight The number of rows in the mesh. Nothing is drawn if 1484 * this is 0 1485 * @param verts Array of x,y pairs, specifying where the mesh should be 1486 * drawn. There must be at least 1487 * (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values 1488 * in the array 1489 * @param vertOffset Number of verts elements to skip before drawing 1490 * @param colors May be null. Specifies a color at each vertex, which is 1491 * interpolated across the cell, and whose values are 1492 * multiplied by the corresponding bitmap colors. If not null, 1493 * there must be at least (meshWidth+1) * (meshHeight+1) + 1494 * colorOffset values in the array. 1495 * @param colorOffset Number of color elements to skip before drawing 1496 * @param paint May be null. The paint used to draw the bitmap 1497 */ 1498 public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight, 1499 @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, 1500 @Nullable Paint paint) { 1501 if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) { 1502 throw new ArrayIndexOutOfBoundsException(); 1503 } 1504 if (meshWidth == 0 || meshHeight == 0) { 1505 return; 1506 } 1507 int count = (meshWidth + 1) * (meshHeight + 1); 1508 // we mul by 2 since we need two floats per vertex 1509 checkRange(verts.length, vertOffset, count * 2); 1510 if (colors != null) { 1511 // no mul by 2, since we need only 1 color per vertex 1512 checkRange(colors.length, colorOffset, count); 1513 } 1514 nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight, 1515 verts, vertOffset, colors, colorOffset, 1516 paint != null ? paint.mNativePaint : 0); 1517 } 1518 1519 public enum VertexMode { 1520 TRIANGLES(0), 1521 TRIANGLE_STRIP(1), 1522 TRIANGLE_FAN(2); 1523 1524 VertexMode(int nativeInt) { 1525 this.nativeInt = nativeInt; 1526 } 1527 1528 /** 1529 * @hide 1530 */ 1531 public final int nativeInt; 1532 } 1533 1534 /** 1535 * Draw the array of vertices, interpreted as triangles (based on mode). The 1536 * verts array is required, and specifies the x,y pairs for each vertex. If 1537 * texs is non-null, then it is used to specify the coordinate in shader 1538 * coordinates to use at each vertex (the paint must have a shader in this 1539 * case). If there is no texs array, but there is a color array, then each 1540 * color is interpolated across its corresponding triangle in a gradient. If 1541 * both texs and colors arrays are present, then they behave as before, but 1542 * the resulting color at each pixels is the result of multiplying the 1543 * colors from the shader and the color-gradient together. The indices array 1544 * is optional, but if it is present, then it is used to specify the index 1545 * of each triangle, rather than just walking through the arrays in order. 1546 * 1547 * @param mode How to interpret the array of vertices 1548 * @param vertexCount The number of values in the vertices array (and 1549 * corresponding texs and colors arrays if non-null). Each logical 1550 * vertex is two values (x, y), vertexCount must be a multiple of 2. 1551 * @param verts Array of vertices for the mesh 1552 * @param vertOffset Number of values in the verts to skip before drawing. 1553 * @param texs May be null. If not null, specifies the coordinates to sample 1554 * into the current shader (e.g. bitmap tile or gradient) 1555 * @param texOffset Number of values in texs to skip before drawing. 1556 * @param colors May be null. If not null, specifies a color for each 1557 * vertex, to be interpolated across the triangle. 1558 * @param colorOffset Number of values in colors to skip before drawing. 1559 * @param indices If not null, array of indices to reference into the 1560 * vertex (texs, colors) array. 1561 * @param indexCount number of entries in the indices array (if not null). 1562 * @param paint Specifies the shader to use if the texs array is non-null. 1563 */ 1564 public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts, 1565 int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, 1566 int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, 1567 @NonNull Paint paint) { 1568 checkRange(verts.length, vertOffset, vertexCount); 1569 if (texs != null) { 1570 checkRange(texs.length, texOffset, vertexCount); 1571 } 1572 if (colors != null) { 1573 checkRange(colors.length, colorOffset, vertexCount / 2); 1574 } 1575 if (indices != null) { 1576 checkRange(indices.length, indexOffset, indexCount); 1577 } 1578 nativeDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts, 1579 vertOffset, texs, texOffset, colors, colorOffset, 1580 indices, indexOffset, indexCount, paint.mNativePaint); 1581 } 1582 1583 /** 1584 * Draw the text, with origin at (x,y), using the specified paint. The 1585 * origin is interpreted based on the Align setting in the paint. 1586 * 1587 * @param text The text to be drawn 1588 * @param x The x-coordinate of the origin of the text being drawn 1589 * @param y The y-coordinate of the origin of the text being drawn 1590 * @param paint The paint used for the text (e.g. color, size, style) 1591 */ 1592 public void drawText(@NonNull char[] text, int index, int count, float x, float y, 1593 @NonNull Paint paint) { 1594 if ((index | count | (index + count) | 1595 (text.length - index - count)) < 0) { 1596 throw new IndexOutOfBoundsException(); 1597 } 1598 native_drawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags, 1599 paint.mNativePaint, paint.mNativeTypeface); 1600 } 1601 1602 /** 1603 * Draw the text, with origin at (x,y), using the specified paint. The 1604 * origin is interpreted based on the Align setting in the paint. 1605 * 1606 * @param text The text to be drawn 1607 * @param x The x-coordinate of the origin of the text being drawn 1608 * @param y The y-coordinate of the origin of the text being drawn 1609 * @param paint The paint used for the text (e.g. color, size, style) 1610 */ 1611 public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) { 1612 native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags, 1613 paint.mNativePaint, paint.mNativeTypeface); 1614 } 1615 1616 /** 1617 * Draw the text, with origin at (x,y), using the specified paint. 1618 * The origin is interpreted based on the Align setting in the paint. 1619 * 1620 * @param text The text to be drawn 1621 * @param start The index of the first character in text to draw 1622 * @param end (end - 1) is the index of the last character in text to draw 1623 * @param x The x-coordinate of the origin of the text being drawn 1624 * @param y The y-coordinate of the origin of the text being drawn 1625 * @param paint The paint used for the text (e.g. color, size, style) 1626 */ 1627 public void drawText(@NonNull String text, int start, int end, float x, float y, 1628 @NonNull Paint paint) { 1629 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1630 throw new IndexOutOfBoundsException(); 1631 } 1632 native_drawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags, 1633 paint.mNativePaint, paint.mNativeTypeface); 1634 } 1635 1636 /** 1637 * Draw the specified range of text, specified by start/end, with its 1638 * origin at (x,y), in the specified Paint. The origin is interpreted 1639 * based on the Align setting in the Paint. 1640 * 1641 * @param text The text to be drawn 1642 * @param start The index of the first character in text to draw 1643 * @param end (end - 1) is the index of the last character in text 1644 * to draw 1645 * @param x The x-coordinate of origin for where to draw the text 1646 * @param y The y-coordinate of origin for where to draw the text 1647 * @param paint The paint used for the text (e.g. color, size, style) 1648 */ 1649 public void drawText(@NonNull CharSequence text, int start, int end, float x, float y, 1650 @NonNull Paint paint) { 1651 if (text instanceof String || text instanceof SpannedString || 1652 text instanceof SpannableString) { 1653 native_drawText(mNativeCanvasWrapper, text.toString(), start, end, x, y, 1654 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); 1655 } else if (text instanceof GraphicsOperations) { 1656 ((GraphicsOperations) text).drawText(this, start, end, x, y, 1657 paint); 1658 } else { 1659 char[] buf = TemporaryBuffer.obtain(end - start); 1660 TextUtils.getChars(text, start, end, buf, 0); 1661 native_drawText(mNativeCanvasWrapper, buf, 0, end - start, x, y, 1662 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); 1663 TemporaryBuffer.recycle(buf); 1664 } 1665 } 1666 1667 /** 1668 * Render a run of all LTR or all RTL text, with shaping. This does not run 1669 * bidi on the provided text, but renders it as a uniform right-to-left or 1670 * left-to-right run, as indicated by dir. Alignment of the text is as 1671 * determined by the Paint's TextAlign value. 1672 * 1673 * @param text the text to render 1674 * @param index the start of the text to render 1675 * @param count the count of chars to render 1676 * @param contextIndex the start of the context for shaping. Must be 1677 * no greater than index. 1678 * @param contextCount the number of characters in the context for shaping. 1679 * ContexIndex + contextCount must be no less than index 1680 * + count. 1681 * @param x the x position at which to draw the text 1682 * @param y the y position at which to draw the text 1683 * @param isRtl whether the run is in RTL direction 1684 * @param paint the paint 1685 * @hide 1686 */ 1687 public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, 1688 int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) { 1689 1690 if (text == null) { 1691 throw new NullPointerException("text is null"); 1692 } 1693 if (paint == null) { 1694 throw new NullPointerException("paint is null"); 1695 } 1696 if ((index | count | text.length - index - count) < 0) { 1697 throw new IndexOutOfBoundsException(); 1698 } 1699 1700 native_drawTextRun(mNativeCanvasWrapper, text, index, count, 1701 contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); 1702 } 1703 1704 /** 1705 * Render a run of all LTR or all RTL text, with shaping. This does not run 1706 * bidi on the provided text, but renders it as a uniform right-to-left or 1707 * left-to-right run, as indicated by dir. Alignment of the text is as 1708 * determined by the Paint's TextAlign value. 1709 * 1710 * @param text the text to render 1711 * @param start the start of the text to render. Data before this position 1712 * can be used for shaping context. 1713 * @param end the end of the text to render. Data at or after this 1714 * position can be used for shaping context. 1715 * @param x the x position at which to draw the text 1716 * @param y the y position at which to draw the text 1717 * @param isRtl whether the run is in RTL direction 1718 * @param paint the paint 1719 * @hide 1720 */ 1721 public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, 1722 int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { 1723 1724 if (text == null) { 1725 throw new NullPointerException("text is null"); 1726 } 1727 if (paint == null) { 1728 throw new NullPointerException("paint is null"); 1729 } 1730 if ((start | end | end - start | text.length() - end) < 0) { 1731 throw new IndexOutOfBoundsException(); 1732 } 1733 1734 if (text instanceof String || text instanceof SpannedString || 1735 text instanceof SpannableString) { 1736 native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end, 1737 contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); 1738 } else if (text instanceof GraphicsOperations) { 1739 ((GraphicsOperations) text).drawTextRun(this, start, end, 1740 contextStart, contextEnd, x, y, isRtl, paint); 1741 } else { 1742 int contextLen = contextEnd - contextStart; 1743 int len = end - start; 1744 char[] buf = TemporaryBuffer.obtain(contextLen); 1745 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 1746 native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, 1747 0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); 1748 TemporaryBuffer.recycle(buf); 1749 } 1750 } 1751 1752 /** 1753 * Draw the text in the array, with each character's origin specified by 1754 * the pos array. 1755 * 1756 * This method does not support glyph composition and decomposition and 1757 * should therefore not be used to render complex scripts. It also doesn't 1758 * handle supplementary characters (eg emoji). 1759 * 1760 * @param text The text to be drawn 1761 * @param index The index of the first character to draw 1762 * @param count The number of characters to draw, starting from index. 1763 * @param pos Array of [x,y] positions, used to position each 1764 * character 1765 * @param paint The paint used for the text (e.g. color, size, style) 1766 */ 1767 @Deprecated 1768 public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos, 1769 @NonNull Paint paint) { 1770 if (index < 0 || index + count > text.length || count*2 > pos.length) { 1771 throw new IndexOutOfBoundsException(); 1772 } 1773 for (int i = 0; i < count; i++) { 1774 drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint); 1775 } 1776 } 1777 1778 /** 1779 * Draw the text in the array, with each character's origin specified by 1780 * the pos array. 1781 * 1782 * This method does not support glyph composition and decomposition and 1783 * should therefore not be used to render complex scripts. It also doesn't 1784 * handle supplementary characters (eg emoji). 1785 * 1786 * @param text The text to be drawn 1787 * @param pos Array of [x,y] positions, used to position each character 1788 * @param paint The paint used for the text (e.g. color, size, style) 1789 */ 1790 @Deprecated 1791 public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) { 1792 drawPosText(text.toCharArray(), 0, text.length(), pos, paint); 1793 } 1794 1795 /** 1796 * Draw the text, with origin at (x,y), using the specified paint, along 1797 * the specified path. The paint's Align setting determins where along the 1798 * path to start the text. 1799 * 1800 * @param text The text to be drawn 1801 * @param path The path the text should follow for its baseline 1802 * @param hOffset The distance along the path to add to the text's 1803 * starting position 1804 * @param vOffset The distance above(-) or below(+) the path to position 1805 * the text 1806 * @param paint The paint used for the text (e.g. color, size, style) 1807 */ 1808 public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path, 1809 float hOffset, float vOffset, @NonNull Paint paint) { 1810 if (index < 0 || index + count > text.length) { 1811 throw new ArrayIndexOutOfBoundsException(); 1812 } 1813 native_drawTextOnPath(mNativeCanvasWrapper, text, index, count, 1814 path.ni(), hOffset, vOffset, 1815 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); 1816 } 1817 1818 /** 1819 * Draw the text, with origin at (x,y), using the specified paint, along 1820 * the specified path. The paint's Align setting determins where along the 1821 * path to start the text. 1822 * 1823 * @param text The text to be drawn 1824 * @param path The path the text should follow for its baseline 1825 * @param hOffset The distance along the path to add to the text's 1826 * starting position 1827 * @param vOffset The distance above(-) or below(+) the path to position 1828 * the text 1829 * @param paint The paint used for the text (e.g. color, size, style) 1830 */ 1831 public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, 1832 float vOffset, @NonNull Paint paint) { 1833 if (text.length() > 0) { 1834 native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset, 1835 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); 1836 } 1837 } 1838 1839 /** 1840 * Save the canvas state, draw the picture, and restore the canvas state. 1841 * This differs from picture.draw(canvas), which does not perform any 1842 * save/restore. 1843 * 1844 * <p> 1845 * <strong>Note:</strong> This forces the picture to internally call 1846 * {@link Picture#endRecording} in order to prepare for playback. 1847 * 1848 * @param picture The picture to be drawn 1849 */ 1850 public void drawPicture(@NonNull Picture picture) { 1851 picture.endRecording(); 1852 int restoreCount = save(); 1853 picture.draw(this); 1854 restoreToCount(restoreCount); 1855 } 1856 1857 /** 1858 * Draw the picture, stretched to fit into the dst rectangle. 1859 */ 1860 public void drawPicture(@NonNull Picture picture, @NonNull RectF dst) { 1861 save(); 1862 translate(dst.left, dst.top); 1863 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 1864 scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); 1865 } 1866 drawPicture(picture); 1867 restore(); 1868 } 1869 1870 /** 1871 * Draw the picture, stretched to fit into the dst rectangle. 1872 */ 1873 public void drawPicture(@NonNull Picture picture, @NonNull Rect dst) { 1874 save(); 1875 translate(dst.left, dst.top); 1876 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 1877 scale((float) dst.width() / picture.getWidth(), 1878 (float) dst.height() / picture.getHeight()); 1879 } 1880 drawPicture(picture); 1881 restore(); 1882 } 1883 1884 /** 1885 * Releases the resources associated with this canvas. 1886 * 1887 * @hide 1888 */ 1889 public void release() { 1890 mFinalizer.dispose(); 1891 } 1892 1893 /** 1894 * Free up as much memory as possible from private caches (e.g. fonts, images) 1895 * 1896 * @hide 1897 */ 1898 public static native void freeCaches(); 1899 1900 /** 1901 * Free up text layout caches 1902 * 1903 * @hide 1904 */ 1905 public static native void freeTextLayoutCaches(); 1906 1907 private static native long initRaster(long nativeBitmapOrZero); 1908 private static native void native_setBitmap(long canvasHandle, 1909 long bitmapHandle, 1910 boolean copyState); 1911 private static native boolean native_isOpaque(long canvasHandle); 1912 private static native int native_getWidth(long canvasHandle); 1913 private static native int native_getHeight(long canvasHandle); 1914 1915 private static native int native_save(long canvasHandle, int saveFlags); 1916 private static native int native_saveLayer(long nativeCanvas, float l, 1917 float t, float r, float b, 1918 long nativePaint, 1919 int layerFlags); 1920 private static native int native_saveLayerAlpha(long nativeCanvas, float l, 1921 float t, float r, float b, 1922 int alpha, int layerFlags); 1923 private static native void native_restore(long canvasHandle); 1924 private static native void native_restoreToCount(long canvasHandle, 1925 int saveCount); 1926 private static native int native_getSaveCount(long canvasHandle); 1927 1928 private static native void native_translate(long canvasHandle, 1929 float dx, float dy); 1930 private static native void native_scale(long canvasHandle, 1931 float sx, float sy); 1932 private static native void native_rotate(long canvasHandle, float degrees); 1933 private static native void native_skew(long canvasHandle, 1934 float sx, float sy); 1935 private static native void native_concat(long nativeCanvas, 1936 long nativeMatrix); 1937 private static native void native_setMatrix(long nativeCanvas, 1938 long nativeMatrix); 1939 private static native boolean native_clipRect(long nativeCanvas, 1940 float left, float top, 1941 float right, float bottom, 1942 int regionOp); 1943 private static native boolean native_clipPath(long nativeCanvas, 1944 long nativePath, 1945 int regionOp); 1946 private static native boolean native_clipRegion(long nativeCanvas, 1947 long nativeRegion, 1948 int regionOp); 1949 private static native void nativeSetDrawFilter(long nativeCanvas, 1950 long nativeFilter); 1951 private static native boolean native_getClipBounds(long nativeCanvas, 1952 Rect bounds); 1953 private static native void native_getCTM(long nativeCanvas, 1954 long nativeMatrix); 1955 private static native boolean native_quickReject(long nativeCanvas, 1956 long nativePath); 1957 private static native boolean native_quickReject(long nativeCanvas, 1958 float left, float top, 1959 float right, float bottom); 1960 private static native void native_drawColor(long nativeCanvas, int color, 1961 int mode); 1962 private static native void native_drawPaint(long nativeCanvas, 1963 long nativePaint); 1964 private static native void native_drawPoint(long canvasHandle, float x, float y, 1965 long paintHandle); 1966 private static native void native_drawPoints(long canvasHandle, float[] pts, 1967 int offset, int count, 1968 long paintHandle); 1969 private static native void native_drawLine(long nativeCanvas, float startX, 1970 float startY, float stopX, 1971 float stopY, long nativePaint); 1972 private static native void native_drawLines(long canvasHandle, float[] pts, 1973 int offset, int count, 1974 long paintHandle); 1975 private static native void native_drawRect(long nativeCanvas, float left, 1976 float top, float right, 1977 float bottom, 1978 long nativePaint); 1979 private static native void native_drawOval(long nativeCanvas, float left, float top, 1980 float right, float bottom, long nativePaint); 1981 private static native void native_drawCircle(long nativeCanvas, float cx, 1982 float cy, float radius, 1983 long nativePaint); 1984 private static native void native_drawArc(long nativeCanvas, float left, float top, 1985 float right, float bottom, 1986 float startAngle, float sweep, boolean useCenter, 1987 long nativePaint); 1988 private static native void native_drawRoundRect(long nativeCanvas, 1989 float left, float top, float right, float bottom, 1990 float rx, float ry, long nativePaint); 1991 private static native void native_drawPath(long nativeCanvas, 1992 long nativePath, 1993 long nativePaint); 1994 private native void native_drawBitmap(long nativeCanvas, long nativeBitmap, 1995 float left, float top, 1996 long nativePaintOrZero, 1997 int canvasDensity, 1998 int screenDensity, 1999 int bitmapDensity); 2000 private native void native_drawBitmap(long nativeCanvas, long nativeBitmap, 2001 float srcLeft, float srcTop, float srcRight, float srcBottom, 2002 float dstLeft, float dstTop, float dstRight, float dstBottom, 2003 long nativePaintOrZero, int screenDensity, int bitmapDensity); 2004 private static native void native_drawBitmap(long nativeCanvas, int[] colors, 2005 int offset, int stride, float x, 2006 float y, int width, int height, 2007 boolean hasAlpha, 2008 long nativePaintOrZero); 2009 private static native void nativeDrawBitmapMatrix(long nativeCanvas, 2010 long nativeBitmap, 2011 long nativeMatrix, 2012 long nativePaint); 2013 private static native void nativeDrawBitmapMesh(long nativeCanvas, 2014 long nativeBitmap, 2015 int meshWidth, int meshHeight, 2016 float[] verts, int vertOffset, 2017 int[] colors, int colorOffset, 2018 long nativePaint); 2019 private static native void nativeDrawVertices(long nativeCanvas, int mode, int n, 2020 float[] verts, int vertOffset, float[] texs, int texOffset, 2021 int[] colors, int colorOffset, short[] indices, 2022 int indexOffset, int indexCount, long nativePaint); 2023 2024 private static native void native_drawText(long nativeCanvas, char[] text, 2025 int index, int count, float x, 2026 float y, int flags, long nativePaint, 2027 long nativeTypeface); 2028 private static native void native_drawText(long nativeCanvas, String text, 2029 int start, int end, float x, 2030 float y, int flags, long nativePaint, 2031 long nativeTypeface); 2032 2033 private static native void native_drawTextRun(long nativeCanvas, String text, 2034 int start, int end, int contextStart, int contextEnd, 2035 float x, float y, boolean isRtl, long nativePaint, long nativeTypeface); 2036 2037 private static native void native_drawTextRun(long nativeCanvas, char[] text, 2038 int start, int count, int contextStart, int contextCount, 2039 float x, float y, boolean isRtl, long nativePaint, long nativeTypeface); 2040 2041 private static native void native_drawTextOnPath(long nativeCanvas, 2042 char[] text, int index, 2043 int count, long nativePath, 2044 float hOffset, 2045 float vOffset, int bidiFlags, 2046 long nativePaint, long nativeTypeface); 2047 private static native void native_drawTextOnPath(long nativeCanvas, 2048 String text, long nativePath, 2049 float hOffset, 2050 float vOffset, 2051 int flags, long nativePaint, long nativeTypeface); 2052 private static native void finalizer(long nativeCanvas); 2053} 2054