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 
Style(int nativeInt)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 
Cap(int nativeInt)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 
Join(int nativeInt)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 
Align(int nativeInt)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      */
Paint()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      */
Paint(int flags)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      */
Paint(Paint paint)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. */
reset()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      */
set(Paint src)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      */
setClassVariablesFrom(Paint paint)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      */
hasEqualAttributes(@onNull Paint other)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 */
setCompatibilityScaling(float factor)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      */
getNativeInstance()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      */
getBidiFlags()658     public int getBidiFlags() {
659         return mBidiFlags;
660     }
661 
662     /**
663      * Set the bidi flags on the paint.
664      * @hide
665      */
setBidiFlags(int flags)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      */
getFlags()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      */
setFlags(int flags)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      */
getHinting()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      */
setHinting(int mode)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      */
isAntiAlias()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      */
setAntiAlias(boolean aa)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      */
isDither()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      */
setDither(boolean dither)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      */
isLinearText()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      */
setLinearText(boolean linearText)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      */
isSubpixelText()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      */
setSubpixelText(boolean subpixelText)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      */
isUnderlineText()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      */
getUnderlinePosition()814     public float getUnderlinePosition() {
815         return nGetUnderlinePosition(mNativePaint);
816     }
817 
818     /**
819      * @hide
820      */
getUnderlineThickness()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      */
setUnderlineText(boolean underlineText)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      */
isStrikeThruText()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      */
getStrikeThruPosition()850     public float getStrikeThruPosition() {
851         return nGetStrikeThruPosition(mNativePaint);
852     }
853 
854     /**
855      * @hide
856      */
getStrikeThruThickness()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      */
setStrikeThruText(boolean strikeThruText)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      */
isFakeBoldText()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      */
setFakeBoldText(boolean fakeBoldText)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      */
isFilterBitmap()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      */
setFilterBitmap(boolean filter)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      */
getStyle()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      */
setStyle(Style style)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
getColor()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      */
setColor(@olorInt int color)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      */
getAlpha()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      */
setAlpha(int a)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      */
setARGB(int a, int r, int g, int b)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      */
getStrokeWidth()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      */
setStrokeWidth(float width)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      */
getStrokeMiter()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      */
setStrokeMiter(float miter)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      */
getStrokeCap()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      */
setStrokeCap(Cap cap)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      */
getStrokeJoin()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      */
setStrokeJoin(Join join)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      */
getFillPath(Path src, Path dst)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      */
getShader()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      */
setShader(Shader shader)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      */
getColorFilter()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      */
setColorFilter(ColorFilter filter)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      */
getXfermode()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      */
setXfermode(Xfermode xfermode)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      */
getPathEffect()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      */
setPathEffect(PathEffect effect)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      */
getMaskFilter()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      */
setMaskFilter(MaskFilter maskfilter)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      */
getTypeface()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      */
setTypeface(Typeface typeface)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
getRasterizer()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
setRasterizer(Rasterizer rasterizer)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      */
setShadowLayer(float radius, float dx, float dy, int shadowColor)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      */
clearShadowLayer()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      */
hasShadowLayer()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      */
getTextAlign()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      */
setTextAlign(Align align)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
getTextLocale()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)
getTextLocales()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      */
setTextLocale(@onNull Locale locale)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      */
setTextLocales(@onNull @izemin=1) LocaleList locales)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 
syncTextLocalesWithMinikin()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      */
isElegantTextHeight()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      */
setElegantTextHeight(boolean elegant)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      */
getTextSize()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      */
setTextSize(float textSize)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      */
getTextScaleX()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      */
setTextScaleX(float scaleX)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      */
getTextSkewX()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      */
setTextSkewX(float skewX)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      */
getLetterSpacing()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      */
setLetterSpacing(float letterSpacing)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      */
getWordSpacing()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      */
setWordSpacing(float wordSpacing)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      */
getFontFeatureSettings()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      */
setFontFeatureSettings(String settings)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      */
getFontVariationSettings()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      */
setFontVariationSettings(String fontVariationSettings)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      */
getHyphenEdit()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      */
setHyphenEdit(int hyphen)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      */
ascent()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      */
descent()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      */
getFontMetrics(FontMetrics metrics)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      */
getFontMetrics()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 
toString()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      */
getFontMetricsInt(FontMetricsInt fmi)1858     public int getFontMetricsInt(FontMetricsInt fmi) {
1859         return nGetFontMetricsInt(mNativePaint, fmi);
1860     }
1861 
getFontMetricsInt()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      */
getFontSpacing()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      */
measureText(char[] text, int index, int count)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      */
measureText(String text, int start, int end)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      */
measureText(String text)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      */
measureText(CharSequence text, int start, int end)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      */
breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth)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      */
breakText(CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)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      */
breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth)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      */
getTextWidths(char[] text, int index, int count, float[] widths)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      */
getTextWidths(CharSequence text, int start, int end, float[] widths)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      */
getTextWidths(String text, int start, int end, float[] widths)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      */
getTextWidths(String text, float[] widths)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      */
getTextRunAdvances(char[] chars, int index, int count, int contextIndex, int contextCount, boolean isRtl, float[] advances, int advancesIndex)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      */
getTextRunAdvances(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex)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      */
getTextRunAdvances(String text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex)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      */
getTextRunCursor(char[] text, int contextStart, int contextLength, int dir, int offset, int cursorOpt)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      */
getTextRunCursor(CharSequence text, int contextStart, int contextEnd, int dir, int offset, int cursorOpt)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      */
getTextRunCursor(String text, int contextStart, int contextEnd, int dir, int offset, int cursorOpt)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      */
getTextPath(char[] text, int index, int count, float x, float y, Path path)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      */
getTextPath(String text, int start, int end, float x, float y, Path path)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      */
getTextBounds(String text, int start, int end, Rect bounds)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      */
getTextBounds(CharSequence text, int start, int end, Rect bounds)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      */
getTextBounds(char[] text, int index, int count, Rect bounds)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      */
hasGlyph(String string)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      */
getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)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      */
getRunAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)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      */
getOffsetForAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)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      */
getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)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      */
equalsForTextMeasurement(@onNull Paint other)2844     public boolean equalsForTextMeasurement(@NonNull Paint other) {
2845         return nEqualsForTextMeasurement(mNativePaint, other.mNativePaint);
2846     }
2847 
2848     // regular JNI
nGetNativeFinalizer()2849     private static native long nGetNativeFinalizer();
nInit()2850     private static native long nInit();
nInitWithPaint(long paint)2851     private static native long nInitWithPaint(long paint);
nBreakText(long nObject, char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth)2852     private static native int nBreakText(long nObject, char[] text, int index, int count,
2853             float maxWidth, int bidiFlags, float[] measuredWidth);
nBreakText(long nObject, String text, boolean measureForwards, 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);
nGetTextAdvances(long paintPtr, char[] text, int index, int count, int contextIndex, int contextCount, int bidiFlags, float[] advances, int advancesIndex)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);
nGetTextAdvances(long paintPtr, String text, int start, int end, int contextStart, int contextEnd, 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);
nGetTextRunCursor(long paintPtr, char[] text, int contextStart, int contextLength, int dir, int offset, int cursorOpt)2860     private native int nGetTextRunCursor(long paintPtr, char[] text, int contextStart,
2861             int contextLength, int dir, int offset, int cursorOpt);
nGetTextRunCursor(long paintPtr, String text, int contextStart, int contextEnd, 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);
nGetTextPath(long paintPtr, int bidiFlags, char[] text, int index, int count, float x, float y, long path)2864     private static native void nGetTextPath(long paintPtr, int bidiFlags, char[] text, int index,
2865             int count, float x, float y, long path);
nGetTextPath(long paintPtr, int bidiFlags, String text, int start, int end, 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);
nGetStringBounds(long nativePaint, String text, int start, int end, int bidiFlags, Rect bounds)2868     private static native void nGetStringBounds(long nativePaint, String text, int start, int end,
2869             int bidiFlags, Rect bounds);
nGetCharArrayBounds(long nativePaint, char[] text, int index, int count, int bidiFlags, Rect bounds)2870     private static native void nGetCharArrayBounds(long nativePaint, char[] text, int index,
2871             int count, int bidiFlags, Rect bounds);
nHasGlyph(long paintPtr, int bidiFlags, String string)2872     private static native boolean nHasGlyph(long paintPtr, int bidiFlags, String string);
nGetRunAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)2873     private static native float nGetRunAdvance(long paintPtr, char[] text, int start, int end,
2874             int contextStart, int contextEnd, boolean isRtl, int offset);
nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)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
nSetTextLocales(long paintPtr, String locales)2882     private static native int nSetTextLocales(long paintPtr, String locales);
2883     @FastNative
nSetFontFeatureSettings(long paintPtr, String settings)2884     private static native void nSetFontFeatureSettings(long paintPtr, String settings);
2885     @FastNative
nGetFontMetrics(long paintPtr, FontMetrics metrics)2886     private static native float nGetFontMetrics(long paintPtr, FontMetrics metrics);
2887     @FastNative
nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi)2888     private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi);
2889 
2890 
2891     // ---------------- @CriticalNative ------------------------
2892 
2893     @CriticalNative
nReset(long paintPtr)2894     private static native void nReset(long paintPtr);
2895     @CriticalNative
nSet(long paintPtrDest, long paintPtrSrc)2896     private static native void nSet(long paintPtrDest, long paintPtrSrc);
2897     @CriticalNative
nGetStyle(long paintPtr)2898     private static native int nGetStyle(long paintPtr);
2899     @CriticalNative
nSetStyle(long paintPtr, int style)2900     private static native void nSetStyle(long paintPtr, int style);
2901     @CriticalNative
nGetStrokeCap(long paintPtr)2902     private static native int nGetStrokeCap(long paintPtr);
2903     @CriticalNative
nSetStrokeCap(long paintPtr, int cap)2904     private static native void nSetStrokeCap(long paintPtr, int cap);
2905     @CriticalNative
nGetStrokeJoin(long paintPtr)2906     private static native int nGetStrokeJoin(long paintPtr);
2907     @CriticalNative
nSetStrokeJoin(long paintPtr, int join)2908     private static native void nSetStrokeJoin(long paintPtr, int join);
2909     @CriticalNative
nGetFillPath(long paintPtr, long src, long dst)2910     private static native boolean nGetFillPath(long paintPtr, long src, long dst);
2911     @CriticalNative
nSetShader(long paintPtr, long shader)2912     private static native long nSetShader(long paintPtr, long shader);
2913     @CriticalNative
nSetColorFilter(long paintPtr, long filter)2914     private static native long nSetColorFilter(long paintPtr, long filter);
2915     @CriticalNative
nSetXfermode(long paintPtr, int xfermode)2916     private static native void nSetXfermode(long paintPtr, int xfermode);
2917     @CriticalNative
nSetPathEffect(long paintPtr, long effect)2918     private static native long nSetPathEffect(long paintPtr, long effect);
2919     @CriticalNative
nSetMaskFilter(long paintPtr, long maskfilter)2920     private static native long nSetMaskFilter(long paintPtr, long maskfilter);
2921     @CriticalNative
nSetTypeface(long paintPtr, long typeface)2922     private static native void nSetTypeface(long paintPtr, long typeface);
2923     @CriticalNative
nGetTextAlign(long paintPtr)2924     private static native int nGetTextAlign(long paintPtr);
2925     @CriticalNative
nSetTextAlign(long paintPtr, int align)2926     private static native void nSetTextAlign(long paintPtr, int align);
2927     @CriticalNative
nSetTextLocalesByMinikinLocaleListId(long paintPtr, int mMinikinLocaleListId)2928     private static native void nSetTextLocalesByMinikinLocaleListId(long paintPtr,
2929             int mMinikinLocaleListId);
2930     @CriticalNative
nSetShadowLayer(long paintPtr, float radius, float dx, float dy, int color)2931     private static native void nSetShadowLayer(long paintPtr,
2932             float radius, float dx, float dy, int color);
2933     @CriticalNative
nHasShadowLayer(long paintPtr)2934     private static native boolean nHasShadowLayer(long paintPtr);
2935     @CriticalNative
nGetLetterSpacing(long paintPtr)2936     private static native float nGetLetterSpacing(long paintPtr);
2937     @CriticalNative
nSetLetterSpacing(long paintPtr, float letterSpacing)2938     private static native void nSetLetterSpacing(long paintPtr, float letterSpacing);
2939     @CriticalNative
nGetWordSpacing(long paintPtr)2940     private static native float nGetWordSpacing(long paintPtr);
2941     @CriticalNative
nSetWordSpacing(long paintPtr, float wordSpacing)2942     private static native void nSetWordSpacing(long paintPtr, float wordSpacing);
2943     @CriticalNative
nGetHyphenEdit(long paintPtr)2944     private static native int nGetHyphenEdit(long paintPtr);
2945     @CriticalNative
nSetHyphenEdit(long paintPtr, int hyphen)2946     private static native void nSetHyphenEdit(long paintPtr, int hyphen);
2947     @CriticalNative
nSetStrokeMiter(long paintPtr, float miter)2948     private static native void nSetStrokeMiter(long paintPtr, float miter);
2949     @CriticalNative
nGetStrokeMiter(long paintPtr)2950     private static native float nGetStrokeMiter(long paintPtr);
2951     @CriticalNative
nSetStrokeWidth(long paintPtr, float width)2952     private static native void nSetStrokeWidth(long paintPtr, float width);
2953     @CriticalNative
nGetStrokeWidth(long paintPtr)2954     private static native float nGetStrokeWidth(long paintPtr);
2955     @CriticalNative
nSetAlpha(long paintPtr, int a)2956     private static native void nSetAlpha(long paintPtr, int a);
2957     @CriticalNative
nSetDither(long paintPtr, boolean dither)2958     private static native void nSetDither(long paintPtr, boolean dither);
2959     @CriticalNative
nGetFlags(long paintPtr)2960     private static native int nGetFlags(long paintPtr);
2961     @CriticalNative
nSetFlags(long paintPtr, int flags)2962     private static native void nSetFlags(long paintPtr, int flags);
2963     @CriticalNative
nGetHinting(long paintPtr)2964     private static native int nGetHinting(long paintPtr);
2965     @CriticalNative
nSetHinting(long paintPtr, int mode)2966     private static native void nSetHinting(long paintPtr, int mode);
2967     @CriticalNative
nSetAntiAlias(long paintPtr, boolean aa)2968     private static native void nSetAntiAlias(long paintPtr, boolean aa);
2969     @CriticalNative
nSetLinearText(long paintPtr, boolean linearText)2970     private static native void nSetLinearText(long paintPtr, boolean linearText);
2971     @CriticalNative
nSetSubpixelText(long paintPtr, boolean subpixelText)2972     private static native void nSetSubpixelText(long paintPtr, boolean subpixelText);
2973     @CriticalNative
nSetUnderlineText(long paintPtr, boolean underlineText)2974     private static native void nSetUnderlineText(long paintPtr, boolean underlineText);
2975     @CriticalNative
nSetFakeBoldText(long paintPtr, boolean fakeBoldText)2976     private static native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
2977     @CriticalNative
nSetFilterBitmap(long paintPtr, boolean filter)2978     private static native void nSetFilterBitmap(long paintPtr, boolean filter);
2979     @CriticalNative
nGetColor(long paintPtr)2980     private static native int nGetColor(long paintPtr);
2981     @CriticalNative
nSetColor(long paintPtr, @ColorInt int color)2982     private static native void nSetColor(long paintPtr, @ColorInt int color);
2983     @CriticalNative
nGetAlpha(long paintPtr)2984     private static native int nGetAlpha(long paintPtr);
2985     @CriticalNative
nSetStrikeThruText(long paintPtr, boolean strikeThruText)2986     private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
2987     @CriticalNative
nIsElegantTextHeight(long paintPtr)2988     private static native boolean nIsElegantTextHeight(long paintPtr);
2989     @CriticalNative
nSetElegantTextHeight(long paintPtr, boolean elegant)2990     private static native void nSetElegantTextHeight(long paintPtr, boolean elegant);
2991     @CriticalNative
nGetTextSize(long paintPtr)2992     private static native float nGetTextSize(long paintPtr);
2993     @CriticalNative
nGetTextScaleX(long paintPtr)2994     private static native float nGetTextScaleX(long paintPtr);
2995     @CriticalNative
nSetTextScaleX(long paintPtr, float scaleX)2996     private static native void nSetTextScaleX(long paintPtr, float scaleX);
2997     @CriticalNative
nGetTextSkewX(long paintPtr)2998     private static native float nGetTextSkewX(long paintPtr);
2999     @CriticalNative
nSetTextSkewX(long paintPtr, float skewX)3000     private static native void nSetTextSkewX(long paintPtr, float skewX);
3001     @CriticalNative
nAscent(long paintPtr)3002     private static native float nAscent(long paintPtr);
3003     @CriticalNative
nDescent(long paintPtr)3004     private static native float nDescent(long paintPtr);
3005     @CriticalNative
nGetUnderlinePosition(long paintPtr)3006     private static native float nGetUnderlinePosition(long paintPtr);
3007     @CriticalNative
nGetUnderlineThickness(long paintPtr)3008     private static native float nGetUnderlineThickness(long paintPtr);
3009     @CriticalNative
nGetStrikeThruPosition(long paintPtr)3010     private static native float nGetStrikeThruPosition(long paintPtr);
3011     @CriticalNative
nGetStrikeThruThickness(long paintPtr)3012     private static native float nGetStrikeThruThickness(long paintPtr);
3013     @CriticalNative
nSetTextSize(long paintPtr, float textSize)3014     private static native void nSetTextSize(long paintPtr, float textSize);
3015     @CriticalNative
nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr)3016     private static native boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr);
3017 }
3018