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