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