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