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