• 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.ni(), dst.ni());
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.ni());
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.ni());
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