Paint.java revision 15c097a1c23105cdc0dd66dd5605ff35467d7118
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 (text == null || text.length == 0 || count == 0) { 1189 return 0f; 1190 } 1191 if (!mHasCompatScaling) return native_measureText(text, index, count); 1192 final float oldSize = getTextSize(); 1193 setTextSize(oldSize*mCompatScaling); 1194 float w = native_measureText(text, index, count); 1195 setTextSize(oldSize); 1196 return w*mInvCompatScaling; 1197 } 1198 1199 private native float native_measureText(char[] text, int index, int count); 1200 1201 /** 1202 * Return the width of the text. 1203 * 1204 * @param text The text to measure 1205 * @param start The index of the first character to start measuring 1206 * @param end 1 beyond the index of the last character to measure 1207 * @return The width of the text 1208 */ 1209 public float measureText(String text, int start, int end) { 1210 if (text == null || text.length() == 0 || start == end) { 1211 return 0f; 1212 } 1213 if (!mHasCompatScaling) return native_measureText(text, start, end); 1214 final float oldSize = getTextSize(); 1215 setTextSize(oldSize*mCompatScaling); 1216 float w = native_measureText(text, start, end); 1217 setTextSize(oldSize); 1218 return w*mInvCompatScaling; 1219 } 1220 1221 private native float native_measureText(String text, int start, int end); 1222 1223 /** 1224 * Return the width of the text. 1225 * 1226 * @param text The text to measure 1227 * @return The width of the text 1228 */ 1229 public float measureText(String text) { 1230 if (text == null || text.length() == 0) { 1231 return 0f; 1232 } 1233 if (!mHasCompatScaling) return native_measureText(text); 1234 final float oldSize = getTextSize(); 1235 setTextSize(oldSize*mCompatScaling); 1236 float w = native_measureText(text); 1237 setTextSize(oldSize); 1238 return w*mInvCompatScaling; 1239 } 1240 1241 private native float native_measureText(String text); 1242 1243 /** 1244 * Return the width of the text. 1245 * 1246 * @param text The text to measure 1247 * @param start The index of the first character to start measuring 1248 * @param end 1 beyond the index of the last character to measure 1249 * @return The width of the text 1250 */ 1251 public float measureText(CharSequence text, int start, int end) { 1252 if (text == null || text.length() == 0 || start == end) { 1253 return 0f; 1254 } 1255 if (text instanceof String) { 1256 return measureText((String)text, start, end); 1257 } 1258 if (text instanceof SpannedString || 1259 text instanceof SpannableString) { 1260 return measureText(text.toString(), start, end); 1261 } 1262 if (text instanceof GraphicsOperations) { 1263 return ((GraphicsOperations)text).measureText(start, end, this); 1264 } 1265 1266 char[] buf = TemporaryBuffer.obtain(end - start); 1267 TextUtils.getChars(text, start, end, buf, 0); 1268 float result = measureText(buf, 0, end - start); 1269 TemporaryBuffer.recycle(buf); 1270 return result; 1271 } 1272 1273 /** 1274 * Measure the text, stopping early if the measured width exceeds maxWidth. 1275 * Return the number of chars that were measured, and if measuredWidth is 1276 * not null, return in it the actual width measured. 1277 * 1278 * @param text The text to measure 1279 * @param index The offset into text to begin measuring at 1280 * @param count The number of maximum number of entries to measure. If count 1281 * is negative, then the characters are measured in reverse order. 1282 * @param maxWidth The maximum width to accumulate. 1283 * @param measuredWidth Optional. If not null, returns the actual width 1284 * measured. 1285 * @return The number of chars that were measured. Will always be <= 1286 * abs(count). 1287 */ 1288 public int breakText(char[] text, int index, int count, 1289 float maxWidth, float[] measuredWidth) { 1290 if (text == null || text.length == 0 || count == 0) { 1291 return 0; 1292 } 1293 if (!mHasCompatScaling) { 1294 return native_breakText(text, index, count, maxWidth, measuredWidth); 1295 } 1296 final float oldSize = getTextSize(); 1297 setTextSize(oldSize*mCompatScaling); 1298 int res = native_breakText(text, index, count, maxWidth*mCompatScaling, 1299 measuredWidth); 1300 setTextSize(oldSize); 1301 if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling; 1302 return res; 1303 } 1304 1305 private native int native_breakText(char[] text, int index, int count, 1306 float maxWidth, float[] measuredWidth); 1307 1308 /** 1309 * Measure the text, stopping early if the measured width exceeds maxWidth. 1310 * Return the number of chars that were measured, and if measuredWidth is 1311 * not null, return in it the actual width measured. 1312 * 1313 * @param text The text to measure 1314 * @param start The offset into text to begin measuring at 1315 * @param end The end of the text slice to measure. 1316 * @param measureForwards If true, measure forwards, starting at start. 1317 * Otherwise, measure backwards, starting with end. 1318 * @param maxWidth The maximum width to accumulate. 1319 * @param measuredWidth Optional. If not null, returns the actual width 1320 * measured. 1321 * @return The number of chars that were measured. Will always be <= 1322 * abs(end - start). 1323 */ 1324 public int breakText(CharSequence text, int start, int end, 1325 boolean measureForwards, 1326 float maxWidth, float[] measuredWidth) { 1327 if (text == null || text.length() == 0 || start == end) { 1328 return 0; 1329 } 1330 if (start == 0 && text instanceof String && end == text.length()) { 1331 return breakText((String) text, measureForwards, maxWidth, 1332 measuredWidth); 1333 } 1334 1335 char[] buf = TemporaryBuffer.obtain(end - start); 1336 int result; 1337 1338 TextUtils.getChars(text, start, end, buf, 0); 1339 1340 if (measureForwards) { 1341 result = breakText(buf, 0, end - start, maxWidth, measuredWidth); 1342 } else { 1343 result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth); 1344 } 1345 1346 TemporaryBuffer.recycle(buf); 1347 return result; 1348 } 1349 1350 /** 1351 * Measure the text, stopping early if the measured width exceeds maxWidth. 1352 * Return the number of chars that were measured, and if measuredWidth is 1353 * not null, return in it the actual width measured. 1354 * 1355 * @param text The text to measure 1356 * @param measureForwards If true, measure forwards, starting with the 1357 * first character in the string. Otherwise, 1358 * measure backwards, starting with the 1359 * last character in the string. 1360 * @param maxWidth The maximum width to accumulate. 1361 * @param measuredWidth Optional. If not null, returns the actual width 1362 * measured. 1363 * @return The number of chars that were measured. Will always be <= 1364 * abs(count). 1365 */ 1366 public int breakText(String text, boolean measureForwards, 1367 float maxWidth, float[] measuredWidth) { 1368 if (text == null || text.length() == 0) { 1369 return 0; 1370 } 1371 if (!mHasCompatScaling) { 1372 return native_breakText(text, measureForwards, maxWidth, measuredWidth); 1373 } 1374 final float oldSize = getTextSize(); 1375 setTextSize(oldSize*mCompatScaling); 1376 int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, 1377 measuredWidth); 1378 setTextSize(oldSize); 1379 if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling; 1380 return res; 1381 } 1382 1383 private native int native_breakText(String text, boolean measureForwards, 1384 float maxWidth, float[] measuredWidth); 1385 1386 /** 1387 * Return the advance widths for the characters in the string. 1388 * 1389 * @param text The text to measure 1390 * @param index The index of the first char to to measure 1391 * @param count The number of chars starting with index to measure 1392 * @param widths array to receive the advance widths of the characters. 1393 * Must be at least a large as count. 1394 * @return the actual number of widths returned. 1395 */ 1396 public int getTextWidths(char[] text, int index, int count, 1397 float[] widths) { 1398 if (text == null || text.length == 0 || count == 0) { 1399 return 0; 1400 } 1401 if ((index | count) < 0 || index + count > text.length 1402 || count > widths.length) { 1403 throw new ArrayIndexOutOfBoundsException(); 1404 } 1405 1406 if (!mHasCompatScaling) { 1407 return native_getTextWidths(mNativePaint, text, index, count, widths); 1408 } 1409 final float oldSize = getTextSize(); 1410 setTextSize(oldSize*mCompatScaling); 1411 int res = native_getTextWidths(mNativePaint, text, index, count, widths); 1412 setTextSize(oldSize); 1413 for (int i=0; i<res; i++) { 1414 widths[i] *= mInvCompatScaling; 1415 } 1416 return res; 1417 } 1418 1419 /** 1420 * Return the advance widths for the characters in the string. 1421 * 1422 * @param text The text to measure 1423 * @param start The index of the first char to to measure 1424 * @param end The end of the text slice to measure 1425 * @param widths array to receive the advance widths of the characters. 1426 * Must be at least a large as (end - start). 1427 * @return the actual number of widths returned. 1428 */ 1429 public int getTextWidths(CharSequence text, int start, int end, 1430 float[] widths) { 1431 if (text == null || text.length() == 0 || start == end) { 1432 return 0; 1433 } 1434 if (text instanceof String) { 1435 return getTextWidths((String) text, start, end, widths); 1436 } 1437 if (text instanceof SpannedString || 1438 text instanceof SpannableString) { 1439 return getTextWidths(text.toString(), start, end, widths); 1440 } 1441 if (text instanceof GraphicsOperations) { 1442 return ((GraphicsOperations) text).getTextWidths(start, end, 1443 widths, this); 1444 } 1445 1446 char[] buf = TemporaryBuffer.obtain(end - start); 1447 TextUtils.getChars(text, start, end, buf, 0); 1448 int result = getTextWidths(buf, 0, end - start, widths); 1449 TemporaryBuffer.recycle(buf); 1450 return result; 1451 } 1452 1453 /** 1454 * Return the advance widths for the characters in the string. 1455 * 1456 * @param text The text to measure 1457 * @param start The index of the first char to to measure 1458 * @param end The end of the text slice to measure 1459 * @param widths array to receive the advance widths of the characters. 1460 * Must be at least a large as the text. 1461 * @return the number of unichars in the specified text. 1462 */ 1463 public int getTextWidths(String text, int start, int end, float[] widths) { 1464 if (text == null || text.length() == 0 || start == end) { 1465 return 0; 1466 } 1467 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1468 throw new IndexOutOfBoundsException(); 1469 } 1470 if (end - start > widths.length) { 1471 throw new ArrayIndexOutOfBoundsException(); 1472 } 1473 1474 if (!mHasCompatScaling) { 1475 return native_getTextWidths(mNativePaint, text, start, end, widths); 1476 } 1477 final float oldSize = getTextSize(); 1478 setTextSize(oldSize*mCompatScaling); 1479 int res = native_getTextWidths(mNativePaint, text, start, end, widths); 1480 setTextSize(oldSize); 1481 for (int i=0; i<res; i++) { 1482 widths[i] *= mInvCompatScaling; 1483 } 1484 return res; 1485 } 1486 1487 /** 1488 * Return the advance widths for the characters in the string. 1489 * 1490 * @param text The text to measure 1491 * @param widths array to receive the advance widths of the characters. 1492 * Must be at least a large as the text. 1493 * @return the number of unichars in the specified text. 1494 */ 1495 public int getTextWidths(String text, float[] widths) { 1496 return getTextWidths(text, 0, text.length(), widths); 1497 } 1498 1499 /** 1500 * Return the glypth Ids for the characters in the string. 1501 * 1502 * @param text The text to measure 1503 * @param start The index of the first char to to measure 1504 * @param end The end of the text slice to measure 1505 * @param contextStart the index of the first character to use for shaping context, 1506 * must be <= start 1507 * @param contextEnd the index past the last character to use for shaping context, 1508 * must be >= end 1509 * @param flags the flags to control the advances, either {@link #DIRECTION_LTR} 1510 * or {@link #DIRECTION_RTL} 1511 * @param glyphs array to receive the glyph Ids of the characters. 1512 * Must be at least a large as the text. 1513 * @return the number of glyphs in the returned array 1514 * 1515 * @hide 1516 * 1517 * Used only for BiDi / RTL Tests 1518 */ 1519 public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd, 1520 int flags, char[] glyphs) { 1521 if ((start | end | contextStart | contextEnd | (end - start) 1522 | (start - contextStart) | (contextEnd - end) | (text.length() - end) 1523 | (text.length() - contextEnd)) < 0) { 1524 throw new IndexOutOfBoundsException(); 1525 } 1526 if (end - start > glyphs.length) { 1527 throw new ArrayIndexOutOfBoundsException(); 1528 } 1529 if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { 1530 throw new IllegalArgumentException("unknown flags value: " + flags); 1531 } 1532 return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd, 1533 flags, glyphs); 1534 } 1535 1536 /** 1537 * Convenience overload that takes a char array instead of a 1538 * String. 1539 * 1540 * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int) 1541 * @hide 1542 */ 1543 public float getTextRunAdvances(char[] chars, int index, int count, 1544 int contextIndex, int contextCount, int flags, float[] advances, 1545 int advancesIndex) { 1546 return getTextRunAdvances(chars, index, count, contextIndex, contextCount, flags, 1547 advances, advancesIndex, 0 /* use Harfbuzz*/); 1548 } 1549 1550 /** 1551 * Convenience overload that takes a char array instead of a 1552 * String. 1553 * 1554 * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int, int) 1555 * @hide 1556 */ 1557 public float getTextRunAdvances(char[] chars, int index, int count, 1558 int contextIndex, int contextCount, int flags, float[] advances, 1559 int advancesIndex, int reserved) { 1560 1561 if (chars == null || chars.length == 0){ 1562 return 0f; 1563 } 1564 if ((index | count | contextIndex | contextCount | advancesIndex 1565 | (index - contextIndex) 1566 | ((contextIndex + contextCount) - (index + count)) 1567 | (chars.length - (contextIndex + contextCount)) 1568 | (advances == null ? 0 : 1569 (advances.length - (advancesIndex + count)))) < 0) { 1570 throw new IndexOutOfBoundsException(); 1571 } 1572 if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { 1573 throw new IllegalArgumentException("unknown flags value: " + flags); 1574 } 1575 1576 if (!mHasCompatScaling) { 1577 return native_getTextRunAdvances(mNativePaint, chars, index, count, 1578 contextIndex, contextCount, flags, advances, advancesIndex, reserved); 1579 } 1580 1581 final float oldSize = getTextSize(); 1582 setTextSize(oldSize * mCompatScaling); 1583 float res = native_getTextRunAdvances(mNativePaint, chars, index, count, 1584 contextIndex, contextCount, flags, advances, advancesIndex, reserved); 1585 setTextSize(oldSize); 1586 1587 if (advances != null) { 1588 for (int i = advancesIndex, e = i + count; i < e; i++) { 1589 advances[i] *= mInvCompatScaling; 1590 } 1591 } 1592 return res * mInvCompatScaling; // assume errors are not significant 1593 } 1594 1595 /** 1596 * Convenience overload that takes a CharSequence instead of a 1597 * String. 1598 * 1599 * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int) 1600 * @hide 1601 */ 1602 public float getTextRunAdvances(CharSequence text, int start, int end, 1603 int contextStart, int contextEnd, int flags, float[] advances, 1604 int advancesIndex) { 1605 return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags, 1606 advances, advancesIndex, 0 /* use Harfbuzz */); 1607 } 1608 1609 /** 1610 * Convenience overload that takes a CharSequence instead of a 1611 * String. 1612 * 1613 * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int) 1614 * @hide 1615 */ 1616 public float getTextRunAdvances(CharSequence text, int start, int end, 1617 int contextStart, int contextEnd, int flags, float[] advances, 1618 int advancesIndex, int reserved) { 1619 1620 if (text == null || text.length() == 0) { 1621 return 0f; 1622 } 1623 if (text instanceof String) { 1624 return getTextRunAdvances((String) text, start, end, 1625 contextStart, contextEnd, flags, advances, advancesIndex, reserved); 1626 } 1627 if (text instanceof SpannedString || 1628 text instanceof SpannableString) { 1629 return getTextRunAdvances(text.toString(), start, end, 1630 contextStart, contextEnd, flags, advances, advancesIndex, reserved); 1631 } 1632 if (text instanceof GraphicsOperations) { 1633 return ((GraphicsOperations) text).getTextRunAdvances(start, end, 1634 contextStart, contextEnd, flags, advances, advancesIndex, this); 1635 } 1636 1637 int contextLen = contextEnd - contextStart; 1638 int len = end - start; 1639 char[] buf = TemporaryBuffer.obtain(contextLen); 1640 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 1641 float result = getTextRunAdvances(buf, start - contextStart, len, 1642 0, contextLen, flags, advances, advancesIndex, reserved); 1643 TemporaryBuffer.recycle(buf); 1644 return result; 1645 } 1646 1647 /** 1648 * Returns the total advance width for the characters in the run 1649 * between start and end, and if advances is not null, the advance 1650 * assigned to each of these characters (java chars). 1651 * 1652 * <p>The trailing surrogate in a valid surrogate pair is assigned 1653 * an advance of 0. Thus the number of returned advances is 1654 * always equal to count, not to the number of unicode codepoints 1655 * represented by the run. 1656 * 1657 * <p>In the case of conjuncts or combining marks, the total 1658 * advance is assigned to the first logical character, and the 1659 * following characters are assigned an advance of 0. 1660 * 1661 * <p>This generates the sum of the advances of glyphs for 1662 * characters in a reordered cluster as the width of the first 1663 * logical character in the cluster, and 0 for the widths of all 1664 * other characters in the cluster. In effect, such clusters are 1665 * treated like conjuncts. 1666 * 1667 * <p>The shaping bounds limit the amount of context available 1668 * outside start and end that can be used for shaping analysis. 1669 * These bounds typically reflect changes in bidi level or font 1670 * metrics across which shaping does not occur. 1671 * 1672 * @param text the text to measure 1673 * @param start the index of the first character to measure 1674 * @param end the index past the last character to measure 1675 * @param contextStart the index of the first character to use for shaping context, 1676 * must be <= start 1677 * @param contextEnd the index past the last character to use for shaping context, 1678 * must be >= end 1679 * @param flags the flags to control the advances, either {@link #DIRECTION_LTR} 1680 * or {@link #DIRECTION_RTL} 1681 * @param advances array to receive the advances, must have room for all advances, 1682 * can be null if only total advance is needed 1683 * @param advancesIndex the position in advances at which to put the 1684 * advance corresponding to the character at start 1685 * @return the total advance 1686 * 1687 * @hide 1688 */ 1689 public float getTextRunAdvances(String text, int start, int end, int contextStart, 1690 int contextEnd, int flags, float[] advances, int advancesIndex) { 1691 return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags, 1692 advances, advancesIndex, 0 /* use Harfbuzz*/); 1693 } 1694 1695 /** 1696 * Returns the total advance width for the characters in the run 1697 * between start and end, and if advances is not null, the advance 1698 * assigned to each of these characters (java chars). 1699 * 1700 * <p>The trailing surrogate in a valid surrogate pair is assigned 1701 * an advance of 0. Thus the number of returned advances is 1702 * always equal to count, not to the number of unicode codepoints 1703 * represented by the run. 1704 * 1705 * <p>In the case of conjuncts or combining marks, the total 1706 * advance is assigned to the first logical character, and the 1707 * following characters are assigned an advance of 0. 1708 * 1709 * <p>This generates the sum of the advances of glyphs for 1710 * characters in a reordered cluster as the width of the first 1711 * logical character in the cluster, and 0 for the widths of all 1712 * other characters in the cluster. In effect, such clusters are 1713 * treated like conjuncts. 1714 * 1715 * <p>The shaping bounds limit the amount of context available 1716 * outside start and end that can be used for shaping analysis. 1717 * These bounds typically reflect changes in bidi level or font 1718 * metrics across which shaping does not occur. 1719 * 1720 * @param text the text to measure 1721 * @param start the index of the first character to measure 1722 * @param end the index past the last character to measure 1723 * @param contextStart the index of the first character to use for shaping context, 1724 * must be <= start 1725 * @param contextEnd the index past the last character to use for shaping context, 1726 * must be >= end 1727 * @param flags the flags to control the advances, either {@link #DIRECTION_LTR} 1728 * or {@link #DIRECTION_RTL} 1729 * @param advances array to receive the advances, must have room for all advances, 1730 * can be null if only total advance is needed 1731 * @param advancesIndex the position in advances at which to put the 1732 * advance corresponding to the character at start 1733 * @param reserved int reserved value 1734 * @return the total advance 1735 * 1736 * @hide 1737 */ 1738 public float getTextRunAdvances(String text, int start, int end, int contextStart, 1739 int contextEnd, int flags, float[] advances, int advancesIndex, int reserved) { 1740 1741 if (text == null || text.length() == 0 || start == end || contextStart == contextEnd) { 1742 return 0f; 1743 } 1744 if ((start | end | contextStart | contextEnd | advancesIndex | (end - start) 1745 | (start - contextStart) | (contextEnd - end) 1746 | (text.length() - contextEnd) 1747 | (advances == null ? 0 : 1748 (advances.length - advancesIndex - (end - start)))) < 0) { 1749 throw new IndexOutOfBoundsException(); 1750 } 1751 if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { 1752 throw new IllegalArgumentException("unknown flags value: " + flags); 1753 } 1754 1755 if (!mHasCompatScaling) { 1756 return native_getTextRunAdvances(mNativePaint, text, start, end, 1757 contextStart, contextEnd, flags, advances, advancesIndex, reserved); 1758 } 1759 1760 final float oldSize = getTextSize(); 1761 setTextSize(oldSize * mCompatScaling); 1762 float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end, 1763 contextStart, contextEnd, flags, advances, advancesIndex, reserved); 1764 setTextSize(oldSize); 1765 1766 if (advances != null) { 1767 for (int i = advancesIndex, e = i + (end - start); i < e; i++) { 1768 advances[i] *= mInvCompatScaling; 1769 } 1770 } 1771 return totalAdvance * mInvCompatScaling; // assume errors are insignificant 1772 } 1773 1774 /** 1775 * Returns the next cursor position in the run. This avoids placing the 1776 * cursor between surrogates, between characters that form conjuncts, 1777 * between base characters and combining marks, or within a reordering 1778 * cluster. 1779 * 1780 * <p>ContextStart and offset are relative to the start of text. 1781 * The context is the shaping context for cursor movement, generally 1782 * the bounds of the metric span enclosing the cursor in the direction of 1783 * movement. 1784 * 1785 * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid 1786 * cursor position, this returns -1. Otherwise this will never return a 1787 * value before contextStart or after contextStart + contextLength. 1788 * 1789 * @param text the text 1790 * @param contextStart the start of the context 1791 * @param contextLength the length of the context 1792 * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} 1793 * @param offset the cursor position to move from 1794 * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, 1795 * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, 1796 * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} 1797 * @return the offset of the next position, or -1 1798 * @hide 1799 */ 1800 public int getTextRunCursor(char[] text, int contextStart, int contextLength, 1801 int flags, int offset, int cursorOpt) { 1802 int contextEnd = contextStart + contextLength; 1803 if (((contextStart | contextEnd | offset | (contextEnd - contextStart) 1804 | (offset - contextStart) | (contextEnd - offset) 1805 | (text.length - contextEnd) | cursorOpt) < 0) 1806 || cursorOpt > CURSOR_OPT_MAX_VALUE) { 1807 throw new IndexOutOfBoundsException(); 1808 } 1809 1810 return native_getTextRunCursor(mNativePaint, text, 1811 contextStart, contextLength, flags, offset, cursorOpt); 1812 } 1813 1814 /** 1815 * Returns the next cursor position in the run. This avoids placing the 1816 * cursor between surrogates, between characters that form conjuncts, 1817 * between base characters and combining marks, or within a reordering 1818 * cluster. 1819 * 1820 * <p>ContextStart, contextEnd, and offset are relative to the start of 1821 * text. The context is the shaping context for cursor movement, generally 1822 * the bounds of the metric span enclosing the cursor in the direction of 1823 * movement. 1824 * 1825 * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid 1826 * cursor position, this returns -1. Otherwise this will never return a 1827 * value before contextStart or after contextEnd. 1828 * 1829 * @param text the text 1830 * @param contextStart the start of the context 1831 * @param contextEnd the end of the context 1832 * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} 1833 * @param offset the cursor position to move from 1834 * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, 1835 * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, 1836 * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} 1837 * @return the offset of the next position, or -1 1838 * @hide 1839 */ 1840 public int getTextRunCursor(CharSequence text, int contextStart, 1841 int contextEnd, int flags, int offset, int cursorOpt) { 1842 1843 if (text instanceof String || text instanceof SpannedString || 1844 text instanceof SpannableString) { 1845 return getTextRunCursor(text.toString(), contextStart, contextEnd, 1846 flags, offset, cursorOpt); 1847 } 1848 if (text instanceof GraphicsOperations) { 1849 return ((GraphicsOperations) text).getTextRunCursor( 1850 contextStart, contextEnd, flags, offset, cursorOpt, this); 1851 } 1852 1853 int contextLen = contextEnd - contextStart; 1854 char[] buf = TemporaryBuffer.obtain(contextLen); 1855 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 1856 int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt); 1857 TemporaryBuffer.recycle(buf); 1858 return result; 1859 } 1860 1861 /** 1862 * Returns the next cursor position in the run. This avoids placing the 1863 * cursor between surrogates, between characters that form conjuncts, 1864 * between base characters and combining marks, or within a reordering 1865 * cluster. 1866 * 1867 * <p>ContextStart, contextEnd, and offset are relative to the start of 1868 * text. The context is the shaping context for cursor movement, generally 1869 * the bounds of the metric span enclosing the cursor in the direction of 1870 * movement. 1871 * 1872 * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid 1873 * cursor position, this returns -1. Otherwise this will never return a 1874 * value before contextStart or after contextEnd. 1875 * 1876 * @param text the text 1877 * @param contextStart the start of the context 1878 * @param contextEnd the end of the context 1879 * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} 1880 * @param offset the cursor position to move from 1881 * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, 1882 * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, 1883 * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} 1884 * @return the offset of the next position, or -1 1885 * @hide 1886 */ 1887 public int getTextRunCursor(String text, int contextStart, int contextEnd, 1888 int flags, int offset, int cursorOpt) { 1889 if (((contextStart | contextEnd | offset | (contextEnd - contextStart) 1890 | (offset - contextStart) | (contextEnd - offset) 1891 | (text.length() - contextEnd) | cursorOpt) < 0) 1892 || cursorOpt > CURSOR_OPT_MAX_VALUE) { 1893 throw new IndexOutOfBoundsException(); 1894 } 1895 1896 return native_getTextRunCursor(mNativePaint, text, 1897 contextStart, contextEnd, flags, offset, cursorOpt); 1898 } 1899 1900 /** 1901 * Return the path (outline) for the specified text. 1902 * Note: just like Canvas.drawText, this will respect the Align setting in 1903 * the paint. 1904 * 1905 * @param text The text to retrieve the path from 1906 * @param index The index of the first character in text 1907 * @param count The number of characterss starting with index 1908 * @param x The x coordinate of the text's origin 1909 * @param y The y coordinate of the text's origin 1910 * @param path The path to receive the data describing the text. Must 1911 * be allocated by the caller. 1912 */ 1913 public void getTextPath(char[] text, int index, int count, 1914 float x, float y, Path path) { 1915 if ((index | count) < 0 || index + count > text.length) { 1916 throw new ArrayIndexOutOfBoundsException(); 1917 } 1918 native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, 1919 path.ni()); 1920 } 1921 1922 /** 1923 * Return the path (outline) for the specified text. 1924 * Note: just like Canvas.drawText, this will respect the Align setting 1925 * in the paint. 1926 * 1927 * @param text The text to retrieve the path from 1928 * @param start The first character in the text 1929 * @param end 1 past the last charcter in the text 1930 * @param x The x coordinate of the text's origin 1931 * @param y The y coordinate of the text's origin 1932 * @param path The path to receive the data describing the text. Must 1933 * be allocated by the caller. 1934 */ 1935 public void getTextPath(String text, int start, int end, 1936 float x, float y, Path path) { 1937 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1938 throw new IndexOutOfBoundsException(); 1939 } 1940 native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, 1941 path.ni()); 1942 } 1943 1944 /** 1945 * Return in bounds (allocated by the caller) the smallest rectangle that 1946 * encloses all of the characters, with an implied origin at (0,0). 1947 * 1948 * @param text String to measure and return its bounds 1949 * @param start Index of the first char in the string to measure 1950 * @param end 1 past the last char in the string measure 1951 * @param bounds Returns the unioned bounds of all the text. Must be 1952 * allocated by the caller. 1953 */ 1954 public void getTextBounds(String text, int start, int end, Rect bounds) { 1955 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1956 throw new IndexOutOfBoundsException(); 1957 } 1958 if (bounds == null) { 1959 throw new NullPointerException("need bounds Rect"); 1960 } 1961 nativeGetStringBounds(mNativePaint, text, start, end, bounds); 1962 } 1963 1964 /** 1965 * Return in bounds (allocated by the caller) the smallest rectangle that 1966 * encloses all of the characters, with an implied origin at (0,0). 1967 * 1968 * @param text Array of chars to measure and return their unioned bounds 1969 * @param index Index of the first char in the array to measure 1970 * @param count The number of chars, beginning at index, to measure 1971 * @param bounds Returns the unioned bounds of all the text. Must be 1972 * allocated by the caller. 1973 */ 1974 public void getTextBounds(char[] text, int index, int count, Rect bounds) { 1975 if ((index | count) < 0 || index + count > text.length) { 1976 throw new ArrayIndexOutOfBoundsException(); 1977 } 1978 if (bounds == null) { 1979 throw new NullPointerException("need bounds Rect"); 1980 } 1981 nativeGetCharArrayBounds(mNativePaint, text, index, count, bounds); 1982 } 1983 1984 @Override 1985 protected void finalize() throws Throwable { 1986 try { 1987 finalizer(mNativePaint); 1988 } finally { 1989 super.finalize(); 1990 } 1991 } 1992 1993 private static native int native_init(); 1994 private static native int native_initWithPaint(int paint); 1995 private static native void native_reset(int native_object); 1996 private static native void native_set(int native_dst, int native_src); 1997 private static native int native_getStyle(int native_object); 1998 private static native void native_setStyle(int native_object, int style); 1999 private static native int native_getStrokeCap(int native_object); 2000 private static native void native_setStrokeCap(int native_object, int cap); 2001 private static native int native_getStrokeJoin(int native_object); 2002 private static native void native_setStrokeJoin(int native_object, 2003 int join); 2004 private static native boolean native_getFillPath(int native_object, 2005 int src, int dst); 2006 private static native int native_setShader(int native_object, int shader); 2007 private static native int native_setColorFilter(int native_object, 2008 int filter); 2009 private static native int native_setXfermode(int native_object, 2010 int xfermode); 2011 private static native int native_setPathEffect(int native_object, 2012 int effect); 2013 private static native int native_setMaskFilter(int native_object, 2014 int maskfilter); 2015 private static native int native_setTypeface(int native_object, 2016 int typeface); 2017 private static native int native_setRasterizer(int native_object, 2018 int rasterizer); 2019 2020 private static native int native_getTextAlign(int native_object); 2021 private static native void native_setTextAlign(int native_object, 2022 int align); 2023 2024 private static native float native_getFontMetrics(int native_paint, 2025 FontMetrics metrics); 2026 private static native int native_getTextWidths(int native_object, 2027 char[] text, int index, int count, float[] widths); 2028 private static native int native_getTextWidths(int native_object, 2029 String text, int start, int end, float[] widths); 2030 2031 private static native int native_getTextGlyphs(int native_object, 2032 String text, int start, int end, int contextStart, int contextEnd, 2033 int flags, char[] glyphs); 2034 2035 private static native float native_getTextRunAdvances(int native_object, 2036 char[] text, int index, int count, int contextIndex, int contextCount, 2037 int flags, float[] advances, int advancesIndex, int reserved); 2038 private static native float native_getTextRunAdvances(int native_object, 2039 String text, int start, int end, int contextStart, int contextEnd, 2040 int flags, float[] advances, int advancesIndex, int reserved); 2041 2042 private native int native_getTextRunCursor(int native_object, char[] text, 2043 int contextStart, int contextLength, int flags, int offset, int cursorOpt); 2044 private native int native_getTextRunCursor(int native_object, String text, 2045 int contextStart, int contextEnd, int flags, int offset, int cursorOpt); 2046 2047 private static native void native_getTextPath(int native_object, int bidiFlags, 2048 char[] text, int index, int count, float x, float y, int path); 2049 private static native void native_getTextPath(int native_object, int bidiFlags, 2050 String text, int start, int end, float x, float y, int path); 2051 private static native void nativeGetStringBounds(int nativePaint, 2052 String text, int start, int end, Rect bounds); 2053 private static native void nativeGetCharArrayBounds(int nativePaint, 2054 char[] text, int index, int count, Rect bounds); 2055 private static native void finalizer(int nativePaint); 2056} 2057