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