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