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