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