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