• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         if (path.isSimplePath && path.rects != null) {
290             nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
291         } else {
292             nDrawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance());
293         }
294     }
295 
296     @Override
drawPicture(@onNull Picture picture)297     public final void drawPicture(@NonNull Picture picture) {
298         picture.endRecording();
299         int restoreCount = save();
300         picture.draw(this);
301         restoreToCount(restoreCount);
302     }
303 
304     @Override
drawPicture(@onNull Picture picture, @NonNull Rect dst)305     public final void drawPicture(@NonNull Picture picture, @NonNull Rect dst) {
306         save();
307         translate(dst.left, dst.top);
308         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
309             scale((float) dst.width() / picture.getWidth(),
310                     (float) dst.height() / picture.getHeight());
311         }
312         drawPicture(picture);
313         restore();
314     }
315 
316     @Override
drawPicture(@onNull Picture picture, @NonNull RectF dst)317     public final void drawPicture(@NonNull Picture picture, @NonNull RectF dst) {
318         save();
319         translate(dst.left, dst.top);
320         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
321             scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
322         }
323         drawPicture(picture);
324         restore();
325     }
326 
327     @Override
drawPoint(float x, float y, @NonNull Paint paint)328     public final void drawPoint(float x, float y, @NonNull Paint paint) {
329         nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
330     }
331 
332     @Override
drawPoints(@izemultiple = 2) float[] pts, int offset, int count, @NonNull Paint paint)333     public final void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
334             @NonNull Paint paint) {
335         nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
336     }
337 
338     @Override
drawPoints(@izemultiple = 2) @onNull float[] pts, @NonNull Paint paint)339     public final void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
340         drawPoints(pts, 0, pts.length, paint);
341     }
342 
343     /** @deprecated checkstyle */
344     @Override
345     @Deprecated
drawPosText(@onNull char[] text, int index, int count, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)346     public final void drawPosText(@NonNull char[] text, int index, int count,
347             @NonNull @Size(multiple = 2) float[] pos,
348             @NonNull Paint paint) {
349         if (index < 0 || index + count > text.length || count * 2 > pos.length) {
350             throw new IndexOutOfBoundsException();
351         }
352         for (int i = 0; i < count; i++) {
353             drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
354         }
355     }
356 
357     /** @deprecated checkstyle */
358     @Override
359     @Deprecated
drawPosText(@onNull String text, @NonNull @Size(multiple = 2) float[] pos, @NonNull Paint paint)360     public final void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
361             @NonNull Paint paint) {
362         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
363     }
364 
365     @Override
drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)366     public final void drawRect(float left, float top, float right, float bottom,
367             @NonNull Paint paint) {
368         nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
369     }
370 
371     @Override
drawRect(@onNull Rect r, @NonNull Paint paint)372     public final void drawRect(@NonNull Rect r, @NonNull Paint paint) {
373         drawRect(r.left, r.top, r.right, r.bottom, paint);
374     }
375 
376     @Override
drawRect(@onNull RectF rect, @NonNull Paint paint)377     public final void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
378         nDrawRect(mNativeCanvasWrapper,
379                 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
380     }
381 
382     @Override
drawRGB(int r, int g, int b)383     public final void drawRGB(int r, int g, int b) {
384         drawColor(Color.rgb(r, g, b));
385     }
386 
387     @Override
drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)388     public final void drawRoundRect(float left, float top, float right, float bottom,
389             float rx, float ry, @NonNull Paint paint) {
390         nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
391                 paint.getNativeInstance());
392     }
393 
394     @Override
drawRoundRect(@onNull RectF rect, float rx, float ry, @NonNull Paint paint)395     public final void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
396         drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
397     }
398 
399     @Override
drawDoubleRoundRect(@onNull RectF outer, float outerRx, float outerRy, @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint)400     public final void drawDoubleRoundRect(@NonNull RectF outer, float outerRx, float outerRy,
401             @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint) {
402         nDrawDoubleRoundRect(mNativeCanvasWrapper,
403                 outer.left, outer.top, outer.right, outer.bottom, outerRx, outerRy,
404                 inner.left, inner.top, inner.right, inner.bottom, innerRx, innerRy,
405                 paint.getNativeInstance());
406     }
407 
408     @Override
drawDoubleRoundRect(@onNull RectF outer, float[] outerRadii, @NonNull RectF inner, float[] innerRadii, @NonNull Paint paint)409     public final void drawDoubleRoundRect(@NonNull RectF outer, float[] outerRadii,
410             @NonNull RectF inner, float[] innerRadii, @NonNull Paint paint) {
411         nDrawDoubleRoundRect(mNativeCanvasWrapper,
412                 outer.left, outer.top, outer.right, outer.bottom, outerRadii,
413                 inner.left, inner.top, inner.right, inner.bottom, innerRadii,
414                 paint.getNativeInstance());
415     }
416 
417     @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)418     public void drawGlyphs(
419             @NonNull int[] glyphIds,
420             @IntRange(from = 0) int glyphIdOffset,
421             @NonNull float[] positions,
422             @IntRange(from = 0) int positionOffset,
423             @IntRange(from = 0) int glyphCount,
424             @NonNull Font font,
425             @NonNull Paint paint) {
426         Objects.requireNonNull(glyphIds, "glyphIds must not be null.");
427         Objects.requireNonNull(positions, "positions must not be null.");
428         Objects.requireNonNull(font, "font must not be null.");
429         Objects.requireNonNull(paint, "paint must not be null.");
430         Preconditions.checkArgumentNonnegative(glyphCount);
431 
432         if (glyphIdOffset < 0 || glyphIdOffset + glyphCount > glyphIds.length) {
433             throw new IndexOutOfBoundsException(
434                     "glyphIds must have at least " + (glyphIdOffset + glyphCount) + " of elements");
435         }
436         if (positionOffset < 0 || positionOffset + glyphCount * 2 > positions.length) {
437             throw new IndexOutOfBoundsException(
438                     "positions must have at least " + (positionOffset + glyphCount * 2)
439                             + " of elements");
440         }
441         nDrawGlyphs(mNativeCanvasWrapper, glyphIds, positions, glyphIdOffset, positionOffset,
442                 glyphCount, font.getNativePtr(), paint.getNativeInstance());
443     }
444 
445     @Override
drawText(@onNull char[] text, int index, int count, float x, float y, @NonNull Paint paint)446     public final void drawText(@NonNull char[] text, int index, int count, float x, float y,
447             @NonNull Paint paint) {
448         if ((index | count | (index + count)
449                 | (text.length - index - count)) < 0) {
450             throw new IndexOutOfBoundsException();
451         }
452         nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
453                 paint.getNativeInstance());
454     }
455 
456     @Override
drawText(@onNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint)457     public final void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
458             @NonNull Paint paint) {
459         if ((start | end | (end - start) | (text.length() - end)) < 0) {
460             throw new IndexOutOfBoundsException();
461         }
462         if (text instanceof String || text instanceof SpannedString
463                 || text instanceof SpannableString) {
464             nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
465                     paint.mBidiFlags, paint.getNativeInstance());
466         } else if (text instanceof GraphicsOperations) {
467             ((GraphicsOperations) text).drawText(this, start, end, x, y,
468                     paint);
469         } else {
470             char[] buf = TemporaryBuffer.obtain(end - start);
471             TextUtils.getChars(text, start, end, buf, 0);
472             nDrawText(mNativeCanvasWrapper, buf, 0, end - start, x, y,
473                     paint.mBidiFlags, paint.getNativeInstance());
474             TemporaryBuffer.recycle(buf);
475         }
476     }
477 
478     @Override
drawText(@onNull String text, float x, float y, @NonNull Paint paint)479     public final void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
480         nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
481                 paint.getNativeInstance());
482     }
483 
484     @Override
drawText(@onNull String text, int start, int end, float x, float y, @NonNull Paint paint)485     public final void drawText(@NonNull String text, int start, int end, float x, float y,
486             @NonNull Paint paint) {
487         if ((start | end | (end - start) | (text.length() - end)) < 0) {
488             throw new IndexOutOfBoundsException();
489         }
490         nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
491                 paint.getNativeInstance());
492     }
493 
494     @Override
drawTextOnPath(@onNull char[] text, int index, int count, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)495     public final void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
496             float hOffset, float vOffset, @NonNull Paint paint) {
497         if (index < 0 || index + count > text.length) {
498             throw new ArrayIndexOutOfBoundsException();
499         }
500         nDrawTextOnPath(mNativeCanvasWrapper, text, index, count,
501                 path.readOnlyNI(), hOffset, vOffset,
502                 paint.mBidiFlags, paint.getNativeInstance());
503     }
504 
505     @Override
drawTextOnPath(@onNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)506     public final void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
507             float vOffset, @NonNull Paint paint) {
508         if (text.length() > 0) {
509             nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset,
510                     paint.mBidiFlags, paint.getNativeInstance());
511         }
512     }
513 
514     @Override
drawTextRun(@onNull char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint)515     public final void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
516             int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
517 
518         if (text == null) {
519             throw new NullPointerException("text is null");
520         }
521         if (paint == null) {
522             throw new NullPointerException("paint is null");
523         }
524         if ((index | count | contextIndex | contextCount | index - contextIndex
525                 | (contextIndex + contextCount) - (index + count)
526                 | text.length - (contextIndex + contextCount)) < 0) {
527             throw new IndexOutOfBoundsException();
528         }
529 
530         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
531                 x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
532     }
533 
534     @Override
drawTextRun(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)535     public final void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
536             int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
537 
538         if (text == null) {
539             throw new NullPointerException("text is null");
540         }
541         if (paint == null) {
542             throw new NullPointerException("paint is null");
543         }
544         if ((start | end | contextStart | contextEnd | start - contextStart | end - start
545                 | contextEnd - end | text.length() - contextEnd) < 0) {
546             throw new IndexOutOfBoundsException();
547         }
548 
549         if (text instanceof String || text instanceof SpannedString
550                 || text instanceof SpannableString) {
551             nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
552                     contextEnd, x, y, isRtl, paint.getNativeInstance());
553         } else if (text instanceof GraphicsOperations) {
554             ((GraphicsOperations) text).drawTextRun(this, start, end,
555                     contextStart, contextEnd, x, y, isRtl, paint);
556         } else {
557             if (text instanceof PrecomputedText) {
558                 final PrecomputedText pt = (PrecomputedText) text;
559                 final int paraIndex = pt.findParaIndex(start);
560                 if (end <= pt.getParagraphEnd(paraIndex)) {
561                     final int paraStart = pt.getParagraphStart(paraIndex);
562                     final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
563                     // Only support if the target is in the same paragraph.
564                     drawTextRun(mp.getMeasuredText(),
565                             start - paraStart,
566                             end - paraStart,
567                             contextStart - paraStart,
568                             contextEnd - paraStart,
569                             x, y, isRtl, paint);
570                     return;
571                 }
572             }
573             int contextLen = contextEnd - contextStart;
574             int len = end - start;
575             char[] buf = TemporaryBuffer.obtain(contextLen);
576             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
577             nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
578                     0, contextLen, x, y, isRtl, paint.getNativeInstance(),
579                     0 /* measured paragraph pointer */);
580             TemporaryBuffer.recycle(buf);
581         }
582     }
583 
584     @Override
drawTextRun(@onNull MeasuredText measuredText, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint)585     public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
586             int contextStart, int contextEnd, float x, float y, boolean isRtl,
587             @NonNull Paint paint) {
588         nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
589                 contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
590                 measuredText.getNativePtr());
591     }
592 
593     @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)594     public final void drawVertices(@NonNull VertexMode mode, int vertexCount,
595             @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset,
596             @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset,
597             int indexCount, @NonNull Paint paint) {
598         checkRange(verts.length, vertOffset, vertexCount);
599         if (texs != null) {
600             checkRange(texs.length, texOffset, vertexCount);
601         }
602         if (colors != null) {
603             checkRange(colors.length, colorOffset, vertexCount / 2);
604         }
605         if (indices != null) {
606             checkRange(indices.length, indexOffset, indexCount);
607         }
608         nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
609                 vertOffset, texs, texOffset, colors, colorOffset,
610                 indices, indexOffset, indexCount, paint.getNativeInstance());
611     }
612 
613     /**
614      * @hide
615      */
616     @Override
punchHole(float left, float top, float right, float bottom, float rx, float ry)617     public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
618         nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
619     }
620 
621     @FastNative
nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)622     private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left,
623             float top, long nativePaintOrZero, int canvasDensity, int screenDensity,
624             int bitmapDensity);
625 
626     @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)627     private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle,
628             float srcLeft, float srcTop, float srcRight, float srcBottom,
629             float dstLeft, float dstTop, float dstRight, float dstBottom,
630             long nativePaintOrZero, int screenDensity, int bitmapDensity);
631 
632     @FastNative
nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)633     private static native void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride,
634             float x, float y, int width, int height, boolean hasAlpha, long nativePaintOrZero);
635 
636     @FastNative
nDrawColor(long nativeCanvas, int color, int mode)637     private static native void nDrawColor(long nativeCanvas, int color, int mode);
638 
639     @FastNative
nDrawColor(long nativeCanvas, long nativeColorSpace, @ColorLong long color, int mode)640     private static native void nDrawColor(long nativeCanvas, long nativeColorSpace,
641             @ColorLong long color, int mode);
642 
643     @FastNative
nDrawPaint(long nativeCanvas, long nativePaint)644     private static native void nDrawPaint(long nativeCanvas, long nativePaint);
645 
646     @FastNative
nDrawPoint(long canvasHandle, float x, float y, long paintHandle)647     private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle);
648 
649     @FastNative
nDrawPoints(long canvasHandle, float[] pts, int offset, int count, long paintHandle)650     private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count,
651             long paintHandle);
652 
653     @FastNative
nDrawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long nativePaint)654     private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX,
655             float stopY, long nativePaint);
656 
657     @FastNative
nDrawLines(long canvasHandle, float[] pts, int offset, int count, long paintHandle)658     private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count,
659             long paintHandle);
660 
661     @FastNative
nDrawRect(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)662     private static native void nDrawRect(long nativeCanvas, float left, float top, float right,
663             float bottom, long nativePaint);
664 
665     @FastNative
nDrawOval(long nativeCanvas, float left, float top, float right, float bottom, long nativePaint)666     private static native void nDrawOval(long nativeCanvas, float left, float top, float right,
667             float bottom, long nativePaint);
668 
669     @FastNative
nDrawCircle(long nativeCanvas, float cx, float cy, float radius, long nativePaint)670     private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius,
671             long nativePaint);
672 
673     @FastNative
nDrawArc(long nativeCanvas, float left, float top, float right, float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint)674     private static native void nDrawArc(long nativeCanvas, float left, float top, float right,
675             float bottom, float startAngle, float sweep, boolean useCenter, long nativePaint);
676 
677     @FastNative
nDrawRoundRect(long nativeCanvas, float left, float top, float right, float bottom, float rx, float ry, long nativePaint)678     private static native void nDrawRoundRect(long nativeCanvas, float left, float top, float right,
679             float bottom, float rx, float ry, long nativePaint);
680 
681     @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)682     private static native void nDrawDoubleRoundRect(long nativeCanvas,
683             float outerLeft, float outerTop, float outerRight, float outerBottom,
684             float outerRx, float outerRy, float innerLeft, float innerTop, float innerRight,
685             float innerBottom, float innerRx, float innerRy, long nativePaint);
686 
687     @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)688     private static native void nDrawDoubleRoundRect(long nativeCanvas, float outerLeft,
689             float outerTop, float outerRight, float outerBottom, float[] outerRadii,
690             float innerLeft, float innerTop, float innerRight, float innerBottom,
691             float[] innerRadii, long nativePaint);
692 
693     @FastNative
nDrawPath(long nativeCanvas, long nativePath, long nativePaint)694     private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint);
695 
696     @FastNative
nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint)697     private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint);
698 
699     @FastNative
nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)700     private static native void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch,
701             float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero,
702             int screenDensity, int bitmapDensity);
703 
704     @FastNative
nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle, long nativeMatrix, long nativePaint)705     private static native void nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle,
706             long nativeMatrix, long nativePaint);
707 
708     @FastNative
nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nativePaint)709     private static native void nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth,
710             int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset,
711             long nativePaint);
712 
713     @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)714     private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts,
715             int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
716             short[] indices, int indexOffset, int indexCount, long nativePaint);
717 
718     @FastNative
nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions, int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint)719     private static native void nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions,
720             int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint);
721 
722     @FastNative
nDrawText(long nativeCanvas, char[] text, int index, int count, float x, float y, int flags, long nativePaint)723     private static native void nDrawText(long nativeCanvas, char[] text, int index, int count,
724             float x, float y, int flags, long nativePaint);
725 
726     @FastNative
nDrawText(long nativeCanvas, String text, int start, int end, float x, float y, int flags, long nativePaint)727     private static native void nDrawText(long nativeCanvas, String text, int start, int end,
728             float x, float y, int flags, long nativePaint);
729 
730     @FastNative
nDrawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint)731     private static native void nDrawTextRun(long nativeCanvas, String text, int start, int end,
732             int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint);
733 
734     @FastNative
nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativePrecomputedText)735     private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
736             int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
737             long nativePrecomputedText);
738 
739     @FastNative
nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint)740     private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
741             long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint);
742 
743     @FastNative
nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint)744     private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
745             float hOffset, float vOffset, int flags, long nativePaint);
746 
747     @FastNative
nPunchHole(long renderer, float left, float top, float right, float bottom, float rx, float ry)748     private static native void nPunchHole(long renderer, float left, float top, float right,
749             float bottom, float rx, float ry);
750 }
751