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