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