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