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