1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics; 18 19 import com.android.ide.common.rendering.api.LayoutLog; 20 import com.android.layoutlib.bridge.Bridge; 21 import com.android.layoutlib.bridge.impl.DelegateManager; 22 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.graphics.FontFamily_Delegate.FontVariant; 27 import android.graphics.Paint.FontMetrics; 28 import android.graphics.Paint.FontMetricsInt; 29 import android.text.TextUtils; 30 31 import java.awt.BasicStroke; 32 import java.awt.Font; 33 import java.awt.Shape; 34 import java.awt.Stroke; 35 import java.awt.Toolkit; 36 import java.awt.geom.AffineTransform; 37 import java.util.Collections; 38 import java.util.List; 39 import java.util.Locale; 40 import java.util.Objects; 41 import java.util.stream.Collectors; 42 import java.util.stream.StreamSupport; 43 44 import libcore.util.NativeAllocationRegistry_Delegate; 45 46 /** 47 * Delegate implementing the native methods of android.graphics.Paint 48 * 49 * Through the layoutlib_create tool, the original native methods of Paint have been replaced 50 * by calls to methods of the same name in this delegate class. 51 * 52 * This class behaves like the original native implementation, but in Java, keeping previously 53 * native data into its own objects and mapping them to int that are sent back and forth between 54 * it and the original Paint class. 55 * 56 * @see DelegateManager 57 * 58 */ 59 public class Paint_Delegate { 60 private static final float DEFAULT_TEXT_SIZE = 20.f; 61 private static final float DEFAULT_TEXT_SCALE_X = 1.f; 62 private static final float DEFAULT_TEXT_SKEW_X = 0.f; 63 64 /** 65 * Class associating a {@link Font} and its {@link java.awt.FontMetrics}. 66 */ 67 /*package*/ static final class FontInfo { 68 final Font mFont; 69 final java.awt.FontMetrics mMetrics; 70 FontInfo(@onNull Font font, @NonNull java.awt.FontMetrics fontMetrics)71 FontInfo(@NonNull Font font, @NonNull java.awt.FontMetrics fontMetrics) { 72 this.mFont = font; 73 this.mMetrics = fontMetrics; 74 } 75 } 76 77 // ---- delegate manager ---- 78 private static final DelegateManager<Paint_Delegate> sManager = 79 new DelegateManager<>(Paint_Delegate.class); 80 private static long sFinalizer = -1; 81 82 // ---- delegate helper data ---- 83 84 // This list can contain null elements. 85 @Nullable 86 private List<FontInfo> mFonts; 87 88 // ---- delegate data ---- 89 private int mFlags; 90 private int mColor; 91 private int mStyle; 92 private int mCap; 93 private int mJoin; 94 private int mTextAlign; 95 private Typeface_Delegate mTypeface; 96 private float mStrokeWidth; 97 private float mStrokeMiter; 98 private float mTextSize; 99 private float mTextScaleX; 100 private float mTextSkewX; 101 private int mHintingMode = Paint.HINTING_ON; 102 private int mStartHyphenEdit; 103 private int mEndHyphenEdit; 104 private float mLetterSpacing; // not used in actual text rendering. 105 private float mWordSpacing; // not used in actual text rendering. 106 // Variant of the font. A paint's variant can only be compact or elegant. 107 private FontVariant mFontVariant = FontVariant.COMPACT; 108 109 private int mPorterDuffMode = Xfermode.DEFAULT; 110 private ColorFilter_Delegate mColorFilter; 111 private Shader_Delegate mShader; 112 private PathEffect_Delegate mPathEffect; 113 private MaskFilter_Delegate mMaskFilter; 114 115 @SuppressWarnings("FieldCanBeLocal") // Used to store the locale for future use 116 private Locale mLocale = Locale.getDefault(); 117 118 // ---- Public Helper methods ---- 119 120 @Nullable getDelegate(long native_paint)121 public static Paint_Delegate getDelegate(long native_paint) { 122 return sManager.getDelegate(native_paint); 123 } 124 125 /** 126 * Returns the list of {@link Font} objects. 127 */ 128 @NonNull getFonts()129 public List<FontInfo> getFonts() { 130 Typeface_Delegate typeface = mTypeface; 131 if (typeface == null) { 132 if (Typeface.sDefaultTypeface == null) { 133 return Collections.emptyList(); 134 } 135 136 typeface = Typeface_Delegate.getDelegate(Typeface.sDefaultTypeface.native_instance); 137 } 138 139 if (mFonts != null) { 140 return mFonts; 141 } 142 143 // Apply an optional transformation for skew and scale 144 AffineTransform affineTransform = mTextScaleX != 1.0 || mTextSkewX != 0 ? 145 new AffineTransform(mTextScaleX, mTextSkewX, 0, 1, 0, 0) : 146 null; 147 148 List<FontInfo> infoList = StreamSupport.stream(typeface.getFonts(mFontVariant).spliterator 149 (), false) 150 .filter(Objects::nonNull) 151 .map(font -> getFontInfo(font, mTextSize, affineTransform)) 152 .collect(Collectors.toList()); 153 mFonts = Collections.unmodifiableList(infoList); 154 155 return mFonts; 156 } 157 isAntiAliased()158 public boolean isAntiAliased() { 159 return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0; 160 } 161 isFilterBitmap()162 public boolean isFilterBitmap() { 163 return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0; 164 } 165 getStyle()166 public int getStyle() { 167 return mStyle; 168 } 169 getColor()170 public int getColor() { 171 return mColor; 172 } 173 getAlpha()174 public int getAlpha() { 175 return mColor >>> 24; 176 } 177 setAlpha(int alpha)178 public void setAlpha(int alpha) { 179 mColor = (alpha << 24) | (mColor & 0x00FFFFFF); 180 } 181 getTextAlign()182 public int getTextAlign() { 183 return mTextAlign; 184 } 185 getStrokeWidth()186 public float getStrokeWidth() { 187 return mStrokeWidth; 188 } 189 190 /** 191 * returns the value of stroke miter needed by the java api. 192 */ getJavaStrokeMiter()193 public float getJavaStrokeMiter() { 194 return mStrokeMiter; 195 } 196 getJavaCap()197 public int getJavaCap() { 198 switch (Paint.sCapArray[mCap]) { 199 case BUTT: 200 return BasicStroke.CAP_BUTT; 201 case ROUND: 202 return BasicStroke.CAP_ROUND; 203 default: 204 case SQUARE: 205 return BasicStroke.CAP_SQUARE; 206 } 207 } 208 getJavaJoin()209 public int getJavaJoin() { 210 switch (Paint.sJoinArray[mJoin]) { 211 default: 212 case MITER: 213 return BasicStroke.JOIN_MITER; 214 case ROUND: 215 return BasicStroke.JOIN_ROUND; 216 case BEVEL: 217 return BasicStroke.JOIN_BEVEL; 218 } 219 } 220 getJavaStroke()221 public Stroke getJavaStroke() { 222 if (mPathEffect != null) { 223 if (mPathEffect.isSupported()) { 224 Stroke stroke = mPathEffect.getStroke(this); 225 assert stroke != null; 226 //noinspection ConstantConditions 227 if (stroke != null) { 228 return stroke; 229 } 230 } else { 231 Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT, 232 mPathEffect.getSupportMessage(), 233 null, null /*data*/); 234 } 235 } 236 237 // if no custom stroke as been set, set the default one. 238 return new BasicStroke( 239 getStrokeWidth(), 240 getJavaCap(), 241 getJavaJoin(), 242 getJavaStrokeMiter()); 243 } 244 245 /** 246 * Returns the {@link PorterDuff.Mode} as an int 247 */ getPorterDuffMode()248 public int getPorterDuffMode() { 249 return mPorterDuffMode; 250 } 251 252 /** 253 * Returns the {@link ColorFilter} delegate or null if none have been set 254 * 255 * @return the delegate or null. 256 */ getColorFilter()257 public ColorFilter_Delegate getColorFilter() { 258 return mColorFilter; 259 } 260 setColorFilter(long colorFilterPtr)261 public void setColorFilter(long colorFilterPtr) { 262 mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr); 263 } 264 setShader(long shaderPtr)265 public void setShader(long shaderPtr) { 266 mShader = Shader_Delegate.getDelegate(shaderPtr); 267 } 268 269 /** 270 * Returns the {@link Shader} delegate or null if none have been set 271 * 272 * @return the delegate or null. 273 */ getShader()274 public Shader_Delegate getShader() { 275 return mShader; 276 } 277 278 /** 279 * Returns the {@link MaskFilter} delegate or null if none have been set 280 * 281 * @return the delegate or null. 282 */ getMaskFilter()283 public MaskFilter_Delegate getMaskFilter() { 284 return mMaskFilter; 285 } 286 287 // ---- native methods ---- 288 289 @LayoutlibDelegate nGetFlags(long nativePaint)290 /*package*/ static int nGetFlags(long nativePaint) { 291 // get the delegate from the native int. 292 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 293 if (delegate == null) { 294 return 0; 295 } 296 297 return delegate.mFlags; 298 } 299 300 301 302 @LayoutlibDelegate nSetFlags(long nativePaint, int flags)303 /*package*/ static void nSetFlags(long nativePaint, int flags) { 304 // get the delegate from the native int. 305 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 306 if (delegate == null) { 307 return; 308 } 309 310 delegate.mFlags = flags; 311 } 312 313 @LayoutlibDelegate nSetFilterBitmap(long nativePaint, boolean filter)314 /*package*/ static void nSetFilterBitmap(long nativePaint, boolean filter) { 315 setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter); 316 } 317 318 @LayoutlibDelegate nGetHinting(long nativePaint)319 /*package*/ static int nGetHinting(long nativePaint) { 320 // get the delegate from the native int. 321 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 322 if (delegate == null) { 323 return Paint.HINTING_ON; 324 } 325 326 return delegate.mHintingMode; 327 } 328 329 @LayoutlibDelegate nSetHinting(long nativePaint, int mode)330 /*package*/ static void nSetHinting(long nativePaint, int mode) { 331 // get the delegate from the native int. 332 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 333 if (delegate == null) { 334 return; 335 } 336 337 delegate.mHintingMode = mode; 338 } 339 340 @LayoutlibDelegate nSetAntiAlias(long nativePaint, boolean aa)341 /*package*/ static void nSetAntiAlias(long nativePaint, boolean aa) { 342 setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa); 343 } 344 345 @LayoutlibDelegate nSetSubpixelText(long nativePaint, boolean subpixelText)346 /*package*/ static void nSetSubpixelText(long nativePaint, 347 boolean subpixelText) { 348 setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText); 349 } 350 351 @LayoutlibDelegate nSetUnderlineText(long nativePaint, boolean underlineText)352 /*package*/ static void nSetUnderlineText(long nativePaint, 353 boolean underlineText) { 354 setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText); 355 } 356 357 @LayoutlibDelegate nSetStrikeThruText(long nativePaint, boolean strikeThruText)358 /*package*/ static void nSetStrikeThruText(long nativePaint, 359 boolean strikeThruText) { 360 setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText); 361 } 362 363 @LayoutlibDelegate nSetFakeBoldText(long nativePaint, boolean fakeBoldText)364 /*package*/ static void nSetFakeBoldText(long nativePaint, 365 boolean fakeBoldText) { 366 setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText); 367 } 368 369 @LayoutlibDelegate nSetDither(long nativePaint, boolean dither)370 /*package*/ static void nSetDither(long nativePaint, boolean dither) { 371 setFlag(nativePaint, Paint.DITHER_FLAG, dither); 372 } 373 374 @LayoutlibDelegate nSetLinearText(long nativePaint, boolean linearText)375 /*package*/ static void nSetLinearText(long nativePaint, boolean linearText) { 376 setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText); 377 } 378 379 @LayoutlibDelegate nSetColor(long paintPtr, long colorSpaceHandle, long color)380 /*package*/ static void nSetColor(long paintPtr, long colorSpaceHandle, long color) { 381 Paint_Delegate delegate = sManager.getDelegate(paintPtr); 382 if (delegate == null) { 383 return; 384 } 385 386 delegate.mColor = Color.toArgb(color); 387 } 388 389 @LayoutlibDelegate nSetColor(long paintPtr, int color)390 /*package*/ static void nSetColor(long paintPtr, int color) { 391 Paint_Delegate delegate = sManager.getDelegate(paintPtr); 392 if (delegate == null) { 393 return; 394 } 395 396 delegate.mColor = color; 397 } 398 399 @LayoutlibDelegate nSetAlpha(long nativePaint, int a)400 /*package*/ static void nSetAlpha(long nativePaint, int a) { 401 // get the delegate from the native int. 402 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 403 if (delegate == null) { 404 return; 405 } 406 407 delegate.setAlpha(a); 408 } 409 410 @LayoutlibDelegate nGetStrokeWidth(long nativePaint)411 /*package*/ static float nGetStrokeWidth(long nativePaint) { 412 // get the delegate from the native int. 413 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 414 if (delegate == null) { 415 return 1.f; 416 } 417 418 return delegate.mStrokeWidth; 419 } 420 421 @LayoutlibDelegate nSetStrokeWidth(long nativePaint, float width)422 /*package*/ static void nSetStrokeWidth(long nativePaint, float width) { 423 // get the delegate from the native int. 424 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 425 if (delegate == null) { 426 return; 427 } 428 429 delegate.mStrokeWidth = width; 430 } 431 432 @LayoutlibDelegate nGetStrokeMiter(long nativePaint)433 /*package*/ static float nGetStrokeMiter(long nativePaint) { 434 // get the delegate from the native int. 435 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 436 if (delegate == null) { 437 return 1.f; 438 } 439 440 return delegate.mStrokeMiter; 441 } 442 443 @LayoutlibDelegate nSetStrokeMiter(long nativePaint, float miter)444 /*package*/ static void nSetStrokeMiter(long nativePaint, float miter) { 445 // get the delegate from the native int. 446 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 447 if (delegate == null) { 448 return; 449 } 450 451 delegate.mStrokeMiter = miter; 452 } 453 454 @LayoutlibDelegate nSetShadowLayer(long paintPtr, float radius, float dx, float dy, long colorSpaceHandle, long shadowColor)455 /*package*/ static void nSetShadowLayer(long paintPtr, 456 float radius, float dx, float dy, long colorSpaceHandle, 457 long shadowColor) { 458 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 459 "Paint.setShadowLayer is not supported.", null, null /*data*/); 460 } 461 462 @LayoutlibDelegate nHasShadowLayer(long paint)463 /*package*/ static boolean nHasShadowLayer(long paint) { 464 // FIXME 465 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 466 "Paint.hasShadowLayer is not supported.", null, null /*data*/); 467 return false; 468 } 469 470 @LayoutlibDelegate nIsElegantTextHeight(long nativePaint)471 /*package*/ static boolean nIsElegantTextHeight(long nativePaint) { 472 // get the delegate from the native int. 473 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 474 return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT; 475 } 476 477 @LayoutlibDelegate nSetElegantTextHeight(long nativePaint, boolean elegant)478 /*package*/ static void nSetElegantTextHeight(long nativePaint, 479 boolean elegant) { 480 // get the delegate from the native int. 481 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 482 if (delegate == null) { 483 return; 484 } 485 486 delegate.mFontVariant = elegant ? FontVariant.ELEGANT : FontVariant.COMPACT; 487 } 488 489 @LayoutlibDelegate nGetTextSize(long nativePaint)490 /*package*/ static float nGetTextSize(long nativePaint) { 491 // get the delegate from the native int. 492 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 493 if (delegate == null) { 494 return 1.f; 495 } 496 497 return delegate.mTextSize; 498 } 499 500 @LayoutlibDelegate nSetTextSize(long nativePaint, float textSize)501 /*package*/ static void nSetTextSize(long nativePaint, float textSize) { 502 // get the delegate from the native int. 503 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 504 if (delegate == null) { 505 return; 506 } 507 508 if (delegate.mTextSize != textSize) { 509 delegate.mTextSize = textSize; 510 delegate.invalidateFonts(); 511 } 512 } 513 514 @LayoutlibDelegate nGetTextScaleX(long nativePaint)515 /*package*/ static float nGetTextScaleX(long nativePaint) { 516 // get the delegate from the native int. 517 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 518 if (delegate == null) { 519 return 1.f; 520 } 521 522 return delegate.mTextScaleX; 523 } 524 525 @LayoutlibDelegate nSetTextScaleX(long nativePaint, float scaleX)526 /*package*/ static void nSetTextScaleX(long nativePaint, float scaleX) { 527 // get the delegate from the native int. 528 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 529 if (delegate == null) { 530 return; 531 } 532 533 if (delegate.mTextScaleX != scaleX) { 534 delegate.mTextScaleX = scaleX; 535 delegate.invalidateFonts(); 536 } 537 } 538 539 @LayoutlibDelegate nGetTextSkewX(long nativePaint)540 /*package*/ static float nGetTextSkewX(long nativePaint) { 541 // get the delegate from the native int. 542 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 543 if (delegate == null) { 544 return 1.f; 545 } 546 547 return delegate.mTextSkewX; 548 } 549 550 @LayoutlibDelegate nSetTextSkewX(long nativePaint, float skewX)551 /*package*/ static void nSetTextSkewX(long nativePaint, float skewX) { 552 // get the delegate from the native int. 553 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 554 if (delegate == null) { 555 return; 556 } 557 558 if (delegate.mTextSkewX != skewX) { 559 delegate.mTextSkewX = skewX; 560 delegate.invalidateFonts(); 561 } 562 } 563 564 @LayoutlibDelegate nAscent(long nativePaint)565 /*package*/ static float nAscent(long nativePaint) { 566 // get the delegate 567 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 568 if (delegate == null) { 569 return 0; 570 } 571 572 List<FontInfo> fonts = delegate.getFonts(); 573 if (fonts.size() > 0) { 574 java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics; 575 // Android expects negative ascent so we invert the value from Java. 576 return - javaMetrics.getAscent(); 577 } 578 579 return 0; 580 } 581 582 @LayoutlibDelegate nDescent(long nativePaint)583 /*package*/ static float nDescent(long nativePaint) { 584 // get the delegate 585 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 586 if (delegate == null) { 587 return 0; 588 } 589 590 List<FontInfo> fonts = delegate.getFonts(); 591 if (fonts.size() > 0) { 592 java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics; 593 return javaMetrics.getDescent(); 594 } 595 596 return 0; 597 598 } 599 600 @LayoutlibDelegate nGetFontMetrics(long nativePaint, FontMetrics metrics)601 /*package*/ static float nGetFontMetrics(long nativePaint, 602 FontMetrics metrics) { 603 // get the delegate 604 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 605 if (delegate == null) { 606 return 0; 607 } 608 609 return delegate.getFontMetrics(metrics); 610 } 611 612 @LayoutlibDelegate nGetFontMetricsInt(long nativePaint, FontMetricsInt fmi)613 /*package*/ static int nGetFontMetricsInt(long nativePaint, FontMetricsInt fmi) { 614 // get the delegate 615 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 616 if (delegate == null) { 617 return 0; 618 } 619 620 List<FontInfo> fonts = delegate.getFonts(); 621 if (fonts.size() > 0) { 622 java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics; 623 if (fmi != null) { 624 // Android expects negative ascent so we invert the value from Java. 625 fmi.top = (int)(- javaMetrics.getMaxAscent() * 1.15); 626 fmi.ascent = - javaMetrics.getAscent(); 627 fmi.descent = javaMetrics.getDescent(); 628 fmi.bottom = (int)(javaMetrics.getMaxDescent() * 1.15); 629 fmi.leading = javaMetrics.getLeading(); 630 } 631 632 return javaMetrics.getHeight(); 633 } 634 635 return 0; 636 } 637 638 @LayoutlibDelegate nBreakText(long nativePaint, char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth)639 /*package*/ static int nBreakText(long nativePaint, char[] text, 640 int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) { 641 642 // get the delegate 643 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 644 if (delegate == null) { 645 return 0; 646 } 647 648 int inc = count > 0 ? 1 : -1; 649 650 int measureIndex = 0; 651 for (int i = index; i != index + count; i += inc, measureIndex++) { 652 int start, end; 653 if (i < index) { 654 start = i; 655 end = index; 656 } else { 657 start = index; 658 end = i; 659 } 660 661 // measure from start to end 662 RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags); 663 float res = bounds.right - bounds.left; 664 665 if (measuredWidth != null) { 666 measuredWidth[measureIndex] = res; 667 } 668 669 if (res > maxWidth) { 670 // we should not return this char index, but since it's 0-based 671 // and we need to return a count, we simply return measureIndex; 672 return measureIndex; 673 } 674 675 } 676 677 return measureIndex; 678 } 679 680 @LayoutlibDelegate nBreakText(long nativePaint, String text, boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth)681 /*package*/ static int nBreakText(long nativePaint, String text, boolean measureForwards, 682 float maxWidth, int bidiFlags, float[] measuredWidth) { 683 return nBreakText(nativePaint, text.toCharArray(), 0, text.length(), 684 maxWidth, bidiFlags, measuredWidth); 685 } 686 687 @LayoutlibDelegate nInit()688 /*package*/ static long nInit() { 689 Paint_Delegate newDelegate = new Paint_Delegate(); 690 return sManager.addNewDelegate(newDelegate); 691 } 692 693 @LayoutlibDelegate nInitWithPaint(long paint)694 /*package*/ static long nInitWithPaint(long paint) { 695 // get the delegate from the native int. 696 Paint_Delegate delegate = sManager.getDelegate(paint); 697 if (delegate == null) { 698 return 0; 699 } 700 701 Paint_Delegate newDelegate = new Paint_Delegate(delegate); 702 return sManager.addNewDelegate(newDelegate); 703 } 704 705 @LayoutlibDelegate nReset(long native_object)706 /*package*/ static void nReset(long native_object) { 707 // get the delegate from the native int. 708 Paint_Delegate delegate = sManager.getDelegate(native_object); 709 if (delegate == null) { 710 return; 711 } 712 713 delegate.reset(); 714 } 715 716 @LayoutlibDelegate nSet(long native_dst, long native_src)717 /*package*/ static void nSet(long native_dst, long native_src) { 718 // get the delegate from the native int. 719 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst); 720 if (delegate_dst == null) { 721 return; 722 } 723 724 // get the delegate from the native int. 725 Paint_Delegate delegate_src = sManager.getDelegate(native_src); 726 if (delegate_src == null) { 727 return; 728 } 729 730 delegate_dst.set(delegate_src); 731 } 732 733 @LayoutlibDelegate nGetStyle(long native_object)734 /*package*/ static int nGetStyle(long native_object) { 735 // get the delegate from the native int. 736 Paint_Delegate delegate = sManager.getDelegate(native_object); 737 if (delegate == null) { 738 return 0; 739 } 740 741 return delegate.mStyle; 742 } 743 744 @LayoutlibDelegate nSetStyle(long native_object, int style)745 /*package*/ static void nSetStyle(long native_object, int style) { 746 // get the delegate from the native int. 747 Paint_Delegate delegate = sManager.getDelegate(native_object); 748 if (delegate == null) { 749 return; 750 } 751 752 delegate.mStyle = style; 753 } 754 755 @LayoutlibDelegate nGetStrokeCap(long native_object)756 /*package*/ static int nGetStrokeCap(long native_object) { 757 // get the delegate from the native int. 758 Paint_Delegate delegate = sManager.getDelegate(native_object); 759 if (delegate == null) { 760 return 0; 761 } 762 763 return delegate.mCap; 764 } 765 766 @LayoutlibDelegate nSetStrokeCap(long native_object, int cap)767 /*package*/ static void nSetStrokeCap(long native_object, int cap) { 768 // get the delegate from the native int. 769 Paint_Delegate delegate = sManager.getDelegate(native_object); 770 if (delegate == null) { 771 return; 772 } 773 774 delegate.mCap = cap; 775 } 776 777 @LayoutlibDelegate nGetStrokeJoin(long native_object)778 /*package*/ static int nGetStrokeJoin(long native_object) { 779 // get the delegate from the native int. 780 Paint_Delegate delegate = sManager.getDelegate(native_object); 781 if (delegate == null) { 782 return 0; 783 } 784 785 return delegate.mJoin; 786 } 787 788 @LayoutlibDelegate nSetStrokeJoin(long native_object, int join)789 /*package*/ static void nSetStrokeJoin(long native_object, int join) { 790 // get the delegate from the native int. 791 Paint_Delegate delegate = sManager.getDelegate(native_object); 792 if (delegate == null) { 793 return; 794 } 795 796 delegate.mJoin = join; 797 } 798 799 @LayoutlibDelegate nGetFillPath(long native_object, long src, long dst)800 /*package*/ static boolean nGetFillPath(long native_object, long src, long dst) { 801 Paint_Delegate paint = sManager.getDelegate(native_object); 802 if (paint == null) { 803 return false; 804 } 805 806 Path_Delegate srcPath = Path_Delegate.getDelegate(src); 807 if (srcPath == null) { 808 return true; 809 } 810 811 Path_Delegate dstPath = Path_Delegate.getDelegate(dst); 812 if (dstPath == null) { 813 return true; 814 } 815 816 Stroke stroke = paint.getJavaStroke(); 817 Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape()); 818 819 dstPath.setJavaShape(strokeShape); 820 821 // FIXME figure out the return value? 822 return true; 823 } 824 825 @LayoutlibDelegate nSetShader(long native_object, long shader)826 /*package*/ static long nSetShader(long native_object, long shader) { 827 // get the delegate from the native int. 828 Paint_Delegate delegate = sManager.getDelegate(native_object); 829 if (delegate == null) { 830 return shader; 831 } 832 833 delegate.mShader = Shader_Delegate.getDelegate(shader); 834 835 return shader; 836 } 837 838 @LayoutlibDelegate nSetColorFilter(long native_object, long filter)839 /*package*/ static long nSetColorFilter(long native_object, long filter) { 840 // get the delegate from the native int. 841 Paint_Delegate delegate = sManager.getDelegate(native_object); 842 if (delegate == null) { 843 return filter; 844 } 845 846 delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter); 847 848 // Log warning if it's not supported. 849 if (delegate.mColorFilter != null && !delegate.mColorFilter.isSupported()) { 850 Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER, 851 delegate.mColorFilter.getSupportMessage(), null, null /*data*/); 852 } 853 854 return filter; 855 } 856 857 @LayoutlibDelegate nSetXfermode(long native_object, int xfermode)858 /*package*/ static void nSetXfermode(long native_object, int xfermode) { 859 Paint_Delegate delegate = sManager.getDelegate(native_object); 860 if (delegate == null) { 861 return; 862 } 863 delegate.mPorterDuffMode = xfermode; 864 } 865 866 @LayoutlibDelegate nSetPathEffect(long native_object, long effect)867 /*package*/ static long nSetPathEffect(long native_object, long effect) { 868 // get the delegate from the native int. 869 Paint_Delegate delegate = sManager.getDelegate(native_object); 870 if (delegate == null) { 871 return effect; 872 } 873 874 delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect); 875 876 return effect; 877 } 878 879 @LayoutlibDelegate nSetMaskFilter(long native_object, long maskfilter)880 /*package*/ static long nSetMaskFilter(long native_object, long maskfilter) { 881 // get the delegate from the native int. 882 Paint_Delegate delegate = sManager.getDelegate(native_object); 883 if (delegate == null) { 884 return maskfilter; 885 } 886 887 delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter); 888 889 // since none of those are supported, display a fidelity warning right away 890 if (delegate.mMaskFilter != null && !delegate.mMaskFilter.isSupported()) { 891 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER, 892 delegate.mMaskFilter.getSupportMessage(), null, null /*data*/); 893 } 894 895 return maskfilter; 896 } 897 898 @LayoutlibDelegate nSetTypeface(long native_object, long typeface)899 /*package*/ static void nSetTypeface(long native_object, long typeface) { 900 // get the delegate from the native int. 901 Paint_Delegate delegate = sManager.getDelegate(native_object); 902 if (delegate == null) { 903 return; 904 } 905 906 Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface); 907 if (delegate.mTypeface != typefaceDelegate) { 908 delegate.mTypeface = typefaceDelegate; 909 delegate.invalidateFonts(); 910 } 911 } 912 913 @LayoutlibDelegate nGetTextAlign(long native_object)914 /*package*/ static int nGetTextAlign(long native_object) { 915 // get the delegate from the native int. 916 Paint_Delegate delegate = sManager.getDelegate(native_object); 917 if (delegate == null) { 918 return 0; 919 } 920 921 return delegate.mTextAlign; 922 } 923 924 @LayoutlibDelegate nSetTextAlign(long native_object, int align)925 /*package*/ static void nSetTextAlign(long native_object, int align) { 926 // get the delegate from the native int. 927 Paint_Delegate delegate = sManager.getDelegate(native_object); 928 if (delegate == null) { 929 return; 930 } 931 932 delegate.mTextAlign = align; 933 } 934 935 @LayoutlibDelegate nSetTextLocales(long native_object, String locale)936 /*package*/ static int nSetTextLocales(long native_object, String locale) { 937 // get the delegate from the native int. 938 Paint_Delegate delegate = sManager.getDelegate(native_object); 939 if (delegate == null) { 940 return 0; 941 } 942 943 delegate.setTextLocale(locale); 944 return 0; 945 } 946 947 @LayoutlibDelegate nSetTextLocalesByMinikinLocaleListId(long paintPtr, int mMinikinLangListId)948 /*package*/ static void nSetTextLocalesByMinikinLocaleListId(long paintPtr, 949 int mMinikinLangListId) { 950 // FIXME 951 } 952 953 @LayoutlibDelegate nGetTextAdvances(long native_object, char[] text, int index, int count, int contextIndex, int contextCount, int bidiFlags, float[] advances, int advancesIndex)954 /*package*/ static float nGetTextAdvances(long native_object, char[] text, int index, 955 int count, int contextIndex, int contextCount, 956 int bidiFlags, float[] advances, int advancesIndex) { 957 958 if (advances != null) 959 for (int i = advancesIndex; i< advancesIndex+count; i++) 960 advances[i]=0; 961 // get the delegate from the native int. 962 Paint_Delegate delegate = sManager.getDelegate(native_object); 963 if (delegate == null) { 964 return 0.f; 965 } 966 967 RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, bidiFlags); 968 return bounds.right - bounds.left; 969 } 970 971 @LayoutlibDelegate nGetTextAdvances(long native_object, String text, int start, int end, int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex)972 /*package*/ static float nGetTextAdvances(long native_object, String text, int start, int end, 973 int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex) { 974 // FIXME: support contextStart and contextEnd 975 int count = end - start; 976 char[] buffer = TemporaryBuffer.obtain(count); 977 TextUtils.getChars(text, start, end, buffer, 0); 978 979 return nGetTextAdvances(native_object, buffer, 0, count, 980 contextStart, contextEnd - contextStart, bidiFlags, advances, advancesIndex); 981 } 982 983 @LayoutlibDelegate nGetTextRunCursor(Paint paint, long native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)984 /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, char[] text, 985 int contextStart, int contextLength, int flags, int offset, int cursorOpt) { 986 // FIXME 987 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 988 "Paint.getTextRunCursor is not supported.", null, null /*data*/); 989 return 0; 990 } 991 992 @LayoutlibDelegate nGetTextRunCursor(Paint paint, long native_object, String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)993 /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, String text, 994 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { 995 // FIXME 996 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 997 "Paint.getTextRunCursor is not supported.", null, null /*data*/); 998 return 0; 999 } 1000 1001 @LayoutlibDelegate nGetTextPath(long native_object, int bidiFlags, char[] text, int index, int count, float x, float y, long path)1002 /*package*/ static void nGetTextPath(long native_object, int bidiFlags, char[] text, 1003 int index, int count, float x, float y, long path) { 1004 // FIXME 1005 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1006 "Paint.getTextPath is not supported.", null, null /*data*/); 1007 } 1008 1009 @LayoutlibDelegate nGetTextPath(long native_object, int bidiFlags, String text, int start, int end, float x, float y, long path)1010 /*package*/ static void nGetTextPath(long native_object, int bidiFlags, String text, int start, 1011 int end, float x, float y, long path) { 1012 // FIXME 1013 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1014 "Paint.getTextPath is not supported.", null, null /*data*/); 1015 } 1016 1017 @LayoutlibDelegate nGetStringBounds(long nativePaint, String text, int start, int end, int bidiFlags, Rect bounds)1018 /*package*/ static void nGetStringBounds(long nativePaint, String text, int start, int end, 1019 int bidiFlags, Rect bounds) { 1020 nGetCharArrayBounds(nativePaint, text.toCharArray(), start, 1021 end - start, bidiFlags, bounds); 1022 } 1023 1024 @LayoutlibDelegate nGetCharArrayBounds(long nativePaint, char[] text, int index, int count, int bidiFlags, Rect bounds)1025 public static void nGetCharArrayBounds(long nativePaint, char[] text, int index, 1026 int count, int bidiFlags, Rect bounds) { 1027 1028 // get the delegate from the native int. 1029 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1030 if (delegate == null) { 1031 return; 1032 } 1033 1034 delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds); 1035 } 1036 1037 @LayoutlibDelegate nGetNativeFinalizer()1038 /*package*/ static long nGetNativeFinalizer() { 1039 synchronized (Paint_Delegate.class) { 1040 if (sFinalizer == -1) { 1041 sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer( 1042 sManager::removeJavaReferenceFor); 1043 } 1044 } 1045 return sFinalizer; 1046 } 1047 1048 @LayoutlibDelegate nGetLetterSpacing(long nativePaint)1049 /*package*/ static float nGetLetterSpacing(long nativePaint) { 1050 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1051 if (delegate == null) { 1052 return 0; 1053 } 1054 return delegate.mLetterSpacing; 1055 } 1056 1057 @LayoutlibDelegate nSetLetterSpacing(long nativePaint, float letterSpacing)1058 /*package*/ static void nSetLetterSpacing(long nativePaint, float letterSpacing) { 1059 Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, 1060 "Paint.setLetterSpacing() not supported.", null, null); 1061 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1062 if (delegate == null) { 1063 return; 1064 } 1065 delegate.mLetterSpacing = letterSpacing; 1066 } 1067 1068 @LayoutlibDelegate nGetWordSpacing(long nativePaint)1069 /*package*/ static float nGetWordSpacing(long nativePaint) { 1070 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1071 if (delegate == null) { 1072 return 0; 1073 } 1074 return delegate.mWordSpacing; 1075 } 1076 1077 @LayoutlibDelegate nSetWordSpacing(long nativePaint, float wordSpacing)1078 /*package*/ static void nSetWordSpacing(long nativePaint, float wordSpacing) { 1079 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1080 if (delegate == null) { 1081 return; 1082 } 1083 delegate.mWordSpacing = wordSpacing; 1084 } 1085 1086 @LayoutlibDelegate nSetFontFeatureSettings(long nativePaint, String settings)1087 /*package*/ static void nSetFontFeatureSettings(long nativePaint, String settings) { 1088 Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, 1089 "Paint.setFontFeatureSettings() not supported.", null, null); 1090 } 1091 1092 @LayoutlibDelegate nGetStartHyphenEdit(long nativePaint)1093 /*package*/ static int nGetStartHyphenEdit(long nativePaint) { 1094 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1095 if (delegate == null) { 1096 return 0; 1097 } 1098 return delegate.mStartHyphenEdit; 1099 } 1100 1101 @LayoutlibDelegate nSetStartHyphenEdit(long nativePaint, int hyphen)1102 /*package*/ static void nSetStartHyphenEdit(long nativePaint, int hyphen) { 1103 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1104 if (delegate == null) { 1105 return; 1106 } 1107 delegate.mStartHyphenEdit = hyphen; 1108 } 1109 1110 @LayoutlibDelegate nGetEndHyphenEdit(long nativePaint)1111 /*package*/ static int nGetEndHyphenEdit(long nativePaint) { 1112 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1113 if (delegate == null) { 1114 return 0; 1115 } 1116 return delegate.mEndHyphenEdit; 1117 } 1118 1119 @LayoutlibDelegate nSetEndHyphenEdit(long nativePaint, int hyphen)1120 /*package*/ static void nSetEndHyphenEdit(long nativePaint, int hyphen) { 1121 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1122 if (delegate == null) { 1123 return; 1124 } 1125 delegate.mEndHyphenEdit = hyphen; 1126 } 1127 1128 @LayoutlibDelegate nHasGlyph(long nativePaint, int bidiFlags, String string)1129 /*package*/ static boolean nHasGlyph(long nativePaint, int bidiFlags, String string) { 1130 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1131 if (delegate == null) { 1132 return false; 1133 } 1134 if (string.length() == 0) { 1135 return false; 1136 } 1137 if (string.length() > 1) { 1138 Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, 1139 "Paint.hasGlyph() is not supported for ligatures.", null, null); 1140 return false; 1141 } 1142 1143 char c = string.charAt(0); 1144 for (Font font : delegate.mTypeface.getFonts(delegate.mFontVariant)) { 1145 if (font.canDisplay(c)) { 1146 return true; 1147 } 1148 } 1149 return false; 1150 } 1151 1152 1153 @LayoutlibDelegate nGetRunAdvance(long nativePaint, @NonNull char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)1154 /*package*/ static float nGetRunAdvance(long nativePaint, @NonNull char[] text, int start, 1155 int end, int contextStart, int contextEnd, 1156 boolean isRtl, int offset) { 1157 int count = end - start; 1158 float[] advances = new float[count]; 1159 int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR; 1160 nGetTextAdvances(nativePaint, text, start, count, contextStart, 1161 contextEnd - contextStart, bidiFlags, advances, 0); 1162 int startOffset = offset - start; // offset from start. 1163 float sum = 0; 1164 for (int i = 0; i < startOffset; i++) { 1165 sum += advances[i]; 1166 } 1167 return sum; 1168 } 1169 1170 @LayoutlibDelegate nGetOffsetForAdvance(long nativePaint, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)1171 /*package*/ static int nGetOffsetForAdvance(long nativePaint, char[] text, int start, 1172 int end, int contextStart, int contextEnd, boolean isRtl, float advance) { 1173 int count = end - start; 1174 float[] advances = new float[count]; 1175 int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR; 1176 nGetTextAdvances(nativePaint, text, start, count, contextStart, 1177 contextEnd - contextStart, bidiFlags, advances, 0); 1178 float sum = 0; 1179 int i; 1180 for (i = 0; i < count && sum < advance; i++) { 1181 sum += advances[i]; 1182 } 1183 float distanceToI = sum - advance; 1184 float distanceToIMinus1 = advance - (sum - advances[i]); 1185 return distanceToI > distanceToIMinus1 ? i : i - 1; 1186 } 1187 1188 @LayoutlibDelegate nGetUnderlinePosition(long paintPtr)1189 /*package*/ static float nGetUnderlinePosition(long paintPtr) { 1190 return (1.0f / 9.0f) * nGetTextSize(paintPtr); 1191 } 1192 1193 @LayoutlibDelegate nGetUnderlineThickness(long paintPtr)1194 /*package*/ static float nGetUnderlineThickness(long paintPtr) { 1195 return (1.0f / 18.0f) * nGetTextSize(paintPtr); 1196 } 1197 1198 @LayoutlibDelegate nGetStrikeThruPosition(long paintPtr)1199 /*package*/ static float nGetStrikeThruPosition(long paintPtr) { 1200 return (-79.0f / 252.0f) * nGetTextSize(paintPtr); 1201 } 1202 1203 @LayoutlibDelegate nGetStrikeThruThickness(long paintPtr)1204 /*package*/ static float nGetStrikeThruThickness(long paintPtr) { 1205 return (1.0f / 18.0f) * nGetTextSize(paintPtr); 1206 } 1207 1208 @LayoutlibDelegate nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr)1209 /*package*/ static boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr) { 1210 return leftPaintPtr == rightPaintPtr; 1211 } 1212 1213 // ---- Private delegate/helper methods ---- 1214 Paint_Delegate()1215 /*package*/ Paint_Delegate() { 1216 reset(); 1217 } 1218 Paint_Delegate(Paint_Delegate paint)1219 private Paint_Delegate(Paint_Delegate paint) { 1220 set(paint); 1221 } 1222 set(Paint_Delegate paint)1223 private void set(Paint_Delegate paint) { 1224 mFlags = paint.mFlags; 1225 mColor = paint.mColor; 1226 mStyle = paint.mStyle; 1227 mCap = paint.mCap; 1228 mJoin = paint.mJoin; 1229 mTextAlign = paint.mTextAlign; 1230 1231 if (mTypeface != paint.mTypeface) { 1232 mTypeface = paint.mTypeface; 1233 invalidateFonts(); 1234 } 1235 1236 if (mTextSize != paint.mTextSize) { 1237 mTextSize = paint.mTextSize; 1238 invalidateFonts(); 1239 } 1240 1241 if (mTextScaleX != paint.mTextScaleX) { 1242 mTextScaleX = paint.mTextScaleX; 1243 invalidateFonts(); 1244 } 1245 1246 if (mTextSkewX != paint.mTextSkewX) { 1247 mTextSkewX = paint.mTextSkewX; 1248 invalidateFonts(); 1249 } 1250 1251 mStrokeWidth = paint.mStrokeWidth; 1252 mStrokeMiter = paint.mStrokeMiter; 1253 mPorterDuffMode = paint.mPorterDuffMode; 1254 mColorFilter = paint.mColorFilter; 1255 mShader = paint.mShader; 1256 mPathEffect = paint.mPathEffect; 1257 mMaskFilter = paint.mMaskFilter; 1258 mHintingMode = paint.mHintingMode; 1259 } 1260 reset()1261 private void reset() { 1262 Typeface_Delegate defaultTypeface = 1263 Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance); 1264 1265 mFlags = Paint.HIDDEN_DEFAULT_PAINT_FLAGS; 1266 mColor = 0xFF000000; 1267 mStyle = Paint.Style.FILL.nativeInt; 1268 mCap = Paint.Cap.BUTT.nativeInt; 1269 mJoin = Paint.Join.MITER.nativeInt; 1270 mTextAlign = 0; 1271 1272 if (mTypeface != defaultTypeface) { 1273 mTypeface = defaultTypeface; 1274 invalidateFonts(); 1275 } 1276 1277 mStrokeWidth = 1.f; 1278 mStrokeMiter = 4.f; 1279 1280 if (mTextSize != DEFAULT_TEXT_SIZE) { 1281 mTextSize = DEFAULT_TEXT_SIZE; 1282 invalidateFonts(); 1283 } 1284 1285 if (mTextScaleX != DEFAULT_TEXT_SCALE_X) { 1286 mTextScaleX = DEFAULT_TEXT_SCALE_X; 1287 invalidateFonts(); 1288 } 1289 1290 if (mTextSkewX != DEFAULT_TEXT_SKEW_X) { 1291 mTextSkewX = DEFAULT_TEXT_SKEW_X; 1292 invalidateFonts(); 1293 } 1294 1295 mPorterDuffMode = Xfermode.DEFAULT; 1296 mColorFilter = null; 1297 mShader = null; 1298 mPathEffect = null; 1299 mMaskFilter = null; 1300 mHintingMode = Paint.HINTING_ON; 1301 } 1302 invalidateFonts()1303 private void invalidateFonts() { 1304 mFonts = null; 1305 } 1306 1307 @Nullable getFontInfo(@ullable Font font, float textSize, @Nullable AffineTransform transform)1308 private static FontInfo getFontInfo(@Nullable Font font, float textSize, 1309 @Nullable AffineTransform transform) { 1310 if (font == null) { 1311 return null; 1312 } 1313 1314 Font transformedFont = font.deriveFont(textSize); 1315 if (transform != null) { 1316 // TODO: support skew 1317 transformedFont = transformedFont.deriveFont(transform); 1318 } 1319 1320 // The metrics here don't have anti-aliasing set. 1321 return new FontInfo(transformedFont, 1322 Toolkit.getDefaultToolkit().getFontMetrics(transformedFont)); 1323 } 1324 measureText(char[] text, int index, int count, float[] advances, int advancesIndex, int bidiFlags)1325 /*package*/ RectF measureText(char[] text, int index, int count, float[] advances, 1326 int advancesIndex, int bidiFlags) { 1327 return new BidiRenderer(null, this, text) 1328 .renderText(index, index + count, bidiFlags, advances, advancesIndex, false); 1329 } 1330 measureText(char[] text, int index, int count, float[] advances, int advancesIndex, boolean isRtl)1331 /*package*/ RectF measureText(char[] text, int index, int count, float[] advances, 1332 int advancesIndex, boolean isRtl) { 1333 return new BidiRenderer(null, this, text) 1334 .renderText(index, index + count, isRtl, advances, advancesIndex, false); 1335 } 1336 getFontMetrics(FontMetrics metrics)1337 private float getFontMetrics(FontMetrics metrics) { 1338 List<FontInfo> fonts = getFonts(); 1339 if (fonts.size() > 0) { 1340 java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics; 1341 if (metrics != null) { 1342 // Android expects negative ascent so we invert the value from Java. 1343 metrics.top = - javaMetrics.getMaxAscent(); 1344 metrics.ascent = - javaMetrics.getAscent(); 1345 metrics.descent = javaMetrics.getDescent(); 1346 metrics.bottom = javaMetrics.getMaxDescent(); 1347 metrics.leading = javaMetrics.getLeading(); 1348 } 1349 1350 return javaMetrics.getHeight(); 1351 } 1352 1353 return 0; 1354 } 1355 setTextLocale(String locale)1356 private void setTextLocale(String locale) { 1357 mLocale = new Locale(locale); 1358 } 1359 setFlag(long nativePaint, int flagMask, boolean flagValue)1360 private static void setFlag(long nativePaint, int flagMask, boolean flagValue) { 1361 // get the delegate from the native int. 1362 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1363 if (delegate == null) { 1364 return; 1365 } 1366 1367 if (flagValue) { 1368 delegate.mFlags |= flagMask; 1369 } else { 1370 delegate.mFlags &= ~flagMask; 1371 } 1372 } 1373 } 1374