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