• 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 static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
20 import static com.android.text.flags.Flags.FLAG_LETTER_SPACING_JUSTIFICATION;
21 
22 import android.annotation.ColorInt;
23 import android.annotation.ColorLong;
24 import android.annotation.FlaggedApi;
25 import android.annotation.IntDef;
26 import android.annotation.IntRange;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.annotation.Px;
30 import android.annotation.Size;
31 import android.app.compat.CompatChanges;
32 import android.compat.annotation.ChangeId;
33 import android.compat.annotation.EnabledSince;
34 import android.compat.annotation.UnsupportedAppUsage;
35 import android.graphics.fonts.FontVariationAxis;
36 import android.os.Build;
37 import android.os.LocaleList;
38 import android.text.GraphicsOperations;
39 import android.text.SpannableString;
40 import android.text.SpannedString;
41 import android.text.TextUtils;
42 
43 import com.android.internal.annotations.GuardedBy;
44 
45 import dalvik.annotation.optimization.CriticalNative;
46 import dalvik.annotation.optimization.FastNative;
47 
48 import libcore.util.NativeAllocationRegistry;
49 
50 import java.lang.annotation.Retention;
51 import java.lang.annotation.RetentionPolicy;
52 import java.util.ArrayList;
53 import java.util.Collections;
54 import java.util.HashMap;
55 import java.util.Locale;
56 import java.util.Objects;
57 
58 /**
59  * The Paint class holds the style and color information about how to draw
60  * geometries, text and bitmaps.
61  */
62 public class Paint {
63 
64     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
65     private long mNativePaint;
66     private long mNativeShader;
67     private long mNativeColorFilter;
68 
69     // Use a Holder to allow static initialization of Paint in the boot image.
70     private static class NoImagePreloadHolder {
71         public static final NativeAllocationRegistry sRegistry =
72                 NativeAllocationRegistry.createMalloced(
73                 Paint.class.getClassLoader(), nGetNativeFinalizer());
74     }
75 
76     @ColorLong private long mColor;
77     private ColorFilter     mColorFilter;
78     private MaskFilter      mMaskFilter;
79     private PathEffect      mPathEffect;
80     private Shader          mShader;
81     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
82     private Typeface        mTypeface;
83     private Xfermode        mXfermode;
84 
85     private boolean         mHasCompatScaling;
86     private float           mCompatScaling;
87     private float           mInvCompatScaling;
88 
89     private LocaleList      mLocales;
90     private String          mFontFeatureSettings;
91     private String          mFontVariationSettings;
92 
93     private float           mShadowLayerRadius;
94     private float           mShadowLayerDx;
95     private float           mShadowLayerDy;
96     @ColorLong private long mShadowLayerColor;
97 
98     private static final Object sCacheLock = new Object();
99 
100     /**
101      * Cache for the Minikin language list ID.
102      *
103      * A map from a string representation of the LocaleList to Minikin's language list ID.
104      */
105     @GuardedBy("sCacheLock")
106     private static final HashMap<String, Integer> sMinikinLocaleListIdCache = new HashMap<>();
107 
108     /**
109      * @hide
110      */
111     public  int         mBidiFlags = BIDI_DEFAULT_LTR;
112 
113     static final Style[] sStyleArray = {
114         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
115     };
116     static final Cap[] sCapArray = {
117         Cap.BUTT, Cap.ROUND, Cap.SQUARE
118     };
119     static final Join[] sJoinArray = {
120         Join.MITER, Join.ROUND, Join.BEVEL
121     };
122     static final Align[] sAlignArray = {
123         Align.LEFT, Align.CENTER, Align.RIGHT
124     };
125 
126     /** @hide */
127     @Retention(RetentionPolicy.SOURCE)
128     @IntDef(flag = true, value = {
129             ANTI_ALIAS_FLAG,
130             FILTER_BITMAP_FLAG,
131             DITHER_FLAG,
132             UNDERLINE_TEXT_FLAG,
133             STRIKE_THRU_TEXT_FLAG,
134             FAKE_BOLD_TEXT_FLAG,
135             LINEAR_TEXT_FLAG,
136             SUBPIXEL_TEXT_FLAG,
137             EMBEDDED_BITMAP_TEXT_FLAG,
138             TEXT_RUN_FLAG_LEFT_EDGE,
139             TEXT_RUN_FLAG_RIGHT_EDGE
140     })
141     public @interface PaintFlag{}
142 
143     /**
144      * Paint flag that enables antialiasing when drawing.
145      *
146      * <p>Enabling this flag will cause all draw operations that support
147      * antialiasing to use it.</p>
148      *
149      * <p>Notable draw operations that do <b>not</b> support antialiasing include:</p>
150      * <ul>
151      *      <li>{@link android.graphics.Canvas#drawBitmapMesh}</li>
152      *      <li>{@link android.graphics.Canvas#drawPatch}</li>
153      *      <li>{@link android.graphics.Canvas#drawVertices}</li>
154      * </ul>
155      *
156      * @see #Paint(int)
157      * @see #setFlags(int)
158      */
159     public static final int ANTI_ALIAS_FLAG     = 0x01;
160     /**
161      * Paint flag that enables bilinear sampling on scaled bitmaps.
162      *
163      * <p>If cleared, scaled bitmaps will be drawn with nearest neighbor
164      * sampling, likely resulting in artifacts. This should generally be on
165      * when drawing bitmaps, unless performance-bound (rendering to software
166      * canvas) or preferring pixelation artifacts to blurriness when scaling
167      * significantly.</p>
168      *
169      * <p>If bitmaps are scaled for device density at creation time (as
170      * resource bitmaps often are) the filtering will already have been
171      * done.</p>
172      *
173      * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
174      * accelerated drawing always uses bilinear sampling on scaled bitmaps,
175      * regardless of this flag. On devices running {@link Build.VERSION_CODES#Q}
176      * and above, this flag defaults to being set on a new {@code Paint}. It can
177      * be cleared with {@link #setFlags} or {@link #setFilterBitmap}.</p>
178      *
179      * @see #Paint()
180      * @see #Paint(int)
181      * @see #setFlags(int)
182      */
183     public static final int FILTER_BITMAP_FLAG  = 0x02;
184     /**
185      * Paint flag that enables dithering when blitting.
186      *
187      * <p>Enabling this flag applies a dither to any blit operation where the
188      * target's colour space is more constrained than the source.
189      *
190      * @see #Paint(int)
191      * @see #setFlags(int)
192      */
193     public static final int DITHER_FLAG         = 0x04;
194     /**
195      * Paint flag that applies an underline decoration to drawn text.
196      *
197      * @see #Paint(int)
198      * @see #setFlags(int)
199      */
200     public static final int UNDERLINE_TEXT_FLAG = 0x08;
201     /**
202      * Paint flag that applies a strike-through decoration to drawn text.
203      *
204      * @see #Paint(int)
205      * @see #setFlags(int)
206      */
207     public static final int STRIKE_THRU_TEXT_FLAG = 0x10;
208     /**
209      * Paint flag that applies a synthetic bolding effect to drawn text.
210      *
211      * <p>Enabling this flag will cause text draw operations to apply a
212      * simulated bold effect when drawing a {@link Typeface} that is not
213      * already bold.</p>
214      *
215      * @see #Paint(int)
216      * @see #setFlags(int)
217      */
218     public static final int FAKE_BOLD_TEXT_FLAG = 0x20;
219     /**
220      * Paint flag that enables smooth linear scaling of text.
221      *
222      * <p>Enabling this flag does not actually scale text, but rather adjusts
223      * text draw operations to deal gracefully with smooth adjustment of scale.
224      * When this flag is enabled, font hinting is disabled to prevent shape
225      * deformation between scale factors, and glyph caching is disabled due to
226      * the large number of glyph images that will be generated.</p>
227      *
228      * <p>{@link #SUBPIXEL_TEXT_FLAG} should be used in conjunction with this
229      * flag to prevent glyph positions from snapping to whole pixel values as
230      * scale factor is adjusted.</p>
231      *
232      * @see #Paint(int)
233      * @see #setFlags(int)
234      */
235     public static final int LINEAR_TEXT_FLAG    = 0x40;
236     /**
237      * Paint flag that enables subpixel positioning of text.
238      *
239      * <p>Enabling this flag causes glyph advances to be computed with subpixel
240      * accuracy.</p>
241      *
242      * <p>This can be used with {@link #LINEAR_TEXT_FLAG} to prevent text from
243      * jittering during smooth scale transitions.</p>
244      *
245      * @see #Paint(int)
246      * @see #setFlags(int)
247      */
248     public static final int SUBPIXEL_TEXT_FLAG  = 0x80;
249     /** Legacy Paint flag, no longer used. */
250     public static final int DEV_KERN_TEXT_FLAG  = 0x100;
251     /** @hide bit mask for the flag enabling subpixel glyph rendering for text */
252     public static final int LCD_RENDER_TEXT_FLAG = 0x200;
253     /**
254      * Paint flag that enables the use of bitmap fonts when drawing text.
255      *
256      * <p>Disabling this flag will prevent text draw operations from using
257      * embedded bitmap strikes in fonts, causing fonts with both scalable
258      * outlines and bitmap strikes to draw only the scalable outlines, and
259      * fonts with only bitmap strikes to not draw at all.</p>
260      *
261      * @see #Paint(int)
262      * @see #setFlags(int)
263      */
264     public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400;
265     /** @hide bit mask for the flag forcing freetype's autohinter on for text */
266     public static final int AUTO_HINTING_TEXT_FLAG = 0x800;
267     /** @hide bit mask for the flag enabling vertical rendering for text */
268     public static final int VERTICAL_TEXT_FLAG = 0x1000;
269 
270     /**
271      * A text run flag that indicates the run is located the visually most left segment of the line.
272      * <p>
273      * This flag is used for telling the underlying text layout engine that the text is located at
274      * the most left of the line. This flag is used for controlling the amount letter spacing
275      * added. If the text is in the middle of the line, the text layout engine assigns additional
276      * letter spacing to the both side of each letter. On the other hand, the letter spacing should
277      * not be added to the visually most left and right of the line. By setting this flag, text
278      * layout engine calculates the layout as it is located at the most visually left of the line
279      * and doesn't add letter spacing to the left of this run.
280      * <p>
281      * Note that the caller must resolve BiDi runs and reorder them visually and set this flag only
282      * if the target run is located visually most left position. This left does not always mean the
283      * beginning of the text.
284      * <p>
285      * If the run covers entire line, caller should set {@link #TEXT_RUN_FLAG_RIGHT_EDGE} as well.
286      * <p>
287      * Note that this flag is only effective for run based APIs. For example, this flag works for
288      * {@link Canvas#drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)}
289      * and
290      * {@link Paint#getRunCharacterAdvance(char[], int, int, int, int, boolean, int, float[], int)}.
291      * However, this doesn't work for
292      * {@link Canvas#drawText(CharSequence, int, int, float, float, Paint)} or
293      * {@link Paint#measureText(CharSequence, int, int)}. The non-run based APIs works as both
294      * {@link #TEXT_RUN_FLAG_LEFT_EDGE} and {@link #TEXT_RUN_FLAG_RIGHT_EDGE} are specified.
295      */
296     @FlaggedApi(FLAG_LETTER_SPACING_JUSTIFICATION)
297     public static final int TEXT_RUN_FLAG_LEFT_EDGE = 0x2000;
298 
299 
300     /**
301      * A text run flag that indicates the run is located the visually most right segment of the
302      * line.
303      * <p>
304      * This flag is used for telling the underlying text layout engine that the text is located at
305      * the most right of the line. This flag is used for controlling the amount letter spacing
306      * added. If the text is in the middle of the line, the text layout engine assigns additional
307      * letter spacing to the both side of each letter. On the other hand, the letter spacing should
308      * not be added to the visually most left and right of the line. By setting this flag, text
309      * layout engine calculates the layout as it is located at the most visually left of the line
310      * and doesn't add letter spacing to the left of this run.
311      * <p>
312      * Note that the caller must resolve BiDi runs and reorder them visually and set this flag only
313      * if the target run is located visually most right position. This right does not always mean
314      * the end of the text.
315      * <p>
316      * If the run covers entire line, caller should set {@link #TEXT_RUN_FLAG_LEFT_EDGE} as well.
317      * <p>
318      * Note that this flag is only effective for run based APIs. For example, this flag works for
319      * {@link Canvas#drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)}
320      * and
321      * {@link Paint#getRunCharacterAdvance(char[], int, int, int, int, boolean, int, float[], int)}.
322      * However, this doesn't work for
323      * {@link Canvas#drawText(CharSequence, int, int, float, float, Paint)} or
324      * {@link Paint#measureText(CharSequence, int, int)}. The non-run based APIs works as both
325      * {@link #TEXT_RUN_FLAG_LEFT_EDGE} and {@link #TEXT_RUN_FLAG_RIGHT_EDGE} are specified.
326      */
327     @FlaggedApi(FLAG_LETTER_SPACING_JUSTIFICATION)
328     public static final int TEXT_RUN_FLAG_RIGHT_EDGE = 0x4000;
329 
330     // These flags are always set on a new/reset paint, even if flags 0 is passed.
331     static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG
332             | FILTER_BITMAP_FLAG;
333 
334     /**
335      * Font hinter option that disables font hinting.
336      *
337      * @see #setHinting(int)
338      */
339     public static final int HINTING_OFF = 0x0;
340 
341     /**
342      * Font hinter option that enables font hinting.
343      *
344      * @see #setHinting(int)
345      */
346     public static final int HINTING_ON = 0x1;
347 
348     /**
349      * Bidi flag to set LTR paragraph direction.
350      *
351      * @hide
352      */
353     public static final int BIDI_LTR = 0x0;
354 
355     /**
356      * Bidi flag to set RTL paragraph direction.
357      *
358      * @hide
359      */
360     public static final int BIDI_RTL = 0x1;
361 
362     /**
363      * Bidi flag to detect paragraph direction via heuristics, defaulting to
364      * LTR.
365      *
366      * @hide
367      */
368     public static final int BIDI_DEFAULT_LTR = 0x2;
369 
370     /**
371      * Bidi flag to detect paragraph direction via heuristics, defaulting to
372      * RTL.
373      *
374      * @hide
375      */
376     public static final int BIDI_DEFAULT_RTL = 0x3;
377 
378     /**
379      * Bidi flag to override direction to all LTR (ignore bidi).
380      *
381      * @hide
382      */
383     public static final int BIDI_FORCE_LTR = 0x4;
384 
385     /**
386      * Bidi flag to override direction to all RTL (ignore bidi).
387      *
388      * @hide
389      */
390     public static final int BIDI_FORCE_RTL = 0x5;
391 
392     /**
393      * Maximum Bidi flag value.
394      * @hide
395      */
396     private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
397 
398     /**
399      * Mask for bidi flags.
400      * @hide
401      */
402     private static final int BIDI_FLAG_MASK = 0x7;
403 
404     /**
405      * Flag for getTextRunAdvances indicating left-to-right run direction.
406      * @hide
407      */
408     public static final int DIRECTION_LTR = 0;
409 
410     /**
411      * Flag for getTextRunAdvances indicating right-to-left run direction.
412      * @hide
413      */
414     public static final int DIRECTION_RTL = 1;
415 
416     /** @hide */
417     @IntDef(prefix = { "CURSOR_" }, value = {
418         CURSOR_AFTER, CURSOR_AT_OR_AFTER, CURSOR_BEFORE, CURSOR_AT_OR_BEFORE
419     })
420     @Retention(RetentionPolicy.SOURCE)
421     public @interface CursorOption {}
422 
423     /**
424      * Option for getTextRunCursor.
425      *
426      * Compute the valid cursor after offset or the limit of the context, whichever is less.
427      */
428     public static final int CURSOR_AFTER = 0;
429 
430     /**
431      * Option for getTextRunCursor.
432      *
433      * Compute the valid cursor at or after the offset or the limit of the context, whichever is
434      * less.
435      */
436     public static final int CURSOR_AT_OR_AFTER = 1;
437 
438      /**
439      * Option for getTextRunCursor.
440      *
441      * Compute the valid cursor before offset or the start of the context, whichever is greater.
442      */
443     public static final int CURSOR_BEFORE = 2;
444 
445    /**
446      * Option for getTextRunCursor.
447      *
448      * Compute the valid cursor at or before offset or the start of the context, whichever is
449      * greater.
450      */
451     public static final int CURSOR_AT_OR_BEFORE = 3;
452 
453     /**
454      * Option for getTextRunCursor.
455      *
456      * Return offset if the cursor at offset is valid, or -1 if it isn't.
457      */
458     public static final int CURSOR_AT = 4;
459 
460     /**
461      * Maximum cursor option value.
462      */
463     private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT;
464 
465     /** @hide */
466     @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = {
467         START_HYPHEN_EDIT_NO_EDIT,
468         START_HYPHEN_EDIT_INSERT_HYPHEN,
469         START_HYPHEN_EDIT_INSERT_ZWJ
470     })
471     @Retention(RetentionPolicy.SOURCE)
472     public @interface StartHyphenEdit {}
473 
474     /**
475      * An integer representing the starting of the line has no modification for hyphenation.
476      */
477     public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00;
478 
479     /**
480      * An integer representing the starting of the line has normal hyphen character (U+002D).
481      */
482     public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01;
483 
484     /**
485      * An integer representing the starting of the line has Zero-Width-Joiner (U+200D).
486      */
487     public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02;
488 
489     /** @hide */
490     @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = {
491         END_HYPHEN_EDIT_NO_EDIT,
492         END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN,
493         END_HYPHEN_EDIT_INSERT_HYPHEN,
494         END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN,
495         END_HYPHEN_EDIT_INSERT_MAQAF,
496         END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN,
497         END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN
498     })
499     @Retention(RetentionPolicy.SOURCE)
500     public @interface EndHyphenEdit {}
501 
502     /**
503      * An integer representing the end of the line has no modification for hyphenation.
504      */
505     public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00;
506 
507     /**
508      * An integer representing the character at the end of the line is replaced with hyphen
509      * character (U+002D).
510      */
511     public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01;
512 
513     /**
514      * An integer representing the end of the line has normal hyphen character (U+002D).
515      */
516     public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02;
517 
518     /**
519      * An integer representing the end of the line has Armentian hyphen (U+058A).
520      */
521     public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03;
522 
523     /**
524      * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE).
525      */
526     public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04;
527 
528     /**
529      * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400).
530      */
531     public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05;
532 
533     /**
534      * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal
535      * hyphen character (U+002D).
536      */
537     public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06;
538 
539     /**
540      * The Style specifies if the primitive being drawn is filled, stroked, or
541      * both (in the same color). The default is FILL.
542      */
543     public enum Style {
544         /**
545          * Geometry and text drawn with this style will be filled, ignoring all
546          * stroke-related settings in the paint.
547          */
548         FILL            (0),
549         /**
550          * Geometry and text drawn with this style will be stroked, respecting
551          * the stroke-related fields on the paint.
552          */
553         STROKE          (1),
554         /**
555          * Geometry and text drawn with this style will be both filled and
556          * stroked at the same time, respecting the stroke-related fields on
557          * the paint. This mode can give unexpected results if the geometry
558          * is oriented counter-clockwise. This restriction does not apply to
559          * either FILL or STROKE.
560          */
561         FILL_AND_STROKE (2);
562 
Style(int nativeInt)563         Style(int nativeInt) {
564             this.nativeInt = nativeInt;
565         }
566         final int nativeInt;
567     }
568 
569     /**
570      * The Cap specifies the treatment for the beginning and ending of
571      * stroked lines and paths. The default is BUTT.
572      */
573     public enum Cap {
574         /**
575          * The stroke ends with the path, and does not project beyond it.
576          */
577         BUTT    (0),
578         /**
579          * The stroke projects out as a semicircle, with the center at the
580          * end of the path.
581          */
582         ROUND   (1),
583         /**
584          * The stroke projects out as a square, with the center at the end
585          * of the path.
586          */
587         SQUARE  (2);
588 
Cap(int nativeInt)589         private Cap(int nativeInt) {
590             this.nativeInt = nativeInt;
591         }
592         final int nativeInt;
593     }
594 
595     /**
596      * The Join specifies the treatment where lines and curve segments
597      * join on a stroked path. The default is MITER.
598      */
599     public enum Join {
600         /**
601          * The outer edges of a join meet at a sharp angle
602          */
603         MITER   (0),
604         /**
605          * The outer edges of a join meet in a circular arc.
606          */
607         ROUND   (1),
608         /**
609          * The outer edges of a join meet with a straight line
610          */
611         BEVEL   (2);
612 
Join(int nativeInt)613         private Join(int nativeInt) {
614             this.nativeInt = nativeInt;
615         }
616         final int nativeInt;
617     }
618 
619     /**
620      * Align specifies how drawText aligns its text relative to the
621      * [x,y] coordinates. The default is LEFT.
622      */
623     public enum Align {
624         /**
625          * The text is drawn to the right of the x,y origin
626          */
627         LEFT    (0),
628         /**
629          * The text is drawn centered horizontally on the x,y origin
630          */
631         CENTER  (1),
632         /**
633          * The text is drawn to the left of the x,y origin
634          */
635         RIGHT   (2);
636 
Align(int nativeInt)637         private Align(int nativeInt) {
638             this.nativeInt = nativeInt;
639         }
640         final int nativeInt;
641     }
642 
643     /**
644      * Create a new paint with default settings.
645      *
646      * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
647      * accelerated drawing always acts as if {@link #FILTER_BITMAP_FLAG} is set.
648      * On devices running {@link Build.VERSION_CODES#Q} and above,
649      * {@code FILTER_BITMAP_FLAG} is set by this constructor, and it can be
650      * cleared with {@link #setFlags} or {@link #setFilterBitmap}.
651      * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG}
652      * is set by this constructor, and it can be cleared with {@link #setFlags} or
653      * {@link #setAntiAlias}.</p>
654      */
Paint()655     public Paint() {
656         this(ANTI_ALIAS_FLAG);
657     }
658 
659     /**
660      * Create a new paint with the specified flags. Use setFlags() to change
661      * these after the paint is created.
662      *
663      * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
664      * accelerated drawing always acts as if {@link #FILTER_BITMAP_FLAG} is set.
665      * On devices running {@link Build.VERSION_CODES#Q} and above,
666      * {@code FILTER_BITMAP_FLAG} is always set by this constructor, regardless
667      * of the value of {@code flags}. It can be cleared with {@link #setFlags} or
668      * {@link #setFilterBitmap}.</p>
669      *
670      * @param flags initial flag bits, as if they were passed via setFlags().
671      */
Paint(int flags)672     public Paint(int flags) {
673         mNativePaint = nInit();
674         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
675         setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS);
676         // TODO: Turning off hinting has undesirable side effects, we need to
677         //       revisit hinting once we add support for subpixel positioning
678         // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
679         //        ? HINTING_OFF : HINTING_ON);
680         mCompatScaling = mInvCompatScaling = 1;
681         setTextLocales(LocaleList.getAdjustedDefault());
682         mColor = Color.pack(Color.BLACK);
683         resetElegantTextHeight();
684     }
685 
686     /**
687      * Create a new paint, initialized with the attributes in the specified
688      * paint parameter.
689      *
690      * @param paint Existing paint used to initialized the attributes of the
691      *              new paint.
692      */
Paint(Paint paint)693     public Paint(Paint paint) {
694         mNativePaint = nInitWithPaint(paint.getNativeInstance());
695         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
696         setClassVariablesFrom(paint);
697     }
698 
699     /** Restores the paint to its default settings. */
reset()700     public void reset() {
701         nReset(mNativePaint);
702         setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | ANTI_ALIAS_FLAG);
703 
704         // TODO: Turning off hinting has undesirable side effects, we need to
705         //       revisit hinting once we add support for subpixel positioning
706         // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
707         //        ? HINTING_OFF : HINTING_ON);
708 
709         mColor = Color.pack(Color.BLACK);
710         mColorFilter = null;
711         mMaskFilter = null;
712         mPathEffect = null;
713         mShader = null;
714         mNativeShader = 0;
715         mTypeface = null;
716         mXfermode = null;
717 
718         mHasCompatScaling = false;
719         mCompatScaling = 1;
720         mInvCompatScaling = 1;
721 
722         mBidiFlags = BIDI_DEFAULT_LTR;
723         setTextLocales(LocaleList.getAdjustedDefault());
724         resetElegantTextHeight();
725         mFontFeatureSettings = null;
726         mFontVariationSettings = null;
727 
728         mShadowLayerRadius = 0.0f;
729         mShadowLayerDx = 0.0f;
730         mShadowLayerDy = 0.0f;
731         mShadowLayerColor = Color.pack(0);
732     }
733 
734     /**
735      * Copy the fields from src into this paint. This is equivalent to calling
736      * get() on all of the src fields, and calling the corresponding set()
737      * methods on this.
738      */
set(Paint src)739     public void set(Paint src) {
740         if (this != src) {
741             // copy over the native settings
742             nSet(mNativePaint, src.mNativePaint);
743             setClassVariablesFrom(src);
744         }
745     }
746 
747     /**
748      * Set all class variables using current values from the given
749      * {@link Paint}.
750      */
setClassVariablesFrom(Paint paint)751     private void setClassVariablesFrom(Paint paint) {
752         mColor = paint.mColor;
753         mColorFilter = paint.mColorFilter;
754         mMaskFilter = paint.mMaskFilter;
755         mPathEffect = paint.mPathEffect;
756         mShader = paint.mShader;
757         mNativeShader = paint.mNativeShader;
758         mTypeface = paint.mTypeface;
759         mXfermode = paint.mXfermode;
760 
761         mHasCompatScaling = paint.mHasCompatScaling;
762         mCompatScaling = paint.mCompatScaling;
763         mInvCompatScaling = paint.mInvCompatScaling;
764 
765         mBidiFlags = paint.mBidiFlags;
766         mLocales = paint.mLocales;
767         mFontFeatureSettings = paint.mFontFeatureSettings;
768         mFontVariationSettings = paint.mFontVariationSettings;
769 
770         mShadowLayerRadius = paint.mShadowLayerRadius;
771         mShadowLayerDx = paint.mShadowLayerDx;
772         mShadowLayerDy = paint.mShadowLayerDy;
773         mShadowLayerColor = paint.mShadowLayerColor;
774     }
775 
776     /** @hide */
777     @UnsupportedAppUsage
setCompatibilityScaling(float factor)778     public void setCompatibilityScaling(float factor) {
779         if (factor == 1.0) {
780             mHasCompatScaling = false;
781             mCompatScaling = mInvCompatScaling = 1.0f;
782         } else {
783             mHasCompatScaling = true;
784             mCompatScaling = factor;
785             mInvCompatScaling = 1.0f/factor;
786         }
787     }
788 
789     /**
790      * Return the pointer to the native object while ensuring that any
791      * mutable objects that are attached to the paint are also up-to-date.
792      *
793      * Note: Although this method is |synchronized|, this is simply so it
794      * is not thread-hostile to multiple threads calling this method. It
795      * is still unsafe to attempt to change the Shader/ColorFilter while
796      * another thread attempts to access the native object.
797      *
798      * @hide
799      */
800     @UnsupportedAppUsage
getNativeInstance()801     public synchronized long getNativeInstance() {
802         boolean filter = isFilterBitmap();
803         long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance(filter);
804         if (newNativeShader != mNativeShader) {
805             mNativeShader = newNativeShader;
806             nSetShader(mNativePaint, mNativeShader);
807         }
808         long newNativeColorFilter = mColorFilter == null ? 0 : mColorFilter.getNativeInstance();
809         if (newNativeColorFilter != mNativeColorFilter) {
810             mNativeColorFilter = newNativeColorFilter;
811             nSetColorFilter(mNativePaint, mNativeColorFilter);
812         }
813         return mNativePaint;
814     }
815 
816     /**
817      * Return the bidi flags on the paint.
818      *
819      * @return the bidi flags on the paint
820      * @hide
821      */
getBidiFlags()822     public int getBidiFlags() {
823         return mBidiFlags;
824     }
825 
826     /**
827      * Set the bidi flags on the paint.
828      * @hide
829      */
setBidiFlags(int flags)830     public void setBidiFlags(int flags) {
831         // only flag value is the 3-bit BIDI control setting
832         flags &= BIDI_FLAG_MASK;
833         if (flags > BIDI_MAX_FLAG_VALUE) {
834             throw new IllegalArgumentException("unknown bidi flag: " + flags);
835         }
836         mBidiFlags = flags;
837     }
838 
839     /**
840      * Return the paint's flags. Use the Flag enum to test flag values.
841      *
842      * @return the paint's flags (see enums ending in _Flag for bit masks)
843      */
getFlags()844     public @PaintFlag int getFlags() {
845         return nGetFlags(mNativePaint);
846     }
847 
848     /**
849      * Set the paint's flags. Use the Flag enum to specific flag values.
850      *
851      * @param flags The new flag bits for the paint
852      */
setFlags(@aintFlag int flags)853     public void setFlags(@PaintFlag int flags) {
854         nSetFlags(mNativePaint, flags);
855     }
856 
857     /**
858      * Return the paint's hinting mode.  Returns either
859      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
860      */
getHinting()861     public int getHinting() {
862         return nGetHinting(mNativePaint);
863     }
864 
865     /**
866      * Set the paint's hinting mode.  May be either
867      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
868      */
setHinting(int mode)869     public void setHinting(int mode) {
870         nSetHinting(mNativePaint, mode);
871     }
872 
873     /**
874      * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
875      * AntiAliasing smooths out the edges of what is being drawn, but is has
876      * no impact on the interior of the shape. See setDither() and
877      * setFilterBitmap() to affect how colors are treated.
878      *
879      * @return true if the antialias bit is set in the paint's flags.
880      */
isAntiAlias()881     public final boolean isAntiAlias() {
882         return (getFlags() & ANTI_ALIAS_FLAG) != 0;
883     }
884 
885     /**
886      * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
887      * AntiAliasing smooths out the edges of what is being drawn, but is has
888      * no impact on the interior of the shape. See setDither() and
889      * setFilterBitmap() to affect how colors are treated.
890      *
891      * @param aa true to set the antialias bit in the flags, false to clear it
892      */
setAntiAlias(boolean aa)893     public void setAntiAlias(boolean aa) {
894         nSetAntiAlias(mNativePaint, aa);
895     }
896 
897     /**
898      * Helper for getFlags(), returning true if DITHER_FLAG bit is set
899      * Dithering affects how colors that are higher precision than the device
900      * are down-sampled. No dithering is generally faster, but higher precision
901      * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
902      * distribute the error inherent in this process, to reduce the visual
903      * artifacts.
904      *
905      * @return true if the dithering bit is set in the paint's flags.
906      */
isDither()907     public final boolean isDither() {
908         return (getFlags() & DITHER_FLAG) != 0;
909     }
910 
911     /**
912      * Helper for setFlags(), setting or clearing the DITHER_FLAG bit
913      * Dithering affects how colors that are higher precision than the device
914      * are down-sampled. No dithering is generally faster, but higher precision
915      * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
916      * distribute the error inherent in this process, to reduce the visual
917      * artifacts.
918      *
919      * @param dither true to set the dithering bit in flags, false to clear it
920      */
setDither(boolean dither)921     public void setDither(boolean dither) {
922         nSetDither(mNativePaint, dither);
923     }
924 
925     /**
926      * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
927      *
928      * @return true if the lineartext bit is set in the paint's flags
929      */
isLinearText()930     public final boolean isLinearText() {
931         return (getFlags() & LINEAR_TEXT_FLAG) != 0;
932     }
933 
934     /**
935      * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit
936      *
937      * @param linearText true to set the linearText bit in the paint's flags,
938      *                   false to clear it.
939      */
setLinearText(boolean linearText)940     public void setLinearText(boolean linearText) {
941         nSetLinearText(mNativePaint, linearText);
942     }
943 
944     /**
945      * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
946      *
947      * @return true if the subpixel bit is set in the paint's flags
948      */
isSubpixelText()949     public final boolean isSubpixelText() {
950         return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
951     }
952 
953     /**
954      * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
955      *
956      * @param subpixelText true to set the subpixelText bit in the paint's
957      *                     flags, false to clear it.
958      */
setSubpixelText(boolean subpixelText)959     public void setSubpixelText(boolean subpixelText) {
960         nSetSubpixelText(mNativePaint, subpixelText);
961     }
962 
963     /**
964      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
965      *
966      * @return true if the underlineText bit is set in the paint's flags.
967      * @see #getUnderlinePosition()
968      * @see #getUnderlineThickness()
969      * @see #setUnderlineText(boolean)
970      */
isUnderlineText()971     public final boolean isUnderlineText() {
972         return (getFlags() & UNDERLINE_TEXT_FLAG) != 0;
973     }
974 
975     /**
976      * Returns the distance from top of the underline to the baseline in pixels.
977      *
978      * The result is positive for positions that are below the baseline.
979      * This method returns where the underline should be drawn independent of if the {@link
980      * #UNDERLINE_TEXT_FLAG} bit is set.
981      *
982      * @return the position of the underline in pixels
983      * @see #isUnderlineText()
984      * @see #getUnderlineThickness()
985      * @see #setUnderlineText(boolean)
986      */
getUnderlinePosition()987     public @Px float getUnderlinePosition() {
988         return nGetUnderlinePosition(mNativePaint);
989     }
990 
991     /**
992      * Returns the thickness of the underline in pixels.
993      *
994      * @return the thickness of the underline in pixels
995      * @see #isUnderlineText()
996      * @see #getUnderlinePosition()
997      * @see #setUnderlineText(boolean)
998      */
getUnderlineThickness()999     public @Px float getUnderlineThickness() {
1000         return nGetUnderlineThickness(mNativePaint);
1001     }
1002 
1003     /**
1004      * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit
1005      *
1006      * @param underlineText true to set the underlineText bit in the paint's
1007      *                      flags, false to clear it.
1008      * @see #isUnderlineText()
1009      * @see #getUnderlinePosition()
1010      * @see #getUnderlineThickness()
1011      */
setUnderlineText(boolean underlineText)1012     public void setUnderlineText(boolean underlineText) {
1013         nSetUnderlineText(mNativePaint, underlineText);
1014     }
1015 
1016     /**
1017      * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
1018      *
1019      * @return true if the {@link #STRIKE_THRU_TEXT_FLAG} bit is set in the paint's flags.
1020      * @see #getStrikeThruPosition()
1021      * @see #getStrikeThruThickness()
1022      * @see #setStrikeThruText(boolean)
1023      */
isStrikeThruText()1024     public final boolean isStrikeThruText() {
1025         return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0;
1026     }
1027 
1028     /**
1029      * Distance from top of the strike-through line to the baseline in pixels.
1030      *
1031      * The result is negative for positions that are above the baseline.
1032      * This method returns where the strike-through line should be drawn independent of if the
1033      * {@link #STRIKE_THRU_TEXT_FLAG} bit is set.
1034      *
1035      * @return the position of the strike-through line in pixels
1036      * @see #getStrikeThruThickness()
1037      * @see #setStrikeThruText(boolean)
1038      * @see #isStrikeThruText()
1039      */
getStrikeThruPosition()1040     public @Px float getStrikeThruPosition() {
1041         return nGetStrikeThruPosition(mNativePaint);
1042     }
1043 
1044     /**
1045      * Returns the thickness of the strike-through line in pixels.
1046      *
1047      * @return the position of the strike-through line in pixels
1048      * @see #getStrikeThruPosition()
1049      * @see #setStrikeThruText(boolean)
1050      * @see #isStrikeThruText()
1051      */
getStrikeThruThickness()1052     public @Px float getStrikeThruThickness() {
1053         return nGetStrikeThruThickness(mNativePaint);
1054     }
1055 
1056     /**
1057      * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
1058      *
1059      * @param strikeThruText true to set the strikeThruText bit in the paint's
1060      *                       flags, false to clear it.
1061      * @see #getStrikeThruPosition()
1062      * @see #getStrikeThruThickness()
1063      * @see #isStrikeThruText()
1064      */
setStrikeThruText(boolean strikeThruText)1065     public void setStrikeThruText(boolean strikeThruText) {
1066         nSetStrikeThruText(mNativePaint, strikeThruText);
1067     }
1068 
1069     /**
1070      * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
1071      *
1072      * @return true if the fakeBoldText bit is set in the paint's flags.
1073      */
isFakeBoldText()1074     public final boolean isFakeBoldText() {
1075         return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0;
1076     }
1077 
1078     /**
1079      * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit
1080      *
1081      * @param fakeBoldText true to set the fakeBoldText bit in the paint's
1082      *                     flags, false to clear it.
1083      */
setFakeBoldText(boolean fakeBoldText)1084     public void setFakeBoldText(boolean fakeBoldText) {
1085         nSetFakeBoldText(mNativePaint, fakeBoldText);
1086     }
1087 
1088     /**
1089      * Whether or not the bitmap filter is activated.
1090      * Filtering affects the sampling of bitmaps when they are transformed.
1091      * Filtering does not affect how the colors in the bitmap are converted into
1092      * device pixels. That is dependent on dithering and xfermodes.
1093      *
1094      * @see #setFilterBitmap(boolean) setFilterBitmap()
1095      * @see #FILTER_BITMAP_FLAG
1096      */
isFilterBitmap()1097     public final boolean isFilterBitmap() {
1098         return (getFlags() & FILTER_BITMAP_FLAG) != 0;
1099     }
1100 
1101     /**
1102      * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
1103      * Filtering affects the sampling of bitmaps when they are transformed.
1104      * Filtering does not affect how the colors in the bitmap are converted into
1105      * device pixels. That is dependent on dithering and xfermodes.
1106      *
1107      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
1108      *               flags, false to clear it.
1109      * @see #FILTER_BITMAP_FLAG
1110      */
setFilterBitmap(boolean filter)1111     public void setFilterBitmap(boolean filter) {
1112         nSetFilterBitmap(mNativePaint, filter);
1113     }
1114 
1115     /**
1116      * Return the paint's style, used for controlling how primitives'
1117      * geometries are interpreted (except for drawBitmap, which always assumes
1118      * FILL_STYLE).
1119      *
1120      * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
1121      */
getStyle()1122     public Style getStyle() {
1123         return sStyleArray[nGetStyle(mNativePaint)];
1124     }
1125 
1126     /**
1127      * Set the paint's style, used for controlling how primitives'
1128      * geometries are interpreted (except for drawBitmap, which always assumes
1129      * Fill).
1130      *
1131      * @param style The new style to set in the paint
1132      */
setStyle(Style style)1133     public void setStyle(Style style) {
1134         nSetStyle(mNativePaint, style.nativeInt);
1135     }
1136 
1137     /**
1138      * Return the paint's color in sRGB. Note that the color is a 32bit value
1139      * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
1140      * meaning that its alpha can be any value, regardless of the values of
1141      * r,g,b. See the Color class for more details.
1142      *
1143      * @return the paint's color (and alpha).
1144      */
1145     @ColorInt
getColor()1146     public int getColor() {
1147         return Color.toArgb(mColor);
1148     }
1149 
1150     /**
1151      * Return the paint's color. Note that the color is a long with an encoded
1152      * {@link ColorSpace} as well as alpha and r,g,b. These values are not
1153      * premultiplied, meaning that alpha can be any value, regardless of the
1154      * values of r,g,b. See the {@link Color} class for more details.
1155      *
1156      * @return the paint's color, alpha, and {@code ColorSpace} encoded as a
1157      *      {@code ColorLong}
1158      */
1159     @ColorLong
getColorLong()1160     public long getColorLong() {
1161         return mColor;
1162     }
1163 
1164     /**
1165      * Set the paint's color. Note that the color is an int containing alpha
1166      * as well as r,g,b. This 32bit value is not premultiplied, meaning that
1167      * its alpha can be any value, regardless of the values of r,g,b.
1168      * See the Color class for more details.
1169      *
1170      * @param color The new color (including alpha) to set in the paint.
1171      */
setColor(@olorInt int color)1172     public void setColor(@ColorInt int color) {
1173         nSetColor(mNativePaint, color);
1174         mColor = Color.pack(color);
1175     }
1176 
1177     /**
1178      * Set the paint's color with a {@code ColorLong}. Note that the color is
1179      * a long with an encoded {@link ColorSpace} as well as alpha and r,g,b.
1180      * These values are not premultiplied, meaning that alpha can be any value,
1181      * regardless of the values of r,g,b. See the {@link Color} class for more
1182      * details.
1183      *
1184      * @param color The new color (including alpha and {@link ColorSpace})
1185      *      to set in the paint.
1186      * @throws IllegalArgumentException if the color space encoded in the
1187      *      {@code ColorLong} is invalid or unknown.
1188      */
setColor(@olorLong long color)1189     public void setColor(@ColorLong long color) {
1190         ColorSpace cs = Color.colorSpace(color);
1191 
1192         nSetColor(mNativePaint, cs.getNativeInstance(), color);
1193         mColor = color;
1194     }
1195 
1196     /**
1197      * Helper to getColor() that just returns the color's alpha value. This is
1198      * the same as calling getColor() >>> 24. It always returns a value between
1199      * 0 (completely transparent) and 255 (completely opaque).
1200      *
1201      * @return the alpha component of the paint's color.
1202      */
getAlpha()1203     public int getAlpha() {
1204         return Math.round(Color.alpha(mColor) * 255.0f);
1205     }
1206 
1207     /**
1208      * Helper to setColor(), that only assigns the color's alpha value,
1209      * leaving its r,g,b values unchanged. Results are undefined if the alpha
1210      * value is outside of the range [0..255]
1211      *
1212      * @param a set the alpha component [0..255] of the paint's color.
1213      */
setAlpha(int a)1214     public void setAlpha(int a) {
1215         // FIXME: No need to unpack this. Instead, just update the alpha bits.
1216         // b/122959599
1217         ColorSpace cs = Color.colorSpace(mColor);
1218         float r = Color.red(mColor);
1219         float g = Color.green(mColor);
1220         float b = Color.blue(mColor);
1221         mColor = Color.pack(r, g, b, a * (1.0f / 255), cs);
1222         nSetAlpha(mNativePaint, a);
1223     }
1224 
1225     /**
1226      * Helper to setColor(), that takes a,r,g,b and constructs the color int
1227      *
1228      * @param a The new alpha component (0..255) of the paint's color.
1229      * @param r The new red component (0..255) of the paint's color.
1230      * @param g The new green component (0..255) of the paint's color.
1231      * @param b The new blue component (0..255) of the paint's color.
1232      */
setARGB(int a, int r, int g, int b)1233     public void setARGB(int a, int r, int g, int b) {
1234         setColor((a << 24) | (r << 16) | (g << 8) | b);
1235     }
1236 
1237     /**
1238      * Return the width for stroking.
1239      * <p />
1240      * A value of 0 strokes in hairline mode.
1241      * Hairlines always draws a single pixel independent of the canvas's matrix.
1242      *
1243      * @return the paint's stroke width, used whenever the paint's style is
1244      *         Stroke or StrokeAndFill.
1245      */
getStrokeWidth()1246     public float getStrokeWidth() {
1247         return nGetStrokeWidth(mNativePaint);
1248     }
1249 
1250     /**
1251      * Set the width for stroking.
1252      * Pass 0 to stroke in hairline mode.
1253      * Hairlines always draws a single pixel independent of the canvas's matrix.
1254      *
1255      * @param width set the paint's stroke width, used whenever the paint's
1256      *              style is Stroke or StrokeAndFill.
1257      */
setStrokeWidth(float width)1258     public void setStrokeWidth(float width) {
1259         nSetStrokeWidth(mNativePaint, width);
1260     }
1261 
1262     /**
1263      * Return the paint's stroke miter value. Used to control the behavior
1264      * of miter joins when the joins angle is sharp.
1265      *
1266      * @return the paint's miter limit, used whenever the paint's style is
1267      *         Stroke or StrokeAndFill.
1268      */
getStrokeMiter()1269     public float getStrokeMiter() {
1270         return nGetStrokeMiter(mNativePaint);
1271     }
1272 
1273     /**
1274      * Set the paint's stroke miter value. This is used to control the behavior
1275      * of miter joins when the joins angle is sharp. This value must be >= 0.
1276      *
1277      * @param miter set the miter limit on the paint, used whenever the paint's
1278      *              style is Stroke or StrokeAndFill.
1279      */
setStrokeMiter(float miter)1280     public void setStrokeMiter(float miter) {
1281         nSetStrokeMiter(mNativePaint, miter);
1282     }
1283 
1284     /**
1285      * Return the paint's Cap, controlling how the start and end of stroked
1286      * lines and paths are treated.
1287      *
1288      * @return the line cap style for the paint, used whenever the paint's
1289      *         style is Stroke or StrokeAndFill.
1290      */
getStrokeCap()1291     public Cap getStrokeCap() {
1292         return sCapArray[nGetStrokeCap(mNativePaint)];
1293     }
1294 
1295     /**
1296      * Set the paint's Cap.
1297      *
1298      * @param cap set the paint's line cap style, used whenever the paint's
1299      *            style is Stroke or StrokeAndFill.
1300      */
setStrokeCap(Cap cap)1301     public void setStrokeCap(Cap cap) {
1302         nSetStrokeCap(mNativePaint, cap.nativeInt);
1303     }
1304 
1305     /**
1306      * Return the paint's stroke join type.
1307      *
1308      * @return the paint's Join.
1309      */
getStrokeJoin()1310     public Join getStrokeJoin() {
1311         return sJoinArray[nGetStrokeJoin(mNativePaint)];
1312     }
1313 
1314     /**
1315      * Set the paint's Join.
1316      *
1317      * @param join set the paint's Join, used whenever the paint's style is
1318      *             Stroke or StrokeAndFill.
1319      */
setStrokeJoin(Join join)1320     public void setStrokeJoin(Join join) {
1321         nSetStrokeJoin(mNativePaint, join.nativeInt);
1322     }
1323 
1324     /**
1325      * Applies any/all effects (patheffect, stroking) to src, returning the
1326      * result in dst. The result is that drawing src with this paint will be
1327      * the same as drawing dst with a default paint (at least from the
1328      * geometric perspective).
1329      *
1330      * @param src input path
1331      * @param dst output path (may be the same as src)
1332      * @return    true if the path should be filled, or false if it should be
1333      *                 drawn with a hairline (width == 0)
1334      */
getFillPath(Path src, Path dst)1335     public boolean getFillPath(Path src, Path dst) {
1336         return nGetFillPath(mNativePaint, src.readOnlyNI(), dst.mutateNI());
1337     }
1338 
1339     /**
1340      * Get the paint's shader object.
1341      *
1342      * @return the paint's shader (or null)
1343      */
getShader()1344     public Shader getShader() {
1345         return mShader;
1346     }
1347 
1348     /**
1349      * Set or clear the shader object.
1350      * <p />
1351      * Pass null to clear any previous shader.
1352      * As a convenience, the parameter passed is also returned.
1353      *
1354      * @param shader May be null. the new shader to be installed in the paint
1355      * @return       shader
1356      */
setShader(Shader shader)1357     public Shader setShader(Shader shader) {
1358         // If mShader changes, cached value of native shader aren't valid, since
1359         // old shader's pointer may be reused by another shader allocation later
1360         if (mShader != shader) {
1361             mNativeShader = -1;
1362             // Release any native references to the old shader content
1363             nSetShader(mNativePaint, 0);
1364         }
1365         // Defer setting the shader natively until getNativeInstance() is called
1366         mShader = shader;
1367         return shader;
1368     }
1369 
1370     /**
1371      * Get the paint's colorfilter (maybe be null).
1372      *
1373      * @return the paint's colorfilter (maybe be null)
1374      */
getColorFilter()1375     public ColorFilter getColorFilter() {
1376         return mColorFilter;
1377     }
1378 
1379     /**
1380      * Set or clear the paint's colorfilter, returning the parameter.
1381      *
1382      * @param filter May be null. The new filter to be installed in the paint
1383      * @return       filter
1384      */
setColorFilter(ColorFilter filter)1385     public ColorFilter setColorFilter(ColorFilter filter) {
1386         // If mColorFilter changes, cached value of native shader aren't valid, since
1387         // old shader's pointer may be reused by another shader allocation later
1388         if (mColorFilter != filter) {
1389             mNativeColorFilter = -1;
1390         }
1391 
1392         // Defer setting the filter natively until getNativeInstance() is called
1393         mColorFilter = filter;
1394         return filter;
1395     }
1396 
1397     /**
1398      * Get the paint's transfer mode object.
1399      *
1400      * @return the paint's transfer mode (or null)
1401      */
getXfermode()1402     public Xfermode getXfermode() {
1403         return mXfermode;
1404     }
1405 
1406     /**
1407      * Get the paint's blend mode object.
1408      *
1409      * @return the paint's blend mode (or null)
1410      */
1411     @Nullable
getBlendMode()1412     public BlendMode getBlendMode() {
1413         if (mXfermode == null) {
1414             return null;
1415         } else {
1416             return BlendMode.fromValue(mXfermode.porterDuffMode);
1417         }
1418     }
1419 
1420     /**
1421      * Set or clear the transfer mode object. A transfer mode defines how
1422      * source pixels (generate by a drawing command) are composited with
1423      * the destination pixels (content of the render target).
1424      * <p />
1425      * Pass null to clear any previous transfer mode.
1426      * As a convenience, the parameter passed is also returned.
1427      * <p />
1428      * {@link PorterDuffXfermode} is the most common transfer mode.
1429      *
1430      * @param xfermode May be null. The xfermode to be installed in the paint
1431      * @return         xfermode
1432      */
setXfermode(Xfermode xfermode)1433     public Xfermode setXfermode(Xfermode xfermode) {
1434         return installXfermode(xfermode);
1435     }
1436 
1437     @Nullable
installXfermode(Xfermode xfermode)1438     private Xfermode installXfermode(Xfermode xfermode) {
1439         int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT;
1440         int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT;
1441         if (newMode != curMode) {
1442             nSetXfermode(mNativePaint, newMode);
1443         }
1444         mXfermode = xfermode;
1445         return xfermode;
1446     }
1447 
1448     /**
1449      * Set or clear the blend mode. A blend mode defines how source pixels
1450      * (generated by a drawing command) are composited with the destination pixels
1451      * (content of the render target).
1452      * <p />
1453      * Pass null to clear any previous blend mode.
1454      * <p />
1455      *
1456      * @see BlendMode
1457      *
1458      * @param blendmode May be null. The blend mode to be installed in the paint
1459      */
setBlendMode(@ullable BlendMode blendmode)1460     public void setBlendMode(@Nullable BlendMode blendmode) {
1461         installXfermode(blendmode != null ? blendmode.getXfermode() : null);
1462     }
1463 
1464     /**
1465      * Get the paint's patheffect object.
1466      *
1467      * @return the paint's patheffect (or null)
1468      */
getPathEffect()1469     public PathEffect getPathEffect() {
1470         return mPathEffect;
1471     }
1472 
1473     /**
1474      * Set or clear the patheffect object.
1475      * <p />
1476      * Pass null to clear any previous patheffect.
1477      * As a convenience, the parameter passed is also returned.
1478      *
1479      * @param effect May be null. The patheffect to be installed in the paint
1480      * @return       effect
1481      */
setPathEffect(PathEffect effect)1482     public PathEffect setPathEffect(PathEffect effect) {
1483         long effectNative = 0;
1484         if (effect != null) {
1485             effectNative = effect.native_instance;
1486         }
1487         nSetPathEffect(mNativePaint, effectNative);
1488         mPathEffect = effect;
1489         return effect;
1490     }
1491 
1492     /**
1493      * Get the paint's maskfilter object.
1494      *
1495      * @return the paint's maskfilter (or null)
1496      */
getMaskFilter()1497     public MaskFilter getMaskFilter() {
1498         return mMaskFilter;
1499     }
1500 
1501     /**
1502      * Set or clear the maskfilter object.
1503      * <p />
1504      * Pass null to clear any previous maskfilter.
1505      * As a convenience, the parameter passed is also returned.
1506      *
1507      * @param maskfilter May be null. The maskfilter to be installed in the
1508      *                   paint
1509      * @return           maskfilter
1510      */
setMaskFilter(MaskFilter maskfilter)1511     public MaskFilter setMaskFilter(MaskFilter maskfilter) {
1512         long maskfilterNative = 0;
1513         if (maskfilter != null) {
1514             maskfilterNative = maskfilter.native_instance;
1515         }
1516         nSetMaskFilter(mNativePaint, maskfilterNative);
1517         mMaskFilter = maskfilter;
1518         return maskfilter;
1519     }
1520 
1521     /**
1522      * Get the paint's typeface object.
1523      * <p />
1524      * The typeface object identifies which font to use when drawing or
1525      * measuring text.
1526      *
1527      * @return the paint's typeface (or null)
1528      */
getTypeface()1529     public Typeface getTypeface() {
1530         return mTypeface;
1531     }
1532 
1533     /**
1534      * Set or clear the typeface object.
1535      * <p />
1536      * Pass null to clear any previous typeface.
1537      * As a convenience, the parameter passed is also returned.
1538      *
1539      * @param typeface May be null. The typeface to be installed in the paint
1540      * @return         typeface
1541      */
setTypeface(Typeface typeface)1542     public Typeface setTypeface(Typeface typeface) {
1543         final long typefaceNative = typeface == null ? 0 : typeface.native_instance;
1544         nSetTypeface(mNativePaint, typefaceNative);
1545         mTypeface = typeface;
1546         return typeface;
1547     }
1548 
1549     /**
1550      * Get the paint's rasterizer (or null).
1551      * <p />
1552      * The raster controls/modifies how paths/text are turned into alpha masks.
1553      *
1554      * @return         the paint's rasterizer (or null)
1555      *
1556      * @deprecated Rasterizer is not supported by either the HW or PDF backends.
1557      * @removed
1558      */
1559     @Deprecated
getRasterizer()1560     public Rasterizer getRasterizer() {
1561         return null;
1562     }
1563 
1564     /**
1565      * Set or clear the rasterizer object.
1566      * <p />
1567      * Pass null to clear any previous rasterizer.
1568      * As a convenience, the parameter passed is also returned.
1569      *
1570      * @param rasterizer May be null. The new rasterizer to be installed in
1571      *                   the paint.
1572      * @return           rasterizer
1573      *
1574      * @deprecated Rasterizer is not supported by either the HW or PDF backends.
1575      * @removed
1576      */
1577     @Deprecated
setRasterizer(Rasterizer rasterizer)1578     public Rasterizer setRasterizer(Rasterizer rasterizer) {
1579         return rasterizer;
1580     }
1581 
1582     /**
1583      * This draws a shadow layer below the main layer, with the specified
1584      * offset and color, and blur radius. If radius is 0, then the shadow
1585      * layer is removed.
1586      * <p>
1587      * Can be used to create a blurred shadow underneath text. Support for use
1588      * with other drawing operations is constrained to the software rendering
1589      * pipeline.
1590      * <p>
1591      * The alpha of the shadow will be the paint's alpha if the shadow color is
1592      * opaque, or the alpha from the shadow color if not.
1593      */
setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor)1594     public void setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor) {
1595         setShadowLayer(radius, dx, dy, Color.pack(shadowColor));
1596     }
1597 
1598     /**
1599      * This draws a shadow layer below the main layer, with the specified
1600      * offset and color, and blur radius. If radius is 0, then the shadow
1601      * layer is removed.
1602      * <p>
1603      * Can be used to create a blurred shadow underneath text. Support for use
1604      * with other drawing operations is constrained to the software rendering
1605      * pipeline.
1606      * <p>
1607      * The alpha of the shadow will be the paint's alpha if the shadow color is
1608      * opaque, or the alpha from the shadow color if not.
1609      *
1610      * @throws IllegalArgumentException if the color space encoded in the
1611      *      {@code ColorLong} is invalid or unknown.
1612      */
setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor)1613     public void setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor) {
1614         ColorSpace cs = Color.colorSpace(shadowColor);
1615         nSetShadowLayer(mNativePaint, radius, dx, dy, cs.getNativeInstance(), shadowColor);
1616 
1617         mShadowLayerRadius = radius;
1618         mShadowLayerDx = dx;
1619         mShadowLayerDy = dy;
1620         mShadowLayerColor = shadowColor;
1621     }
1622 
1623     /**
1624      * Clear the shadow layer.
1625      */
clearShadowLayer()1626     public void clearShadowLayer() {
1627         setShadowLayer(0, 0, 0, 0);
1628     }
1629 
1630     /**
1631      * Checks if the paint has a shadow layer attached
1632      *
1633      * @return true if the paint has a shadow layer attached and false otherwise
1634      * @hide
1635      */
hasShadowLayer()1636     public boolean hasShadowLayer() {
1637         return nHasShadowLayer(mNativePaint);
1638     }
1639 
1640     /**
1641      * Returns the blur radius of the shadow layer.
1642      * @see #setShadowLayer(float,float,float,int)
1643      * @see #setShadowLayer(float,float,float,long)
1644      */
getShadowLayerRadius()1645     public float getShadowLayerRadius() {
1646         return mShadowLayerRadius;
1647     }
1648 
1649     /**
1650      * Returns the x offset of the shadow layer.
1651      * @see #setShadowLayer(float,float,float,int)
1652      * @see #setShadowLayer(float,float,float,long)
1653      */
getShadowLayerDx()1654     public float getShadowLayerDx() {
1655         return mShadowLayerDx;
1656     }
1657 
1658     /**
1659      * Returns the y offset of the shadow layer.
1660      * @see #setShadowLayer(float,float,float,int)
1661      * @see #setShadowLayer(float,float,float,long)
1662      */
getShadowLayerDy()1663     public float getShadowLayerDy() {
1664         return mShadowLayerDy;
1665     }
1666 
1667     /**
1668      * Returns the color of the shadow layer.
1669      * @see #setShadowLayer(float,float,float,int)
1670      * @see #setShadowLayer(float,float,float,long)
1671      */
getShadowLayerColor()1672     public @ColorInt int getShadowLayerColor() {
1673         return Color.toArgb(mShadowLayerColor);
1674     }
1675 
1676     /**
1677      * Returns the color of the shadow layer.
1678      *
1679      * @return the shadow layer's color encoded as a {@code ColorLong}.
1680      * @see #setShadowLayer(float,float,float,int)
1681      * @see #setShadowLayer(float,float,float,long)
1682      * @see Color
1683      */
getShadowLayerColorLong()1684     public @ColorLong long getShadowLayerColorLong() {
1685         return mShadowLayerColor;
1686     }
1687 
1688     /**
1689      * Return the paint's Align value for drawing text. This controls how the
1690      * text is positioned relative to its origin. LEFT align means that all of
1691      * the text will be drawn to the right of its origin (i.e. the origin
1692      * specifies the LEFT edge of the text) and so on.
1693      *
1694      * @return the paint's Align value for drawing text.
1695      */
getTextAlign()1696     public Align getTextAlign() {
1697         return sAlignArray[nGetTextAlign(mNativePaint)];
1698     }
1699 
1700     /**
1701      * Set the paint's text alignment. This controls how the
1702      * text is positioned relative to its origin. LEFT align means that all of
1703      * the text will be drawn to the right of its origin (i.e. the origin
1704      * specifies the LEFT edge of the text) and so on.
1705      *
1706      * @param align set the paint's Align value for drawing text.
1707      */
setTextAlign(Align align)1708     public void setTextAlign(Align align) {
1709         nSetTextAlign(mNativePaint, align.nativeInt);
1710     }
1711 
1712     /**
1713      * Get the text's primary Locale. Note that this is not all of the locale-related information
1714      * Paint has. Use {@link #getTextLocales()} to get the complete list.
1715      *
1716      * @return the paint's primary Locale used for drawing text, never null.
1717      */
1718     @NonNull
getTextLocale()1719     public Locale getTextLocale() {
1720         return mLocales.get(0);
1721     }
1722 
1723     /**
1724      * Get the text locale list.
1725      *
1726      * @return the paint's LocaleList used for drawing text, never null or empty.
1727      */
1728     @NonNull @Size(min=1)
getTextLocales()1729     public LocaleList getTextLocales() {
1730         return mLocales;
1731     }
1732 
1733     /**
1734      * Set the text locale list to a one-member list consisting of just the locale.
1735      *
1736      * See {@link #setTextLocales(LocaleList)} for how the locale list affects
1737      * the way the text is drawn for some languages.
1738      *
1739      * @param locale the paint's locale value for drawing text, must not be null.
1740      */
setTextLocale(@onNull Locale locale)1741     public void setTextLocale(@NonNull Locale locale) {
1742         if (locale == null) {
1743             throw new IllegalArgumentException("locale cannot be null");
1744         }
1745         if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.get(0))) {
1746             return;
1747         }
1748         mLocales = new LocaleList(locale);
1749         syncTextLocalesWithMinikin();
1750     }
1751 
1752     /**
1753      * Set the text locale list.
1754      *
1755      * The text locale list affects how the text is drawn for some languages.
1756      *
1757      * For example, if the locale list contains {@link Locale#CHINESE} or {@link Locale#CHINA},
1758      * then the text renderer will prefer to draw text using a Chinese font. Likewise,
1759      * if the locale list contains {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
1760      * renderer will prefer to draw text using a Japanese font. If the locale list contains both,
1761      * the order those locales appear in the list is considered for deciding the font.
1762      *
1763      * This distinction is important because Chinese and Japanese text both use many
1764      * of the same Unicode code points but their appearance is subtly different for
1765      * each language.
1766      *
1767      * By default, the text locale list is initialized to a one-member list just containing the
1768      * system locales. This assumes that the text to be rendered will most likely be in the user's
1769      * preferred language.
1770      *
1771      * If the actual language or languages of the text is/are known, then they can be provided to
1772      * the text renderer using this method. The text renderer may attempt to guess the
1773      * language script based on the contents of the text to be drawn independent of
1774      * the text locale here. Specifying the text locales just helps it do a better
1775      * job in certain ambiguous cases.
1776      *
1777      * @param locales the paint's locale list for drawing text, must not be null or empty.
1778      */
setTextLocales(@onNull @izemin=1) LocaleList locales)1779     public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
1780         if (locales == null || locales.isEmpty()) {
1781             throw new IllegalArgumentException("locales cannot be null or empty");
1782         }
1783         if (locales.equals(mLocales)) return;
1784         mLocales = locales;
1785         syncTextLocalesWithMinikin();
1786     }
1787 
syncTextLocalesWithMinikin()1788     private void syncTextLocalesWithMinikin() {
1789         final String languageTags = mLocales.toLanguageTags();
1790         final Integer minikinLocaleListId;
1791         synchronized (sCacheLock) {
1792             minikinLocaleListId = sMinikinLocaleListIdCache.get(languageTags);
1793             if (minikinLocaleListId == null) {
1794                 final int newID = nSetTextLocales(mNativePaint, languageTags);
1795                 sMinikinLocaleListIdCache.put(languageTags, newID);
1796                 return;
1797             }
1798         }
1799         nSetTextLocalesByMinikinLocaleListId(mNativePaint, minikinLocaleListId.intValue());
1800     }
1801 
1802     /**
1803      * Get the elegant metrics flag.
1804      *
1805      * @return true if elegant metrics are enabled for text drawing.
1806      */
isElegantTextHeight()1807     public boolean isElegantTextHeight() {
1808         int rawValue = nGetElegantTextHeight(mNativePaint);
1809         switch (rawValue) {
1810             case ELEGANT_TEXT_HEIGHT_DISABLED:
1811                 return false;
1812             case ELEGANT_TEXT_HEIGHT_ENABLED:
1813                 return true;
1814             case ELEGANT_TEXT_HEIGHT_UNSET:
1815             default:
1816                 return com.android.text.flags.Flags.deprecateUiFonts();
1817         }
1818     }
1819 
1820     // Note: the following three values must be equal to the ones in the JNI file: Paint.cpp
1821     private static final int ELEGANT_TEXT_HEIGHT_UNSET = -1;
1822     private static final int ELEGANT_TEXT_HEIGHT_ENABLED = 0;
1823     private static final int ELEGANT_TEXT_HEIGHT_DISABLED = 1;
1824 
1825     /**
1826      * Set the paint's elegant height metrics flag. This setting selects font
1827      * variants that have not been compacted to fit Latin-based vertical
1828      * metrics, and also increases top and bottom bounds to provide more space.
1829      *
1830      * @param elegant set the paint's elegant metrics flag for drawing text.
1831      */
setElegantTextHeight(boolean elegant)1832     public void setElegantTextHeight(boolean elegant) {
1833         nSetElegantTextHeight(mNativePaint,
1834                 elegant ? ELEGANT_TEXT_HEIGHT_ENABLED : ELEGANT_TEXT_HEIGHT_DISABLED);
1835     }
1836 
1837     /**
1838      * A change ID for deprecating UI fonts.
1839      *
1840      * From API {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the default value will be true by
1841      * default if the app has a target SDK of API {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} or
1842      * later.
1843      *
1844      * @hide
1845      */
1846     @ChangeId
1847     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
1848     public static final long DEPRECATE_UI_FONT = 279646685L;
1849 
resetElegantTextHeight()1850     private void resetElegantTextHeight() {
1851         if (CompatChanges.isChangeEnabled(DEPRECATE_UI_FONT)) {
1852             nSetElegantTextHeight(mNativePaint, ELEGANT_TEXT_HEIGHT_UNSET);
1853         } else {
1854             nSetElegantTextHeight(mNativePaint, ELEGANT_TEXT_HEIGHT_DISABLED);
1855         }
1856     }
1857 
1858     /**
1859      * Return the paint's text size.
1860      *
1861      * @return the paint's text size in pixel units.
1862      */
getTextSize()1863     public float getTextSize() {
1864         return nGetTextSize(mNativePaint);
1865     }
1866 
1867     /**
1868      * Set the paint's text size. This value must be > 0
1869      *
1870      * @param textSize set the paint's text size in pixel units.
1871      */
setTextSize(float textSize)1872     public void setTextSize(float textSize) {
1873         nSetTextSize(mNativePaint, textSize);
1874     }
1875 
1876     /**
1877      * Return the paint's horizontal scale factor for text. The default value
1878      * is 1.0.
1879      *
1880      * @return the paint's scale factor in X for drawing/measuring text
1881      */
getTextScaleX()1882     public float getTextScaleX() {
1883         return nGetTextScaleX(mNativePaint);
1884     }
1885 
1886     /**
1887      * Set the paint's horizontal scale factor for text. The default value
1888      * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
1889      * stretch the text narrower.
1890      *
1891      * @param scaleX set the paint's scale in X for drawing/measuring text.
1892      */
setTextScaleX(float scaleX)1893     public void setTextScaleX(float scaleX) {
1894         nSetTextScaleX(mNativePaint, scaleX);
1895     }
1896 
1897     /**
1898      * Return the paint's horizontal skew factor for text. The default value
1899      * is 0.
1900      *
1901      * @return         the paint's skew factor in X for drawing text.
1902      */
getTextSkewX()1903     public float getTextSkewX() {
1904         return nGetTextSkewX(mNativePaint);
1905     }
1906 
1907     /**
1908      * Set the paint's horizontal skew factor for text. The default value
1909      * is 0. For approximating oblique text, use values around -0.25.
1910      *
1911      * @param skewX set the paint's skew factor in X for drawing text.
1912      */
setTextSkewX(float skewX)1913     public void setTextSkewX(float skewX) {
1914         nSetTextSkewX(mNativePaint, skewX);
1915     }
1916 
1917     /**
1918      * Return the paint's letter-spacing for text. The default value
1919      * is 0.
1920      *
1921      * @return         the paint's letter-spacing for drawing text.
1922      */
getLetterSpacing()1923     public float getLetterSpacing() {
1924         return nGetLetterSpacing(mNativePaint);
1925     }
1926 
1927     /**
1928      * Set the paint's letter-spacing for text. The default value
1929      * is 0.  The value is in 'EM' units.  Typical values for slight
1930      * expansion will be around 0.05.  Negative values tighten text.
1931      *
1932      * @param letterSpacing set the paint's letter-spacing for drawing text.
1933      */
setLetterSpacing(float letterSpacing)1934     public void setLetterSpacing(float letterSpacing) {
1935         nSetLetterSpacing(mNativePaint, letterSpacing);
1936     }
1937 
1938     /**
1939      * Return the paint's extra word-spacing for text.
1940      *
1941      * The default value is 0.
1942      *
1943      * @return the paint's extra word-spacing for drawing text in pixels.
1944      * @see #setWordSpacing(float)
1945      */
getWordSpacing()1946     public @Px float getWordSpacing() {
1947         return nGetWordSpacing(mNativePaint);
1948     }
1949 
1950     /**
1951      * Set the paint's extra word-spacing for text.
1952      *
1953      * Increases the white space width between words with the given amount of pixels.
1954      * The default value is 0.
1955      *
1956      * @param wordSpacing set the paint's extra word-spacing for drawing text in pixels.
1957      * @see #getWordSpacing()
1958      */
setWordSpacing(@x float wordSpacing)1959     public void setWordSpacing(@Px float wordSpacing) {
1960         nSetWordSpacing(mNativePaint, wordSpacing);
1961     }
1962 
1963     /**
1964      * Returns the font feature settings. The format is the same as the CSS
1965      * font-feature-settings attribute:
1966      * <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
1967      *     https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop</a>
1968      *
1969      * @return the paint's currently set font feature settings. Default is null.
1970      *
1971      * @see #setFontFeatureSettings(String)
1972      */
getFontFeatureSettings()1973     public String getFontFeatureSettings() {
1974         return mFontFeatureSettings;
1975     }
1976 
1977     /**
1978      * Set font feature settings.
1979      *
1980      * The format is the same as the CSS font-feature-settings attribute:
1981      * <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
1982      *     https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop</a>
1983      *
1984      * @see #getFontFeatureSettings()
1985      *
1986      * @param settings the font feature settings string to use, may be null.
1987      */
setFontFeatureSettings(String settings)1988     public void setFontFeatureSettings(String settings) {
1989         if (settings != null && settings.equals("")) {
1990             settings = null;
1991         }
1992         if ((settings == null && mFontFeatureSettings == null)
1993                 || (settings != null && settings.equals(mFontFeatureSettings))) {
1994             return;
1995         }
1996         mFontFeatureSettings = settings;
1997         nSetFontFeatureSettings(mNativePaint, settings);
1998     }
1999 
2000     /**
2001      * Returns the font variation settings.
2002      *
2003      * @return the paint's currently set font variation settings. Default is null.
2004      *
2005      * @see #setFontVariationSettings(String)
2006      */
getFontVariationSettings()2007     public String getFontVariationSettings() {
2008         return mFontVariationSettings;
2009     }
2010 
2011     /**
2012      * Sets TrueType or OpenType font variation settings. The settings string is constructed from
2013      * multiple pairs of axis tag and style values. The axis tag must contain four ASCII characters
2014      * and must be wrapped with single quotes (U+0027) or double quotes (U+0022). Axis strings that
2015      * are longer or shorter than four characters, or contain characters outside of U+0020..U+007E
2016      * are invalid. If a specified axis name is not defined in the font, the settings will be
2017      * ignored.
2018      *
2019      * Examples,
2020      * <ul>
2021      * <li>Set font width to 150.
2022      * <pre>
2023      * <code>
2024      *   Paint paint = new Paint();
2025      *   paint.setFontVariationSettings("'wdth' 150");
2026      * </code>
2027      * </pre>
2028      * </li>
2029      *
2030      * <li>Set the font slant to 20 degrees and ask for italic style.
2031      * <pre>
2032      * <code>
2033      *   Paint paint = new Paint();
2034      *   paint.setFontVariationSettings("'slnt' 20, 'ital' 1");
2035      * </code>
2036      * </pre>
2037      * </li>
2038      * </ul>
2039      *
2040      * @param fontVariationSettings font variation settings. You can pass null or empty string as
2041      *                              no variation settings.
2042      *
2043      * @return true if the given settings is effective to at least one font file underlying this
2044      *         typeface. This function also returns true for empty settings string. Otherwise
2045      *         returns false
2046      *
2047      * @throws IllegalArgumentException If given string is not a valid font variation settings
2048      *                                  format
2049      *
2050      * @see #getFontVariationSettings()
2051      * @see FontVariationAxis
2052      */
setFontVariationSettings(String fontVariationSettings)2053     public boolean setFontVariationSettings(String fontVariationSettings) {
2054         final String settings = TextUtils.nullIfEmpty(fontVariationSettings);
2055         if (settings == mFontVariationSettings
2056                 || (settings != null && settings.equals(mFontVariationSettings))) {
2057             return true;
2058         }
2059 
2060         if (settings == null || settings.length() == 0) {
2061             mFontVariationSettings = null;
2062             setTypeface(Typeface.createFromTypefaceWithVariation(mTypeface,
2063                       Collections.emptyList()));
2064             return true;
2065         }
2066 
2067         // The null typeface is valid and it is equivalent to Typeface.DEFAULT.
2068         // To call isSupportedAxes method, use Typeface.DEFAULT instance.
2069         Typeface targetTypeface = mTypeface == null ? Typeface.DEFAULT : mTypeface;
2070         FontVariationAxis[] axes = FontVariationAxis.fromFontVariationSettings(settings);
2071         final ArrayList<FontVariationAxis> filteredAxes = new ArrayList<FontVariationAxis>();
2072         for (final FontVariationAxis axis : axes) {
2073             if (targetTypeface.isSupportedAxes(axis.getOpenTypeTagValue())) {
2074                 filteredAxes.add(axis);
2075             }
2076         }
2077         if (filteredAxes.isEmpty()) {
2078             return false;
2079         }
2080         mFontVariationSettings = settings;
2081         setTypeface(Typeface.createFromTypefaceWithVariation(targetTypeface, filteredAxes));
2082         return true;
2083     }
2084 
2085     /**
2086      * Get the current value of start hyphen edit.
2087      *
2088      * The default value is 0 which is equivalent to {@link #START_HYPHEN_EDIT_NO_EDIT}.
2089      *
2090      * @return the current starting hyphen edit value
2091      * @see #setStartHyphenEdit(int)
2092      */
getStartHyphenEdit()2093     public @StartHyphenEdit int getStartHyphenEdit() {
2094         return nGetStartHyphenEdit(mNativePaint);
2095     }
2096 
2097     /**
2098      * Get the current value of end hyphen edit.
2099      *
2100      * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}.
2101      *
2102      * @return the current starting hyphen edit value
2103      * @see #setStartHyphenEdit(int)
2104      */
getEndHyphenEdit()2105     public @EndHyphenEdit int getEndHyphenEdit() {
2106         return nGetEndHyphenEdit(mNativePaint);
2107     }
2108 
2109     /**
2110      * Set a start hyphen edit on the paint.
2111      *
2112      * By setting start hyphen edit, the measurement and drawing is performed with modifying
2113      * hyphenation at the start of line. For example, by passing
2114      * {@link #START_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
2115      * character is appended at the start of line.
2116      *
2117      * <pre>
2118      * <code>
2119      *   Paint paint = new Paint();
2120      *   paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
2121      *   paint.measureText("abc", 0, 3);  // Returns the width of "-abc"
2122      *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "-abc"
2123      * </code>
2124      * </pre>
2125      *
2126      * The default value is 0 which is equivalent to
2127      * {@link #START_HYPHEN_EDIT_NO_EDIT}.
2128      *
2129      * @param startHyphen a start hyphen edit value.
2130      * @see #getStartHyphenEdit()
2131      */
setStartHyphenEdit(@tartHyphenEdit int startHyphen)2132     public void setStartHyphenEdit(@StartHyphenEdit int startHyphen) {
2133         nSetStartHyphenEdit(mNativePaint, startHyphen);
2134     }
2135 
2136     /**
2137      * Set a end hyphen edit on the paint.
2138      *
2139      * By setting end hyphen edit, the measurement and drawing is performed with modifying
2140      * hyphenation at the end of line. For example, by passing
2141      * {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
2142      * character is appended at the end of line.
2143      *
2144      * <pre>
2145      * <code>
2146      *   Paint paint = new Paint();
2147      *   paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
2148      *   paint.measureText("abc", 0, 3);  // Returns the width of "abc-"
2149      *   Canvas.drawText("abc", 0, 3, 0f, 0f, paint);  // Draws "abc-"
2150      * </code>
2151      * </pre>
2152      *
2153      * The default value is 0 which is equivalent to {@link #END_HYPHEN_EDIT_NO_EDIT}.
2154      *
2155      * @param endHyphen a end hyphen edit value.
2156      * @see #getEndHyphenEdit()
2157      */
setEndHyphenEdit(@ndHyphenEdit int endHyphen)2158     public void setEndHyphenEdit(@EndHyphenEdit int endHyphen) {
2159         nSetEndHyphenEdit(mNativePaint, endHyphen);
2160     }
2161 
2162     /**
2163      * Return the distance above (negative) the baseline (ascent) based on the
2164      * current typeface and text size.
2165      *
2166      * <p>Note that this is the ascent of the main typeface, and actual text rendered may need a
2167      * larger ascent because fallback fonts may get used in rendering the text.
2168      *
2169      * @return the distance above (negative) the baseline (ascent) based on the
2170      *         current typeface and text size.
2171      */
ascent()2172     public float ascent() {
2173         return nAscent(mNativePaint);
2174     }
2175 
2176     /**
2177      * Return the distance below (positive) the baseline (descent) based on the
2178      * current typeface and text size.
2179      *
2180      * <p>Note that this is the descent of the main typeface, and actual text rendered may need a
2181      * larger descent because fallback fonts may get used in rendering the text.
2182      *
2183      * @return the distance below (positive) the baseline (descent) based on
2184      *         the current typeface and text size.
2185      */
descent()2186     public float descent() {
2187         return nDescent(mNativePaint);
2188     }
2189 
2190     /**
2191      * Class that describes the various metrics for a font at a given text size.
2192      * Remember, Y values increase going down, so those values will be positive,
2193      * and values that measure distances going up will be negative. This class
2194      * is returned by getFontMetrics().
2195      */
2196     public static class FontMetrics {
2197         /**
2198          * The maximum distance above the baseline for the tallest glyph in
2199          * the font at a given text size.
2200          */
2201         public float   top;
2202         /**
2203          * The recommended distance above the baseline for singled spaced text.
2204          */
2205         public float   ascent;
2206         /**
2207          * The recommended distance below the baseline for singled spaced text.
2208          */
2209         public float   descent;
2210         /**
2211          * The maximum distance below the baseline for the lowest glyph in
2212          * the font at a given text size.
2213          */
2214         public float   bottom;
2215         /**
2216          * The recommended additional space to add between lines of text.
2217          */
2218         public float   leading;
2219 
2220         @Override
equals(Object o)2221         public boolean equals(Object o) {
2222             if (this == o) return true;
2223             if (o == null || !(o instanceof FontMetrics)) return false;
2224             FontMetrics that = (FontMetrics) o;
2225             return that.top == top && that.ascent == ascent && that.descent == descent
2226                     && that.bottom == bottom && that.leading == leading;
2227         }
2228 
2229         @Override
hashCode()2230         public int hashCode() {
2231             return Objects.hash(top, ascent, descent, bottom, leading);
2232         }
2233 
2234         @Override
toString()2235         public String toString() {
2236             return "FontMetrics{"
2237                     + "top=" + top
2238                     + ", ascent=" + ascent
2239                     + ", descent=" + descent
2240                     + ", bottom=" + bottom
2241                     + ", leading=" + leading
2242                     + '}';
2243         }
2244     }
2245 
2246     /**
2247      * Return the font's recommended interline spacing, given the Paint's
2248      * settings for typeface, textSize, etc. If metrics is not null, return the
2249      * fontmetric values in it.
2250      *
2251      * <p>Note that these are the values for the main typeface, and actual text rendered may need a
2252      * larger set of values because fallback fonts may get used in rendering the text.
2253      *
2254      * @param metrics If this object is not null, its fields are filled with
2255      *                the appropriate values given the paint's text attributes.
2256      * @return the font's recommended interline spacing.
2257      */
getFontMetrics(FontMetrics metrics)2258     public float getFontMetrics(FontMetrics metrics) {
2259         return nGetFontMetrics(mNativePaint, metrics, false);
2260     }
2261 
2262     /**
2263      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
2264      * with it, returning the object.
2265      */
getFontMetrics()2266     public FontMetrics getFontMetrics() {
2267         FontMetrics fm = new FontMetrics();
2268         getFontMetrics(fm);
2269         return fm;
2270     }
2271 
2272     /**
2273      * Get the font metrics used for the locale
2274      *
2275      * Obtain the metrics of the font that is used for the specified locale by
2276      * {@link #setTextLocales(LocaleList)}. If multiple locales are specified, the minimum ascent
2277      * and maximum descent will be set.
2278      *
2279      * This API is useful for determining the default line height of the empty text field, e.g.
2280      * {@link android.widget.EditText}.
2281      *
2282      * Note, if the {@link android.graphics.Typeface} is created from the custom font files, its
2283      * metrics are reserved, i.e. the ascent will be the custom font's ascent or smaller, the
2284      * descent will be the custom font's descent or larger.
2285      *
2286      * Note, if the {@link android.graphics.Typeface} is a system fallback, e.g.
2287      * {@link android.graphics.Typeface#SERIF}, the default font's metrics are reserved, i.e. the
2288      * ascent will be the serif font's ascent or smaller, the descent will be the serif font's
2289      * descent or larger.
2290      *
2291      * @param metrics an output parameter. All members will be set by calling this function.
2292      */
2293     @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
getFontMetricsForLocale(@onNull FontMetrics metrics)2294     public void getFontMetricsForLocale(@NonNull FontMetrics metrics) {
2295         nGetFontMetrics(mNativePaint, metrics, true);
2296     }
2297 
2298     /**
2299      * Returns the font metrics value for the given text.
2300      *
2301      * If the text is rendered with multiple font files, this function returns the large ascent and
2302      * descent that are enough for drawing all font files.
2303      *
2304      * The context range is used for shaping context. Some script, e.g. Arabic or Devanagari,
2305      * changes letter shape based on its location or surrounding characters.
2306      *
2307      * @param text a text to be measured.
2308      * @param start a starting offset in the text.
2309      * @param count a length of the text to be measured.
2310      * @param contextStart a context starting offset in the text.
2311      * @param contextCount a length of the context to be used.
2312      * @param isRtl true if measuring on RTL context, otherwise false.
2313      * @param outMetrics the output font metrics.
2314      */
getFontMetricsInt( @onNull CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int count, @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextCount, boolean isRtl, @NonNull FontMetricsInt outMetrics)2315     public void getFontMetricsInt(
2316             @NonNull CharSequence text,
2317             @IntRange(from = 0) int start, @IntRange(from = 0) int count,
2318             @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextCount,
2319             boolean isRtl,
2320             @NonNull FontMetricsInt outMetrics) {
2321 
2322         if (text == null) {
2323             throw new IllegalArgumentException("text must not be null");
2324         }
2325         if (start < 0 || start >= text.length()) {
2326             throw new IllegalArgumentException("start argument is out of bounds.");
2327         }
2328         if (count < 0 || start + count > text.length()) {
2329             throw new IllegalArgumentException("count argument is out of bounds.");
2330         }
2331         if (contextStart < 0 || contextStart >= text.length()) {
2332             throw new IllegalArgumentException("ctxStart argument is out of bounds.");
2333         }
2334         if (contextCount < 0 || contextStart + contextCount > text.length()) {
2335             throw new IllegalArgumentException("ctxCount argument is out of bounds.");
2336         }
2337         if (outMetrics == null) {
2338             throw new IllegalArgumentException("outMetrics must not be null.");
2339         }
2340 
2341         if (count == 0) {
2342             getFontMetricsInt(outMetrics);
2343             return;
2344         }
2345 
2346         if (text instanceof String) {
2347             nGetFontMetricsIntForText(mNativePaint, (String) text, start, count, contextStart,
2348                     contextCount, isRtl, outMetrics);
2349         } else {
2350             char[] buf = TemporaryBuffer.obtain(contextCount);
2351             try {
2352                 TextUtils.getChars(text, contextStart, contextStart + contextCount, buf, 0);
2353                 nGetFontMetricsIntForText(mNativePaint, buf, start - contextStart, count, 0,
2354                         contextCount, isRtl, outMetrics);
2355             } finally {
2356                 TemporaryBuffer.recycle(buf);
2357             }
2358         }
2359 
2360     }
2361 
2362     /**
2363      * Returns the font metrics value for the given text.
2364      *
2365      * If the text is rendered with multiple font files, this function returns the large ascent and
2366      * descent that are enough for drawing all font files.
2367      *
2368      * The context range is used for shaping context. Some script, e.g. Arabic or Devanagari,
2369      * changes letter shape based on its location or surrounding characters.
2370      *
2371      * @param text a text to be measured.
2372      * @param start a starting offset in the text.
2373      * @param count a length of the text to be measured.
2374      * @param contextStart a context starting offset in the text.
2375      * @param contextCount a length of the context to be used.
2376      * @param isRtl true if measuring on RTL context, otherwise false.
2377      * @param outMetrics the output font metrics.
2378      */
getFontMetricsInt(@onNull char[] text, @IntRange(from = 0) int start, @IntRange(from = 0) int count, @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextCount, boolean isRtl, @NonNull FontMetricsInt outMetrics)2379     public void getFontMetricsInt(@NonNull char[] text,
2380             @IntRange(from = 0) int start, @IntRange(from = 0) int count,
2381             @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextCount,
2382             boolean isRtl,
2383             @NonNull FontMetricsInt outMetrics) {
2384         if (text == null) {
2385             throw new IllegalArgumentException("text must not be null");
2386         }
2387         if (start < 0 || start >= text.length) {
2388             throw new IllegalArgumentException("start argument is out of bounds.");
2389         }
2390         if (count < 0 || start + count > text.length) {
2391             throw new IllegalArgumentException("count argument is out of bounds.");
2392         }
2393         if (contextStart < 0 || contextStart >= text.length) {
2394             throw new IllegalArgumentException("ctxStart argument is out of bounds.");
2395         }
2396         if (contextCount < 0 || contextStart + contextCount > text.length) {
2397             throw new IllegalArgumentException("ctxCount argument is out of bounds.");
2398         }
2399         if (outMetrics == null) {
2400             throw new IllegalArgumentException("outMetrics must not be null.");
2401         }
2402 
2403         if (count == 0) {
2404             getFontMetricsInt(outMetrics);
2405             return;
2406         }
2407 
2408         nGetFontMetricsIntForText(mNativePaint, text, start, count, contextStart, contextCount,
2409                 isRtl, outMetrics);
2410     }
2411 
2412     /**
2413      * Convenience method for callers that want to have FontMetrics values as
2414      * integers.
2415      */
2416     public static class FontMetricsInt {
2417         /**
2418          * The maximum distance above the baseline for the tallest glyph in
2419          * the font at a given text size.
2420          */
2421         public int   top;
2422         /**
2423          * The recommended distance above the baseline for singled spaced text.
2424          */
2425         public int   ascent;
2426         /**
2427          * The recommended distance below the baseline for singled spaced text.
2428          */
2429         public int   descent;
2430         /**
2431          * The maximum distance below the baseline for the lowest glyph in
2432          * the font at a given text size.
2433          */
2434         public int   bottom;
2435         /**
2436          * The recommended additional space to add between lines of text.
2437          */
2438         public int   leading;
2439 
2440         /**
2441          * Set values from {@link FontMetricsInt}.
2442          * @param fontMetricsInt a font metrics.
2443          */
2444         @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
set(@onNull FontMetricsInt fontMetricsInt)2445         public void set(@NonNull FontMetricsInt fontMetricsInt) {
2446             top = fontMetricsInt.top;
2447             ascent = fontMetricsInt.ascent;
2448             descent = fontMetricsInt.descent;
2449             bottom = fontMetricsInt.bottom;
2450             leading = fontMetricsInt.leading;
2451         }
2452 
2453         /**
2454          * Set values from {@link FontMetrics} with rounding accordingly.
2455          * @param fontMetrics a font metrics.
2456          */
2457         @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
set(@onNull FontMetrics fontMetrics)2458         public void set(@NonNull FontMetrics fontMetrics) {
2459             // See GraphicsJNI::set_metrics_int method for consistency.
2460             top = (int) Math.floor(fontMetrics.top);
2461             ascent = Math.round(fontMetrics.ascent);
2462             descent = Math.round(fontMetrics.descent);
2463             bottom = (int) Math.ceil(fontMetrics.bottom);
2464             leading = Math.round(fontMetrics.leading);
2465         }
2466 
toString()2467         @Override public String toString() {
2468             return "FontMetricsInt: top=" + top + " ascent=" + ascent +
2469                     " descent=" + descent + " bottom=" + bottom +
2470                     " leading=" + leading;
2471         }
2472 
2473         @Override
equals(Object o)2474         public boolean equals(Object o) {
2475             if (this == o) return true;
2476             if (!(o instanceof FontMetricsInt)) return false;
2477             FontMetricsInt that = (FontMetricsInt) o;
2478             return top == that.top
2479                     && ascent == that.ascent
2480                     && descent == that.descent
2481                     && bottom == that.bottom
2482                     && leading == that.leading;
2483         }
2484 
2485         @Override
hashCode()2486         public int hashCode() {
2487             return Objects.hash(top, ascent, descent, bottom, leading);
2488         }
2489     }
2490 
2491     /**
2492      * Return the font's interline spacing, given the Paint's settings for
2493      * typeface, textSize, etc. If metrics is not null, return the fontmetric
2494      * values in it. Note: all values have been converted to integers from
2495      * floats, in such a way has to make the answers useful for both spacing
2496      * and clipping. If you want more control over the rounding, call
2497      * getFontMetrics().
2498      *
2499      * <p>Note that these are the values for the main typeface, and actual text rendered may need a
2500      * larger set of values because fallback fonts may get used in rendering the text.
2501      *
2502      * @return the font's interline spacing.
2503      */
getFontMetricsInt(FontMetricsInt fmi)2504     public int getFontMetricsInt(FontMetricsInt fmi) {
2505         return nGetFontMetricsInt(mNativePaint, fmi, false);
2506     }
2507 
getFontMetricsInt()2508     public FontMetricsInt getFontMetricsInt() {
2509         FontMetricsInt fm = new FontMetricsInt();
2510         getFontMetricsInt(fm);
2511         return fm;
2512     }
2513 
2514     /**
2515      * Get the font metrics used for the locale
2516      *
2517      * Obtain the metrics of the font that is used for the specified locale by
2518      * {@link #setTextLocales(LocaleList)}. If multiple locales are specified, the minimum ascent
2519      * and maximum descent will be set.
2520      *
2521      * This API is useful for determining the default line height of the empty text field, e.g.
2522      * {@link android.widget.EditText}.
2523      *
2524      * Note, if the {@link android.graphics.Typeface} is created from the custom font files, its
2525      * metrics are reserved, i.e. the ascent will be the custom font's ascent or smaller, the
2526      * descent will be the custom font's descent or larger.
2527      *
2528      * Note, if the {@link android.graphics.Typeface} is a system fallback, e.g.
2529      * {@link android.graphics.Typeface#SERIF}, the default font's metrics are reserved, i.e. the
2530      * ascent will be the serif font's ascent or smaller, the descent will be the serif font's
2531      * descent or larger.
2532      *
2533      * @param metrics an output parameter. All members will be set by calling this function.
2534      */
2535     @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
getFontMetricsIntForLocale(@onNull FontMetricsInt metrics)2536     public void getFontMetricsIntForLocale(@NonNull FontMetricsInt metrics) {
2537         nGetFontMetricsInt(mNativePaint, metrics, true);
2538     }
2539 
2540     /** @hide */
2541     public static final class RunInfo {
2542         private int mClusterCount = 0;
2543 
getClusterCount()2544         public int getClusterCount() {
2545             return mClusterCount;
2546         }
2547 
setClusterCount(int clusterCount)2548         public void setClusterCount(int clusterCount) {
2549             mClusterCount = clusterCount;
2550         }
2551     }
2552 
2553     /**
2554      * Return the recommend line spacing based on the current typeface and
2555      * text size.
2556      *
2557      * <p>Note that this is the value for the main typeface, and actual text rendered may need a
2558      * larger value because fallback fonts may get used in rendering the text.
2559      *
2560      * @return  recommend line spacing based on the current typeface and
2561      *          text size.
2562      */
getFontSpacing()2563     public float getFontSpacing() {
2564         return getFontMetrics(null);
2565     }
2566 
2567     /**
2568      * Return the width of the text.
2569      *
2570      * @param text  The text to measure. Cannot be null.
2571      * @param index The index of the first character to start measuring
2572      * @param count THe number of characters to measure, beginning with start
2573      * @return      The width of the text
2574      */
measureText(char[] text, int index, int count)2575     public float measureText(char[] text, int index, int count) {
2576         if (text == null) {
2577             throw new IllegalArgumentException("text cannot be null");
2578         }
2579         if ((index | count) < 0 || index + count > text.length) {
2580             throw new ArrayIndexOutOfBoundsException();
2581         }
2582 
2583         if (text.length == 0 || count == 0) {
2584             return 0f;
2585         }
2586         int oldFlag = getFlags();
2587         setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));
2588         try {
2589 
2590             if (!mHasCompatScaling) {
2591                 return (float) Math.ceil(nGetTextAdvances(mNativePaint, text,
2592                         index, count, index, count, mBidiFlags, null, 0));
2593             }
2594 
2595             final float oldSize = getTextSize();
2596             setTextSize(oldSize * mCompatScaling);
2597             final float w = nGetTextAdvances(mNativePaint, text, index, count, index, count,
2598                     mBidiFlags, null, 0);
2599             setTextSize(oldSize);
2600             return (float) Math.ceil(w * mInvCompatScaling);
2601         } finally {
2602             setFlags(oldFlag);
2603         }
2604     }
2605 
2606     /**
2607      * Return the width of the text.
2608      *
2609      * @param text  The text to measure. Cannot be null.
2610      * @param start The index of the first character to start measuring
2611      * @param end   1 beyond the index of the last character to measure
2612      * @return      The width of the text
2613      */
measureText(String text, int start, int end)2614     public float measureText(String text, int start, int end) {
2615         if (text == null) {
2616             throw new IllegalArgumentException("text cannot be null");
2617         }
2618         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2619             throw new IndexOutOfBoundsException();
2620         }
2621 
2622         if (text.length() == 0 || start == end) {
2623             return 0f;
2624         }
2625         int oldFlag = getFlags();
2626         setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));
2627         try {
2628             if (!mHasCompatScaling) {
2629                 return (float) Math.ceil(nGetTextAdvances(mNativePaint, text,
2630                         start, end, start, end, mBidiFlags, null, 0));
2631             }
2632             final float oldSize = getTextSize();
2633             setTextSize(oldSize * mCompatScaling);
2634             final float w = nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags,
2635                     null, 0);
2636             setTextSize(oldSize);
2637             return (float) Math.ceil(w * mInvCompatScaling);
2638         } finally {
2639             setFlags(oldFlag);
2640         }
2641     }
2642 
2643     /**
2644      * Return the width of the text.
2645      *
2646      * @param text  The text to measure. Cannot be null.
2647      * @return      The width of the text
2648      */
measureText(String text)2649     public float measureText(String text) {
2650         if (text == null) {
2651             throw new IllegalArgumentException("text cannot be null");
2652         }
2653         return measureText(text, 0, text.length());
2654     }
2655 
2656     /**
2657      * Return the width of the text.
2658      *
2659      * @param text  The text to measure
2660      * @param start The index of the first character to start measuring
2661      * @param end   1 beyond the index of the last character to measure
2662      * @return      The width of the text
2663      */
measureText(CharSequence text, int start, int end)2664     public float measureText(CharSequence text, int start, int end) {
2665         if (text == null) {
2666             throw new IllegalArgumentException("text cannot be null");
2667         }
2668         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2669             throw new IndexOutOfBoundsException();
2670         }
2671 
2672         if (text.length() == 0 || start == end) {
2673             return 0f;
2674         }
2675         if (text instanceof String) {
2676             return measureText((String)text, start, end);
2677         }
2678         if (text instanceof SpannedString ||
2679             text instanceof SpannableString) {
2680             return measureText(text.toString(), start, end);
2681         }
2682         if (text instanceof GraphicsOperations) {
2683             return ((GraphicsOperations)text).measureText(start, end, this);
2684         }
2685 
2686         char[] buf = TemporaryBuffer.obtain(end - start);
2687         TextUtils.getChars(text, start, end, buf, 0);
2688         float result = measureText(buf, 0, end - start);
2689         TemporaryBuffer.recycle(buf);
2690         return result;
2691     }
2692 
2693     /**
2694      * Measure the text, stopping early if the measured width exceeds maxWidth.
2695      * Return the number of chars that were measured, and if measuredWidth is
2696      * not null, return in it the actual width measured.
2697      *
2698      * @param text  The text to measure. Cannot be null.
2699      * @param index The offset into text to begin measuring at
2700      * @param count The number of maximum number of entries to measure. If count
2701      *              is negative, then the characters are measured in reverse order.
2702      * @param maxWidth The maximum width to accumulate.
2703      * @param measuredWidth Optional. If not null, returns the actual width
2704      *                     measured.
2705      * @return The number of chars that were measured. Will always be <=
2706      *         abs(count).
2707      */
breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth)2708     public int breakText(char[] text, int index, int count,
2709                                 float maxWidth, float[] measuredWidth) {
2710         if (text == null) {
2711             throw new IllegalArgumentException("text cannot be null");
2712         }
2713         if (index < 0 || text.length - index < Math.abs(count)) {
2714             throw new ArrayIndexOutOfBoundsException();
2715         }
2716 
2717         if (text.length == 0 || count == 0) {
2718             return 0;
2719         }
2720         if (!mHasCompatScaling) {
2721             return nBreakText(mNativePaint, text, index, count, maxWidth, mBidiFlags,
2722                     measuredWidth);
2723         }
2724 
2725         final float oldSize = getTextSize();
2726         setTextSize(oldSize * mCompatScaling);
2727         final int res = nBreakText(mNativePaint, text, index, count, maxWidth * mCompatScaling,
2728                 mBidiFlags, measuredWidth);
2729         setTextSize(oldSize);
2730         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
2731         return res;
2732     }
2733 
2734     /**
2735      * Measure the text, stopping early if the measured width exceeds maxWidth.
2736      * Return the number of chars that were measured, and if measuredWidth is
2737      * not null, return in it the actual width measured.
2738      *
2739      * @param text  The text to measure. Cannot be null.
2740      * @param start The offset into text to begin measuring at
2741      * @param end   The end of the text slice to measure.
2742      * @param measureForwards If true, measure forwards, starting at start.
2743      *                        Otherwise, measure backwards, starting with end.
2744      * @param maxWidth The maximum width to accumulate.
2745      * @param measuredWidth Optional. If not null, returns the actual width
2746      *                     measured.
2747      * @return The number of chars that were measured. Will always be <=
2748      *         abs(end - start).
2749      */
breakText(CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)2750     public int breakText(CharSequence text, int start, int end,
2751                          boolean measureForwards,
2752                          float maxWidth, float[] measuredWidth) {
2753         if (text == null) {
2754             throw new IllegalArgumentException("text cannot be null");
2755         }
2756         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2757             throw new IndexOutOfBoundsException();
2758         }
2759 
2760         if (text.length() == 0 || start == end) {
2761             return 0;
2762         }
2763         if (start == 0 && text instanceof String && end == text.length()) {
2764             return breakText((String) text, measureForwards, maxWidth,
2765                              measuredWidth);
2766         }
2767 
2768         char[] buf = TemporaryBuffer.obtain(end - start);
2769         int result;
2770 
2771         TextUtils.getChars(text, start, end, buf, 0);
2772 
2773         if (measureForwards) {
2774             result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
2775         } else {
2776             result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
2777         }
2778 
2779         TemporaryBuffer.recycle(buf);
2780         return result;
2781     }
2782 
2783     /**
2784      * Measure the text, stopping early if the measured width exceeds maxWidth.
2785      * Return the number of chars that were measured, and if measuredWidth is
2786      * not null, return in it the actual width measured.
2787      *
2788      * @param text  The text to measure. Cannot be null.
2789      * @param measureForwards If true, measure forwards, starting with the
2790      *                        first character in the string. Otherwise,
2791      *                        measure backwards, starting with the
2792      *                        last character in the string.
2793      * @param maxWidth The maximum width to accumulate.
2794      * @param measuredWidth Optional. If not null, returns the actual width
2795      *                     measured.
2796      * @return The number of chars that were measured. Will always be <=
2797      *         abs(count).
2798      */
breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth)2799     public int breakText(String text, boolean measureForwards,
2800                                 float maxWidth, float[] measuredWidth) {
2801         if (text == null) {
2802             throw new IllegalArgumentException("text cannot be null");
2803         }
2804 
2805         if (text.length() == 0) {
2806             return 0;
2807         }
2808         if (!mHasCompatScaling) {
2809             return nBreakText(mNativePaint, text, measureForwards,
2810                     maxWidth, mBidiFlags, measuredWidth);
2811         }
2812 
2813         final float oldSize = getTextSize();
2814         setTextSize(oldSize*mCompatScaling);
2815         final int res = nBreakText(mNativePaint, text, measureForwards, maxWidth*mCompatScaling,
2816                 mBidiFlags, measuredWidth);
2817         setTextSize(oldSize);
2818         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
2819         return res;
2820     }
2821 
2822     /**
2823      * Return the advance widths for the characters in the string.
2824      *
2825      * @param text     The text to measure. Cannot be null.
2826      * @param index    The index of the first char to to measure
2827      * @param count    The number of chars starting with index to measure
2828      * @param widths   array to receive the advance widths of the characters.
2829      *                 Must be at least a large as count.
2830      * @return         the actual number of widths returned.
2831      */
getTextWidths(char[] text, int index, int count, float[] widths)2832     public int getTextWidths(char[] text, int index, int count,
2833                              float[] widths) {
2834         if (text == null) {
2835             throw new IllegalArgumentException("text cannot be null");
2836         }
2837         if ((index | count) < 0 || index + count > text.length
2838                 || count > widths.length) {
2839             throw new ArrayIndexOutOfBoundsException();
2840         }
2841 
2842         if (text.length == 0 || count == 0) {
2843             return 0;
2844         }
2845         int oldFlag = getFlags();
2846         setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));
2847         try {
2848             if (!mHasCompatScaling) {
2849                 nGetTextAdvances(mNativePaint, text, index, count, index, count, mBidiFlags, widths,
2850                         0);
2851                 return count;
2852             }
2853 
2854             final float oldSize = getTextSize();
2855             setTextSize(oldSize * mCompatScaling);
2856             nGetTextAdvances(mNativePaint, text, index, count, index, count, mBidiFlags, widths, 0);
2857             setTextSize(oldSize);
2858             for (int i = 0; i < count; i++) {
2859                 widths[i] *= mInvCompatScaling;
2860             }
2861             return count;
2862         } finally {
2863             setFlags(oldFlag);
2864         }
2865     }
2866 
2867     /**
2868      * Return the advance widths for the characters in the string.
2869      *
2870      * @param text     The text to measure. Cannot be null.
2871      * @param start    The index of the first char to to measure
2872      * @param end      The end of the text slice to measure
2873      * @param widths   array to receive the advance widths of the characters.
2874      *                 Must be at least a large as (end - start).
2875      * @return         the actual number of widths returned.
2876      */
getTextWidths(CharSequence text, int start, int end, float[] widths)2877     public int getTextWidths(CharSequence text, int start, int end,
2878                              float[] widths) {
2879         if (text == null) {
2880             throw new IllegalArgumentException("text cannot be null");
2881         }
2882         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2883             throw new IndexOutOfBoundsException();
2884         }
2885         if (end - start > widths.length) {
2886             throw new ArrayIndexOutOfBoundsException();
2887         }
2888 
2889         if (text.length() == 0 || start == end) {
2890             return 0;
2891         }
2892         if (text instanceof String) {
2893             return getTextWidths((String) text, start, end, widths);
2894         }
2895         if (text instanceof SpannedString ||
2896             text instanceof SpannableString) {
2897             return getTextWidths(text.toString(), start, end, widths);
2898         }
2899         if (text instanceof GraphicsOperations) {
2900             return ((GraphicsOperations) text).getTextWidths(start, end,
2901                                                                  widths, this);
2902         }
2903 
2904         char[] buf = TemporaryBuffer.obtain(end - start);
2905         TextUtils.getChars(text, start, end, buf, 0);
2906         int result = getTextWidths(buf, 0, end - start, widths);
2907         TemporaryBuffer.recycle(buf);
2908         return result;
2909     }
2910 
2911     /**
2912      * Return the advance widths for the characters in the string.
2913      *
2914      * @param text   The text to measure. Cannot be null.
2915      * @param start  The index of the first char to to measure
2916      * @param end    The end of the text slice to measure
2917      * @param widths array to receive the advance widths of the characters.
2918      *               Must be at least a large as the text.
2919      * @return       the number of code units in the specified text.
2920      */
getTextWidths(String text, int start, int end, float[] widths)2921     public int getTextWidths(String text, int start, int end, float[] widths) {
2922         if (text == null) {
2923             throw new IllegalArgumentException("text cannot be null");
2924         }
2925         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2926             throw new IndexOutOfBoundsException();
2927         }
2928         if (end - start > widths.length) {
2929             throw new ArrayIndexOutOfBoundsException();
2930         }
2931 
2932         if (text.length() == 0 || start == end) {
2933             return 0;
2934         }
2935         int oldFlag = getFlags();
2936         setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));
2937         try {
2938             if (!mHasCompatScaling) {
2939                 nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, widths, 0);
2940                 return end - start;
2941             }
2942 
2943             final float oldSize = getTextSize();
2944             setTextSize(oldSize * mCompatScaling);
2945             nGetTextAdvances(mNativePaint, text, start, end, start, end, mBidiFlags, widths, 0);
2946             setTextSize(oldSize);
2947             for (int i = 0; i < end - start; i++) {
2948                 widths[i] *= mInvCompatScaling;
2949             }
2950             return end - start;
2951         } finally {
2952             setFlags(oldFlag);
2953         }
2954     }
2955 
2956     /**
2957      * Return the advance widths for the characters in the string.
2958      *
2959      * @param text   The text to measure
2960      * @param widths array to receive the advance widths of the characters.
2961      *               Must be at least a large as the text.
2962      * @return       the number of code units in the specified text.
2963      */
getTextWidths(String text, float[] widths)2964     public int getTextWidths(String text, float[] widths) {
2965         return getTextWidths(text, 0, text.length(), widths);
2966     }
2967 
2968     /**
2969      * Retrieve the character advances of the text.
2970      *
2971      * Returns the total advance width for the characters in the run from {@code index} for
2972      * {@code count} of chars, and if {@code advances} is not null, the advance assigned to each of
2973      * these characters (java chars).
2974      *
2975      * <p>
2976      * The trailing surrogate in a valid surrogate pair is assigned an advance of 0.  Thus the
2977      * number of returned advances is always equal to count, not to the number of unicode codepoints
2978      * represented by the run.
2979      * </p>
2980      *
2981      * <p>
2982      * In the case of conjuncts or combining marks, the total advance is assigned to the first
2983      * logical character, and the following characters are assigned an advance of 0.
2984      * </p>
2985      *
2986      * <p>
2987      * This generates the sum of the advances of glyphs for characters in a reordered cluster as the
2988      * width of the first logical character in the cluster, and 0 for the widths of all other
2989      * characters in the cluster.  In effect, such clusters are treated like conjuncts.
2990      * </p>
2991      *
2992      * <p>
2993      * The shaping bounds limit the amount of context available outside start and end that can be
2994      * used for shaping analysis.  These bounds typically reflect changes in bidi level or font
2995      * metrics across which shaping does not occur.
2996      * </p>
2997      *
2998      * @param chars the text to measure.
2999      * @param index the index of the first character to measure
3000      * @param count the number of characters to measure
3001      * @param contextIndex the index of the first character to use for shaping context.
3002      *                     Context must cover the measureing target.
3003      * @param contextCount the number of character to use for shaping context.
3004      *                     Context must cover the measureing target.
3005      * @param isRtl whether the run is in RTL direction
3006      * @param advances array to receive the advances, must have room for all advances.
3007      *                 This can be null if only total advance is needed
3008      * @param advancesIndex the position in advances at which to put the advance corresponding to
3009      *                      the character at start
3010      * @return the total advance in pixels
3011      */
getTextRunAdvances(@onNull char[] chars, @IntRange(from = 0) int index, @IntRange(from = 0) int count, @IntRange(from = 0) int contextIndex, @IntRange(from = 0) int contextCount, boolean isRtl, @Nullable float[] advances, @IntRange(from = 0) int advancesIndex)3012     public float getTextRunAdvances(@NonNull char[] chars, @IntRange(from = 0) int index,
3013             @IntRange(from = 0) int count, @IntRange(from = 0) int contextIndex,
3014             @IntRange(from = 0) int contextCount, boolean isRtl, @Nullable float[] advances,
3015             @IntRange(from = 0) int advancesIndex) {
3016         if (chars == null) {
3017             throw new IllegalArgumentException("text cannot be null");
3018         }
3019         if ((index | count | contextIndex | contextCount | advancesIndex
3020                 | (index - contextIndex) | (contextCount - count)
3021                 | ((contextIndex + contextCount) - (index + count))
3022                 | (chars.length - (contextIndex + contextCount))
3023                 | (advances == null ? 0 :
3024                     (advances.length - (advancesIndex + count)))) < 0) {
3025             throw new IndexOutOfBoundsException();
3026         }
3027 
3028         if (chars.length == 0 || count == 0){
3029             return 0f;
3030         }
3031         if (!mHasCompatScaling) {
3032             return nGetTextAdvances(mNativePaint, chars, index, count, contextIndex, contextCount,
3033                     isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
3034                     advancesIndex);
3035         }
3036 
3037         final float oldSize = getTextSize();
3038         setTextSize(oldSize * mCompatScaling);
3039         final float res = nGetTextAdvances(mNativePaint, chars, index, count, contextIndex,
3040                 contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
3041         setTextSize(oldSize);
3042 
3043         if (advances != null) {
3044             for (int i = advancesIndex, e = i + count; i < e; i++) {
3045                 advances[i] *= mInvCompatScaling;
3046             }
3047         }
3048         return res * mInvCompatScaling; // assume errors are not significant
3049     }
3050 
3051     /**
3052      * Returns the next cursor position in the run.
3053      *
3054      * This avoids placing the cursor between surrogates, between characters that form conjuncts,
3055      * between base characters and combining marks, or within a reordering cluster.
3056      *
3057      * <p>
3058      * ContextStart and offset are relative to the start of text.
3059      * The context is the shaping context for cursor movement, generally the bounds of the metric
3060      * span enclosing the cursor in the direction of movement.
3061      *
3062      * <p>
3063      * If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid cursor position, this
3064      * returns -1.  Otherwise this will never return a value before contextStart or after
3065      * contextStart + contextLength.
3066      *
3067      * @param text the text
3068      * @param contextStart the start of the context
3069      * @param contextLength the length of the context
3070      * @param isRtl true if the paragraph context is RTL, otherwise false
3071      * @param offset the cursor position to move from
3072      * @param cursorOpt how to move the cursor
3073      * @return the offset of the next position, or -1
3074      */
getTextRunCursor(@onNull char[] text, @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextLength, boolean isRtl, @IntRange(from = 0) int offset, @CursorOption int cursorOpt)3075     public int getTextRunCursor(@NonNull char[] text, @IntRange(from = 0) int contextStart,
3076             @IntRange(from = 0) int contextLength, boolean isRtl, @IntRange(from = 0) int offset,
3077             @CursorOption int cursorOpt) {
3078         int contextEnd = contextStart + contextLength;
3079         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
3080                 | (offset - contextStart) | (contextEnd - offset)
3081                 | (text.length - contextEnd) | cursorOpt) < 0)
3082                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
3083             throw new IndexOutOfBoundsException();
3084         }
3085 
3086         return nGetTextRunCursor(mNativePaint, text, contextStart, contextLength,
3087                 isRtl ? DIRECTION_RTL : DIRECTION_LTR, offset, cursorOpt);
3088     }
3089 
3090     /**
3091      * Returns the next cursor position in the run.
3092      *
3093      * This avoids placing the cursor between surrogates, between characters that form conjuncts,
3094      * between base characters and combining marks, or within a reordering cluster.
3095      *
3096      * <p>
3097      * ContextStart, contextEnd, and offset are relative to the start of
3098      * text.  The context is the shaping context for cursor movement, generally
3099      * the bounds of the metric span enclosing the cursor in the direction of
3100      * movement.
3101      *
3102      * <p>
3103      * If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid cursor position, this
3104      * returns -1.  Otherwise this will never return a value before contextStart or after
3105      * contextEnd.
3106      *
3107      * @param text the text
3108      * @param contextStart the start of the context
3109      * @param contextEnd the end of the context
3110      * @param isRtl true if the paragraph context is RTL, otherwise false
3111      * @param offset the cursor position to move from
3112      * @param cursorOpt how to move the cursor
3113      * @return the offset of the next position, or -1
3114      */
getTextRunCursor(@onNull CharSequence text, @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextEnd, boolean isRtl, @IntRange(from = 0) int offset, @CursorOption int cursorOpt)3115     public int getTextRunCursor(@NonNull CharSequence text, @IntRange(from = 0) int contextStart,
3116             @IntRange(from = 0) int contextEnd, boolean isRtl, @IntRange(from = 0) int offset,
3117             @CursorOption int cursorOpt) {
3118 
3119         if (text instanceof String || text instanceof SpannedString ||
3120                 text instanceof SpannableString) {
3121             return getTextRunCursor(text.toString(), contextStart, contextEnd,
3122                     isRtl, offset, cursorOpt);
3123         }
3124         if (text instanceof GraphicsOperations) {
3125             return ((GraphicsOperations) text).getTextRunCursor(
3126                     contextStart, contextEnd, isRtl, offset, cursorOpt, this);
3127         }
3128 
3129         int contextLen = contextEnd - contextStart;
3130         char[] buf = TemporaryBuffer.obtain(contextLen);
3131         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
3132         int relPos = getTextRunCursor(buf, 0, contextLen, isRtl, offset - contextStart, cursorOpt);
3133         TemporaryBuffer.recycle(buf);
3134         return (relPos == -1) ? -1 : relPos + contextStart;
3135     }
3136 
3137     /**
3138      * Returns the next cursor position in the run.
3139      *
3140      * This avoids placing the cursor between surrogates, between characters that form conjuncts,
3141      * between base characters and combining marks, or within a reordering cluster.
3142      *
3143      * <p>
3144      * ContextStart, contextEnd, and offset are relative to the start of text.  The context is the
3145      * shaping context for cursor movement, generally the bounds of the metric span enclosing the
3146      * cursor in the direction of movement.
3147      * </p>
3148      *
3149      * <p>
3150      * If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid cursor position, this
3151      * returns -1.  Otherwise this will never return a value before contextStart or after
3152      * contextEnd.
3153      * </p>
3154      *
3155      * @param text the text
3156      * @param contextStart the start of the context
3157      * @param contextEnd the end of the context
3158      * @param isRtl true if the paragraph context is RTL, otherwise false.
3159      * @param offset the cursor position to move from
3160      * @param cursorOpt how to move the cursor
3161      * @return the offset of the next position, or -1
3162      * @hide
3163      */
getTextRunCursor(@onNull String text, @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextEnd, boolean isRtl, @IntRange(from = 0) int offset, @CursorOption int cursorOpt)3164     public int getTextRunCursor(@NonNull String text, @IntRange(from = 0) int contextStart,
3165             @IntRange(from = 0) int contextEnd, boolean isRtl, @IntRange(from = 0) int offset,
3166             @CursorOption int cursorOpt) {
3167         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
3168                 | (offset - contextStart) | (contextEnd - offset)
3169                 | (text.length() - contextEnd) | cursorOpt) < 0)
3170                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
3171             throw new IndexOutOfBoundsException();
3172         }
3173 
3174         return nGetTextRunCursor(mNativePaint, text, contextStart, contextEnd,
3175                 isRtl ? DIRECTION_RTL : DIRECTION_LTR, offset, cursorOpt);
3176     }
3177 
3178     /**
3179      * Return the path (outline) for the specified text.
3180      * Note: just like Canvas.drawText, this will respect the Align setting in
3181      * the paint.
3182      *
3183      * @param text the text to retrieve the path from
3184      * @param index the index of the first character in text
3185      * @param count the number of characters starting with index
3186      * @param x the x coordinate of the text's origin
3187      * @param y the y coordinate of the text's origin
3188      * @param path the path to receive the data describing the text. Must be allocated by the caller
3189      */
getTextPath(char[] text, int index, int count, float x, float y, Path path)3190     public void getTextPath(char[] text, int index, int count,
3191                             float x, float y, Path path) {
3192         if ((index | count) < 0 || index + count > text.length) {
3193             throw new ArrayIndexOutOfBoundsException();
3194         }
3195         nGetTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, path.mutateNI());
3196     }
3197 
3198     /**
3199      * Return the path (outline) for the specified text.
3200      * Note: just like Canvas.drawText, this will respect the Align setting
3201      * in the paint.
3202      *
3203      * @param text the text to retrieve the path from
3204      * @param start the first character in the text
3205      * @param end 1 past the last character in the text
3206      * @param x the x coordinate of the text's origin
3207      * @param y the y coordinate of the text's origin
3208      * @param path the path to receive the data describing the text. Must be allocated by the caller
3209      */
getTextPath(String text, int start, int end, float x, float y, Path path)3210     public void getTextPath(String text, int start, int end,
3211                             float x, float y, Path path) {
3212         if ((start | end | (end - start) | (text.length() - end)) < 0) {
3213             throw new IndexOutOfBoundsException();
3214         }
3215         nGetTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, path.mutateNI());
3216     }
3217 
3218     /**
3219      * Retrieve the text boundary box and store to bounds.
3220      *
3221      * Return in bounds (allocated by the caller) the smallest rectangle that
3222      * encloses all of the characters, with an implied origin at (0,0).
3223      *
3224      * @param text string to measure and return its bounds
3225      * @param start index of the first char in the string to measure
3226      * @param end 1 past the last char in the string to measure
3227      * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
3228      */
getTextBounds(String text, int start, int end, Rect bounds)3229     public void getTextBounds(String text, int start, int end, Rect bounds) {
3230         if ((start | end | (end - start) | (text.length() - end)) < 0) {
3231             throw new IndexOutOfBoundsException();
3232         }
3233         if (bounds == null) {
3234             throw new NullPointerException("need bounds Rect");
3235         }
3236         nGetStringBounds(mNativePaint, text, start, end, mBidiFlags, bounds);
3237     }
3238 
3239     /**
3240      * Retrieve the text boundary box and store to bounds.
3241      *
3242      * Return in bounds (allocated by the caller) the smallest rectangle that
3243      * encloses all of the characters, with an implied origin at (0,0).
3244      *
3245      * Note that styles are ignored even if you pass {@link android.text.Spanned} instance.
3246      * Use {@link android.text.StaticLayout} for measuring bounds of {@link android.text.Spanned}.
3247      *
3248      * @param text text to measure and return its bounds
3249      * @param start index of the first char in the text to measure
3250      * @param end 1 past the last char in the text to measure
3251      * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
3252      */
getTextBounds(@onNull CharSequence text, int start, int end, @NonNull Rect bounds)3253     public void getTextBounds(@NonNull CharSequence text, int start, int end,
3254             @NonNull Rect bounds) {
3255         if ((start | end | (end - start) | (text.length() - end)) < 0) {
3256             throw new IndexOutOfBoundsException();
3257         }
3258         if (bounds == null) {
3259             throw new NullPointerException("need bounds Rect");
3260         }
3261         char[] buf = TemporaryBuffer.obtain(end - start);
3262         TextUtils.getChars(text, start, end, buf, 0);
3263         getTextBounds(buf, 0, end - start, bounds);
3264         TemporaryBuffer.recycle(buf);
3265     }
3266 
3267     /**
3268      * Return in bounds (allocated by the caller) the smallest rectangle that
3269      * encloses all of the characters, with an implied origin at (0,0).
3270      *
3271      * @param text  array of chars to measure and return their unioned bounds
3272      * @param index index of the first char in the array to measure
3273      * @param count the number of chars, beginning at index, to measure
3274      * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
3275      */
getTextBounds(char[] text, int index, int count, Rect bounds)3276     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
3277         if ((index | count) < 0 || index + count > text.length) {
3278             throw new ArrayIndexOutOfBoundsException();
3279         }
3280         if (bounds == null) {
3281             throw new NullPointerException("need bounds Rect");
3282         }
3283         nGetCharArrayBounds(mNativePaint, text, index, count, mBidiFlags,
3284             bounds);
3285     }
3286 
3287     /**
3288      * Determine whether the typeface set on the paint has a glyph supporting the string. The
3289      * simplest case is when the string contains a single character, in which this method
3290      * determines whether the font has the character. In the case of multiple characters, the
3291      * method returns true if there is a single glyph representing the ligature. For example, if
3292      * the input is a pair of regional indicator symbols, determine whether there is an emoji flag
3293      * for the pair.
3294      *
3295      * <p>Finally, if the string contains a variation selector, the method only returns true if
3296      * the fonts contains a glyph specific to that variation.
3297      *
3298      * <p>Checking is done on the entire fallback chain, not just the immediate font referenced.
3299      *
3300      * @param string the string to test whether there is glyph support
3301      * @return true if the typeface has a glyph for the string
3302      */
hasGlyph(String string)3303     public boolean hasGlyph(String string) {
3304         return nHasGlyph(mNativePaint, mBidiFlags, string);
3305     }
3306 
3307     /**
3308      * Measure cursor position within a run of text.
3309      *
3310      * <p>The run of text includes the characters from {@code start} to {@code end} in the text. In
3311      * addition, the range {@code contextStart} to {@code contextEnd} is used as context for the
3312      * purpose of complex text shaping, such as Arabic text potentially shaped differently based on
3313      * the text next to it.
3314      *
3315      * <p>All text outside the range {@code contextStart..contextEnd} is ignored. The text between
3316      * {@code start} and {@code end} will be laid out to be measured.
3317      *
3318      * <p>The returned width measurement is the advance from {@code start} to {@code offset}. It is
3319      * generally a positive value, no matter the direction of the run. If {@code offset == end},
3320      * the return value is simply the width of the whole run from {@code start} to {@code end}.
3321      *
3322      * <p>Ligatures are formed for characters in the range {@code start..end} (but not for
3323      * {@code start..contextStart} or {@code end..contextEnd}). If {@code offset} points to a
3324      * character in the middle of such a formed ligature, but at a grapheme cluster boundary, the
3325      * return value will also reflect an advance in the middle of the ligature. See
3326      * {@link #getOffsetForAdvance} for more discussion of grapheme cluster boundaries.
3327      *
3328      * <p>The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is
3329      * suitable only for runs of a single direction.
3330      *
3331      * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart
3332      * <= start <= offset <= end <= contextEnd <= text.length} must hold on entry.
3333      *
3334      * @param text the text to measure. Cannot be null.
3335      * @param start the index of the start of the range to measure
3336      * @param end the index + 1 of the end of the range to measure
3337      * @param contextStart the index of the start of the shaping context
3338      * @param contextEnd the index + 1 of the end of the shaping context
3339      * @param isRtl whether the run is in RTL direction
3340      * @param offset index of caret position
3341      * @return width measurement between start and offset
3342      */
getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)3343     public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd,
3344             boolean isRtl, int offset) {
3345         if (text == null) {
3346             throw new IllegalArgumentException("text cannot be null");
3347         }
3348         if ((contextStart | start | offset | end | contextEnd
3349                 | start - contextStart | offset - start | end - offset
3350                 | contextEnd - end | text.length - contextEnd) < 0) {
3351             throw new IndexOutOfBoundsException();
3352         }
3353         if (end == start) {
3354             return 0.0f;
3355         }
3356         // TODO: take mCompatScaling into account (or eliminate compat scaling)?
3357         return nGetRunAdvance(mNativePaint, text, start, end, contextStart, contextEnd, isRtl,
3358                 offset);
3359     }
3360 
3361     /**
3362      * @see #getRunAdvance(char[], int, int, int, int, boolean, int)
3363      *
3364      * @param text the text to measure. Cannot be null.
3365      * @param start the index of the start of the range to measure
3366      * @param end the index + 1 of the end of the range to measure
3367      * @param contextStart the index of the start of the shaping context
3368      * @param contextEnd the index + 1 of the end of the shaping context
3369      * @param isRtl whether the run is in RTL direction
3370      * @param offset index of caret position
3371      * @return width measurement between start and offset
3372      */
getRunAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)3373     public float getRunAdvance(CharSequence text, int start, int end, int contextStart,
3374             int contextEnd, boolean isRtl, int offset) {
3375         if (text == null) {
3376             throw new IllegalArgumentException("text cannot be null");
3377         }
3378         if ((contextStart | start | offset | end | contextEnd
3379                 | start - contextStart | offset - start | end - offset
3380                 | contextEnd - end | text.length() - contextEnd) < 0) {
3381             throw new IndexOutOfBoundsException();
3382         }
3383         if (end == start) {
3384             return 0.0f;
3385         }
3386         // TODO performance: specialized alternatives to avoid buffer copy, if win is significant
3387         char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart);
3388         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
3389         float result = getRunAdvance(buf, start - contextStart, end - contextStart, 0,
3390                 contextEnd - contextStart, isRtl, offset - contextStart);
3391         TemporaryBuffer.recycle(buf);
3392         return result;
3393     }
3394 
3395 
3396     /**
3397      * Measure the advance of each character within a run of text and also return the cursor
3398      * position within the run.
3399      *
3400      * @see #getRunAdvance(char[], int, int, int, int, boolean, int) for more details.
3401      *
3402      * @param text the text to measure. Cannot be null.
3403      * @param start the start index of the range to measure, inclusive
3404      * @param end the end index of the range to measure, exclusive
3405      * @param contextStart the start index of the shaping context, inclusive
3406      * @param contextEnd the end index of the shaping context, exclusive
3407      * @param isRtl whether the run is in RTL direction
3408      * @param offset index of caret position
3409      * @param advances the array that receives the computed character advances
3410      * @param advancesIndex the start index from which the advances array is filled
3411      * @return width measurement between start and offset
3412      * @throws IndexOutOfBoundsException if a) contextStart or contextEnd is out of array's range
3413      * or contextStart is larger than contextEnd,
3414      * b) start or end is not within the range [contextStart, contextEnd), or start is larger than
3415      * end,
3416      * c) offset is not within the range [start, end),
3417      * d) advances.length - advanceIndex is smaller than the length of the run, which equals to
3418      * end - start.
3419      *
3420      */
getRunCharacterAdvance(@onNull char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex)3421     public float getRunCharacterAdvance(@NonNull char[] text, int start, int end, int contextStart,
3422             int contextEnd, boolean isRtl, int offset,
3423             @Nullable float[] advances, int advancesIndex) {
3424         return getRunCharacterAdvance(text, start, end, contextStart, contextEnd, isRtl, offset,
3425                 advances, advancesIndex, null, null);
3426     }
3427 
3428     /**
3429      * Measure the advance of each character within a run of text and also return the cursor
3430      * position within the run.
3431      *
3432      * @see #getRunAdvance(char[], int, int, int, int, boolean, int) for more details.
3433      *
3434      * @param text the text to measure. Cannot be null.
3435      * @param start the start index of the range to measure, inclusive
3436      * @param end the end index of the range to measure, exclusive
3437      * @param contextStart the start index of the shaping context, inclusive
3438      * @param contextEnd the end index of the shaping context, exclusive
3439      * @param isRtl whether the run is in RTL direction
3440      * @param offset index of caret position
3441      * @param advances the array that receives the computed character advances
3442      * @param advancesIndex the start index from which the advances array is filled
3443      * @param drawBounds the output parameter for the bounding box of drawing text, optional
3444      * @param runInfo the output parameter for storing run information.
3445      * @return width measurement between start and offset
3446      * @hide TODO: Reorganize APIs
3447      */
getRunCharacterAdvance(@onNull char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds, @Nullable RunInfo runInfo)3448     public float getRunCharacterAdvance(@NonNull char[] text, int start, int end, int contextStart,
3449             int contextEnd, boolean isRtl, int offset,
3450             @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds,
3451             @Nullable RunInfo runInfo) {
3452         if (text == null) {
3453             throw new IllegalArgumentException("text cannot be null");
3454         }
3455         if (contextStart < 0 || contextEnd > text.length) {
3456             throw new IndexOutOfBoundsException("Invalid Context Range: " + contextStart + ", "
3457                     + contextEnd + " must be in 0, " + text.length);
3458         }
3459 
3460         if (start < contextStart || contextEnd < end) {
3461             throw new IndexOutOfBoundsException("Invalid start/end range: " + start + ", " + end
3462                     + " must be in " + contextStart + ", " + contextEnd);
3463         }
3464 
3465         if (offset < start || end < offset) {
3466             throw new IndexOutOfBoundsException("Invalid offset position: " + offset
3467                     + " must be in " + start + ", " + end);
3468         }
3469 
3470         if (advances != null && advances.length < advancesIndex - start + end) {
3471             throw new IndexOutOfBoundsException("Given array doesn't have enough space to receive "
3472                     + "the result, advances.length: " + advances.length + " advanceIndex: "
3473                     + advancesIndex + " needed space: " + (offset - start));
3474         }
3475 
3476         if (end == start) {
3477             if (runInfo != null) {
3478                 runInfo.setClusterCount(0);
3479             }
3480             return 0.0f;
3481         }
3482 
3483         return nGetRunCharacterAdvance(mNativePaint, text, start, end, contextStart, contextEnd,
3484                 isRtl, offset, advances, advancesIndex, drawBounds, runInfo);
3485     }
3486 
3487     /**
3488      * @see #getRunCharacterAdvance(char[], int, int, int, int, boolean, int, float[], int)
3489      *
3490      * @param text the text to measure. Cannot be null.
3491      * @param start the index of the start of the range to measure
3492      * @param end the index + 1 of the end of the range to measure
3493      * @param contextStart the index of the start of the shaping context
3494      * @param contextEnd the index + 1 of the end of the shaping context
3495      * @param isRtl whether the run is in RTL direction
3496      * @param offset index of caret position
3497      * @param advances the array that receives the computed character advances
3498      * @param advancesIndex the start index from which the advances array is filled
3499      * @return width measurement between start and offset
3500      * @throws IndexOutOfBoundsException if a) contextStart or contextEnd is out of array's range
3501      * or contextStart is larger than contextEnd,
3502      * b) start or end is not within the range [contextStart, contextEnd), or end is larger than
3503      * start,
3504      * c) offset is not within the range [start, end),
3505      * d) advances.length - advanceIndex is smaller than the run length, which equals to
3506      * end - start.
3507      */
getRunCharacterAdvance(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex)3508     public float getRunCharacterAdvance(@NonNull CharSequence text, int start, int end,
3509             int contextStart, int contextEnd, boolean isRtl, int offset,
3510             @Nullable float[] advances, int advancesIndex) {
3511         return getRunCharacterAdvance(text, start, end, contextStart, contextEnd, isRtl, offset,
3512                 advances, advancesIndex, null, null);
3513     }
3514 
3515     /**
3516      * @see #getRunCharacterAdvance(char[], int, int, int, int, boolean, int, float[], int)
3517      *
3518      * @param text the text to measure. Cannot be null.
3519      * @param start the index of the start of the range to measure
3520      * @param end the index + 1 of the end of the range to measure
3521      * @param contextStart the index of the start of the shaping context
3522      * @param contextEnd the index + 1 of the end of the shaping context
3523      * @param isRtl whether the run is in RTL direction
3524      * @param offset index of caret position
3525      * @param advances the array that receives the computed character advances
3526      * @param advancesIndex the start index from which the advances array is filled
3527      * @param drawBounds the output parameter for the bounding box of drawing text, optional
3528      * @param runInfo an optional output parameter for filling run information.
3529      * @return width measurement between start and offset
3530      * @hide  TODO: Reorganize APIs
3531      */
getRunCharacterAdvance(@onNull CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds, @Nullable RunInfo runInfo)3532     public float getRunCharacterAdvance(@NonNull CharSequence text, int start, int end,
3533             int contextStart, int contextEnd, boolean isRtl, int offset,
3534             @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds,
3535             @Nullable RunInfo runInfo) {
3536         if (text == null) {
3537             throw new IllegalArgumentException("text cannot be null");
3538         }
3539         if (contextStart < 0 || contextEnd > text.length()) {
3540             throw new IndexOutOfBoundsException("Invalid Context Range: " + contextStart + ", "
3541                     + contextEnd + " must be in 0, " + text.length());
3542         }
3543 
3544         if (start < contextStart || contextEnd < end) {
3545             throw new IndexOutOfBoundsException("Invalid start/end range: " + start + ", " + end
3546                     + " must be in " + contextStart + ", " + contextEnd);
3547         }
3548 
3549         if (offset < start || end < offset) {
3550             throw new IndexOutOfBoundsException("Invalid offset position: " + offset
3551                     + " must be in " + start + ", " + end);
3552         }
3553 
3554         if (advances != null && advances.length < advancesIndex - start + end) {
3555             throw new IndexOutOfBoundsException("Given array doesn't have enough space to receive "
3556                     + "the result, advances.length: " + advances.length + " advanceIndex: "
3557                     + advancesIndex + " needed space: " + (offset - start));
3558         }
3559 
3560         if (end == start) {
3561             return 0.0f;
3562         }
3563 
3564         char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart);
3565         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
3566         final float result = getRunCharacterAdvance(buf, start - contextStart, end - contextStart,
3567                 0, contextEnd - contextStart, isRtl, offset - contextStart,
3568                 advances, advancesIndex, drawBounds, runInfo);
3569         TemporaryBuffer.recycle(buf);
3570         return result;
3571     }
3572 
3573     /**
3574      * Get the character offset within the string whose position is closest to the specified
3575      * horizontal position.
3576      *
3577      * <p>The returned value is generally the value of {@code offset} for which
3578      * {@link #getRunAdvance} yields a result most closely approximating {@code advance},
3579      * and which is also on a grapheme cluster boundary. As such, it is the preferred method
3580      * for positioning a cursor in response to a touch or pointer event. The grapheme cluster
3581      * boundaries are based on
3582      * <a href="http://unicode.org/reports/tr29/">Unicode Standard Annex #29</a> but with some
3583      * tailoring for better user experience.
3584      *
3585      * <p>Note that {@code advance} is a (generally positive) width measurement relative to the start
3586      * of the run. Thus, for RTL runs it the distance from the point to the right edge.
3587      *
3588      * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart
3589      * <= start <= end <= contextEnd <= text.length} must hold on entry, and {@code start <= result
3590      * <= end} will hold on return.
3591      *
3592      * @param text the text to measure. Cannot be null.
3593      * @param start the index of the start of the range to measure
3594      * @param end the index + 1 of the end of the range to measure
3595      * @param contextStart the index of the start of the shaping context
3596      * @param contextEnd the index + 1 of the end of the range to measure
3597      * @param isRtl whether the run is in RTL direction
3598      * @param advance width relative to start of run
3599      * @return index of offset
3600      */
getOffsetForAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)3601     public int getOffsetForAdvance(char[] text, int start, int end, int contextStart,
3602             int contextEnd, boolean isRtl, float advance) {
3603         if (text == null) {
3604             throw new IllegalArgumentException("text cannot be null");
3605         }
3606         if ((contextStart | start | end | contextEnd
3607                 | start - contextStart | end - start | contextEnd - end
3608                 | text.length - contextEnd) < 0) {
3609             throw new IndexOutOfBoundsException();
3610         }
3611         // TODO: take mCompatScaling into account (or eliminate compat scaling)?
3612         return nGetOffsetForAdvance(mNativePaint, text, start, end, contextStart, contextEnd,
3613                 isRtl, advance);
3614     }
3615 
3616     /**
3617      * @see #getOffsetForAdvance(char[], int, int, int, int, boolean, float)
3618      *
3619      * @param text the text to measure. Cannot be null.
3620      * @param start the index of the start of the range to measure
3621      * @param end the index + 1 of the end of the range to measure
3622      * @param contextStart the index of the start of the shaping context
3623      * @param contextEnd the index + 1 of the end of the range to measure
3624      * @param isRtl whether the run is in RTL direction
3625      * @param advance width relative to start of run
3626      * @return index of offset
3627      */
getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)3628     public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart,
3629             int contextEnd, boolean isRtl, float advance) {
3630         if (text == null) {
3631             throw new IllegalArgumentException("text cannot be null");
3632         }
3633         if ((contextStart | start | end | contextEnd
3634                 | start - contextStart | end - start | contextEnd - end
3635                 | text.length() - contextEnd) < 0) {
3636             throw new IndexOutOfBoundsException();
3637         }
3638         // TODO performance: specialized alternatives to avoid buffer copy, if win is significant
3639         char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart);
3640         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
3641         int result = getOffsetForAdvance(buf, start - contextStart, end - contextStart, 0,
3642                 contextEnd - contextStart, isRtl, advance) + contextStart;
3643         TemporaryBuffer.recycle(buf);
3644         return result;
3645     }
3646 
3647     /**
3648      * Returns true of the passed {@link Paint} will have the same effect on text measurement
3649      *
3650      * @param other A {@link Paint} object.
3651      * @return true if the other {@link Paint} has the same effect on text measurement.
3652      */
equalsForTextMeasurement(@onNull Paint other)3653     public boolean equalsForTextMeasurement(@NonNull Paint other) {
3654         return nEqualsForTextMeasurement(mNativePaint, other.mNativePaint);
3655     }
3656 
3657     // regular JNI
nGetNativeFinalizer()3658     private static native long nGetNativeFinalizer();
nInit()3659     private static native long nInit();
nInitWithPaint(long paint)3660     private static native long nInitWithPaint(long paint);
nBreakText(long nObject, char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth)3661     private static native int nBreakText(long nObject, char[] text, int index, int count,
3662             float maxWidth, int bidiFlags, float[] measuredWidth);
nBreakText(long nObject, String text, boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth)3663     private static native int nBreakText(long nObject, String text, boolean measureForwards,
3664             float maxWidth, int bidiFlags, float[] measuredWidth);
nGetTextAdvances(long paintPtr, char[] text, int index, int count, int contextIndex, int contextCount, int bidiFlags, float[] advances, int advancesIndex)3665     private static native float nGetTextAdvances(long paintPtr, char[] text, int index, int count,
3666             int contextIndex, int contextCount, int bidiFlags, float[] advances, int advancesIndex);
nGetTextAdvances(long paintPtr, String text, int start, int end, int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex)3667     private static native float nGetTextAdvances(long paintPtr, String text, int start, int end,
3668             int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex);
nGetTextRunCursor(long paintPtr, char[] text, int contextStart, int contextLength, int dir, int offset, int cursorOpt)3669     private native int nGetTextRunCursor(long paintPtr, char[] text, int contextStart,
3670             int contextLength, int dir, int offset, int cursorOpt);
nGetTextRunCursor(long paintPtr, String text, int contextStart, int contextEnd, int dir, int offset, int cursorOpt)3671     private native int nGetTextRunCursor(long paintPtr, String text, int contextStart,
3672             int contextEnd, int dir, int offset, int cursorOpt);
nGetTextPath(long paintPtr, int bidiFlags, char[] text, int index, int count, float x, float y, long path)3673     private static native void nGetTextPath(long paintPtr, int bidiFlags, char[] text, int index,
3674             int count, float x, float y, long path);
nGetTextPath(long paintPtr, int bidiFlags, String text, int start, int end, float x, float y, long path)3675     private static native void nGetTextPath(long paintPtr, int bidiFlags, String text, int start,
3676             int end, float x, float y, long path);
nGetStringBounds(long nativePaint, String text, int start, int end, int bidiFlags, Rect bounds)3677     private static native void nGetStringBounds(long nativePaint, String text, int start, int end,
3678             int bidiFlags, Rect bounds);
nGetCharArrayBounds(long nativePaint, char[] text, int index, int count, int bidiFlags, Rect bounds)3679     private static native void nGetCharArrayBounds(long nativePaint, char[] text, int index,
3680             int count, int bidiFlags, Rect bounds);
nHasGlyph(long paintPtr, int bidiFlags, String string)3681     private static native boolean nHasGlyph(long paintPtr, int bidiFlags, String string);
nGetRunAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)3682     private static native float nGetRunAdvance(long paintPtr, char[] text, int start, int end,
3683             int contextStart, int contextEnd, boolean isRtl, int offset);
nGetRunCharacterAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, float[] advances, int advancesIndex, RectF drawingBounds, RunInfo runInfo)3684     private static native float nGetRunCharacterAdvance(long paintPtr, char[] text, int start,
3685             int end, int contextStart, int contextEnd, boolean isRtl, int offset, float[] advances,
3686             int advancesIndex, RectF drawingBounds, RunInfo runInfo);
nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)3687     private static native int nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end,
3688             int contextStart, int contextEnd, boolean isRtl, float advance);
nGetFontMetricsIntForText(long paintPtr, char[] text, int start, int count, int ctxStart, int ctxCount, boolean isRtl, FontMetricsInt outMetrics)3689     private static native void nGetFontMetricsIntForText(long paintPtr, char[] text,
3690             int start, int count, int ctxStart, int ctxCount, boolean isRtl,
3691             FontMetricsInt outMetrics);
nGetFontMetricsIntForText(long paintPtr, String text, int start, int count, int ctxStart, int ctxCount, boolean isRtl, FontMetricsInt outMetrics)3692     private static native void nGetFontMetricsIntForText(long paintPtr, String text,
3693             int start, int count, int ctxStart, int ctxCount, boolean isRtl,
3694             FontMetricsInt outMetrics);
3695 
3696 
3697 
3698     // ---------------- @FastNative ------------------------
3699 
3700     @FastNative
nSetTextLocales(long paintPtr, String locales)3701     private static native int nSetTextLocales(long paintPtr, String locales);
3702     @FastNative
nSetFontFeatureSettings(long paintPtr, String settings)3703     private static native void nSetFontFeatureSettings(long paintPtr, String settings);
3704     @FastNative
nGetFontMetrics(long paintPtr, FontMetrics metrics, boolean useLocale)3705     private static native float nGetFontMetrics(long paintPtr, FontMetrics metrics,
3706             boolean useLocale);
3707     @FastNative
nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi, boolean useLocale)3708     private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi,
3709             boolean useLocale);
3710 
3711     // ---------------- @CriticalNative ------------------------
3712 
3713     @CriticalNative
nReset(long paintPtr)3714     private static native void nReset(long paintPtr);
3715     @CriticalNative
nSet(long paintPtrDest, long paintPtrSrc)3716     private static native void nSet(long paintPtrDest, long paintPtrSrc);
3717     @CriticalNative
nGetStyle(long paintPtr)3718     private static native int nGetStyle(long paintPtr);
3719     @CriticalNative
nSetStyle(long paintPtr, int style)3720     private static native void nSetStyle(long paintPtr, int style);
3721     @CriticalNative
nGetStrokeCap(long paintPtr)3722     private static native int nGetStrokeCap(long paintPtr);
3723     @CriticalNative
nSetStrokeCap(long paintPtr, int cap)3724     private static native void nSetStrokeCap(long paintPtr, int cap);
3725     @CriticalNative
nGetStrokeJoin(long paintPtr)3726     private static native int nGetStrokeJoin(long paintPtr);
3727     @CriticalNative
nSetStrokeJoin(long paintPtr, int join)3728     private static native void nSetStrokeJoin(long paintPtr, int join);
3729     @CriticalNative
nGetFillPath(long paintPtr, long src, long dst)3730     private static native boolean nGetFillPath(long paintPtr, long src, long dst);
3731     @CriticalNative
nSetShader(long paintPtr, long shader)3732     private static native long nSetShader(long paintPtr, long shader);
3733     @CriticalNative
nSetColorFilter(long paintPtr, long filter)3734     private static native long nSetColorFilter(long paintPtr, long filter);
3735     @CriticalNative
nSetXfermode(long paintPtr, int xfermode)3736     private static native void nSetXfermode(long paintPtr, int xfermode);
3737     @CriticalNative
nSetPathEffect(long paintPtr, long effect)3738     private static native long nSetPathEffect(long paintPtr, long effect);
3739     @CriticalNative
nSetMaskFilter(long paintPtr, long maskfilter)3740     private static native long nSetMaskFilter(long paintPtr, long maskfilter);
3741     @CriticalNative
nSetTypeface(long paintPtr, long typeface)3742     private static native void nSetTypeface(long paintPtr, long typeface);
3743     @CriticalNative
nGetTextAlign(long paintPtr)3744     private static native int nGetTextAlign(long paintPtr);
3745     @CriticalNative
nSetTextAlign(long paintPtr, int align)3746     private static native void nSetTextAlign(long paintPtr, int align);
3747     @CriticalNative
nSetTextLocalesByMinikinLocaleListId(long paintPtr, int mMinikinLocaleListId)3748     private static native void nSetTextLocalesByMinikinLocaleListId(long paintPtr,
3749             int mMinikinLocaleListId);
3750     @CriticalNative
nSetShadowLayer(long paintPtr, float radius, float dx, float dy, long colorSpaceHandle, @ColorLong long shadowColor)3751     private static native void nSetShadowLayer(long paintPtr,
3752             float radius, float dx, float dy, long colorSpaceHandle,
3753             @ColorLong long shadowColor);
3754     @CriticalNative
nHasShadowLayer(long paintPtr)3755     private static native boolean nHasShadowLayer(long paintPtr);
3756     @CriticalNative
nGetLetterSpacing(long paintPtr)3757     private static native float nGetLetterSpacing(long paintPtr);
3758     @CriticalNative
nSetLetterSpacing(long paintPtr, float letterSpacing)3759     private static native void nSetLetterSpacing(long paintPtr, float letterSpacing);
3760     @CriticalNative
nGetWordSpacing(long paintPtr)3761     private static native float nGetWordSpacing(long paintPtr);
3762     @CriticalNative
nSetWordSpacing(long paintPtr, float wordSpacing)3763     private static native void nSetWordSpacing(long paintPtr, float wordSpacing);
3764     @CriticalNative
nGetStartHyphenEdit(long paintPtr)3765     private static native int nGetStartHyphenEdit(long paintPtr);
3766     @CriticalNative
nGetEndHyphenEdit(long paintPtr)3767     private static native int nGetEndHyphenEdit(long paintPtr);
3768     @CriticalNative
nSetStartHyphenEdit(long paintPtr, int hyphen)3769     private static native void nSetStartHyphenEdit(long paintPtr, int hyphen);
3770     @CriticalNative
nSetEndHyphenEdit(long paintPtr, int hyphen)3771     private static native void nSetEndHyphenEdit(long paintPtr, int hyphen);
3772     @CriticalNative
nSetStrokeMiter(long paintPtr, float miter)3773     private static native void nSetStrokeMiter(long paintPtr, float miter);
3774     @CriticalNative
nGetStrokeMiter(long paintPtr)3775     private static native float nGetStrokeMiter(long paintPtr);
3776     @CriticalNative
nSetStrokeWidth(long paintPtr, float width)3777     private static native void nSetStrokeWidth(long paintPtr, float width);
3778     @CriticalNative
nGetStrokeWidth(long paintPtr)3779     private static native float nGetStrokeWidth(long paintPtr);
3780     @CriticalNative
nSetAlpha(long paintPtr, int a)3781     private static native void nSetAlpha(long paintPtr, int a);
3782     @CriticalNative
nSetDither(long paintPtr, boolean dither)3783     private static native void nSetDither(long paintPtr, boolean dither);
3784     @CriticalNative
nGetFlags(long paintPtr)3785     private static native int nGetFlags(long paintPtr);
3786     @CriticalNative
nSetFlags(long paintPtr, int flags)3787     private static native void nSetFlags(long paintPtr, int flags);
3788     @CriticalNative
nGetHinting(long paintPtr)3789     private static native int nGetHinting(long paintPtr);
3790     @CriticalNative
nSetHinting(long paintPtr, int mode)3791     private static native void nSetHinting(long paintPtr, int mode);
3792     @CriticalNative
nSetAntiAlias(long paintPtr, boolean aa)3793     private static native void nSetAntiAlias(long paintPtr, boolean aa);
3794     @CriticalNative
nSetLinearText(long paintPtr, boolean linearText)3795     private static native void nSetLinearText(long paintPtr, boolean linearText);
3796     @CriticalNative
nSetSubpixelText(long paintPtr, boolean subpixelText)3797     private static native void nSetSubpixelText(long paintPtr, boolean subpixelText);
3798     @CriticalNative
nSetUnderlineText(long paintPtr, boolean underlineText)3799     private static native void nSetUnderlineText(long paintPtr, boolean underlineText);
3800     @CriticalNative
nSetFakeBoldText(long paintPtr, boolean fakeBoldText)3801     private static native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
3802     @CriticalNative
nSetFilterBitmap(long paintPtr, boolean filter)3803     private static native void nSetFilterBitmap(long paintPtr, boolean filter);
3804     @CriticalNative
nSetColor(long paintPtr, long colorSpaceHandle, @ColorLong long color)3805     private static native void nSetColor(long paintPtr, long colorSpaceHandle,
3806             @ColorLong long color);
3807     @CriticalNative
nSetColor(long paintPtr, @ColorInt int color)3808     private static native void nSetColor(long paintPtr, @ColorInt int color);
3809     @CriticalNative
nSetStrikeThruText(long paintPtr, boolean strikeThruText)3810     private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
3811     @CriticalNative
nGetElegantTextHeight(long paintPtr)3812     private static native int nGetElegantTextHeight(long paintPtr);
3813     @CriticalNative
nSetElegantTextHeight(long paintPtr, int elegant)3814     private static native void nSetElegantTextHeight(long paintPtr, int elegant);
3815     @CriticalNative
nGetTextSize(long paintPtr)3816     private static native float nGetTextSize(long paintPtr);
3817     @CriticalNative
nGetTextScaleX(long paintPtr)3818     private static native float nGetTextScaleX(long paintPtr);
3819     @CriticalNative
nSetTextScaleX(long paintPtr, float scaleX)3820     private static native void nSetTextScaleX(long paintPtr, float scaleX);
3821     @CriticalNative
nGetTextSkewX(long paintPtr)3822     private static native float nGetTextSkewX(long paintPtr);
3823     @CriticalNative
nSetTextSkewX(long paintPtr, float skewX)3824     private static native void nSetTextSkewX(long paintPtr, float skewX);
3825     @CriticalNative
nAscent(long paintPtr)3826     private static native float nAscent(long paintPtr);
3827     @CriticalNative
nDescent(long paintPtr)3828     private static native float nDescent(long paintPtr);
3829     @CriticalNative
nGetUnderlinePosition(long paintPtr)3830     private static native float nGetUnderlinePosition(long paintPtr);
3831     @CriticalNative
nGetUnderlineThickness(long paintPtr)3832     private static native float nGetUnderlineThickness(long paintPtr);
3833     @CriticalNative
nGetStrikeThruPosition(long paintPtr)3834     private static native float nGetStrikeThruPosition(long paintPtr);
3835     @CriticalNative
nGetStrikeThruThickness(long paintPtr)3836     private static native float nGetStrikeThruThickness(long paintPtr);
3837     @CriticalNative
nSetTextSize(long paintPtr, float textSize)3838     private static native void nSetTextSize(long paintPtr, float textSize);
3839     @CriticalNative
nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr)3840     private static native boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr);
3841 
3842 
3843     // Following Native methods are kept for old Robolectric JNI signature used by
3844     // SystemUIGoogleRoboRNGTests
nGetRunCharacterAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, float[] advances, int advancesIndex, RectF drawingBounds)3845     private static native float nGetRunCharacterAdvance(long paintPtr, char[] text,
3846             int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset,
3847             float[] advances, int advancesIndex, RectF drawingBounds);
3848 }
3849