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