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