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