Paint_Delegate.java revision 6dac0d4b7c55da32cb5deb9b589b1acb43cb536d
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 17package android.graphics; 18 19import com.android.ide.common.rendering.api.LayoutLog; 20import com.android.layoutlib.bridge.Bridge; 21import com.android.layoutlib.bridge.impl.DelegateManager; 22import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 23 24import android.annotation.NonNull; 25import android.annotation.Nullable; 26import android.graphics.FontFamily_Delegate.FontVariant; 27import android.graphics.Paint.FontMetrics; 28import android.graphics.Paint.FontMetricsInt; 29import android.text.TextUtils; 30 31import java.awt.BasicStroke; 32import java.awt.Font; 33import java.awt.Shape; 34import java.awt.Stroke; 35import java.awt.Toolkit; 36import java.awt.geom.AffineTransform; 37import java.util.ArrayList; 38import java.util.Collections; 39import java.util.List; 40import 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 */ 55public 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 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 */ 115 public List<FontInfo> getFonts() { 116 return mFonts; 117 } 118 119 public boolean isAntiAliased() { 120 return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0; 121 } 122 123 public boolean isFilterBitmap() { 124 return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0; 125 } 126 127 public int getStyle() { 128 return mStyle; 129 } 130 131 public int getColor() { 132 return mColor; 133 } 134 135 public int getAlpha() { 136 return mColor >>> 24; 137 } 138 139 public void setAlpha(int alpha) { 140 mColor = (alpha << 24) | (mColor & 0x00FFFFFF); 141 } 142 143 public int getTextAlign() { 144 return mTextAlign; 145 } 146 147 public float getStrokeWidth() { 148 return mStrokeWidth; 149 } 150 151 /** 152 * returns the value of stroke miter needed by the java api. 153 */ 154 public float getJavaStrokeMiter() { 155 float miter = mStrokeMiter * mStrokeWidth; 156 if (miter < 1.f) { 157 miter = 1.f; 158 } 159 return miter; 160 } 161 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 250 public Rasterizer_Delegate getRasterizer() { 251 return mRasterizer; 252 } 253 254 // ---- native methods ---- 255 256 @LayoutlibDelegate 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 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 281 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) { 282 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter); 283 } 284 285 @LayoutlibDelegate 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 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 308 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) { 309 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa); 310 } 311 312 @LayoutlibDelegate 313 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) { 314 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText); 315 } 316 317 @LayoutlibDelegate 318 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) { 319 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText); 320 } 321 322 @LayoutlibDelegate 323 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) { 324 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText); 325 } 326 327 @LayoutlibDelegate 328 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) { 329 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText); 330 } 331 332 @LayoutlibDelegate 333 /*package*/ static void setDither(Paint thisPaint, boolean dither) { 334 setFlag(thisPaint, Paint.DITHER_FLAG, dither); 335 } 336 337 @LayoutlibDelegate 338 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) { 339 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText); 340 } 341 342 @LayoutlibDelegate 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 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 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 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 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 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 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 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 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 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 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 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 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 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 if (delegate.mTextSize != textSize) { 484 delegate.mTextSize = textSize; 485 delegate.updateFontObject(); 486 } 487 } 488 489 @LayoutlibDelegate 490 /*package*/ static float getTextScaleX(Paint thisPaint) { 491 // get the delegate from the native int. 492 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 493 if (delegate == null) { 494 return 1.f; 495 } 496 497 return delegate.mTextScaleX; 498 } 499 500 @LayoutlibDelegate 501 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) { 502 // get the delegate from the native int. 503 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 504 if (delegate == null) { 505 return; 506 } 507 508 if (delegate.mTextScaleX != scaleX) { 509 delegate.mTextScaleX = scaleX; 510 delegate.updateFontObject(); 511 } 512 } 513 514 @LayoutlibDelegate 515 /*package*/ static float getTextSkewX(Paint thisPaint) { 516 // get the delegate from the native int. 517 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 518 if (delegate == null) { 519 return 1.f; 520 } 521 522 return delegate.mTextSkewX; 523 } 524 525 @LayoutlibDelegate 526 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) { 527 // get the delegate from the native int. 528 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 529 if (delegate == null) { 530 return; 531 } 532 533 if (delegate.mTextSkewX != skewX) { 534 delegate.mTextSkewX = skewX; 535 delegate.updateFontObject(); 536 } 537 } 538 539 @LayoutlibDelegate 540 /*package*/ static float ascent(Paint thisPaint) { 541 // get the delegate 542 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 543 if (delegate == null) { 544 return 0; 545 } 546 547 if (delegate.mFonts.size() > 0) { 548 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 549 // Android expects negative ascent so we invert the value from Java. 550 return - javaMetrics.getAscent(); 551 } 552 553 return 0; 554 } 555 556 @LayoutlibDelegate 557 /*package*/ static float descent(Paint thisPaint) { 558 // get the delegate 559 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 560 if (delegate == null) { 561 return 0; 562 } 563 564 if (delegate.mFonts.size() > 0) { 565 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 566 return javaMetrics.getDescent(); 567 } 568 569 return 0; 570 571 } 572 573 @LayoutlibDelegate 574 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) { 575 // get the delegate 576 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 577 if (delegate == null) { 578 return 0; 579 } 580 581 return delegate.getFontMetrics(metrics); 582 } 583 584 @LayoutlibDelegate 585 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { 586 // get the delegate 587 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 588 if (delegate == null) { 589 return 0; 590 } 591 592 if (delegate.mFonts.size() > 0) { 593 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 594 if (fmi != null) { 595 // Android expects negative ascent so we invert the value from Java. 596 fmi.top = - javaMetrics.getMaxAscent(); 597 fmi.ascent = - javaMetrics.getAscent(); 598 fmi.descent = javaMetrics.getDescent(); 599 fmi.bottom = javaMetrics.getMaxDescent(); 600 fmi.leading = javaMetrics.getLeading(); 601 } 602 603 return javaMetrics.getHeight(); 604 } 605 606 return 0; 607 } 608 609 @LayoutlibDelegate 610 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, 611 int count, int bidiFlags) { 612 // get the delegate 613 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 614 if (delegate == null) { 615 return 0; 616 } 617 618 RectF bounds = delegate.measureText(text, index, count, null, 0, bidiFlags); 619 return bounds.right - bounds.left; 620 } 621 622 @LayoutlibDelegate 623 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end, 624 int bidiFlags) { 625 return native_measureText(thisPaint, text.toCharArray(), start, end - start, bidiFlags); 626 } 627 628 @LayoutlibDelegate 629 /*package*/ static float native_measureText(Paint thisPaint, String text, int bidiFlags) { 630 return native_measureText(thisPaint, text.toCharArray(), 0, text.length(), bidiFlags); 631 } 632 633 @LayoutlibDelegate 634 /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, char[] text, 635 int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) { 636 637 // get the delegate 638 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 639 if (delegate == null) { 640 return 0; 641 } 642 643 int inc = count > 0 ? 1 : -1; 644 645 int measureIndex = 0; 646 for (int i = index; i != index + count; i += inc, measureIndex++) { 647 int start, end; 648 if (i < index) { 649 start = i; 650 end = index; 651 } else { 652 start = index; 653 end = i; 654 } 655 656 // measure from start to end 657 RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags); 658 float res = bounds.right - bounds.left; 659 660 if (measuredWidth != null) { 661 measuredWidth[measureIndex] = res; 662 } 663 664 if (res > maxWidth) { 665 // we should not return this char index, but since it's 0-based 666 // and we need to return a count, we simply return measureIndex; 667 return measureIndex; 668 } 669 670 } 671 672 return measureIndex; 673 } 674 675 @LayoutlibDelegate 676 /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, String text, 677 boolean measureForwards, 678 float maxWidth, int bidiFlags, float[] measuredWidth) { 679 return native_breakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(), 680 maxWidth, bidiFlags, measuredWidth); 681 } 682 683 @LayoutlibDelegate 684 /*package*/ static long native_init() { 685 Paint_Delegate newDelegate = new Paint_Delegate(); 686 return sManager.addNewDelegate(newDelegate); 687 } 688 689 @LayoutlibDelegate 690 /*package*/ static long native_initWithPaint(long paint) { 691 // get the delegate from the native int. 692 Paint_Delegate delegate = sManager.getDelegate(paint); 693 if (delegate == null) { 694 return 0; 695 } 696 697 Paint_Delegate newDelegate = new Paint_Delegate(delegate); 698 return sManager.addNewDelegate(newDelegate); 699 } 700 701 @LayoutlibDelegate 702 /*package*/ static void native_reset(long native_object) { 703 // get the delegate from the native int. 704 Paint_Delegate delegate = sManager.getDelegate(native_object); 705 if (delegate == null) { 706 return; 707 } 708 709 delegate.reset(); 710 } 711 712 @LayoutlibDelegate 713 /*package*/ static void native_set(long native_dst, long native_src) { 714 // get the delegate from the native int. 715 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst); 716 if (delegate_dst == null) { 717 return; 718 } 719 720 // get the delegate from the native int. 721 Paint_Delegate delegate_src = sManager.getDelegate(native_src); 722 if (delegate_src == null) { 723 return; 724 } 725 726 delegate_dst.set(delegate_src); 727 } 728 729 @LayoutlibDelegate 730 /*package*/ static int native_getStyle(long native_object) { 731 // get the delegate from the native int. 732 Paint_Delegate delegate = sManager.getDelegate(native_object); 733 if (delegate == null) { 734 return 0; 735 } 736 737 return delegate.mStyle; 738 } 739 740 @LayoutlibDelegate 741 /*package*/ static void native_setStyle(long native_object, int style) { 742 // get the delegate from the native int. 743 Paint_Delegate delegate = sManager.getDelegate(native_object); 744 if (delegate == null) { 745 return; 746 } 747 748 delegate.mStyle = style; 749 } 750 751 @LayoutlibDelegate 752 /*package*/ static int native_getStrokeCap(long native_object) { 753 // get the delegate from the native int. 754 Paint_Delegate delegate = sManager.getDelegate(native_object); 755 if (delegate == null) { 756 return 0; 757 } 758 759 return delegate.mCap; 760 } 761 762 @LayoutlibDelegate 763 /*package*/ static void native_setStrokeCap(long native_object, int cap) { 764 // get the delegate from the native int. 765 Paint_Delegate delegate = sManager.getDelegate(native_object); 766 if (delegate == null) { 767 return; 768 } 769 770 delegate.mCap = cap; 771 } 772 773 @LayoutlibDelegate 774 /*package*/ static int native_getStrokeJoin(long native_object) { 775 // get the delegate from the native int. 776 Paint_Delegate delegate = sManager.getDelegate(native_object); 777 if (delegate == null) { 778 return 0; 779 } 780 781 return delegate.mJoin; 782 } 783 784 @LayoutlibDelegate 785 /*package*/ static void native_setStrokeJoin(long native_object, int join) { 786 // get the delegate from the native int. 787 Paint_Delegate delegate = sManager.getDelegate(native_object); 788 if (delegate == null) { 789 return; 790 } 791 792 delegate.mJoin = join; 793 } 794 795 @LayoutlibDelegate 796 /*package*/ static boolean native_getFillPath(long native_object, long src, long dst) { 797 Paint_Delegate paint = sManager.getDelegate(native_object); 798 if (paint == null) { 799 return false; 800 } 801 802 Path_Delegate srcPath = Path_Delegate.getDelegate(src); 803 if (srcPath == null) { 804 return true; 805 } 806 807 Path_Delegate dstPath = Path_Delegate.getDelegate(dst); 808 if (dstPath == null) { 809 return true; 810 } 811 812 Stroke stroke = paint.getJavaStroke(); 813 Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape()); 814 815 dstPath.setJavaShape(strokeShape); 816 817 // FIXME figure out the return value? 818 return true; 819 } 820 821 @LayoutlibDelegate 822 /*package*/ static long native_setShader(long native_object, long shader) { 823 // get the delegate from the native int. 824 Paint_Delegate delegate = sManager.getDelegate(native_object); 825 if (delegate == null) { 826 return shader; 827 } 828 829 delegate.mShader = Shader_Delegate.getDelegate(shader); 830 831 return shader; 832 } 833 834 @LayoutlibDelegate 835 /*package*/ static long native_setColorFilter(long native_object, long filter) { 836 // get the delegate from the native int. 837 Paint_Delegate delegate = sManager.getDelegate(native_object); 838 if (delegate == null) { 839 return filter; 840 } 841 842 delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter); 843 844 // Log warning if it's not supported. 845 if (delegate.mColorFilter != null && !delegate.mColorFilter.isSupported()) { 846 Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER, 847 delegate.mColorFilter.getSupportMessage(), null, null /*data*/); 848 } 849 850 return filter; 851 } 852 853 @LayoutlibDelegate 854 /*package*/ static long native_setXfermode(long native_object, long xfermode) { 855 // get the delegate from the native int. 856 Paint_Delegate delegate = sManager.getDelegate(native_object); 857 if (delegate == null) { 858 return xfermode; 859 } 860 861 delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode); 862 863 return xfermode; 864 } 865 866 @LayoutlibDelegate 867 /*package*/ static long native_setPathEffect(long native_object, long effect) { 868 // get the delegate from the native int. 869 Paint_Delegate delegate = sManager.getDelegate(native_object); 870 if (delegate == null) { 871 return effect; 872 } 873 874 delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect); 875 876 return effect; 877 } 878 879 @LayoutlibDelegate 880 /*package*/ static long native_setMaskFilter(long native_object, long maskfilter) { 881 // get the delegate from the native int. 882 Paint_Delegate delegate = sManager.getDelegate(native_object); 883 if (delegate == null) { 884 return maskfilter; 885 } 886 887 delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter); 888 889 // since none of those are supported, display a fidelity warning right away 890 if (delegate.mMaskFilter != null && !delegate.mMaskFilter.isSupported()) { 891 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER, 892 delegate.mMaskFilter.getSupportMessage(), null, null /*data*/); 893 } 894 895 return maskfilter; 896 } 897 898 @LayoutlibDelegate 899 /*package*/ static long native_setTypeface(long native_object, long typeface) { 900 // get the delegate from the native int. 901 Paint_Delegate delegate = sManager.getDelegate(native_object); 902 if (delegate == null) { 903 return 0; 904 } 905 906 Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface); 907 if (delegate.mTypeface != typefaceDelegate || delegate.mNativeTypeface != typeface) { 908 delegate.mTypeface = Typeface_Delegate.getDelegate(typeface); 909 delegate.mNativeTypeface = typeface; 910 delegate.updateFontObject(); 911 } 912 return typeface; 913 } 914 915 @LayoutlibDelegate 916 /*package*/ static long native_setRasterizer(long native_object, long rasterizer) { 917 // get the delegate from the native int. 918 Paint_Delegate delegate = sManager.getDelegate(native_object); 919 if (delegate == null) { 920 return rasterizer; 921 } 922 923 delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer); 924 925 // since none of those are supported, display a fidelity warning right away 926 if (delegate.mRasterizer != null && !delegate.mRasterizer.isSupported()) { 927 Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER, 928 delegate.mRasterizer.getSupportMessage(), null, null /*data*/); 929 } 930 931 return rasterizer; 932 } 933 934 @LayoutlibDelegate 935 /*package*/ static int native_getTextAlign(long native_object) { 936 // get the delegate from the native int. 937 Paint_Delegate delegate = sManager.getDelegate(native_object); 938 if (delegate == null) { 939 return 0; 940 } 941 942 return delegate.mTextAlign; 943 } 944 945 @LayoutlibDelegate 946 /*package*/ static void native_setTextAlign(long native_object, int align) { 947 // get the delegate from the native int. 948 Paint_Delegate delegate = sManager.getDelegate(native_object); 949 if (delegate == null) { 950 return; 951 } 952 953 delegate.mTextAlign = align; 954 } 955 956 @LayoutlibDelegate 957 /*package*/ static void native_setTextLocale(long native_object, String locale) { 958 // get the delegate from the native int. 959 Paint_Delegate delegate = sManager.getDelegate(native_object); 960 if (delegate == null) { 961 return; 962 } 963 964 delegate.setTextLocale(locale); 965 } 966 967 @LayoutlibDelegate 968 /*package*/ static int native_getTextWidths(long native_object, long native_typeface, 969 char[] text, int index, int count, int bidiFlags, float[] widths) { 970 971 if (widths != null) { 972 for (int i = 0; i< count; i++) { 973 widths[i]=0; 974 } 975 } 976 // get the delegate from the native int. 977 Paint_Delegate delegate = sManager.getDelegate(native_object); 978 if (delegate == null) { 979 return 0; 980 } 981 982 // native_typeface is passed here since Framework's old implementation did not have the 983 // typeface object associated with the Paint. Since, we follow the new framework way, 984 // we store the typeface with the paint and use it directly. 985 assert (native_typeface == delegate.mNativeTypeface); 986 987 RectF bounds = delegate.measureText(text, index, count, widths, 0, bidiFlags); 988 return ((int) (bounds.right - bounds.left)); 989 } 990 991 @LayoutlibDelegate 992 /*package*/ static int native_getTextWidths(long native_object, long native_typeface, 993 String text, int start, int end, int bidiFlags, float[] widths) { 994 return native_getTextWidths(native_object, native_typeface, text.toCharArray(), start, 995 end - start, bidiFlags, widths); 996 } 997 998 @LayoutlibDelegate 999 /* package */static int native_getTextGlyphs(long native_object, String text, int start, 1000 int end, int contextStart, int contextEnd, int flags, char[] glyphs) { 1001 // FIXME 1002 return 0; 1003 } 1004 1005 @LayoutlibDelegate 1006 /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface, 1007 char[] text, int index, int count, int contextIndex, int contextCount, 1008 boolean isRtl, float[] advances, int advancesIndex) { 1009 1010 if (advances != null) 1011 for (int i = advancesIndex; i< advancesIndex+count; i++) 1012 advances[i]=0; 1013 // get the delegate from the native int. 1014 Paint_Delegate delegate = sManager.getDelegate(native_object); 1015 if (delegate == null) { 1016 return 0.f; 1017 } 1018 1019 // native_typeface is passed here since Framework's old implementation did not have the 1020 // typeface object associated with the Paint. Since, we follow the new framework way, 1021 // we store the typeface with the paint and use it directly. 1022 assert (native_typeface == delegate.mNativeTypeface); 1023 1024 RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, isRtl); 1025 return bounds.right - bounds.left; 1026 } 1027 1028 @LayoutlibDelegate 1029 /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface, 1030 String text, int start, int end, int contextStart, int contextEnd, 1031 boolean isRtl, float[] advances, int advancesIndex) { 1032 // FIXME: support contextStart and contextEnd 1033 int count = end - start; 1034 char[] buffer = TemporaryBuffer.obtain(count); 1035 TextUtils.getChars(text, start, end, buffer, 0); 1036 1037 return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count, 1038 contextStart, contextEnd - contextStart, isRtl, advances, advancesIndex); 1039 } 1040 1041 @LayoutlibDelegate 1042 /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, char[] text, 1043 int contextStart, int contextLength, 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 1051 /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, String text, 1052 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { 1053 // FIXME 1054 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1055 "Paint.getTextRunCursor is not supported.", null, null /*data*/); 1056 return 0; 1057 } 1058 1059 @LayoutlibDelegate 1060 /*package*/ static void native_getTextPath(long native_object, long native_typeface, 1061 int bidiFlags, char[] text, int index, int count, float x, float y, long path) { 1062 // FIXME 1063 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1064 "Paint.getTextPath is not supported.", null, null /*data*/); 1065 } 1066 1067 @LayoutlibDelegate 1068 /*package*/ static void native_getTextPath(long native_object, long native_typeface, 1069 int bidiFlags, String text, int start, int end, float x, float y, long path) { 1070 // FIXME 1071 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1072 "Paint.getTextPath is not supported.", null, null /*data*/); 1073 } 1074 1075 @LayoutlibDelegate 1076 /*package*/ static void nativeGetStringBounds(long nativePaint, long native_typeface, 1077 String text, int start, int end, int bidiFlags, Rect bounds) { 1078 nativeGetCharArrayBounds(nativePaint, native_typeface, text.toCharArray(), start, 1079 end - start, bidiFlags, bounds); 1080 } 1081 1082 @LayoutlibDelegate 1083 /*package*/ static void nativeGetCharArrayBounds(long nativePaint, long native_typeface, 1084 char[] text, int index, int count, int bidiFlags, Rect bounds) { 1085 1086 // get the delegate from the native int. 1087 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1088 if (delegate == null) { 1089 return; 1090 } 1091 1092 // assert that the typeface passed is actually the one that we had stored. 1093 assert (native_typeface == delegate.mNativeTypeface); 1094 1095 delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds); 1096 } 1097 1098 @LayoutlibDelegate 1099 /*package*/ static void finalizer(long nativePaint) { 1100 sManager.removeJavaReferenceFor(nativePaint); 1101 } 1102 1103 @LayoutlibDelegate 1104 /*package*/ static float native_getLetterSpacing(long nativePaint) { 1105 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1106 if (delegate == null) { 1107 return 0; 1108 } 1109 return delegate.mLetterSpacing; 1110 } 1111 1112 @LayoutlibDelegate 1113 /*package*/ static void native_setLetterSpacing(long nativePaint, float letterSpacing) { 1114 Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, 1115 "Paint.setLetterSpacing() not supported.", null, null); 1116 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1117 if (delegate == null) { 1118 return; 1119 } 1120 delegate.mLetterSpacing = letterSpacing; 1121 } 1122 1123 @LayoutlibDelegate 1124 /*package*/ static void native_setFontFeatureSettings(long nativePaint, String settings) { 1125 Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, 1126 "Paint.setFontFeatureSettings() not supported.", null, null); 1127 } 1128 1129 @LayoutlibDelegate 1130 /*package*/ static int native_getHyphenEdit(long nativePaint) { 1131 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1132 if (delegate == null) { 1133 return 0; 1134 } 1135 return delegate.mHyphenEdit; 1136 } 1137 1138 @LayoutlibDelegate 1139 /*package*/ static void native_setHyphenEdit(long nativePaint, int hyphen) { 1140 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1141 if (delegate == null) { 1142 return; 1143 } 1144 delegate.mHyphenEdit = hyphen; 1145 } 1146 1147 @LayoutlibDelegate 1148 /*package*/ static boolean native_hasGlyph(long nativePaint, long nativeTypeface, int bidiFlags, 1149 String string) { 1150 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1151 if (delegate == null) { 1152 return false; 1153 } 1154 if (string.length() == 0) { 1155 return false; 1156 } 1157 if (string.length() > 1) { 1158 Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, 1159 "Paint.hasGlyph() is not supported for ligatures.", null, null); 1160 return false; 1161 } 1162 assert nativeTypeface == delegate.mNativeTypeface; 1163 Typeface_Delegate typeface_delegate = Typeface_Delegate.getDelegate(nativeTypeface); 1164 1165 char c = string.charAt(0); 1166 for (Font font : typeface_delegate.getFonts(delegate.mFontVariant)) { 1167 if (font.canDisplay(c)) { 1168 return true; 1169 } 1170 } 1171 return false; 1172 } 1173 1174 1175 @LayoutlibDelegate 1176 /*package*/ static float native_getRunAdvance(long nativePaint, long nativeTypeface, 1177 @NonNull char[] text, int start, int end, int contextStart, int contextEnd, 1178 boolean isRtl, int offset) { 1179 int count = end - start; 1180 float[] advances = new float[count]; 1181 native_getTextRunAdvances(nativePaint, nativeTypeface, text, start, count, 1182 contextStart, contextEnd - contextStart, isRtl, advances, 0); 1183 int startOffset = offset - start; // offset from start. 1184 float sum = 0; 1185 for (int i = 0; i < startOffset; i++) { 1186 sum += advances[i]; 1187 } 1188 return sum; 1189 } 1190 1191 @LayoutlibDelegate 1192 /*package*/ static int native_getOffsetForAdvance(long nativePaint, long nativeTypeface, 1193 char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, 1194 float advance) { 1195 int count = end - start; 1196 float[] advances = new float[count]; 1197 native_getTextRunAdvances(nativePaint, nativeTypeface, text, start, count, 1198 contextStart, contextEnd - contextStart, isRtl, advances, 0); 1199 float sum = 0; 1200 int i; 1201 for (i = 0; i < count && sum < advance; i++) { 1202 sum += advances[i]; 1203 } 1204 float distanceToI = sum - advance; 1205 float distanceToIMinus1 = advance - (sum - advances[i]); 1206 return distanceToI > distanceToIMinus1 ? i : i - 1; 1207 } 1208 1209 // ---- Private delegate/helper methods ---- 1210 1211 /*package*/ Paint_Delegate() { 1212 reset(); 1213 } 1214 1215 private Paint_Delegate(Paint_Delegate paint) { 1216 set(paint); 1217 } 1218 1219 private void set(Paint_Delegate paint) { 1220 mFlags = paint.mFlags; 1221 mColor = paint.mColor; 1222 mStyle = paint.mStyle; 1223 mCap = paint.mCap; 1224 mJoin = paint.mJoin; 1225 mTextAlign = paint.mTextAlign; 1226 1227 boolean needsFontUpdate = false; 1228 if (mTypeface != paint.mTypeface || mNativeTypeface != paint.mNativeTypeface) { 1229 mTypeface = paint.mTypeface; 1230 mNativeTypeface = paint.mNativeTypeface; 1231 needsFontUpdate = true; 1232 } 1233 1234 if (mTextSize != paint.mTextSize) { 1235 mTextSize = paint.mTextSize; 1236 needsFontUpdate = true; 1237 } 1238 1239 if (mTextScaleX != paint.mTextScaleX) { 1240 mTextScaleX = paint.mTextScaleX; 1241 needsFontUpdate = true; 1242 } 1243 1244 if (mTextSkewX != paint.mTextSkewX) { 1245 mTextSkewX = paint.mTextSkewX; 1246 needsFontUpdate = true; 1247 } 1248 1249 mStrokeWidth = paint.mStrokeWidth; 1250 mStrokeMiter = paint.mStrokeMiter; 1251 mXfermode = paint.mXfermode; 1252 mColorFilter = paint.mColorFilter; 1253 mShader = paint.mShader; 1254 mPathEffect = paint.mPathEffect; 1255 mMaskFilter = paint.mMaskFilter; 1256 mRasterizer = paint.mRasterizer; 1257 mHintingMode = paint.mHintingMode; 1258 1259 if (needsFontUpdate) { 1260 updateFontObject(); 1261 } 1262 } 1263 1264 private void reset() { 1265 mFlags = Paint.HIDDEN_DEFAULT_PAINT_FLAGS; 1266 mColor = 0xFF000000; 1267 mStyle = Paint.Style.FILL.nativeInt; 1268 mCap = Paint.Cap.BUTT.nativeInt; 1269 mJoin = Paint.Join.MITER.nativeInt; 1270 mTextAlign = 0; 1271 mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance); 1272 mNativeTypeface = 0; 1273 mStrokeWidth = 1.f; 1274 mStrokeMiter = 4.f; 1275 mTextSize = 20.f; 1276 mTextScaleX = 1.f; 1277 mTextSkewX = 0.f; 1278 mXfermode = null; 1279 mColorFilter = null; 1280 mShader = null; 1281 mPathEffect = null; 1282 mMaskFilter = null; 1283 mRasterizer = null; 1284 updateFontObject(); 1285 mHintingMode = Paint.HINTING_ON; 1286 } 1287 1288 /** 1289 * Update the {@link Font} object from the typeface, text size and scaling 1290 */ 1291 @SuppressWarnings("deprecation") 1292 private void updateFontObject() { 1293 if (mTypeface != null) { 1294 // Get the fonts from the TypeFace object. 1295 List<Font> fonts = mTypeface.getFonts(mFontVariant); 1296 1297 if (fonts.isEmpty()) { 1298 mFonts = Collections.emptyList(); 1299 return; 1300 } 1301 1302 // create new font objects as well as FontMetrics, based on the current text size 1303 // and skew info. 1304 int nFonts = fonts.size(); 1305 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(nFonts); 1306 //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation) 1307 for (int i = 0; i < nFonts; i++) { 1308 Font font = fonts.get(i); 1309 if (font == null) { 1310 // If the font is null, add null to infoList. When rendering the text, if this 1311 // null is reached, a warning will be logged. 1312 infoList.add(null); 1313 continue; 1314 } 1315 FontInfo info = new FontInfo(); 1316 info.mFont = font.deriveFont(mTextSize); 1317 if (mTextScaleX != 1.0 || mTextSkewX != 0) { 1318 // TODO: support skew 1319 info.mFont = info.mFont.deriveFont(new AffineTransform( 1320 mTextScaleX, mTextSkewX, 0, 1, 0, 0)); 1321 } 1322 // The metrics here don't have anti-aliasing set. 1323 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); 1324 1325 infoList.add(info); 1326 } 1327 1328 mFonts = Collections.unmodifiableList(infoList); 1329 } 1330 } 1331 1332 /*package*/ RectF measureText(char[] text, int index, int count, float[] advances, 1333 int advancesIndex, int bidiFlags) { 1334 return new BidiRenderer(null, this, text) 1335 .renderText(index, index + count, bidiFlags, advances, advancesIndex, false); 1336 } 1337 1338 /*package*/ RectF measureText(char[] text, int index, int count, float[] advances, 1339 int advancesIndex, boolean isRtl) { 1340 return new BidiRenderer(null, this, text) 1341 .renderText(index, index + count, isRtl, advances, advancesIndex, false); 1342 } 1343 1344 private float getFontMetrics(FontMetrics metrics) { 1345 if (mFonts.size() > 0) { 1346 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; 1347 if (metrics != null) { 1348 // Android expects negative ascent so we invert the value from Java. 1349 metrics.top = - javaMetrics.getMaxAscent(); 1350 metrics.ascent = - javaMetrics.getAscent(); 1351 metrics.descent = javaMetrics.getDescent(); 1352 metrics.bottom = javaMetrics.getMaxDescent(); 1353 metrics.leading = javaMetrics.getLeading(); 1354 } 1355 1356 return javaMetrics.getHeight(); 1357 } 1358 1359 return 0; 1360 } 1361 1362 private void setTextLocale(String locale) { 1363 mLocale = new Locale(locale); 1364 } 1365 1366 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) { 1367 // get the delegate from the native int. 1368 Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance()); 1369 if (delegate == null) { 1370 return; 1371 } 1372 1373 if (flagValue) { 1374 delegate.mFlags |= flagMask; 1375 } else { 1376 delegate.mFlags &= ~flagMask; 1377 } 1378 } 1379} 1380