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