Paint.java revision 219e2c79490296b03e58ec36a3a4ff4a2ebf52e3
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.annotation.ColorInt; 20import android.annotation.NonNull; 21import android.annotation.Size; 22import android.os.LocaleList; 23import android.text.GraphicsOperations; 24import android.text.SpannableString; 25import android.text.SpannedString; 26import android.text.TextUtils; 27 28import com.android.internal.annotations.GuardedBy; 29 30import dalvik.annotation.optimization.CriticalNative; 31import dalvik.annotation.optimization.FastNative; 32 33import java.util.HashMap; 34import java.util.Locale; 35 36import libcore.util.NativeAllocationRegistry; 37 38/** 39 * The Paint class holds the style and color information about how to draw 40 * geometries, text and bitmaps. 41 */ 42public class Paint { 43 44 private long mNativePaint; 45 private long mNativeShader = 0; 46 47 // The approximate size of a native paint object. 48 private static final long NATIVE_PAINT_SIZE = 98; 49 50 // Use a Holder to allow static initialization of Paint in the boot image. 51 private static class NoImagePreloadHolder { 52 public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( 53 Paint.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_PAINT_SIZE); 54 } 55 56 /** 57 * @hide 58 */ 59 public long mNativeTypeface; 60 61 private ColorFilter mColorFilter; 62 private MaskFilter mMaskFilter; 63 private PathEffect mPathEffect; 64 private Rasterizer mRasterizer; 65 private Shader mShader; 66 private Typeface mTypeface; 67 private Xfermode mXfermode; 68 69 private boolean mHasCompatScaling; 70 private float mCompatScaling; 71 private float mInvCompatScaling; 72 73 private LocaleList mLocales; 74 private String mFontFeatureSettings; 75 76 private static final Object sCacheLock = new Object(); 77 78 /** 79 * Cache for the Minikin language list ID. 80 * 81 * A map from a string representation of the LocaleList to Minikin's language list ID. 82 */ 83 @GuardedBy("sCacheLock") 84 private static final HashMap<String, Integer> sMinikinLangListIdCache = new HashMap<>(); 85 86 /** 87 * @hide 88 */ 89 public int mBidiFlags = BIDI_DEFAULT_LTR; 90 91 static final Style[] sStyleArray = { 92 Style.FILL, Style.STROKE, Style.FILL_AND_STROKE 93 }; 94 static final Cap[] sCapArray = { 95 Cap.BUTT, Cap.ROUND, Cap.SQUARE 96 }; 97 static final Join[] sJoinArray = { 98 Join.MITER, Join.ROUND, Join.BEVEL 99 }; 100 static final Align[] sAlignArray = { 101 Align.LEFT, Align.CENTER, Align.RIGHT 102 }; 103 104 /** 105 * Paint flag that enables antialiasing when drawing. 106 * 107 * <p>Enabling this flag will cause all draw operations that support 108 * antialiasing to use it.</p> 109 * 110 * @see #Paint(int) 111 * @see #setFlags(int) 112 */ 113 public static final int ANTI_ALIAS_FLAG = 0x01; 114 /** 115 * Paint flag that enables bilinear sampling on scaled bitmaps. 116 * 117 * <p>If cleared, scaled bitmaps will be drawn with nearest neighbor 118 * sampling, likely resulting in artifacts. This should generally be on 119 * when drawing bitmaps, unless performance-bound (rendering to software 120 * canvas) or preferring pixelation artifacts to blurriness when scaling 121 * significantly.</p> 122 * 123 * <p>If bitmaps are scaled for device density at creation time (as 124 * resource bitmaps often are) the filtering will already have been 125 * done.</p> 126 * 127 * @see #Paint(int) 128 * @see #setFlags(int) 129 */ 130 public static final int FILTER_BITMAP_FLAG = 0x02; 131 /** 132 * Paint flag that enables dithering when blitting. 133 * 134 * <p>Enabling this flag applies a dither to any blit operation where the 135 * target's colour space is more constrained than the source. 136 * 137 * @see #Paint(int) 138 * @see #setFlags(int) 139 */ 140 public static final int DITHER_FLAG = 0x04; 141 /** 142 * Paint flag that applies an underline decoration to drawn text. 143 * 144 * @see #Paint(int) 145 * @see #setFlags(int) 146 */ 147 public static final int UNDERLINE_TEXT_FLAG = 0x08; 148 /** 149 * Paint flag that applies a strike-through decoration to drawn text. 150 * 151 * @see #Paint(int) 152 * @see #setFlags(int) 153 */ 154 public static final int STRIKE_THRU_TEXT_FLAG = 0x10; 155 /** 156 * Paint flag that applies a synthetic bolding effect to drawn text. 157 * 158 * <p>Enabling this flag will cause text draw operations to apply a 159 * simulated bold effect when drawing a {@link Typeface} that is not 160 * already bold.</p> 161 * 162 * @see #Paint(int) 163 * @see #setFlags(int) 164 */ 165 public static final int FAKE_BOLD_TEXT_FLAG = 0x20; 166 /** 167 * Paint flag that enables smooth linear scaling of text. 168 * 169 * <p>Enabling this flag does not actually scale text, but rather adjusts 170 * text draw operations to deal gracefully with smooth adjustment of scale. 171 * When this flag is enabled, font hinting is disabled to prevent shape 172 * deformation between scale factors, and glyph caching is disabled due to 173 * the large number of glyph images that will be generated.</p> 174 * 175 * <p>{@link #SUBPIXEL_TEXT_FLAG} should be used in conjunction with this 176 * flag to prevent glyph positions from snapping to whole pixel values as 177 * scale factor is adjusted.</p> 178 * 179 * @see #Paint(int) 180 * @see #setFlags(int) 181 */ 182 public static final int LINEAR_TEXT_FLAG = 0x40; 183 /** 184 * Paint flag that enables subpixel positioning of text. 185 * 186 * <p>Enabling this flag causes glyph advances to be computed with subpixel 187 * accuracy.</p> 188 * 189 * <p>This can be used with {@link #LINEAR_TEXT_FLAG} to prevent text from 190 * jittering during smooth scale transitions.</p> 191 * 192 * @see #Paint(int) 193 * @see #setFlags(int) 194 */ 195 public static final int SUBPIXEL_TEXT_FLAG = 0x80; 196 /** Legacy Paint flag, no longer used. */ 197 public static final int DEV_KERN_TEXT_FLAG = 0x100; 198 /** @hide bit mask for the flag enabling subpixel glyph rendering for text */ 199 public static final int LCD_RENDER_TEXT_FLAG = 0x200; 200 /** 201 * Paint flag that enables the use of bitmap fonts when drawing text. 202 * 203 * <p>Disabling this flag will prevent text draw operations from using 204 * embedded bitmap strikes in fonts, causing fonts with both scalable 205 * outlines and bitmap strikes to draw only the scalable outlines, and 206 * fonts with only bitmap strikes to not draw at all.</p> 207 * 208 * @see #Paint(int) 209 * @see #setFlags(int) 210 */ 211 public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400; 212 /** @hide bit mask for the flag forcing freetype's autohinter on for text */ 213 public static final int AUTO_HINTING_TEXT_FLAG = 0x800; 214 /** @hide bit mask for the flag enabling vertical rendering for text */ 215 public static final int VERTICAL_TEXT_FLAG = 0x1000; 216 217 // These flags are always set on a new/reset paint, even if flags 0 is passed. 218 static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG; 219 220 /** 221 * Font hinter option that disables font hinting. 222 * 223 * @see #setHinting(int) 224 */ 225 public static final int HINTING_OFF = 0x0; 226 227 /** 228 * Font hinter option that enables font hinting. 229 * 230 * @see #setHinting(int) 231 */ 232 public static final int HINTING_ON = 0x1; 233 234 /** 235 * Bidi flag to set LTR paragraph direction. 236 * 237 * @hide 238 */ 239 public static final int BIDI_LTR = 0x0; 240 241 /** 242 * Bidi flag to set RTL paragraph direction. 243 * 244 * @hide 245 */ 246 public static final int BIDI_RTL = 0x1; 247 248 /** 249 * Bidi flag to detect paragraph direction via heuristics, defaulting to 250 * LTR. 251 * 252 * @hide 253 */ 254 public static final int BIDI_DEFAULT_LTR = 0x2; 255 256 /** 257 * Bidi flag to detect paragraph direction via heuristics, defaulting to 258 * RTL. 259 * 260 * @hide 261 */ 262 public static final int BIDI_DEFAULT_RTL = 0x3; 263 264 /** 265 * Bidi flag to override direction to all LTR (ignore bidi). 266 * 267 * @hide 268 */ 269 public static final int BIDI_FORCE_LTR = 0x4; 270 271 /** 272 * Bidi flag to override direction to all RTL (ignore bidi). 273 * 274 * @hide 275 */ 276 public static final int BIDI_FORCE_RTL = 0x5; 277 278 /** 279 * Maximum Bidi flag value. 280 * @hide 281 */ 282 private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL; 283 284 /** 285 * Mask for bidi flags. 286 * @hide 287 */ 288 private static final int BIDI_FLAG_MASK = 0x7; 289 290 /** 291 * Flag for getTextRunAdvances indicating left-to-right run direction. 292 * @hide 293 */ 294 public static final int DIRECTION_LTR = 0; 295 296 /** 297 * Flag for getTextRunAdvances indicating right-to-left run direction. 298 * @hide 299 */ 300 public static final int DIRECTION_RTL = 1; 301 302 /** 303 * Option for getTextRunCursor to compute the valid cursor after 304 * offset or the limit of the context, whichever is less. 305 * @hide 306 */ 307 public static final int CURSOR_AFTER = 0; 308 309 /** 310 * Option for getTextRunCursor to compute the valid cursor at or after 311 * the offset or the limit of the context, whichever is less. 312 * @hide 313 */ 314 public static final int CURSOR_AT_OR_AFTER = 1; 315 316 /** 317 * Option for getTextRunCursor to compute the valid cursor before 318 * offset or the start of the context, whichever is greater. 319 * @hide 320 */ 321 public static final int CURSOR_BEFORE = 2; 322 323 /** 324 * Option for getTextRunCursor to compute the valid cursor at or before 325 * offset or the start of the context, whichever is greater. 326 * @hide 327 */ 328 public static final int CURSOR_AT_OR_BEFORE = 3; 329 330 /** 331 * Option for getTextRunCursor to return offset if the cursor at offset 332 * is valid, or -1 if it isn't. 333 * @hide 334 */ 335 public static final int CURSOR_AT = 4; 336 337 /** 338 * Maximum cursor option value. 339 */ 340 private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT; 341 342 /** 343 * The Style specifies if the primitive being drawn is filled, stroked, or 344 * both (in the same color). The default is FILL. 345 */ 346 public enum Style { 347 /** 348 * Geometry and text drawn with this style will be filled, ignoring all 349 * stroke-related settings in the paint. 350 */ 351 FILL (0), 352 /** 353 * Geometry and text drawn with this style will be stroked, respecting 354 * the stroke-related fields on the paint. 355 */ 356 STROKE (1), 357 /** 358 * Geometry and text drawn with this style will be both filled and 359 * stroked at the same time, respecting the stroke-related fields on 360 * the paint. This mode can give unexpected results if the geometry 361 * is oriented counter-clockwise. This restriction does not apply to 362 * either FILL or STROKE. 363 */ 364 FILL_AND_STROKE (2); 365 366 Style(int nativeInt) { 367 this.nativeInt = nativeInt; 368 } 369 final int nativeInt; 370 } 371 372 /** 373 * The Cap specifies the treatment for the beginning and ending of 374 * stroked lines and paths. The default is BUTT. 375 */ 376 public enum Cap { 377 /** 378 * The stroke ends with the path, and does not project beyond it. 379 */ 380 BUTT (0), 381 /** 382 * The stroke projects out as a semicircle, with the center at the 383 * end of the path. 384 */ 385 ROUND (1), 386 /** 387 * The stroke projects out as a square, with the center at the end 388 * of the path. 389 */ 390 SQUARE (2); 391 392 private Cap(int nativeInt) { 393 this.nativeInt = nativeInt; 394 } 395 final int nativeInt; 396 } 397 398 /** 399 * The Join specifies the treatment where lines and curve segments 400 * join on a stroked path. The default is MITER. 401 */ 402 public enum Join { 403 /** 404 * The outer edges of a join meet at a sharp angle 405 */ 406 MITER (0), 407 /** 408 * The outer edges of a join meet in a circular arc. 409 */ 410 ROUND (1), 411 /** 412 * The outer edges of a join meet with a straight line 413 */ 414 BEVEL (2); 415 416 private Join(int nativeInt) { 417 this.nativeInt = nativeInt; 418 } 419 final int nativeInt; 420 } 421 422 /** 423 * Align specifies how drawText aligns its text relative to the 424 * [x,y] coordinates. The default is LEFT. 425 */ 426 public enum Align { 427 /** 428 * The text is drawn to the right of the x,y origin 429 */ 430 LEFT (0), 431 /** 432 * The text is drawn centered horizontally on the x,y origin 433 */ 434 CENTER (1), 435 /** 436 * The text is drawn to the left of the x,y origin 437 */ 438 RIGHT (2); 439 440 private Align(int nativeInt) { 441 this.nativeInt = nativeInt; 442 } 443 final int nativeInt; 444 } 445 446 /** 447 * Create a new paint with default settings. 448 */ 449 public Paint() { 450 this(0); 451 } 452 453 /** 454 * Create a new paint with the specified flags. Use setFlags() to change 455 * these after the paint is created. 456 * 457 * @param flags initial flag bits, as if they were passed via setFlags(). 458 */ 459 public Paint(int flags) { 460 mNativePaint = nInit(); 461 NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint); 462 setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS); 463 // TODO: Turning off hinting has undesirable side effects, we need to 464 // revisit hinting once we add support for subpixel positioning 465 // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV 466 // ? HINTING_OFF : HINTING_ON); 467 mCompatScaling = mInvCompatScaling = 1; 468 setTextLocales(LocaleList.getAdjustedDefault()); 469 } 470 471 /** 472 * Create a new paint, initialized with the attributes in the specified 473 * paint parameter. 474 * 475 * @param paint Existing paint used to initialized the attributes of the 476 * new paint. 477 */ 478 public Paint(Paint paint) { 479 mNativePaint = nInitWithPaint(paint.getNativeInstance()); 480 NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint); 481 setClassVariablesFrom(paint); 482 } 483 484 /** Restores the paint to its default settings. */ 485 public void reset() { 486 nReset(mNativePaint); 487 setFlags(HIDDEN_DEFAULT_PAINT_FLAGS); 488 489 // TODO: Turning off hinting has undesirable side effects, we need to 490 // revisit hinting once we add support for subpixel positioning 491 // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV 492 // ? HINTING_OFF : HINTING_ON); 493 494 mColorFilter = null; 495 mMaskFilter = null; 496 mPathEffect = null; 497 mRasterizer = null; 498 mShader = null; 499 mNativeShader = 0; 500 mTypeface = null; 501 mNativeTypeface = 0; 502 mXfermode = null; 503 504 mHasCompatScaling = false; 505 mCompatScaling = 1; 506 mInvCompatScaling = 1; 507 508 mBidiFlags = BIDI_DEFAULT_LTR; 509 setTextLocales(LocaleList.getAdjustedDefault()); 510 setElegantTextHeight(false); 511 mFontFeatureSettings = null; 512 } 513 514 /** 515 * Copy the fields from src into this paint. This is equivalent to calling 516 * get() on all of the src fields, and calling the corresponding set() 517 * methods on this. 518 */ 519 public void set(Paint src) { 520 if (this != src) { 521 // copy over the native settings 522 nSet(mNativePaint, src.mNativePaint); 523 setClassVariablesFrom(src); 524 } 525 } 526 527 /** 528 * Set all class variables using current values from the given 529 * {@link Paint}. 530 */ 531 private void setClassVariablesFrom(Paint paint) { 532 mColorFilter = paint.mColorFilter; 533 mMaskFilter = paint.mMaskFilter; 534 mPathEffect = paint.mPathEffect; 535 mRasterizer = paint.mRasterizer; 536 mShader = paint.mShader; 537 mNativeShader = paint.mNativeShader; 538 mTypeface = paint.mTypeface; 539 mNativeTypeface = paint.mNativeTypeface; 540 mXfermode = paint.mXfermode; 541 542 mHasCompatScaling = paint.mHasCompatScaling; 543 mCompatScaling = paint.mCompatScaling; 544 mInvCompatScaling = paint.mInvCompatScaling; 545 546 mBidiFlags = paint.mBidiFlags; 547 mLocales = paint.mLocales; 548 mFontFeatureSettings = paint.mFontFeatureSettings; 549 } 550 551 /** @hide */ 552 public void setCompatibilityScaling(float factor) { 553 if (factor == 1.0) { 554 mHasCompatScaling = false; 555 mCompatScaling = mInvCompatScaling = 1.0f; 556 } else { 557 mHasCompatScaling = true; 558 mCompatScaling = factor; 559 mInvCompatScaling = 1.0f/factor; 560 } 561 } 562 563 /** 564 * Return the pointer to the native object while ensuring that any 565 * mutable objects that are attached to the paint are also up-to-date. 566 * 567 * @hide 568 */ 569 public long getNativeInstance() { 570 long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance(); 571 if (newNativeShader != mNativeShader) { 572 mNativeShader = newNativeShader; 573 nSetShader(mNativePaint, mNativeShader); 574 } 575 return mNativePaint; 576 } 577 578 /** 579 * Return the bidi flags on the paint. 580 * 581 * @return the bidi flags on the paint 582 * @hide 583 */ 584 public int getBidiFlags() { 585 return mBidiFlags; 586 } 587 588 /** 589 * Set the bidi flags on the paint. 590 * @hide 591 */ 592 public void setBidiFlags(int flags) { 593 // only flag value is the 3-bit BIDI control setting 594 flags &= BIDI_FLAG_MASK; 595 if (flags > BIDI_MAX_FLAG_VALUE) { 596 throw new IllegalArgumentException("unknown bidi flag: " + flags); 597 } 598 mBidiFlags = flags; 599 } 600 601 /** 602 * Return the paint's flags. Use the Flag enum to test flag values. 603 * 604 * @return the paint's flags (see enums ending in _Flag for bit masks) 605 */ 606 public int getFlags() { 607 return nGetFlags(mNativePaint); 608 } 609 610 /** 611 * Set the paint's flags. Use the Flag enum to specific flag values. 612 * 613 * @param flags The new flag bits for the paint 614 */ 615 public void setFlags(int flags) { 616 nSetFlags(mNativePaint, flags); 617 } 618 619 /** 620 * Return the paint's hinting mode. Returns either 621 * {@link #HINTING_OFF} or {@link #HINTING_ON}. 622 */ 623 public int getHinting() { 624 return nGetHinting(mNativePaint); 625 } 626 627 /** 628 * Set the paint's hinting mode. May be either 629 * {@link #HINTING_OFF} or {@link #HINTING_ON}. 630 */ 631 public void setHinting(int mode) { 632 nSetHinting(mNativePaint, mode); 633 } 634 635 /** 636 * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set 637 * AntiAliasing smooths out the edges of what is being drawn, but is has 638 * no impact on the interior of the shape. See setDither() and 639 * setFilterBitmap() to affect how colors are treated. 640 * 641 * @return true if the antialias bit is set in the paint's flags. 642 */ 643 public final boolean isAntiAlias() { 644 return (getFlags() & ANTI_ALIAS_FLAG) != 0; 645 } 646 647 /** 648 * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit 649 * AntiAliasing smooths out the edges of what is being drawn, but is has 650 * no impact on the interior of the shape. See setDither() and 651 * setFilterBitmap() to affect how colors are treated. 652 * 653 * @param aa true to set the antialias bit in the flags, false to clear it 654 */ 655 public void setAntiAlias(boolean aa) { 656 nSetAntiAlias(mNativePaint, aa); 657 } 658 659 /** 660 * Helper for getFlags(), returning true if DITHER_FLAG bit is set 661 * Dithering affects how colors that are higher precision than the device 662 * are down-sampled. No dithering is generally faster, but higher precision 663 * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to 664 * distribute the error inherent in this process, to reduce the visual 665 * artifacts. 666 * 667 * @return true if the dithering bit is set in the paint's flags. 668 */ 669 public final boolean isDither() { 670 return (getFlags() & DITHER_FLAG) != 0; 671 } 672 673 /** 674 * Helper for setFlags(), setting or clearing the DITHER_FLAG bit 675 * Dithering affects how colors that are higher precision than the device 676 * are down-sampled. No dithering is generally faster, but higher precision 677 * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to 678 * distribute the error inherent in this process, to reduce the visual 679 * artifacts. 680 * 681 * @param dither true to set the dithering bit in flags, false to clear it 682 */ 683 public void setDither(boolean dither) { 684 nSetDither(mNativePaint, dither); 685 } 686 687 /** 688 * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set 689 * 690 * @return true if the lineartext bit is set in the paint's flags 691 */ 692 public final boolean isLinearText() { 693 return (getFlags() & LINEAR_TEXT_FLAG) != 0; 694 } 695 696 /** 697 * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit 698 * 699 * @param linearText true to set the linearText bit in the paint's flags, 700 * false to clear it. 701 */ 702 public void setLinearText(boolean linearText) { 703 nSetLinearText(mNativePaint, linearText); 704 } 705 706 /** 707 * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set 708 * 709 * @return true if the subpixel bit is set in the paint's flags 710 */ 711 public final boolean isSubpixelText() { 712 return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0; 713 } 714 715 /** 716 * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit 717 * 718 * @param subpixelText true to set the subpixelText bit in the paint's 719 * flags, false to clear it. 720 */ 721 public void setSubpixelText(boolean subpixelText) { 722 nSetSubpixelText(mNativePaint, subpixelText); 723 } 724 725 /** 726 * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set 727 * 728 * @return true if the underlineText bit is set in the paint's flags. 729 */ 730 public final boolean isUnderlineText() { 731 return (getFlags() & UNDERLINE_TEXT_FLAG) != 0; 732 } 733 734 /** 735 * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit 736 * 737 * @param underlineText true to set the underlineText bit in the paint's 738 * flags, false to clear it. 739 */ 740 public void setUnderlineText(boolean underlineText) { 741 nSetUnderlineText(mNativePaint, underlineText); 742 } 743 744 /** 745 * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set 746 * 747 * @return true if the strikeThruText bit is set in the paint's flags. 748 */ 749 public final boolean isStrikeThruText() { 750 return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0; 751 } 752 753 /** 754 * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit 755 * 756 * @param strikeThruText true to set the strikeThruText bit in the paint's 757 * flags, false to clear it. 758 */ 759 public void setStrikeThruText(boolean strikeThruText) { 760 nSetStrikeThruText(mNativePaint, strikeThruText); 761 } 762 763 /** 764 * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set 765 * 766 * @return true if the fakeBoldText bit is set in the paint's flags. 767 */ 768 public final boolean isFakeBoldText() { 769 return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0; 770 } 771 772 /** 773 * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit 774 * 775 * @param fakeBoldText true to set the fakeBoldText bit in the paint's 776 * flags, false to clear it. 777 */ 778 public void setFakeBoldText(boolean fakeBoldText) { 779 nSetFakeBoldText(mNativePaint, fakeBoldText); 780 } 781 782 /** 783 * Whether or not the bitmap filter is activated. 784 * Filtering affects the sampling of bitmaps when they are transformed. 785 * Filtering does not affect how the colors in the bitmap are converted into 786 * device pixels. That is dependent on dithering and xfermodes. 787 * 788 * @see #setFilterBitmap(boolean) setFilterBitmap() 789 */ 790 public final boolean isFilterBitmap() { 791 return (getFlags() & FILTER_BITMAP_FLAG) != 0; 792 } 793 794 /** 795 * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit. 796 * Filtering affects the sampling of bitmaps when they are transformed. 797 * Filtering does not affect how the colors in the bitmap are converted into 798 * device pixels. That is dependent on dithering and xfermodes. 799 * 800 * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's 801 * flags, false to clear it. 802 */ 803 public void setFilterBitmap(boolean filter) { 804 nSetFilterBitmap(mNativePaint, filter); 805 } 806 807 /** 808 * Return the paint's style, used for controlling how primitives' 809 * geometries are interpreted (except for drawBitmap, which always assumes 810 * FILL_STYLE). 811 * 812 * @return the paint's style setting (Fill, Stroke, StrokeAndFill) 813 */ 814 public Style getStyle() { 815 return sStyleArray[nGetStyle(mNativePaint)]; 816 } 817 818 /** 819 * Set the paint's style, used for controlling how primitives' 820 * geometries are interpreted (except for drawBitmap, which always assumes 821 * Fill). 822 * 823 * @param style The new style to set in the paint 824 */ 825 public void setStyle(Style style) { 826 nSetStyle(mNativePaint, style.nativeInt); 827 } 828 829 /** 830 * Return the paint's color. Note that the color is a 32bit value 831 * containing alpha as well as r,g,b. This 32bit value is not premultiplied, 832 * meaning that its alpha can be any value, regardless of the values of 833 * r,g,b. See the Color class for more details. 834 * 835 * @return the paint's color (and alpha). 836 */ 837 @ColorInt 838 public int getColor() { 839 return nGetColor(mNativePaint); 840 } 841 842 /** 843 * Set the paint's color. Note that the color is an int containing alpha 844 * as well as r,g,b. This 32bit value is not premultiplied, meaning that 845 * its alpha can be any value, regardless of the values of r,g,b. 846 * See the Color class for more details. 847 * 848 * @param color The new color (including alpha) to set in the paint. 849 */ 850 public void setColor(@ColorInt int color) { 851 nSetColor(mNativePaint, color); 852 } 853 854 /** 855 * Helper to getColor() that just returns the color's alpha value. This is 856 * the same as calling getColor() >>> 24. It always returns a value between 857 * 0 (completely transparent) and 255 (completely opaque). 858 * 859 * @return the alpha component of the paint's color. 860 */ 861 public int getAlpha() { 862 return nGetAlpha(mNativePaint); 863 } 864 865 /** 866 * Helper to setColor(), that only assigns the color's alpha value, 867 * leaving its r,g,b values unchanged. Results are undefined if the alpha 868 * value is outside of the range [0..255] 869 * 870 * @param a set the alpha component [0..255] of the paint's color. 871 */ 872 public void setAlpha(int a) { 873 nSetAlpha(mNativePaint, a); 874 } 875 876 /** 877 * Helper to setColor(), that takes a,r,g,b and constructs the color int 878 * 879 * @param a The new alpha component (0..255) of the paint's color. 880 * @param r The new red component (0..255) of the paint's color. 881 * @param g The new green component (0..255) of the paint's color. 882 * @param b The new blue component (0..255) of the paint's color. 883 */ 884 public void setARGB(int a, int r, int g, int b) { 885 setColor((a << 24) | (r << 16) | (g << 8) | b); 886 } 887 888 /** 889 * Return the width for stroking. 890 * <p /> 891 * A value of 0 strokes in hairline mode. 892 * Hairlines always draws a single pixel independent of the canva's matrix. 893 * 894 * @return the paint's stroke width, used whenever the paint's style is 895 * Stroke or StrokeAndFill. 896 */ 897 public float getStrokeWidth() { 898 return nGetStrokeWidth(mNativePaint); 899 } 900 901 /** 902 * Set the width for stroking. 903 * Pass 0 to stroke in hairline mode. 904 * Hairlines always draws a single pixel independent of the canva's matrix. 905 * 906 * @param width set the paint's stroke width, used whenever the paint's 907 * style is Stroke or StrokeAndFill. 908 */ 909 public void setStrokeWidth(float width) { 910 nSetStrokeWidth(mNativePaint, width); 911 } 912 913 /** 914 * Return the paint's stroke miter value. Used to control the behavior 915 * of miter joins when the joins angle is sharp. 916 * 917 * @return the paint's miter limit, used whenever the paint's style is 918 * Stroke or StrokeAndFill. 919 */ 920 public float getStrokeMiter() { 921 return nGetStrokeMiter(mNativePaint); 922 } 923 924 /** 925 * Set the paint's stroke miter value. This is used to control the behavior 926 * of miter joins when the joins angle is sharp. This value must be >= 0. 927 * 928 * @param miter set the miter limit on the paint, used whenever the paint's 929 * style is Stroke or StrokeAndFill. 930 */ 931 public void setStrokeMiter(float miter) { 932 nSetStrokeMiter(mNativePaint, miter); 933 } 934 935 /** 936 * Return the paint's Cap, controlling how the start and end of stroked 937 * lines and paths are treated. 938 * 939 * @return the line cap style for the paint, used whenever the paint's 940 * style is Stroke or StrokeAndFill. 941 */ 942 public Cap getStrokeCap() { 943 return sCapArray[nGetStrokeCap(mNativePaint)]; 944 } 945 946 /** 947 * Set the paint's Cap. 948 * 949 * @param cap set the paint's line cap style, used whenever the paint's 950 * style is Stroke or StrokeAndFill. 951 */ 952 public void setStrokeCap(Cap cap) { 953 nSetStrokeCap(mNativePaint, cap.nativeInt); 954 } 955 956 /** 957 * Return the paint's stroke join type. 958 * 959 * @return the paint's Join. 960 */ 961 public Join getStrokeJoin() { 962 return sJoinArray[nGetStrokeJoin(mNativePaint)]; 963 } 964 965 /** 966 * Set the paint's Join. 967 * 968 * @param join set the paint's Join, used whenever the paint's style is 969 * Stroke or StrokeAndFill. 970 */ 971 public void setStrokeJoin(Join join) { 972 nSetStrokeJoin(mNativePaint, join.nativeInt); 973 } 974 975 /** 976 * Applies any/all effects (patheffect, stroking) to src, returning the 977 * result in dst. The result is that drawing src with this paint will be 978 * the same as drawing dst with a default paint (at least from the 979 * geometric perspective). 980 * 981 * @param src input path 982 * @param dst output path (may be the same as src) 983 * @return true if the path should be filled, or false if it should be 984 * drawn with a hairline (width == 0) 985 */ 986 public boolean getFillPath(Path src, Path dst) { 987 return nGetFillPath(mNativePaint, src.readOnlyNI(), dst.mutateNI()); 988 } 989 990 /** 991 * Get the paint's shader object. 992 * 993 * @return the paint's shader (or null) 994 */ 995 public Shader getShader() { 996 return mShader; 997 } 998 999 /** 1000 * Set or clear the shader object. 1001 * <p /> 1002 * Pass null to clear any previous shader. 1003 * As a convenience, the parameter passed is also returned. 1004 * 1005 * @param shader May be null. the new shader to be installed in the paint 1006 * @return shader 1007 */ 1008 public Shader setShader(Shader shader) { 1009 // If mShader changes, cached value of native shader aren't valid, since 1010 // old shader's pointer may be reused by another shader allocation later 1011 if (mShader != shader) { 1012 mNativeShader = -1; 1013 } 1014 // Defer setting the shader natively until getNativeInstance() is called 1015 mShader = shader; 1016 return shader; 1017 } 1018 1019 /** 1020 * Get the paint's colorfilter (maybe be null). 1021 * 1022 * @return the paint's colorfilter (maybe be null) 1023 */ 1024 public ColorFilter getColorFilter() { 1025 return mColorFilter; 1026 } 1027 1028 /** 1029 * Set or clear the paint's colorfilter, returning the parameter. 1030 * 1031 * @param filter May be null. The new filter to be installed in the paint 1032 * @return filter 1033 */ 1034 public ColorFilter setColorFilter(ColorFilter filter) { 1035 long filterNative = 0; 1036 if (filter != null) 1037 filterNative = filter.native_instance; 1038 nSetColorFilter(mNativePaint, filterNative); 1039 mColorFilter = filter; 1040 return filter; 1041 } 1042 1043 /** 1044 * Get the paint's xfermode object. 1045 * 1046 * @return the paint's xfermode (or null) 1047 */ 1048 public Xfermode getXfermode() { 1049 return mXfermode; 1050 } 1051 1052 /** 1053 * Set or clear the xfermode object. 1054 * <p /> 1055 * Pass null to clear any previous xfermode. 1056 * As a convenience, the parameter passed is also returned. 1057 * 1058 * @param xfermode May be null. The xfermode to be installed in the paint 1059 * @return xfermode 1060 */ 1061 public Xfermode setXfermode(Xfermode xfermode) { 1062 int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT; 1063 int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT; 1064 if (newMode != curMode) { 1065 nSetXfermode(mNativePaint, newMode); 1066 } 1067 mXfermode = xfermode; 1068 return xfermode; 1069 } 1070 1071 /** 1072 * Get the paint's patheffect object. 1073 * 1074 * @return the paint's patheffect (or null) 1075 */ 1076 public PathEffect getPathEffect() { 1077 return mPathEffect; 1078 } 1079 1080 /** 1081 * Set or clear the patheffect object. 1082 * <p /> 1083 * Pass null to clear any previous patheffect. 1084 * As a convenience, the parameter passed is also returned. 1085 * 1086 * @param effect May be null. The patheffect to be installed in the paint 1087 * @return effect 1088 */ 1089 public PathEffect setPathEffect(PathEffect effect) { 1090 long effectNative = 0; 1091 if (effect != null) { 1092 effectNative = effect.native_instance; 1093 } 1094 nSetPathEffect(mNativePaint, effectNative); 1095 mPathEffect = effect; 1096 return effect; 1097 } 1098 1099 /** 1100 * Get the paint's maskfilter object. 1101 * 1102 * @return the paint's maskfilter (or null) 1103 */ 1104 public MaskFilter getMaskFilter() { 1105 return mMaskFilter; 1106 } 1107 1108 /** 1109 * Set or clear the maskfilter object. 1110 * <p /> 1111 * Pass null to clear any previous maskfilter. 1112 * As a convenience, the parameter passed is also returned. 1113 * 1114 * @param maskfilter May be null. The maskfilter to be installed in the 1115 * paint 1116 * @return maskfilter 1117 */ 1118 public MaskFilter setMaskFilter(MaskFilter maskfilter) { 1119 long maskfilterNative = 0; 1120 if (maskfilter != null) { 1121 maskfilterNative = maskfilter.native_instance; 1122 } 1123 nSetMaskFilter(mNativePaint, maskfilterNative); 1124 mMaskFilter = maskfilter; 1125 return maskfilter; 1126 } 1127 1128 /** 1129 * Get the paint's typeface object. 1130 * <p /> 1131 * The typeface object identifies which font to use when drawing or 1132 * measuring text. 1133 * 1134 * @return the paint's typeface (or null) 1135 */ 1136 public Typeface getTypeface() { 1137 return mTypeface; 1138 } 1139 1140 /** 1141 * Set or clear the typeface object. 1142 * <p /> 1143 * Pass null to clear any previous typeface. 1144 * As a convenience, the parameter passed is also returned. 1145 * 1146 * @param typeface May be null. The typeface to be installed in the paint 1147 * @return typeface 1148 */ 1149 public Typeface setTypeface(Typeface typeface) { 1150 long typefaceNative = 0; 1151 if (typeface != null) { 1152 typefaceNative = typeface.native_instance; 1153 } 1154 nSetTypeface(mNativePaint, typefaceNative); 1155 mTypeface = typeface; 1156 mNativeTypeface = typefaceNative; 1157 return typeface; 1158 } 1159 1160 /** 1161 * Get the paint's rasterizer (or null). 1162 * <p /> 1163 * The raster controls/modifies how paths/text are turned into alpha masks. 1164 * 1165 * @return the paint's rasterizer (or null) 1166 * 1167 * @deprecated Rasterizer is not supported by either the HW or PDF backends. 1168 */ 1169 @Deprecated 1170 public Rasterizer getRasterizer() { 1171 return mRasterizer; 1172 } 1173 1174 /** 1175 * Set or clear the rasterizer object. 1176 * <p /> 1177 * Pass null to clear any previous rasterizer. 1178 * As a convenience, the parameter passed is also returned. 1179 * 1180 * @param rasterizer May be null. The new rasterizer to be installed in 1181 * the paint. 1182 * @return rasterizer 1183 * 1184 * @deprecated Rasterizer is not supported by either the HW or PDF backends. 1185 */ 1186 @Deprecated 1187 public Rasterizer setRasterizer(Rasterizer rasterizer) { 1188 long rasterizerNative = 0; 1189 if (rasterizer != null) { 1190 rasterizerNative = rasterizer.native_instance; 1191 } 1192 nSetRasterizer(mNativePaint, rasterizerNative); 1193 mRasterizer = rasterizer; 1194 return rasterizer; 1195 } 1196 1197 /** 1198 * This draws a shadow layer below the main layer, with the specified 1199 * offset and color, and blur radius. If radius is 0, then the shadow 1200 * layer is removed. 1201 * <p> 1202 * Can be used to create a blurred shadow underneath text. Support for use 1203 * with other drawing operations is constrained to the software rendering 1204 * pipeline. 1205 * <p> 1206 * The alpha of the shadow will be the paint's alpha if the shadow color is 1207 * opaque, or the alpha from the shadow color if not. 1208 */ 1209 public void setShadowLayer(float radius, float dx, float dy, int shadowColor) { 1210 nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor); 1211 } 1212 1213 /** 1214 * Clear the shadow layer. 1215 */ 1216 public void clearShadowLayer() { 1217 setShadowLayer(0, 0, 0, 0); 1218 } 1219 1220 /** 1221 * Checks if the paint has a shadow layer attached 1222 * 1223 * @return true if the paint has a shadow layer attached and false otherwise 1224 * @hide 1225 */ 1226 public boolean hasShadowLayer() { 1227 return nHasShadowLayer(mNativePaint); 1228 } 1229 1230 /** 1231 * Return the paint's Align value for drawing text. This controls how the 1232 * text is positioned relative to its origin. LEFT align means that all of 1233 * the text will be drawn to the right of its origin (i.e. the origin 1234 * specifieds the LEFT edge of the text) and so on. 1235 * 1236 * @return the paint's Align value for drawing text. 1237 */ 1238 public Align getTextAlign() { 1239 return sAlignArray[nGetTextAlign(mNativePaint)]; 1240 } 1241 1242 /** 1243 * Set the paint's text alignment. This controls how the 1244 * text is positioned relative to its origin. LEFT align means that all of 1245 * the text will be drawn to the right of its origin (i.e. the origin 1246 * specifieds the LEFT edge of the text) and so on. 1247 * 1248 * @param align set the paint's Align value for drawing text. 1249 */ 1250 public void setTextAlign(Align align) { 1251 nSetTextAlign(mNativePaint, align.nativeInt); 1252 } 1253 1254 /** 1255 * Get the text's primary Locale. Note that this is not all of the locale-related information 1256 * Paint has. Use {@link #getTextLocales()} to get the complete list. 1257 * 1258 * @return the paint's primary Locale used for drawing text, never null. 1259 */ 1260 @NonNull 1261 public Locale getTextLocale() { 1262 return mLocales.get(0); 1263 } 1264 1265 /** 1266 * Get the text locale list. 1267 * 1268 * @return the paint's LocaleList used for drawing text, never null or empty. 1269 */ 1270 @NonNull @Size(min=1) 1271 public LocaleList getTextLocales() { 1272 return mLocales; 1273 } 1274 1275 /** 1276 * Set the text locale list to a one-member list consisting of just the locale. 1277 * 1278 * See {@link #setTextLocales(LocaleList)} for how the locale list affects 1279 * the way the text is drawn for some languages. 1280 * 1281 * @param locale the paint's locale value for drawing text, must not be null. 1282 */ 1283 public void setTextLocale(@NonNull Locale locale) { 1284 if (locale == null) { 1285 throw new IllegalArgumentException("locale cannot be null"); 1286 } 1287 if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.get(0))) { 1288 return; 1289 } 1290 mLocales = new LocaleList(locale); 1291 syncTextLocalesWithMinikin(); 1292 } 1293 1294 /** 1295 * Set the text locale list. 1296 * 1297 * The text locale list affects how the text is drawn for some languages. 1298 * 1299 * For example, if the locale list contains {@link Locale#CHINESE} or {@link Locale#CHINA}, 1300 * then the text renderer will prefer to draw text using a Chinese font. Likewise, 1301 * if the locale list contains {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text 1302 * renderer will prefer to draw text using a Japanese font. If the locale list contains both, 1303 * the order those locales appear in the list is considered for deciding the font. 1304 * 1305 * This distinction is important because Chinese and Japanese text both use many 1306 * of the same Unicode code points but their appearance is subtly different for 1307 * each language. 1308 * 1309 * By default, the text locale list is initialized to a one-member list just containing the 1310 * system locales. This assumes that the text to be rendered will most likely be in the user's 1311 * preferred language. 1312 * 1313 * If the actual language or languages of the text is/are known, then they can be provided to 1314 * the text renderer using this method. The text renderer may attempt to guess the 1315 * language script based on the contents of the text to be drawn independent of 1316 * the text locale here. Specifying the text locales just helps it do a better 1317 * job in certain ambiguous cases. 1318 * 1319 * @param locales the paint's locale list for drawing text, must not be null or empty. 1320 */ 1321 public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) { 1322 if (locales == null || locales.isEmpty()) { 1323 throw new IllegalArgumentException("locales cannot be null or empty"); 1324 } 1325 if (locales.equals(mLocales)) return; 1326 mLocales = locales; 1327 syncTextLocalesWithMinikin(); 1328 } 1329 1330 private void syncTextLocalesWithMinikin() { 1331 final String languageTags = mLocales.toLanguageTags(); 1332 final Integer minikinLangListId; 1333 synchronized (sCacheLock) { 1334 minikinLangListId = sMinikinLangListIdCache.get(languageTags); 1335 if (minikinLangListId == null) { 1336 final int newID = nSetTextLocales(mNativePaint, languageTags); 1337 sMinikinLangListIdCache.put(languageTags, newID); 1338 return; 1339 } 1340 } 1341 nSetTextLocalesByMinikinLangListId(mNativePaint, minikinLangListId.intValue()); 1342 } 1343 1344 /** 1345 * Get the elegant metrics flag. 1346 * 1347 * @return true if elegant metrics are enabled for text drawing. 1348 */ 1349 public boolean isElegantTextHeight() { 1350 return nIsElegantTextHeight(mNativePaint); 1351 } 1352 1353 /** 1354 * Set the paint's elegant height metrics flag. This setting selects font 1355 * variants that have not been compacted to fit Latin-based vertical 1356 * metrics, and also increases top and bottom bounds to provide more space. 1357 * 1358 * @param elegant set the paint's elegant metrics flag for drawing text. 1359 */ 1360 public void setElegantTextHeight(boolean elegant) { 1361 nSetElegantTextHeight(mNativePaint, elegant); 1362 } 1363 1364 /** 1365 * Return the paint's text size. 1366 * 1367 * @return the paint's text size. 1368 */ 1369 public float getTextSize() { 1370 return nGetTextSize(mNativePaint); 1371 } 1372 1373 /** 1374 * Set the paint's text size. This value must be > 0 1375 * 1376 * @param textSize set the paint's text size. 1377 */ 1378 public void setTextSize(float textSize) { 1379 nSetTextSize(mNativePaint, textSize); 1380 } 1381 1382 /** 1383 * Return the paint's horizontal scale factor for text. The default value 1384 * is 1.0. 1385 * 1386 * @return the paint's scale factor in X for drawing/measuring text 1387 */ 1388 public float getTextScaleX() { 1389 return nGetTextScaleX(mNativePaint); 1390 } 1391 1392 /** 1393 * Set the paint's horizontal scale factor for text. The default value 1394 * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will 1395 * stretch the text narrower. 1396 * 1397 * @param scaleX set the paint's scale in X for drawing/measuring text. 1398 */ 1399 public void setTextScaleX(float scaleX) { 1400 nSetTextScaleX(mNativePaint, scaleX); 1401 } 1402 1403 /** 1404 * Return the paint's horizontal skew factor for text. The default value 1405 * is 0. 1406 * 1407 * @return the paint's skew factor in X for drawing text. 1408 */ 1409 public float getTextSkewX() { 1410 return nGetTextSkewX(mNativePaint); 1411 } 1412 1413 /** 1414 * Set the paint's horizontal skew factor for text. The default value 1415 * is 0. For approximating oblique text, use values around -0.25. 1416 * 1417 * @param skewX set the paint's skew factor in X for drawing text. 1418 */ 1419 public void setTextSkewX(float skewX) { 1420 nSetTextSkewX(mNativePaint, skewX); 1421 } 1422 1423 /** 1424 * Return the paint's letter-spacing for text. The default value 1425 * is 0. 1426 * 1427 * @return the paint's letter-spacing for drawing text. 1428 */ 1429 public float getLetterSpacing() { 1430 return nGetLetterSpacing(mNativePaint); 1431 } 1432 1433 /** 1434 * Set the paint's letter-spacing for text. The default value 1435 * is 0. The value is in 'EM' units. Typical values for slight 1436 * expansion will be around 0.05. Negative values tighten text. 1437 * 1438 * @param letterSpacing set the paint's letter-spacing for drawing text. 1439 */ 1440 public void setLetterSpacing(float letterSpacing) { 1441 nSetLetterSpacing(mNativePaint, letterSpacing); 1442 } 1443 1444 /** 1445 * Return the paint's word-spacing for text. The default value is 0. 1446 * 1447 * @return the paint's word-spacing for drawing text. 1448 * @hide 1449 */ 1450 public float getWordSpacing() { 1451 return nGetWordSpacing(mNativePaint); 1452 } 1453 1454 /** 1455 * Set the paint's word-spacing for text. The default value is 0. 1456 * The value is in pixels (note the units are not the same as for 1457 * letter-spacing). 1458 * 1459 * @param wordSpacing set the paint's word-spacing for drawing text. 1460 * @hide 1461 */ 1462 public void setWordSpacing(float wordSpacing) { 1463 nSetWordSpacing(mNativePaint, wordSpacing); 1464 } 1465 1466 /** 1467 * Returns the font feature settings. The format is the same as the CSS 1468 * font-feature-settings attribute: 1469 * <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop"> 1470 * https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop</a> 1471 * 1472 * @return the paint's currently set font feature settings. Default is null. 1473 * 1474 * @see #setFontFeatureSettings(String) 1475 */ 1476 public String getFontFeatureSettings() { 1477 return mFontFeatureSettings; 1478 } 1479 1480 /** 1481 * Set font feature settings. 1482 * 1483 * The format is the same as the CSS font-feature-settings attribute: 1484 * <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop"> 1485 * https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop</a> 1486 * 1487 * @see #getFontFeatureSettings() 1488 * 1489 * @param settings the font feature settings string to use, may be null. 1490 */ 1491 public void setFontFeatureSettings(String settings) { 1492 if (settings != null && settings.equals("")) { 1493 settings = null; 1494 } 1495 if ((settings == null && mFontFeatureSettings == null) 1496 || (settings != null && settings.equals(mFontFeatureSettings))) { 1497 return; 1498 } 1499 mFontFeatureSettings = settings; 1500 nSetFontFeatureSettings(mNativePaint, settings); 1501 } 1502 1503 /** 1504 * Get the current value of hyphen edit. 1505 * 1506 * @return the current hyphen edit value 1507 * 1508 * @hide 1509 */ 1510 public int getHyphenEdit() { 1511 return nGetHyphenEdit(mNativePaint); 1512 } 1513 1514 /** 1515 * Set a hyphen edit on the paint (causes a hyphen to be added to text when 1516 * measured or drawn). 1517 * 1518 * @param hyphen 0 for no edit, 1 for adding a hyphen (other values in future) 1519 * 1520 * @hide 1521 */ 1522 public void setHyphenEdit(int hyphen) { 1523 nSetHyphenEdit(mNativePaint, hyphen); 1524 } 1525 1526 /** 1527 * Return the distance above (negative) the baseline (ascent) based on the 1528 * current typeface and text size. 1529 * 1530 * @return the distance above (negative) the baseline (ascent) based on the 1531 * current typeface and text size. 1532 */ 1533 public float ascent() { 1534 return nAscent(mNativePaint, mNativeTypeface); 1535 } 1536 1537 /** 1538 * Return the distance below (positive) the baseline (descent) based on the 1539 * current typeface and text size. 1540 * 1541 * @return the distance below (positive) the baseline (descent) based on 1542 * the current typeface and text size. 1543 */ 1544 public float descent() { 1545 return nDescent(mNativePaint, mNativeTypeface); 1546 } 1547 1548 /** 1549 * Class that describes the various metrics for a font at a given text size. 1550 * Remember, Y values increase going down, so those values will be positive, 1551 * and values that measure distances going up will be negative. This class 1552 * is returned by getFontMetrics(). 1553 */ 1554 public static class FontMetrics { 1555 /** 1556 * The maximum distance above the baseline for the tallest glyph in 1557 * the font at a given text size. 1558 */ 1559 public float top; 1560 /** 1561 * The recommended distance above the baseline for singled spaced text. 1562 */ 1563 public float ascent; 1564 /** 1565 * The recommended distance below the baseline for singled spaced text. 1566 */ 1567 public float descent; 1568 /** 1569 * The maximum distance below the baseline for the lowest glyph in 1570 * the font at a given text size. 1571 */ 1572 public float bottom; 1573 /** 1574 * The recommended additional space to add between lines of text. 1575 */ 1576 public float leading; 1577 } 1578 1579 /** 1580 * Return the font's recommended interline spacing, given the Paint's 1581 * settings for typeface, textSize, etc. If metrics is not null, return the 1582 * fontmetric values in it. 1583 * 1584 * @param metrics If this object is not null, its fields are filled with 1585 * the appropriate values given the paint's text attributes. 1586 * @return the font's recommended interline spacing. 1587 */ 1588 public float getFontMetrics(FontMetrics metrics) { 1589 return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics); 1590 } 1591 1592 /** 1593 * Allocates a new FontMetrics object, and then calls getFontMetrics(fm) 1594 * with it, returning the object. 1595 */ 1596 public FontMetrics getFontMetrics() { 1597 FontMetrics fm = new FontMetrics(); 1598 getFontMetrics(fm); 1599 return fm; 1600 } 1601 1602 /** 1603 * Convenience method for callers that want to have FontMetrics values as 1604 * integers. 1605 */ 1606 public static class FontMetricsInt { 1607 /** 1608 * The maximum distance above the baseline for the tallest glyph in 1609 * the font at a given text size. 1610 */ 1611 public int top; 1612 /** 1613 * The recommended distance above the baseline for singled spaced text. 1614 */ 1615 public int ascent; 1616 /** 1617 * The recommended distance below the baseline for singled spaced text. 1618 */ 1619 public int descent; 1620 /** 1621 * The maximum distance below the baseline for the lowest glyph in 1622 * the font at a given text size. 1623 */ 1624 public int bottom; 1625 /** 1626 * The recommended additional space to add between lines of text. 1627 */ 1628 public int leading; 1629 1630 @Override public String toString() { 1631 return "FontMetricsInt: top=" + top + " ascent=" + ascent + 1632 " descent=" + descent + " bottom=" + bottom + 1633 " leading=" + leading; 1634 } 1635 } 1636 1637 /** 1638 * Return the font's interline spacing, given the Paint's settings for 1639 * typeface, textSize, etc. If metrics is not null, return the fontmetric 1640 * values in it. Note: all values have been converted to integers from 1641 * floats, in such a way has to make the answers useful for both spacing 1642 * and clipping. If you want more control over the rounding, call 1643 * getFontMetrics(). 1644 * 1645 * @return the font's interline spacing. 1646 */ 1647 public int getFontMetricsInt(FontMetricsInt fmi) { 1648 return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi); 1649 } 1650 1651 public FontMetricsInt getFontMetricsInt() { 1652 FontMetricsInt fm = new FontMetricsInt(); 1653 getFontMetricsInt(fm); 1654 return fm; 1655 } 1656 1657 /** 1658 * Return the recommend line spacing based on the current typeface and 1659 * text size. 1660 * 1661 * @return recommend line spacing based on the current typeface and 1662 * text size. 1663 */ 1664 public float getFontSpacing() { 1665 return getFontMetrics(null); 1666 } 1667 1668 /** 1669 * Return the width of the text. 1670 * 1671 * @param text The text to measure. Cannot be null. 1672 * @param index The index of the first character to start measuring 1673 * @param count THe number of characters to measure, beginning with start 1674 * @return The width of the text 1675 */ 1676 public float measureText(char[] text, int index, int count) { 1677 if (text == null) { 1678 throw new IllegalArgumentException("text cannot be null"); 1679 } 1680 if ((index | count) < 0 || index + count > text.length) { 1681 throw new ArrayIndexOutOfBoundsException(); 1682 } 1683 1684 if (text.length == 0 || count == 0) { 1685 return 0f; 1686 } 1687 if (!mHasCompatScaling) { 1688 return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text, 1689 index, count, index, count, mBidiFlags, null, 0)); 1690 } 1691 1692 final float oldSize = getTextSize(); 1693 setTextSize(oldSize * mCompatScaling); 1694 float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, 1695 count, mBidiFlags, null, 0); 1696 setTextSize(oldSize); 1697 return (float) Math.ceil(w*mInvCompatScaling); 1698 } 1699 1700 /** 1701 * Return the width of the text. 1702 * 1703 * @param text The text to measure. Cannot be null. 1704 * @param start The index of the first character to start measuring 1705 * @param end 1 beyond the index of the last character to measure 1706 * @return The width of the text 1707 */ 1708 public float measureText(String text, int start, int end) { 1709 if (text == null) { 1710 throw new IllegalArgumentException("text cannot be null"); 1711 } 1712 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1713 throw new IndexOutOfBoundsException(); 1714 } 1715 1716 if (text.length() == 0 || start == end) { 1717 return 0f; 1718 } 1719 if (!mHasCompatScaling) { 1720 return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text, 1721 start, end, start, end, mBidiFlags, null, 0)); 1722 } 1723 final float oldSize = getTextSize(); 1724 setTextSize(oldSize * mCompatScaling); 1725 float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, 1726 end, mBidiFlags, null, 0); 1727 setTextSize(oldSize); 1728 return (float) Math.ceil(w * mInvCompatScaling); 1729 } 1730 1731 /** 1732 * Return the width of the text. 1733 * 1734 * @param text The text to measure. Cannot be null. 1735 * @return The width of the text 1736 */ 1737 public float measureText(String text) { 1738 if (text == null) { 1739 throw new IllegalArgumentException("text cannot be null"); 1740 } 1741 return measureText(text, 0, text.length()); 1742 } 1743 1744 /** 1745 * Return the width of the text. 1746 * 1747 * @param text The text to measure 1748 * @param start The index of the first character to start measuring 1749 * @param end 1 beyond the index of the last character to measure 1750 * @return The width of the text 1751 */ 1752 public float measureText(CharSequence text, int start, int end) { 1753 if (text == null) { 1754 throw new IllegalArgumentException("text cannot be null"); 1755 } 1756 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1757 throw new IndexOutOfBoundsException(); 1758 } 1759 1760 if (text.length() == 0 || start == end) { 1761 return 0f; 1762 } 1763 if (text instanceof String) { 1764 return measureText((String)text, start, end); 1765 } 1766 if (text instanceof SpannedString || 1767 text instanceof SpannableString) { 1768 return measureText(text.toString(), start, end); 1769 } 1770 if (text instanceof GraphicsOperations) { 1771 return ((GraphicsOperations)text).measureText(start, end, this); 1772 } 1773 1774 char[] buf = TemporaryBuffer.obtain(end - start); 1775 TextUtils.getChars(text, start, end, buf, 0); 1776 float result = measureText(buf, 0, end - start); 1777 TemporaryBuffer.recycle(buf); 1778 return result; 1779 } 1780 1781 /** 1782 * Measure the text, stopping early if the measured width exceeds maxWidth. 1783 * Return the number of chars that were measured, and if measuredWidth is 1784 * not null, return in it the actual width measured. 1785 * 1786 * @param text The text to measure. Cannot be null. 1787 * @param index The offset into text to begin measuring at 1788 * @param count The number of maximum number of entries to measure. If count 1789 * is negative, then the characters are measured in reverse order. 1790 * @param maxWidth The maximum width to accumulate. 1791 * @param measuredWidth Optional. If not null, returns the actual width 1792 * measured. 1793 * @return The number of chars that were measured. Will always be <= 1794 * abs(count). 1795 */ 1796 public int breakText(char[] text, int index, int count, 1797 float maxWidth, float[] measuredWidth) { 1798 if (text == null) { 1799 throw new IllegalArgumentException("text cannot be null"); 1800 } 1801 if (index < 0 || text.length - index < Math.abs(count)) { 1802 throw new ArrayIndexOutOfBoundsException(); 1803 } 1804 1805 if (text.length == 0 || count == 0) { 1806 return 0; 1807 } 1808 if (!mHasCompatScaling) { 1809 return nBreakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth, 1810 mBidiFlags, measuredWidth); 1811 } 1812 1813 final float oldSize = getTextSize(); 1814 setTextSize(oldSize * mCompatScaling); 1815 int res = nBreakText(mNativePaint, mNativeTypeface, text, index, count, 1816 maxWidth * mCompatScaling, mBidiFlags, measuredWidth); 1817 setTextSize(oldSize); 1818 if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling; 1819 return res; 1820 } 1821 1822 /** 1823 * Measure the text, stopping early if the measured width exceeds maxWidth. 1824 * Return the number of chars that were measured, and if measuredWidth is 1825 * not null, return in it the actual width measured. 1826 * 1827 * @param text The text to measure. Cannot be null. 1828 * @param start The offset into text to begin measuring at 1829 * @param end The end of the text slice to measure. 1830 * @param measureForwards If true, measure forwards, starting at start. 1831 * Otherwise, measure backwards, starting with end. 1832 * @param maxWidth The maximum width to accumulate. 1833 * @param measuredWidth Optional. If not null, returns the actual width 1834 * measured. 1835 * @return The number of chars that were measured. Will always be <= 1836 * abs(end - start). 1837 */ 1838 public int breakText(CharSequence text, int start, int end, 1839 boolean measureForwards, 1840 float maxWidth, float[] measuredWidth) { 1841 if (text == null) { 1842 throw new IllegalArgumentException("text cannot be null"); 1843 } 1844 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1845 throw new IndexOutOfBoundsException(); 1846 } 1847 1848 if (text.length() == 0 || start == end) { 1849 return 0; 1850 } 1851 if (start == 0 && text instanceof String && end == text.length()) { 1852 return breakText((String) text, measureForwards, maxWidth, 1853 measuredWidth); 1854 } 1855 1856 char[] buf = TemporaryBuffer.obtain(end - start); 1857 int result; 1858 1859 TextUtils.getChars(text, start, end, buf, 0); 1860 1861 if (measureForwards) { 1862 result = breakText(buf, 0, end - start, maxWidth, measuredWidth); 1863 } else { 1864 result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth); 1865 } 1866 1867 TemporaryBuffer.recycle(buf); 1868 return result; 1869 } 1870 1871 /** 1872 * Measure the text, stopping early if the measured width exceeds maxWidth. 1873 * Return the number of chars that were measured, and if measuredWidth is 1874 * not null, return in it the actual width measured. 1875 * 1876 * @param text The text to measure. Cannot be null. 1877 * @param measureForwards If true, measure forwards, starting with the 1878 * first character in the string. Otherwise, 1879 * measure backwards, starting with the 1880 * last character in the string. 1881 * @param maxWidth The maximum width to accumulate. 1882 * @param measuredWidth Optional. If not null, returns the actual width 1883 * measured. 1884 * @return The number of chars that were measured. Will always be <= 1885 * abs(count). 1886 */ 1887 public int breakText(String text, boolean measureForwards, 1888 float maxWidth, float[] measuredWidth) { 1889 if (text == null) { 1890 throw new IllegalArgumentException("text cannot be null"); 1891 } 1892 1893 if (text.length() == 0) { 1894 return 0; 1895 } 1896 if (!mHasCompatScaling) { 1897 return nBreakText(mNativePaint, mNativeTypeface, text, measureForwards, 1898 maxWidth, mBidiFlags, measuredWidth); 1899 } 1900 1901 final float oldSize = getTextSize(); 1902 setTextSize(oldSize*mCompatScaling); 1903 int res = nBreakText(mNativePaint, mNativeTypeface, text, measureForwards, 1904 maxWidth*mCompatScaling, mBidiFlags, measuredWidth); 1905 setTextSize(oldSize); 1906 if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling; 1907 return res; 1908 } 1909 1910 /** 1911 * Return the advance widths for the characters in the string. 1912 * 1913 * @param text The text to measure. Cannot be null. 1914 * @param index The index of the first char to to measure 1915 * @param count The number of chars starting with index to measure 1916 * @param widths array to receive the advance widths of the characters. 1917 * Must be at least a large as count. 1918 * @return the actual number of widths returned. 1919 */ 1920 public int getTextWidths(char[] text, int index, int count, 1921 float[] widths) { 1922 if (text == null) { 1923 throw new IllegalArgumentException("text cannot be null"); 1924 } 1925 if ((index | count) < 0 || index + count > text.length 1926 || count > widths.length) { 1927 throw new ArrayIndexOutOfBoundsException(); 1928 } 1929 1930 if (text.length == 0 || count == 0) { 1931 return 0; 1932 } 1933 if (!mHasCompatScaling) { 1934 nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, 1935 mBidiFlags, widths, 0); 1936 return count; 1937 } 1938 1939 final float oldSize = getTextSize(); 1940 setTextSize(oldSize * mCompatScaling); 1941 nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, 1942 mBidiFlags, widths, 0); 1943 setTextSize(oldSize); 1944 for (int i = 0; i < count; i++) { 1945 widths[i] *= mInvCompatScaling; 1946 } 1947 return count; 1948 } 1949 1950 /** 1951 * Return the advance widths for the characters in the string. 1952 * 1953 * @param text The text to measure. Cannot be null. 1954 * @param start The index of the first char to to measure 1955 * @param end The end of the text slice to measure 1956 * @param widths array to receive the advance widths of the characters. 1957 * Must be at least a large as (end - start). 1958 * @return the actual number of widths returned. 1959 */ 1960 public int getTextWidths(CharSequence text, int start, int end, 1961 float[] widths) { 1962 if (text == null) { 1963 throw new IllegalArgumentException("text cannot be null"); 1964 } 1965 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1966 throw new IndexOutOfBoundsException(); 1967 } 1968 if (end - start > widths.length) { 1969 throw new ArrayIndexOutOfBoundsException(); 1970 } 1971 1972 if (text.length() == 0 || start == end) { 1973 return 0; 1974 } 1975 if (text instanceof String) { 1976 return getTextWidths((String) text, start, end, widths); 1977 } 1978 if (text instanceof SpannedString || 1979 text instanceof SpannableString) { 1980 return getTextWidths(text.toString(), start, end, widths); 1981 } 1982 if (text instanceof GraphicsOperations) { 1983 return ((GraphicsOperations) text).getTextWidths(start, end, 1984 widths, this); 1985 } 1986 1987 char[] buf = TemporaryBuffer.obtain(end - start); 1988 TextUtils.getChars(text, start, end, buf, 0); 1989 int result = getTextWidths(buf, 0, end - start, widths); 1990 TemporaryBuffer.recycle(buf); 1991 return result; 1992 } 1993 1994 /** 1995 * Return the advance widths for the characters in the string. 1996 * 1997 * @param text The text to measure. Cannot be null. 1998 * @param start The index of the first char to to measure 1999 * @param end The end of the text slice to measure 2000 * @param widths array to receive the advance widths of the characters. 2001 * Must be at least a large as the text. 2002 * @return the number of code units in the specified text. 2003 */ 2004 public int getTextWidths(String text, int start, int end, float[] widths) { 2005 if (text == null) { 2006 throw new IllegalArgumentException("text cannot be null"); 2007 } 2008 if ((start | end | (end - start) | (text.length() - end)) < 0) { 2009 throw new IndexOutOfBoundsException(); 2010 } 2011 if (end - start > widths.length) { 2012 throw new ArrayIndexOutOfBoundsException(); 2013 } 2014 2015 if (text.length() == 0 || start == end) { 2016 return 0; 2017 } 2018 if (!mHasCompatScaling) { 2019 nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, 2020 mBidiFlags, widths, 0); 2021 return end - start; 2022 } 2023 2024 final float oldSize = getTextSize(); 2025 setTextSize(oldSize * mCompatScaling); 2026 nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, 2027 mBidiFlags, widths, 0); 2028 setTextSize(oldSize); 2029 for (int i = 0; i < end - start; i++) { 2030 widths[i] *= mInvCompatScaling; 2031 } 2032 return end - start; 2033 } 2034 2035 /** 2036 * Return the advance widths for the characters in the string. 2037 * 2038 * @param text The text to measure 2039 * @param widths array to receive the advance widths of the characters. 2040 * Must be at least a large as the text. 2041 * @return the number of code units in the specified text. 2042 */ 2043 public int getTextWidths(String text, float[] widths) { 2044 return getTextWidths(text, 0, text.length(), widths); 2045 } 2046 2047 /** 2048 * Convenience overload that takes a char array instead of a 2049 * String. 2050 * 2051 * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int) 2052 * @hide 2053 */ 2054 public float getTextRunAdvances(char[] chars, int index, int count, 2055 int contextIndex, int contextCount, boolean isRtl, float[] advances, 2056 int advancesIndex) { 2057 2058 if (chars == null) { 2059 throw new IllegalArgumentException("text cannot be null"); 2060 } 2061 if ((index | count | contextIndex | contextCount | advancesIndex 2062 | (index - contextIndex) | (contextCount - count) 2063 | ((contextIndex + contextCount) - (index + count)) 2064 | (chars.length - (contextIndex + contextCount)) 2065 | (advances == null ? 0 : 2066 (advances.length - (advancesIndex + count)))) < 0) { 2067 throw new IndexOutOfBoundsException(); 2068 } 2069 2070 if (chars.length == 0 || count == 0){ 2071 return 0f; 2072 } 2073 if (!mHasCompatScaling) { 2074 return nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, 2075 contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, 2076 advancesIndex); 2077 } 2078 2079 final float oldSize = getTextSize(); 2080 setTextSize(oldSize * mCompatScaling); 2081 float res = nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, 2082 contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, 2083 advancesIndex); 2084 setTextSize(oldSize); 2085 2086 if (advances != null) { 2087 for (int i = advancesIndex, e = i + count; i < e; i++) { 2088 advances[i] *= mInvCompatScaling; 2089 } 2090 } 2091 return res * mInvCompatScaling; // assume errors are not significant 2092 } 2093 2094 /** 2095 * Convenience overload that takes a CharSequence instead of a 2096 * String. 2097 * 2098 * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int) 2099 * @hide 2100 */ 2101 public float getTextRunAdvances(CharSequence text, int start, int end, 2102 int contextStart, int contextEnd, boolean isRtl, float[] advances, 2103 int advancesIndex) { 2104 if (text == null) { 2105 throw new IllegalArgumentException("text cannot be null"); 2106 } 2107 if ((start | end | contextStart | contextEnd | advancesIndex | (end - start) 2108 | (start - contextStart) | (contextEnd - end) 2109 | (text.length() - contextEnd) 2110 | (advances == null ? 0 : 2111 (advances.length - advancesIndex - (end - start)))) < 0) { 2112 throw new IndexOutOfBoundsException(); 2113 } 2114 2115 if (text instanceof String) { 2116 return getTextRunAdvances((String) text, start, end, 2117 contextStart, contextEnd, isRtl, advances, advancesIndex); 2118 } 2119 if (text instanceof SpannedString || 2120 text instanceof SpannableString) { 2121 return getTextRunAdvances(text.toString(), start, end, 2122 contextStart, contextEnd, isRtl, advances, advancesIndex); 2123 } 2124 if (text instanceof GraphicsOperations) { 2125 return ((GraphicsOperations) text).getTextRunAdvances(start, end, 2126 contextStart, contextEnd, isRtl, advances, advancesIndex, this); 2127 } 2128 if (text.length() == 0 || end == start) { 2129 return 0f; 2130 } 2131 2132 int contextLen = contextEnd - contextStart; 2133 int len = end - start; 2134 char[] buf = TemporaryBuffer.obtain(contextLen); 2135 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 2136 float result = getTextRunAdvances(buf, start - contextStart, len, 2137 0, contextLen, isRtl, advances, advancesIndex); 2138 TemporaryBuffer.recycle(buf); 2139 return result; 2140 } 2141 2142 /** 2143 * Returns the total advance width for the characters in the run 2144 * between start and end, and if advances is not null, the advance 2145 * assigned to each of these characters (java chars). 2146 * 2147 * <p>The trailing surrogate in a valid surrogate pair is assigned 2148 * an advance of 0. Thus the number of returned advances is 2149 * always equal to count, not to the number of unicode codepoints 2150 * represented by the run. 2151 * 2152 * <p>In the case of conjuncts or combining marks, the total 2153 * advance is assigned to the first logical character, and the 2154 * following characters are assigned an advance of 0. 2155 * 2156 * <p>This generates the sum of the advances of glyphs for 2157 * characters in a reordered cluster as the width of the first 2158 * logical character in the cluster, and 0 for the widths of all 2159 * other characters in the cluster. In effect, such clusters are 2160 * treated like conjuncts. 2161 * 2162 * <p>The shaping bounds limit the amount of context available 2163 * outside start and end that can be used for shaping analysis. 2164 * These bounds typically reflect changes in bidi level or font 2165 * metrics across which shaping does not occur. 2166 * 2167 * @param text the text to measure. Cannot be null. 2168 * @param start the index of the first character to measure 2169 * @param end the index past the last character to measure 2170 * @param contextStart the index of the first character to use for shaping context, 2171 * must be <= start 2172 * @param contextEnd the index past the last character to use for shaping context, 2173 * must be >= end 2174 * @param isRtl whether the run is in RTL direction 2175 * @param advances array to receive the advances, must have room for all advances, 2176 * can be null if only total advance is needed 2177 * @param advancesIndex the position in advances at which to put the 2178 * advance corresponding to the character at start 2179 * @return the total advance 2180 * 2181 * @hide 2182 */ 2183 public float getTextRunAdvances(String text, int start, int end, int contextStart, 2184 int contextEnd, boolean isRtl, float[] advances, int advancesIndex) { 2185 if (text == null) { 2186 throw new IllegalArgumentException("text cannot be null"); 2187 } 2188 if ((start | end | contextStart | contextEnd | advancesIndex | (end - start) 2189 | (start - contextStart) | (contextEnd - end) 2190 | (text.length() - contextEnd) 2191 | (advances == null ? 0 : 2192 (advances.length - advancesIndex - (end - start)))) < 0) { 2193 throw new IndexOutOfBoundsException(); 2194 } 2195 2196 if (text.length() == 0 || start == end) { 2197 return 0f; 2198 } 2199 2200 if (!mHasCompatScaling) { 2201 return nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, 2202 contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, 2203 advancesIndex); 2204 } 2205 2206 final float oldSize = getTextSize(); 2207 setTextSize(oldSize * mCompatScaling); 2208 float totalAdvance = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, 2209 end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, 2210 advancesIndex); 2211 setTextSize(oldSize); 2212 2213 if (advances != null) { 2214 for (int i = advancesIndex, e = i + (end - start); i < e; i++) { 2215 advances[i] *= mInvCompatScaling; 2216 } 2217 } 2218 return totalAdvance * mInvCompatScaling; // assume errors are insignificant 2219 } 2220 2221 /** 2222 * Returns the next cursor position in the run. This avoids placing the 2223 * cursor between surrogates, between characters that form conjuncts, 2224 * between base characters and combining marks, or within a reordering 2225 * cluster. 2226 * 2227 * <p>ContextStart and offset are relative to the start of text. 2228 * The context is the shaping context for cursor movement, generally 2229 * the bounds of the metric span enclosing the cursor in the direction of 2230 * movement. 2231 * 2232 * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid 2233 * cursor position, this returns -1. Otherwise this will never return a 2234 * value before contextStart or after contextStart + contextLength. 2235 * 2236 * @param text the text 2237 * @param contextStart the start of the context 2238 * @param contextLength the length of the context 2239 * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} 2240 * @param offset the cursor position to move from 2241 * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, 2242 * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, 2243 * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} 2244 * @return the offset of the next position, or -1 2245 * @hide 2246 */ 2247 public int getTextRunCursor(char[] text, int contextStart, int contextLength, 2248 int dir, int offset, int cursorOpt) { 2249 int contextEnd = contextStart + contextLength; 2250 if (((contextStart | contextEnd | offset | (contextEnd - contextStart) 2251 | (offset - contextStart) | (contextEnd - offset) 2252 | (text.length - contextEnd) | cursorOpt) < 0) 2253 || cursorOpt > CURSOR_OPT_MAX_VALUE) { 2254 throw new IndexOutOfBoundsException(); 2255 } 2256 2257 return nGetTextRunCursor(mNativePaint, text, 2258 contextStart, contextLength, dir, offset, cursorOpt); 2259 } 2260 2261 /** 2262 * Returns the next cursor position in the run. This avoids placing the 2263 * cursor between surrogates, between characters that form conjuncts, 2264 * between base characters and combining marks, or within a reordering 2265 * cluster. 2266 * 2267 * <p>ContextStart, contextEnd, and offset are relative to the start of 2268 * text. The context is the shaping context for cursor movement, generally 2269 * the bounds of the metric span enclosing the cursor in the direction of 2270 * movement. 2271 * 2272 * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid 2273 * cursor position, this returns -1. Otherwise this will never return a 2274 * value before contextStart or after contextEnd. 2275 * 2276 * @param text the text 2277 * @param contextStart the start of the context 2278 * @param contextEnd the end of the context 2279 * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} 2280 * @param offset the cursor position to move from 2281 * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, 2282 * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, 2283 * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} 2284 * @return the offset of the next position, or -1 2285 * @hide 2286 */ 2287 public int getTextRunCursor(CharSequence text, int contextStart, 2288 int contextEnd, int dir, int offset, int cursorOpt) { 2289 2290 if (text instanceof String || text instanceof SpannedString || 2291 text instanceof SpannableString) { 2292 return getTextRunCursor(text.toString(), contextStart, contextEnd, 2293 dir, offset, cursorOpt); 2294 } 2295 if (text instanceof GraphicsOperations) { 2296 return ((GraphicsOperations) text).getTextRunCursor( 2297 contextStart, contextEnd, dir, offset, cursorOpt, this); 2298 } 2299 2300 int contextLen = contextEnd - contextStart; 2301 char[] buf = TemporaryBuffer.obtain(contextLen); 2302 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 2303 int relPos = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt); 2304 TemporaryBuffer.recycle(buf); 2305 return (relPos == -1) ? -1 : relPos + contextStart; 2306 } 2307 2308 /** 2309 * Returns the next cursor position in the run. This avoids placing the 2310 * cursor between surrogates, between characters that form conjuncts, 2311 * between base characters and combining marks, or within a reordering 2312 * cluster. 2313 * 2314 * <p>ContextStart, contextEnd, and offset are relative to the start of 2315 * text. The context is the shaping context for cursor movement, generally 2316 * the bounds of the metric span enclosing the cursor in the direction of 2317 * movement. 2318 * 2319 * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid 2320 * cursor position, this returns -1. Otherwise this will never return a 2321 * value before contextStart or after contextEnd. 2322 * 2323 * @param text the text 2324 * @param contextStart the start of the context 2325 * @param contextEnd the end of the context 2326 * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} 2327 * @param offset the cursor position to move from 2328 * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, 2329 * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, 2330 * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} 2331 * @return the offset of the next position, or -1 2332 * @hide 2333 */ 2334 public int getTextRunCursor(String text, int contextStart, int contextEnd, 2335 int dir, int offset, int cursorOpt) { 2336 if (((contextStart | contextEnd | offset | (contextEnd - contextStart) 2337 | (offset - contextStart) | (contextEnd - offset) 2338 | (text.length() - contextEnd) | cursorOpt) < 0) 2339 || cursorOpt > CURSOR_OPT_MAX_VALUE) { 2340 throw new IndexOutOfBoundsException(); 2341 } 2342 2343 return nGetTextRunCursor(mNativePaint, text, 2344 contextStart, contextEnd, dir, offset, cursorOpt); 2345 } 2346 2347 /** 2348 * Return the path (outline) for the specified text. 2349 * Note: just like Canvas.drawText, this will respect the Align setting in 2350 * the paint. 2351 * 2352 * @param text the text to retrieve the path from 2353 * @param index the index of the first character in text 2354 * @param count the number of characters starting with index 2355 * @param x the x coordinate of the text's origin 2356 * @param y the y coordinate of the text's origin 2357 * @param path the path to receive the data describing the text. Must be allocated by the caller 2358 */ 2359 public void getTextPath(char[] text, int index, int count, 2360 float x, float y, Path path) { 2361 if ((index | count) < 0 || index + count > text.length) { 2362 throw new ArrayIndexOutOfBoundsException(); 2363 } 2364 nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y, 2365 path.mutateNI()); 2366 } 2367 2368 /** 2369 * Return the path (outline) for the specified text. 2370 * Note: just like Canvas.drawText, this will respect the Align setting 2371 * in the paint. 2372 * 2373 * @param text the text to retrieve the path from 2374 * @param start the first character in the text 2375 * @param end 1 past the last character in the text 2376 * @param x the x coordinate of the text's origin 2377 * @param y the y coordinate of the text's origin 2378 * @param path the path to receive the data describing the text. Must be allocated by the caller 2379 */ 2380 public void getTextPath(String text, int start, int end, 2381 float x, float y, Path path) { 2382 if ((start | end | (end - start) | (text.length() - end)) < 0) { 2383 throw new IndexOutOfBoundsException(); 2384 } 2385 nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y, 2386 path.mutateNI()); 2387 } 2388 2389 /** 2390 * Return in bounds (allocated by the caller) the smallest rectangle that 2391 * encloses all of the characters, with an implied origin at (0,0). 2392 * 2393 * @param text string to measure and return its bounds 2394 * @param start index of the first char in the string to measure 2395 * @param end 1 past the last char in the string to measure 2396 * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller 2397 */ 2398 public void getTextBounds(String text, int start, int end, Rect bounds) { 2399 if ((start | end | (end - start) | (text.length() - end)) < 0) { 2400 throw new IndexOutOfBoundsException(); 2401 } 2402 if (bounds == null) { 2403 throw new NullPointerException("need bounds Rect"); 2404 } 2405 nGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds); 2406 } 2407 2408 /** 2409 * Return in bounds (allocated by the caller) the smallest rectangle that 2410 * encloses all of the characters, with an implied origin at (0,0). 2411 * 2412 * @param text text to measure and return its bounds 2413 * @param start index of the first char in the text to measure 2414 * @param end 1 past the last char in the text to measure 2415 * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller 2416 * @hide 2417 */ 2418 public void getTextBounds(CharSequence text, int start, int end, Rect bounds) { 2419 if ((start | end | (end - start) | (text.length() - end)) < 0) { 2420 throw new IndexOutOfBoundsException(); 2421 } 2422 if (bounds == null) { 2423 throw new NullPointerException("need bounds Rect"); 2424 } 2425 char[] buf = TemporaryBuffer.obtain(end - start); 2426 TextUtils.getChars(text, start, end, buf, 0); 2427 getTextBounds(buf, 0, end - start, bounds); 2428 TemporaryBuffer.recycle(buf); 2429 } 2430 2431 /** 2432 * Return in bounds (allocated by the caller) the smallest rectangle that 2433 * encloses all of the characters, with an implied origin at (0,0). 2434 * 2435 * @param text array of chars to measure and return their unioned bounds 2436 * @param index index of the first char in the array to measure 2437 * @param count the number of chars, beginning at index, to measure 2438 * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller 2439 */ 2440 public void getTextBounds(char[] text, int index, int count, Rect bounds) { 2441 if ((index | count) < 0 || index + count > text.length) { 2442 throw new ArrayIndexOutOfBoundsException(); 2443 } 2444 if (bounds == null) { 2445 throw new NullPointerException("need bounds Rect"); 2446 } 2447 nGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, 2448 bounds); 2449 } 2450 2451 /** 2452 * Determine whether the typeface set on the paint has a glyph supporting the string. The 2453 * simplest case is when the string contains a single character, in which this method 2454 * determines whether the font has the character. In the case of multiple characters, the 2455 * method returns true if there is a single glyph representing the ligature. For example, if 2456 * the input is a pair of regional indicator symbols, determine whether there is an emoji flag 2457 * for the pair. 2458 * 2459 * <p>Finally, if the string contains a variation selector, the method only returns true if 2460 * the fonts contains a glyph specific to that variation. 2461 * 2462 * <p>Checking is done on the entire fallback chain, not just the immediate font referenced. 2463 * 2464 * @param string the string to test whether there is glyph support 2465 * @return true if the typeface has a glyph for the string 2466 */ 2467 public boolean hasGlyph(String string) { 2468 return nHasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string); 2469 } 2470 2471 /** 2472 * Measure cursor position within a run of text. 2473 * 2474 * <p>The run of text includes the characters from {@code start} to {@code end} in the text. In 2475 * addition, the range {@code contextStart} to {@code contextEnd} is used as context for the 2476 * purpose of complex text shaping, such as Arabic text potentially shaped differently based on 2477 * the text next to it. 2478 * 2479 * <p>All text outside the range {@code contextStart..contextEnd} is ignored. The text between 2480 * {@code start} and {@code end} will be laid out to be measured. 2481 * 2482 * <p>The returned width measurement is the advance from {@code start} to {@code offset}. It is 2483 * generally a positive value, no matter the direction of the run. If {@code offset == end}, 2484 * the return value is simply the width of the whole run from {@code start} to {@code end}. 2485 * 2486 * <p>Ligatures are formed for characters in the range {@code start..end} (but not for 2487 * {@code start..contextStart} or {@code end..contextEnd}). If {@code offset} points to a 2488 * character in the middle of such a formed ligature, but at a grapheme cluster boundary, the 2489 * return value will also reflect an advance in the middle of the ligature. See 2490 * {@link #getOffsetForAdvance} for more discussion of grapheme cluster boundaries. 2491 * 2492 * <p>The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is 2493 * suitable only for runs of a single direction. 2494 * 2495 * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart 2496 * <= start <= offset <= end <= contextEnd <= text.length} must hold on entry. 2497 * 2498 * @param text the text to measure. Cannot be null. 2499 * @param start the index of the start of the range to measure 2500 * @param end the index + 1 of the end of the range to measure 2501 * @param contextStart the index of the start of the shaping context 2502 * @param contextEnd the index + 1 of the end of the shaping context 2503 * @param isRtl whether the run is in RTL direction 2504 * @param offset index of caret position 2505 * @return width measurement between start and offset 2506 */ 2507 public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd, 2508 boolean isRtl, int offset) { 2509 if (text == null) { 2510 throw new IllegalArgumentException("text cannot be null"); 2511 } 2512 if ((contextStart | start | offset | end | contextEnd 2513 | start - contextStart | offset - start | end - offset 2514 | contextEnd - end | text.length - contextEnd) < 0) { 2515 throw new IndexOutOfBoundsException(); 2516 } 2517 if (end == start) { 2518 return 0.0f; 2519 } 2520 // TODO: take mCompatScaling into account (or eliminate compat scaling)? 2521 return nGetRunAdvance(mNativePaint, mNativeTypeface, text, start, end, 2522 contextStart, contextEnd, isRtl, offset); 2523 } 2524 2525 /** 2526 * @see #getRunAdvance(char[], int, int, int, int, boolean, int) 2527 * 2528 * @param text the text to measure. Cannot be null. 2529 * @param start the index of the start of the range to measure 2530 * @param end the index + 1 of the end of the range to measure 2531 * @param contextStart the index of the start of the shaping context 2532 * @param contextEnd the index + 1 of the end of the shaping context 2533 * @param isRtl whether the run is in RTL direction 2534 * @param offset index of caret position 2535 * @return width measurement between start and offset 2536 */ 2537 public float getRunAdvance(CharSequence text, int start, int end, int contextStart, 2538 int contextEnd, boolean isRtl, int offset) { 2539 if (text == null) { 2540 throw new IllegalArgumentException("text cannot be null"); 2541 } 2542 if ((contextStart | start | offset | end | contextEnd 2543 | start - contextStart | offset - start | end - offset 2544 | contextEnd - end | text.length() - contextEnd) < 0) { 2545 throw new IndexOutOfBoundsException(); 2546 } 2547 if (end == start) { 2548 return 0.0f; 2549 } 2550 // TODO performance: specialized alternatives to avoid buffer copy, if win is significant 2551 char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart); 2552 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 2553 float result = getRunAdvance(buf, start - contextStart, end - contextStart, 0, 2554 contextEnd - contextStart, isRtl, offset - contextStart); 2555 TemporaryBuffer.recycle(buf); 2556 return result; 2557 } 2558 2559 /** 2560 * Get the character offset within the string whose position is closest to the specified 2561 * horizontal position. 2562 * 2563 * <p>The returned value is generally the value of {@code offset} for which 2564 * {@link #getRunAdvance} yields a result most closely approximating {@code advance}, 2565 * and which is also on a grapheme cluster boundary. As such, it is the preferred method 2566 * for positioning a cursor in response to a touch or pointer event. The grapheme cluster 2567 * boundaries are based on 2568 * <a href="http://unicode.org/reports/tr29/">Unicode Standard Annex #29</a> but with some 2569 * tailoring for better user experience. 2570 * 2571 * <p>Note that {@code advance} is a (generally positive) width measurement relative to the start 2572 * of the run. Thus, for RTL runs it the distance from the point to the right edge. 2573 * 2574 * <p>All indices are relative to the start of {@code text}. Further, {@code 0 <= contextStart 2575 * <= start <= end <= contextEnd <= text.length} must hold on entry, and {@code start <= result 2576 * <= end} will hold on return. 2577 * 2578 * @param text the text to measure. Cannot be null. 2579 * @param start the index of the start of the range to measure 2580 * @param end the index + 1 of the end of the range to measure 2581 * @param contextStart the index of the start of the shaping context 2582 * @param contextEnd the index + 1 of the end of the range to measure 2583 * @param isRtl whether the run is in RTL direction 2584 * @param advance width relative to start of run 2585 * @return index of offset 2586 */ 2587 public int getOffsetForAdvance(char[] text, int start, int end, int contextStart, 2588 int contextEnd, boolean isRtl, float advance) { 2589 if (text == null) { 2590 throw new IllegalArgumentException("text cannot be null"); 2591 } 2592 if ((contextStart | start | end | contextEnd 2593 | start - contextStart | end - start | contextEnd - end 2594 | text.length - contextEnd) < 0) { 2595 throw new IndexOutOfBoundsException(); 2596 } 2597 // TODO: take mCompatScaling into account (or eliminate compat scaling)? 2598 return nGetOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end, 2599 contextStart, contextEnd, isRtl, advance); 2600 } 2601 2602 /** 2603 * @see #getOffsetForAdvance(char[], int, int, int, int, boolean, float) 2604 * 2605 * @param text the text to measure. Cannot be null. 2606 * @param start the index of the start of the range to measure 2607 * @param end the index + 1 of the end of the range to measure 2608 * @param contextStart the index of the start of the shaping context 2609 * @param contextEnd the index + 1 of the end of the range to measure 2610 * @param isRtl whether the run is in RTL direction 2611 * @param advance width relative to start of run 2612 * @return index of offset 2613 */ 2614 public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, 2615 int contextEnd, boolean isRtl, float advance) { 2616 if (text == null) { 2617 throw new IllegalArgumentException("text cannot be null"); 2618 } 2619 if ((contextStart | start | end | contextEnd 2620 | start - contextStart | end - start | contextEnd - end 2621 | text.length() - contextEnd) < 0) { 2622 throw new IndexOutOfBoundsException(); 2623 } 2624 // TODO performance: specialized alternatives to avoid buffer copy, if win is significant 2625 char[] buf = TemporaryBuffer.obtain(contextEnd - contextStart); 2626 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 2627 int result = getOffsetForAdvance(buf, start - contextStart, end - contextStart, 0, 2628 contextEnd - contextStart, isRtl, advance) + contextStart; 2629 TemporaryBuffer.recycle(buf); 2630 return result; 2631 } 2632 2633 // regular JNI 2634 private static native long nGetNativeFinalizer(); 2635 private static native long nInit(); 2636 private static native long nInitWithPaint(long paint); 2637 private static native int nBreakText(long nObject, long nTypeface, 2638 char[] text, int index, int count, 2639 float maxWidth, int bidiFlags, float[] measuredWidth); 2640 private static native int nBreakText(long nObject, long nTypeface, 2641 String text, boolean measureForwards, 2642 float maxWidth, int bidiFlags, float[] measuredWidth); 2643 private static native float nGetTextAdvances(long paintPtr, long typefacePtr, 2644 char[] text, int index, int count, int contextIndex, int contextCount, 2645 int bidiFlags, float[] advances, int advancesIndex); 2646 private static native float nGetTextAdvances(long paintPtr, long typefacePtr, 2647 String text, int start, int end, int contextStart, int contextEnd, 2648 int bidiFlags, float[] advances, int advancesIndex); 2649 private native int nGetTextRunCursor(long paintPtr, char[] text, 2650 int contextStart, int contextLength, int dir, int offset, int cursorOpt); 2651 private native int nGetTextRunCursor(long paintPtr, String text, 2652 int contextStart, int contextEnd, int dir, int offset, int cursorOpt); 2653 private static native void nGetTextPath(long paintPtr, long typefacePtr, 2654 int bidiFlags, char[] text, int index, int count, float x, float y, long path); 2655 private static native void nGetTextPath(long paintPtr, long typefacePtr, 2656 int bidiFlags, String text, int start, int end, float x, float y, long path); 2657 private static native void nGetStringBounds(long nativePaint, long typefacePtr, 2658 String text, int start, int end, int bidiFlags, Rect bounds); 2659 private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr, 2660 char[] text, int index, int count, int bidiFlags, Rect bounds); 2661 private static native boolean nHasGlyph(long paintPtr, long typefacePtr, 2662 int bidiFlags, String string); 2663 private static native float nGetRunAdvance(long paintPtr, long typefacePtr, 2664 char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, 2665 int offset); 2666 private static native int nGetOffsetForAdvance(long paintPtr, 2667 long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd, 2668 boolean isRtl, float advance); 2669 2670 2671 // ---------------- @FastNative ------------------------ 2672 2673 @FastNative 2674 private static native int nSetTextLocales(long paintPtr, String locales); 2675 @FastNative 2676 private static native void nSetFontFeatureSettings(long paintPtr, String settings); 2677 @FastNative 2678 private static native float nGetFontMetrics(long paintPtr, 2679 long typefacePtr, FontMetrics metrics); 2680 @FastNative 2681 private static native int nGetFontMetricsInt(long paintPtr, 2682 long typefacePtr, FontMetricsInt fmi); 2683 2684 2685 // ---------------- @CriticalNative ------------------------ 2686 2687 @CriticalNative 2688 private static native void nReset(long paintPtr); 2689 @CriticalNative 2690 private static native void nSet(long paintPtrDest, long paintPtrSrc); 2691 @CriticalNative 2692 private static native int nGetStyle(long paintPtr); 2693 @CriticalNative 2694 private static native void nSetStyle(long paintPtr, int style); 2695 @CriticalNative 2696 private static native int nGetStrokeCap(long paintPtr); 2697 @CriticalNative 2698 private static native void nSetStrokeCap(long paintPtr, int cap); 2699 @CriticalNative 2700 private static native int nGetStrokeJoin(long paintPtr); 2701 @CriticalNative 2702 private static native void nSetStrokeJoin(long paintPtr, int join); 2703 @CriticalNative 2704 private static native boolean nGetFillPath(long paintPtr, long src, long dst); 2705 @CriticalNative 2706 private static native long nSetShader(long paintPtr, long shader); 2707 @CriticalNative 2708 private static native long nSetColorFilter(long paintPtr, long filter); 2709 @CriticalNative 2710 private static native void nSetXfermode(long paintPtr, int xfermode); 2711 @CriticalNative 2712 private static native long nSetPathEffect(long paintPtr, long effect); 2713 @CriticalNative 2714 private static native long nSetMaskFilter(long paintPtr, long maskfilter); 2715 @CriticalNative 2716 private static native long nSetTypeface(long paintPtr, long typeface); 2717 @CriticalNative 2718 private static native long nSetRasterizer(long paintPtr, long rasterizer); 2719 @CriticalNative 2720 private static native int nGetTextAlign(long paintPtr); 2721 @CriticalNative 2722 private static native void nSetTextAlign(long paintPtr, int align); 2723 @CriticalNative 2724 private static native void nSetTextLocalesByMinikinLangListId(long paintPtr, 2725 int mMinikinLangListId); 2726 @CriticalNative 2727 private static native void nSetShadowLayer(long paintPtr, 2728 float radius, float dx, float dy, int color); 2729 @CriticalNative 2730 private static native boolean nHasShadowLayer(long paintPtr); 2731 @CriticalNative 2732 private static native float nGetLetterSpacing(long paintPtr); 2733 @CriticalNative 2734 private static native void nSetLetterSpacing(long paintPtr, float letterSpacing); 2735 @CriticalNative 2736 private static native float nGetWordSpacing(long paintPtr); 2737 @CriticalNative 2738 private static native void nSetWordSpacing(long paintPtr, float wordSpacing); 2739 @CriticalNative 2740 private static native int nGetHyphenEdit(long paintPtr); 2741 @CriticalNative 2742 private static native void nSetHyphenEdit(long paintPtr, int hyphen); 2743 @CriticalNative 2744 private static native void nSetStrokeMiter(long paintPtr, float miter); 2745 @CriticalNative 2746 private static native float nGetStrokeMiter(long paintPtr); 2747 @CriticalNative 2748 private static native void nSetStrokeWidth(long paintPtr, float width); 2749 @CriticalNative 2750 private static native float nGetStrokeWidth(long paintPtr); 2751 @CriticalNative 2752 private static native void nSetAlpha(long paintPtr, int a); 2753 @CriticalNative 2754 private static native void nSetDither(long paintPtr, boolean dither); 2755 @CriticalNative 2756 private static native int nGetFlags(long paintPtr); 2757 @CriticalNative 2758 private static native void nSetFlags(long paintPtr, int flags); 2759 @CriticalNative 2760 private static native int nGetHinting(long paintPtr); 2761 @CriticalNative 2762 private static native void nSetHinting(long paintPtr, int mode); 2763 @CriticalNative 2764 private static native void nSetAntiAlias(long paintPtr, boolean aa); 2765 @CriticalNative 2766 private static native void nSetLinearText(long paintPtr, boolean linearText); 2767 @CriticalNative 2768 private static native void nSetSubpixelText(long paintPtr, boolean subpixelText); 2769 @CriticalNative 2770 private static native void nSetUnderlineText(long paintPtr, boolean underlineText); 2771 @CriticalNative 2772 private static native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText); 2773 @CriticalNative 2774 private static native void nSetFilterBitmap(long paintPtr, boolean filter); 2775 @CriticalNative 2776 private static native int nGetColor(long paintPtr); 2777 @CriticalNative 2778 private static native void nSetColor(long paintPtr, @ColorInt int color); 2779 @CriticalNative 2780 private static native int nGetAlpha(long paintPtr); 2781 @CriticalNative 2782 private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText); 2783 @CriticalNative 2784 private static native boolean nIsElegantTextHeight(long paintPtr); 2785 @CriticalNative 2786 private static native void nSetElegantTextHeight(long paintPtr, boolean elegant); 2787 @CriticalNative 2788 private static native float nGetTextSize(long paintPtr); 2789 @CriticalNative 2790 private static native float nGetTextScaleX(long paintPtr); 2791 @CriticalNative 2792 private static native void nSetTextScaleX(long paintPtr, float scaleX); 2793 @CriticalNative 2794 private static native float nGetTextSkewX(long paintPtr); 2795 @CriticalNative 2796 private static native void nSetTextSkewX(long paintPtr, float skewX); 2797 @CriticalNative 2798 private static native float nAscent(long paintPtr, long typefacePtr); 2799 @CriticalNative 2800 private static native float nDescent(long paintPtr, long typefacePtr); 2801 @CriticalNative 2802 private static native void nSetTextSize(long paintPtr, float textSize); 2803} 2804