• 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      */
isLinearText()556     public final boolean isLinearText() {
557         return (getFlags() & LINEAR_TEXT_FLAG) != 0;
558     }
559 
560     /**
561      * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit
562      *
563      * @param linearText true to set the linearText bit in the paint's flags,
564      *                   false to clear it.
565      */
setLinearText(boolean linearText)566     public native void setLinearText(boolean linearText);
567 
568     /**
569      * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
570      *
571      * @return true if the subpixel bit is set in the paint's flags
572      */
isSubpixelText()573     public final boolean isSubpixelText() {
574         return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
575     }
576 
577     /**
578      * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
579      *
580      * @param subpixelText true to set the subpixelText bit in the paint's
581      *                     flags, false to clear it.
582      */
setSubpixelText(boolean subpixelText)583     public native void setSubpixelText(boolean subpixelText);
584 
585     /**
586      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
587      *
588      * @return true if the underlineText bit is set in the paint's flags.
589      */
isUnderlineText()590     public final boolean isUnderlineText() {
591         return (getFlags() & UNDERLINE_TEXT_FLAG) != 0;
592     }
593 
594     /**
595      * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit
596      *
597      * @param underlineText true to set the underlineText bit in the paint's
598      *                      flags, false to clear it.
599      */
setUnderlineText(boolean underlineText)600     public native void setUnderlineText(boolean underlineText);
601 
602     /**
603      * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
604      *
605      * @return true if the strikeThruText bit is set in the paint's flags.
606      */
isStrikeThruText()607     public final boolean isStrikeThruText() {
608         return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0;
609     }
610 
611     /**
612      * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
613      *
614      * @param strikeThruText true to set the strikeThruText bit in the paint's
615      *                       flags, false to clear it.
616      */
setStrikeThruText(boolean strikeThruText)617     public native void setStrikeThruText(boolean strikeThruText);
618 
619     /**
620      * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
621      *
622      * @return true if the fakeBoldText bit is set in the paint's flags.
623      */
isFakeBoldText()624     public final boolean isFakeBoldText() {
625         return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0;
626     }
627 
628     /**
629      * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit
630      *
631      * @param fakeBoldText true to set the fakeBoldText bit in the paint's
632      *                     flags, false to clear it.
633      */
setFakeBoldText(boolean fakeBoldText)634     public native void setFakeBoldText(boolean fakeBoldText);
635 
636     /**
637      * Whether or not the bitmap filter is activated.
638      * Filtering affects the sampling of bitmaps when they are transformed.
639      * Filtering does not affect how the colors in the bitmap are converted into
640      * device pixels. That is dependent on dithering and xfermodes.
641      *
642      * @see #setFilterBitmap(boolean) setFilterBitmap()
643      */
isFilterBitmap()644     public final boolean isFilterBitmap() {
645         return (getFlags() & FILTER_BITMAP_FLAG) != 0;
646     }
647 
648     /**
649      * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
650      * Filtering affects the sampling of bitmaps when they are transformed.
651      * Filtering does not affect how the colors in the bitmap are converted into
652      * device pixels. That is dependent on dithering and xfermodes.
653      *
654      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
655      *               flags, false to clear it.
656      */
setFilterBitmap(boolean filter)657     public native void setFilterBitmap(boolean filter);
658 
659     /**
660      * Return the paint's style, used for controlling how primitives'
661      * geometries are interpreted (except for drawBitmap, which always assumes
662      * FILL_STYLE).
663      *
664      * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
665      */
getStyle()666     public Style getStyle() {
667         return sStyleArray[native_getStyle(mNativePaint)];
668     }
669 
670     /**
671      * Set the paint's style, used for controlling how primitives'
672      * geometries are interpreted (except for drawBitmap, which always assumes
673      * Fill).
674      *
675      * @param style The new style to set in the paint
676      */
setStyle(Style style)677     public void setStyle(Style style) {
678         native_setStyle(mNativePaint, style.nativeInt);
679     }
680 
681     /**
682      * Return the paint's color. Note that the color is a 32bit value
683      * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
684      * meaning that its alpha can be any value, regardless of the values of
685      * r,g,b. See the Color class for more details.
686      *
687      * @return the paint's color (and alpha).
688      */
getColor()689     public native int getColor();
690 
691     /**
692      * Set the paint's color. Note that the color is an int containing alpha
693      * as well as r,g,b. This 32bit value is not premultiplied, meaning that
694      * its alpha can be any value, regardless of the values of r,g,b.
695      * See the Color class for more details.
696      *
697      * @param color The new color (including alpha) to set in the paint.
698      */
setColor(int color)699     public native void setColor(int color);
700 
701     /**
702      * Helper to getColor() that just returns the color's alpha value. This is
703      * the same as calling getColor() >>> 24. It always returns a value between
704      * 0 (completely transparent) and 255 (completely opaque).
705      *
706      * @return the alpha component of the paint's color.
707      */
getAlpha()708     public native int getAlpha();
709 
710     /**
711      * Helper to setColor(), that only assigns the color's alpha value,
712      * leaving its r,g,b values unchanged. Results are undefined if the alpha
713      * value is outside of the range [0..255]
714      *
715      * @param a set the alpha component [0..255] of the paint's color.
716      */
setAlpha(int a)717     public native void setAlpha(int a);
718 
719     /**
720      * Helper to setColor(), that takes a,r,g,b and constructs the color int
721      *
722      * @param a The new alpha component (0..255) of the paint's color.
723      * @param r The new red component (0..255) of the paint's color.
724      * @param g The new green component (0..255) of the paint's color.
725      * @param b The new blue component (0..255) of the paint's color.
726      */
setARGB(int a, int r, int g, int b)727     public void setARGB(int a, int r, int g, int b) {
728         setColor((a << 24) | (r << 16) | (g << 8) | b);
729     }
730 
731     /**
732      * Return the width for stroking.
733      * <p />
734      * A value of 0 strokes in hairline mode.
735      * Hairlines always draws a single pixel independent of the canva's matrix.
736      *
737      * @return the paint's stroke width, used whenever the paint's style is
738      *         Stroke or StrokeAndFill.
739      */
getStrokeWidth()740     public native float getStrokeWidth();
741 
742     /**
743      * Set the width for stroking.
744      * Pass 0 to stroke in hairline mode.
745      * Hairlines always draws a single pixel independent of the canva's matrix.
746      *
747      * @param width set the paint's stroke width, used whenever the paint's
748      *              style is Stroke or StrokeAndFill.
749      */
setStrokeWidth(float width)750     public native void setStrokeWidth(float width);
751 
752     /**
753      * Return the paint's stroke miter value. Used to control the behavior
754      * of miter joins when the joins angle is sharp.
755      *
756      * @return the paint's miter limit, used whenever the paint's style is
757      *         Stroke or StrokeAndFill.
758      */
getStrokeMiter()759     public native float getStrokeMiter();
760 
761     /**
762      * Set the paint's stroke miter value. This is used to control the behavior
763      * of miter joins when the joins angle is sharp. This value must be >= 0.
764      *
765      * @param miter set the miter limit on the paint, used whenever the paint's
766      *              style is Stroke or StrokeAndFill.
767      */
setStrokeMiter(float miter)768     public native void setStrokeMiter(float miter);
769 
770     /**
771      * Return the paint's Cap, controlling how the start and end of stroked
772      * lines and paths are treated.
773      *
774      * @return the line cap style for the paint, used whenever the paint's
775      *         style is Stroke or StrokeAndFill.
776      */
getStrokeCap()777     public Cap getStrokeCap() {
778         return sCapArray[native_getStrokeCap(mNativePaint)];
779     }
780 
781     /**
782      * Set the paint's Cap.
783      *
784      * @param cap set the paint's line cap style, used whenever the paint's
785      *            style is Stroke or StrokeAndFill.
786      */
setStrokeCap(Cap cap)787     public void setStrokeCap(Cap cap) {
788         native_setStrokeCap(mNativePaint, cap.nativeInt);
789     }
790 
791     /**
792      * Return the paint's stroke join type.
793      *
794      * @return the paint's Join.
795      */
getStrokeJoin()796     public Join getStrokeJoin() {
797         return sJoinArray[native_getStrokeJoin(mNativePaint)];
798     }
799 
800     /**
801      * Set the paint's Join.
802      *
803      * @param join set the paint's Join, used whenever the paint's style is
804      *             Stroke or StrokeAndFill.
805      */
setStrokeJoin(Join join)806     public void setStrokeJoin(Join join) {
807         native_setStrokeJoin(mNativePaint, join.nativeInt);
808     }
809 
810     /**
811      * Applies any/all effects (patheffect, stroking) to src, returning the
812      * result in dst. The result is that drawing src with this paint will be
813      * the same as drawing dst with a default paint (at least from the
814      * geometric perspective).
815      *
816      * @param src input path
817      * @param dst output path (may be the same as src)
818      * @return    true if the path should be filled, or false if it should be
819      *                 drawn with a hairline (width == 0)
820      */
getFillPath(Path src, Path dst)821     public boolean getFillPath(Path src, Path dst) {
822         return native_getFillPath(mNativePaint, src.ni(), dst.ni());
823     }
824 
825     /**
826      * Get the paint's shader object.
827      *
828      * @return the paint's shader (or null)
829      */
getShader()830     public Shader getShader() {
831         return mShader;
832     }
833 
834     /**
835      * Set or clear the shader object.
836      * <p />
837      * Pass null to clear any previous shader.
838      * As a convenience, the parameter passed is also returned.
839      *
840      * @param shader May be null. the new shader to be installed in the paint
841      * @return       shader
842      */
setShader(Shader shader)843     public Shader setShader(Shader shader) {
844         int shaderNative = 0;
845         if (shader != null)
846             shaderNative = shader.native_instance;
847         native_setShader(mNativePaint, shaderNative);
848         mShader = shader;
849         return shader;
850     }
851 
852     /**
853      * Get the paint's colorfilter (maybe be null).
854      *
855      * @return the paint's colorfilter (maybe be null)
856      */
getColorFilter()857     public ColorFilter getColorFilter() {
858         return mColorFilter;
859     }
860 
861     /**
862      * Set or clear the paint's colorfilter, returning the parameter.
863      *
864      * @param filter May be null. The new filter to be installed in the paint
865      * @return       filter
866      */
setColorFilter(ColorFilter filter)867     public ColorFilter setColorFilter(ColorFilter filter) {
868         int filterNative = 0;
869         if (filter != null)
870             filterNative = filter.native_instance;
871         native_setColorFilter(mNativePaint, filterNative);
872         mColorFilter = filter;
873         return filter;
874     }
875 
876     /**
877      * Get the paint's xfermode object.
878      *
879      * @return the paint's xfermode (or null)
880      */
getXfermode()881     public Xfermode getXfermode() {
882         return mXfermode;
883     }
884 
885     /**
886      * Set or clear the xfermode object.
887      * <p />
888      * Pass null to clear any previous xfermode.
889      * As a convenience, the parameter passed is also returned.
890      *
891      * @param xfermode May be null. The xfermode to be installed in the paint
892      * @return         xfermode
893      */
setXfermode(Xfermode xfermode)894     public Xfermode setXfermode(Xfermode xfermode) {
895         int xfermodeNative = 0;
896         if (xfermode != null)
897             xfermodeNative = xfermode.native_instance;
898         native_setXfermode(mNativePaint, xfermodeNative);
899         mXfermode = xfermode;
900         return xfermode;
901     }
902 
903     /**
904      * Get the paint's patheffect object.
905      *
906      * @return the paint's patheffect (or null)
907      */
getPathEffect()908     public PathEffect getPathEffect() {
909         return mPathEffect;
910     }
911 
912     /**
913      * Set or clear the patheffect object.
914      * <p />
915      * Pass null to clear any previous patheffect.
916      * As a convenience, the parameter passed is also returned.
917      *
918      * @param effect May be null. The patheffect to be installed in the paint
919      * @return       effect
920      */
setPathEffect(PathEffect effect)921     public PathEffect setPathEffect(PathEffect effect) {
922         int effectNative = 0;
923         if (effect != null) {
924             effectNative = effect.native_instance;
925         }
926         native_setPathEffect(mNativePaint, effectNative);
927         mPathEffect = effect;
928         return effect;
929     }
930 
931     /**
932      * Get the paint's maskfilter object.
933      *
934      * @return the paint's maskfilter (or null)
935      */
getMaskFilter()936     public MaskFilter getMaskFilter() {
937         return mMaskFilter;
938     }
939 
940     /**
941      * Set or clear the maskfilter object.
942      * <p />
943      * Pass null to clear any previous maskfilter.
944      * As a convenience, the parameter passed is also returned.
945      *
946      * @param maskfilter May be null. The maskfilter to be installed in the
947      *                   paint
948      * @return           maskfilter
949      */
setMaskFilter(MaskFilter maskfilter)950     public MaskFilter setMaskFilter(MaskFilter maskfilter) {
951         int maskfilterNative = 0;
952         if (maskfilter != null) {
953             maskfilterNative = maskfilter.native_instance;
954         }
955         native_setMaskFilter(mNativePaint, maskfilterNative);
956         mMaskFilter = maskfilter;
957         return maskfilter;
958     }
959 
960     /**
961      * Get the paint's typeface object.
962      * <p />
963      * The typeface object identifies which font to use when drawing or
964      * measuring text.
965      *
966      * @return the paint's typeface (or null)
967      */
getTypeface()968     public Typeface getTypeface() {
969         return mTypeface;
970     }
971 
972     /**
973      * Set or clear the typeface object.
974      * <p />
975      * Pass null to clear any previous typeface.
976      * As a convenience, the parameter passed is also returned.
977      *
978      * @param typeface May be null. The typeface to be installed in the paint
979      * @return         typeface
980      */
setTypeface(Typeface typeface)981     public Typeface setTypeface(Typeface typeface) {
982         int typefaceNative = 0;
983         if (typeface != null) {
984             typefaceNative = typeface.native_instance;
985         }
986         native_setTypeface(mNativePaint, typefaceNative);
987         mTypeface = typeface;
988         return typeface;
989     }
990 
991     /**
992      * Get the paint's rasterizer (or null).
993      * <p />
994      * The raster controls/modifies how paths/text are turned into alpha masks.
995      *
996      * @return         the paint's rasterizer (or null)
997      */
getRasterizer()998     public Rasterizer getRasterizer() {
999         return mRasterizer;
1000     }
1001 
1002     /**
1003      * Set or clear the rasterizer object.
1004      * <p />
1005      * Pass null to clear any previous rasterizer.
1006      * As a convenience, the parameter passed is also returned.
1007      *
1008      * @param rasterizer May be null. The new rasterizer to be installed in
1009      *                   the paint.
1010      * @return           rasterizer
1011      */
setRasterizer(Rasterizer rasterizer)1012     public Rasterizer setRasterizer(Rasterizer rasterizer) {
1013         int rasterizerNative = 0;
1014         if (rasterizer != null) {
1015             rasterizerNative = rasterizer.native_instance;
1016         }
1017         native_setRasterizer(mNativePaint, rasterizerNative);
1018         mRasterizer = rasterizer;
1019         return rasterizer;
1020     }
1021 
1022     /**
1023      * This draws a shadow layer below the main layer, with the specified
1024      * offset and color, and blur radius. If radius is 0, then the shadow
1025      * layer is removed.
1026      */
setShadowLayer(float radius, float dx, float dy, int color)1027     public void setShadowLayer(float radius, float dx, float dy, int color) {
1028         hasShadow = radius > 0.0f;
1029         shadowRadius = radius;
1030         shadowDx = dx;
1031         shadowDy = dy;
1032         shadowColor = color;
1033         nSetShadowLayer(radius, dx, dy, color);
1034     }
1035 
nSetShadowLayer(float radius, float dx, float dy, int color)1036     private native void nSetShadowLayer(float radius, float dx, float dy, int color);
1037 
1038     /**
1039      * Clear the shadow layer.
1040      */
clearShadowLayer()1041     public void clearShadowLayer() {
1042         hasShadow = false;
1043         nSetShadowLayer(0, 0, 0, 0);
1044     }
1045 
1046     /**
1047      * Return the paint's Align value for drawing text. This controls how the
1048      * text is positioned relative to its origin. LEFT align means that all of
1049      * the text will be drawn to the right of its origin (i.e. the origin
1050      * specifieds the LEFT edge of the text) and so on.
1051      *
1052      * @return the paint's Align value for drawing text.
1053      */
getTextAlign()1054     public Align getTextAlign() {
1055         return sAlignArray[native_getTextAlign(mNativePaint)];
1056     }
1057 
1058     /**
1059      * Set the paint's text alignment. This controls how the
1060      * text is positioned relative to its origin. LEFT align means that all of
1061      * the text will be drawn to the right of its origin (i.e. the origin
1062      * specifieds the LEFT edge of the text) and so on.
1063      *
1064      * @param align set the paint's Align value for drawing text.
1065      */
setTextAlign(Align align)1066     public void setTextAlign(Align align) {
1067         native_setTextAlign(mNativePaint, align.nativeInt);
1068     }
1069 
1070     /**
1071      * Get the text Locale.
1072      *
1073      * @return the paint's Locale used for drawing text, never null.
1074      */
getTextLocale()1075     public Locale getTextLocale() {
1076         return mLocale;
1077     }
1078 
1079     /**
1080      * Set the text locale.
1081      *
1082      * The text locale affects how the text is drawn for some languages.
1083      *
1084      * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
1085      * then the text renderer will prefer to draw text using a Chinese font. Likewise,
1086      * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
1087      * renderer will prefer to draw text using a Japanese font.
1088      *
1089      * This distinction is important because Chinese and Japanese text both use many
1090      * of the same Unicode code points but their appearance is subtly different for
1091      * each language.
1092      *
1093      * By default, the text locale is initialized to the system locale (as returned
1094      * by {@link Locale#getDefault}). This assumes that the text to be rendered will
1095      * most likely be in the user's preferred language.
1096      *
1097      * If the actual language of the text is known, then it can be provided to the
1098      * text renderer using this method. The text renderer may attempt to guess the
1099      * language script based on the contents of the text to be drawn independent of
1100      * the text locale here. Specifying the text locale just helps it do a better
1101      * job in certain ambiguous cases
1102      *
1103      * @param locale the paint's locale value for drawing text, must not be null.
1104      */
setTextLocale(Locale locale)1105     public void setTextLocale(Locale locale) {
1106         if (locale == null) {
1107             throw new IllegalArgumentException("locale cannot be null");
1108         }
1109         if (locale.equals(mLocale)) return;
1110         mLocale = locale;
1111         native_setTextLocale(mNativePaint, locale.toString());
1112     }
1113 
1114     /**
1115      * Return the paint's text size.
1116      *
1117      * @return the paint's text size.
1118      */
getTextSize()1119     public native float getTextSize();
1120 
1121     /**
1122      * Set the paint's text size. This value must be > 0
1123      *
1124      * @param textSize set the paint's text size.
1125      */
setTextSize(float textSize)1126     public native void setTextSize(float textSize);
1127 
1128     /**
1129      * Return the paint's horizontal scale factor for text. The default value
1130      * is 1.0.
1131      *
1132      * @return the paint's scale factor in X for drawing/measuring text
1133      */
getTextScaleX()1134     public native float getTextScaleX();
1135 
1136     /**
1137      * Set the paint's horizontal scale factor for text. The default value
1138      * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
1139      * stretch the text narrower.
1140      *
1141      * @param scaleX set the paint's scale in X for drawing/measuring text.
1142      */
setTextScaleX(float scaleX)1143     public native void setTextScaleX(float scaleX);
1144 
1145     /**
1146      * Return the paint's horizontal skew factor for text. The default value
1147      * is 0.
1148      *
1149      * @return         the paint's skew factor in X for drawing text.
1150      */
getTextSkewX()1151     public native float getTextSkewX();
1152 
1153     /**
1154      * Set the paint's horizontal skew factor for text. The default value
1155      * is 0. For approximating oblique text, use values around -0.25.
1156      *
1157      * @param skewX set the paint's skew factor in X for drawing text.
1158      */
setTextSkewX(float skewX)1159     public native void setTextSkewX(float skewX);
1160 
1161     /**
1162      * Return the distance above (negative) the baseline (ascent) based on the
1163      * current typeface and text size.
1164      *
1165      * @return the distance above (negative) the baseline (ascent) based on the
1166      *         current typeface and text size.
1167      */
ascent()1168     public native float ascent();
1169 
1170     /**
1171      * Return the distance below (positive) the baseline (descent) based on the
1172      * current typeface and text size.
1173      *
1174      * @return the distance below (positive) the baseline (descent) based on
1175      *         the current typeface and text size.
1176      */
descent()1177     public native float descent();
1178 
1179     /**
1180      * Class that describes the various metrics for a font at a given text size.
1181      * Remember, Y values increase going down, so those values will be positive,
1182      * and values that measure distances going up will be negative. This class
1183      * is returned by getFontMetrics().
1184      */
1185     public static class FontMetrics {
1186         /**
1187          * The maximum distance above the baseline for the tallest glyph in
1188          * the font at a given text size.
1189          */
1190         public float   top;
1191         /**
1192          * The recommended distance above the baseline for singled spaced text.
1193          */
1194         public float   ascent;
1195         /**
1196          * The recommended distance below the baseline for singled spaced text.
1197          */
1198         public float   descent;
1199         /**
1200          * The maximum distance below the baseline for the lowest glyph in
1201          * the font at a given text size.
1202          */
1203         public float   bottom;
1204         /**
1205          * The recommended additional space to add between lines of text.
1206          */
1207         public float   leading;
1208     }
1209 
1210     /**
1211      * Return the font's recommended interline spacing, given the Paint's
1212      * settings for typeface, textSize, etc. If metrics is not null, return the
1213      * fontmetric values in it.
1214      *
1215      * @param metrics If this object is not null, its fields are filled with
1216      *                the appropriate values given the paint's text attributes.
1217      * @return the font's recommended interline spacing.
1218      */
getFontMetrics(FontMetrics metrics)1219     public native float getFontMetrics(FontMetrics metrics);
1220 
1221     /**
1222      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
1223      * with it, returning the object.
1224      */
getFontMetrics()1225     public FontMetrics getFontMetrics() {
1226         FontMetrics fm = new FontMetrics();
1227         getFontMetrics(fm);
1228         return fm;
1229     }
1230 
1231     /**
1232      * Convenience method for callers that want to have FontMetrics values as
1233      * integers.
1234      */
1235     public static class FontMetricsInt {
1236         public int   top;
1237         public int   ascent;
1238         public int   descent;
1239         public int   bottom;
1240         public int   leading;
1241 
toString()1242         @Override public String toString() {
1243             return "FontMetricsInt: top=" + top + " ascent=" + ascent +
1244                     " descent=" + descent + " bottom=" + bottom +
1245                     " leading=" + leading;
1246         }
1247     }
1248 
1249     /**
1250      * Return the font's interline spacing, given the Paint's settings for
1251      * typeface, textSize, etc. If metrics is not null, return the fontmetric
1252      * values in it. Note: all values have been converted to integers from
1253      * floats, in such a way has to make the answers useful for both spacing
1254      * and clipping. If you want more control over the rounding, call
1255      * getFontMetrics().
1256      *
1257      * @return the font's interline spacing.
1258      */
getFontMetricsInt(FontMetricsInt fmi)1259     public native int getFontMetricsInt(FontMetricsInt fmi);
1260 
getFontMetricsInt()1261     public FontMetricsInt getFontMetricsInt() {
1262         FontMetricsInt fm = new FontMetricsInt();
1263         getFontMetricsInt(fm);
1264         return fm;
1265     }
1266 
1267     /**
1268      * Return the recommend line spacing based on the current typeface and
1269      * text size.
1270      *
1271      * @return  recommend line spacing based on the current typeface and
1272      *          text size.
1273      */
getFontSpacing()1274     public float getFontSpacing() {
1275         return getFontMetrics(null);
1276     }
1277 
1278     /**
1279      * Return the width of the text.
1280      *
1281      * @param text  The text to measure. Cannot be null.
1282      * @param index The index of the first character to start measuring
1283      * @param count THe number of characters to measure, beginning with start
1284      * @return      The width of the text
1285      */
measureText(char[] text, int index, int count)1286     public float measureText(char[] text, int index, int count) {
1287         if (text == null) {
1288             throw new IllegalArgumentException("text cannot be null");
1289         }
1290         if ((index | count) < 0 || index + count > text.length) {
1291             throw new ArrayIndexOutOfBoundsException();
1292         }
1293 
1294         if (text.length == 0 || count == 0) {
1295             return 0f;
1296         }
1297         if (!mHasCompatScaling) {
1298             return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
1299         }
1300 
1301         final float oldSize = getTextSize();
1302         setTextSize(oldSize*mCompatScaling);
1303         float w = native_measureText(text, index, count, mBidiFlags);
1304         setTextSize(oldSize);
1305         return (float) Math.ceil(w*mInvCompatScaling);
1306     }
1307 
native_measureText(char[] text, int index, int count, int bidiFlags)1308     private native float native_measureText(char[] text, int index, int count, int bidiFlags);
1309 
1310     /**
1311      * Return the width of the text.
1312      *
1313      * @param text  The text to measure. Cannot be null.
1314      * @param start The index of the first character to start measuring
1315      * @param end   1 beyond the index of the last character to measure
1316      * @return      The width of the text
1317      */
measureText(String text, int start, int end)1318     public float measureText(String text, int start, int end) {
1319         if (text == null) {
1320             throw new IllegalArgumentException("text cannot be null");
1321         }
1322         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1323             throw new IndexOutOfBoundsException();
1324         }
1325 
1326         if (text.length() == 0 || start == end) {
1327             return 0f;
1328         }
1329         if (!mHasCompatScaling) {
1330             return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
1331         }
1332 
1333         final float oldSize = getTextSize();
1334         setTextSize(oldSize*mCompatScaling);
1335         float w = native_measureText(text, start, end, mBidiFlags);
1336         setTextSize(oldSize);
1337         return (float) Math.ceil(w*mInvCompatScaling);
1338     }
1339 
native_measureText(String text, int start, int end, int bidiFlags)1340     private native float native_measureText(String text, int start, int end, int bidiFlags);
1341 
1342     /**
1343      * Return the width of the text.
1344      *
1345      * @param text  The text to measure. Cannot be null.
1346      * @return      The width of the text
1347      */
measureText(String text)1348     public float measureText(String text) {
1349         if (text == null) {
1350             throw new IllegalArgumentException("text cannot be null");
1351         }
1352 
1353         if (text.length() == 0) {
1354             return 0f;
1355         }
1356 
1357         if (!mHasCompatScaling) {
1358             return (float) Math.ceil(native_measureText(text, mBidiFlags));
1359         }
1360         final float oldSize = getTextSize();
1361         setTextSize(oldSize*mCompatScaling);
1362         float w = native_measureText(text, mBidiFlags);
1363         setTextSize(oldSize);
1364         return (float) Math.ceil(w*mInvCompatScaling);
1365     }
1366 
native_measureText(String text, int bidiFlags)1367     private native float native_measureText(String text, int bidiFlags);
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, mBidiFlags, measuredWidth);
1435         }
1436 
1437         final float oldSize = getTextSize();
1438         setTextSize(oldSize*mCompatScaling);
1439         int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
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, int bidiFlags, float[] measuredWidth)1446     private native int native_breakText(char[] text, int index, int count,
1447                                         float maxWidth, int bidiFlags, 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, mBidiFlags, measuredWidth);
1525         }
1526 
1527         final float oldSize = getTextSize();
1528         setTextSize(oldSize*mCompatScaling);
1529         int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
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, int bidiFlags, float[] measuredWidth)1536     private native int native_breakText(String text, boolean measureForwards,
1537                                         float maxWidth, int bidiFlags, 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, mBidiFlags, widths);
1564         }
1565 
1566         final float oldSize = getTextSize();
1567         setTextSize(oldSize*mCompatScaling);
1568         int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, 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, mBidiFlags, widths);
1646         }
1647 
1648         final float oldSize = getTextSize();
1649         setTextSize(oldSize*mCompatScaling);
1650         int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, 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 
1721         if (chars == null) {
1722             throw new IllegalArgumentException("text cannot be null");
1723         }
1724         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
1725             throw new IllegalArgumentException("unknown flags value: " + flags);
1726         }
1727         if ((index | count | contextIndex | contextCount | advancesIndex
1728                 | (index - contextIndex) | (contextCount - count)
1729                 | ((contextIndex + contextCount) - (index + count))
1730                 | (chars.length - (contextIndex + contextCount))
1731                 | (advances == null ? 0 :
1732                     (advances.length - (advancesIndex + count)))) < 0) {
1733             throw new IndexOutOfBoundsException();
1734         }
1735 
1736         if (chars.length == 0 || count == 0){
1737             return 0f;
1738         }
1739         if (!mHasCompatScaling) {
1740             return native_getTextRunAdvances(mNativePaint, chars, index, count,
1741                     contextIndex, contextCount, flags, advances, advancesIndex);
1742         }
1743 
1744         final float oldSize = getTextSize();
1745         setTextSize(oldSize * mCompatScaling);
1746         float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
1747                 contextIndex, contextCount, flags, advances, advancesIndex);
1748         setTextSize(oldSize);
1749 
1750         if (advances != null) {
1751             for (int i = advancesIndex, e = i + count; i < e; i++) {
1752                 advances[i] *= mInvCompatScaling;
1753             }
1754         }
1755         return res * mInvCompatScaling; // assume errors are not significant
1756     }
1757 
1758     /**
1759      * Convenience overload that takes a CharSequence instead of a
1760      * String.
1761      *
1762      * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
1763      * @hide
1764      */
getTextRunAdvances(CharSequence text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex)1765     public float getTextRunAdvances(CharSequence text, int start, int end,
1766             int contextStart, int contextEnd, int flags, float[] advances,
1767             int advancesIndex) {
1768 
1769         if (text == null) {
1770             throw new IllegalArgumentException("text cannot be null");
1771         }
1772         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
1773                 | (start - contextStart) | (contextEnd - end)
1774                 | (text.length() - contextEnd)
1775                 | (advances == null ? 0 :
1776                     (advances.length - advancesIndex - (end - start)))) < 0) {
1777             throw new IndexOutOfBoundsException();
1778         }
1779 
1780         if (text instanceof String) {
1781             return getTextRunAdvances((String) text, start, end,
1782                     contextStart, contextEnd, flags, advances, advancesIndex);
1783         }
1784         if (text instanceof SpannedString ||
1785             text instanceof SpannableString) {
1786             return getTextRunAdvances(text.toString(), start, end,
1787                     contextStart, contextEnd, flags, advances, advancesIndex);
1788         }
1789         if (text instanceof GraphicsOperations) {
1790             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
1791                     contextStart, contextEnd, flags, advances, advancesIndex, this);
1792         }
1793         if (text.length() == 0 || end == start) {
1794             return 0f;
1795         }
1796 
1797         int contextLen = contextEnd - contextStart;
1798         int len = end - start;
1799         char[] buf = TemporaryBuffer.obtain(contextLen);
1800         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1801         float result = getTextRunAdvances(buf, start - contextStart, len,
1802                 0, contextLen, flags, advances, advancesIndex);
1803         TemporaryBuffer.recycle(buf);
1804         return result;
1805     }
1806 
1807     /**
1808      * Returns the total advance width for the characters in the run
1809      * between start and end, and if advances is not null, the advance
1810      * assigned to each of these characters (java chars).
1811      *
1812      * <p>The trailing surrogate in a valid surrogate pair is assigned
1813      * an advance of 0.  Thus the number of returned advances is
1814      * always equal to count, not to the number of unicode codepoints
1815      * represented by the run.
1816      *
1817      * <p>In the case of conjuncts or combining marks, the total
1818      * advance is assigned to the first logical character, and the
1819      * following characters are assigned an advance of 0.
1820      *
1821      * <p>This generates the sum of the advances of glyphs for
1822      * characters in a reordered cluster as the width of the first
1823      * logical character in the cluster, and 0 for the widths of all
1824      * other characters in the cluster.  In effect, such clusters are
1825      * treated like conjuncts.
1826      *
1827      * <p>The shaping bounds limit the amount of context available
1828      * outside start and end that can be used for shaping analysis.
1829      * These bounds typically reflect changes in bidi level or font
1830      * metrics across which shaping does not occur.
1831      *
1832      * @param text the text to measure. Cannot be null.
1833      * @param start the index of the first character to measure
1834      * @param end the index past the last character to measure
1835      * @param contextStart the index of the first character to use for shaping context,
1836      * must be <= start
1837      * @param contextEnd the index past the last character to use for shaping context,
1838      * must be >= end
1839      * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
1840      * or {@link #DIRECTION_RTL}
1841      * @param advances array to receive the advances, must have room for all advances,
1842      * can be null if only total advance is needed
1843      * @param advancesIndex the position in advances at which to put the
1844      * advance corresponding to the character at start
1845      * @return the total advance
1846      *
1847      * @hide
1848      */
getTextRunAdvances(String text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex)1849     public float getTextRunAdvances(String text, int start, int end, int contextStart,
1850             int contextEnd, int flags, float[] advances, int advancesIndex) {
1851 
1852         if (text == null) {
1853             throw new IllegalArgumentException("text cannot be null");
1854         }
1855         if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
1856             throw new IllegalArgumentException("unknown flags value: " + flags);
1857         }
1858         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
1859                 | (start - contextStart) | (contextEnd - end)
1860                 | (text.length() - contextEnd)
1861                 | (advances == null ? 0 :
1862                     (advances.length - advancesIndex - (end - start)))) < 0) {
1863             throw new IndexOutOfBoundsException();
1864         }
1865 
1866         if (text.length() == 0 || start == end) {
1867             return 0f;
1868         }
1869 
1870         if (!mHasCompatScaling) {
1871             return native_getTextRunAdvances(mNativePaint, text, start, end,
1872                     contextStart, contextEnd, flags, advances, advancesIndex);
1873         }
1874 
1875         final float oldSize = getTextSize();
1876         setTextSize(oldSize * mCompatScaling);
1877         float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
1878                 contextStart, contextEnd, flags, advances, advancesIndex);
1879         setTextSize(oldSize);
1880 
1881         if (advances != null) {
1882             for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
1883                 advances[i] *= mInvCompatScaling;
1884             }
1885         }
1886         return totalAdvance * mInvCompatScaling; // assume errors are insignificant
1887     }
1888 
1889     /**
1890      * Returns the next cursor position in the run.  This avoids placing the
1891      * cursor between surrogates, between characters that form conjuncts,
1892      * between base characters and combining marks, or within a reordering
1893      * cluster.
1894      *
1895      * <p>ContextStart and offset are relative to the start of text.
1896      * The context is the shaping context for cursor movement, generally
1897      * the bounds of the metric span enclosing the cursor in the direction of
1898      * movement.
1899      *
1900      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
1901      * cursor position, this returns -1.  Otherwise this will never return a
1902      * value before contextStart or after contextStart + contextLength.
1903      *
1904      * @param text the text
1905      * @param contextStart the start of the context
1906      * @param contextLength the length of the context
1907      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
1908      * @param offset the cursor position to move from
1909      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
1910      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
1911      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
1912      * @return the offset of the next position, or -1
1913      * @hide
1914      */
getTextRunCursor(char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)1915     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
1916             int flags, int offset, int cursorOpt) {
1917         int contextEnd = contextStart + contextLength;
1918         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
1919                 | (offset - contextStart) | (contextEnd - offset)
1920                 | (text.length - contextEnd) | cursorOpt) < 0)
1921                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
1922             throw new IndexOutOfBoundsException();
1923         }
1924 
1925         return native_getTextRunCursor(mNativePaint, text,
1926                 contextStart, contextLength, flags, offset, cursorOpt);
1927     }
1928 
1929     /**
1930      * Returns the next cursor position in the run.  This avoids placing the
1931      * cursor between surrogates, between characters that form conjuncts,
1932      * between base characters and combining marks, or within a reordering
1933      * cluster.
1934      *
1935      * <p>ContextStart, contextEnd, and offset are relative to the start of
1936      * text.  The context is the shaping context for cursor movement, generally
1937      * the bounds of the metric span enclosing the cursor in the direction of
1938      * movement.
1939      *
1940      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
1941      * cursor position, this returns -1.  Otherwise this will never return a
1942      * value before contextStart or after contextEnd.
1943      *
1944      * @param text the text
1945      * @param contextStart the start of the context
1946      * @param contextEnd the end of the context
1947      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
1948      * @param offset the cursor position to move from
1949      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
1950      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
1951      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
1952      * @return the offset of the next position, or -1
1953      * @hide
1954      */
getTextRunCursor(CharSequence text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)1955     public int getTextRunCursor(CharSequence text, int contextStart,
1956            int contextEnd, int flags, int offset, int cursorOpt) {
1957 
1958         if (text instanceof String || text instanceof SpannedString ||
1959                 text instanceof SpannableString) {
1960             return getTextRunCursor(text.toString(), contextStart, contextEnd,
1961                     flags, offset, cursorOpt);
1962         }
1963         if (text instanceof GraphicsOperations) {
1964             return ((GraphicsOperations) text).getTextRunCursor(
1965                     contextStart, contextEnd, flags, offset, cursorOpt, this);
1966         }
1967 
1968         int contextLen = contextEnd - contextStart;
1969         char[] buf = TemporaryBuffer.obtain(contextLen);
1970         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1971         int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
1972         TemporaryBuffer.recycle(buf);
1973         return result;
1974     }
1975 
1976     /**
1977      * Returns the next cursor position in the run.  This avoids placing the
1978      * cursor between surrogates, between characters that form conjuncts,
1979      * between base characters and combining marks, or within a reordering
1980      * cluster.
1981      *
1982      * <p>ContextStart, contextEnd, and offset are relative to the start of
1983      * text.  The context is the shaping context for cursor movement, generally
1984      * the bounds of the metric span enclosing the cursor in the direction of
1985      * movement.
1986      *
1987      * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
1988      * cursor position, this returns -1.  Otherwise this will never return a
1989      * value before contextStart or after contextEnd.
1990      *
1991      * @param text the text
1992      * @param contextStart the start of the context
1993      * @param contextEnd the end of the context
1994      * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
1995      * @param offset the cursor position to move from
1996      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
1997      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
1998      * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
1999      * @return the offset of the next position, or -1
2000      * @hide
2001      */
getTextRunCursor(String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)2002     public int getTextRunCursor(String text, int contextStart, int contextEnd,
2003             int flags, int offset, int cursorOpt) {
2004         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
2005                 | (offset - contextStart) | (contextEnd - offset)
2006                 | (text.length() - contextEnd) | cursorOpt) < 0)
2007                 || cursorOpt > CURSOR_OPT_MAX_VALUE) {
2008             throw new IndexOutOfBoundsException();
2009         }
2010 
2011         return native_getTextRunCursor(mNativePaint, text,
2012                 contextStart, contextEnd, flags, offset, cursorOpt);
2013     }
2014 
2015     /**
2016      * Return the path (outline) for the specified text.
2017      * Note: just like Canvas.drawText, this will respect the Align setting in
2018      * the paint.
2019      *
2020      * @param text     The text to retrieve the path from
2021      * @param index    The index of the first character in text
2022      * @param count    The number of characterss starting with index
2023      * @param x        The x coordinate of the text's origin
2024      * @param y        The y coordinate of the text's origin
2025      * @param path     The path to receive the data describing the text. Must
2026      *                 be allocated by the caller.
2027      */
getTextPath(char[] text, int index, int count, float x, float y, Path path)2028     public void getTextPath(char[] text, int index, int count,
2029                             float x, float y, Path path) {
2030         if ((index | count) < 0 || index + count > text.length) {
2031             throw new ArrayIndexOutOfBoundsException();
2032         }
2033         native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y,
2034                 path.ni());
2035     }
2036 
2037     /**
2038      * Return the path (outline) for the specified text.
2039      * Note: just like Canvas.drawText, this will respect the Align setting
2040      * in the paint.
2041      *
2042      * @param text  The text to retrieve the path from
2043      * @param start The first character in the text
2044      * @param end   1 past the last charcter in the text
2045      * @param x     The x coordinate of the text's origin
2046      * @param y     The y coordinate of the text's origin
2047      * @param path  The path to receive the data describing the text. Must
2048      *              be allocated by the caller.
2049      */
getTextPath(String text, int start, int end, float x, float y, Path path)2050     public void getTextPath(String text, int start, int end,
2051                             float x, float y, Path path) {
2052         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2053             throw new IndexOutOfBoundsException();
2054         }
2055         native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y,
2056                 path.ni());
2057     }
2058 
2059     /**
2060      * Return in bounds (allocated by the caller) the smallest rectangle that
2061      * encloses all of the characters, with an implied origin at (0,0).
2062      *
2063      * @param text  String to measure and return its bounds
2064      * @param start Index of the first char in the string to measure
2065      * @param end   1 past the last char in the string measure
2066      * @param bounds Returns the unioned bounds of all the text. Must be
2067      *               allocated by the caller.
2068      */
getTextBounds(String text, int start, int end, Rect bounds)2069     public void getTextBounds(String text, int start, int end, Rect bounds) {
2070         if ((start | end | (end - start) | (text.length() - end)) < 0) {
2071             throw new IndexOutOfBoundsException();
2072         }
2073         if (bounds == null) {
2074             throw new NullPointerException("need bounds Rect");
2075         }
2076         nativeGetStringBounds(mNativePaint, text, start, end, mBidiFlags, bounds);
2077     }
2078 
2079     /**
2080      * Return in bounds (allocated by the caller) the smallest rectangle that
2081      * encloses all of the characters, with an implied origin at (0,0).
2082      *
2083      * @param text  Array of chars to measure and return their unioned bounds
2084      * @param index Index of the first char in the array to measure
2085      * @param count The number of chars, beginning at index, to measure
2086      * @param bounds Returns the unioned bounds of all the text. Must be
2087      *               allocated by the caller.
2088      */
getTextBounds(char[] text, int index, int count, Rect bounds)2089     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
2090         if ((index | count) < 0 || index + count > text.length) {
2091             throw new ArrayIndexOutOfBoundsException();
2092         }
2093         if (bounds == null) {
2094             throw new NullPointerException("need bounds Rect");
2095         }
2096         nativeGetCharArrayBounds(mNativePaint, text, index, count, mBidiFlags, bounds);
2097     }
2098 
2099     @Override
finalize()2100     protected void finalize() throws Throwable {
2101         try {
2102             finalizer(mNativePaint);
2103         } finally {
2104             super.finalize();
2105         }
2106     }
2107 
native_init()2108     private static native int native_init();
native_initWithPaint(int paint)2109     private static native int native_initWithPaint(int paint);
native_reset(int native_object)2110     private static native void native_reset(int native_object);
native_set(int native_dst, int native_src)2111     private static native void native_set(int native_dst, int native_src);
native_getStyle(int native_object)2112     private static native int native_getStyle(int native_object);
native_setStyle(int native_object, int style)2113     private static native void native_setStyle(int native_object, int style);
native_getStrokeCap(int native_object)2114     private static native int native_getStrokeCap(int native_object);
native_setStrokeCap(int native_object, int cap)2115     private static native void native_setStrokeCap(int native_object, int cap);
native_getStrokeJoin(int native_object)2116     private static native int native_getStrokeJoin(int native_object);
native_setStrokeJoin(int native_object, int join)2117     private static native void native_setStrokeJoin(int native_object,
2118                                                     int join);
native_getFillPath(int native_object, int src, int dst)2119     private static native boolean native_getFillPath(int native_object,
2120                                                      int src, int dst);
native_setShader(int native_object, int shader)2121     private static native int native_setShader(int native_object, int shader);
native_setColorFilter(int native_object, int filter)2122     private static native int native_setColorFilter(int native_object,
2123                                                     int filter);
native_setXfermode(int native_object, int xfermode)2124     private static native int native_setXfermode(int native_object,
2125                                                  int xfermode);
native_setPathEffect(int native_object, int effect)2126     private static native int native_setPathEffect(int native_object,
2127                                                    int effect);
native_setMaskFilter(int native_object, int maskfilter)2128     private static native int native_setMaskFilter(int native_object,
2129                                                    int maskfilter);
native_setTypeface(int native_object, int typeface)2130     private static native int native_setTypeface(int native_object,
2131                                                  int typeface);
native_setRasterizer(int native_object, int rasterizer)2132     private static native int native_setRasterizer(int native_object,
2133                                                    int rasterizer);
2134 
native_getTextAlign(int native_object)2135     private static native int native_getTextAlign(int native_object);
native_setTextAlign(int native_object, int align)2136     private static native void native_setTextAlign(int native_object,
2137                                                    int align);
2138 
native_setTextLocale(int native_object, String locale)2139     private static native void native_setTextLocale(int native_object,
2140                                                     String locale);
2141 
native_getTextWidths(int native_object, char[] text, int index, int count, int bidiFlags, float[] widths)2142     private static native int native_getTextWidths(int native_object,
2143                             char[] text, int index, int count, int bidiFlags, float[] widths);
native_getTextWidths(int native_object, String text, int start, int end, int bidiFlags, float[] widths)2144     private static native int native_getTextWidths(int native_object,
2145                             String text, int start, int end, int bidiFlags, float[] widths);
2146 
native_getTextGlyphs(int native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, char[] glyphs)2147     private static native int native_getTextGlyphs(int native_object,
2148             String text, int start, int end, int contextStart, int contextEnd,
2149             int flags, char[] glyphs);
2150 
native_getTextRunAdvances(int native_object, char[] text, int index, int count, int contextIndex, int contextCount, int flags, float[] advances, int advancesIndex)2151     private static native float native_getTextRunAdvances(int native_object,
2152             char[] text, int index, int count, int contextIndex, int contextCount,
2153             int flags, float[] advances, int advancesIndex);
native_getTextRunAdvances(int native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex)2154     private static native float native_getTextRunAdvances(int native_object,
2155             String text, int start, int end, int contextStart, int contextEnd,
2156             int flags, float[] advances, int advancesIndex);
2157 
native_getTextRunCursor(int native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)2158     private native int native_getTextRunCursor(int native_object, char[] text,
2159             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)2160     private native int native_getTextRunCursor(int native_object, String text,
2161             int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
2162 
native_getTextPath(int native_object, int bidiFlags, char[] text, int index, int count, float x, float y, int path)2163     private static native void native_getTextPath(int native_object, int bidiFlags,
2164                 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)2165     private static native void native_getTextPath(int native_object, int bidiFlags,
2166                 String text, int start, int end, float x, float y, int path);
nativeGetStringBounds(int nativePaint, String text, int start, int end, int bidiFlags, Rect bounds)2167     private static native void nativeGetStringBounds(int nativePaint,
2168                                 String text, int start, int end, int bidiFlags, Rect bounds);
nativeGetCharArrayBounds(int nativePaint, char[] text, int index, int count, int bidiFlags, Rect bounds)2169     private static native void nativeGetCharArrayBounds(int nativePaint,
2170                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
finalizer(int nativePaint)2171     private static native void finalizer(int nativePaint);
2172 }
2173