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