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