1 /*
2  * Copyright (C) 2016 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.view;
18 
19 import android.annotation.ColorInt;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.Size;
23 import android.graphics.BaseCanvas;
24 import android.graphics.Bitmap;
25 import android.graphics.Canvas;
26 import android.graphics.Color;
27 import android.graphics.Matrix;
28 import android.graphics.NinePatch;
29 import android.graphics.Paint;
30 import android.graphics.Path;
31 import android.graphics.Picture;
32 import android.graphics.PorterDuff;
33 import android.graphics.Rect;
34 import android.graphics.RectF;
35 import android.graphics.TemporaryBuffer;
36 import android.text.GraphicsOperations;
37 import android.text.SpannableString;
38 import android.text.SpannedString;
39 import android.text.TextUtils;
40 
41 import dalvik.annotation.optimization.FastNative;
42 
43 /**
44  * This class is a base class for canvases that defer drawing operations, so all
45  * the draw operations can be marked @FastNative. It contains a re-implementation of
46  * all the methods in {@link BaseCanvas}.
47  *
48  * @hide
49  */
50 public class RecordingCanvas extends Canvas {
51 
RecordingCanvas(long nativeCanvas)52     public RecordingCanvas(long nativeCanvas) {
53         super(nativeCanvas);
54     }
55 
56     @Override
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)57     public final void drawArc(float left, float top, float right, float bottom, float startAngle,
58             float sweepAngle, boolean useCenter, @NonNull Paint paint) {
59         nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
60                 useCenter, paint.getNativeInstance());
61     }
62 
63     @Override
drawArc(@onNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint)64     public final void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle,
65             boolean useCenter, @NonNull Paint paint) {
66         drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
67                 paint);
68     }
69 
70     @Override
drawARGB(int a, int r, int g, int b)71     public final void drawARGB(int a, int r, int g, int b) {
72         drawColor(Color.argb(a, r, g, b));
73     }
74 
75     @Override
drawBitmap(@onNull Bitmap bitmap, float left, float top, @Nullable Paint paint)76     public final void drawBitmap(@NonNull Bitmap bitmap, float left, float top,
77             @Nullable Paint paint) {
78         throwIfCannotDraw(bitmap);
79         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top,
80                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
81                 bitmap.mDensity);
82     }
83 
84     @Override
drawBitmap(@onNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)85     public final void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix,
86             @Nullable Paint paint) {
87         nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
88                 paint != null ? paint.getNativeInstance() : 0);
89     }
90 
91     @Override
drawBitmap(@onNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint)92     public final void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
93             @Nullable Paint paint) {
94         if (dst == null) {
95             throw new NullPointerException();
96         }
97         throwIfCannotDraw(bitmap);
98         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
99 
100         int left, top, right, bottom;
101         if (src == null) {
102             left = top = 0;
103             right = bitmap.getWidth();
104             bottom = bitmap.getHeight();
105         } else {
106             left = src.left;
107             right = src.right;
108             top = src.top;
109             bottom = src.bottom;
110         }
111 
112         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
113                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
114                 bitmap.mDensity);
115     }
116 
117     @Override
drawBitmap(@onNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint)118     public final void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
119             @Nullable Paint paint) {
120         if (dst == null) {
121             throw new NullPointerException();
122         }
123         throwIfCannotDraw(bitmap);
124         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
125 
126         float left, top, right, bottom;
127         if (src == null) {
128             left = top = 0;
129             right = bitmap.getWidth();
130             bottom = bitmap.getHeight();
131         } else {
132             left = src.left;
133             right = src.right;
134             top = src.top;
135             bottom = src.bottom;
136         }
137 
138         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
139                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
140                 bitmap.mDensity);
141     }
142 
143     /** @deprecated checkstyle */
144     @Override
145     @Deprecated
drawBitmap(@onNull int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, @Nullable Paint paint)146     public final void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y,
147             int width, int height, boolean hasAlpha, @Nullable Paint paint) {
148         // check for valid input
149         if (width < 0) {
150             throw new IllegalArgumentException("width must be >= 0");
151         }
152         if (height < 0) {
153             throw new IllegalArgumentException("height must be >= 0");
154         }
155         if (Math.abs(stride) < width) {
156             throw new IllegalArgumentException("abs(stride) must be >= width");
157         }
158         int lastScanline = offset + (height - 1) * stride;
159         int length = colors.length;
160         if (offset < 0 || (offset + width > length) || lastScanline < 0
161                 || (lastScanline + width > length)) {
162             throw new ArrayIndexOutOfBoundsException();
163         }
164         // quick escape if there's nothing to draw
165         if (width == 0 || height == 0) {
166             return;
167         }
168         // punch down to native for the actual draw
169         nDrawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha,
170                 paint != null ? paint.getNativeInstance() : 0);
171     }
172 
173     /** @deprecated checkstyle */
174     @Override
175     @Deprecated
drawBitmap(@onNull int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, @Nullable Paint paint)176     public final void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y,
177             int width, int height, boolean hasAlpha, @Nullable Paint paint) {
178         // call through to the common float version
179         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height,
180                 hasAlpha, paint);
181     }
182 
183     @Override
drawBitmapMesh(@onNull Bitmap bitmap, int meshWidth, int meshHeight, @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, @Nullable Paint paint)184     public final void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,
185             @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,
186             @Nullable Paint paint) {
187         if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
188             throw new ArrayIndexOutOfBoundsException();
189         }
190         if (meshWidth == 0 || meshHeight == 0) {
191             return;
192         }
193         int count = (meshWidth + 1) * (meshHeight + 1);
194         // we mul by 2 since we need two floats per vertex
195         checkRange(verts.length, vertOffset, count * 2);
196         if (colors != null) {
197             // no mul by 2, since we need only 1 color per vertex
198             checkRange(colors.length, colorOffset, count);
199         }
200         nDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight,
201                 verts, vertOffset, colors, colorOffset,
202                 paint != null ? paint.getNativeInstance() : 0);
203     }
204 
205     @Override
drawCircle(float cx, float cy, float radius, @NonNull Paint paint)206     public final void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
207         nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
208     }
209 
210     @Override
drawColor(@olorInt int color)211     public final void drawColor(@ColorInt int color) {
212         nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
213     }
214 
215     @Override
drawColor(@olorInt int color, @NonNull PorterDuff.Mode mode)216     public final void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
217         nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt);
218     }
219 
220     @Override
drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint)221     public final void drawLine(float startX, float startY, float stopX, float stopY,
222             @NonNull Paint paint) {
223         nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
224     }
225 
226     @Override
drawLines(@izemultiple = 4) @onNull float[] pts, int offset, int count, @NonNull Paint paint)227     public final void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
228             @NonNull Paint paint) {
229         nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
230     }
231 
232     @Override
drawLines(@izemultiple = 4) @onNull float[] pts, @NonNull Paint paint)233     public final void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
234         drawLines(pts, 0, pts.length, paint);
235     }
236 
237     @Override
drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)238     public final void drawOval(float left, float top, float right, float bottom,
239             @NonNull Paint paint) {
240         nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
241     }
242 
243     @Override
drawOval(@onNull RectF oval, @NonNull Paint paint)244     public final void drawOval(@NonNull RectF oval, @NonNull Paint paint) {
245         if (oval == null) {
246             throw new NullPointerException();
247         }
248         drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
249     }
250 
251     @Override
drawPaint(@onNull Paint paint)252     public final void drawPaint(@NonNull Paint paint) {
253         nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance());
254     }
255 
256     @Override
drawPatch(@onNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint)257     public final void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst,
258             @Nullable Paint paint) {
259         Bitmap bitmap = patch.getBitmap();
260         throwIfCannotDraw(bitmap);
261         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
262         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
263                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
264                 mDensity, patch.getDensity());
265     }
266 
267     @Override
drawPatch(@onNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint)268     public final void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst,
269             @Nullable Paint paint) {
270         Bitmap bitmap = patch.getBitmap();
271         throwIfCannotDraw(bitmap);
272         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
273         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
274                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
275                 mDensity, patch.getDensity());
276     }
277 
278     @Override
drawPath(@onNull Path path, @NonNull Paint paint)279     public final void drawPath(@NonNull Path path, @NonNull Paint paint) {
280         if (path.isSimplePath && path.rects != null) {
281             nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
282         } else {
283             nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance());
284         }
285     }
286 
287     @Override
drawPicture(@onNull Picture picture)288     public final void drawPicture(@NonNull Picture picture) {
289         picture.endRecording();
290         int restoreCount = save();
291         picture.draw(this);
292         restoreToCount(restoreCount);
293     }
294 
295     @Override
drawPicture(@onNull Picture picture, @NonNull Rect dst)296     public final void drawPicture(@NonNull Picture picture, @NonNull Rect dst) {
297         save();
298         translate(dst.left, dst.top);
299         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
300             scale((float) dst.width() / picture.getWidth(),
301                     (float) dst.height() / picture.getHeight());
302         }
303         drawPicture(picture);
304         restore();
305     }
306 
307     @Override
drawPicture(@onNull Picture picture, @NonNull RectF dst)308     public final void drawPicture(@NonNull Picture picture, @NonNull RectF dst) {
309         save();
310         translate(dst.left, dst.top);
311         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
312             scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
313         }
314         drawPicture(picture);
315         restore();
316     }
317 
318     @Override
drawPoint(float x, float y, @NonNull Paint paint)319     public final void drawPoint(float x, float y, @NonNull Paint paint) {
320         nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
321     }
322 
323     @Override
drawPoints(@izemultiple = 2) float[] pts, int offset, int count, @NonNull Paint paint)324     public final void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
325             @NonNull Paint paint) {
326         nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
327     }
328 
329     @Override
drawPoints(@izemultiple = 2) @onNull float[] pts, @NonNull Paint paint)330     public final void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
331         drawPoints(pts, 0, pts.length, paint);
332     }
333 
334     /** @deprecated checkstyle */
335     @Override
336     @Deprecated
drawPosText(@onNull char[] text, int index, int count, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)337     public final void drawPosText(@NonNull char[] text, int index, int count,
338             @NonNull @Size(multiple = 2) float[] pos,
339             @NonNull Paint paint) {
340         if (index < 0 || index + count > text.length || count * 2 > pos.length) {
341             throw new IndexOutOfBoundsException();
342         }
343         for (int i = 0; i < count; i++) {
344             drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
345         }
346     }
347 
348     /** @deprecated checkstyle */
349     @Override
350     @Deprecated
drawPosText(@onNull String text, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)351     public final void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
352             @NonNull Paint paint) {
353         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
354     }
355 
356     @Override
drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)357     public final void drawRect(float left, float top, float right, float bottom,
358             @NonNull Paint paint) {
359         nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
360     }
361 
362     @Override
drawRect(@onNull Rect r, @NonNull Paint paint)363     public final void drawRect(@NonNull Rect r, @NonNull Paint paint) {
364         drawRect(r.left, r.top, r.right, r.bottom, paint);
365     }
366 
367     @Override
drawRect(@onNull RectF rect, @NonNull Paint paint)368     public final void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
369         nDrawRect(mNativeCanvasWrapper,
370                 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
371     }
372 
373     @Override
drawRGB(int r, int g, int b)374     public final void drawRGB(int r, int g, int b) {
375         drawColor(Color.rgb(r, g, b));
376     }
377 
378     @Override
drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)379     public final void drawRoundRect(float left, float top, float right, float bottom,
380             float rx, float ry, @NonNull Paint paint) {
381         nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
382                 paint.getNativeInstance());
383     }
384 
385     @Override
drawRoundRect(@onNull RectF rect, float rx, float ry, @NonNull Paint paint)386     public final void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
387         drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
388     }
389 
390     @Override
drawText(@onNull char[] text, int index, int count, float x, float y, @NonNull Paint paint)391     public final void drawText(@NonNull char[] text, int index, int count, float x, float y,
392             @NonNull Paint paint) {
393         if ((index | count | (index + count)
394                 | (text.length - index - count)) < 0) {
395             throw new IndexOutOfBoundsException();
396         }
397         nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
398                 paint.getNativeInstance(), paint.mNativeTypeface);
399     }
400 
401     @Override
drawText(@onNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint)402     public final void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
403             @NonNull Paint paint) {
404         if ((start | end | (end - start) | (text.length() - end)) < 0) {
405             throw new IndexOutOfBoundsException();
406         }
407         if (text instanceof String || text instanceof SpannedString
408                 || text instanceof SpannableString) {
409             nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
410                     paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
411         } else if (text instanceof GraphicsOperations) {
412             ((GraphicsOperations) text).drawText(this, start, end, x, y,
413                     paint);
414         } else {
415             char[] buf = TemporaryBuffer.obtain(end - start);
416             TextUtils.getChars(text, start, end, buf, 0);
417             nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y,
418                     paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
419             TemporaryBuffer.recycle(buf);
420         }
421     }
422 
423     @Override
drawText(@onNull String text, float x, float y, @NonNull Paint paint)424     public final void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
425         nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
426                 paint.getNativeInstance(), paint.mNativeTypeface);
427     }
428 
429     @Override
drawText(@onNull String text, int start, int end, float x, float y, @NonNull Paint paint)430     public final void drawText(@NonNull String text, int start, int end, float x, float y,
431             @NonNull Paint paint) {
432         if ((start | end | (end - start) | (text.length() - end)) < 0) {
433             throw new IndexOutOfBoundsException();
434         }
435         nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
436                 paint.getNativeInstance(), paint.mNativeTypeface);
437     }
438 
439     @Override
drawTextOnPath(@onNull char[] text, int index, int count, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)440     public final void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
441             float hOffset, float vOffset, @NonNull Paint paint) {
442         if (index < 0 || index + count > text.length) {
443             throw new ArrayIndexOutOfBoundsException();
444         }
445         nDrawTextOnPath(mNativeCanvasWrapper, text, index, count,
446                 path.readOnlyNI(), hOffset, vOffset,
447                 paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
448     }
449 
450     @Override
drawTextOnPath(@onNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)451     public final void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
452             float vOffset, @NonNull Paint paint) {
453         if (text.length() > 0) {
454             nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset,
455                     paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
456         }
457     }
458 
459     @Override
drawTextRun(@onNull char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint)460     public final void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
461             int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
462 
463         if (text == null) {
464             throw new NullPointerException("text is null");
465         }
466         if (paint == null) {
467             throw new NullPointerException("paint is null");
468         }
469         if ((index | count | contextIndex | contextCount | index - contextIndex
470                 | (contextIndex + contextCount) - (index + count)
471                 | text.length - (contextIndex + contextCount)) < 0) {
472             throw new IndexOutOfBoundsException();
473         }
474 
475         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
476                 x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
477     }
478 
479     @Override
drawTextRun(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)480     public final void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
481             int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
482 
483         if (text == null) {
484             throw new NullPointerException("text is null");
485         }
486         if (paint == null) {
487             throw new NullPointerException("paint is null");
488         }
489         if ((start | end | contextStart | contextEnd | start - contextStart | end - start
490                 | contextEnd - end | text.length() - contextEnd) < 0) {
491             throw new IndexOutOfBoundsException();
492         }
493 
494         if (text instanceof String || text instanceof SpannedString
495                 || text instanceof SpannableString) {
496             nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
497                     contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
498         } else if (text instanceof GraphicsOperations) {
499             ((GraphicsOperations) text).drawTextRun(this, start, end,
500                     contextStart, contextEnd, x, y, isRtl, paint);
501         } else {
502             int contextLen = contextEnd - contextStart;
503             int len = end - start;
504             char[] buf = TemporaryBuffer.obtain(contextLen);
505             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
506             nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
507                     0, contextLen, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
508             TemporaryBuffer.recycle(buf);
509         }
510     }
511 
512     @Override
drawVertices(@onNull VertexMode mode, int vertexCount, @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, @NonNull Paint paint)513     public final void drawVertices(@NonNull VertexMode mode, int vertexCount,
514             @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset,
515             @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset,
516             int indexCount, @NonNull Paint paint) {
517         checkRange(verts.length, vertOffset, vertexCount);
518         if (isHardwareAccelerated()) {
519             return;
520         }
521         if (texs != null) {
522             checkRange(texs.length, texOffset, vertexCount);
523         }
524         if (colors != null) {
525             checkRange(colors.length, colorOffset, vertexCount / 2);
526         }
527         if (indices != null) {
528             checkRange(indices.length, indexOffset, indexCount);
529         }
530         nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
531                 vertOffset, texs, texOffset, colors, colorOffset,
532                 indices, indexOffset, indexCount, paint.getNativeInstance());
533     }
534 
535     @FastNative
nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)536     private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
537             long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);
538 
539     @FastNative
nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)540     private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap,
541             float srcLeft, float srcTop, float srcRight, float srcBottom,
542             float dstLeft, float dstTop, float dstRight, float dstBottom,
543             long nativePaintOrZero, int screenDensity, int bitmapDensity);
544 
545     @FastNative
nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)546     private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride,
547             float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero);
548 
549     @FastNative
nDrawColor(long nativeCanvas, int color, int mode)550     private static native void nDrawColor(long nativeCanvas, int color, int mode);
551 
552     @FastNative
nDrawPaint(long nativeCanvas, long nativePaint)553     private static native void nDrawPaint(long nativeCanvas, long nativePaint);
554 
555     @FastNative
nDrawPoint(long canvasHandle, float x, float y, long paintHandle)556     private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle);
557 
558     @FastNative
nDrawPoints(long canvasHandle, float[] pts, int offset, int count, long paintHandle)559     private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count,
560             long paintHandle);
561 
562     @FastNative
nDrawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long nativePaint)563     private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX,
564             float stopY, long nativePaint);
565 
566     @FastNative
nDrawLines(long canvasHandle, float[] pts, int offset, int count, long paintHandle)567     private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count,
568             long paintHandle);
569 
570     @FastNative
nDrawRect(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)571     private static native void nDrawRect(long nativeCanvas, float left, float top, float right,
572             float bottom, long nativePaint);
573 
574     @FastNative
nDrawOval(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)575     private static native void nDrawOval(long nativeCanvas, float left, float top, float right,
576             float bottom, long nativePaint);
577 
578     @FastNative
nDrawCircle(long nativeCanvas, float cx, float cy, float radius, long nativePaint)579     private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius,
580             long nativePaint);
581 
582     @FastNative
nDrawArc(long nativeCanvas, float left, float top, float right, float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint)583     private static native void nDrawArc(long nativeCanvas, float left, float top, float right,
584             float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint);
585 
586     @FastNative
nDrawRoundRect(long nativeCanvas, float left, float top, float right, float bottom, float rx, float ry, long nativePaint)587     private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right,
588             float bottom, float rx, float ry, long nativePaint);
589 
590     @FastNative
nDrawPath(long nativeCanvas, long nativePath, long nativePaint)591     private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint);
592 
593     @FastNative
nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint)594     private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint);
595 
596     @FastNative
nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)597     private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch,
598             float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero,
599             int screenDensity, int bitmapDensity);
600 
601     @FastNative
nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap, long nativeMatrix, long nativePaint)602     private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap,
603             long nativeMatrix, long nativePaint);
604 
605     @FastNative
nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nativePaint)606     private static native void nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth,
607             int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset,
608             long nativePaint);
609 
610     @FastNative
nDrawVertices(long nativeCanvas, int mode, int n, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, long nativePaint)611     private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts,
612             int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
613             short[] indices, int indexOffset, int indexCount, long nativePaint);
614 
615     @FastNative
nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint, long nativeTypeface)616     private static native void nDrawText(long nativeCanvas, char[] text, int index, int count,
617             float x, float y, int flags, long nativePaint, long nativeTypeface);
618 
619     @FastNative
nDrawText(long nativeCanvas, String text, int start, int end, float x, float y, int flags, long nativePaint, long nativeTypeface)620     private static native void nDrawText(long nativeCanvas, String text, int start, int end,
621             float x, float y, int flags, long nativePaint, long nativeTypeface);
622 
623     @FastNative
nDrawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface)624     private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end,
625             int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint,
626             long nativeTypeface);
627 
628     @FastNative
nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface)629     private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
630             int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
631             long nativeTypeface);
632 
633     @FastNative
nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint, long nativeTypeface)634     private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
635             long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint,
636             long nativeTypeface);
637 
638     @FastNative
nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint, long nativeTypeface)639     private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
640             float hOffset, float vOffset, int flags, long nativePaint, long nativeTypeface);
641 }
642