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