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