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