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