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