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