Canvas.java revision 4d1c1538e2422d0a5b19ad1cd2fb353ed6279a88
1/*
2 * Copyright (C) 2006 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.graphics;
18
19import android.text.GraphicsOperations;
20import android.text.SpannableString;
21import android.text.SpannedString;
22import android.text.TextUtils;
23
24import javax.microedition.khronos.opengles.GL;
25
26/**
27 * The Canvas class holds the "draw" calls. To draw something, you need
28 * 4 basic components: A Bitmap to hold the pixels, a Canvas to host
29 * the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect,
30 * Path, text, Bitmap), and a paint (to describe the colors and styles for the
31 * drawing).
32 *
33 * <div class="special reference">
34 * <h3>Developer Guides</h3>
35 * <p>For more information about how to use Canvas, read the
36 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html">
37 * Canvas and Drawables</a> developer guide.</p></div>
38 */
39public class Canvas {
40
41    // assigned in constructors or setBitmap, freed in finalizer
42    /** @hide */
43    public long mNativeCanvas;
44
45    // may be null
46    private Bitmap mBitmap;
47
48    // optional field set by the caller
49    private DrawFilter mDrawFilter;
50
51    /**
52     * @hide
53     */
54    protected int mDensity = Bitmap.DENSITY_NONE;
55
56    /**
57     * Used to determine when compatibility scaling is in effect.
58     *
59     * @hide
60     */
61    protected int mScreenDensity = Bitmap.DENSITY_NONE;
62
63    // Used by native code
64    @SuppressWarnings("UnusedDeclaration")
65    private int mSurfaceFormat;
66
67    /**
68     * Flag for drawTextRun indicating left-to-right run direction.
69     * @hide
70     */
71    public static final int DIRECTION_LTR = 0;
72
73    /**
74     * Flag for drawTextRun indicating right-to-left run direction.
75     * @hide
76     */
77    public static final int DIRECTION_RTL = 1;
78
79    // Maximum bitmap size as defined in Skia's native code
80    // (see SkCanvas.cpp, SkDraw.cpp)
81    private static final int MAXMIMUM_BITMAP_SIZE = 32766;
82
83    // This field is used to finalize the native Canvas properly
84    private final CanvasFinalizer mFinalizer;
85
86    private static final class CanvasFinalizer {
87        private long mNativeCanvas;
88
89        public CanvasFinalizer(long nativeCanvas) {
90            mNativeCanvas = nativeCanvas;
91        }
92
93        @Override
94        protected void finalize() throws Throwable {
95            try {
96                dispose();
97            } finally {
98                super.finalize();
99            }
100        }
101
102        public void dispose() {
103            if (mNativeCanvas != 0) {
104                finalizer(mNativeCanvas);
105                mNativeCanvas = 0;
106            }
107        }
108    }
109
110    /**
111     * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
112     * draw into.  The initial target density is {@link Bitmap#DENSITY_NONE};
113     * this will typically be replaced when a target bitmap is set for the
114     * canvas.
115     */
116    public Canvas() {
117        if (!isHardwareAccelerated()) {
118            // 0 means no native bitmap
119            mNativeCanvas = initRaster(0);
120            mFinalizer = new CanvasFinalizer(mNativeCanvas);
121        } else {
122            mFinalizer = null;
123        }
124    }
125
126    /**
127     * Construct a canvas with the specified bitmap to draw into. The bitmap
128     * must be mutable.
129     *
130     * <p>The initial target density of the canvas is the same as the given
131     * bitmap's density.
132     *
133     * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
134     */
135    public Canvas(Bitmap bitmap) {
136        if (!bitmap.isMutable()) {
137            throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
138        }
139        throwIfCannotDraw(bitmap);
140        mNativeCanvas = initRaster(bitmap.ni());
141        mFinalizer = new CanvasFinalizer(mNativeCanvas);
142        mBitmap = bitmap;
143        mDensity = bitmap.mDensity;
144    }
145
146    /** @hide */
147    public Canvas(long nativeCanvas) {
148        if (nativeCanvas == 0) {
149            throw new IllegalStateException();
150        }
151        mNativeCanvas = nativeCanvas;
152        mFinalizer = new CanvasFinalizer(mNativeCanvas);
153        mDensity = Bitmap.getDefaultDensity();
154    }
155
156    /**
157     * Replace existing canvas while ensuring that the swap has occurred before
158     * the previous native canvas is unreferenced.
159     */
160    private void safeCanvasSwap(long nativeCanvas, boolean copyState) {
161        final long oldCanvas = mNativeCanvas;
162        mNativeCanvas = nativeCanvas;
163        mFinalizer.mNativeCanvas = nativeCanvas;
164        if (copyState) {
165            copyNativeCanvasState(oldCanvas, mNativeCanvas);
166        }
167        finalizer(oldCanvas);
168    }
169
170    /**
171     * Returns null.
172     *
173     * @deprecated This method is not supported and should not be invoked.
174     *
175     * @hide
176     */
177    @Deprecated
178    protected GL getGL() {
179        return null;
180    }
181
182    /**
183     * Indicates whether this Canvas uses hardware acceleration.
184     *
185     * Note that this method does not define what type of hardware acceleration
186     * may or may not be used.
187     *
188     * @return True if drawing operations are hardware accelerated,
189     *         false otherwise.
190     */
191    public boolean isHardwareAccelerated() {
192        return false;
193    }
194
195    /**
196     * Specify a bitmap for the canvas to draw into. All canvas state such as
197     * layers, filters, and the save/restore stack are reset with the exception
198     * of the current matrix and clip stack. Additionally, as a side-effect
199     * the canvas' target density is updated to match that of the bitmap.
200     *
201     * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
202     * @see #setDensity(int)
203     * @see #getDensity()
204     */
205    public void setBitmap(Bitmap bitmap) {
206        if (isHardwareAccelerated()) {
207            throw new RuntimeException("Can't set a bitmap device on a GL canvas");
208        }
209
210        if (bitmap == null) {
211            safeCanvasSwap(initRaster(0), false);
212            mDensity = Bitmap.DENSITY_NONE;
213        } else {
214            if (!bitmap.isMutable()) {
215                throw new IllegalStateException();
216            }
217            throwIfCannotDraw(bitmap);
218
219            safeCanvasSwap(initRaster(bitmap.ni()), true);
220            mDensity = bitmap.mDensity;
221        }
222
223        mBitmap = bitmap;
224    }
225
226    /**
227     * Set the viewport dimensions if this canvas is GL based. If it is not,
228     * this method is ignored and no exception is thrown.
229     *
230     * @param width The width of the viewport
231     * @param height The height of the viewport
232     *
233     * @hide
234     */
235    public void setViewport(int width, int height) {
236    }
237
238    /**
239     * Return true if the device that the current layer draws into is opaque
240     * (i.e. does not support per-pixel alpha).
241     *
242     * @return true if the device that the current layer draws into is opaque
243     */
244    public native boolean isOpaque();
245
246    /**
247     * Returns the width of the current drawing layer
248     *
249     * @return the width of the current drawing layer
250     */
251    public native int getWidth();
252
253    /**
254     * Returns the height of the current drawing layer
255     *
256     * @return the height of the current drawing layer
257     */
258    public native int getHeight();
259
260    /**
261     * <p>Returns the target density of the canvas.  The default density is
262     * derived from the density of its backing bitmap, or
263     * {@link Bitmap#DENSITY_NONE} if there is not one.</p>
264     *
265     * @return Returns the current target density of the canvas, which is used
266     * to determine the scaling factor when drawing a bitmap into it.
267     *
268     * @see #setDensity(int)
269     * @see Bitmap#getDensity()
270     */
271    public int getDensity() {
272        return mDensity;
273    }
274
275    /**
276     * <p>Specifies the density for this Canvas' backing bitmap.  This modifies
277     * the target density of the canvas itself, as well as the density of its
278     * backing bitmap via {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}.
279     *
280     * @param density The new target density of the canvas, which is used
281     * to determine the scaling factor when drawing a bitmap into it.  Use
282     * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
283     *
284     * @see #getDensity()
285     * @see Bitmap#setDensity(int)
286     */
287    public void setDensity(int density) {
288        if (mBitmap != null) {
289            mBitmap.setDensity(density);
290        }
291        mDensity = density;
292    }
293
294    /** @hide */
295    public void setScreenDensity(int density) {
296        mScreenDensity = density;
297    }
298
299    /**
300     * Returns the maximum allowed width for bitmaps drawn with this canvas.
301     * Attempting to draw with a bitmap wider than this value will result
302     * in an error.
303     *
304     * @see #getMaximumBitmapHeight()
305     */
306    public int getMaximumBitmapWidth() {
307        return MAXMIMUM_BITMAP_SIZE;
308    }
309
310    /**
311     * Returns the maximum allowed height for bitmaps drawn with this canvas.
312     * Attempting to draw with a bitmap taller than this value will result
313     * in an error.
314     *
315     * @see #getMaximumBitmapWidth()
316     */
317    public int getMaximumBitmapHeight() {
318        return MAXMIMUM_BITMAP_SIZE;
319    }
320
321    // the SAVE_FLAG constants must match their native equivalents
322
323    /** restore the current matrix when restore() is called */
324    public static final int MATRIX_SAVE_FLAG = 0x01;
325    /** restore the current clip when restore() is called */
326    public static final int CLIP_SAVE_FLAG = 0x02;
327    /** the layer needs to per-pixel alpha */
328    public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;
329    /** the layer needs to 8-bits per color component */
330    public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;
331    /** clip against the layer's bounds */
332    public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
333    /** restore everything when restore() is called */
334    public static final int ALL_SAVE_FLAG = 0x1F;
335
336    /**
337     * Saves the current matrix and clip onto a private stack. Subsequent
338     * calls to translate,scale,rotate,skew,concat or clipRect,clipPath
339     * will all operate as usual, but when the balancing call to restore()
340     * is made, those calls will be forgotten, and the settings that existed
341     * before the save() will be reinstated.
342     *
343     * @return The value to pass to restoreToCount() to balance this save()
344     */
345    public native int save();
346
347    /**
348     * Based on saveFlags, can save the current matrix and clip onto a private
349     * stack. Subsequent calls to translate,scale,rotate,skew,concat or
350     * clipRect,clipPath will all operate as usual, but when the balancing
351     * call to restore() is made, those calls will be forgotten, and the
352     * settings that existed before the save() will be reinstated.
353     *
354     * @param saveFlags flag bits that specify which parts of the Canvas state
355     *                  to save/restore
356     * @return The value to pass to restoreToCount() to balance this save()
357     */
358    public native int save(int saveFlags);
359
360    /**
361     * This behaves the same as save(), but in addition it allocates an
362     * offscreen bitmap. All drawing calls are directed there, and only when
363     * the balancing call to restore() is made is that offscreen transfered to
364     * the canvas (or the previous layer). Subsequent calls to translate,
365     * scale, rotate, skew, concat or clipRect, clipPath all operate on this
366     * copy. When the balancing call to restore() is made, this copy is
367     * deleted and the previous matrix/clip state is restored.
368     *
369     * @param bounds May be null. The maximum size the offscreen bitmap
370     *               needs to be (in local coordinates)
371     * @param paint  This is copied, and is applied to the offscreen when
372     *               restore() is called.
373     * @param saveFlags  see _SAVE_FLAG constants
374     * @return       value to pass to restoreToCount() to balance this save()
375     */
376    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
377        return native_saveLayer(mNativeCanvas, bounds,
378                paint != null ? paint.mNativePaint : 0,
379                saveFlags);
380    }
381
382    /**
383     * Convenience for saveLayer(bounds, paint, {@link #ALL_SAVE_FLAG})
384     */
385    public int saveLayer(RectF bounds, Paint paint) {
386        return saveLayer(bounds, paint, ALL_SAVE_FLAG);
387    }
388
389    /**
390     * Helper version of saveLayer() that takes 4 values rather than a RectF.
391     */
392    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
393            int saveFlags) {
394        return native_saveLayer(mNativeCanvas, left, top, right, bottom,
395                paint != null ? paint.mNativePaint : 0,
396                saveFlags);
397    }
398
399    /**
400     * Convenience for saveLayer(left, top, right, bottom, paint, {@link #ALL_SAVE_FLAG})
401     */
402    public int saveLayer(float left, float top, float right, float bottom, Paint paint) {
403        return saveLayer(left, top, right, bottom, paint, ALL_SAVE_FLAG);
404    }
405
406    /**
407     * This behaves the same as save(), but in addition it allocates an
408     * offscreen bitmap. All drawing calls are directed there, and only when
409     * the balancing call to restore() is made is that offscreen transfered to
410     * the canvas (or the previous layer). Subsequent calls to translate,
411     * scale, rotate, skew, concat or clipRect, clipPath all operate on this
412     * copy. When the balancing call to restore() is made, this copy is
413     * deleted and the previous matrix/clip state is restored.
414     *
415     * @param bounds    The maximum size the offscreen bitmap needs to be
416     *                  (in local coordinates)
417     * @param alpha     The alpha to apply to the offscreen when when it is
418                        drawn during restore()
419     * @param saveFlags see _SAVE_FLAG constants
420     * @return          value to pass to restoreToCount() to balance this call
421     */
422    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
423        alpha = Math.min(255, Math.max(0, alpha));
424        return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags);
425    }
426
427    /**
428     * Convenience for saveLayerAlpha(bounds, alpha, {@link #ALL_SAVE_FLAG})
429     */
430    public int saveLayerAlpha(RectF bounds, int alpha) {
431        return saveLayerAlpha(bounds, alpha, ALL_SAVE_FLAG);
432    }
433
434    /**
435     * Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
436     */
437    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
438            int saveFlags) {
439        return native_saveLayerAlpha(mNativeCanvas, left, top, right, bottom,
440                                     alpha, saveFlags);
441    }
442
443    /**
444     * Helper for saveLayerAlpha(left, top, right, bottom, alpha, {@link #ALL_SAVE_FLAG})
445     */
446    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) {
447        return saveLayerAlpha(left, top, right, bottom, alpha, ALL_SAVE_FLAG);
448    }
449
450    /**
451     * This call balances a previous call to save(), and is used to remove all
452     * modifications to the matrix/clip state since the last save call. It is
453     * an error to call restore() more times than save() was called.
454     */
455    public native void restore();
456
457    /**
458     * Returns the number of matrix/clip states on the Canvas' private stack.
459     * This will equal # save() calls - # restore() calls.
460     */
461    public native int getSaveCount();
462
463    /**
464     * Efficient way to pop any calls to save() that happened after the save
465     * count reached saveCount. It is an error for saveCount to be less than 1.
466     *
467     * Example:
468     *    int count = canvas.save();
469     *    ... // more calls potentially to save()
470     *    canvas.restoreToCount(count);
471     *    // now the canvas is back in the same state it was before the initial
472     *    // call to save().
473     *
474     * @param saveCount The save level to restore to.
475     */
476    public native void restoreToCount(int saveCount);
477
478    /**
479     * Preconcat the current matrix with the specified translation
480     *
481     * @param dx The distance to translate in X
482     * @param dy The distance to translate in Y
483    */
484    public native void translate(float dx, float dy);
485
486    /**
487     * Preconcat the current matrix with the specified scale.
488     *
489     * @param sx The amount to scale in X
490     * @param sy The amount to scale in Y
491     */
492    public native void scale(float sx, float sy);
493
494    /**
495     * Preconcat the current matrix with the specified scale.
496     *
497     * @param sx The amount to scale in X
498     * @param sy The amount to scale in Y
499     * @param px The x-coord for the pivot point (unchanged by the scale)
500     * @param py The y-coord for the pivot point (unchanged by the scale)
501     */
502    public final void scale(float sx, float sy, float px, float py) {
503        translate(px, py);
504        scale(sx, sy);
505        translate(-px, -py);
506    }
507
508    /**
509     * Preconcat the current matrix with the specified rotation.
510     *
511     * @param degrees The amount to rotate, in degrees
512     */
513    public native void rotate(float degrees);
514
515    /**
516     * Preconcat the current matrix with the specified rotation.
517     *
518     * @param degrees The amount to rotate, in degrees
519     * @param px The x-coord for the pivot point (unchanged by the rotation)
520     * @param py The y-coord for the pivot point (unchanged by the rotation)
521     */
522    public final void rotate(float degrees, float px, float py) {
523        translate(px, py);
524        rotate(degrees);
525        translate(-px, -py);
526    }
527
528    /**
529     * Preconcat the current matrix with the specified skew.
530     *
531     * @param sx The amount to skew in X
532     * @param sy The amount to skew in Y
533     */
534    public native void skew(float sx, float sy);
535
536    /**
537     * Preconcat the current matrix with the specified matrix. If the specified
538     * matrix is null, this method does nothing.
539     *
540     * @param matrix The matrix to preconcatenate with the current matrix
541     */
542    public void concat(Matrix matrix) {
543        if (matrix != null) native_concat(mNativeCanvas, matrix.native_instance);
544    }
545
546    /**
547     * Completely replace the current matrix with the specified matrix. If the
548     * matrix parameter is null, then the current matrix is reset to identity.
549     *
550     * <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)},
551     * {@link #scale(float, float)}, {@link #translate(float, float)} and
552     * {@link #rotate(float)} instead of this method.
553     *
554     * @param matrix The matrix to replace the current matrix with. If it is
555     *               null, set the current matrix to identity.
556     *
557     * @see #concat(Matrix)
558     */
559    public void setMatrix(Matrix matrix) {
560        native_setMatrix(mNativeCanvas,
561                         matrix == null ? 0 : matrix.native_instance);
562    }
563
564    /**
565     * Return, in ctm, the current transformation matrix. This does not alter
566     * the matrix in the canvas, but just returns a copy of it.
567     */
568    @Deprecated
569    public void getMatrix(Matrix ctm) {
570        native_getCTM(mNativeCanvas, ctm.native_instance);
571    }
572
573    /**
574     * Return a new matrix with a copy of the canvas' current transformation
575     * matrix.
576     */
577    @Deprecated
578    public final Matrix getMatrix() {
579        Matrix m = new Matrix();
580        //noinspection deprecation
581        getMatrix(m);
582        return m;
583    }
584
585    /**
586     * Modify the current clip with the specified rectangle.
587     *
588     * @param rect The rect to intersect with the current clip
589     * @param op How the clip is modified
590     * @return true if the resulting clip is non-empty
591     */
592    public boolean clipRect(RectF rect, Region.Op op) {
593        return native_clipRect(mNativeCanvas, rect.left, rect.top, rect.right, rect.bottom,
594                op.nativeInt);
595    }
596
597    /**
598     * Modify the current clip with the specified rectangle, which is
599     * expressed in local coordinates.
600     *
601     * @param rect The rectangle to intersect with the current clip.
602     * @param op How the clip is modified
603     * @return true if the resulting clip is non-empty
604     */
605    public boolean clipRect(Rect rect, Region.Op op) {
606        return native_clipRect(mNativeCanvas, rect.left, rect.top, rect.right, rect.bottom,
607                op.nativeInt);
608    }
609
610    /**
611     * Intersect the current clip with the specified rectangle, which is
612     * expressed in local coordinates.
613     *
614     * @param rect The rectangle to intersect with the current clip.
615     * @return true if the resulting clip is non-empty
616     */
617    public native boolean clipRect(RectF rect);
618
619    /**
620     * Intersect the current clip with the specified rectangle, which is
621     * expressed in local coordinates.
622     *
623     * @param rect The rectangle to intersect with the current clip.
624     * @return true if the resulting clip is non-empty
625     */
626    public native boolean clipRect(Rect rect);
627
628    /**
629     * Modify the current clip with the specified rectangle, which is
630     * expressed in local coordinates.
631     *
632     * @param left   The left side of the rectangle to intersect with the
633     *               current clip
634     * @param top    The top of the rectangle to intersect with the current
635     *               clip
636     * @param right  The right side of the rectangle to intersect with the
637     *               current clip
638     * @param bottom The bottom of the rectangle to intersect with the current
639     *               clip
640     * @param op     How the clip is modified
641     * @return       true if the resulting clip is non-empty
642     */
643    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
644        return native_clipRect(mNativeCanvas, left, top, right, bottom, op.nativeInt);
645    }
646
647    /**
648     * Intersect the current clip with the specified rectangle, which is
649     * expressed in local coordinates.
650     *
651     * @param left   The left side of the rectangle to intersect with the
652     *               current clip
653     * @param top    The top of the rectangle to intersect with the current clip
654     * @param right  The right side of the rectangle to intersect with the
655     *               current clip
656     * @param bottom The bottom of the rectangle to intersect with the current
657     *               clip
658     * @return       true if the resulting clip is non-empty
659     */
660    public native boolean clipRect(float left, float top, float right, float bottom);
661
662    /**
663     * Intersect the current clip with the specified rectangle, which is
664     * expressed in local coordinates.
665     *
666     * @param left   The left side of the rectangle to intersect with the
667     *               current clip
668     * @param top    The top of the rectangle to intersect with the current clip
669     * @param right  The right side of the rectangle to intersect with the
670     *               current clip
671     * @param bottom The bottom of the rectangle to intersect with the current
672     *               clip
673     * @return       true if the resulting clip is non-empty
674     */
675    public native boolean clipRect(int left, int top, int right, int bottom);
676
677    /**
678        * Modify the current clip with the specified path.
679     *
680     * @param path The path to operate on the current clip
681     * @param op   How the clip is modified
682     * @return     true if the resulting is non-empty
683     */
684    public boolean clipPath(Path path, Region.Op op) {
685        return native_clipPath(mNativeCanvas, path.ni(), op.nativeInt);
686    }
687
688    /**
689     * Intersect the current clip with the specified path.
690     *
691     * @param path The path to intersect with the current clip
692     * @return     true if the resulting is non-empty
693     */
694    public boolean clipPath(Path path) {
695        return clipPath(path, Region.Op.INTERSECT);
696    }
697
698    /**
699     * Modify the current clip with the specified region. Note that unlike
700     * clipRect() and clipPath() which transform their arguments by the
701     * current matrix, clipRegion() assumes its argument is already in the
702     * coordinate system of the current layer's bitmap, and so not
703     * transformation is performed.
704     *
705     * @param region The region to operate on the current clip, based on op
706     * @param op How the clip is modified
707     * @return true if the resulting is non-empty
708     */
709    public boolean clipRegion(Region region, Region.Op op) {
710        return native_clipRegion(mNativeCanvas, region.ni(), op.nativeInt);
711    }
712
713    /**
714     * Intersect the current clip with the specified region. Note that unlike
715     * clipRect() and clipPath() which transform their arguments by the
716     * current matrix, clipRegion() assumes its argument is already in the
717     * coordinate system of the current layer's bitmap, and so not
718     * transformation is performed.
719     *
720     * @param region The region to operate on the current clip, based on op
721     * @return true if the resulting is non-empty
722     */
723    public boolean clipRegion(Region region) {
724        return clipRegion(region, Region.Op.INTERSECT);
725    }
726
727    public DrawFilter getDrawFilter() {
728        return mDrawFilter;
729    }
730
731    public void setDrawFilter(DrawFilter filter) {
732        long nativeFilter = 0;
733        if (filter != null) {
734            nativeFilter = filter.mNativeInt;
735        }
736        mDrawFilter = filter;
737        nativeSetDrawFilter(mNativeCanvas, nativeFilter);
738    }
739
740    public enum EdgeType {
741
742        /**
743         * Black-and-White: Treat edges by just rounding to nearest pixel boundary
744         */
745        BW(0),  //!< treat edges by just rounding to nearest pixel boundary
746
747        /**
748         * Antialiased: Treat edges by rounding-out, since they may be antialiased
749         */
750        AA(1);
751
752        EdgeType(int nativeInt) {
753            this.nativeInt = nativeInt;
754        }
755
756        /**
757         * @hide
758         */
759        public final int nativeInt;
760    }
761
762    /**
763     * Return true if the specified rectangle, after being transformed by the
764     * current matrix, would lie completely outside of the current clip. Call
765     * this to check if an area you intend to draw into is clipped out (and
766     * therefore you can skip making the draw calls).
767     *
768     * @param rect  the rect to compare with the current clip
769     * @param type  {@link Canvas.EdgeType#AA} if the path should be considered antialiased,
770     *              since that means it may affect a larger area (more pixels) than
771     *              non-antialiased ({@link Canvas.EdgeType#BW}).
772     * @return      true if the rect (transformed by the canvas' matrix)
773     *              does not intersect with the canvas' clip
774     */
775    public boolean quickReject(RectF rect, EdgeType type) {
776        return native_quickReject(mNativeCanvas, rect);
777    }
778
779    /**
780     * Return true if the specified path, after being transformed by the
781     * current matrix, would lie completely outside of the current clip. Call
782     * this to check if an area you intend to draw into is clipped out (and
783     * therefore you can skip making the draw calls). Note: for speed it may
784     * return false even if the path itself might not intersect the clip
785     * (i.e. the bounds of the path intersects, but the path does not).
786     *
787     * @param path        The path to compare with the current clip
788     * @param type        {@link Canvas.EdgeType#AA} if the path should be considered antialiased,
789     *                    since that means it may affect a larger area (more pixels) than
790     *                    non-antialiased ({@link Canvas.EdgeType#BW}).
791     * @return            true if the path (transformed by the canvas' matrix)
792     *                    does not intersect with the canvas' clip
793     */
794    public boolean quickReject(Path path, EdgeType type) {
795        return native_quickReject(mNativeCanvas, path.ni());
796    }
797
798    /**
799     * Return true if the specified rectangle, after being transformed by the
800     * current matrix, would lie completely outside of the current clip. Call
801     * this to check if an area you intend to draw into is clipped out (and
802     * therefore you can skip making the draw calls).
803     *
804     * @param left        The left side of the rectangle to compare with the
805     *                    current clip
806     * @param top         The top of the rectangle to compare with the current
807     *                    clip
808     * @param right       The right side of the rectangle to compare with the
809     *                    current clip
810     * @param bottom      The bottom of the rectangle to compare with the
811     *                    current clip
812     * @param type        {@link Canvas.EdgeType#AA} if the path should be considered antialiased,
813     *                    since that means it may affect a larger area (more pixels) than
814     *                    non-antialiased ({@link Canvas.EdgeType#BW}).
815     * @return            true if the rect (transformed by the canvas' matrix)
816     *                    does not intersect with the canvas' clip
817     */
818    public boolean quickReject(float left, float top, float right, float bottom,
819                               EdgeType type) {
820        return native_quickReject(mNativeCanvas, left, top, right, bottom);
821    }
822
823    /**
824     * Return the bounds of the current clip (in local coordinates) in the
825     * bounds parameter, and return true if it is non-empty. This can be useful
826     * in a way similar to quickReject, in that it tells you that drawing
827     * outside of these bounds will be clipped out.
828     *
829     * @param bounds Return the clip bounds here. If it is null, ignore it but
830     *               still return true if the current clip is non-empty.
831     * @return true if the current clip is non-empty.
832     */
833    public boolean getClipBounds(Rect bounds) {
834        return native_getClipBounds(mNativeCanvas, bounds);
835    }
836
837    /**
838     * Retrieve the bounds of the current clip (in local coordinates).
839     *
840     * @return the clip bounds, or [0, 0, 0, 0] if the clip is empty.
841     */
842    public final Rect getClipBounds() {
843        Rect r = new Rect();
844        getClipBounds(r);
845        return r;
846    }
847
848    /**
849     * Fill the entire canvas' bitmap (restricted to the current clip) with the
850     * specified RGB color, using srcover porterduff mode.
851     *
852     * @param r red component (0..255) of the color to draw onto the canvas
853     * @param g green component (0..255) of the color to draw onto the canvas
854     * @param b blue component (0..255) of the color to draw onto the canvas
855     */
856    public void drawRGB(int r, int g, int b) {
857        native_drawRGB(mNativeCanvas, r, g, b);
858    }
859
860    /**
861     * Fill the entire canvas' bitmap (restricted to the current clip) with the
862     * specified ARGB color, using srcover porterduff mode.
863     *
864     * @param a alpha component (0..255) of the color to draw onto the canvas
865     * @param r red component (0..255) of the color to draw onto the canvas
866     * @param g green component (0..255) of the color to draw onto the canvas
867     * @param b blue component (0..255) of the color to draw onto the canvas
868     */
869    public void drawARGB(int a, int r, int g, int b) {
870        native_drawARGB(mNativeCanvas, a, r, g, b);
871    }
872
873    /**
874     * Fill the entire canvas' bitmap (restricted to the current clip) with the
875     * specified color, using srcover porterduff mode.
876     *
877     * @param color the color to draw onto the canvas
878     */
879    public void drawColor(int color) {
880        native_drawColor(mNativeCanvas, color);
881    }
882
883    /**
884     * Fill the entire canvas' bitmap (restricted to the current clip) with the
885     * specified color and porter-duff xfermode.
886     *
887     * @param color the color to draw with
888     * @param mode  the porter-duff mode to apply to the color
889     */
890    public void drawColor(int color, PorterDuff.Mode mode) {
891        native_drawColor(mNativeCanvas, color, mode.nativeInt);
892    }
893
894    /**
895     * Fill the entire canvas' bitmap (restricted to the current clip) with
896     * the specified paint. This is equivalent (but faster) to drawing an
897     * infinitely large rectangle with the specified paint.
898     *
899     * @param paint The paint used to draw onto the canvas
900     */
901    public void drawPaint(Paint paint) {
902        native_drawPaint(mNativeCanvas, paint.mNativePaint);
903    }
904
905    /**
906     * Draw a series of points. Each point is centered at the coordinate
907     * specified by pts[], and its diameter is specified by the paint's stroke
908     * width (as transformed by the canvas' CTM), with special treatment for
909     * a stroke width of 0, which always draws exactly 1 pixel (or at most 4
910     * if antialiasing is enabled). The shape of the point is controlled by
911     * the paint's Cap type. The shape is a square, unless the cap type is
912     * Round, in which case the shape is a circle.
913     *
914     * @param pts      Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
915     * @param offset   Number of values to skip before starting to draw.
916     * @param count    The number of values to process, after skipping offset
917     *                 of them. Since one point uses two values, the number of
918     *                 "points" that are drawn is really (count >> 1).
919     * @param paint    The paint used to draw the points
920     */
921    public native void drawPoints(float[] pts, int offset, int count, Paint paint);
922
923    /**
924     * Helper for drawPoints() that assumes you want to draw the entire array
925     */
926    public void drawPoints(float[] pts, Paint paint) {
927        drawPoints(pts, 0, pts.length, paint);
928    }
929
930    /**
931     * Helper for drawPoints() for drawing a single point.
932     */
933    public native void drawPoint(float x, float y, Paint paint);
934
935    /**
936     * Draw a line segment with the specified start and stop x,y coordinates,
937     * using the specified paint.
938     *
939     * <p>Note that since a line is always "framed", the Style is ignored in the paint.</p>
940     *
941     * <p>Degenerate lines (length is 0) will not be drawn.</p>
942     *
943     * @param startX The x-coordinate of the start point of the line
944     * @param startY The y-coordinate of the start point of the line
945     * @param paint  The paint used to draw the line
946     */
947    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
948        native_drawLine(mNativeCanvas, startX, startY, stopX, stopY, paint.mNativePaint);
949    }
950
951    /**
952     * Draw a series of lines. Each line is taken from 4 consecutive values
953     * in the pts array. Thus to draw 1 line, the array must contain at least 4
954     * values. This is logically the same as drawing the array as follows:
955     * drawLine(pts[0], pts[1], pts[2], pts[3]) followed by
956     * drawLine(pts[4], pts[5], pts[6], pts[7]) and so on.
957     *
958     * @param pts      Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
959     * @param offset   Number of values in the array to skip before drawing.
960     * @param count    The number of values in the array to process, after
961     *                 skipping "offset" of them. Since each line uses 4 values,
962     *                 the number of "lines" that are drawn is really
963     *                 (count >> 2).
964     * @param paint    The paint used to draw the points
965     */
966    public native void drawLines(float[] pts, int offset, int count, Paint paint);
967
968    public void drawLines(float[] pts, Paint paint) {
969        drawLines(pts, 0, pts.length, paint);
970    }
971
972    /**
973     * Draw the specified Rect using the specified paint. The rectangle will
974     * be filled or framed based on the Style in the paint.
975     *
976     * @param rect  The rect to be drawn
977     * @param paint The paint used to draw the rect
978     */
979    public void drawRect(RectF rect, Paint paint) {
980        native_drawRect(mNativeCanvas, rect, paint.mNativePaint);
981    }
982
983    /**
984     * Draw the specified Rect using the specified Paint. The rectangle
985     * will be filled or framed based on the Style in the paint.
986     *
987     * @param r        The rectangle to be drawn.
988     * @param paint    The paint used to draw the rectangle
989     */
990    public void drawRect(Rect r, Paint paint) {
991        drawRect(r.left, r.top, r.right, r.bottom, paint);
992    }
993
994
995    /**
996     * Draw the specified Rect using the specified paint. The rectangle will
997     * be filled or framed based on the Style in the paint.
998     *
999     * @param left   The left side of the rectangle to be drawn
1000     * @param top    The top side of the rectangle to be drawn
1001     * @param right  The right side of the rectangle to be drawn
1002     * @param bottom The bottom side of the rectangle to be drawn
1003     * @param paint  The paint used to draw the rect
1004     */
1005    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
1006        native_drawRect(mNativeCanvas, left, top, right, bottom, paint.mNativePaint);
1007    }
1008
1009    /**
1010     * Draw the specified oval using the specified paint. The oval will be
1011     * filled or framed based on the Style in the paint.
1012     *
1013     * @param oval The rectangle bounds of the oval to be drawn
1014     */
1015    public void drawOval(RectF oval, Paint paint) {
1016        if (oval == null) {
1017            throw new NullPointerException();
1018        }
1019        native_drawOval(mNativeCanvas, oval, paint.mNativePaint);
1020    }
1021
1022    /**
1023     * Draw the specified circle using the specified paint. If radius is <= 0,
1024     * then nothing will be drawn. The circle will be filled or framed based
1025     * on the Style in the paint.
1026     *
1027     * @param cx     The x-coordinate of the center of the cirle to be drawn
1028     * @param cy     The y-coordinate of the center of the cirle to be drawn
1029     * @param radius The radius of the cirle to be drawn
1030     * @param paint  The paint used to draw the circle
1031     */
1032    public void drawCircle(float cx, float cy, float radius, Paint paint) {
1033        native_drawCircle(mNativeCanvas, cx, cy, radius, paint.mNativePaint);
1034    }
1035
1036    /**
1037     * <p>Draw the specified arc, which will be scaled to fit inside the
1038     * specified oval.</p>
1039     *
1040     * <p>If the start angle is negative or >= 360, the start angle is treated
1041     * as start angle modulo 360.</p>
1042     *
1043     * <p>If the sweep angle is >= 360, then the oval is drawn
1044     * completely. Note that this differs slightly from SkPath::arcTo, which
1045     * treats the sweep angle modulo 360. If the sweep angle is negative,
1046     * the sweep angle is treated as sweep angle modulo 360</p>
1047     *
1048     * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
1049     * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
1050     *
1051     * @param oval       The bounds of oval used to define the shape and size
1052     *                   of the arc
1053     * @param startAngle Starting angle (in degrees) where the arc begins
1054     * @param sweepAngle Sweep angle (in degrees) measured clockwise
1055     * @param useCenter If true, include the center of the oval in the arc, and
1056                        close it if it is being stroked. This will draw a wedge
1057     * @param paint      The paint used to draw the arc
1058     */
1059    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
1060            Paint paint) {
1061        if (oval == null) {
1062            throw new NullPointerException();
1063        }
1064        native_drawArc(mNativeCanvas, oval, startAngle, sweepAngle,
1065                useCenter, paint.mNativePaint);
1066    }
1067
1068    /**
1069     * Draw the specified round-rect using the specified paint. The roundrect
1070     * will be filled or framed based on the Style in the paint.
1071     *
1072     * @param rect  The rectangular bounds of the roundRect to be drawn
1073     * @param rx    The x-radius of the oval used to round the corners
1074     * @param ry    The y-radius of the oval used to round the corners
1075     * @param paint The paint used to draw the roundRect
1076     */
1077    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
1078        drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
1079    }
1080
1081    /**
1082     * Draw the specified round-rect using the specified paint. The roundrect
1083     * will be filled or framed based on the Style in the paint.
1084     *
1085     * @param rx    The x-radius of the oval used to round the corners
1086     * @param ry    The y-radius of the oval used to round the corners
1087     * @param paint The paint used to draw the roundRect
1088     */
1089    public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
1090            Paint paint) {
1091        native_drawRoundRect(mNativeCanvas, left, top, right, bottom, rx, ry, paint.mNativePaint);
1092    }
1093
1094    /**
1095     * Draw the specified path using the specified paint. The path will be
1096     * filled or framed based on the Style in the paint.
1097     *
1098     * @param path  The path to be drawn
1099     * @param paint The paint used to draw the path
1100     */
1101    public void drawPath(Path path, Paint paint) {
1102        native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint);
1103    }
1104
1105    /**
1106     * @hide
1107     */
1108    protected static void throwIfCannotDraw(Bitmap bitmap) {
1109        if (bitmap.isRecycled()) {
1110            throw new RuntimeException("Canvas: trying to use a recycled bitmap " + bitmap);
1111        }
1112        if (!bitmap.isPremultiplied() && bitmap.getConfig() == Bitmap.Config.ARGB_8888 &&
1113                bitmap.hasAlpha()) {
1114            throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap "
1115                    + bitmap);
1116        }
1117    }
1118
1119    /**
1120     * Draws the specified bitmap as an N-patch (most often, a 9-patches.)
1121     *
1122     * @param patch The ninepatch object to render
1123     * @param dst The destination rectangle.
1124     * @param paint The paint to draw the bitmap with. may be null
1125     *
1126     * @hide
1127     */
1128    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
1129        patch.drawSoftware(this, dst, paint);
1130    }
1131
1132    /**
1133     * Draws the specified bitmap as an N-patch (most often, a 9-patches.)
1134     *
1135     * @param patch The ninepatch object to render
1136     * @param dst The destination rectangle.
1137     * @param paint The paint to draw the bitmap with. may be null
1138     *
1139     * @hide
1140     */
1141    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
1142        patch.drawSoftware(this, dst, paint);
1143    }
1144
1145    /**
1146     * Draw the specified bitmap, with its top/left corner at (x,y), using
1147     * the specified paint, transformed by the current matrix.
1148     *
1149     * <p>Note: if the paint contains a maskfilter that generates a mask which
1150     * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
1151     * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
1152     * Thus the color outside of the original width/height will be the edge
1153     * color replicated.
1154     *
1155     * <p>If the bitmap and canvas have different densities, this function
1156     * will take care of automatically scaling the bitmap to draw at the
1157     * same density as the canvas.
1158     *
1159     * @param bitmap The bitmap to be drawn
1160     * @param left   The position of the left side of the bitmap being drawn
1161     * @param top    The position of the top side of the bitmap being drawn
1162     * @param paint  The paint used to draw the bitmap (may be null)
1163     */
1164    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
1165        throwIfCannotDraw(bitmap);
1166        native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
1167                paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity);
1168    }
1169
1170    /**
1171     * Draw the specified bitmap, scaling/translating automatically to fill
1172     * the destination rectangle. If the source rectangle is not null, it
1173     * specifies the subset of the bitmap to draw.
1174     *
1175     * <p>Note: if the paint contains a maskfilter that generates a mask which
1176     * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
1177     * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
1178     * Thus the color outside of the original width/height will be the edge
1179     * color replicated.
1180     *
1181     * <p>This function <em>ignores the density associated with the bitmap</em>.
1182     * This is because the source and destination rectangle coordinate
1183     * spaces are in their respective densities, so must already have the
1184     * appropriate scaling factor applied.
1185     *
1186     * @param bitmap The bitmap to be drawn
1187     * @param src    May be null. The subset of the bitmap to be drawn
1188     * @param dst    The rectangle that the bitmap will be scaled/translated
1189     *               to fit into
1190     * @param paint  May be null. The paint used to draw the bitmap
1191     */
1192    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
1193        if (dst == null) {
1194            throw new NullPointerException();
1195        }
1196        throwIfCannotDraw(bitmap);
1197        native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
1198                          paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
1199    }
1200
1201    /**
1202     * Draw the specified bitmap, scaling/translating automatically to fill
1203     * the destination rectangle. If the source rectangle is not null, it
1204     * specifies the subset of the bitmap to draw.
1205     *
1206     * <p>Note: if the paint contains a maskfilter that generates a mask which
1207     * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
1208     * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
1209     * Thus the color outside of the original width/height will be the edge
1210     * color replicated.
1211     *
1212     * <p>This function <em>ignores the density associated with the bitmap</em>.
1213     * This is because the source and destination rectangle coordinate
1214     * spaces are in their respective densities, so must already have the
1215     * appropriate scaling factor applied.
1216     *
1217     * @param bitmap The bitmap to be drawn
1218     * @param src    May be null. The subset of the bitmap to be drawn
1219     * @param dst    The rectangle that the bitmap will be scaled/translated
1220     *               to fit into
1221     * @param paint  May be null. The paint used to draw the bitmap
1222     */
1223    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
1224        if (dst == null) {
1225            throw new NullPointerException();
1226        }
1227        throwIfCannotDraw(bitmap);
1228        native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
1229                paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
1230    }
1231
1232    /**
1233     * Treat the specified array of colors as a bitmap, and draw it. This gives
1234     * the same result as first creating a bitmap from the array, and then
1235     * drawing it, but this method avoids explicitly creating a bitmap object
1236     * which can be more efficient if the colors are changing often.
1237     *
1238     * @param colors Array of colors representing the pixels of the bitmap
1239     * @param offset Offset into the array of colors for the first pixel
1240     * @param stride The number of colors in the array between rows (must be
1241     *               >= width or <= -width).
1242     * @param x The X coordinate for where to draw the bitmap
1243     * @param y The Y coordinate for where to draw the bitmap
1244     * @param width The width of the bitmap
1245     * @param height The height of the bitmap
1246     * @param hasAlpha True if the alpha channel of the colors contains valid
1247     *                 values. If false, the alpha byte is ignored (assumed to
1248     *                 be 0xFF for every pixel).
1249     * @param paint  May be null. The paint used to draw the bitmap
1250     *
1251     * @deprecated Usage with a {@link #isHardwareAccelerated() hardware accelerated} canvas
1252     * requires an internal copy of color buffer contents every time this method is called. Using a
1253     * Bitmap avoids this copy, and allows the application to more explicitly control the lifetime
1254     * and copies of pixel data.
1255     */
1256    @Deprecated
1257    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
1258            int width, int height, boolean hasAlpha, Paint paint) {
1259        // check for valid input
1260        if (width < 0) {
1261            throw new IllegalArgumentException("width must be >= 0");
1262        }
1263        if (height < 0) {
1264            throw new IllegalArgumentException("height must be >= 0");
1265        }
1266        if (Math.abs(stride) < width) {
1267            throw new IllegalArgumentException("abs(stride) must be >= width");
1268        }
1269        int lastScanline = offset + (height - 1) * stride;
1270        int length = colors.length;
1271        if (offset < 0 || (offset + width > length) || lastScanline < 0
1272                || (lastScanline + width > length)) {
1273            throw new ArrayIndexOutOfBoundsException();
1274        }
1275        // quick escape if there's nothing to draw
1276        if (width == 0 || height == 0) {
1277            return;
1278        }
1279        // punch down to native for the actual draw
1280        native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha,
1281                paint != null ? paint.mNativePaint : 0);
1282    }
1283
1284    /**
1285     * Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y
1286     *
1287     * @deprecated Usage with a {@link #isHardwareAccelerated() hardware accelerated} canvas
1288     * requires an internal copy of color buffer contents every time this method is called. Using a
1289     * Bitmap avoids this copy, and allows the application to more explicitly control the lifetime
1290     * and copies of pixel data.
1291     */
1292    @Deprecated
1293    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
1294            int width, int height, boolean hasAlpha, Paint paint) {
1295        // call through to the common float version
1296        drawBitmap(colors, offset, stride, (float)x, (float)y, width, height,
1297                   hasAlpha, paint);
1298    }
1299
1300    /**
1301     * Draw the bitmap using the specified matrix.
1302     *
1303     * @param bitmap The bitmap to draw
1304     * @param matrix The matrix used to transform the bitmap when it is drawn
1305     * @param paint  May be null. The paint used to draw the bitmap
1306     */
1307    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
1308        nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(),
1309                paint != null ? paint.mNativePaint : 0);
1310    }
1311
1312    /**
1313     * @hide
1314     */
1315    protected static void checkRange(int length, int offset, int count) {
1316        if ((offset | count) < 0 || offset + count > length) {
1317            throw new ArrayIndexOutOfBoundsException();
1318        }
1319    }
1320
1321    /**
1322     * Draw the bitmap through the mesh, where mesh vertices are evenly
1323     * distributed across the bitmap. There are meshWidth+1 vertices across, and
1324     * meshHeight+1 vertices down. The verts array is accessed in row-major
1325     * order, so that the first meshWidth+1 vertices are distributed across the
1326     * top of the bitmap from left to right. A more general version of this
1327     * method is drawVertices().
1328     *
1329     * @param bitmap The bitmap to draw using the mesh
1330     * @param meshWidth The number of columns in the mesh. Nothing is drawn if
1331     *                  this is 0
1332     * @param meshHeight The number of rows in the mesh. Nothing is drawn if
1333     *                   this is 0
1334     * @param verts Array of x,y pairs, specifying where the mesh should be
1335     *              drawn. There must be at least
1336     *              (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values
1337     *              in the array
1338     * @param vertOffset Number of verts elements to skip before drawing
1339     * @param colors May be null. Specifies a color at each vertex, which is
1340     *               interpolated across the cell, and whose values are
1341     *               multiplied by the corresponding bitmap colors. If not null,
1342     *               there must be at least (meshWidth+1) * (meshHeight+1) +
1343     *               colorOffset values in the array.
1344     * @param colorOffset Number of color elements to skip before drawing
1345     * @param paint  May be null. The paint used to draw the bitmap
1346     */
1347    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight,
1348            float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint) {
1349        if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
1350            throw new ArrayIndexOutOfBoundsException();
1351        }
1352        if (meshWidth == 0 || meshHeight == 0) {
1353            return;
1354        }
1355        int count = (meshWidth + 1) * (meshHeight + 1);
1356        // we mul by 2 since we need two floats per vertex
1357        checkRange(verts.length, vertOffset, count * 2);
1358        if (colors != null) {
1359            // no mul by 2, since we need only 1 color per vertex
1360            checkRange(colors.length, colorOffset, count);
1361        }
1362        nativeDrawBitmapMesh(mNativeCanvas, bitmap.ni(), meshWidth, meshHeight,
1363                verts, vertOffset, colors, colorOffset,
1364                paint != null ? paint.mNativePaint : 0);
1365    }
1366
1367    public enum VertexMode {
1368        TRIANGLES(0),
1369        TRIANGLE_STRIP(1),
1370        TRIANGLE_FAN(2);
1371
1372        VertexMode(int nativeInt) {
1373            this.nativeInt = nativeInt;
1374        }
1375
1376        /**
1377         * @hide
1378         */
1379        public final int nativeInt;
1380    }
1381
1382    /**
1383     * Draw the array of vertices, interpreted as triangles (based on mode). The
1384     * verts array is required, and specifies the x,y pairs for each vertex. If
1385     * texs is non-null, then it is used to specify the coordinate in shader
1386     * coordinates to use at each vertex (the paint must have a shader in this
1387     * case). If there is no texs array, but there is a color array, then each
1388     * color is interpolated across its corresponding triangle in a gradient. If
1389     * both texs and colors arrays are present, then they behave as before, but
1390     * the resulting color at each pixels is the result of multiplying the
1391     * colors from the shader and the color-gradient together. The indices array
1392     * is optional, but if it is present, then it is used to specify the index
1393     * of each triangle, rather than just walking through the arrays in order.
1394     *
1395     * @param mode How to interpret the array of vertices
1396     * @param vertexCount The number of values in the vertices array (and
1397     *      corresponding texs and colors arrays if non-null). Each logical
1398     *      vertex is two values (x, y), vertexCount must be a multiple of 2.
1399     * @param verts Array of vertices for the mesh
1400     * @param vertOffset Number of values in the verts to skip before drawing.
1401     * @param texs May be null. If not null, specifies the coordinates to sample
1402     *      into the current shader (e.g. bitmap tile or gradient)
1403     * @param texOffset Number of values in texs to skip before drawing.
1404     * @param colors May be null. If not null, specifies a color for each
1405     *      vertex, to be interpolated across the triangle.
1406     * @param colorOffset Number of values in colors to skip before drawing.
1407     * @param indices If not null, array of indices to reference into the
1408     *      vertex (texs, colors) array.
1409     * @param indexCount number of entries in the indices array (if not null).
1410     * @param paint Specifies the shader to use if the texs array is non-null.
1411     */
1412    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1413            float[] texs, int texOffset, int[] colors, int colorOffset,
1414            short[] indices, int indexOffset, int indexCount, Paint paint) {
1415        checkRange(verts.length, vertOffset, vertexCount);
1416        if (texs != null) {
1417            checkRange(texs.length, texOffset, vertexCount);
1418        }
1419        if (colors != null) {
1420            checkRange(colors.length, colorOffset, vertexCount / 2);
1421        }
1422        if (indices != null) {
1423            checkRange(indices.length, indexOffset, indexCount);
1424        }
1425        nativeDrawVertices(mNativeCanvas, mode.nativeInt, vertexCount, verts,
1426                vertOffset, texs, texOffset, colors, colorOffset,
1427                indices, indexOffset, indexCount, paint.mNativePaint);
1428    }
1429
1430    /**
1431     * Draw the text, with origin at (x,y), using the specified paint. The
1432     * origin is interpreted based on the Align setting in the paint.
1433     *
1434     * @param text  The text to be drawn
1435     * @param x     The x-coordinate of the origin of the text being drawn
1436     * @param y     The y-coordinate of the origin of the text being drawn
1437     * @param paint The paint used for the text (e.g. color, size, style)
1438     */
1439    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
1440        if ((index | count | (index + count) |
1441            (text.length - index - count)) < 0) {
1442            throw new IndexOutOfBoundsException();
1443        }
1444        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
1445                paint.mNativePaint, paint.mNativeTypeface);
1446    }
1447
1448    /**
1449     * Draw the text, with origin at (x,y), using the specified paint. The
1450     * origin is interpreted based on the Align setting in the paint.
1451     *
1452     * @param text  The text to be drawn
1453     * @param x     The x-coordinate of the origin of the text being drawn
1454     * @param y     The y-coordinate of the origin of the text being drawn
1455     * @param paint The paint used for the text (e.g. color, size, style)
1456     */
1457    public void drawText(String text, float x, float y, Paint paint) {
1458        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
1459                paint.mNativePaint, paint.mNativeTypeface);
1460    }
1461
1462    /**
1463     * Draw the text, with origin at (x,y), using the specified paint.
1464     * The origin is interpreted based on the Align setting in the paint.
1465     *
1466     * @param text  The text to be drawn
1467     * @param start The index of the first character in text to draw
1468     * @param end   (end - 1) is the index of the last character in text to draw
1469     * @param x     The x-coordinate of the origin of the text being drawn
1470     * @param y     The y-coordinate of the origin of the text being drawn
1471     * @param paint The paint used for the text (e.g. color, size, style)
1472     */
1473    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1474        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1475            throw new IndexOutOfBoundsException();
1476        }
1477        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
1478                paint.mNativePaint, paint.mNativeTypeface);
1479    }
1480
1481    /**
1482     * Draw the specified range of text, specified by start/end, with its
1483     * origin at (x,y), in the specified Paint. The origin is interpreted
1484     * based on the Align setting in the Paint.
1485     *
1486     * @param text     The text to be drawn
1487     * @param start    The index of the first character in text to draw
1488     * @param end      (end - 1) is the index of the last character in text
1489     *                 to draw
1490     * @param x        The x-coordinate of origin for where to draw the text
1491     * @param y        The y-coordinate of origin for where to draw the text
1492     * @param paint The paint used for the text (e.g. color, size, style)
1493     */
1494    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
1495        if (text instanceof String || text instanceof SpannedString ||
1496            text instanceof SpannableString) {
1497            native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
1498                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
1499        } else if (text instanceof GraphicsOperations) {
1500            ((GraphicsOperations) text).drawText(this, start, end, x, y,
1501                    paint);
1502        } else {
1503            char[] buf = TemporaryBuffer.obtain(end - start);
1504            TextUtils.getChars(text, start, end, buf, 0);
1505            native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
1506                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
1507            TemporaryBuffer.recycle(buf);
1508        }
1509    }
1510
1511    /**
1512     * Render a run of all LTR or all RTL text, with shaping. This does not run
1513     * bidi on the provided text, but renders it as a uniform right-to-left or
1514     * left-to-right run, as indicated by dir. Alignment of the text is as
1515     * determined by the Paint's TextAlign value.
1516     *
1517     * @param text the text to render
1518     * @param index the start of the text to render
1519     * @param count the count of chars to render
1520     * @param contextIndex the start of the context for shaping.  Must be
1521     *         no greater than index.
1522     * @param contextCount the number of characters in the context for shaping.
1523     *         ContexIndex + contextCount must be no less than index
1524     *         + count.
1525     * @param x the x position at which to draw the text
1526     * @param y the y position at which to draw the text
1527     * @param dir the run direction, either {@link #DIRECTION_LTR} or
1528     *         {@link #DIRECTION_RTL}.
1529     * @param paint the paint
1530     * @hide
1531     */
1532    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1533            float x, float y, int dir, Paint paint) {
1534
1535        if (text == null) {
1536            throw new NullPointerException("text is null");
1537        }
1538        if (paint == null) {
1539            throw new NullPointerException("paint is null");
1540        }
1541        if ((index | count | text.length - index - count) < 0) {
1542            throw new IndexOutOfBoundsException();
1543        }
1544        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1545            throw new IllegalArgumentException("unknown dir: " + dir);
1546        }
1547
1548        native_drawTextRun(mNativeCanvas, text, index, count,
1549                contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface);
1550    }
1551
1552    /**
1553     * Render a run of all LTR or all RTL text, with shaping. This does not run
1554     * bidi on the provided text, but renders it as a uniform right-to-left or
1555     * left-to-right run, as indicated by dir. Alignment of the text is as
1556     * determined by the Paint's TextAlign value.
1557     *
1558     * @param text the text to render
1559     * @param start the start of the text to render. Data before this position
1560     *            can be used for shaping context.
1561     * @param end the end of the text to render. Data at or after this
1562     *            position can be used for shaping context.
1563     * @param x the x position at which to draw the text
1564     * @param y the y position at which to draw the text
1565     * @param dir the run direction, either 0 for LTR or 1 for RTL.
1566     * @param paint the paint
1567     * @hide
1568     */
1569    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1570            float x, float y, int dir, Paint paint) {
1571
1572        if (text == null) {
1573            throw new NullPointerException("text is null");
1574        }
1575        if (paint == null) {
1576            throw new NullPointerException("paint is null");
1577        }
1578        if ((start | end | end - start | text.length() - end) < 0) {
1579            throw new IndexOutOfBoundsException();
1580        }
1581
1582        int flags = dir == 0 ? 0 : 1;
1583
1584        if (text instanceof String || text instanceof SpannedString ||
1585                text instanceof SpannableString) {
1586            native_drawTextRun(mNativeCanvas, text.toString(), start, end,
1587                    contextStart, contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
1588        } else if (text instanceof GraphicsOperations) {
1589            ((GraphicsOperations) text).drawTextRun(this, start, end,
1590                    contextStart, contextEnd, x, y, flags, paint);
1591        } else {
1592            int contextLen = contextEnd - contextStart;
1593            int len = end - start;
1594            char[] buf = TemporaryBuffer.obtain(contextLen);
1595            TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1596            native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
1597                    0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
1598            TemporaryBuffer.recycle(buf);
1599        }
1600    }
1601
1602    /**
1603     * Draw the text in the array, with each character's origin specified by
1604     * the pos array.
1605     *
1606     * This method does not support glyph composition and decomposition and
1607     * should therefore not be used to render complex scripts.
1608     *
1609     * @param text     The text to be drawn
1610     * @param index    The index of the first character to draw
1611     * @param count    The number of characters to draw, starting from index.
1612     * @param pos      Array of [x,y] positions, used to position each
1613     *                 character
1614     * @param paint    The paint used for the text (e.g. color, size, style)
1615     */
1616    @Deprecated
1617    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
1618        if (index < 0 || index + count > text.length || count*2 > pos.length) {
1619            throw new IndexOutOfBoundsException();
1620        }
1621        native_drawPosText(mNativeCanvas, text, index, count, pos,
1622                paint.mNativePaint);
1623    }
1624
1625    /**
1626     * Draw the text in the array, with each character's origin specified by
1627     * the pos array.
1628     *
1629     * This method does not support glyph composition and decomposition and
1630     * should therefore not be used to render complex scripts.
1631     *
1632     * @param text  The text to be drawn
1633     * @param pos   Array of [x,y] positions, used to position each character
1634     * @param paint The paint used for the text (e.g. color, size, style)
1635     */
1636    @Deprecated
1637    public void drawPosText(String text, float[] pos, Paint paint) {
1638        if (text.length()*2 > pos.length) {
1639            throw new ArrayIndexOutOfBoundsException();
1640        }
1641        native_drawPosText(mNativeCanvas, text, pos, paint.mNativePaint);
1642    }
1643
1644    /**
1645     * Draw the text, with origin at (x,y), using the specified paint, along
1646     * the specified path. The paint's Align setting determins where along the
1647     * path to start the text.
1648     *
1649     * @param text     The text to be drawn
1650     * @param path     The path the text should follow for its baseline
1651     * @param hOffset  The distance along the path to add to the text's
1652     *                 starting position
1653     * @param vOffset  The distance above(-) or below(+) the path to position
1654     *                 the text
1655     * @param paint    The paint used for the text (e.g. color, size, style)
1656     */
1657    public void drawTextOnPath(char[] text, int index, int count, Path path,
1658            float hOffset, float vOffset, Paint paint) {
1659        if (index < 0 || index + count > text.length) {
1660            throw new ArrayIndexOutOfBoundsException();
1661        }
1662        native_drawTextOnPath(mNativeCanvas, text, index, count,
1663                path.ni(), hOffset, vOffset,
1664                paint.mBidiFlags, paint.mNativePaint);
1665    }
1666
1667    /**
1668     * Draw the text, with origin at (x,y), using the specified paint, along
1669     * the specified path. The paint's Align setting determins where along the
1670     * path to start the text.
1671     *
1672     * @param text     The text to be drawn
1673     * @param path     The path the text should follow for its baseline
1674     * @param hOffset  The distance along the path to add to the text's
1675     *                 starting position
1676     * @param vOffset  The distance above(-) or below(+) the path to position
1677     *                 the text
1678     * @param paint    The paint used for the text (e.g. color, size, style)
1679     */
1680    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1681        if (text.length() > 0) {
1682            native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
1683                    paint.mBidiFlags, paint.mNativePaint);
1684        }
1685    }
1686
1687    /**
1688     * Save the canvas state, draw the picture, and restore the canvas state.
1689     * This differs from picture.draw(canvas), which does not perform any
1690     * save/restore.
1691     *
1692     * <p>
1693     * <strong>Note:</strong> This forces the picture to internally call
1694     * {@link Picture#endRecording} in order to prepare for playback.
1695     *
1696     * @param picture  The picture to be drawn
1697     */
1698    public void drawPicture(Picture picture) {
1699        picture.endRecording();
1700        int restoreCount = save();
1701        picture.draw(this);
1702        restoreToCount(restoreCount);
1703    }
1704
1705    /**
1706     * Draw the picture, stretched to fit into the dst rectangle.
1707     */
1708    public void drawPicture(Picture picture, RectF dst) {
1709        save();
1710        translate(dst.left, dst.top);
1711        if (picture.getWidth() > 0 && picture.getHeight() > 0) {
1712            scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
1713        }
1714        drawPicture(picture);
1715        restore();
1716    }
1717
1718    /**
1719     * Draw the picture, stretched to fit into the dst rectangle.
1720     */
1721    public void drawPicture(Picture picture, Rect dst) {
1722        save();
1723        translate(dst.left, dst.top);
1724        if (picture.getWidth() > 0 && picture.getHeight() > 0) {
1725            scale((float) dst.width() / picture.getWidth(),
1726                    (float) dst.height() / picture.getHeight());
1727        }
1728        drawPicture(picture);
1729        restore();
1730    }
1731
1732    /**
1733     * Releases the resources associated with this canvas.
1734     *
1735     * @hide
1736     */
1737    public void release() {
1738        mFinalizer.dispose();
1739    }
1740
1741    /**
1742     * Free up as much memory as possible from private caches (e.g. fonts, images)
1743     *
1744     * @hide
1745     */
1746    public static native void freeCaches();
1747
1748    /**
1749     * Free up text layout caches
1750     *
1751     * @hide
1752     */
1753    public static native void freeTextLayoutCaches();
1754
1755    private static native long initRaster(long nativeBitmapOrZero);
1756    private static native void copyNativeCanvasState(long nativeSrcCanvas,
1757                                                     long nativeDstCanvas);
1758    private static native int native_saveLayer(long nativeCanvas,
1759                                               RectF bounds,
1760                                               long nativePaint,
1761                                               int layerFlags);
1762    private static native int native_saveLayer(long nativeCanvas, float l,
1763                                               float t, float r, float b,
1764                                               long nativePaint,
1765                                               int layerFlags);
1766    private static native int native_saveLayerAlpha(long nativeCanvas,
1767                                                    RectF bounds, int alpha,
1768                                                    int layerFlags);
1769    private static native int native_saveLayerAlpha(long nativeCanvas, float l,
1770                                                    float t, float r, float b,
1771                                                    int alpha, int layerFlags);
1772
1773    private static native void native_concat(long nativeCanvas,
1774                                             long nativeMatrix);
1775    private static native void native_setMatrix(long nativeCanvas,
1776                                                long nativeMatrix);
1777    private static native boolean native_clipRect(long nativeCanvas,
1778                                                  float left, float top,
1779                                                  float right, float bottom,
1780                                                  int regionOp);
1781    private static native boolean native_clipPath(long nativeCanvas,
1782                                                  long nativePath,
1783                                                  int regionOp);
1784    private static native boolean native_clipRegion(long nativeCanvas,
1785                                                    long nativeRegion,
1786                                                    int regionOp);
1787    private static native void nativeSetDrawFilter(long nativeCanvas,
1788                                                   long nativeFilter);
1789    private static native boolean native_getClipBounds(long nativeCanvas,
1790                                                       Rect bounds);
1791    private static native void native_getCTM(long nativeCanvas,
1792                                             long nativeMatrix);
1793    private static native boolean native_quickReject(long nativeCanvas,
1794                                                     RectF rect);
1795    private static native boolean native_quickReject(long nativeCanvas,
1796                                                     long nativePath);
1797    private static native boolean native_quickReject(long nativeCanvas,
1798                                                     float left, float top,
1799                                                     float right, float bottom);
1800    private static native void native_drawRGB(long nativeCanvas, int r, int g,
1801                                              int b);
1802    private static native void native_drawARGB(long nativeCanvas, int a, int r,
1803                                               int g, int b);
1804    private static native void native_drawColor(long nativeCanvas, int color);
1805    private static native void native_drawColor(long nativeCanvas, int color,
1806                                                int mode);
1807    private static native void native_drawPaint(long nativeCanvas,
1808                                                long nativePaint);
1809    private static native void native_drawLine(long nativeCanvas, float startX,
1810                                               float startY, float stopX,
1811                                               float stopY, long nativePaint);
1812    private static native void native_drawRect(long nativeCanvas, RectF rect,
1813                                               long nativePaint);
1814    private static native void native_drawRect(long nativeCanvas, float left,
1815                                               float top, float right,
1816                                               float bottom,
1817                                               long nativePaint);
1818    private static native void native_drawOval(long nativeCanvas, RectF oval,
1819                                               long nativePaint);
1820    private static native void native_drawCircle(long nativeCanvas, float cx,
1821                                                 float cy, float radius,
1822                                                 long nativePaint);
1823    private static native void native_drawArc(long nativeCanvas, RectF oval,
1824                                              float startAngle, float sweep,
1825                                              boolean useCenter,
1826                                              long nativePaint);
1827    private static native void native_drawRoundRect(long nativeCanvas,
1828            float left, float top, float right, float bottom,
1829            float rx, float ry, long nativePaint);
1830    private static native void native_drawPath(long nativeCanvas,
1831                                               long nativePath,
1832                                               long nativePaint);
1833    private native void native_drawBitmap(long nativeCanvas, long nativeBitmap,
1834                                                 float left, float top,
1835                                                 long nativePaintOrZero,
1836                                                 int canvasDensity,
1837                                                 int screenDensity,
1838                                                 int bitmapDensity);
1839    private native void native_drawBitmap(long nativeCanvas, long nativeBitmap,
1840                                                 Rect src, RectF dst,
1841                                                 long nativePaintOrZero,
1842                                                 int screenDensity,
1843                                                 int bitmapDensity);
1844    private static native void native_drawBitmap(long nativeCanvas,
1845                                                 long nativeBitmap,
1846                                                 Rect src, Rect dst,
1847                                                 long nativePaintOrZero,
1848                                                 int screenDensity,
1849                                                 int bitmapDensity);
1850    private static native void native_drawBitmap(long nativeCanvas, int[] colors,
1851                                                int offset, int stride, float x,
1852                                                 float y, int width, int height,
1853                                                 boolean hasAlpha,
1854                                                 long nativePaintOrZero);
1855    private static native void nativeDrawBitmapMatrix(long nativeCanvas,
1856                                                      long nativeBitmap,
1857                                                      long nativeMatrix,
1858                                                      long nativePaint);
1859    private static native void nativeDrawBitmapMesh(long nativeCanvas,
1860                                                    long nativeBitmap,
1861                                                    int meshWidth, int meshHeight,
1862                                                    float[] verts, int vertOffset,
1863                                                    int[] colors, int colorOffset,
1864                                                    long nativePaint);
1865    private static native void nativeDrawVertices(long nativeCanvas, int mode, int n,
1866                   float[] verts, int vertOffset, float[] texs, int texOffset,
1867                   int[] colors, int colorOffset, short[] indices,
1868                   int indexOffset, int indexCount, long nativePaint);
1869
1870    private static native void native_drawText(long nativeCanvas, char[] text,
1871                                               int index, int count, float x,
1872                                               float y, int flags, long nativePaint,
1873                                               long nativeTypeface);
1874    private static native void native_drawText(long nativeCanvas, String text,
1875                                               int start, int end, float x,
1876                                               float y, int flags, long nativePaint,
1877                                               long nativeTypeface);
1878
1879    private static native void native_drawTextRun(long nativeCanvas, String text,
1880            int start, int end, int contextStart, int contextEnd,
1881            float x, float y, int flags, long nativePaint, long nativeTypeface);
1882
1883    private static native void native_drawTextRun(long nativeCanvas, char[] text,
1884            int start, int count, int contextStart, int contextCount,
1885            float x, float y, int flags, long nativePaint, long nativeTypeface);
1886
1887    private static native void native_drawPosText(long nativeCanvas,
1888                                                  char[] text, int index,
1889                                                  int count, float[] pos,
1890                                                  long nativePaint);
1891    private static native void native_drawPosText(long nativeCanvas,
1892                                                  String text, float[] pos,
1893                                                  long nativePaint);
1894    private static native void native_drawTextOnPath(long nativeCanvas,
1895                                                     char[] text, int index,
1896                                                     int count, long nativePath,
1897                                                     float hOffset,
1898                                                     float vOffset, int bidiFlags,
1899                                                     long nativePaint);
1900    private static native void native_drawTextOnPath(long nativeCanvas,
1901                                                     String text, long nativePath,
1902                                                     float hOffset,
1903                                                     float vOffset,
1904                                                     int flags, long nativePaint);
1905    private static native void finalizer(long nativeCanvas);
1906}
1907