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