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     public final boolean isLinearText() {
    557         return (getFlags() & LINEAR_TEXT_FLAG) != 0;
    558     }
    559 
    560     /**
    561      * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit
    562      *
    563      * @param linearText true to set the linearText bit in the paint's flags,
    564      *                   false to clear it.
    565      */
    566     public native void setLinearText(boolean linearText);
    567 
    568     /**
    569      * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
    570      *
    571      * @return true if the subpixel bit is set in the paint's flags
    572      */
    573     public final boolean isSubpixelText() {
    574         return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
    575     }
    576 
    577     /**
    578      * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
    579      *
    580      * @param subpixelText true to set the subpixelText bit in the paint's
    581      *                     flags, false to clear it.
    582      */
    583     public native void setSubpixelText(boolean subpixelText);
    584 
    585     /**
    586      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
    587      *
    588      * @return true if the underlineText bit is set in the paint's flags.
    589      */
    590     public final boolean isUnderlineText() {
    591         return (getFlags() & UNDERLINE_TEXT_FLAG) != 0;
    592     }
    593 
    594     /**
    595      * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit
    596      *
    597      * @param underlineText true to set the underlineText bit in the paint's
    598      *                      flags, false to clear it.
    599      */
    600     public native void setUnderlineText(boolean underlineText);
    601 
    602     /**
    603      * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
    604      *
    605      * @return true if the strikeThruText bit is set in the paint's flags.
    606      */
    607     public final boolean isStrikeThruText() {
    608         return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0;
    609     }
    610 
    611     /**
    612      * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
    613      *
    614      * @param strikeThruText true to set the strikeThruText bit in the paint's
    615      *                       flags, false to clear it.
    616      */
    617     public native void setStrikeThruText(boolean strikeThruText);
    618 
    619     /**
    620      * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
    621      *
    622      * @return true if the fakeBoldText bit is set in the paint's flags.
    623      */
    624     public final boolean isFakeBoldText() {
    625         return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0;
    626     }
    627 
    628     /**
    629      * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit
    630      *
    631      * @param fakeBoldText true to set the fakeBoldText bit in the paint's
    632      *                     flags, false to clear it.
    633      */
    634     public native void setFakeBoldText(boolean fakeBoldText);
    635 
    636     /**
    637      * Whether or not the bitmap filter is activated.
    638      * Filtering affects the sampling of bitmaps when they are transformed.
    639      * Filtering does not affect how the colors in the bitmap are converted into
    640      * device pixels. That is dependent on dithering and xfermodes.
    641      *
    642      * @see #setFilterBitmap(boolean) setFilterBitmap()
    643      */
    644     public final boolean isFilterBitmap() {
    645         return (getFlags() & FILTER_BITMAP_FLAG) != 0;
    646     }
    647 
    648     /**
    649      * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
    650      * Filtering affects the sampling of bitmaps when they are transformed.
    651      * Filtering does not affect how the colors in the bitmap are converted into
    652      * device pixels. That is dependent on dithering and xfermodes.
    653      *
    654      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
    655      *               flags, false to clear it.
    656      */
    657     public native void setFilterBitmap(boolean filter);
    658 
    659     /**
    660      * Return the paint's style, used for controlling how primitives'
    661      * geometries are interpreted (except for drawBitmap, which always assumes
    662      * FILL_STYLE).
    663      *
    664      * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
    665      */
    666     public Style getStyle() {
    667         return sStyleArray[native_getStyle(mNativePaint)];
    668     }
    669 
    670     /**
    671      * Set the paint's style, used for controlling how primitives'
    672      * geometries are interpreted (except for drawBitmap, which always assumes
    673      * Fill).
    674      *
    675      * @param style The new style to set in the paint
    676      */
    677     public void setStyle(Style style) {
    678         native_setStyle(mNativePaint, style.nativeInt);
    679     }
    680 
    681     /**
    682      * Return the paint's color. Note that the color is a 32bit value
    683      * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
    684      * meaning that its alpha can be any value, regardless of the values of
    685      * r,g,b. See the Color class for more details.
    686      *
    687      * @return the paint's color (and alpha).
    688      */
    689     public native int getColor();
    690 
    691     /**
    692      * Set the paint's color. Note that the color is an int containing alpha
    693      * as well as r,g,b. This 32bit value is not premultiplied, meaning that
    694      * its alpha can be any value, regardless of the values of r,g,b.
    695      * See the Color class for more details.
    696      *
    697      * @param color The new color (including alpha) to set in the paint.
    698      */
    699     public native void setColor(int color);
    700 
    701     /**
    702      * Helper to getColor() that just returns the color's alpha value. This is
    703      * the same as calling getColor() >>> 24. It always returns a value between
    704      * 0 (completely transparent) and 255 (completely opaque).
    705      *
    706      * @return the alpha component of the paint's color.
    707      */
    708     public native int getAlpha();
    709 
    710     /**
    711      * Helper to setColor(), that only assigns the color's alpha value,
    712      * leaving its r,g,b values unchanged. Results are undefined if the alpha
    713      * value is outside of the range [0..255]
    714      *
    715      * @param a set the alpha component [0..255] of the paint's color.
    716      */
    717     public native void setAlpha(int a);
    718 
    719     /**
    720      * Helper to setColor(), that takes a,r,g,b and constructs the color int
    721      *
    722      * @param a The new alpha component (0..255) of the paint's color.
    723      * @param r The new red component (0..255) of the paint's color.
    724      * @param g The new green component (0..255) of the paint's color.
    725      * @param b The new blue component (0..255) of the paint's color.
    726      */
    727     public void setARGB(int a, int r, int g, int b) {
    728         setColor((a << 24) | (r << 16) | (g << 8) | b);
    729     }
    730 
    731     /**
    732      * Return the width for stroking.
    733      * <p />
    734      * A value of 0 strokes in hairline mode.
    735      * Hairlines always draws a single pixel independent of the canva's matrix.
    736      *
    737      * @return the paint's stroke width, used whenever the paint's style is
    738      *         Stroke or StrokeAndFill.
    739      */
    740     public native float getStrokeWidth();
    741 
    742     /**
    743      * Set the width for stroking.
    744      * Pass 0 to stroke in hairline mode.
    745      * Hairlines always draws a single pixel independent of the canva's matrix.
    746      *
    747      * @param width set the paint's stroke width, used whenever the paint's
    748      *              style is Stroke or StrokeAndFill.
    749      */
    750     public native void setStrokeWidth(float width);
    751 
    752     /**
    753      * Return the paint's stroke miter value. Used to control the behavior
    754      * of miter joins when the joins angle is sharp.
    755      *
    756      * @return the paint's miter limit, used whenever the paint's style is
    757      *         Stroke or StrokeAndFill.
    758      */
    759     public native float getStrokeMiter();
    760 
    761     /**
    762      * Set the paint's stroke miter value. This is used to control the behavior
    763      * of miter joins when the joins angle is sharp. This value must be >= 0.
    764      *
    765      * @param miter set the miter limit on the paint, used whenever the paint's
    766      *              style is Stroke or StrokeAndFill.
    767      */
    768     public native void setStrokeMiter(float miter);
    769 
    770     /**
    771      * Return the paint's Cap, controlling how the start and end of stroked
    772      * lines and paths are treated.
    773      *
    774      * @return the line cap style for the paint, used whenever the paint's
    775      *         style is Stroke or StrokeAndFill.
    776      */
    777     public Cap getStrokeCap() {
    778         return sCapArray[native_getStrokeCap(mNativePaint)];
    779     }
    780 
    781     /**
    782      * Set the paint's Cap.
    783      *
    784      * @param cap set the paint's line cap style, used whenever the paint's
    785      *            style is Stroke or StrokeAndFill.
    786      */
    787     public void setStrokeCap(Cap cap) {
    788         native_setStrokeCap(mNativePaint, cap.nativeInt);
    789     }
    790 
    791     /**
    792      * Return the paint's stroke join type.
    793      *
    794      * @return the paint's Join.
    795      */
    796     public Join getStrokeJoin() {
    797         return sJoinArray[native_getStrokeJoin(mNativePaint)];
    798     }
    799 
    800     /**
    801      * Set the paint's Join.
    802      *
    803      * @param join set the paint's Join, used whenever the paint's style is
    804      *             Stroke or StrokeAndFill.
    805      */
    806     public void setStrokeJoin(Join join) {
    807         native_setStrokeJoin(mNativePaint, join.nativeInt);
    808     }
    809 
    810     /**
    811      * Applies any/all effects (patheffect, stroking) to src, returning the
    812      * result in dst. The result is that drawing src with this paint will be
    813      * the same as drawing dst with a default paint (at least from the
    814      * geometric perspective).
    815      *
    816      * @param src input path
    817      * @param dst output path (may be the same as src)
    818      * @return    true if the path should be filled, or false if it should be
    819      *                 drawn with a hairline (width == 0)
    820      */
    821     public boolean getFillPath(Path src, Path dst) {
    822         return native_getFillPath(mNativePaint, src.ni(), dst.ni());
    823     }
    824 
    825     /**
    826      * Get the paint's shader object.
    827      *
    828      * @return the paint's shader (or null)
    829      */
    830     public Shader getShader() {
    831         return mShader;
    832     }
    833 
    834     /**
    835      * Set or clear the shader object.
    836      * <p />
    837      * Pass null to clear any previous shader.
    838      * As a convenience, the parameter passed is also returned.
    839      *
    840      * @param shader May be null. the new shader to be installed in the paint
    841      * @return       shader
    842      */
    843     public Shader setShader(Shader shader) {
    844         int shaderNative = 0;
    845         if (shader != null)
    846             shaderNative = shader.native_instance;
    847         native_setShader(mNativePaint, shaderNative);
    848         mShader = shader;
    849         return shader;
    850     }
    851 
    852     /**
    853      * Get the paint's colorfilter (maybe be null).
    854      *
    855      * @return the paint's colorfilter (maybe be null)
    856      */
    857     public ColorFilter getColorFilter() {
    858         return mColorFilter;
    859     }
    860 
    861     /**
    862      * Set or clear the paint's colorfilter, returning the parameter.
    863      *
    864      * @param filter May be null. The new filter to be installed in the paint
    865      * @return       filter
    866      */
    867     public ColorFilter setColorFilter(ColorFilter filter) {
    868         int filterNative = 0;
    869         if (filter != null)
    870             filterNative = filter.native_instance;
    871         native_setColorFilter(mNativePaint, filterNative);
    872         mColorFilter = filter;
    873         return filter;
    874     }
    875 
    876     /**
    877      * Get the paint's xfermode object.
    878      *
    879      * @return the paint's xfermode (or null)
    880      */
    881     public Xfermode getXfermode() {
    882         return mXfermode;
    883     }
    884 
    885     /**
    886      * Set or clear the xfermode object.
    887      * <p />
    888      * Pass null to clear any previous xfermode.
    889      * As a convenience, the parameter passed is also returned.
    890      *
    891      * @param xfermode May be null. The xfermode to be installed in the paint
    892      * @return         xfermode
    893      */
    894     public Xfermode setXfermode(Xfermode xfermode) {
    895         int xfermodeNative = 0;
    896         if (xfermode != null)
    897             xfermodeNative = xfermode.native_instance;
    898         native_setXfermode(mNativePaint, xfermodeNative);
    899         mXfermode = xfermode;
    900         return xfermode;
    901     }
    902 
    903     /**
    904      * Get the paint's patheffect object.
    905      *
    906      * @return the paint's patheffect (or null)
    907      */
    908     public PathEffect getPathEffect() {
    909         return mPathEffect;
    910     }
    911 
    912     /**
    913      * Set or clear the patheffect object.
    914      * <p />
    915      * Pass null to clear any previous patheffect.
    916      * As a convenience, the parameter passed is also returned.
    917      *
    918      * @param effect May be null. The patheffect to be installed in the paint
    919      * @return       effect
    920      */
    921     public PathEffect setPathEffect(PathEffect effect) {
    922         int effectNative = 0;
    923         if (effect != null) {
    924             effectNative = effect.native_instance;
    925         }
    926         native_setPathEffect(mNativePaint, effectNative);
    927         mPathEffect = effect;
    928         return effect;
    929     }
    930 
    931     /**
    932      * Get the paint's maskfilter object.
    933      *
    934      * @return the paint's maskfilter (or null)
    935      */
    936     public MaskFilter getMaskFilter() {
    937         return mMaskFilter;
    938     }
    939 
    940     /**
    941      * Set or clear the maskfilter object.
    942      * <p />
    943      * Pass null to clear any previous maskfilter.
    944      * As a convenience, the parameter passed is also returned.
    945      *
    946      * @param maskfilter May be null. The maskfilter to be installed in the
    947      *                   paint
    948      * @return           maskfilter
    949      */
    950     public MaskFilter setMaskFilter(MaskFilter maskfilter) {
    951         int maskfilterNative = 0;
    952         if (maskfilter != null) {
    953             maskfilterNative = maskfilter.native_instance;
    954         }
    955         native_setMaskFilter(mNativePaint, maskfilterNative);
    956         mMaskFilter = maskfilter;
    957         return maskfilter;
    958     }
    959 
    960     /**
    961      * Get the paint's typeface object.
    962      * <p />
    963      * The typeface object identifies which font to use when drawing or
    964      * measuring text.
    965      *
    966      * @return the paint's typeface (or null)
    967      */
    968     public Typeface getTypeface() {
    969         return mTypeface;
    970     }
    971 
    972     /**
    973      * Set or clear the typeface object.
    974      * <p />
    975      * Pass null to clear any previous typeface.
    976      * As a convenience, the parameter passed is also returned.
    977      *
    978      * @param typeface May be null. The typeface to be installed in the paint
    979      * @return         typeface
    980      */
    981     public Typeface setTypeface(Typeface typeface) {
    982         int typefaceNative = 0;
    983         if (typeface != null) {
    984             typefaceNative = typeface.native_instance;
    985         }
    986         native_setTypeface(mNativePaint, typefaceNative);
    987         mTypeface = typeface;
    988         return typeface;
    989     }
    990 
    991     /**
    992      * Get the paint's rasterizer (or null).
    993      * <p />
    994      * The raster controls/modifies how paths/text are turned into alpha masks.
    995      *
    996      * @return         the paint's rasterizer (or null)
    997      */
    998     public Rasterizer getRasterizer() {
    999         return mRasterizer;
   1000     }
   1001 
   1002     /**
   1003      * Set or clear the rasterizer object.
   1004      * <p />
   1005      * Pass null to clear any previous rasterizer.
   1006      * As a convenience, the parameter passed is also returned.
   1007      *
   1008      * @param rasterizer May be null. The new rasterizer to be installed in
   1009      *                   the paint.
   1010      * @return           rasterizer
   1011      */
   1012     public Rasterizer setRasterizer(Rasterizer rasterizer) {
   1013         int rasterizerNative = 0;
   1014         if (rasterizer != null) {
   1015             rasterizerNative = rasterizer.native_instance;
   1016         }
   1017         native_setRasterizer(mNativePaint, rasterizerNative);
   1018         mRasterizer = rasterizer;
   1019         return rasterizer;
   1020     }
   1021 
   1022     /**
   1023      * This draws a shadow layer below the main layer, with the specified
   1024      * offset and color, and blur radius. If radius is 0, then the shadow
   1025      * layer is removed.
   1026      */
   1027     public void setShadowLayer(float radius, float dx, float dy, int color) {
   1028         hasShadow = radius > 0.0f;
   1029         shadowRadius = radius;
   1030         shadowDx = dx;
   1031         shadowDy = dy;
   1032         shadowColor = color;
   1033         nSetShadowLayer(radius, dx, dy, color);
   1034     }
   1035 
   1036     private native void nSetShadowLayer(float radius, float dx, float dy, int color);
   1037 
   1038     /**
   1039      * Clear the shadow layer.
   1040      */
   1041     public void clearShadowLayer() {
   1042         hasShadow = false;
   1043         nSetShadowLayer(0, 0, 0, 0);
   1044     }
   1045 
   1046     /**
   1047      * Return the paint's Align value for drawing text. This controls how the
   1048      * text is positioned relative to its origin. LEFT align means that all of
   1049      * the text will be drawn to the right of its origin (i.e. the origin
   1050      * specifieds the LEFT edge of the text) and so on.
   1051      *
   1052      * @return the paint's Align value for drawing text.
   1053      */
   1054     public Align getTextAlign() {
   1055         return sAlignArray[native_getTextAlign(mNativePaint)];
   1056     }
   1057 
   1058     /**
   1059      * Set the paint's text alignment. This controls how the
   1060      * text is positioned relative to its origin. LEFT align means that all of
   1061      * the text will be drawn to the right of its origin (i.e. the origin
   1062      * specifieds the LEFT edge of the text) and so on.
   1063      *
   1064      * @param align set the paint's Align value for drawing text.
   1065      */
   1066     public void setTextAlign(Align align) {
   1067         native_setTextAlign(mNativePaint, align.nativeInt);
   1068     }
   1069 
   1070     /**
   1071      * Get the text Locale.
   1072      *
   1073      * @return the paint's Locale used for drawing text, never null.
   1074      */
   1075     public Locale getTextLocale() {
   1076         return mLocale;
   1077     }
   1078 
   1079     /**
   1080      * Set the text locale.
   1081      *
   1082      * The text locale affects how the text is drawn for some languages.
   1083      *
   1084      * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
   1085      * then the text renderer will prefer to draw text using a Chinese font. Likewise,
   1086      * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
   1087      * renderer will prefer to draw text using a Japanese font.
   1088      *
   1089      * This distinction is important because Chinese and Japanese text both use many
   1090      * of the same Unicode code points but their appearance is subtly different for
   1091      * each language.
   1092      *
   1093      * By default, the text locale is initialized to the system locale (as returned
   1094      * by {@link Locale#getDefault}). This assumes that the text to be rendered will
   1095      * most likely be in the user's preferred language.
   1096      *
   1097      * If the actual language of the text is known, then it can be provided to the
   1098      * text renderer using this method. The text renderer may attempt to guess the
   1099      * language script based on the contents of the text to be drawn independent of
   1100      * the text locale here. Specifying the text locale just helps it do a better
   1101      * job in certain ambiguous cases
   1102      *
   1103      * @param locale the paint's locale value for drawing text, must not be null.
   1104      */
   1105     public void setTextLocale(Locale locale) {
   1106         if (locale == null) {
   1107             throw new IllegalArgumentException("locale cannot be null");
   1108         }
   1109         if (locale.equals(mLocale)) return;
   1110         mLocale = locale;
   1111         native_setTextLocale(mNativePaint, locale.toString());
   1112     }
   1113 
   1114     /**
   1115      * Return the paint's text size.
   1116      *
   1117      * @return the paint's text size.
   1118      */
   1119     public native float getTextSize();
   1120 
   1121     /**
   1122      * Set the paint's text size. This value must be > 0
   1123      *
   1124      * @param textSize set the paint's text size.
   1125      */
   1126     public native void setTextSize(float textSize);
   1127 
   1128     /**
   1129      * Return the paint's horizontal scale factor for text. The default value
   1130      * is 1.0.
   1131      *
   1132      * @return the paint's scale factor in X for drawing/measuring text
   1133      */
   1134     public native float getTextScaleX();
   1135 
   1136     /**
   1137      * Set the paint's horizontal scale factor for text. The default value
   1138      * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
   1139      * stretch the text narrower.
   1140      *
   1141      * @param scaleX set the paint's scale in X for drawing/measuring text.
   1142      */
   1143     public native void setTextScaleX(float scaleX);
   1144 
   1145     /**
   1146      * Return the paint's horizontal skew factor for text. The default value
   1147      * is 0.
   1148      *
   1149      * @return         the paint's skew factor in X for drawing text.
   1150      */
   1151     public native float getTextSkewX();
   1152 
   1153     /**
   1154      * Set the paint's horizontal skew factor for text. The default value
   1155      * is 0. For approximating oblique text, use values around -0.25.
   1156      *
   1157      * @param skewX set the paint's skew factor in X for drawing text.
   1158      */
   1159     public native void setTextSkewX(float skewX);
   1160 
   1161     /**
   1162      * Return the distance above (negative) the baseline (ascent) based on the
   1163      * current typeface and text size.
   1164      *
   1165      * @return the distance above (negative) the baseline (ascent) based on the
   1166      *         current typeface and text size.
   1167      */
   1168     public native float ascent();
   1169 
   1170     /**
   1171      * Return the distance below (positive) the baseline (descent) based on the
   1172      * current typeface and text size.
   1173      *
   1174      * @return the distance below (positive) the baseline (descent) based on
   1175      *         the current typeface and text size.
   1176      */
   1177     public native float descent();
   1178 
   1179     /**
   1180      * Class that describes the various metrics for a font at a given text size.
   1181      * Remember, Y values increase going down, so those values will be positive,
   1182      * and values that measure distances going up will be negative. This class
   1183      * is returned by getFontMetrics().
   1184      */
   1185     public static class FontMetrics {
   1186         /**
   1187          * The maximum distance above the baseline for the tallest glyph in
   1188          * the font at a given text size.
   1189          */
   1190         public float   top;
   1191         /**
   1192          * The recommended distance above the baseline for singled spaced text.
   1193          */
   1194         public float   ascent;
   1195         /**
   1196          * The recommended distance below the baseline for singled spaced text.
   1197          */
   1198         public float   descent;
   1199         /**
   1200          * The maximum distance below the baseline for the lowest glyph in
   1201          * the font at a given text size.
   1202          */
   1203         public float   bottom;
   1204         /**
   1205          * The recommended additional space to add between lines of text.
   1206          */
   1207         public float   leading;
   1208     }
   1209 
   1210     /**
   1211      * Return the font's recommended interline spacing, given the Paint's
   1212      * settings for typeface, textSize, etc. If metrics is not null, return the
   1213      * fontmetric values in it.
   1214      *
   1215      * @param metrics If this object is not null, its fields are filled with
   1216      *                the appropriate values given the paint's text attributes.
   1217      * @return the font's recommended interline spacing.
   1218      */
   1219     public native float getFontMetrics(FontMetrics metrics);
   1220 
   1221     /**
   1222      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
   1223      * with it, returning the object.
   1224      */
   1225     public FontMetrics getFontMetrics() {
   1226         FontMetrics fm = new FontMetrics();
   1227         getFontMetrics(fm);
   1228         return fm;
   1229     }
   1230 
   1231     /**
   1232      * Convenience method for callers that want to have FontMetrics values as
   1233      * integers.
   1234      */
   1235     public static class FontMetricsInt {
   1236         public int   top;
   1237         public int   ascent;
   1238         public int   descent;
   1239         public int   bottom;
   1240         public int   leading;
   1241 
   1242         @Override public String toString() {
   1243             return "FontMetricsInt: top=" + top + " ascent=" + ascent +
   1244                     " descent=" + descent + " bottom=" + bottom +
   1245                     " leading=" + leading;
   1246         }
   1247     }
   1248 
   1249     /**
   1250      * Return the font's interline spacing, given the Paint's settings for
   1251      * typeface, textSize, etc. If metrics is not null, return the fontmetric
   1252      * values in it. Note: all values have been converted to integers from
   1253      * floats, in such a way has to make the answers useful for both spacing
   1254      * and clipping. If you want more control over the rounding, call
   1255      * getFontMetrics().
   1256      *
   1257      * @return the font's interline spacing.
   1258      */
   1259     public native int getFontMetricsInt(FontMetricsInt fmi);
   1260 
   1261     public FontMetricsInt getFontMetricsInt() {
   1262         FontMetricsInt fm = new FontMetricsInt();
   1263         getFontMetricsInt(fm);
   1264         return fm;
   1265     }
   1266 
   1267     /**
   1268      * Return the recommend line spacing based on the current typeface and
   1269      * text size.
   1270      *
   1271      * @return  recommend line spacing based on the current typeface and
   1272      *          text size.
   1273      */
   1274     public float getFontSpacing() {
   1275         return getFontMetrics(null);
   1276     }
   1277 
   1278     /**
   1279      * Return the width of the text.
   1280      *
   1281      * @param text  The text to measure. Cannot be null.
   1282      * @param index The index of the first character to start measuring
   1283      * @param count THe number of characters to measure, beginning with start
   1284      * @return      The width of the text
   1285      */
   1286     public float measureText(char[] text, int index, int count) {
   1287         if (text == null) {
   1288             throw new IllegalArgumentException("text cannot be null");
   1289         }
   1290         if ((index | count) < 0 || index + count > text.length) {
   1291             throw new ArrayIndexOutOfBoundsException();
   1292         }
   1293 
   1294         if (text.length == 0 || count == 0) {
   1295             return 0f;
   1296         }
   1297         if (!mHasCompatScaling) {
   1298             return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
   1299         }
   1300 
   1301         final float oldSize = getTextSize();
   1302         setTextSize(oldSize*mCompatScaling);
   1303         float w = native_measureText(text, index, count, mBidiFlags);
   1304         setTextSize(oldSize);
   1305         return (float) Math.ceil(w*mInvCompatScaling);
   1306     }
   1307 
   1308     private native float native_measureText(char[] text, int index, int count, int bidiFlags);
   1309 
   1310     /**
   1311      * Return the width of the text.
   1312      *
   1313      * @param text  The text to measure. Cannot be null.
   1314      * @param start The index of the first character to start measuring
   1315      * @param end   1 beyond the index of the last character to measure
   1316      * @return      The width of the text
   1317      */
   1318     public float measureText(String text, int start, int end) {
   1319         if (text == null) {
   1320             throw new IllegalArgumentException("text cannot be null");
   1321         }
   1322         if ((start | end | (end - start) | (text.length() - end)) < 0) {
   1323             throw new IndexOutOfBoundsException();
   1324         }
   1325 
   1326         if (text.length() == 0 || start == end) {
   1327             return 0f;
   1328         }
   1329         if (!mHasCompatScaling) {
   1330             return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
   1331         }
   1332 
   1333         final float oldSize = getTextSize();
   1334         setTextSize(oldSize*mCompatScaling);
   1335         float w = native_measureText(text, start, end, mBidiFlags);
   1336         setTextSize(oldSize);
   1337         return (float) Math.ceil(w*mInvCompatScaling);
   1338     }
   1339 
   1340     private native float native_measureText(String text, int start, int end, int bidiFlags);
   1341 
   1342     /**
   1343      * Return the width of the text.
   1344      *
   1345      * @param text  The text to measure. Cannot be null.
   1346      * @return      The width of the text
   1347      */
   1348     public float measureText(String text) {
   1349         if (text == null) {
   1350             throw new IllegalArgumentException("text cannot be null");
   1351         }
   1352 
   1353         if (text.length() == 0) {
   1354             return 0f;
   1355         }
   1356 
   1357         if (!mHasCompatScaling) {
   1358             return (float) Math.ceil(native_measureText(text, mBidiFlags));
   1359         }
   1360         final float oldSize = getTextSize();
   1361         setTextSize(oldSize*mCompatScaling);
   1362         float w = native_measureText(text, mBidiFlags);
   1363         setTextSize(oldSize);
   1364         return (float) Math.ceil(w*mInvCompatScaling);
   1365     }
   1366 
   1367     private native float native_measureText(String text, int bidiFlags);
   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, mBidiFlags, measuredWidth);
   1435         }
   1436 
   1437         final float oldSize = getTextSize();
   1438         setTextSize(oldSize*mCompatScaling);
   1439         int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
   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, int bidiFlags, 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, mBidiFlags, measuredWidth);
   1525         }
   1526 
   1527         final float oldSize = getTextSize();
   1528         setTextSize(oldSize*mCompatScaling);
   1529         int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
   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, int bidiFlags, 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, mBidiFlags, widths);
   1564         }
   1565 
   1566         final float oldSize = getTextSize();
   1567         setTextSize(oldSize*mCompatScaling);
   1568         int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, 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, mBidiFlags, widths);
   1646         }
   1647 
   1648         final float oldSize = getTextSize();
   1649         setTextSize(oldSize*mCompatScaling);
   1650         int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, 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 
   1721         if (chars == null) {
   1722             throw new IllegalArgumentException("text cannot be null");
   1723         }
   1724         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
   1725             throw new IllegalArgumentException("unknown flags value: " + flags);
   1726         }
   1727         if ((index | count | contextIndex | contextCount | advancesIndex
   1728                 | (index - contextIndex) | (contextCount - count)
   1729                 | ((contextIndex + contextCount) - (index + count))
   1730                 | (chars.length - (contextIndex + contextCount))
   1731                 | (advances == null ? 0 :
   1732                     (advances.length - (advancesIndex + count)))) < 0) {
   1733             throw new IndexOutOfBoundsException();
   1734         }
   1735 
   1736         if (chars.length == 0 || count == 0){
   1737             return 0f;
   1738         }
   1739         if (!mHasCompatScaling) {
   1740             return native_getTextRunAdvances(mNativePaint, chars, index, count,
   1741                     contextIndex, contextCount, flags, advances, advancesIndex);
   1742         }
   1743 
   1744         final float oldSize = getTextSize();
   1745         setTextSize(oldSize * mCompatScaling);
   1746         float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
   1747                 contextIndex, contextCount, flags, advances, advancesIndex);
   1748         setTextSize(oldSize);
   1749 
   1750         if (advances != null) {
   1751             for (int i = advancesIndex, e = i + count; i < e; i++) {
   1752                 advances[i] *= mInvCompatScaling;
   1753             }
   1754         }
   1755         return res * mInvCompatScaling; // assume errors are not significant
   1756     }
   1757 
   1758     /**
   1759      * Convenience overload that takes a CharSequence instead of a
   1760      * String.
   1761      *
   1762      * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
   1763      * @hide
   1764      */
   1765     public float getTextRunAdvances(CharSequence text, int start, int end,
   1766             int contextStart, int contextEnd, int flags, float[] advances,
   1767             int advancesIndex) {
   1768 
   1769         if (text == null) {
   1770             throw new IllegalArgumentException("text cannot be null");
   1771         }
   1772         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
   1773                 | (start - contextStart) | (contextEnd - end)
   1774                 | (text.length() - contextEnd)
   1775                 | (advances == null ? 0 :
   1776                     (advances.length - advancesIndex - (end - start)))) < 0) {
   1777             throw new IndexOutOfBoundsException();
   1778         }
   1779 
   1780         if (text instanceof String) {
   1781             return getTextRunAdvances((String) text, start, end,
   1782                     contextStart, contextEnd, flags, advances, advancesIndex);
   1783         }
   1784         if (text instanceof SpannedString ||
   1785             text instanceof SpannableString) {
   1786             return getTextRunAdvances(text.toString(), start, end,
   1787                     contextStart, contextEnd, flags, advances, advancesIndex);
   1788         }
   1789         if (text instanceof GraphicsOperations) {
   1790             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
   1791                     contextStart, contextEnd, flags, advances, advancesIndex, this);
   1792         }
   1793         if (text.length() == 0 || end == start) {
   1794             return 0f;
   1795         }
   1796 
   1797         int contextLen = contextEnd - contextStart;
   1798         int len = end - start;
   1799         char[] buf = TemporaryBuffer.obtain(contextLen);
   1800         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
   1801         float result = getTextRunAdvances(buf, start - contextStart, len,
   1802                 0, contextLen, flags, advances, advancesIndex);
   1803         TemporaryBuffer.recycle(buf);
   1804         return result;
   1805     }
   1806 
   1807     /**
   1808      * Returns the total advance width for the characters in the run
   1809      * between start and end, and if advances is not null, the advance
   1810      * assigned to each of these characters (java chars).
   1811      *
   1812      * <p>The trailing surrogate in a valid surrogate pair is assigned
   1813      * an advance of 0.  Thus the number of returned advances is
   1814      * always equal to count, not to the number of unicode codepoints
   1815      * represented by the run.
   1816      *
   1817      * <p>In the case of conjuncts or combining marks, the total
   1818      * advance is assigned to the first logical character, and the
   1819      * following characters are assigned an advance of 0.
   1820      *
   1821      * <p>This generates the sum of the advances of glyphs for
   1822      * characters in a reordered cluster as the width of the first
   1823      * logical character in the cluster, and 0 for the widths of all
   1824      * other characters in the cluster.  In effect, such clusters are
   1825      * treated like conjuncts.
   1826      *
   1827      * <p>The shaping bounds limit the amount of context available
   1828      * outside start and end that can be used for shaping analysis.
   1829      * These bounds typically reflect changes in bidi level or font
   1830      * metrics across which shaping does not occur.
   1831      *
   1832      * @param text the text to measure. Cannot be null.
   1833      * @param start the index of the first character to measure
   1834      * @param end the index past the last character to measure
   1835      * @param contextStart the index of the first character to use for shaping context,
   1836      * must be <= start
   1837      * @param contextEnd the index past the last character to use for shaping context,
   1838      * must be >= end
   1839      * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
   1840      * or {@link #DIRECTION_RTL}
   1841      * @param advances array to receive the advances, must have room for all advances,
   1842      * can be null if only total advance is needed
   1843      * @param advancesIndex the position in advances at which to put the
   1844      * advance corresponding to the character at start
   1845      * @return the total advance
   1846      *
   1847      * @hide
   1848      */
   1849     public float getTextRunAdvances(String text, int start, int end, int contextStart,
   1850             int contextEnd, int flags, float[] advances, int advancesIndex) {
   1851 
   1852         if (text == null) {
   1853             throw new IllegalArgumentException("text cannot be null");
   1854         }
   1855         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
   1856             throw new IllegalArgumentException("unknown flags value: " + flags);
   1857         }
   1858         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
   1859                 | (start - contextStart) | (contextEnd - end)
   1860                 | (text.length() - contextEnd)
   1861                 | (advances == null ? 0 :
   1862                     (advances.length - advancesIndex - (end - start)))) < 0) {
   1863             throw new IndexOutOfBoundsException();
   1864         }
   1865 
   1866         if (text.length() == 0 || start == end) {
   1867             return 0f;
   1868         }
   1869 
   1870         if (!mHasCompatScaling) {
   1871             return native_getTextRunAdvances(mNativePaint, text, start, end,
   1872                     contextStart, contextEnd, flags, advances, advancesIndex);
   1873         }
   1874 
   1875         final float oldSize = getTextSize();
   1876         setTextSize(oldSize * mCompatScaling);
   1877         float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
   1878                 contextStart, contextEnd, flags, advances, advancesIndex);
   1879         setTextSize(oldSize);
   1880 
   1881         if (advances != null) {
   1882             for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
   1883                 advances[i] *= mInvCompatScaling;
   1884             }
   1885         }
   1886         return totalAdvance * mInvCompatScaling; // assume errors are insignificant
   1887     }
   1888 
   1889     /**
   1890      * Returns the next cursor position in the run.  This avoids placing the
   1891      * cursor between surrogates, between characters that form conjuncts,
   1892      * between base characters and combining marks, or within a reordering
   1893      * cluster.
   1894      *
   1895      * <p>ContextStart and offset are relative to the start of text.
   1896      * The context is the shaping context for cursor movement, generally
   1897      * the bounds of the metric span enclosing the cursor in the direction of
   1898      * movement.
   1899      *
   1900      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
   1901      * cursor position, this returns -1.  Otherwise this will never return a
   1902      * value before contextStart or after contextStart + contextLength.
   1903      *
   1904      * @param text the text
   1905      * @param contextStart the start of the context
   1906      * @param contextLength the length of the context
   1907      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
   1908      * @param offset the cursor position to move from
   1909      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
   1910      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
   1911      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
   1912      * @return the offset of the next position, or -1
   1913      * @hide
   1914      */
   1915     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
   1916             int flags, int offset, int cursorOpt) {
   1917         int contextEnd = contextStart + contextLength;
   1918         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
   1919                 | (offset - contextStart) | (contextEnd - offset)
   1920                 | (text.length - contextEnd) | cursorOpt) < 0)
   1921                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
   1922             throw new IndexOutOfBoundsException();
   1923         }
   1924 
   1925         return native_getTextRunCursor(mNativePaint, text,
   1926                 contextStart, contextLength, flags, offset, cursorOpt);
   1927     }
   1928 
   1929     /**
   1930      * Returns the next cursor position in the run.  This avoids placing the
   1931      * cursor between surrogates, between characters that form conjuncts,
   1932      * between base characters and combining marks, or within a reordering
   1933      * cluster.
   1934      *
   1935      * <p>ContextStart, contextEnd, and offset are relative to the start of
   1936      * text.  The context is the shaping context for cursor movement, generally
   1937      * the bounds of the metric span enclosing the cursor in the direction of
   1938      * movement.
   1939      *
   1940      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
   1941      * cursor position, this returns -1.  Otherwise this will never return a
   1942      * value before contextStart or after contextEnd.
   1943      *
   1944      * @param text the text
   1945      * @param contextStart the start of the context
   1946      * @param contextEnd the end of the context
   1947      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
   1948      * @param offset the cursor position to move from
   1949      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
   1950      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
   1951      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
   1952      * @return the offset of the next position, or -1
   1953      * @hide
   1954      */
   1955     public int getTextRunCursor(CharSequence text, int contextStart,
   1956            int contextEnd, int flags, int offset, int cursorOpt) {
   1957 
   1958         if (text instanceof String || text instanceof SpannedString ||
   1959                 text instanceof SpannableString) {
   1960             return getTextRunCursor(text.toString(), contextStart, contextEnd,
   1961                     flags, offset, cursorOpt);
   1962         }
   1963         if (text instanceof GraphicsOperations) {
   1964             return ((GraphicsOperations) text).getTextRunCursor(
   1965                     contextStart, contextEnd, flags, offset, cursorOpt, this);
   1966         }
   1967 
   1968         int contextLen = contextEnd - contextStart;
   1969         char[] buf = TemporaryBuffer.obtain(contextLen);
   1970         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
   1971         int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
   1972         TemporaryBuffer.recycle(buf);
   1973         return result;
   1974     }
   1975 
   1976     /**
   1977      * Returns the next cursor position in the run.  This avoids placing the
   1978      * cursor between surrogates, between characters that form conjuncts,
   1979      * between base characters and combining marks, or within a reordering
   1980      * cluster.
   1981      *
   1982      * <p>ContextStart, contextEnd, and offset are relative to the start of
   1983      * text.  The context is the shaping context for cursor movement, generally
   1984      * the bounds of the metric span enclosing the cursor in the direction of
   1985      * movement.
   1986      *
   1987      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
   1988      * cursor position, this returns -1.  Otherwise this will never return a
   1989      * value before contextStart or after contextEnd.
   1990      *
   1991      * @param text the text
   1992      * @param contextStart the start of the context
   1993      * @param contextEnd the end of the context
   1994      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
   1995      * @param offset the cursor position to move from
   1996      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
   1997      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
   1998      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
   1999      * @return the offset of the next position, or -1
   2000      * @hide
   2001      */
   2002     public int getTextRunCursor(String text, int contextStart, int contextEnd,
   2003             int flags, int offset, int cursorOpt) {
   2004         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
   2005                 | (offset - contextStart) | (contextEnd - offset)
   2006                 | (text.length() - contextEnd) | cursorOpt) < 0)
   2007                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
   2008             throw new IndexOutOfBoundsException();
   2009         }
   2010 
   2011         return native_getTextRunCursor(mNativePaint, text,
   2012                 contextStart, contextEnd, flags, offset, cursorOpt);
   2013     }
   2014 
   2015     /**
   2016      * Return the path (outline) for the specified text.
   2017      * Note: just like Canvas.drawText, this will respect the Align setting in
   2018      * the paint.
   2019      *
   2020      * @param text     The text to retrieve the path from
   2021      * @param index    The index of the first character in text
   2022      * @param count    The number of characterss starting with index
   2023      * @param x        The x coordinate of the text's origin
   2024      * @param y        The y coordinate of the text's origin
   2025      * @param path     The path to receive the data describing the text. Must
   2026      *                 be allocated by the caller.
   2027      */
   2028     public void getTextPath(char[] text, int index, int count,
   2029                             float x, float y, Path path) {
   2030         if ((index | count) < 0 || index + count > text.length) {
   2031             throw new ArrayIndexOutOfBoundsException();
   2032         }
   2033         native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y,
   2034                 path.ni());
   2035     }
   2036 
   2037     /**
   2038      * Return the path (outline) for the specified text.
   2039      * Note: just like Canvas.drawText, this will respect the Align setting
   2040      * in the paint.
   2041      *
   2042      * @param text  The text to retrieve the path from
   2043      * @param start The first character in the text
   2044      * @param end   1 past the last charcter in the text
   2045      * @param x     The x coordinate of the text's origin
   2046      * @param y     The y coordinate of the text's origin
   2047      * @param path  The path to receive the data describing the text. Must
   2048      *              be allocated by the caller.
   2049      */
   2050     public void getTextPath(String text, int start, int end,
   2051                             float x, float y, Path path) {
   2052         if ((start | end | (end - start) | (text.length() - end)) < 0) {
   2053             throw new IndexOutOfBoundsException();
   2054         }
   2055         native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y,
   2056                 path.ni());
   2057     }
   2058 
   2059     /**
   2060      * Return in bounds (allocated by the caller) the smallest rectangle that
   2061      * encloses all of the characters, with an implied origin at (0,0).
   2062      *
   2063      * @param text  String to measure and return its bounds
   2064      * @param start Index of the first char in the string to measure
   2065      * @param end   1 past the last char in the string measure
   2066      * @param bounds Returns the unioned bounds of all the text. Must be
   2067      *               allocated by the caller.
   2068      */
   2069     public void getTextBounds(String text, int start, int end, Rect bounds) {
   2070         if ((start | end | (end - start) | (text.length() - end)) < 0) {
   2071             throw new IndexOutOfBoundsException();
   2072         }
   2073         if (bounds == null) {
   2074             throw new NullPointerException("need bounds Rect");
   2075         }
   2076         nativeGetStringBounds(mNativePaint, text, start, end, mBidiFlags, bounds);
   2077     }
   2078 
   2079     /**
   2080      * Return in bounds (allocated by the caller) the smallest rectangle that
   2081      * encloses all of the characters, with an implied origin at (0,0).
   2082      *
   2083      * @param text  Array of chars to measure and return their unioned bounds
   2084      * @param index Index of the first char in the array to measure
   2085      * @param count The number of chars, beginning at index, to measure
   2086      * @param bounds Returns the unioned bounds of all the text. Must be
   2087      *               allocated by the caller.
   2088      */
   2089     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
   2090         if ((index | count) < 0 || index + count > text.length) {
   2091             throw new ArrayIndexOutOfBoundsException();
   2092         }
   2093         if (bounds == null) {
   2094             throw new NullPointerException("need bounds Rect");
   2095         }
   2096         nativeGetCharArrayBounds(mNativePaint, text, index, count, mBidiFlags, bounds);
   2097     }
   2098 
   2099     @Override
   2100     protected void finalize() throws Throwable {
   2101         try {
   2102             finalizer(mNativePaint);
   2103         } finally {
   2104             super.finalize();
   2105         }
   2106     }
   2107 
   2108     private static native int native_init();
   2109     private static native int native_initWithPaint(int paint);
   2110     private static native void native_reset(int native_object);
   2111     private static native void native_set(int native_dst, int native_src);
   2112     private static native int native_getStyle(int native_object);
   2113     private static native void native_setStyle(int native_object, int style);
   2114     private static native int native_getStrokeCap(int native_object);
   2115     private static native void native_setStrokeCap(int native_object, int cap);
   2116     private static native int native_getStrokeJoin(int native_object);
   2117     private static native void native_setStrokeJoin(int native_object,
   2118                                                     int join);
   2119     private static native boolean native_getFillPath(int native_object,
   2120                                                      int src, int dst);
   2121     private static native int native_setShader(int native_object, int shader);
   2122     private static native int native_setColorFilter(int native_object,
   2123                                                     int filter);
   2124     private static native int native_setXfermode(int native_object,
   2125                                                  int xfermode);
   2126     private static native int native_setPathEffect(int native_object,
   2127                                                    int effect);
   2128     private static native int native_setMaskFilter(int native_object,
   2129                                                    int maskfilter);
   2130     private static native int native_setTypeface(int native_object,
   2131                                                  int typeface);
   2132     private static native int native_setRasterizer(int native_object,
   2133                                                    int rasterizer);
   2134 
   2135     private static native int native_getTextAlign(int native_object);
   2136     private static native void native_setTextAlign(int native_object,
   2137                                                    int align);
   2138 
   2139     private static native void native_setTextLocale(int native_object,
   2140                                                     String locale);
   2141 
   2142     private static native int native_getTextWidths(int native_object,
   2143                             char[] text, int index, int count, int bidiFlags, float[] widths);
   2144     private static native int native_getTextWidths(int native_object,
   2145                             String text, int start, int end, int bidiFlags, float[] widths);
   2146 
   2147     private static native int native_getTextGlyphs(int native_object,
   2148             String text, int start, int end, int contextStart, int contextEnd,
   2149             int flags, char[] glyphs);
   2150 
   2151     private static native float native_getTextRunAdvances(int native_object,
   2152             char[] text, int index, int count, int contextIndex, int contextCount,
   2153             int flags, float[] advances, int advancesIndex);
   2154     private static native float native_getTextRunAdvances(int native_object,
   2155             String text, int start, int end, int contextStart, int contextEnd,
   2156             int flags, float[] advances, int advancesIndex);
   2157 
   2158     private native int native_getTextRunCursor(int native_object, char[] text,
   2159             int contextStart, int contextLength, int flags, int offset, int cursorOpt);
   2160     private native int native_getTextRunCursor(int native_object, String text,
   2161             int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
   2162 
   2163     private static native void native_getTextPath(int native_object, int bidiFlags,
   2164                 char[] text, int index, int count, float x, float y, int path);
   2165     private static native void native_getTextPath(int native_object, int bidiFlags,
   2166                 String text, int start, int end, float x, float y, int path);
   2167     private static native void nativeGetStringBounds(int nativePaint,
   2168                                 String text, int start, int end, int bidiFlags, Rect bounds);
   2169     private static native void nativeGetCharArrayBounds(int nativePaint,
   2170                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
   2171     private static native void finalizer(int nativePaint);
   2172 }
   2173