• 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.text.GraphicsOperations;
20 import android.text.SpannableString;
21 import android.text.SpannedString;
22 import android.text.TextUtils;
23 
24 import java.util.Locale;
25 
26 /**
27  * The Paint class holds the style and color information about how to draw
28  * geometries, text and bitmaps.
29  */
30 public class Paint {
31 
32     /**
33      * @hide
34      */
35     public int mNativePaint;
36 
37     private ColorFilter mColorFilter;
38     private MaskFilter  mMaskFilter;
39     private PathEffect  mPathEffect;
40     private Rasterizer  mRasterizer;
41     private Shader      mShader;
42     private Typeface    mTypeface;
43     private Xfermode    mXfermode;
44 
45     private boolean     mHasCompatScaling;
46     private float       mCompatScaling;
47     private float       mInvCompatScaling;
48 
49     private Locale      mLocale;
50 
51     /**
52      * @hide
53      */
54     public boolean hasShadow;
55     /**
56      * @hide
57      */
58     public float shadowDx;
59     /**
60      * @hide
61      */
62     public float shadowDy;
63     /**
64      * @hide
65      */
66     public float shadowRadius;
67     /**
68      * @hide
69      */
70     public int shadowColor;
71 
72     /**
73      * @hide
74      */
75     public  int         mBidiFlags = BIDI_DEFAULT_LTR;
76 
77     static final Style[] sStyleArray = {
78         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
79     };
80     static final Cap[] sCapArray = {
81         Cap.BUTT, Cap.ROUND, Cap.SQUARE
82     };
83     static final Join[] sJoinArray = {
84         Join.MITER, Join.ROUND, Join.BEVEL
85     };
86     static final Align[] sAlignArray = {
87         Align.LEFT, Align.CENTER, Align.RIGHT
88     };
89 
90     /**
91      * Paint flag that enables antialiasing when drawing.
92      *
93      * <p>Enabling this flag will cause all draw operations that support
94      * antialiasing to use it.</p>
95      *
96      * @see #Paint(int)
97      * @see #setFlags(int)
98      */
99     public static final int ANTI_ALIAS_FLAG     = 0x01;
100     /**
101      * Paint flag that enables bilinear sampling on scaled bitmaps.
102      *
103      * <p>If cleared, scaled bitmaps will be drawn with nearest neighbor
104      * sampling, likely resulting in artifacts. This should generally be on
105      * when drawing bitmaps, unless performance-bound (rendering to software
106      * canvas) or preferring pixelation artifacts to blurriness when scaling
107      * significantly.</p>
108      *
109      * <p>If bitmaps are scaled for device density at creation time (as
110      * resource bitmaps often are) the filtering will already have been
111      * done.</p>
112      *
113      * @see #Paint(int)
114      * @see #setFlags(int)
115      */
116     public static final int FILTER_BITMAP_FLAG  = 0x02;
117     /**
118      * Paint flag that enables dithering when blitting.
119      *
120      * <p>Enabling this flag applies a dither to any blit operation where the
121      * target's colour space is more constrained than the source.
122      *
123      * @see #Paint(int)
124      * @see #setFlags(int)
125      */
126     public static final int DITHER_FLAG         = 0x04;
127     /**
128      * Paint flag that applies an underline decoration to drawn text.
129      *
130      * @see #Paint(int)
131      * @see #setFlags(int)
132      */
133     public static final int UNDERLINE_TEXT_FLAG = 0x08;
134     /**
135      * Paint flag that applies a strike-through decoration to drawn text.
136      *
137      * @see #Paint(int)
138      * @see #setFlags(int)
139      */
140     public static final int STRIKE_THRU_TEXT_FLAG = 0x10;
141     /**
142      * Paint flag that applies a synthetic bolding effect to drawn text.
143      *
144      * <p>Enabling this flag will cause text draw operations to apply a
145      * simulated bold effect when drawing a {@link Typeface} that is not
146      * already bold.</p>
147      *
148      * @see #Paint(int)
149      * @see #setFlags(int)
150      */
151     public static final int FAKE_BOLD_TEXT_FLAG = 0x20;
152     /**
153      * Paint flag that enables smooth linear scaling of text.
154      *
155      * <p>Enabling this flag does not actually scale text, but rather adjusts
156      * text draw operations to deal gracefully with smooth adjustment of scale.
157      * When this flag is enabled, font hinting is disabled to prevent shape
158      * deformation between scale factors, and glyph caching is disabled due to
159      * the large number of glyph images that will be generated.</p>
160      *
161      * <p>{@link #SUBPIXEL_TEXT_FLAG} should be used in conjunction with this
162      * flag to prevent glyph positions from snapping to whole pixel values as
163      * scale factor is adjusted.</p>
164      *
165      * @see #Paint(int)
166      * @see #setFlags(int)
167      */
168     public static final int LINEAR_TEXT_FLAG    = 0x40;
169     /**
170      * Paint flag that enables subpixel positioning of text.
171      *
172      * <p>Enabling this flag causes glyph advances to be computed with subpixel
173      * accuracy.</p>
174      *
175      * <p>This can be used with {@link #LINEAR_TEXT_FLAG} to prevent text from
176      * jittering during smooth scale transitions.</p>
177      *
178      * @see #Paint(int)
179      * @see #setFlags(int)
180      */
181     public static final int SUBPIXEL_TEXT_FLAG  = 0x80;
182     /** Legacy Paint flag, no longer used. */
183     public static final int DEV_KERN_TEXT_FLAG  = 0x100;
184     /** @hide bit mask for the flag enabling subpixel glyph rendering for text */
185     public static final int LCD_RENDER_TEXT_FLAG = 0x200;
186     /**
187      * Paint flag that enables the use of bitmap fonts when drawing text.
188      *
189      * <p>Disabling this flag will prevent text draw operations from using
190      * embedded bitmap strikes in fonts, causing fonts with both scalable
191      * outlines and bitmap strikes to draw only the scalable outlines, and
192      * fonts with only bitmap strikes to not draw at all.</p>
193      *
194      * @see #Paint(int)
195      * @see #setFlags(int)
196      */
197     public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400;
198     /** @hide bit mask for the flag forcing freetype's autohinter on for text */
199     public static final int AUTO_HINTING_TEXT_FLAG = 0x800;
200     /** @hide bit mask for the flag enabling vertical rendering for text */
201     public static final int VERTICAL_TEXT_FLAG = 0x1000;
202 
203     // we use this when we first create a paint
204     static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG;
205 
206     /**
207      * Font hinter option that disables font hinting.
208      *
209      * @see #setHinting(int)
210      */
211     public static final int HINTING_OFF = 0x0;
212 
213     /**
214      * Font hinter option that enables font hinting.
215      *
216      * @see #setHinting(int)
217      */
218     public static final int HINTING_ON = 0x1;
219 
220     /**
221      * Bidi flag to set LTR paragraph direction.
222      *
223      * @hide
224      */
225     public static final int BIDI_LTR = 0x0;
226 
227     /**
228      * Bidi flag to set RTL paragraph direction.
229      *
230      * @hide
231      */
232     public static final int BIDI_RTL = 0x1;
233 
234     /**
235      * Bidi flag to detect paragraph direction via heuristics, defaulting to
236      * LTR.
237      *
238      * @hide
239      */
240     public static final int BIDI_DEFAULT_LTR = 0x2;
241 
242     /**
243      * Bidi flag to detect paragraph direction via heuristics, defaulting to
244      * RTL.
245      *
246      * @hide
247      */
248     public static final int BIDI_DEFAULT_RTL = 0x3;
249 
250     /**
251      * Bidi flag to override direction to all LTR (ignore bidi).
252      *
253      * @hide
254      */
255     public static final int BIDI_FORCE_LTR = 0x4;
256 
257     /**
258      * Bidi flag to override direction to all RTL (ignore bidi).
259      *
260      * @hide
261      */
262     public static final int BIDI_FORCE_RTL = 0x5;
263 
264     /**
265      * Maximum Bidi flag value.
266      * @hide
267      */
268     private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
269 
270     /**
271      * Mask for bidi flags.
272      * @hide
273      */
274     private static final int BIDI_FLAG_MASK = 0x7;
275 
276     /**
277      * Flag for getTextRunAdvances indicating left-to-right run direction.
278      * @hide
279      */
280     public static final int DIRECTION_LTR = 0;
281 
282     /**
283      * Flag for getTextRunAdvances indicating right-to-left run direction.
284      * @hide
285      */
286     public static final int DIRECTION_RTL = 1;
287 
288     /**
289      * Option for getTextRunCursor to compute the valid cursor after
290      * offset or the limit of the context, whichever is less.
291      * @hide
292      */
293     public static final int CURSOR_AFTER = 0;
294 
295     /**
296      * Option for getTextRunCursor to compute the valid cursor at or after
297      * the offset or the limit of the context, whichever is less.
298      * @hide
299      */
300     public static final int CURSOR_AT_OR_AFTER = 1;
301 
302      /**
303      * Option for getTextRunCursor to compute the valid cursor before
304      * offset or the start of the context, whichever is greater.
305      * @hide
306      */
307     public static final int CURSOR_BEFORE = 2;
308 
309    /**
310      * Option for getTextRunCursor to compute the valid cursor at or before
311      * offset or the start of the context, whichever is greater.
312      * @hide
313      */
314     public static final int CURSOR_AT_OR_BEFORE = 3;
315 
316     /**
317      * Option for getTextRunCursor to return offset if the cursor at offset
318      * is valid, or -1 if it isn't.
319      * @hide
320      */
321     public static final int CURSOR_AT = 4;
322 
323     /**
324      * Maximum cursor option value.
325      */
326     private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT;
327 
328     /**
329      * The Style specifies if the primitive being drawn is filled, stroked, or
330      * both (in the same color). The default is FILL.
331      */
332     public enum Style {
333         /**
334          * Geometry and text drawn with this style will be filled, ignoring all
335          * stroke-related settings in the paint.
336          */
337         FILL            (0),
338         /**
339          * Geometry and text drawn with this style will be stroked, respecting
340          * the stroke-related fields on the paint.
341          */
342         STROKE          (1),
343         /**
344          * Geometry and text drawn with this style will be both filled and
345          * stroked at the same time, respecting the stroke-related fields on
346          * the paint. This mode can give unexpected results if the geometry
347          * is oriented counter-clockwise. This restriction does not apply to
348          * either FILL or STROKE.
349          */
350         FILL_AND_STROKE (2);
351 
Style(int nativeInt)352         Style(int nativeInt) {
353             this.nativeInt = nativeInt;
354         }
355         final int nativeInt;
356     }
357 
358     /**
359      * The Cap specifies the treatment for the beginning and ending of
360      * stroked lines and paths. The default is BUTT.
361      */
362     public enum Cap {
363         /**
364          * The stroke ends with the path, and does not project beyond it.
365          */
366         BUTT    (0),
367         /**
368          * The stroke projects out as a semicircle, with the center at the
369          * end of the path.
370          */
371         ROUND   (1),
372         /**
373          * The stroke projects out as a square, with the center at the end
374          * of the path.
375          */
376         SQUARE  (2);
377 
Cap(int nativeInt)378         private Cap(int nativeInt) {
379             this.nativeInt = nativeInt;
380         }
381         final int nativeInt;
382     }
383 
384     /**
385      * The Join specifies the treatment where lines and curve segments
386      * join on a stroked path. The default is MITER.
387      */
388     public enum Join {
389         /**
390          * The outer edges of a join meet at a sharp angle
391          */
392         MITER   (0),
393         /**
394          * The outer edges of a join meet in a circular arc.
395          */
396         ROUND   (1),
397         /**
398          * The outer edges of a join meet with a straight line
399          */
400         BEVEL   (2);
401 
Join(int nativeInt)402         private Join(int nativeInt) {
403             this.nativeInt = nativeInt;
404         }
405         final int nativeInt;
406     }
407 
408     /**
409      * Align specifies how drawText aligns its text relative to the
410      * [x,y] coordinates. The default is LEFT.
411      */
412     public enum Align {
413         /**
414          * The text is drawn to the right of the x,y origin
415          */
416         LEFT    (0),
417         /**
418          * The text is drawn centered horizontally on the x,y origin
419          */
420         CENTER  (1),
421         /**
422          * The text is drawn to the left of the x,y origin
423          */
424         RIGHT   (2);
425 
Align(int nativeInt)426         private Align(int nativeInt) {
427             this.nativeInt = nativeInt;
428         }
429         final int nativeInt;
430     }
431 
432     /**
433      * Create a new paint with default settings.
434      */
Paint()435     public Paint() {
436         this(0);
437     }
438 
439     /**
440      * Create a new paint with the specified flags. Use setFlags() to change
441      * these after the paint is created.
442      *
443      * @param flags initial flag bits, as if they were passed via setFlags().
444      */
Paint(int flags)445     public Paint(int flags) {
446         mNativePaint = native_init();
447         setFlags(flags | DEFAULT_PAINT_FLAGS);
448         // TODO: Turning off hinting has undesirable side effects, we need to
449         //       revisit hinting once we add support for subpixel positioning
450         // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
451         //        ? HINTING_OFF : HINTING_ON);
452         mCompatScaling = mInvCompatScaling = 1;
453         setTextLocale(Locale.getDefault());
454     }
455 
456     /**
457      * Create a new paint, initialized with the attributes in the specified
458      * paint parameter.
459      *
460      * @param paint Existing paint used to initialized the attributes of the
461      *              new paint.
462      */
Paint(Paint paint)463     public Paint(Paint paint) {
464         mNativePaint = native_initWithPaint(paint.mNativePaint);
465         setClassVariablesFrom(paint);
466     }
467 
468     /** Restores the paint to its default settings. */
reset()469     public void reset() {
470         native_reset(mNativePaint);
471         setFlags(DEFAULT_PAINT_FLAGS);
472 
473         // TODO: Turning off hinting has undesirable side effects, we need to
474         //       revisit hinting once we add support for subpixel positioning
475         // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
476         //        ? HINTING_OFF : HINTING_ON);
477 
478         mColorFilter = null;
479         mMaskFilter = null;
480         mPathEffect = null;
481         mRasterizer = null;
482         mShader = null;
483         mTypeface = null;
484         mXfermode = null;
485 
486         mHasCompatScaling = false;
487         mCompatScaling = 1;
488         mInvCompatScaling = 1;
489 
490         hasShadow = false;
491         shadowDx = 0;
492         shadowDy = 0;
493         shadowRadius = 0;
494         shadowColor = 0;
495 
496         mBidiFlags = BIDI_DEFAULT_LTR;
497         setTextLocale(Locale.getDefault());
498     }
499 
500     /**
501      * Copy the fields from src into this paint. This is equivalent to calling
502      * get() on all of the src fields, and calling the corresponding set()
503      * methods on this.
504      */
set(Paint src)505     public void set(Paint src) {
506         if (this != src) {
507             // copy over the native settings
508             native_set(mNativePaint, src.mNativePaint);
509             setClassVariablesFrom(src);
510         }
511     }
512 
513     /**
514      * Set all class variables using current values from the given
515      * {@link Paint}.
516      */
setClassVariablesFrom(Paint paint)517     private void setClassVariablesFrom(Paint paint) {
518         mColorFilter = paint.mColorFilter;
519         mMaskFilter = paint.mMaskFilter;
520         mPathEffect = paint.mPathEffect;
521         mRasterizer = paint.mRasterizer;
522         if (paint.mShader != null) {
523             mShader = paint.mShader.copy();
524         } else {
525             mShader = null;
526         }
527         mTypeface = paint.mTypeface;
528         mXfermode = paint.mXfermode;
529 
530         mHasCompatScaling = paint.mHasCompatScaling;
531         mCompatScaling = paint.mCompatScaling;
532         mInvCompatScaling = paint.mInvCompatScaling;
533 
534         hasShadow = paint.hasShadow;
535         shadowDx = paint.shadowDx;
536         shadowDy = paint.shadowDy;
537         shadowRadius = paint.shadowRadius;
538         shadowColor = paint.shadowColor;
539 
540         mBidiFlags = paint.mBidiFlags;
541         mLocale = paint.mLocale;
542     }
543 
544     /** @hide */
setCompatibilityScaling(float factor)545     public void setCompatibilityScaling(float factor) {
546         if (factor == 1.0) {
547             mHasCompatScaling = false;
548             mCompatScaling = mInvCompatScaling = 1.0f;
549         } else {
550             mHasCompatScaling = true;
551             mCompatScaling = factor;
552             mInvCompatScaling = 1.0f/factor;
553         }
554     }
555 
556     /**
557      * Return the bidi flags on the paint.
558      *
559      * @return the bidi flags on the paint
560      * @hide
561      */
getBidiFlags()562     public int getBidiFlags() {
563         return mBidiFlags;
564     }
565 
566     /**
567      * Set the bidi flags on the paint.
568      * @hide
569      */
setBidiFlags(int flags)570     public void setBidiFlags(int flags) {
571         // only flag value is the 3-bit BIDI control setting
572         flags &= BIDI_FLAG_MASK;
573         if (flags > BIDI_MAX_FLAG_VALUE) {
574             throw new IllegalArgumentException("unknown bidi flag: " + flags);
575         }
576         mBidiFlags = flags;
577     }
578 
579     /**
580      * Return the paint's flags. Use the Flag enum to test flag values.
581      *
582      * @return the paint's flags (see enums ending in _Flag for bit masks)
583      */
getFlags()584     public native int getFlags();
585 
586     /**
587      * Set the paint's flags. Use the Flag enum to specific flag values.
588      *
589      * @param flags The new flag bits for the paint
590      */
setFlags(int flags)591     public native void setFlags(int flags);
592 
593     /**
594      * Return the paint's hinting mode.  Returns either
595      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
596      */
getHinting()597     public native int getHinting();
598 
599     /**
600      * Set the paint's hinting mode.  May be either
601      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
602      */
setHinting(int mode)603     public native void setHinting(int mode);
604 
605     /**
606      * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
607      * AntiAliasing smooths out the edges of what is being drawn, but is has
608      * no impact on the interior of the shape. See setDither() and
609      * setFilterBitmap() to affect how colors are treated.
610      *
611      * @return true if the antialias bit is set in the paint's flags.
612      */
isAntiAlias()613     public final boolean isAntiAlias() {
614         return (getFlags() & ANTI_ALIAS_FLAG) != 0;
615     }
616 
617     /**
618      * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
619      * AntiAliasing smooths out the edges of what is being drawn, but is has
620      * no impact on the interior of the shape. See setDither() and
621      * setFilterBitmap() to affect how colors are treated.
622      *
623      * @param aa true to set the antialias bit in the flags, false to clear it
624      */
setAntiAlias(boolean aa)625     public native void setAntiAlias(boolean aa);
626 
627     /**
628      * Helper for getFlags(), returning true if DITHER_FLAG bit is set
629      * Dithering affects how colors that are higher precision than the device
630      * are down-sampled. No dithering is generally faster, but higher precision
631      * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
632      * distribute the error inherent in this process, to reduce the visual
633      * artifacts.
634      *
635      * @return true if the dithering bit is set in the paint's flags.
636      */
isDither()637     public final boolean isDither() {
638         return (getFlags() & DITHER_FLAG) != 0;
639     }
640 
641     /**
642      * Helper for setFlags(), setting or clearing the DITHER_FLAG bit
643      * Dithering affects how colors that are higher precision than the device
644      * are down-sampled. No dithering is generally faster, but higher precision
645      * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
646      * distribute the error inherent in this process, to reduce the visual
647      * artifacts.
648      *
649      * @param dither true to set the dithering bit in flags, false to clear it
650      */
setDither(boolean dither)651     public native void setDither(boolean dither);
652 
653     /**
654      * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
655      *
656      * @return true if the lineartext bit is set in the paint's flags
657      */
isLinearText()658     public final boolean isLinearText() {
659         return (getFlags() & LINEAR_TEXT_FLAG) != 0;
660     }
661 
662     /**
663      * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit
664      *
665      * @param linearText true to set the linearText bit in the paint's flags,
666      *                   false to clear it.
667      */
setLinearText(boolean linearText)668     public native void setLinearText(boolean linearText);
669 
670     /**
671      * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
672      *
673      * @return true if the subpixel bit is set in the paint's flags
674      */
isSubpixelText()675     public final boolean isSubpixelText() {
676         return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
677     }
678 
679     /**
680      * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
681      *
682      * @param subpixelText true to set the subpixelText bit in the paint's
683      *                     flags, false to clear it.
684      */
setSubpixelText(boolean subpixelText)685     public native void setSubpixelText(boolean subpixelText);
686 
687     /**
688      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
689      *
690      * @return true if the underlineText bit is set in the paint's flags.
691      */
isUnderlineText()692     public final boolean isUnderlineText() {
693         return (getFlags() & UNDERLINE_TEXT_FLAG) != 0;
694     }
695 
696     /**
697      * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit
698      *
699      * @param underlineText true to set the underlineText bit in the paint's
700      *                      flags, false to clear it.
701      */
setUnderlineText(boolean underlineText)702     public native void setUnderlineText(boolean underlineText);
703 
704     /**
705      * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
706      *
707      * @return true if the strikeThruText bit is set in the paint's flags.
708      */
isStrikeThruText()709     public final boolean isStrikeThruText() {
710         return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0;
711     }
712 
713     /**
714      * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
715      *
716      * @param strikeThruText true to set the strikeThruText bit in the paint's
717      *                       flags, false to clear it.
718      */
setStrikeThruText(boolean strikeThruText)719     public native void setStrikeThruText(boolean strikeThruText);
720 
721     /**
722      * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
723      *
724      * @return true if the fakeBoldText bit is set in the paint's flags.
725      */
isFakeBoldText()726     public final boolean isFakeBoldText() {
727         return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0;
728     }
729 
730     /**
731      * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit
732      *
733      * @param fakeBoldText true to set the fakeBoldText bit in the paint's
734      *                     flags, false to clear it.
735      */
setFakeBoldText(boolean fakeBoldText)736     public native void setFakeBoldText(boolean fakeBoldText);
737 
738     /**
739      * Whether or not the bitmap filter is activated.
740      * Filtering affects the sampling of bitmaps when they are transformed.
741      * Filtering does not affect how the colors in the bitmap are converted into
742      * device pixels. That is dependent on dithering and xfermodes.
743      *
744      * @see #setFilterBitmap(boolean) setFilterBitmap()
745      */
isFilterBitmap()746     public final boolean isFilterBitmap() {
747         return (getFlags() & FILTER_BITMAP_FLAG) != 0;
748     }
749 
750     /**
751      * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
752      * Filtering affects the sampling of bitmaps when they are transformed.
753      * Filtering does not affect how the colors in the bitmap are converted into
754      * device pixels. That is dependent on dithering and xfermodes.
755      *
756      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
757      *               flags, false to clear it.
758      */
setFilterBitmap(boolean filter)759     public native void setFilterBitmap(boolean filter);
760 
761     /**
762      * Return the paint's style, used for controlling how primitives'
763      * geometries are interpreted (except for drawBitmap, which always assumes
764      * FILL_STYLE).
765      *
766      * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
767      */
getStyle()768     public Style getStyle() {
769         return sStyleArray[native_getStyle(mNativePaint)];
770     }
771 
772     /**
773      * Set the paint's style, used for controlling how primitives'
774      * geometries are interpreted (except for drawBitmap, which always assumes
775      * Fill).
776      *
777      * @param style The new style to set in the paint
778      */
setStyle(Style style)779     public void setStyle(Style style) {
780         native_setStyle(mNativePaint, style.nativeInt);
781     }
782 
783     /**
784      * Return the paint's color. Note that the color is a 32bit value
785      * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
786      * meaning that its alpha can be any value, regardless of the values of
787      * r,g,b. See the Color class for more details.
788      *
789      * @return the paint's color (and alpha).
790      */
getColor()791     public native int getColor();
792 
793     /**
794      * Set the paint's color. Note that the color is an int containing alpha
795      * as well as r,g,b. This 32bit value is not premultiplied, meaning that
796      * its alpha can be any value, regardless of the values of r,g,b.
797      * See the Color class for more details.
798      *
799      * @param color The new color (including alpha) to set in the paint.
800      */
setColor(int color)801     public native void setColor(int color);
802 
803     /**
804      * Helper to getColor() that just returns the color's alpha value. This is
805      * the same as calling getColor() >>> 24. It always returns a value between
806      * 0 (completely transparent) and 255 (completely opaque).
807      *
808      * @return the alpha component of the paint's color.
809      */
getAlpha()810     public native int getAlpha();
811 
812     /**
813      * Helper to setColor(), that only assigns the color's alpha value,
814      * leaving its r,g,b values unchanged. Results are undefined if the alpha
815      * value is outside of the range [0..255]
816      *
817      * @param a set the alpha component [0..255] of the paint's color.
818      */
setAlpha(int a)819     public native void setAlpha(int a);
820 
821     /**
822      * Helper to setColor(), that takes a,r,g,b and constructs the color int
823      *
824      * @param a The new alpha component (0..255) of the paint's color.
825      * @param r The new red component (0..255) of the paint's color.
826      * @param g The new green component (0..255) of the paint's color.
827      * @param b The new blue component (0..255) of the paint's color.
828      */
setARGB(int a, int r, int g, int b)829     public void setARGB(int a, int r, int g, int b) {
830         setColor((a << 24) | (r << 16) | (g << 8) | b);
831     }
832 
833     /**
834      * Return the width for stroking.
835      * <p />
836      * A value of 0 strokes in hairline mode.
837      * Hairlines always draws a single pixel independent of the canva's matrix.
838      *
839      * @return the paint's stroke width, used whenever the paint's style is
840      *         Stroke or StrokeAndFill.
841      */
getStrokeWidth()842     public native float getStrokeWidth();
843 
844     /**
845      * Set the width for stroking.
846      * Pass 0 to stroke in hairline mode.
847      * Hairlines always draws a single pixel independent of the canva's matrix.
848      *
849      * @param width set the paint's stroke width, used whenever the paint's
850      *              style is Stroke or StrokeAndFill.
851      */
setStrokeWidth(float width)852     public native void setStrokeWidth(float width);
853 
854     /**
855      * Return the paint's stroke miter value. Used to control the behavior
856      * of miter joins when the joins angle is sharp.
857      *
858      * @return the paint's miter limit, used whenever the paint's style is
859      *         Stroke or StrokeAndFill.
860      */
getStrokeMiter()861     public native float getStrokeMiter();
862 
863     /**
864      * Set the paint's stroke miter value. This is used to control the behavior
865      * of miter joins when the joins angle is sharp. This value must be >= 0.
866      *
867      * @param miter set the miter limit on the paint, used whenever the paint's
868      *              style is Stroke or StrokeAndFill.
869      */
setStrokeMiter(float miter)870     public native void setStrokeMiter(float miter);
871 
872     /**
873      * Return the paint's Cap, controlling how the start and end of stroked
874      * lines and paths are treated.
875      *
876      * @return the line cap style for the paint, used whenever the paint's
877      *         style is Stroke or StrokeAndFill.
878      */
getStrokeCap()879     public Cap getStrokeCap() {
880         return sCapArray[native_getStrokeCap(mNativePaint)];
881     }
882 
883     /**
884      * Set the paint's Cap.
885      *
886      * @param cap set the paint's line cap style, used whenever the paint's
887      *            style is Stroke or StrokeAndFill.
888      */
setStrokeCap(Cap cap)889     public void setStrokeCap(Cap cap) {
890         native_setStrokeCap(mNativePaint, cap.nativeInt);
891     }
892 
893     /**
894      * Return the paint's stroke join type.
895      *
896      * @return the paint's Join.
897      */
getStrokeJoin()898     public Join getStrokeJoin() {
899         return sJoinArray[native_getStrokeJoin(mNativePaint)];
900     }
901 
902     /**
903      * Set the paint's Join.
904      *
905      * @param join set the paint's Join, used whenever the paint's style is
906      *             Stroke or StrokeAndFill.
907      */
setStrokeJoin(Join join)908     public void setStrokeJoin(Join join) {
909         native_setStrokeJoin(mNativePaint, join.nativeInt);
910     }
911 
912     /**
913      * Applies any/all effects (patheffect, stroking) to src, returning the
914      * result in dst. The result is that drawing src with this paint will be
915      * the same as drawing dst with a default paint (at least from the
916      * geometric perspective).
917      *
918      * @param src input path
919      * @param dst output path (may be the same as src)
920      * @return    true if the path should be filled, or false if it should be
921      *                 drawn with a hairline (width == 0)
922      */
getFillPath(Path src, Path dst)923     public boolean getFillPath(Path src, Path dst) {
924         return native_getFillPath(mNativePaint, src.ni(), dst.ni());
925     }
926 
927     /**
928      * Get the paint's shader object.
929      *
930      * @return the paint's shader (or null)
931      */
getShader()932     public Shader getShader() {
933         return mShader;
934     }
935 
936     /**
937      * Set or clear the shader object.
938      * <p />
939      * Pass null to clear any previous shader.
940      * As a convenience, the parameter passed is also returned.
941      *
942      * @param shader May be null. the new shader to be installed in the paint
943      * @return       shader
944      */
setShader(Shader shader)945     public Shader setShader(Shader shader) {
946         int shaderNative = 0;
947         if (shader != null)
948             shaderNative = shader.native_instance;
949         native_setShader(mNativePaint, shaderNative);
950         mShader = shader;
951         return shader;
952     }
953 
954     /**
955      * Get the paint's colorfilter (maybe be null).
956      *
957      * @return the paint's colorfilter (maybe be null)
958      */
getColorFilter()959     public ColorFilter getColorFilter() {
960         return mColorFilter;
961     }
962 
963     /**
964      * Set or clear the paint's colorfilter, returning the parameter.
965      *
966      * @param filter May be null. The new filter to be installed in the paint
967      * @return       filter
968      */
setColorFilter(ColorFilter filter)969     public ColorFilter setColorFilter(ColorFilter filter) {
970         int filterNative = 0;
971         if (filter != null)
972             filterNative = filter.native_instance;
973         native_setColorFilter(mNativePaint, filterNative);
974         mColorFilter = filter;
975         return filter;
976     }
977 
978     /**
979      * Get the paint's xfermode object.
980      *
981      * @return the paint's xfermode (or null)
982      */
getXfermode()983     public Xfermode getXfermode() {
984         return mXfermode;
985     }
986 
987     /**
988      * Set or clear the xfermode object.
989      * <p />
990      * Pass null to clear any previous xfermode.
991      * As a convenience, the parameter passed is also returned.
992      *
993      * @param xfermode May be null. The xfermode to be installed in the paint
994      * @return         xfermode
995      */
setXfermode(Xfermode xfermode)996     public Xfermode setXfermode(Xfermode xfermode) {
997         int xfermodeNative = 0;
998         if (xfermode != null)
999             xfermodeNative = xfermode.native_instance;
1000         native_setXfermode(mNativePaint, xfermodeNative);
1001         mXfermode = xfermode;
1002         return xfermode;
1003     }
1004 
1005     /**
1006      * Get the paint's patheffect object.
1007      *
1008      * @return the paint's patheffect (or null)
1009      */
getPathEffect()1010     public PathEffect getPathEffect() {
1011         return mPathEffect;
1012     }
1013 
1014     /**
1015      * Set or clear the patheffect object.
1016      * <p />
1017      * Pass null to clear any previous patheffect.
1018      * As a convenience, the parameter passed is also returned.
1019      *
1020      * @param effect May be null. The patheffect to be installed in the paint
1021      * @return       effect
1022      */
setPathEffect(PathEffect effect)1023     public PathEffect setPathEffect(PathEffect effect) {
1024         int effectNative = 0;
1025         if (effect != null) {
1026             effectNative = effect.native_instance;
1027         }
1028         native_setPathEffect(mNativePaint, effectNative);
1029         mPathEffect = effect;
1030         return effect;
1031     }
1032 
1033     /**
1034      * Get the paint's maskfilter object.
1035      *
1036      * @return the paint's maskfilter (or null)
1037      */
getMaskFilter()1038     public MaskFilter getMaskFilter() {
1039         return mMaskFilter;
1040     }
1041 
1042     /**
1043      * Set or clear the maskfilter object.
1044      * <p />
1045      * Pass null to clear any previous maskfilter.
1046      * As a convenience, the parameter passed is also returned.
1047      *
1048      * @param maskfilter May be null. The maskfilter to be installed in the
1049      *                   paint
1050      * @return           maskfilter
1051      */
setMaskFilter(MaskFilter maskfilter)1052     public MaskFilter setMaskFilter(MaskFilter maskfilter) {
1053         int maskfilterNative = 0;
1054         if (maskfilter != null) {
1055             maskfilterNative = maskfilter.native_instance;
1056         }
1057         native_setMaskFilter(mNativePaint, maskfilterNative);
1058         mMaskFilter = maskfilter;
1059         return maskfilter;
1060     }
1061 
1062     /**
1063      * Get the paint's typeface object.
1064      * <p />
1065      * The typeface object identifies which font to use when drawing or
1066      * measuring text.
1067      *
1068      * @return the paint's typeface (or null)
1069      */
getTypeface()1070     public Typeface getTypeface() {
1071         return mTypeface;
1072     }
1073 
1074     /**
1075      * Set or clear the typeface object.
1076      * <p />
1077      * Pass null to clear any previous typeface.
1078      * As a convenience, the parameter passed is also returned.
1079      *
1080      * @param typeface May be null. The typeface to be installed in the paint
1081      * @return         typeface
1082      */
setTypeface(Typeface typeface)1083     public Typeface setTypeface(Typeface typeface) {
1084         int typefaceNative = 0;
1085         if (typeface != null) {
1086             typefaceNative = typeface.native_instance;
1087         }
1088         native_setTypeface(mNativePaint, typefaceNative);
1089         mTypeface = typeface;
1090         return typeface;
1091     }
1092 
1093     /**
1094      * Get the paint's rasterizer (or null).
1095      * <p />
1096      * The raster controls/modifies how paths/text are turned into alpha masks.
1097      *
1098      * @return         the paint's rasterizer (or null)
1099      */
getRasterizer()1100     public Rasterizer getRasterizer() {
1101         return mRasterizer;
1102     }
1103 
1104     /**
1105      * Set or clear the rasterizer object.
1106      * <p />
1107      * Pass null to clear any previous rasterizer.
1108      * As a convenience, the parameter passed is also returned.
1109      *
1110      * @param rasterizer May be null. The new rasterizer to be installed in
1111      *                   the paint.
1112      * @return           rasterizer
1113      */
setRasterizer(Rasterizer rasterizer)1114     public Rasterizer setRasterizer(Rasterizer rasterizer) {
1115         int rasterizerNative = 0;
1116         if (rasterizer != null) {
1117             rasterizerNative = rasterizer.native_instance;
1118         }
1119         native_setRasterizer(mNativePaint, rasterizerNative);
1120         mRasterizer = rasterizer;
1121         return rasterizer;
1122     }
1123 
1124     /**
1125      * This draws a shadow layer below the main layer, with the specified
1126      * offset and color, and blur radius. If radius is 0, then the shadow
1127      * layer is removed.
1128      */
setShadowLayer(float radius, float dx, float dy, int color)1129     public void setShadowLayer(float radius, float dx, float dy, int color) {
1130         hasShadow = radius > 0.0f;
1131         shadowRadius = radius;
1132         shadowDx = dx;
1133         shadowDy = dy;
1134         shadowColor = color;
1135         nSetShadowLayer(radius, dx, dy, color);
1136     }
1137 
nSetShadowLayer(float radius, float dx, float dy, int color)1138     private native void nSetShadowLayer(float radius, float dx, float dy, int color);
1139 
1140     /**
1141      * Clear the shadow layer.
1142      */
clearShadowLayer()1143     public void clearShadowLayer() {
1144         hasShadow = false;
1145         nSetShadowLayer(0, 0, 0, 0);
1146     }
1147 
1148     /**
1149      * Return the paint's Align value for drawing text. This controls how the
1150      * text is positioned relative to its origin. LEFT align means that all of
1151      * the text will be drawn to the right of its origin (i.e. the origin
1152      * specifieds the LEFT edge of the text) and so on.
1153      *
1154      * @return the paint's Align value for drawing text.
1155      */
getTextAlign()1156     public Align getTextAlign() {
1157         return sAlignArray[native_getTextAlign(mNativePaint)];
1158     }
1159 
1160     /**
1161      * Set the paint's text alignment. This controls how the
1162      * text is positioned relative to its origin. LEFT align means that all of
1163      * the text will be drawn to the right of its origin (i.e. the origin
1164      * specifieds the LEFT edge of the text) and so on.
1165      *
1166      * @param align set the paint's Align value for drawing text.
1167      */
setTextAlign(Align align)1168     public void setTextAlign(Align align) {
1169         native_setTextAlign(mNativePaint, align.nativeInt);
1170     }
1171 
1172     /**
1173      * Get the text Locale.
1174      *
1175      * @return the paint's Locale used for drawing text, never null.
1176      */
getTextLocale()1177     public Locale getTextLocale() {
1178         return mLocale;
1179     }
1180 
1181     /**
1182      * Set the text locale.
1183      *
1184      * The text locale affects how the text is drawn for some languages.
1185      *
1186      * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
1187      * then the text renderer will prefer to draw text using a Chinese font. Likewise,
1188      * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
1189      * renderer will prefer to draw text using a Japanese font.
1190      *
1191      * This distinction is important because Chinese and Japanese text both use many
1192      * of the same Unicode code points but their appearance is subtly different for
1193      * each language.
1194      *
1195      * By default, the text locale is initialized to the system locale (as returned
1196      * by {@link Locale#getDefault}). This assumes that the text to be rendered will
1197      * most likely be in the user's preferred language.
1198      *
1199      * If the actual language of the text is known, then it can be provided to the
1200      * text renderer using this method. The text renderer may attempt to guess the
1201      * language script based on the contents of the text to be drawn independent of
1202      * the text locale here. Specifying the text locale just helps it do a better
1203      * job in certain ambiguous cases
1204      *
1205      * @param locale the paint's locale value for drawing text, must not be null.
1206      */
setTextLocale(Locale locale)1207     public void setTextLocale(Locale locale) {
1208         if (locale == null) {
1209             throw new IllegalArgumentException("locale cannot be null");
1210         }
1211         if (locale.equals(mLocale)) return;
1212         mLocale = locale;
1213         native_setTextLocale(mNativePaint, locale.toString());
1214     }
1215 
1216     /**
1217      * Return the paint's text size.
1218      *
1219      * @return the paint's text size.
1220      */
getTextSize()1221     public native float getTextSize();
1222 
1223     /**
1224      * Set the paint's text size. This value must be > 0
1225      *
1226      * @param textSize set the paint's text size.
1227      */
setTextSize(float textSize)1228     public native void setTextSize(float textSize);
1229 
1230     /**
1231      * Return the paint's horizontal scale factor for text. The default value
1232      * is 1.0.
1233      *
1234      * @return the paint's scale factor in X for drawing/measuring text
1235      */
getTextScaleX()1236     public native float getTextScaleX();
1237 
1238     /**
1239      * Set the paint's horizontal scale factor for text. The default value
1240      * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
1241      * stretch the text narrower.
1242      *
1243      * @param scaleX set the paint's scale in X for drawing/measuring text.
1244      */
setTextScaleX(float scaleX)1245     public native void setTextScaleX(float scaleX);
1246 
1247     /**
1248      * Return the paint's horizontal skew factor for text. The default value
1249      * is 0.
1250      *
1251      * @return         the paint's skew factor in X for drawing text.
1252      */
getTextSkewX()1253     public native float getTextSkewX();
1254 
1255     /**
1256      * Set the paint's horizontal skew factor for text. The default value
1257      * is 0. For approximating oblique text, use values around -0.25.
1258      *
1259      * @param skewX set the paint's skew factor in X for drawing text.
1260      */
setTextSkewX(float skewX)1261     public native void setTextSkewX(float skewX);
1262 
1263     /**
1264      * Return the distance above (negative) the baseline (ascent) based on the
1265      * current typeface and text size.
1266      *
1267      * @return the distance above (negative) the baseline (ascent) based on the
1268      *         current typeface and text size.
1269      */
ascent()1270     public native float ascent();
1271 
1272     /**
1273      * Return the distance below (positive) the baseline (descent) based on the
1274      * current typeface and text size.
1275      *
1276      * @return the distance below (positive) the baseline (descent) based on
1277      *         the current typeface and text size.
1278      */
descent()1279     public native float descent();
1280 
1281     /**
1282      * Class that describes the various metrics for a font at a given text size.
1283      * Remember, Y values increase going down, so those values will be positive,
1284      * and values that measure distances going up will be negative. This class
1285      * is returned by getFontMetrics().
1286      */
1287     public static class FontMetrics {
1288         /**
1289          * The maximum distance above the baseline for the tallest glyph in
1290          * the font at a given text size.
1291          */
1292         public float   top;
1293         /**
1294          * The recommended distance above the baseline for singled spaced text.
1295          */
1296         public float   ascent;
1297         /**
1298          * The recommended distance below the baseline for singled spaced text.
1299          */
1300         public float   descent;
1301         /**
1302          * The maximum distance below the baseline for the lowest glyph in
1303          * the font at a given text size.
1304          */
1305         public float   bottom;
1306         /**
1307          * The recommended additional space to add between lines of text.
1308          */
1309         public float   leading;
1310     }
1311 
1312     /**
1313      * Return the font's recommended interline spacing, given the Paint's
1314      * settings for typeface, textSize, etc. If metrics is not null, return the
1315      * fontmetric values in it.
1316      *
1317      * @param metrics If this object is not null, its fields are filled with
1318      *                the appropriate values given the paint's text attributes.
1319      * @return the font's recommended interline spacing.
1320      */
getFontMetrics(FontMetrics metrics)1321     public native float getFontMetrics(FontMetrics metrics);
1322 
1323     /**
1324      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
1325      * with it, returning the object.
1326      */
getFontMetrics()1327     public FontMetrics getFontMetrics() {
1328         FontMetrics fm = new FontMetrics();
1329         getFontMetrics(fm);
1330         return fm;
1331     }
1332 
1333     /**
1334      * Convenience method for callers that want to have FontMetrics values as
1335      * integers.
1336      */
1337     public static class FontMetricsInt {
1338         public int   top;
1339         public int   ascent;
1340         public int   descent;
1341         public int   bottom;
1342         public int   leading;
1343 
toString()1344         @Override public String toString() {
1345             return "FontMetricsInt: top=" + top + " ascent=" + ascent +
1346                     " descent=" + descent + " bottom=" + bottom +
1347                     " leading=" + leading;
1348         }
1349     }
1350 
1351     /**
1352      * Return the font's interline spacing, given the Paint's settings for
1353      * typeface, textSize, etc. If metrics is not null, return the fontmetric
1354      * values in it. Note: all values have been converted to integers from
1355      * floats, in such a way has to make the answers useful for both spacing
1356      * and clipping. If you want more control over the rounding, call
1357      * getFontMetrics().
1358      *
1359      * @return the font's interline spacing.
1360      */
getFontMetricsInt(FontMetricsInt fmi)1361     public native int getFontMetricsInt(FontMetricsInt fmi);
1362 
getFontMetricsInt()1363     public FontMetricsInt getFontMetricsInt() {
1364         FontMetricsInt fm = new FontMetricsInt();
1365         getFontMetricsInt(fm);
1366         return fm;
1367     }
1368 
1369     /**
1370      * Return the recommend line spacing based on the current typeface and
1371      * text size.
1372      *
1373      * @return  recommend line spacing based on the current typeface and
1374      *          text size.
1375      */
getFontSpacing()1376     public float getFontSpacing() {
1377         return getFontMetrics(null);
1378     }
1379 
1380     /**
1381      * Return the width of the text.
1382      *
1383      * @param text  The text to measure. Cannot be null.
1384      * @param index The index of the first character to start measuring
1385      * @param count THe number of characters to measure, beginning with start
1386      * @return      The width of the text
1387      */
measureText(char[] text, int index, int count)1388     public float measureText(char[] text, int index, int count) {
1389         if (text == null) {
1390             throw new IllegalArgumentException("text cannot be null");
1391         }
1392         if ((index | count) < 0 || index + count > text.length) {
1393             throw new ArrayIndexOutOfBoundsException();
1394         }
1395 
1396         if (text.length == 0 || count == 0) {
1397             return 0f;
1398         }
1399         if (!mHasCompatScaling) {
1400             return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
1401         }
1402 
1403         final float oldSize = getTextSize();
1404         setTextSize(oldSize*mCompatScaling);
1405         float w = native_measureText(text, index, count, mBidiFlags);
1406         setTextSize(oldSize);
1407         return (float) Math.ceil(w*mInvCompatScaling);
1408     }
1409 
native_measureText(char[] text, int index, int count, int bidiFlags)1410     private native float native_measureText(char[] text, int index, int count, int bidiFlags);
1411 
1412     /**
1413      * Return the width of the text.
1414      *
1415      * @param text  The text to measure. Cannot be null.
1416      * @param start The index of the first character to start measuring
1417      * @param end   1 beyond the index of the last character to measure
1418      * @return      The width of the text
1419      */
measureText(String text, int start, int end)1420     public float measureText(String text, int start, int end) {
1421         if (text == null) {
1422             throw new IllegalArgumentException("text cannot be null");
1423         }
1424         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1425             throw new IndexOutOfBoundsException();
1426         }
1427 
1428         if (text.length() == 0 || start == end) {
1429             return 0f;
1430         }
1431         if (!mHasCompatScaling) {
1432             return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
1433         }
1434 
1435         final float oldSize = getTextSize();
1436         setTextSize(oldSize*mCompatScaling);
1437         float w = native_measureText(text, start, end, mBidiFlags);
1438         setTextSize(oldSize);
1439         return (float) Math.ceil(w*mInvCompatScaling);
1440     }
1441 
native_measureText(String text, int start, int end, int bidiFlags)1442     private native float native_measureText(String text, int start, int end, int bidiFlags);
1443 
1444     /**
1445      * Return the width of the text.
1446      *
1447      * @param text  The text to measure. Cannot be null.
1448      * @return      The width of the text
1449      */
measureText(String text)1450     public float measureText(String text) {
1451         if (text == null) {
1452             throw new IllegalArgumentException("text cannot be null");
1453         }
1454 
1455         if (text.length() == 0) {
1456             return 0f;
1457         }
1458 
1459         if (!mHasCompatScaling) {
1460             return (float) Math.ceil(native_measureText(text, mBidiFlags));
1461         }
1462         final float oldSize = getTextSize();
1463         setTextSize(oldSize*mCompatScaling);
1464         float w = native_measureText(text, mBidiFlags);
1465         setTextSize(oldSize);
1466         return (float) Math.ceil(w*mInvCompatScaling);
1467     }
1468 
native_measureText(String text, int bidiFlags)1469     private native float native_measureText(String text, int bidiFlags);
1470 
1471     /**
1472      * Return the width of the text.
1473      *
1474      * @param text  The text to measure
1475      * @param start The index of the first character to start measuring
1476      * @param end   1 beyond the index of the last character to measure
1477      * @return      The width of the text
1478      */
measureText(CharSequence text, int start, int end)1479     public float measureText(CharSequence text, int start, int end) {
1480         if (text == null) {
1481             throw new IllegalArgumentException("text cannot be null");
1482         }
1483         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1484             throw new IndexOutOfBoundsException();
1485         }
1486 
1487         if (text.length() == 0 || start == end) {
1488             return 0f;
1489         }
1490         if (text instanceof String) {
1491             return measureText((String)text, start, end);
1492         }
1493         if (text instanceof SpannedString ||
1494             text instanceof SpannableString) {
1495             return measureText(text.toString(), start, end);
1496         }
1497         if (text instanceof GraphicsOperations) {
1498             return ((GraphicsOperations)text).measureText(start, end, this);
1499         }
1500 
1501         char[] buf = TemporaryBuffer.obtain(end - start);
1502         TextUtils.getChars(text, start, end, buf, 0);
1503         float result = measureText(buf, 0, end - start);
1504         TemporaryBuffer.recycle(buf);
1505         return result;
1506     }
1507 
1508     /**
1509      * Measure the text, stopping early if the measured width exceeds maxWidth.
1510      * Return the number of chars that were measured, and if measuredWidth is
1511      * not null, return in it the actual width measured.
1512      *
1513      * @param text  The text to measure. Cannot be null.
1514      * @param index The offset into text to begin measuring at
1515      * @param count The number of maximum number of entries to measure. If count
1516      *              is negative, then the characters are measured in reverse order.
1517      * @param maxWidth The maximum width to accumulate.
1518      * @param measuredWidth Optional. If not null, returns the actual width
1519      *                     measured.
1520      * @return The number of chars that were measured. Will always be <=
1521      *         abs(count).
1522      */
breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth)1523     public int breakText(char[] text, int index, int count,
1524                                 float maxWidth, float[] measuredWidth) {
1525         if (text == null) {
1526             throw new IllegalArgumentException("text cannot be null");
1527         }
1528         if (index < 0 || text.length - index < Math.abs(count)) {
1529             throw new ArrayIndexOutOfBoundsException();
1530         }
1531 
1532         if (text.length == 0 || count == 0) {
1533             return 0;
1534         }
1535         if (!mHasCompatScaling) {
1536             return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
1537         }
1538 
1539         final float oldSize = getTextSize();
1540         setTextSize(oldSize*mCompatScaling);
1541         int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
1542                 measuredWidth);
1543         setTextSize(oldSize);
1544         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
1545         return res;
1546     }
1547 
native_breakText(char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth)1548     private native int native_breakText(char[] text, int index, int count,
1549                                         float maxWidth, int bidiFlags, float[] measuredWidth);
1550 
1551     /**
1552      * Measure the text, stopping early if the measured width exceeds maxWidth.
1553      * Return the number of chars that were measured, and if measuredWidth is
1554      * not null, return in it the actual width measured.
1555      *
1556      * @param text  The text to measure. Cannot be null.
1557      * @param start The offset into text to begin measuring at
1558      * @param end   The end of the text slice to measure.
1559      * @param measureForwards If true, measure forwards, starting at start.
1560      *                        Otherwise, measure backwards, starting with end.
1561      * @param maxWidth The maximum width to accumulate.
1562      * @param measuredWidth Optional. If not null, returns the actual width
1563      *                     measured.
1564      * @return The number of chars that were measured. Will always be <=
1565      *         abs(end - start).
1566      */
breakText(CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)1567     public int breakText(CharSequence text, int start, int end,
1568                          boolean measureForwards,
1569                          float maxWidth, float[] measuredWidth) {
1570         if (text == null) {
1571             throw new IllegalArgumentException("text cannot be null");
1572         }
1573         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1574             throw new IndexOutOfBoundsException();
1575         }
1576 
1577         if (text.length() == 0 || start == end) {
1578             return 0;
1579         }
1580         if (start == 0 && text instanceof String && end == text.length()) {
1581             return breakText((String) text, measureForwards, maxWidth,
1582                              measuredWidth);
1583         }
1584 
1585         char[] buf = TemporaryBuffer.obtain(end - start);
1586         int result;
1587 
1588         TextUtils.getChars(text, start, end, buf, 0);
1589 
1590         if (measureForwards) {
1591             result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
1592         } else {
1593             result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
1594         }
1595 
1596         TemporaryBuffer.recycle(buf);
1597         return result;
1598     }
1599 
1600     /**
1601      * Measure the text, stopping early if the measured width exceeds maxWidth.
1602      * Return the number of chars that were measured, and if measuredWidth is
1603      * not null, return in it the actual width measured.
1604      *
1605      * @param text  The text to measure. Cannot be null.
1606      * @param measureForwards If true, measure forwards, starting with the
1607      *                        first character in the string. Otherwise,
1608      *                        measure backwards, starting with the
1609      *                        last character in the string.
1610      * @param maxWidth The maximum width to accumulate.
1611      * @param measuredWidth Optional. If not null, returns the actual width
1612      *                     measured.
1613      * @return The number of chars that were measured. Will always be <=
1614      *         abs(count).
1615      */
breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth)1616     public int breakText(String text, boolean measureForwards,
1617                                 float maxWidth, float[] measuredWidth) {
1618         if (text == null) {
1619             throw new IllegalArgumentException("text cannot be null");
1620         }
1621 
1622         if (text.length() == 0) {
1623             return 0;
1624         }
1625         if (!mHasCompatScaling) {
1626             return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
1627         }
1628 
1629         final float oldSize = getTextSize();
1630         setTextSize(oldSize*mCompatScaling);
1631         int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
1632                 measuredWidth);
1633         setTextSize(oldSize);
1634         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
1635         return res;
1636     }
1637 
native_breakText(String text, boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth)1638     private native int native_breakText(String text, boolean measureForwards,
1639                                         float maxWidth, int bidiFlags, float[] measuredWidth);
1640 
1641     /**
1642      * Return the advance widths for the characters in the string.
1643      *
1644      * @param text     The text to measure. Cannot be null.
1645      * @param index    The index of the first char to to measure
1646      * @param count    The number of chars starting with index to measure
1647      * @param widths   array to receive the advance widths of the characters.
1648      *                 Must be at least a large as count.
1649      * @return         the actual number of widths returned.
1650      */
getTextWidths(char[] text, int index, int count, float[] widths)1651     public int getTextWidths(char[] text, int index, int count,
1652                              float[] widths) {
1653         if (text == null) {
1654             throw new IllegalArgumentException("text cannot be null");
1655         }
1656         if ((index | count) < 0 || index + count > text.length
1657                 || count > widths.length) {
1658             throw new ArrayIndexOutOfBoundsException();
1659         }
1660 
1661         if (text.length == 0 || count == 0) {
1662             return 0;
1663         }
1664         if (!mHasCompatScaling) {
1665             return native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
1666         }
1667 
1668         final float oldSize = getTextSize();
1669         setTextSize(oldSize*mCompatScaling);
1670         int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
1671         setTextSize(oldSize);
1672         for (int i=0; i<res; i++) {
1673             widths[i] *= mInvCompatScaling;
1674         }
1675         return res;
1676     }
1677 
1678     /**
1679      * Return the advance widths for the characters in the string.
1680      *
1681      * @param text     The text to measure. Cannot be null.
1682      * @param start    The index of the first char to to measure
1683      * @param end      The end of the text slice to measure
1684      * @param widths   array to receive the advance widths of the characters.
1685      *                 Must be at least a large as (end - start).
1686      * @return         the actual number of widths returned.
1687      */
getTextWidths(CharSequence text, int start, int end, float[] widths)1688     public int getTextWidths(CharSequence text, int start, int end,
1689                              float[] widths) {
1690         if (text == null) {
1691             throw new IllegalArgumentException("text cannot be null");
1692         }
1693         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1694             throw new IndexOutOfBoundsException();
1695         }
1696         if (end - start > widths.length) {
1697             throw new ArrayIndexOutOfBoundsException();
1698         }
1699 
1700         if (text.length() == 0 || start == end) {
1701             return 0;
1702         }
1703         if (text instanceof String) {
1704             return getTextWidths((String) text, start, end, widths);
1705         }
1706         if (text instanceof SpannedString ||
1707             text instanceof SpannableString) {
1708             return getTextWidths(text.toString(), start, end, widths);
1709         }
1710         if (text instanceof GraphicsOperations) {
1711             return ((GraphicsOperations) text).getTextWidths(start, end,
1712                                                                  widths, this);
1713         }
1714 
1715         char[] buf = TemporaryBuffer.obtain(end - start);
1716         TextUtils.getChars(text, start, end, buf, 0);
1717         int result = getTextWidths(buf, 0, end - start, widths);
1718         TemporaryBuffer.recycle(buf);
1719         return result;
1720     }
1721 
1722     /**
1723      * Return the advance widths for the characters in the string.
1724      *
1725      * @param text   The text to measure. Cannot be null.
1726      * @param start  The index of the first char to to measure
1727      * @param end    The end of the text slice to measure
1728      * @param widths array to receive the advance widths of the characters.
1729      *               Must be at least a large as the text.
1730      * @return       the number of unichars in the specified text.
1731      */
getTextWidths(String text, int start, int end, float[] widths)1732     public int getTextWidths(String text, int start, int end, float[] widths) {
1733         if (text == null) {
1734             throw new IllegalArgumentException("text cannot be null");
1735         }
1736         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1737             throw new IndexOutOfBoundsException();
1738         }
1739         if (end - start > widths.length) {
1740             throw new ArrayIndexOutOfBoundsException();
1741         }
1742 
1743         if (text.length() == 0 || start == end) {
1744             return 0;
1745         }
1746         if (!mHasCompatScaling) {
1747             return native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
1748         }
1749 
1750         final float oldSize = getTextSize();
1751         setTextSize(oldSize*mCompatScaling);
1752         int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
1753         setTextSize(oldSize);
1754         for (int i=0; i<res; i++) {
1755             widths[i] *= mInvCompatScaling;
1756         }
1757         return res;
1758     }
1759 
1760     /**
1761      * Return the advance widths for the characters in the string.
1762      *
1763      * @param text   The text to measure
1764      * @param widths array to receive the advance widths of the characters.
1765      *               Must be at least a large as the text.
1766      * @return       the number of unichars in the specified text.
1767      */
getTextWidths(String text, float[] widths)1768     public int getTextWidths(String text, float[] widths) {
1769         return getTextWidths(text, 0, text.length(), widths);
1770     }
1771 
1772     /**
1773      * Return the glyph Ids for the characters in the string.
1774      *
1775      * @param text   The text to measure
1776      * @param start  The index of the first char to to measure
1777      * @param end    The end of the text slice to measure
1778      * @param contextStart the index of the first character to use for shaping context,
1779      * must be <= start
1780      * @param contextEnd the index past the last character to use for shaping context,
1781      * must be >= end
1782      * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
1783      * or {@link #DIRECTION_RTL}
1784      * @param glyphs array to receive the glyph Ids of the characters.
1785      *               Must be at least a large as the text.
1786      * @return       the number of glyphs in the returned array
1787      *
1788      * @hide
1789      *
1790      * Used only for BiDi / RTL Tests
1791      */
getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd, int flags, char[] glyphs)1792     public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
1793             int flags, char[] glyphs) {
1794         if (text == null) {
1795             throw new IllegalArgumentException("text cannot be null");
1796         }
1797         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
1798             throw new IllegalArgumentException("unknown flags value: " + flags);
1799         }
1800         if ((start | end | contextStart | contextEnd | (end - start)
1801                 | (start - contextStart) | (contextEnd - end) | (text.length() - end)
1802                 | (text.length() - contextEnd)) < 0) {
1803             throw new IndexOutOfBoundsException();
1804         }
1805         if (end - start > glyphs.length) {
1806             throw new ArrayIndexOutOfBoundsException();
1807         }
1808         return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
1809                 flags, glyphs);
1810     }
1811 
1812     /**
1813      * Convenience overload that takes a char array instead of a
1814      * String.
1815      *
1816      * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
1817      * @hide
1818      */
getTextRunAdvances(char[] chars, int index, int count, int contextIndex, int contextCount, int flags, float[] advances, int advancesIndex)1819     public float getTextRunAdvances(char[] chars, int index, int count,
1820             int contextIndex, int contextCount, int flags, float[] advances,
1821             int advancesIndex) {
1822 
1823         if (chars == null) {
1824             throw new IllegalArgumentException("text cannot be null");
1825         }
1826         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
1827             throw new IllegalArgumentException("unknown flags value: " + flags);
1828         }
1829         if ((index | count | contextIndex | contextCount | advancesIndex
1830                 | (index - contextIndex) | (contextCount - count)
1831                 | ((contextIndex + contextCount) - (index + count))
1832                 | (chars.length - (contextIndex + contextCount))
1833                 | (advances == null ? 0 :
1834                     (advances.length - (advancesIndex + count)))) < 0) {
1835             throw new IndexOutOfBoundsException();
1836         }
1837 
1838         if (chars.length == 0 || count == 0){
1839             return 0f;
1840         }
1841         if (!mHasCompatScaling) {
1842             return native_getTextRunAdvances(mNativePaint, chars, index, count,
1843                     contextIndex, contextCount, flags, advances, advancesIndex);
1844         }
1845 
1846         final float oldSize = getTextSize();
1847         setTextSize(oldSize * mCompatScaling);
1848         float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
1849                 contextIndex, contextCount, flags, advances, advancesIndex);
1850         setTextSize(oldSize);
1851 
1852         if (advances != null) {
1853             for (int i = advancesIndex, e = i + count; i < e; i++) {
1854                 advances[i] *= mInvCompatScaling;
1855             }
1856         }
1857         return res * mInvCompatScaling; // assume errors are not significant
1858     }
1859 
1860     /**
1861      * Convenience overload that takes a CharSequence instead of a
1862      * String.
1863      *
1864      * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
1865      * @hide
1866      */
getTextRunAdvances(CharSequence text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex)1867     public float getTextRunAdvances(CharSequence text, int start, int end,
1868             int contextStart, int contextEnd, int flags, float[] advances,
1869             int advancesIndex) {
1870 
1871         if (text == null) {
1872             throw new IllegalArgumentException("text cannot be null");
1873         }
1874         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
1875                 | (start - contextStart) | (contextEnd - end)
1876                 | (text.length() - contextEnd)
1877                 | (advances == null ? 0 :
1878                     (advances.length - advancesIndex - (end - start)))) < 0) {
1879             throw new IndexOutOfBoundsException();
1880         }
1881 
1882         if (text instanceof String) {
1883             return getTextRunAdvances((String) text, start, end,
1884                     contextStart, contextEnd, flags, advances, advancesIndex);
1885         }
1886         if (text instanceof SpannedString ||
1887             text instanceof SpannableString) {
1888             return getTextRunAdvances(text.toString(), start, end,
1889                     contextStart, contextEnd, flags, advances, advancesIndex);
1890         }
1891         if (text instanceof GraphicsOperations) {
1892             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
1893                     contextStart, contextEnd, flags, advances, advancesIndex, this);
1894         }
1895         if (text.length() == 0 || end == start) {
1896             return 0f;
1897         }
1898 
1899         int contextLen = contextEnd - contextStart;
1900         int len = end - start;
1901         char[] buf = TemporaryBuffer.obtain(contextLen);
1902         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1903         float result = getTextRunAdvances(buf, start - contextStart, len,
1904                 0, contextLen, flags, advances, advancesIndex);
1905         TemporaryBuffer.recycle(buf);
1906         return result;
1907     }
1908 
1909     /**
1910      * Returns the total advance width for the characters in the run
1911      * between start and end, and if advances is not null, the advance
1912      * assigned to each of these characters (java chars).
1913      *
1914      * <p>The trailing surrogate in a valid surrogate pair is assigned
1915      * an advance of 0.  Thus the number of returned advances is
1916      * always equal to count, not to the number of unicode codepoints
1917      * represented by the run.
1918      *
1919      * <p>In the case of conjuncts or combining marks, the total
1920      * advance is assigned to the first logical character, and the
1921      * following characters are assigned an advance of 0.
1922      *
1923      * <p>This generates the sum of the advances of glyphs for
1924      * characters in a reordered cluster as the width of the first
1925      * logical character in the cluster, and 0 for the widths of all
1926      * other characters in the cluster.  In effect, such clusters are
1927      * treated like conjuncts.
1928      *
1929      * <p>The shaping bounds limit the amount of context available
1930      * outside start and end that can be used for shaping analysis.
1931      * These bounds typically reflect changes in bidi level or font
1932      * metrics across which shaping does not occur.
1933      *
1934      * @param text the text to measure. Cannot be null.
1935      * @param start the index of the first character to measure
1936      * @param end the index past the last character to measure
1937      * @param contextStart the index of the first character to use for shaping context,
1938      * must be <= start
1939      * @param contextEnd the index past the last character to use for shaping context,
1940      * must be >= end
1941      * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
1942      * or {@link #DIRECTION_RTL}
1943      * @param advances array to receive the advances, must have room for all advances,
1944      * can be null if only total advance is needed
1945      * @param advancesIndex the position in advances at which to put the
1946      * advance corresponding to the character at start
1947      * @return the total advance
1948      *
1949      * @hide
1950      */
getTextRunAdvances(String text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex)1951     public float getTextRunAdvances(String text, int start, int end, int contextStart,
1952             int contextEnd, int flags, float[] advances, int advancesIndex) {
1953 
1954         if (text == null) {
1955             throw new IllegalArgumentException("text cannot be null");
1956         }
1957         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
1958             throw new IllegalArgumentException("unknown flags value: " + flags);
1959         }
1960         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
1961                 | (start - contextStart) | (contextEnd - end)
1962                 | (text.length() - contextEnd)
1963                 | (advances == null ? 0 :
1964                     (advances.length - advancesIndex - (end - start)))) < 0) {
1965             throw new IndexOutOfBoundsException();
1966         }
1967 
1968         if (text.length() == 0 || start == end) {
1969             return 0f;
1970         }
1971 
1972         if (!mHasCompatScaling) {
1973             return native_getTextRunAdvances(mNativePaint, text, start, end,
1974                     contextStart, contextEnd, flags, advances, advancesIndex);
1975         }
1976 
1977         final float oldSize = getTextSize();
1978         setTextSize(oldSize * mCompatScaling);
1979         float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
1980                 contextStart, contextEnd, flags, advances, advancesIndex);
1981         setTextSize(oldSize);
1982 
1983         if (advances != null) {
1984             for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
1985                 advances[i] *= mInvCompatScaling;
1986             }
1987         }
1988         return totalAdvance * mInvCompatScaling; // assume errors are insignificant
1989     }
1990 
1991     /**
1992      * Returns the next cursor position in the run.  This avoids placing the
1993      * cursor between surrogates, between characters that form conjuncts,
1994      * between base characters and combining marks, or within a reordering
1995      * cluster.
1996      *
1997      * <p>ContextStart and offset are relative to the start of text.
1998      * The context is the shaping context for cursor movement, generally
1999      * the bounds of the metric span enclosing the cursor in the direction of
2000      * movement.
2001      *
2002      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
2003      * cursor position, this returns -1.  Otherwise this will never return a
2004      * value before contextStart or after contextStart + contextLength.
2005      *
2006      * @param text the text
2007      * @param contextStart the start of the context
2008      * @param contextLength the length of the context
2009      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
2010      * @param offset the cursor position to move from
2011      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
2012      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
2013      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
2014      * @return the offset of the next position, or -1
2015      * @hide
2016      */
getTextRunCursor(char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)2017     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
2018             int flags, int offset, int cursorOpt) {
2019         int contextEnd = contextStart + contextLength;
2020         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
2021                 | (offset - contextStart) | (contextEnd - offset)
2022                 | (text.length - contextEnd) | cursorOpt) < 0)
2023                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
2024             throw new IndexOutOfBoundsException();
2025         }
2026 
2027         return native_getTextRunCursor(mNativePaint, text,
2028                 contextStart, contextLength, flags, offset, cursorOpt);
2029     }
2030 
2031     /**
2032      * Returns the next cursor position in the run.  This avoids placing the
2033      * cursor between surrogates, between characters that form conjuncts,
2034      * between base characters and combining marks, or within a reordering
2035      * cluster.
2036      *
2037      * <p>ContextStart, contextEnd, and offset are relative to the start of
2038      * text.  The context is the shaping context for cursor movement, generally
2039      * the bounds of the metric span enclosing the cursor in the direction of
2040      * movement.
2041      *
2042      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
2043      * cursor position, this returns -1.  Otherwise this will never return a
2044      * value before contextStart or after contextEnd.
2045      *
2046      * @param text the text
2047      * @param contextStart the start of the context
2048      * @param contextEnd the end of the context
2049      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
2050      * @param offset the cursor position to move from
2051      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
2052      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
2053      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
2054      * @return the offset of the next position, or -1
2055      * @hide
2056      */
getTextRunCursor(CharSequence text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)2057     public int getTextRunCursor(CharSequence text, int contextStart,
2058            int contextEnd, int flags, int offset, int cursorOpt) {
2059 
2060         if (text instanceof String || text instanceof SpannedString ||
2061                 text instanceof SpannableString) {
2062             return getTextRunCursor(text.toString(), contextStart, contextEnd,
2063                     flags, offset, cursorOpt);
2064         }
2065         if (text instanceof GraphicsOperations) {
2066             return ((GraphicsOperations) text).getTextRunCursor(
2067                     contextStart, contextEnd, flags, offset, cursorOpt, this);
2068         }
2069 
2070         int contextLen = contextEnd - contextStart;
2071         char[] buf = TemporaryBuffer.obtain(contextLen);
2072         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
2073         int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
2074         TemporaryBuffer.recycle(buf);
2075         return result;
2076     }
2077 
2078     /**
2079      * Returns the next cursor position in the run.  This avoids placing the
2080      * cursor between surrogates, between characters that form conjuncts,
2081      * between base characters and combining marks, or within a reordering
2082      * cluster.
2083      *
2084      * <p>ContextStart, contextEnd, and offset are relative to the start of
2085      * text.  The context is the shaping context for cursor movement, generally
2086      * the bounds of the metric span enclosing the cursor in the direction of
2087      * movement.
2088      *
2089      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
2090      * cursor position, this returns -1.  Otherwise this will never return a
2091      * value before contextStart or after contextEnd.
2092      *
2093      * @param text the text
2094      * @param contextStart the start of the context
2095      * @param contextEnd the end of the context
2096      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
2097      * @param offset the cursor position to move from
2098      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
2099      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
2100      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
2101      * @return the offset of the next position, or -1
2102      * @hide
2103      */
getTextRunCursor(String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)2104     public int getTextRunCursor(String text, int contextStart, int contextEnd,
2105             int flags, int offset, int cursorOpt) {
2106         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
2107                 | (offset - contextStart) | (contextEnd - offset)
2108                 | (text.length() - contextEnd) | cursorOpt) < 0)
2109                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
2110             throw new IndexOutOfBoundsException();
2111         }
2112 
2113         return native_getTextRunCursor(mNativePaint, text,
2114                 contextStart, contextEnd, flags, offset, cursorOpt);
2115     }
2116 
2117     /**
2118      * Return the path (outline) for the specified text.
2119      * Note: just like Canvas.drawText, this will respect the Align setting in
2120      * the paint.
2121      *
2122      * @param text     The text to retrieve the path from
2123      * @param index    The index of the first character in text
2124      * @param count    The number of characterss starting with index
2125      * @param x        The x coordinate of the text's origin
2126      * @param y        The y coordinate of the text's origin
2127      * @param path     The path to receive the data describing the text. Must
2128      *                 be allocated by the caller.
2129      */
getTextPath(char[] text, int index, int count, float x, float y, Path path)2130     public void getTextPath(char[] text, int index, int count,
2131                             float x, float y, Path path) {
2132         if ((index | count) < 0 || index + count > text.length) {
2133             throw new ArrayIndexOutOfBoundsException();
2134         }
2135         native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y,
2136                 path.ni());
2137     }
2138 
2139     /**
2140      * Return the path (outline) for the specified text.
2141      * Note: just like Canvas.drawText, this will respect the Align setting
2142      * in the paint.
2143      *
2144      * @param text  The text to retrieve the path from
2145      * @param start The first character in the text
2146      * @param end   1 past the last charcter in the text
2147      * @param x     The x coordinate of the text's origin
2148      * @param y     The y coordinate of the text's origin
2149      * @param path  The path to receive the data describing the text. Must
2150      *              be allocated by the caller.
2151      */
getTextPath(String text, int start, int end, float x, float y, Path path)2152     public void getTextPath(String text, int start, int end,
2153                             float x, float y, Path path) {
2154         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2155             throw new IndexOutOfBoundsException();
2156         }
2157         native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y,
2158                 path.ni());
2159     }
2160 
2161     /**
2162      * Return in bounds (allocated by the caller) the smallest rectangle that
2163      * encloses all of the characters, with an implied origin at (0,0).
2164      *
2165      * @param text  String to measure and return its bounds
2166      * @param start Index of the first char in the string to measure
2167      * @param end   1 past the last char in the string measure
2168      * @param bounds Returns the unioned bounds of all the text. Must be
2169      *               allocated by the caller.
2170      */
getTextBounds(String text, int start, int end, Rect bounds)2171     public void getTextBounds(String text, int start, int end, Rect bounds) {
2172         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2173             throw new IndexOutOfBoundsException();
2174         }
2175         if (bounds == null) {
2176             throw new NullPointerException("need bounds Rect");
2177         }
2178         nativeGetStringBounds(mNativePaint, text, start, end, mBidiFlags, bounds);
2179     }
2180 
2181     /**
2182      * Return in bounds (allocated by the caller) the smallest rectangle that
2183      * encloses all of the characters, with an implied origin at (0,0).
2184      *
2185      * @param text  Array of chars to measure and return their unioned bounds
2186      * @param index Index of the first char in the array to measure
2187      * @param count The number of chars, beginning at index, to measure
2188      * @param bounds Returns the unioned bounds of all the text. Must be
2189      *               allocated by the caller.
2190      */
getTextBounds(char[] text, int index, int count, Rect bounds)2191     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
2192         if ((index | count) < 0 || index + count > text.length) {
2193             throw new ArrayIndexOutOfBoundsException();
2194         }
2195         if (bounds == null) {
2196             throw new NullPointerException("need bounds Rect");
2197         }
2198         nativeGetCharArrayBounds(mNativePaint, text, index, count, mBidiFlags, bounds);
2199     }
2200 
2201     @Override
finalize()2202     protected void finalize() throws Throwable {
2203         try {
2204             finalizer(mNativePaint);
2205         } finally {
2206             super.finalize();
2207         }
2208     }
2209 
native_init()2210     private static native int native_init();
native_initWithPaint(int paint)2211     private static native int native_initWithPaint(int paint);
native_reset(int native_object)2212     private static native void native_reset(int native_object);
native_set(int native_dst, int native_src)2213     private static native void native_set(int native_dst, int native_src);
native_getStyle(int native_object)2214     private static native int native_getStyle(int native_object);
native_setStyle(int native_object, int style)2215     private static native void native_setStyle(int native_object, int style);
native_getStrokeCap(int native_object)2216     private static native int native_getStrokeCap(int native_object);
native_setStrokeCap(int native_object, int cap)2217     private static native void native_setStrokeCap(int native_object, int cap);
native_getStrokeJoin(int native_object)2218     private static native int native_getStrokeJoin(int native_object);
native_setStrokeJoin(int native_object, int join)2219     private static native void native_setStrokeJoin(int native_object,
2220                                                     int join);
native_getFillPath(int native_object, int src, int dst)2221     private static native boolean native_getFillPath(int native_object,
2222                                                      int src, int dst);
native_setShader(int native_object, int shader)2223     private static native int native_setShader(int native_object, int shader);
native_setColorFilter(int native_object, int filter)2224     private static native int native_setColorFilter(int native_object,
2225                                                     int filter);
native_setXfermode(int native_object, int xfermode)2226     private static native int native_setXfermode(int native_object,
2227                                                  int xfermode);
native_setPathEffect(int native_object, int effect)2228     private static native int native_setPathEffect(int native_object,
2229                                                    int effect);
native_setMaskFilter(int native_object, int maskfilter)2230     private static native int native_setMaskFilter(int native_object,
2231                                                    int maskfilter);
native_setTypeface(int native_object, int typeface)2232     private static native int native_setTypeface(int native_object,
2233                                                  int typeface);
native_setRasterizer(int native_object, int rasterizer)2234     private static native int native_setRasterizer(int native_object,
2235                                                    int rasterizer);
2236 
native_getTextAlign(int native_object)2237     private static native int native_getTextAlign(int native_object);
native_setTextAlign(int native_object, int align)2238     private static native void native_setTextAlign(int native_object,
2239                                                    int align);
2240 
native_setTextLocale(int native_object, String locale)2241     private static native void native_setTextLocale(int native_object,
2242                                                     String locale);
2243 
native_getTextWidths(int native_object, char[] text, int index, int count, int bidiFlags, float[] widths)2244     private static native int native_getTextWidths(int native_object,
2245                             char[] text, int index, int count, int bidiFlags, float[] widths);
native_getTextWidths(int native_object, String text, int start, int end, int bidiFlags, float[] widths)2246     private static native int native_getTextWidths(int native_object,
2247                             String text, int start, int end, int bidiFlags, float[] widths);
2248 
native_getTextGlyphs(int native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, char[] glyphs)2249     private static native int native_getTextGlyphs(int native_object,
2250             String text, int start, int end, int contextStart, int contextEnd,
2251             int flags, char[] glyphs);
2252 
native_getTextRunAdvances(int native_object, char[] text, int index, int count, int contextIndex, int contextCount, int flags, float[] advances, int advancesIndex)2253     private static native float native_getTextRunAdvances(int native_object,
2254             char[] text, int index, int count, int contextIndex, int contextCount,
2255             int flags, float[] advances, int advancesIndex);
native_getTextRunAdvances(int native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex)2256     private static native float native_getTextRunAdvances(int native_object,
2257             String text, int start, int end, int contextStart, int contextEnd,
2258             int flags, float[] advances, int advancesIndex);
2259 
native_getTextRunCursor(int native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)2260     private native int native_getTextRunCursor(int native_object, char[] text,
2261             int contextStart, int contextLength, int flags, int offset, int cursorOpt);
native_getTextRunCursor(int native_object, String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)2262     private native int native_getTextRunCursor(int native_object, String text,
2263             int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
2264 
native_getTextPath(int native_object, int bidiFlags, char[] text, int index, int count, float x, float y, int path)2265     private static native void native_getTextPath(int native_object, int bidiFlags,
2266                 char[] text, int index, int count, float x, float y, int path);
native_getTextPath(int native_object, int bidiFlags, String text, int start, int end, float x, float y, int path)2267     private static native void native_getTextPath(int native_object, int bidiFlags,
2268                 String text, int start, int end, float x, float y, int path);
nativeGetStringBounds(int nativePaint, String text, int start, int end, int bidiFlags, Rect bounds)2269     private static native void nativeGetStringBounds(int nativePaint,
2270                                 String text, int start, int end, int bidiFlags, Rect bounds);
nativeGetCharArrayBounds(int nativePaint, char[] text, int index, int count, int bidiFlags, Rect bounds)2271     private static native void nativeGetCharArrayBounds(int nativePaint,
2272                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
finalizer(int nativePaint)2273     private static native void finalizer(int nativePaint);
2274 }
2275