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