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