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
17package android.view;
18
19import android.annotation.ColorInt;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.Size;
23import android.graphics.BaseCanvas;
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Color;
27import android.graphics.Matrix;
28import android.graphics.NinePatch;
29import android.graphics.Paint;
30import android.graphics.Path;
31import android.graphics.Picture;
32import android.graphics.PorterDuff;
33import android.graphics.Rect;
34import android.graphics.RectF;
35import android.graphics.TemporaryBuffer;
36import android.text.GraphicsOperations;
37import android.text.PrecomputedText;
38import android.text.SpannableString;
39import android.text.SpannedString;
40import android.text.TextUtils;
41
42import 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 */
51public class RecordingCanvas extends Canvas {
52
53    public RecordingCanvas(long nativeCanvas) {
54        super(nativeCanvas);
55    }
56
57    @Override
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
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
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
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
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
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
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
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
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
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
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
212    public final void drawColor(@ColorInt int color) {
213        nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
214    }
215
216    @Override
217    public final void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
218        nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt);
219    }
220
221    @Override
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
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
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
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
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
253    public final void drawPaint(@NonNull Paint paint) {
254        nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance());
255    }
256
257    @Override
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
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
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
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
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
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
320    public final void drawPoint(float x, float y, @NonNull Paint paint) {
321        nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
322    }
323
324    @Override
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
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
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
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
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
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
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
375    public final void drawRGB(int r, int g, int b) {
376        drawColor(Color.rgb(r, g, b));
377    }
378
379    @Override
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
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
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
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
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
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
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
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
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
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
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
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
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
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
560    private static native void nDrawColor(long nativeCanvas, int color, int mode);
561
562    @FastNative
563    private static native void nDrawPaint(long nativeCanvas, long nativePaint);
564
565    @FastNative
566    private static native void nDrawPoint(long canvasHandle, float x, float y, long paintHandle);
567
568    @FastNative
569    private static native void nDrawPoints(long canvasHandle, float[] pts, int offset, int count,
570            long paintHandle);
571
572    @FastNative
573    private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX,
574            float stopY, long nativePaint);
575
576    @FastNative
577    private static native void nDrawLines(long canvasHandle, float[] pts, int offset, int count,
578            long paintHandle);
579
580    @FastNative
581    private static native void nDrawRect(long nativeCanvas, float left, float top, float right,
582            float bottom, long nativePaint);
583
584    @FastNative
585    private static native void nDrawOval(long nativeCanvas, float left, float top, float right,
586            float bottom, long nativePaint);
587
588    @FastNative
589    private static native void nDrawCircle(long nativeCanvas, float cx, float cy, float radius,
590            long nativePaint);
591
592    @FastNative
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
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
601    private static native void nDrawPath(long nativeCanvas, long nativePath, long nativePaint);
602
603    @FastNative
604    private static native void nDrawRegion(long nativeCanvas, long nativeRegion, long nativePaint);
605
606    @FastNative
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
612    private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap,
613            long nativeMatrix, long nativePaint);
614
615    @FastNative
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
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
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
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
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
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
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
647    private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
648            float hOffset, float vOffset, int flags, long nativePaint);
649}
650