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