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