Paint.java revision e9ad3931fae71c8a8cd000fd52d5df4be79b0895
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 java.util.Locale;
25
26/**
27 * The Paint class holds the style and color information about how to draw
28 * geometries, text and bitmaps.
29 */
30public class Paint {
31
32    /**
33     * @hide
34     */
35    public long mNativePaint;
36    /**
37     * @hide
38     */
39    public long mNativeTypeface;
40
41    private ColorFilter mColorFilter;
42    private MaskFilter  mMaskFilter;
43    private PathEffect  mPathEffect;
44    private Rasterizer  mRasterizer;
45    private Shader      mShader;
46    private Typeface    mTypeface;
47    private Xfermode    mXfermode;
48
49    private boolean     mHasCompatScaling;
50    private float       mCompatScaling;
51    private float       mInvCompatScaling;
52
53    private Locale      mLocale;
54    private String      mFontFeatureSettings;
55
56    /**
57     * @hide
58     */
59    public  int         mBidiFlags = BIDI_DEFAULT_LTR;
60
61    static final Style[] sStyleArray = {
62        Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
63    };
64    static final Cap[] sCapArray = {
65        Cap.BUTT, Cap.ROUND, Cap.SQUARE
66    };
67    static final Join[] sJoinArray = {
68        Join.MITER, Join.ROUND, Join.BEVEL
69    };
70    static final Align[] sAlignArray = {
71        Align.LEFT, Align.CENTER, Align.RIGHT
72    };
73
74    /**
75     * Paint flag that enables antialiasing when drawing.
76     *
77     * <p>Enabling this flag will cause all draw operations that support
78     * antialiasing to use it.</p>
79     *
80     * @see #Paint(int)
81     * @see #setFlags(int)
82     */
83    public static final int ANTI_ALIAS_FLAG     = 0x01;
84    /**
85     * Paint flag that enables bilinear sampling on scaled bitmaps.
86     *
87     * <p>If cleared, scaled bitmaps will be drawn with nearest neighbor
88     * sampling, likely resulting in artifacts. This should generally be on
89     * when drawing bitmaps, unless performance-bound (rendering to software
90     * canvas) or preferring pixelation artifacts to blurriness when scaling
91     * significantly.</p>
92     *
93     * <p>If bitmaps are scaled for device density at creation time (as
94     * resource bitmaps often are) the filtering will already have been
95     * done.</p>
96     *
97     * @see #Paint(int)
98     * @see #setFlags(int)
99     */
100    public static final int FILTER_BITMAP_FLAG  = 0x02;
101    /**
102     * Paint flag that enables dithering when blitting.
103     *
104     * <p>Enabling this flag applies a dither to any blit operation where the
105     * target's colour space is more constrained than the source.
106     *
107     * @see #Paint(int)
108     * @see #setFlags(int)
109     */
110    public static final int DITHER_FLAG         = 0x04;
111    /**
112     * Paint flag that applies an underline decoration to drawn text.
113     *
114     * @see #Paint(int)
115     * @see #setFlags(int)
116     */
117    public static final int UNDERLINE_TEXT_FLAG = 0x08;
118    /**
119     * Paint flag that applies a strike-through decoration to drawn text.
120     *
121     * @see #Paint(int)
122     * @see #setFlags(int)
123     */
124    public static final int STRIKE_THRU_TEXT_FLAG = 0x10;
125    /**
126     * Paint flag that applies a synthetic bolding effect to drawn text.
127     *
128     * <p>Enabling this flag will cause text draw operations to apply a
129     * simulated bold effect when drawing a {@link Typeface} that is not
130     * already bold.</p>
131     *
132     * @see #Paint(int)
133     * @see #setFlags(int)
134     */
135    public static final int FAKE_BOLD_TEXT_FLAG = 0x20;
136    /**
137     * Paint flag that enables smooth linear scaling of text.
138     *
139     * <p>Enabling this flag does not actually scale text, but rather adjusts
140     * text draw operations to deal gracefully with smooth adjustment of scale.
141     * When this flag is enabled, font hinting is disabled to prevent shape
142     * deformation between scale factors, and glyph caching is disabled due to
143     * the large number of glyph images that will be generated.</p>
144     *
145     * <p>{@link #SUBPIXEL_TEXT_FLAG} should be used in conjunction with this
146     * flag to prevent glyph positions from snapping to whole pixel values as
147     * scale factor is adjusted.</p>
148     *
149     * @see #Paint(int)
150     * @see #setFlags(int)
151     */
152    public static final int LINEAR_TEXT_FLAG    = 0x40;
153    /**
154     * Paint flag that enables subpixel positioning of text.
155     *
156     * <p>Enabling this flag causes glyph advances to be computed with subpixel
157     * accuracy.</p>
158     *
159     * <p>This can be used with {@link #LINEAR_TEXT_FLAG} to prevent text from
160     * jittering during smooth scale transitions.</p>
161     *
162     * @see #Paint(int)
163     * @see #setFlags(int)
164     */
165    public static final int SUBPIXEL_TEXT_FLAG  = 0x80;
166    /** Legacy Paint flag, no longer used. */
167    public static final int DEV_KERN_TEXT_FLAG  = 0x100;
168    /** @hide bit mask for the flag enabling subpixel glyph rendering for text */
169    public static final int LCD_RENDER_TEXT_FLAG = 0x200;
170    /**
171     * Paint flag that enables the use of bitmap fonts when drawing text.
172     *
173     * <p>Disabling this flag will prevent text draw operations from using
174     * embedded bitmap strikes in fonts, causing fonts with both scalable
175     * outlines and bitmap strikes to draw only the scalable outlines, and
176     * fonts with only bitmap strikes to not draw at all.</p>
177     *
178     * @see #Paint(int)
179     * @see #setFlags(int)
180     */
181    public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400;
182    /** @hide bit mask for the flag forcing freetype's autohinter on for text */
183    public static final int AUTO_HINTING_TEXT_FLAG = 0x800;
184    /** @hide bit mask for the flag enabling vertical rendering for text */
185    public static final int VERTICAL_TEXT_FLAG = 0x1000;
186
187    // we use this when we first create a paint
188    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG;
189
190    /**
191     * Font hinter option that disables font hinting.
192     *
193     * @see #setHinting(int)
194     */
195    public static final int HINTING_OFF = 0x0;
196
197    /**
198     * Font hinter option that enables font hinting.
199     *
200     * @see #setHinting(int)
201     */
202    public static final int HINTING_ON = 0x1;
203
204    /**
205     * Bidi flag to set LTR paragraph direction.
206     *
207     * @hide
208     */
209    public static final int BIDI_LTR = 0x0;
210
211    /**
212     * Bidi flag to set RTL paragraph direction.
213     *
214     * @hide
215     */
216    public static final int BIDI_RTL = 0x1;
217
218    /**
219     * Bidi flag to detect paragraph direction via heuristics, defaulting to
220     * LTR.
221     *
222     * @hide
223     */
224    public static final int BIDI_DEFAULT_LTR = 0x2;
225
226    /**
227     * Bidi flag to detect paragraph direction via heuristics, defaulting to
228     * RTL.
229     *
230     * @hide
231     */
232    public static final int BIDI_DEFAULT_RTL = 0x3;
233
234    /**
235     * Bidi flag to override direction to all LTR (ignore bidi).
236     *
237     * @hide
238     */
239    public static final int BIDI_FORCE_LTR = 0x4;
240
241    /**
242     * Bidi flag to override direction to all RTL (ignore bidi).
243     *
244     * @hide
245     */
246    public static final int BIDI_FORCE_RTL = 0x5;
247
248    /**
249     * Maximum Bidi flag value.
250     * @hide
251     */
252    private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
253
254    /**
255     * Mask for bidi flags.
256     * @hide
257     */
258    private static final int BIDI_FLAG_MASK = 0x7;
259
260    /**
261     * Flag for getTextRunAdvances indicating left-to-right run direction.
262     * @hide
263     */
264    public static final int DIRECTION_LTR = 0;
265
266    /**
267     * Flag for getTextRunAdvances indicating right-to-left run direction.
268     * @hide
269     */
270    public static final int DIRECTION_RTL = 1;
271
272    /**
273     * Option for getTextRunCursor to compute the valid cursor after
274     * offset or the limit of the context, whichever is less.
275     * @hide
276     */
277    public static final int CURSOR_AFTER = 0;
278
279    /**
280     * Option for getTextRunCursor to compute the valid cursor at or after
281     * the offset or the limit of the context, whichever is less.
282     * @hide
283     */
284    public static final int CURSOR_AT_OR_AFTER = 1;
285
286     /**
287     * Option for getTextRunCursor to compute the valid cursor before
288     * offset or the start of the context, whichever is greater.
289     * @hide
290     */
291    public static final int CURSOR_BEFORE = 2;
292
293   /**
294     * Option for getTextRunCursor to compute the valid cursor at or before
295     * offset or the start of the context, whichever is greater.
296     * @hide
297     */
298    public static final int CURSOR_AT_OR_BEFORE = 3;
299
300    /**
301     * Option for getTextRunCursor to return offset if the cursor at offset
302     * is valid, or -1 if it isn't.
303     * @hide
304     */
305    public static final int CURSOR_AT = 4;
306
307    /**
308     * Maximum cursor option value.
309     */
310    private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT;
311
312    /**
313     * The Style specifies if the primitive being drawn is filled, stroked, or
314     * both (in the same color). The default is FILL.
315     */
316    public enum Style {
317        /**
318         * Geometry and text drawn with this style will be filled, ignoring all
319         * stroke-related settings in the paint.
320         */
321        FILL            (0),
322        /**
323         * Geometry and text drawn with this style will be stroked, respecting
324         * the stroke-related fields on the paint.
325         */
326        STROKE          (1),
327        /**
328         * Geometry and text drawn with this style will be both filled and
329         * stroked at the same time, respecting the stroke-related fields on
330         * the paint. This mode can give unexpected results if the geometry
331         * is oriented counter-clockwise. This restriction does not apply to
332         * either FILL or STROKE.
333         */
334        FILL_AND_STROKE (2);
335
336        Style(int nativeInt) {
337            this.nativeInt = nativeInt;
338        }
339        final int nativeInt;
340    }
341
342    /**
343     * The Cap specifies the treatment for the beginning and ending of
344     * stroked lines and paths. The default is BUTT.
345     */
346    public enum Cap {
347        /**
348         * The stroke ends with the path, and does not project beyond it.
349         */
350        BUTT    (0),
351        /**
352         * The stroke projects out as a semicircle, with the center at the
353         * end of the path.
354         */
355        ROUND   (1),
356        /**
357         * The stroke projects out as a square, with the center at the end
358         * of the path.
359         */
360        SQUARE  (2);
361
362        private Cap(int nativeInt) {
363            this.nativeInt = nativeInt;
364        }
365        final int nativeInt;
366    }
367
368    /**
369     * The Join specifies the treatment where lines and curve segments
370     * join on a stroked path. The default is MITER.
371     */
372    public enum Join {
373        /**
374         * The outer edges of a join meet at a sharp angle
375         */
376        MITER   (0),
377        /**
378         * The outer edges of a join meet in a circular arc.
379         */
380        ROUND   (1),
381        /**
382         * The outer edges of a join meet with a straight line
383         */
384        BEVEL   (2);
385
386        private Join(int nativeInt) {
387            this.nativeInt = nativeInt;
388        }
389        final int nativeInt;
390    }
391
392    /**
393     * Align specifies how drawText aligns its text relative to the
394     * [x,y] coordinates. The default is LEFT.
395     */
396    public enum Align {
397        /**
398         * The text is drawn to the right of the x,y origin
399         */
400        LEFT    (0),
401        /**
402         * The text is drawn centered horizontally on the x,y origin
403         */
404        CENTER  (1),
405        /**
406         * The text is drawn to the left of the x,y origin
407         */
408        RIGHT   (2);
409
410        private Align(int nativeInt) {
411            this.nativeInt = nativeInt;
412        }
413        final int nativeInt;
414    }
415
416    /**
417     * Create a new paint with default settings.
418     */
419    public Paint() {
420        this(0);
421    }
422
423    /**
424     * Create a new paint with the specified flags. Use setFlags() to change
425     * these after the paint is created.
426     *
427     * @param flags initial flag bits, as if they were passed via setFlags().
428     */
429    public Paint(int flags) {
430        mNativePaint = native_init();
431        setFlags(flags | DEFAULT_PAINT_FLAGS);
432        // TODO: Turning off hinting has undesirable side effects, we need to
433        //       revisit hinting once we add support for subpixel positioning
434        // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
435        //        ? HINTING_OFF : HINTING_ON);
436        mCompatScaling = mInvCompatScaling = 1;
437        setTextLocale(Locale.getDefault());
438    }
439
440    /**
441     * Create a new paint, initialized with the attributes in the specified
442     * paint parameter.
443     *
444     * @param paint Existing paint used to initialized the attributes of the
445     *              new paint.
446     */
447    public Paint(Paint paint) {
448        mNativePaint = native_initWithPaint(paint.mNativePaint);
449        setClassVariablesFrom(paint);
450    }
451
452    /** Restores the paint to its default settings. */
453    public void reset() {
454        native_reset(mNativePaint);
455        setFlags(DEFAULT_PAINT_FLAGS);
456
457        // TODO: Turning off hinting has undesirable side effects, we need to
458        //       revisit hinting once we add support for subpixel positioning
459        // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
460        //        ? HINTING_OFF : HINTING_ON);
461
462        mColorFilter = null;
463        mMaskFilter = null;
464        mPathEffect = null;
465        mRasterizer = null;
466        mShader = null;
467        mTypeface = null;
468        mNativeTypeface = 0;
469        mXfermode = null;
470
471        mHasCompatScaling = false;
472        mCompatScaling = 1;
473        mInvCompatScaling = 1;
474
475        mBidiFlags = BIDI_DEFAULT_LTR;
476        setTextLocale(Locale.getDefault());
477        setElegantTextHeight(false);
478        mFontFeatureSettings = null;
479    }
480
481    /**
482     * Copy the fields from src into this paint. This is equivalent to calling
483     * get() on all of the src fields, and calling the corresponding set()
484     * methods on this.
485     */
486    public void set(Paint src) {
487        if (this != src) {
488            // copy over the native settings
489            native_set(mNativePaint, src.mNativePaint);
490            setClassVariablesFrom(src);
491        }
492    }
493
494    /**
495     * Set all class variables using current values from the given
496     * {@link Paint}.
497     */
498    private void setClassVariablesFrom(Paint paint) {
499        mColorFilter = paint.mColorFilter;
500        mMaskFilter = paint.mMaskFilter;
501        mPathEffect = paint.mPathEffect;
502        mRasterizer = paint.mRasterizer;
503        if (paint.mShader != null) {
504            mShader = paint.mShader.copy();
505        } else {
506            mShader = null;
507        }
508        mTypeface = paint.mTypeface;
509        mNativeTypeface = paint.mNativeTypeface;
510        mXfermode = paint.mXfermode;
511
512        mHasCompatScaling = paint.mHasCompatScaling;
513        mCompatScaling = paint.mCompatScaling;
514        mInvCompatScaling = paint.mInvCompatScaling;
515
516        mBidiFlags = paint.mBidiFlags;
517        mLocale = paint.mLocale;
518        mFontFeatureSettings = paint.mFontFeatureSettings;
519    }
520
521    /** @hide */
522    public void setCompatibilityScaling(float factor) {
523        if (factor == 1.0) {
524            mHasCompatScaling = false;
525            mCompatScaling = mInvCompatScaling = 1.0f;
526        } else {
527            mHasCompatScaling = true;
528            mCompatScaling = factor;
529            mInvCompatScaling = 1.0f/factor;
530        }
531    }
532
533    /**
534     * Return the bidi flags on the paint.
535     *
536     * @return the bidi flags on the paint
537     * @hide
538     */
539    public int getBidiFlags() {
540        return mBidiFlags;
541    }
542
543    /**
544     * Set the bidi flags on the paint.
545     * @hide
546     */
547    public void setBidiFlags(int flags) {
548        // only flag value is the 3-bit BIDI control setting
549        flags &= BIDI_FLAG_MASK;
550        if (flags > BIDI_MAX_FLAG_VALUE) {
551            throw new IllegalArgumentException("unknown bidi flag: " + flags);
552        }
553        mBidiFlags = flags;
554    }
555
556    /**
557     * Return the paint's flags. Use the Flag enum to test flag values.
558     *
559     * @return the paint's flags (see enums ending in _Flag for bit masks)
560     */
561    public native int getFlags();
562
563    /**
564     * Set the paint's flags. Use the Flag enum to specific flag values.
565     *
566     * @param flags The new flag bits for the paint
567     */
568    public native void setFlags(int flags);
569
570    /**
571     * Return the paint's hinting mode.  Returns either
572     * {@link #HINTING_OFF} or {@link #HINTING_ON}.
573     */
574    public native int getHinting();
575
576    /**
577     * Set the paint's hinting mode.  May be either
578     * {@link #HINTING_OFF} or {@link #HINTING_ON}.
579     */
580    public native void setHinting(int mode);
581
582    /**
583     * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
584     * AntiAliasing smooths out the edges of what is being drawn, but is has
585     * no impact on the interior of the shape. See setDither() and
586     * setFilterBitmap() to affect how colors are treated.
587     *
588     * @return true if the antialias bit is set in the paint's flags.
589     */
590    public final boolean isAntiAlias() {
591        return (getFlags() & ANTI_ALIAS_FLAG) != 0;
592    }
593
594    /**
595     * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
596     * AntiAliasing smooths out the edges of what is being drawn, but is has
597     * no impact on the interior of the shape. See setDither() and
598     * setFilterBitmap() to affect how colors are treated.
599     *
600     * @param aa true to set the antialias bit in the flags, false to clear it
601     */
602    public native void setAntiAlias(boolean aa);
603
604    /**
605     * Helper for getFlags(), returning true if DITHER_FLAG bit is set
606     * Dithering affects how colors that are higher precision than the device
607     * are down-sampled. No dithering is generally faster, but higher precision
608     * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
609     * distribute the error inherent in this process, to reduce the visual
610     * artifacts.
611     *
612     * @return true if the dithering bit is set in the paint's flags.
613     */
614    public final boolean isDither() {
615        return (getFlags() & DITHER_FLAG) != 0;
616    }
617
618    /**
619     * Helper for setFlags(), setting or clearing the DITHER_FLAG bit
620     * Dithering affects how colors that are higher precision than the device
621     * are down-sampled. No dithering is generally faster, but higher precision
622     * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
623     * distribute the error inherent in this process, to reduce the visual
624     * artifacts.
625     *
626     * @param dither true to set the dithering bit in flags, false to clear it
627     */
628    public native void setDither(boolean dither);
629
630    /**
631     * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
632     *
633     * @return true if the lineartext bit is set in the paint's flags
634     */
635    public final boolean isLinearText() {
636        return (getFlags() & LINEAR_TEXT_FLAG) != 0;
637    }
638
639    /**
640     * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit
641     *
642     * @param linearText true to set the linearText bit in the paint's flags,
643     *                   false to clear it.
644     */
645    public native void setLinearText(boolean linearText);
646
647    /**
648     * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
649     *
650     * @return true if the subpixel bit is set in the paint's flags
651     */
652    public final boolean isSubpixelText() {
653        return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
654    }
655
656    /**
657     * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
658     *
659     * @param subpixelText true to set the subpixelText bit in the paint's
660     *                     flags, false to clear it.
661     */
662    public native void setSubpixelText(boolean subpixelText);
663
664    /**
665     * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
666     *
667     * @return true if the underlineText bit is set in the paint's flags.
668     */
669    public final boolean isUnderlineText() {
670        return (getFlags() & UNDERLINE_TEXT_FLAG) != 0;
671    }
672
673    /**
674     * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit
675     *
676     * @param underlineText true to set the underlineText bit in the paint's
677     *                      flags, false to clear it.
678     */
679    public native void setUnderlineText(boolean underlineText);
680
681    /**
682     * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
683     *
684     * @return true if the strikeThruText bit is set in the paint's flags.
685     */
686    public final boolean isStrikeThruText() {
687        return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0;
688    }
689
690    /**
691     * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
692     *
693     * @param strikeThruText true to set the strikeThruText bit in the paint's
694     *                       flags, false to clear it.
695     */
696    public native void setStrikeThruText(boolean strikeThruText);
697
698    /**
699     * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
700     *
701     * @return true if the fakeBoldText bit is set in the paint's flags.
702     */
703    public final boolean isFakeBoldText() {
704        return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0;
705    }
706
707    /**
708     * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit
709     *
710     * @param fakeBoldText true to set the fakeBoldText bit in the paint's
711     *                     flags, false to clear it.
712     */
713    public native void setFakeBoldText(boolean fakeBoldText);
714
715    /**
716     * Whether or not the bitmap filter is activated.
717     * Filtering affects the sampling of bitmaps when they are transformed.
718     * Filtering does not affect how the colors in the bitmap are converted into
719     * device pixels. That is dependent on dithering and xfermodes.
720     *
721     * @see #setFilterBitmap(boolean) setFilterBitmap()
722     */
723    public final boolean isFilterBitmap() {
724        return (getFlags() & FILTER_BITMAP_FLAG) != 0;
725    }
726
727    /**
728     * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
729     * Filtering affects the sampling of bitmaps when they are transformed.
730     * Filtering does not affect how the colors in the bitmap are converted into
731     * device pixels. That is dependent on dithering and xfermodes.
732     *
733     * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
734     *               flags, false to clear it.
735     */
736    public native void setFilterBitmap(boolean filter);
737
738    /**
739     * Return the paint's style, used for controlling how primitives'
740     * geometries are interpreted (except for drawBitmap, which always assumes
741     * FILL_STYLE).
742     *
743     * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
744     */
745    public Style getStyle() {
746        return sStyleArray[native_getStyle(mNativePaint)];
747    }
748
749    /**
750     * Set the paint's style, used for controlling how primitives'
751     * geometries are interpreted (except for drawBitmap, which always assumes
752     * Fill).
753     *
754     * @param style The new style to set in the paint
755     */
756    public void setStyle(Style style) {
757        native_setStyle(mNativePaint, style.nativeInt);
758    }
759
760    /**
761     * Return the paint's color. Note that the color is a 32bit value
762     * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
763     * meaning that its alpha can be any value, regardless of the values of
764     * r,g,b. See the Color class for more details.
765     *
766     * @return the paint's color (and alpha).
767     */
768    public native int getColor();
769
770    /**
771     * Set the paint's color. Note that the color is an int containing alpha
772     * as well as r,g,b. This 32bit value is not premultiplied, meaning that
773     * its alpha can be any value, regardless of the values of r,g,b.
774     * See the Color class for more details.
775     *
776     * @param color The new color (including alpha) to set in the paint.
777     */
778    public native void setColor(int color);
779
780    /**
781     * Helper to getColor() that just returns the color's alpha value. This is
782     * the same as calling getColor() >>> 24. It always returns a value between
783     * 0 (completely transparent) and 255 (completely opaque).
784     *
785     * @return the alpha component of the paint's color.
786     */
787    public native int getAlpha();
788
789    /**
790     * Helper to setColor(), that only assigns the color's alpha value,
791     * leaving its r,g,b values unchanged. Results are undefined if the alpha
792     * value is outside of the range [0..255]
793     *
794     * @param a set the alpha component [0..255] of the paint's color.
795     */
796    public native void setAlpha(int a);
797
798    /**
799     * Helper to setColor(), that takes a,r,g,b and constructs the color int
800     *
801     * @param a The new alpha component (0..255) of the paint's color.
802     * @param r The new red component (0..255) of the paint's color.
803     * @param g The new green component (0..255) of the paint's color.
804     * @param b The new blue component (0..255) of the paint's color.
805     */
806    public void setARGB(int a, int r, int g, int b) {
807        setColor((a << 24) | (r << 16) | (g << 8) | b);
808    }
809
810    /**
811     * Return the width for stroking.
812     * <p />
813     * A value of 0 strokes in hairline mode.
814     * Hairlines always draws a single pixel independent of the canva's matrix.
815     *
816     * @return the paint's stroke width, used whenever the paint's style is
817     *         Stroke or StrokeAndFill.
818     */
819    public native float getStrokeWidth();
820
821    /**
822     * Set the width for stroking.
823     * Pass 0 to stroke in hairline mode.
824     * Hairlines always draws a single pixel independent of the canva's matrix.
825     *
826     * @param width set the paint's stroke width, used whenever the paint's
827     *              style is Stroke or StrokeAndFill.
828     */
829    public native void setStrokeWidth(float width);
830
831    /**
832     * Return the paint's stroke miter value. Used to control the behavior
833     * of miter joins when the joins angle is sharp.
834     *
835     * @return the paint's miter limit, used whenever the paint's style is
836     *         Stroke or StrokeAndFill.
837     */
838    public native float getStrokeMiter();
839
840    /**
841     * Set the paint's stroke miter value. This is used to control the behavior
842     * of miter joins when the joins angle is sharp. This value must be >= 0.
843     *
844     * @param miter set the miter limit on the paint, used whenever the paint's
845     *              style is Stroke or StrokeAndFill.
846     */
847    public native void setStrokeMiter(float miter);
848
849    /**
850     * Return the paint's Cap, controlling how the start and end of stroked
851     * lines and paths are treated.
852     *
853     * @return the line cap style for the paint, used whenever the paint's
854     *         style is Stroke or StrokeAndFill.
855     */
856    public Cap getStrokeCap() {
857        return sCapArray[native_getStrokeCap(mNativePaint)];
858    }
859
860    /**
861     * Set the paint's Cap.
862     *
863     * @param cap set the paint's line cap style, used whenever the paint's
864     *            style is Stroke or StrokeAndFill.
865     */
866    public void setStrokeCap(Cap cap) {
867        native_setStrokeCap(mNativePaint, cap.nativeInt);
868    }
869
870    /**
871     * Return the paint's stroke join type.
872     *
873     * @return the paint's Join.
874     */
875    public Join getStrokeJoin() {
876        return sJoinArray[native_getStrokeJoin(mNativePaint)];
877    }
878
879    /**
880     * Set the paint's Join.
881     *
882     * @param join set the paint's Join, used whenever the paint's style is
883     *             Stroke or StrokeAndFill.
884     */
885    public void setStrokeJoin(Join join) {
886        native_setStrokeJoin(mNativePaint, join.nativeInt);
887    }
888
889    /**
890     * Applies any/all effects (patheffect, stroking) to src, returning the
891     * result in dst. The result is that drawing src with this paint will be
892     * the same as drawing dst with a default paint (at least from the
893     * geometric perspective).
894     *
895     * @param src input path
896     * @param dst output path (may be the same as src)
897     * @return    true if the path should be filled, or false if it should be
898     *                 drawn with a hairline (width == 0)
899     */
900    public boolean getFillPath(Path src, Path dst) {
901        return native_getFillPath(mNativePaint, src.ni(), dst.ni());
902    }
903
904    /**
905     * Get the paint's shader object.
906     *
907     * @return the paint's shader (or null)
908     */
909    public Shader getShader() {
910        return mShader;
911    }
912
913    /**
914     * Set or clear the shader object.
915     * <p />
916     * Pass null to clear any previous shader.
917     * As a convenience, the parameter passed is also returned.
918     *
919     * @param shader May be null. the new shader to be installed in the paint
920     * @return       shader
921     */
922    public Shader setShader(Shader shader) {
923        long shaderNative = 0;
924        if (shader != null)
925            shaderNative = shader.getNativeInstance();
926        native_setShader(mNativePaint, shaderNative);
927        mShader = shader;
928        return shader;
929    }
930
931    /**
932     * Get the paint's colorfilter (maybe be null).
933     *
934     * @return the paint's colorfilter (maybe be null)
935     */
936    public ColorFilter getColorFilter() {
937        return mColorFilter;
938    }
939
940    /**
941     * Set or clear the paint's colorfilter, returning the parameter.
942     *
943     * @param filter May be null. The new filter to be installed in the paint
944     * @return       filter
945     */
946    public ColorFilter setColorFilter(ColorFilter filter) {
947        long filterNative = 0;
948        if (filter != null)
949            filterNative = filter.native_instance;
950        native_setColorFilter(mNativePaint, filterNative);
951        mColorFilter = filter;
952        return filter;
953    }
954
955    /**
956     * Get the paint's xfermode object.
957     *
958     * @return the paint's xfermode (or null)
959     */
960    public Xfermode getXfermode() {
961        return mXfermode;
962    }
963
964    /**
965     * Set or clear the xfermode object.
966     * <p />
967     * Pass null to clear any previous xfermode.
968     * As a convenience, the parameter passed is also returned.
969     *
970     * @param xfermode May be null. The xfermode to be installed in the paint
971     * @return         xfermode
972     */
973    public Xfermode setXfermode(Xfermode xfermode) {
974        long xfermodeNative = 0;
975        if (xfermode != null)
976            xfermodeNative = xfermode.native_instance;
977        native_setXfermode(mNativePaint, xfermodeNative);
978        mXfermode = xfermode;
979        return xfermode;
980    }
981
982    /**
983     * Get the paint's patheffect object.
984     *
985     * @return the paint's patheffect (or null)
986     */
987    public PathEffect getPathEffect() {
988        return mPathEffect;
989    }
990
991    /**
992     * Set or clear the patheffect object.
993     * <p />
994     * Pass null to clear any previous patheffect.
995     * As a convenience, the parameter passed is also returned.
996     *
997     * @param effect May be null. The patheffect to be installed in the paint
998     * @return       effect
999     */
1000    public PathEffect setPathEffect(PathEffect effect) {
1001        long effectNative = 0;
1002        if (effect != null) {
1003            effectNative = effect.native_instance;
1004        }
1005        native_setPathEffect(mNativePaint, effectNative);
1006        mPathEffect = effect;
1007        return effect;
1008    }
1009
1010    /**
1011     * Get the paint's maskfilter object.
1012     *
1013     * @return the paint's maskfilter (or null)
1014     */
1015    public MaskFilter getMaskFilter() {
1016        return mMaskFilter;
1017    }
1018
1019    /**
1020     * Set or clear the maskfilter object.
1021     * <p />
1022     * Pass null to clear any previous maskfilter.
1023     * As a convenience, the parameter passed is also returned.
1024     *
1025     * @param maskfilter May be null. The maskfilter to be installed in the
1026     *                   paint
1027     * @return           maskfilter
1028     */
1029    public MaskFilter setMaskFilter(MaskFilter maskfilter) {
1030        long maskfilterNative = 0;
1031        if (maskfilter != null) {
1032            maskfilterNative = maskfilter.native_instance;
1033        }
1034        native_setMaskFilter(mNativePaint, maskfilterNative);
1035        mMaskFilter = maskfilter;
1036        return maskfilter;
1037    }
1038
1039    /**
1040     * Get the paint's typeface object.
1041     * <p />
1042     * The typeface object identifies which font to use when drawing or
1043     * measuring text.
1044     *
1045     * @return the paint's typeface (or null)
1046     */
1047    public Typeface getTypeface() {
1048        return mTypeface;
1049    }
1050
1051    /**
1052     * Set or clear the typeface object.
1053     * <p />
1054     * Pass null to clear any previous typeface.
1055     * As a convenience, the parameter passed is also returned.
1056     *
1057     * @param typeface May be null. The typeface to be installed in the paint
1058     * @return         typeface
1059     */
1060    public Typeface setTypeface(Typeface typeface) {
1061        long typefaceNative = 0;
1062        if (typeface != null) {
1063            typefaceNative = typeface.native_instance;
1064        }
1065        native_setTypeface(mNativePaint, typefaceNative);
1066        mTypeface = typeface;
1067        mNativeTypeface = typefaceNative;
1068        return typeface;
1069    }
1070
1071    /**
1072     * Get the paint's rasterizer (or null).
1073     * <p />
1074     * The raster controls/modifies how paths/text are turned into alpha masks.
1075     *
1076     * @return         the paint's rasterizer (or null)
1077     *
1078     *  @deprecated Rasterizer is not supported by either the HW or PDF backends.
1079     */
1080    @Deprecated
1081    public Rasterizer getRasterizer() {
1082        return mRasterizer;
1083    }
1084
1085    /**
1086     * Set or clear the rasterizer object.
1087     * <p />
1088     * Pass null to clear any previous rasterizer.
1089     * As a convenience, the parameter passed is also returned.
1090     *
1091     * @param rasterizer May be null. The new rasterizer to be installed in
1092     *                   the paint.
1093     * @return           rasterizer
1094     *
1095     *  @deprecated Rasterizer is not supported by either the HW or PDF backends.
1096     */
1097    @Deprecated
1098    public Rasterizer setRasterizer(Rasterizer rasterizer) {
1099        long rasterizerNative = 0;
1100        if (rasterizer != null) {
1101            rasterizerNative = rasterizer.native_instance;
1102        }
1103        native_setRasterizer(mNativePaint, rasterizerNative);
1104        mRasterizer = rasterizer;
1105        return rasterizer;
1106    }
1107
1108    /**
1109     * This draws a shadow layer below the main layer, with the specified
1110     * offset and color, and blur radius. If radius is 0, then the shadow
1111     * layer is removed.
1112     */
1113    public void setShadowLayer(float radius, float dx, float dy, int color) {
1114      native_setShadowLayer(mNativePaint, radius, dx, dy, color);
1115    }
1116
1117    /**
1118     * Clear the shadow layer.
1119     */
1120    public void clearShadowLayer() {
1121        setShadowLayer(0, 0, 0, 0);
1122    }
1123
1124    /**
1125     * Checks if the paint has a shadow layer attached
1126     *
1127     * @return true if the paint has a shadow layer attached and false otherwise
1128     * @hide
1129     */
1130    public boolean hasShadowLayer() {
1131      return native_hasShadowLayer(mNativePaint);
1132    }
1133
1134    /**
1135     * Return the paint's Align value for drawing text. This controls how the
1136     * text is positioned relative to its origin. LEFT align means that all of
1137     * the text will be drawn to the right of its origin (i.e. the origin
1138     * specifieds the LEFT edge of the text) and so on.
1139     *
1140     * @return the paint's Align value for drawing text.
1141     */
1142    public Align getTextAlign() {
1143        return sAlignArray[native_getTextAlign(mNativePaint)];
1144    }
1145
1146    /**
1147     * Set the paint's text alignment. This controls how the
1148     * text is positioned relative to its origin. LEFT align means that all of
1149     * the text will be drawn to the right of its origin (i.e. the origin
1150     * specifieds the LEFT edge of the text) and so on.
1151     *
1152     * @param align set the paint's Align value for drawing text.
1153     */
1154    public void setTextAlign(Align align) {
1155        native_setTextAlign(mNativePaint, align.nativeInt);
1156    }
1157
1158    /**
1159     * Get the text Locale.
1160     *
1161     * @return the paint's Locale used for drawing text, never null.
1162     */
1163    public Locale getTextLocale() {
1164        return mLocale;
1165    }
1166
1167    /**
1168     * Set the text locale.
1169     *
1170     * The text locale affects how the text is drawn for some languages.
1171     *
1172     * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
1173     * then the text renderer will prefer to draw text using a Chinese font. Likewise,
1174     * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
1175     * renderer will prefer to draw text using a Japanese font.
1176     *
1177     * This distinction is important because Chinese and Japanese text both use many
1178     * of the same Unicode code points but their appearance is subtly different for
1179     * each language.
1180     *
1181     * By default, the text locale is initialized to the system locale (as returned
1182     * by {@link Locale#getDefault}). This assumes that the text to be rendered will
1183     * most likely be in the user's preferred language.
1184     *
1185     * If the actual language of the text is known, then it can be provided to the
1186     * text renderer using this method. The text renderer may attempt to guess the
1187     * language script based on the contents of the text to be drawn independent of
1188     * the text locale here. Specifying the text locale just helps it do a better
1189     * job in certain ambiguous cases
1190     *
1191     * @param locale the paint's locale value for drawing text, must not be null.
1192     */
1193    public void setTextLocale(Locale locale) {
1194        if (locale == null) {
1195            throw new IllegalArgumentException("locale cannot be null");
1196        }
1197        if (locale.equals(mLocale)) return;
1198        mLocale = locale;
1199        native_setTextLocale(mNativePaint, locale.toString());
1200    }
1201
1202    /**
1203     * Get the elegant metrics flag.
1204     *
1205     * @return true if elegant metrics are enabled for text drawing.
1206     */
1207    public native boolean isElegantTextHeight();
1208
1209    /**
1210     * Set the paint's elegant height metrics flag. This setting selects font
1211     * variants that have not been compacted to fit Latin-based vertical
1212     * metrics, and also increases top and bottom bounds to provide more space.
1213     *
1214     * @param elegant set the paint's elegant metrics flag for drawing text.
1215     */
1216    public native void setElegantTextHeight(boolean elegant);
1217
1218    /**
1219     * Return the paint's text size.
1220     *
1221     * @return the paint's text size.
1222     */
1223    public native float getTextSize();
1224
1225    /**
1226     * Set the paint's text size. This value must be > 0
1227     *
1228     * @param textSize set the paint's text size.
1229     */
1230    public native void setTextSize(float textSize);
1231
1232    /**
1233     * Return the paint's horizontal scale factor for text. The default value
1234     * is 1.0.
1235     *
1236     * @return the paint's scale factor in X for drawing/measuring text
1237     */
1238    public native float getTextScaleX();
1239
1240    /**
1241     * Set the paint's horizontal scale factor for text. The default value
1242     * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
1243     * stretch the text narrower.
1244     *
1245     * @param scaleX set the paint's scale in X for drawing/measuring text.
1246     */
1247    public native void setTextScaleX(float scaleX);
1248
1249    /**
1250     * Return the paint's horizontal skew factor for text. The default value
1251     * is 0.
1252     *
1253     * @return         the paint's skew factor in X for drawing text.
1254     */
1255    public native float getTextSkewX();
1256
1257    /**
1258     * Set the paint's horizontal skew factor for text. The default value
1259     * is 0. For approximating oblique text, use values around -0.25.
1260     *
1261     * @param skewX set the paint's skew factor in X for drawing text.
1262     */
1263    public native void setTextSkewX(float skewX);
1264
1265    /**
1266     * Return the paint's letter-spacing for text. The default value
1267     * is 0.
1268     *
1269     * @return         the paint's letter-spacing for drawing text.
1270     * @hide
1271     */
1272    public float getLetterSpacing() {
1273        return native_getLetterSpacing(mNativePaint);
1274    }
1275
1276    /**
1277     * Set the paint's letter-spacing for text. The default value
1278     * is 0.  The value is in 'EM' units.  Typical values for slight
1279     * expansion will be around 0.05.  Negative values tighten text.
1280     *
1281     * @param letterSpacing set the paint's letter-spacing for drawing text.
1282     * @hide
1283     */
1284    public void setLetterSpacing(float letterSpacing) {
1285        native_setLetterSpacing(mNativePaint, letterSpacing);
1286    }
1287
1288    /**
1289     * Get font feature settings.  Default is null.
1290     *
1291     * @return the paint's currently set font feature settings.
1292     * @hide
1293     */
1294    public String getFontFeatureSettings() {
1295        return mFontFeatureSettings;
1296    }
1297
1298    /**
1299     * Set font feature settings.
1300     *
1301     * The format is the same as the CSS font-feature-settings attribute:
1302     * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
1303     *
1304     * @param settings the font feature settings string to use, may be null.
1305     * @hide
1306     */
1307    public void setFontFeatureSettings(String settings) {
1308        if (settings != null && settings.equals("")) {
1309            settings = null;
1310        }
1311        if ((settings == null && mFontFeatureSettings == null)
1312                || (settings != null && settings.equals(mFontFeatureSettings))) {
1313            return;
1314        }
1315        mFontFeatureSettings = settings;
1316        native_setFontFeatureSettings(mNativePaint, settings);
1317    }
1318
1319    /**
1320     * Return the distance above (negative) the baseline (ascent) based on the
1321     * current typeface and text size.
1322     *
1323     * @return the distance above (negative) the baseline (ascent) based on the
1324     *         current typeface and text size.
1325     */
1326    public native float ascent();
1327
1328    /**
1329     * Return the distance below (positive) the baseline (descent) based on the
1330     * current typeface and text size.
1331     *
1332     * @return the distance below (positive) the baseline (descent) based on
1333     *         the current typeface and text size.
1334     */
1335    public native float descent();
1336
1337    /**
1338     * Class that describes the various metrics for a font at a given text size.
1339     * Remember, Y values increase going down, so those values will be positive,
1340     * and values that measure distances going up will be negative. This class
1341     * is returned by getFontMetrics().
1342     */
1343    public static class FontMetrics {
1344        /**
1345         * The maximum distance above the baseline for the tallest glyph in
1346         * the font at a given text size.
1347         */
1348        public float   top;
1349        /**
1350         * The recommended distance above the baseline for singled spaced text.
1351         */
1352        public float   ascent;
1353        /**
1354         * The recommended distance below the baseline for singled spaced text.
1355         */
1356        public float   descent;
1357        /**
1358         * The maximum distance below the baseline for the lowest glyph in
1359         * the font at a given text size.
1360         */
1361        public float   bottom;
1362        /**
1363         * The recommended additional space to add between lines of text.
1364         */
1365        public float   leading;
1366    }
1367
1368    /**
1369     * Return the font's recommended interline spacing, given the Paint's
1370     * settings for typeface, textSize, etc. If metrics is not null, return the
1371     * fontmetric values in it.
1372     *
1373     * @param metrics If this object is not null, its fields are filled with
1374     *                the appropriate values given the paint's text attributes.
1375     * @return the font's recommended interline spacing.
1376     */
1377    public native float getFontMetrics(FontMetrics metrics);
1378
1379    /**
1380     * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
1381     * with it, returning the object.
1382     */
1383    public FontMetrics getFontMetrics() {
1384        FontMetrics fm = new FontMetrics();
1385        getFontMetrics(fm);
1386        return fm;
1387    }
1388
1389    /**
1390     * Convenience method for callers that want to have FontMetrics values as
1391     * integers.
1392     */
1393    public static class FontMetricsInt {
1394        public int   top;
1395        public int   ascent;
1396        public int   descent;
1397        public int   bottom;
1398        public int   leading;
1399
1400        @Override public String toString() {
1401            return "FontMetricsInt: top=" + top + " ascent=" + ascent +
1402                    " descent=" + descent + " bottom=" + bottom +
1403                    " leading=" + leading;
1404        }
1405    }
1406
1407    /**
1408     * Return the font's interline spacing, given the Paint's settings for
1409     * typeface, textSize, etc. If metrics is not null, return the fontmetric
1410     * values in it. Note: all values have been converted to integers from
1411     * floats, in such a way has to make the answers useful for both spacing
1412     * and clipping. If you want more control over the rounding, call
1413     * getFontMetrics().
1414     *
1415     * @return the font's interline spacing.
1416     */
1417    public native int getFontMetricsInt(FontMetricsInt fmi);
1418
1419    public FontMetricsInt getFontMetricsInt() {
1420        FontMetricsInt fm = new FontMetricsInt();
1421        getFontMetricsInt(fm);
1422        return fm;
1423    }
1424
1425    /**
1426     * Return the recommend line spacing based on the current typeface and
1427     * text size.
1428     *
1429     * @return  recommend line spacing based on the current typeface and
1430     *          text size.
1431     */
1432    public float getFontSpacing() {
1433        return getFontMetrics(null);
1434    }
1435
1436    /**
1437     * Return the width of the text.
1438     *
1439     * @param text  The text to measure. Cannot be null.
1440     * @param index The index of the first character to start measuring
1441     * @param count THe number of characters to measure, beginning with start
1442     * @return      The width of the text
1443     */
1444    public float measureText(char[] text, int index, int count) {
1445        if (text == null) {
1446            throw new IllegalArgumentException("text cannot be null");
1447        }
1448        if ((index | count) < 0 || index + count > text.length) {
1449            throw new ArrayIndexOutOfBoundsException();
1450        }
1451
1452        if (text.length == 0 || count == 0) {
1453            return 0f;
1454        }
1455        if (!mHasCompatScaling) {
1456            return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
1457        }
1458
1459        final float oldSize = getTextSize();
1460        setTextSize(oldSize*mCompatScaling);
1461        float w = native_measureText(text, index, count, mBidiFlags);
1462        setTextSize(oldSize);
1463        return (float) Math.ceil(w*mInvCompatScaling);
1464    }
1465
1466    private native float native_measureText(char[] text, int index, int count, int bidiFlags);
1467
1468    /**
1469     * Return the width of the text.
1470     *
1471     * @param text  The text to measure. Cannot be null.
1472     * @param start The index of the first character to start measuring
1473     * @param end   1 beyond the index of the last character to measure
1474     * @return      The width of the text
1475     */
1476    public float measureText(String text, int start, int end) {
1477        if (text == null) {
1478            throw new IllegalArgumentException("text cannot be null");
1479        }
1480        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1481            throw new IndexOutOfBoundsException();
1482        }
1483
1484        if (text.length() == 0 || start == end) {
1485            return 0f;
1486        }
1487        if (!mHasCompatScaling) {
1488            return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
1489        }
1490
1491        final float oldSize = getTextSize();
1492        setTextSize(oldSize*mCompatScaling);
1493        float w = native_measureText(text, start, end, mBidiFlags);
1494        setTextSize(oldSize);
1495        return (float) Math.ceil(w*mInvCompatScaling);
1496    }
1497
1498    private native float native_measureText(String text, int start, int end, int bidiFlags);
1499
1500    /**
1501     * Return the width of the text.
1502     *
1503     * @param text  The text to measure. Cannot be null.
1504     * @return      The width of the text
1505     */
1506    public float measureText(String text) {
1507        if (text == null) {
1508            throw new IllegalArgumentException("text cannot be null");
1509        }
1510
1511        if (text.length() == 0) {
1512            return 0f;
1513        }
1514
1515        if (!mHasCompatScaling) {
1516            return (float) Math.ceil(native_measureText(text, mBidiFlags));
1517        }
1518        final float oldSize = getTextSize();
1519        setTextSize(oldSize*mCompatScaling);
1520        float w = native_measureText(text, mBidiFlags);
1521        setTextSize(oldSize);
1522        return (float) Math.ceil(w*mInvCompatScaling);
1523    }
1524
1525    private native float native_measureText(String text, int bidiFlags);
1526
1527    /**
1528     * Return the width of the text.
1529     *
1530     * @param text  The text to measure
1531     * @param start The index of the first character to start measuring
1532     * @param end   1 beyond the index of the last character to measure
1533     * @return      The width of the text
1534     */
1535    public float measureText(CharSequence text, int start, int end) {
1536        if (text == null) {
1537            throw new IllegalArgumentException("text cannot be null");
1538        }
1539        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1540            throw new IndexOutOfBoundsException();
1541        }
1542
1543        if (text.length() == 0 || start == end) {
1544            return 0f;
1545        }
1546        if (text instanceof String) {
1547            return measureText((String)text, start, end);
1548        }
1549        if (text instanceof SpannedString ||
1550            text instanceof SpannableString) {
1551            return measureText(text.toString(), start, end);
1552        }
1553        if (text instanceof GraphicsOperations) {
1554            return ((GraphicsOperations)text).measureText(start, end, this);
1555        }
1556
1557        char[] buf = TemporaryBuffer.obtain(end - start);
1558        TextUtils.getChars(text, start, end, buf, 0);
1559        float result = measureText(buf, 0, end - start);
1560        TemporaryBuffer.recycle(buf);
1561        return result;
1562    }
1563
1564    /**
1565     * Measure the text, stopping early if the measured width exceeds maxWidth.
1566     * Return the number of chars that were measured, and if measuredWidth is
1567     * not null, return in it the actual width measured.
1568     *
1569     * @param text  The text to measure. Cannot be null.
1570     * @param index The offset into text to begin measuring at
1571     * @param count The number of maximum number of entries to measure. If count
1572     *              is negative, then the characters are measured in reverse order.
1573     * @param maxWidth The maximum width to accumulate.
1574     * @param measuredWidth Optional. If not null, returns the actual width
1575     *                     measured.
1576     * @return The number of chars that were measured. Will always be <=
1577     *         abs(count).
1578     */
1579    public int breakText(char[] text, int index, int count,
1580                                float maxWidth, float[] measuredWidth) {
1581        if (text == null) {
1582            throw new IllegalArgumentException("text cannot be null");
1583        }
1584        if (index < 0 || text.length - index < Math.abs(count)) {
1585            throw new ArrayIndexOutOfBoundsException();
1586        }
1587
1588        if (text.length == 0 || count == 0) {
1589            return 0;
1590        }
1591        if (!mHasCompatScaling) {
1592            return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
1593                    mBidiFlags, measuredWidth);
1594        }
1595
1596        final float oldSize = getTextSize();
1597        setTextSize(oldSize * mCompatScaling);
1598        int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
1599                maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
1600        setTextSize(oldSize);
1601        if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
1602        return res;
1603    }
1604
1605    private static native int native_breakText(long native_object, long native_typeface,
1606                                               char[] text, int index, int count,
1607                                               float maxWidth, int bidiFlags, float[] measuredWidth);
1608
1609    /**
1610     * Measure the text, stopping early if the measured width exceeds maxWidth.
1611     * Return the number of chars that were measured, and if measuredWidth is
1612     * not null, return in it the actual width measured.
1613     *
1614     * @param text  The text to measure. Cannot be null.
1615     * @param start The offset into text to begin measuring at
1616     * @param end   The end of the text slice to measure.
1617     * @param measureForwards If true, measure forwards, starting at start.
1618     *                        Otherwise, measure backwards, starting with end.
1619     * @param maxWidth The maximum width to accumulate.
1620     * @param measuredWidth Optional. If not null, returns the actual width
1621     *                     measured.
1622     * @return The number of chars that were measured. Will always be <=
1623     *         abs(end - start).
1624     */
1625    public int breakText(CharSequence text, int start, int end,
1626                         boolean measureForwards,
1627                         float maxWidth, float[] measuredWidth) {
1628        if (text == null) {
1629            throw new IllegalArgumentException("text cannot be null");
1630        }
1631        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1632            throw new IndexOutOfBoundsException();
1633        }
1634
1635        if (text.length() == 0 || start == end) {
1636            return 0;
1637        }
1638        if (start == 0 && text instanceof String && end == text.length()) {
1639            return breakText((String) text, measureForwards, maxWidth,
1640                             measuredWidth);
1641        }
1642
1643        char[] buf = TemporaryBuffer.obtain(end - start);
1644        int result;
1645
1646        TextUtils.getChars(text, start, end, buf, 0);
1647
1648        if (measureForwards) {
1649            result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
1650        } else {
1651            result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
1652        }
1653
1654        TemporaryBuffer.recycle(buf);
1655        return result;
1656    }
1657
1658    /**
1659     * Measure the text, stopping early if the measured width exceeds maxWidth.
1660     * Return the number of chars that were measured, and if measuredWidth is
1661     * not null, return in it the actual width measured.
1662     *
1663     * @param text  The text to measure. Cannot be null.
1664     * @param measureForwards If true, measure forwards, starting with the
1665     *                        first character in the string. Otherwise,
1666     *                        measure backwards, starting with the
1667     *                        last character in the string.
1668     * @param maxWidth The maximum width to accumulate.
1669     * @param measuredWidth Optional. If not null, returns the actual width
1670     *                     measured.
1671     * @return The number of chars that were measured. Will always be <=
1672     *         abs(count).
1673     */
1674    public int breakText(String text, boolean measureForwards,
1675                                float maxWidth, float[] measuredWidth) {
1676        if (text == null) {
1677            throw new IllegalArgumentException("text cannot be null");
1678        }
1679
1680        if (text.length() == 0) {
1681            return 0;
1682        }
1683        if (!mHasCompatScaling) {
1684            return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
1685                    maxWidth, mBidiFlags, measuredWidth);
1686        }
1687
1688        final float oldSize = getTextSize();
1689        setTextSize(oldSize*mCompatScaling);
1690        int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
1691                maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
1692        setTextSize(oldSize);
1693        if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
1694        return res;
1695    }
1696
1697    private static native int native_breakText(long native_object, long native_typeface,
1698                                        String text, boolean measureForwards,
1699                                        float maxWidth, int bidiFlags, float[] measuredWidth);
1700
1701    /**
1702     * Return the advance widths for the characters in the string.
1703     *
1704     * @param text     The text to measure. Cannot be null.
1705     * @param index    The index of the first char to to measure
1706     * @param count    The number of chars starting with index to measure
1707     * @param widths   array to receive the advance widths of the characters.
1708     *                 Must be at least a large as count.
1709     * @return         the actual number of widths returned.
1710     */
1711    public int getTextWidths(char[] text, int index, int count,
1712                             float[] widths) {
1713        if (text == null) {
1714            throw new IllegalArgumentException("text cannot be null");
1715        }
1716        if ((index | count) < 0 || index + count > text.length
1717                || count > widths.length) {
1718            throw new ArrayIndexOutOfBoundsException();
1719        }
1720
1721        if (text.length == 0 || count == 0) {
1722            return 0;
1723        }
1724        if (!mHasCompatScaling) {
1725            return native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
1726        }
1727
1728        final float oldSize = getTextSize();
1729        setTextSize(oldSize*mCompatScaling);
1730        int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
1731        setTextSize(oldSize);
1732        for (int i=0; i<res; i++) {
1733            widths[i] *= mInvCompatScaling;
1734        }
1735        return res;
1736    }
1737
1738    /**
1739     * Return the advance widths for the characters in the string.
1740     *
1741     * @param text     The text to measure. Cannot be null.
1742     * @param start    The index of the first char to to measure
1743     * @param end      The end of the text slice to measure
1744     * @param widths   array to receive the advance widths of the characters.
1745     *                 Must be at least a large as (end - start).
1746     * @return         the actual number of widths returned.
1747     */
1748    public int getTextWidths(CharSequence text, int start, int end,
1749                             float[] widths) {
1750        if (text == null) {
1751            throw new IllegalArgumentException("text cannot be null");
1752        }
1753        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1754            throw new IndexOutOfBoundsException();
1755        }
1756        if (end - start > widths.length) {
1757            throw new ArrayIndexOutOfBoundsException();
1758        }
1759
1760        if (text.length() == 0 || start == end) {
1761            return 0;
1762        }
1763        if (text instanceof String) {
1764            return getTextWidths((String) text, start, end, widths);
1765        }
1766        if (text instanceof SpannedString ||
1767            text instanceof SpannableString) {
1768            return getTextWidths(text.toString(), start, end, widths);
1769        }
1770        if (text instanceof GraphicsOperations) {
1771            return ((GraphicsOperations) text).getTextWidths(start, end,
1772                                                                 widths, this);
1773        }
1774
1775        char[] buf = TemporaryBuffer.obtain(end - start);
1776        TextUtils.getChars(text, start, end, buf, 0);
1777        int result = getTextWidths(buf, 0, end - start, widths);
1778        TemporaryBuffer.recycle(buf);
1779        return result;
1780    }
1781
1782    /**
1783     * Return the advance widths for the characters in the string.
1784     *
1785     * @param text   The text to measure. Cannot be null.
1786     * @param start  The index of the first char to to measure
1787     * @param end    The end of the text slice to measure
1788     * @param widths array to receive the advance widths of the characters.
1789     *               Must be at least a large as the text.
1790     * @return       the number of unichars in the specified text.
1791     */
1792    public int getTextWidths(String text, int start, int end, float[] widths) {
1793        if (text == null) {
1794            throw new IllegalArgumentException("text cannot be null");
1795        }
1796        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1797            throw new IndexOutOfBoundsException();
1798        }
1799        if (end - start > widths.length) {
1800            throw new ArrayIndexOutOfBoundsException();
1801        }
1802
1803        if (text.length() == 0 || start == end) {
1804            return 0;
1805        }
1806        if (!mHasCompatScaling) {
1807            return native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
1808        }
1809
1810        final float oldSize = getTextSize();
1811        setTextSize(oldSize*mCompatScaling);
1812        int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
1813        setTextSize(oldSize);
1814        for (int i=0; i<res; i++) {
1815            widths[i] *= mInvCompatScaling;
1816        }
1817        return res;
1818    }
1819
1820    /**
1821     * Return the advance widths for the characters in the string.
1822     *
1823     * @param text   The text to measure
1824     * @param widths array to receive the advance widths of the characters.
1825     *               Must be at least a large as the text.
1826     * @return       the number of unichars in the specified text.
1827     */
1828    public int getTextWidths(String text, float[] widths) {
1829        return getTextWidths(text, 0, text.length(), widths);
1830    }
1831
1832    /**
1833     * Convenience overload that takes a char array instead of a
1834     * String.
1835     *
1836     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
1837     * @hide
1838     */
1839    public float getTextRunAdvances(char[] chars, int index, int count,
1840            int contextIndex, int contextCount, boolean isRtl, float[] advances,
1841            int advancesIndex) {
1842
1843        if (chars == null) {
1844            throw new IllegalArgumentException("text cannot be null");
1845        }
1846        if ((index | count | contextIndex | contextCount | advancesIndex
1847                | (index - contextIndex) | (contextCount - count)
1848                | ((contextIndex + contextCount) - (index + count))
1849                | (chars.length - (contextIndex + contextCount))
1850                | (advances == null ? 0 :
1851                    (advances.length - (advancesIndex + count)))) < 0) {
1852            throw new IndexOutOfBoundsException();
1853        }
1854
1855        if (chars.length == 0 || count == 0){
1856            return 0f;
1857        }
1858        if (!mHasCompatScaling) {
1859            return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
1860                    contextIndex, contextCount, isRtl, advances, advancesIndex);
1861        }
1862
1863        final float oldSize = getTextSize();
1864        setTextSize(oldSize * mCompatScaling);
1865        float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
1866                contextIndex, contextCount, isRtl, advances, advancesIndex);
1867        setTextSize(oldSize);
1868
1869        if (advances != null) {
1870            for (int i = advancesIndex, e = i + count; i < e; i++) {
1871                advances[i] *= mInvCompatScaling;
1872            }
1873        }
1874        return res * mInvCompatScaling; // assume errors are not significant
1875    }
1876
1877    /**
1878     * Convenience overload that takes a CharSequence instead of a
1879     * String.
1880     *
1881     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
1882     * @hide
1883     */
1884    public float getTextRunAdvances(CharSequence text, int start, int end,
1885            int contextStart, int contextEnd, boolean isRtl, float[] advances,
1886            int advancesIndex) {
1887
1888        if (text == null) {
1889            throw new IllegalArgumentException("text cannot be null");
1890        }
1891        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
1892                | (start - contextStart) | (contextEnd - end)
1893                | (text.length() - contextEnd)
1894                | (advances == null ? 0 :
1895                    (advances.length - advancesIndex - (end - start)))) < 0) {
1896            throw new IndexOutOfBoundsException();
1897        }
1898
1899        if (text instanceof String) {
1900            return getTextRunAdvances((String) text, start, end,
1901                    contextStart, contextEnd, isRtl, advances, advancesIndex);
1902        }
1903        if (text instanceof SpannedString ||
1904            text instanceof SpannableString) {
1905            return getTextRunAdvances(text.toString(), start, end,
1906                    contextStart, contextEnd, isRtl, advances, advancesIndex);
1907        }
1908        if (text instanceof GraphicsOperations) {
1909            return ((GraphicsOperations) text).getTextRunAdvances(start, end,
1910                    contextStart, contextEnd, isRtl, advances, advancesIndex, this);
1911        }
1912        if (text.length() == 0 || end == start) {
1913            return 0f;
1914        }
1915
1916        int contextLen = contextEnd - contextStart;
1917        int len = end - start;
1918        char[] buf = TemporaryBuffer.obtain(contextLen);
1919        TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1920        float result = getTextRunAdvances(buf, start - contextStart, len,
1921                0, contextLen, isRtl, advances, advancesIndex);
1922        TemporaryBuffer.recycle(buf);
1923        return result;
1924    }
1925
1926    /**
1927     * Returns the total advance width for the characters in the run
1928     * between start and end, and if advances is not null, the advance
1929     * assigned to each of these characters (java chars).
1930     *
1931     * <p>The trailing surrogate in a valid surrogate pair is assigned
1932     * an advance of 0.  Thus the number of returned advances is
1933     * always equal to count, not to the number of unicode codepoints
1934     * represented by the run.
1935     *
1936     * <p>In the case of conjuncts or combining marks, the total
1937     * advance is assigned to the first logical character, and the
1938     * following characters are assigned an advance of 0.
1939     *
1940     * <p>This generates the sum of the advances of glyphs for
1941     * characters in a reordered cluster as the width of the first
1942     * logical character in the cluster, and 0 for the widths of all
1943     * other characters in the cluster.  In effect, such clusters are
1944     * treated like conjuncts.
1945     *
1946     * <p>The shaping bounds limit the amount of context available
1947     * outside start and end that can be used for shaping analysis.
1948     * These bounds typically reflect changes in bidi level or font
1949     * metrics across which shaping does not occur.
1950     *
1951     * @param text the text to measure. Cannot be null.
1952     * @param start the index of the first character to measure
1953     * @param end the index past the last character to measure
1954     * @param contextStart the index of the first character to use for shaping context,
1955     * must be <= start
1956     * @param contextEnd the index past the last character to use for shaping context,
1957     * must be >= end
1958     * @param isRtl whether the run is in RTL direction
1959     * @param advances array to receive the advances, must have room for all advances,
1960     * can be null if only total advance is needed
1961     * @param advancesIndex the position in advances at which to put the
1962     * advance corresponding to the character at start
1963     * @return the total advance
1964     *
1965     * @hide
1966     */
1967    public float getTextRunAdvances(String text, int start, int end, int contextStart,
1968            int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
1969
1970        if (text == null) {
1971            throw new IllegalArgumentException("text cannot be null");
1972        }
1973        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
1974                | (start - contextStart) | (contextEnd - end)
1975                | (text.length() - contextEnd)
1976                | (advances == null ? 0 :
1977                    (advances.length - advancesIndex - (end - start)))) < 0) {
1978            throw new IndexOutOfBoundsException();
1979        }
1980
1981        if (text.length() == 0 || start == end) {
1982            return 0f;
1983        }
1984
1985        if (!mHasCompatScaling) {
1986            return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
1987                    contextStart, contextEnd, isRtl, advances, advancesIndex);
1988        }
1989
1990        final float oldSize = getTextSize();
1991        setTextSize(oldSize * mCompatScaling);
1992        float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
1993                contextStart, contextEnd, isRtl, advances, advancesIndex);
1994        setTextSize(oldSize);
1995
1996        if (advances != null) {
1997            for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
1998                advances[i] *= mInvCompatScaling;
1999            }
2000        }
2001        return totalAdvance * mInvCompatScaling; // assume errors are insignificant
2002    }
2003
2004    /**
2005     * Returns the next cursor position in the run.  This avoids placing the
2006     * cursor between surrogates, between characters that form conjuncts,
2007     * between base characters and combining marks, or within a reordering
2008     * cluster.
2009     *
2010     * <p>ContextStart and offset are relative to the start of text.
2011     * The context is the shaping context for cursor movement, generally
2012     * the bounds of the metric span enclosing the cursor in the direction of
2013     * movement.
2014     *
2015     * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
2016     * cursor position, this returns -1.  Otherwise this will never return a
2017     * value before contextStart or after contextStart + contextLength.
2018     *
2019     * @param text the text
2020     * @param contextStart the start of the context
2021     * @param contextLength the length of the context
2022     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
2023     * @param offset the cursor position to move from
2024     * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
2025     * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
2026     * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
2027     * @return the offset of the next position, or -1
2028     * @hide
2029     */
2030    public int getTextRunCursor(char[] text, int contextStart, int contextLength,
2031            int dir, int offset, int cursorOpt) {
2032        int contextEnd = contextStart + contextLength;
2033        if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
2034                | (offset - contextStart) | (contextEnd - offset)
2035                | (text.length - contextEnd) | cursorOpt) < 0)
2036                || cursorOpt > CURSOR_OPT_MAX_VALUE) {
2037            throw new IndexOutOfBoundsException();
2038        }
2039
2040        return native_getTextRunCursor(mNativePaint, text,
2041                contextStart, contextLength, dir, offset, cursorOpt);
2042    }
2043
2044    /**
2045     * Returns the next cursor position in the run.  This avoids placing the
2046     * cursor between surrogates, between characters that form conjuncts,
2047     * between base characters and combining marks, or within a reordering
2048     * cluster.
2049     *
2050     * <p>ContextStart, contextEnd, and offset are relative to the start of
2051     * text.  The context is the shaping context for cursor movement, generally
2052     * the bounds of the metric span enclosing the cursor in the direction of
2053     * movement.
2054     *
2055     * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
2056     * cursor position, this returns -1.  Otherwise this will never return a
2057     * value before contextStart or after contextEnd.
2058     *
2059     * @param text the text
2060     * @param contextStart the start of the context
2061     * @param contextEnd the end of the context
2062     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
2063     * @param offset the cursor position to move from
2064     * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
2065     * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
2066     * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
2067     * @return the offset of the next position, or -1
2068     * @hide
2069     */
2070    public int getTextRunCursor(CharSequence text, int contextStart,
2071           int contextEnd, int dir, int offset, int cursorOpt) {
2072
2073        if (text instanceof String || text instanceof SpannedString ||
2074                text instanceof SpannableString) {
2075            return getTextRunCursor(text.toString(), contextStart, contextEnd,
2076                    dir, offset, cursorOpt);
2077        }
2078        if (text instanceof GraphicsOperations) {
2079            return ((GraphicsOperations) text).getTextRunCursor(
2080                    contextStart, contextEnd, dir, offset, cursorOpt, this);
2081        }
2082
2083        int contextLen = contextEnd - contextStart;
2084        char[] buf = TemporaryBuffer.obtain(contextLen);
2085        TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
2086        int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
2087        TemporaryBuffer.recycle(buf);
2088        return result;
2089    }
2090
2091    /**
2092     * Returns the next cursor position in the run.  This avoids placing the
2093     * cursor between surrogates, between characters that form conjuncts,
2094     * between base characters and combining marks, or within a reordering
2095     * cluster.
2096     *
2097     * <p>ContextStart, contextEnd, and offset are relative to the start of
2098     * text.  The context is the shaping context for cursor movement, generally
2099     * the bounds of the metric span enclosing the cursor in the direction of
2100     * movement.
2101     *
2102     * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
2103     * cursor position, this returns -1.  Otherwise this will never return a
2104     * value before contextStart or after contextEnd.
2105     *
2106     * @param text the text
2107     * @param contextStart the start of the context
2108     * @param contextEnd the end of the context
2109     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
2110     * @param offset the cursor position to move from
2111     * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
2112     * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
2113     * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
2114     * @return the offset of the next position, or -1
2115     * @hide
2116     */
2117    public int getTextRunCursor(String text, int contextStart, int contextEnd,
2118            int dir, int offset, int cursorOpt) {
2119        if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
2120                | (offset - contextStart) | (contextEnd - offset)
2121                | (text.length() - contextEnd) | cursorOpt) < 0)
2122                || cursorOpt > CURSOR_OPT_MAX_VALUE) {
2123            throw new IndexOutOfBoundsException();
2124        }
2125
2126        return native_getTextRunCursor(mNativePaint, text,
2127                contextStart, contextEnd, dir, offset, cursorOpt);
2128    }
2129
2130    /**
2131     * Return the path (outline) for the specified text.
2132     * Note: just like Canvas.drawText, this will respect the Align setting in
2133     * the paint.
2134     *
2135     * @param text     The text to retrieve the path from
2136     * @param index    The index of the first character in text
2137     * @param count    The number of characterss starting with index
2138     * @param x        The x coordinate of the text's origin
2139     * @param y        The y coordinate of the text's origin
2140     * @param path     The path to receive the data describing the text. Must
2141     *                 be allocated by the caller.
2142     */
2143    public void getTextPath(char[] text, int index, int count,
2144                            float x, float y, Path path) {
2145        if ((index | count) < 0 || index + count > text.length) {
2146            throw new ArrayIndexOutOfBoundsException();
2147        }
2148        native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y,
2149                path.ni());
2150    }
2151
2152    /**
2153     * Return the path (outline) for the specified text.
2154     * Note: just like Canvas.drawText, this will respect the Align setting
2155     * in the paint.
2156     *
2157     * @param text  The text to retrieve the path from
2158     * @param start The first character in the text
2159     * @param end   1 past the last charcter in the text
2160     * @param x     The x coordinate of the text's origin
2161     * @param y     The y coordinate of the text's origin
2162     * @param path  The path to receive the data describing the text. Must
2163     *              be allocated by the caller.
2164     */
2165    public void getTextPath(String text, int start, int end,
2166                            float x, float y, Path path) {
2167        if ((start | end | (end - start) | (text.length() - end)) < 0) {
2168            throw new IndexOutOfBoundsException();
2169        }
2170        native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
2171                path.ni());
2172    }
2173
2174    /**
2175     * Return in bounds (allocated by the caller) the smallest rectangle that
2176     * encloses all of the characters, with an implied origin at (0,0).
2177     *
2178     * @param text  String to measure and return its bounds
2179     * @param start Index of the first char in the string to measure
2180     * @param end   1 past the last char in the string measure
2181     * @param bounds Returns the unioned bounds of all the text. Must be
2182     *               allocated by the caller.
2183     */
2184    public void getTextBounds(String text, int start, int end, Rect bounds) {
2185        if ((start | end | (end - start) | (text.length() - end)) < 0) {
2186            throw new IndexOutOfBoundsException();
2187        }
2188        if (bounds == null) {
2189            throw new NullPointerException("need bounds Rect");
2190        }
2191        nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
2192    }
2193
2194    /**
2195     * Return in bounds (allocated by the caller) the smallest rectangle that
2196     * encloses all of the characters, with an implied origin at (0,0).
2197     *
2198     * @param text  Array of chars to measure and return their unioned bounds
2199     * @param index Index of the first char in the array to measure
2200     * @param count The number of chars, beginning at index, to measure
2201     * @param bounds Returns the unioned bounds of all the text. Must be
2202     *               allocated by the caller.
2203     */
2204    public void getTextBounds(char[] text, int index, int count, Rect bounds) {
2205        if ((index | count) < 0 || index + count > text.length) {
2206            throw new ArrayIndexOutOfBoundsException();
2207        }
2208        if (bounds == null) {
2209            throw new NullPointerException("need bounds Rect");
2210        }
2211        nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
2212            bounds);
2213    }
2214
2215    @Override
2216    protected void finalize() throws Throwable {
2217        try {
2218            finalizer(mNativePaint);
2219        } finally {
2220            super.finalize();
2221        }
2222    }
2223
2224    private static native long native_init();
2225    private static native long native_initWithPaint(long paint);
2226    private static native void native_reset(long native_object);
2227    private static native void native_set(long native_dst, long native_src);
2228    private static native int native_getStyle(long native_object);
2229    private static native void native_setStyle(long native_object, int style);
2230    private static native int native_getStrokeCap(long native_object);
2231    private static native void native_setStrokeCap(long native_object, int cap);
2232    private static native int native_getStrokeJoin(long native_object);
2233    private static native void native_setStrokeJoin(long native_object,
2234                                                    int join);
2235    private static native boolean native_getFillPath(long native_object,
2236                                                     long src, long dst);
2237    private static native long native_setShader(long native_object, long shader);
2238    private static native long native_setColorFilter(long native_object,
2239                                                    long filter);
2240    private static native long native_setXfermode(long native_object,
2241                                                  long xfermode);
2242    private static native long native_setPathEffect(long native_object,
2243                                                    long effect);
2244    private static native long native_setMaskFilter(long native_object,
2245                                                    long maskfilter);
2246    private static native long native_setTypeface(long native_object,
2247                                                  long typeface);
2248    private static native long native_setRasterizer(long native_object,
2249                                                   long rasterizer);
2250
2251    private static native int native_getTextAlign(long native_object);
2252    private static native void native_setTextAlign(long native_object,
2253                                                   int align);
2254
2255    private static native void native_setTextLocale(long native_object,
2256                                                    String locale);
2257
2258    private static native int native_getTextWidths(long native_object, long native_typeface,
2259                            char[] text, int index, int count, int bidiFlags, float[] widths);
2260    private static native int native_getTextWidths(long native_object, long native_typeface,
2261                            String text, int start, int end, int bidiFlags, float[] widths);
2262
2263    private static native int native_getTextGlyphs(long native_object,
2264            String text, int start, int end, int contextStart, int contextEnd,
2265            int flags, char[] glyphs);
2266
2267    private static native float native_getTextRunAdvances(long native_object, long native_typeface,
2268            char[] text, int index, int count, int contextIndex, int contextCount,
2269            boolean isRtl, float[] advances, int advancesIndex);
2270    private static native float native_getTextRunAdvances(long native_object, long native_typeface,
2271            String text, int start, int end, int contextStart, int contextEnd,
2272            boolean isRtl, float[] advances, int advancesIndex);
2273
2274    private native int native_getTextRunCursor(long native_object, char[] text,
2275            int contextStart, int contextLength, int dir, int offset, int cursorOpt);
2276    private native int native_getTextRunCursor(long native_object, String text,
2277            int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
2278
2279    private static native void native_getTextPath(long native_object, long native_typeface,
2280            int bidiFlags, char[] text, int index, int count, float x, float y, long path);
2281    private static native void native_getTextPath(long native_object, long native_typeface,
2282            int bidiFlags, String text, int start, int end, float x, float y, long path);
2283    private static native void nativeGetStringBounds(long nativePaint, long native_typeface,
2284                                String text, int start, int end, int bidiFlags, Rect bounds);
2285    private static native void nativeGetCharArrayBounds(long nativePaint, long native_typeface,
2286                                char[] text, int index, int count, int bidiFlags, Rect bounds);
2287    private static native void finalizer(long nativePaint);
2288
2289    private static native void native_setShadowLayer(long native_object,
2290            float radius, float dx, float dy, int color);
2291    private static native boolean native_hasShadowLayer(long native_object);
2292
2293    private static native float native_getLetterSpacing(long native_object);
2294    private static native void native_setLetterSpacing(long native_object,
2295                                                       float letterSpacing);
2296    private static native void native_setFontFeatureSettings(long native_object,
2297                                                             String settings);
2298}
2299