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