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