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