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