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