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