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