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