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