Paint_Delegate.java revision 08ea918c86175d313c8e7f10c0b4a25c1424639b
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.Paint.FontMetrics; 25import android.graphics.Paint.FontMetricsInt; 26import android.text.TextUtils; 27 28import java.awt.BasicStroke; 29import java.awt.Font; 30import java.awt.Shape; 31import java.awt.Stroke; 32import java.awt.Toolkit; 33import java.awt.font.FontRenderContext; 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 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(long 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 boolean isElegantTextHeight(Paint thisPaint) { 432 return false; 433 } 434 435 @LayoutlibDelegate 436 /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) { 437 // TODO 438 } 439 440 @LayoutlibDelegate 441 /*package*/ static float getTextSize(Paint thisPaint) { 442 // get the delegate from the native int. 443 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 444 if (delegate == null) { 445 return 1.f; 446 } 447 448 return delegate.mTextSize; 449 } 450 451 @LayoutlibDelegate 452 /*package*/ static void setTextSize(Paint thisPaint, float textSize) { 453 // get the delegate from the native int. 454 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 455 if (delegate == null) { 456 return; 457 } 458 459 delegate.mTextSize = textSize; 460 delegate.updateFontObject(); 461 } 462 463 @LayoutlibDelegate 464 /*package*/ static float getTextScaleX(Paint thisPaint) { 465 // get the delegate from the native int. 466 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 467 if (delegate == null) { 468 return 1.f; 469 } 470 471 return delegate.mTextScaleX; 472 } 473 474 @LayoutlibDelegate 475 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) { 476 // get the delegate from the native int. 477 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 478 if (delegate == null) { 479 return; 480 } 481 482 delegate.mTextScaleX = scaleX; 483 delegate.updateFontObject(); 484 } 485 486 @LayoutlibDelegate 487 /*package*/ static float getTextSkewX(Paint thisPaint) { 488 // get the delegate from the native int. 489 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 490 if (delegate == null) { 491 return 1.f; 492 } 493 494 return delegate.mTextSkewX; 495 } 496 497 @LayoutlibDelegate 498 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) { 499 // get the delegate from the native int. 500 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 501 if (delegate == null) { 502 return; 503 } 504 505 delegate.mTextSkewX = skewX; 506 delegate.updateFontObject(); 507 } 508 509 @LayoutlibDelegate 510 /*package*/ static float ascent(Paint thisPaint) { 511 // get the delegate 512 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 513 if (delegate == null) { 514 return 0; 515 } 516 517 if (delegate.mFonts.size() > 0) { 518 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 519 // Android expects negative ascent so we invert the value from Java. 520 return - javaMetrics.getAscent(); 521 } 522 523 return 0; 524 } 525 526 @LayoutlibDelegate 527 /*package*/ static float descent(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 return javaMetrics.getDescent(); 537 } 538 539 return 0; 540 541 } 542 543 @LayoutlibDelegate 544 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) { 545 // get the delegate 546 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 547 if (delegate == null) { 548 return 0; 549 } 550 551 return delegate.getFontMetrics(metrics); 552 } 553 554 @LayoutlibDelegate 555 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { 556 // get the delegate 557 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 558 if (delegate == null) { 559 return 0; 560 } 561 562 if (delegate.mFonts.size() > 0) { 563 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 564 if (fmi != null) { 565 // Android expects negative ascent so we invert the value from Java. 566 fmi.top = - javaMetrics.getMaxAscent(); 567 fmi.ascent = - javaMetrics.getAscent(); 568 fmi.descent = javaMetrics.getDescent(); 569 fmi.bottom = javaMetrics.getMaxDescent(); 570 fmi.leading = javaMetrics.getLeading(); 571 } 572 573 return javaMetrics.getHeight(); 574 } 575 576 return 0; 577 } 578 579 @LayoutlibDelegate 580 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, 581 int count, int bidiFlags) { 582 // get the delegate 583 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 584 if (delegate == null) { 585 return 0; 586 } 587 588 RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags)); 589 return bounds.right - bounds.left; 590 } 591 592 @LayoutlibDelegate 593 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end, 594 int bidiFlags) { 595 return native_measureText(thisPaint, text.toCharArray(), start, end - start, bidiFlags); 596 } 597 598 @LayoutlibDelegate 599 /*package*/ static float native_measureText(Paint thisPaint, String text, int bidiFlags) { 600 return native_measureText(thisPaint, text.toCharArray(), 0, text.length(), bidiFlags); 601 } 602 603 @LayoutlibDelegate 604 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count, 605 float maxWidth, int bidiFlags, float[] measuredWidth) { 606 607 // get the delegate 608 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 609 if (delegate == null) { 610 return 0; 611 } 612 613 int inc = count > 0 ? 1 : -1; 614 615 int measureIndex = 0; 616 float measureAcc = 0; 617 for (int i = index; i != index + count; i += inc, measureIndex++) { 618 int start, end; 619 if (i < index) { 620 start = i; 621 end = index; 622 } else { 623 start = index; 624 end = i; 625 } 626 627 // measure from start to end 628 RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags)); 629 float res = bounds.right - bounds.left; 630 631 if (measuredWidth != null) { 632 measuredWidth[measureIndex] = res; 633 } 634 635 measureAcc += res; 636 if (res > maxWidth) { 637 // we should not return this char index, but since it's 0-based 638 // and we need to return a count, we simply return measureIndex; 639 return measureIndex; 640 } 641 642 } 643 644 return measureIndex; 645 } 646 647 @LayoutlibDelegate 648 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards, 649 float maxWidth, int bidiFlags, float[] measuredWidth) { 650 return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth, 651 bidiFlags, measuredWidth); 652 } 653 654 @LayoutlibDelegate 655 /*package*/ static long native_init() { 656 Paint_Delegate newDelegate = new Paint_Delegate(); 657 return sManager.addNewDelegate(newDelegate); 658 } 659 660 @LayoutlibDelegate 661 /*package*/ static long native_initWithPaint(long paint) { 662 // get the delegate from the native int. 663 Paint_Delegate delegate = sManager.getDelegate(paint); 664 if (delegate == null) { 665 return 0; 666 } 667 668 Paint_Delegate newDelegate = new Paint_Delegate(delegate); 669 return sManager.addNewDelegate(newDelegate); 670 } 671 672 @LayoutlibDelegate 673 /*package*/ static void native_reset(long native_object) { 674 // get the delegate from the native int. 675 Paint_Delegate delegate = sManager.getDelegate(native_object); 676 if (delegate == null) { 677 return; 678 } 679 680 delegate.reset(); 681 } 682 683 @LayoutlibDelegate 684 /*package*/ static void native_set(long native_dst, long native_src) { 685 // get the delegate from the native int. 686 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst); 687 if (delegate_dst == null) { 688 return; 689 } 690 691 // get the delegate from the native int. 692 Paint_Delegate delegate_src = sManager.getDelegate(native_src); 693 if (delegate_src == null) { 694 return; 695 } 696 697 delegate_dst.set(delegate_src); 698 } 699 700 @LayoutlibDelegate 701 /*package*/ static int native_getStyle(long native_object) { 702 // get the delegate from the native int. 703 Paint_Delegate delegate = sManager.getDelegate(native_object); 704 if (delegate == null) { 705 return 0; 706 } 707 708 return delegate.mStyle; 709 } 710 711 @LayoutlibDelegate 712 /*package*/ static void native_setStyle(long native_object, int style) { 713 // get the delegate from the native int. 714 Paint_Delegate delegate = sManager.getDelegate(native_object); 715 if (delegate == null) { 716 return; 717 } 718 719 delegate.mStyle = style; 720 } 721 722 @LayoutlibDelegate 723 /*package*/ static int native_getStrokeCap(long native_object) { 724 // get the delegate from the native int. 725 Paint_Delegate delegate = sManager.getDelegate(native_object); 726 if (delegate == null) { 727 return 0; 728 } 729 730 return delegate.mCap; 731 } 732 733 @LayoutlibDelegate 734 /*package*/ static void native_setStrokeCap(long native_object, int cap) { 735 // get the delegate from the native int. 736 Paint_Delegate delegate = sManager.getDelegate(native_object); 737 if (delegate == null) { 738 return; 739 } 740 741 delegate.mCap = cap; 742 } 743 744 @LayoutlibDelegate 745 /*package*/ static int native_getStrokeJoin(long native_object) { 746 // get the delegate from the native int. 747 Paint_Delegate delegate = sManager.getDelegate(native_object); 748 if (delegate == null) { 749 return 0; 750 } 751 752 return delegate.mJoin; 753 } 754 755 @LayoutlibDelegate 756 /*package*/ static void native_setStrokeJoin(long native_object, int join) { 757 // get the delegate from the native int. 758 Paint_Delegate delegate = sManager.getDelegate(native_object); 759 if (delegate == null) { 760 return; 761 } 762 763 delegate.mJoin = join; 764 } 765 766 @LayoutlibDelegate 767 /*package*/ static boolean native_getFillPath(long native_object, long src, long dst) { 768 Paint_Delegate paint = sManager.getDelegate(native_object); 769 if (paint == null) { 770 return false; 771 } 772 773 Path_Delegate srcPath = Path_Delegate.getDelegate(src); 774 if (srcPath == null) { 775 return true; 776 } 777 778 Path_Delegate dstPath = Path_Delegate.getDelegate(dst); 779 if (dstPath == null) { 780 return true; 781 } 782 783 Stroke stroke = paint.getJavaStroke(); 784 Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape()); 785 786 dstPath.setJavaShape(strokeShape); 787 788 // FIXME figure out the return value? 789 return true; 790 } 791 792 @LayoutlibDelegate 793 /*package*/ static long native_setShader(long native_object, long shader) { 794 // get the delegate from the native int. 795 Paint_Delegate delegate = sManager.getDelegate(native_object); 796 if (delegate == null) { 797 return shader; 798 } 799 800 delegate.mShader = Shader_Delegate.getDelegate(shader); 801 802 return shader; 803 } 804 805 @LayoutlibDelegate 806 /*package*/ static long native_setColorFilter(long native_object, long filter) { 807 // get the delegate from the native int. 808 Paint_Delegate delegate = sManager.getDelegate(native_object); 809 if (delegate == null) { 810 return filter; 811 } 812 813 delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);; 814 815 // since none of those are supported, display a fidelity warning right away 816 if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) { 817 Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER, 818 delegate.mColorFilter.getSupportMessage(), null, null /*data*/); 819 } 820 821 return filter; 822 } 823 824 @LayoutlibDelegate 825 /*package*/ static long native_setXfermode(long native_object, long xfermode) { 826 // get the delegate from the native int. 827 Paint_Delegate delegate = sManager.getDelegate(native_object); 828 if (delegate == null) { 829 return xfermode; 830 } 831 832 delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode); 833 834 return xfermode; 835 } 836 837 @LayoutlibDelegate 838 /*package*/ static long native_setPathEffect(long native_object, long effect) { 839 // get the delegate from the native int. 840 Paint_Delegate delegate = sManager.getDelegate(native_object); 841 if (delegate == null) { 842 return effect; 843 } 844 845 delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect); 846 847 return effect; 848 } 849 850 @LayoutlibDelegate 851 /*package*/ static long native_setMaskFilter(long native_object, long maskfilter) { 852 // get the delegate from the native int. 853 Paint_Delegate delegate = sManager.getDelegate(native_object); 854 if (delegate == null) { 855 return maskfilter; 856 } 857 858 delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter); 859 860 // since none of those are supported, display a fidelity warning right away 861 if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) { 862 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER, 863 delegate.mMaskFilter.getSupportMessage(), null, null /*data*/); 864 } 865 866 return maskfilter; 867 } 868 869 @LayoutlibDelegate 870 /*package*/ static long native_setTypeface(long native_object, long typeface) { 871 // get the delegate from the native int. 872 Paint_Delegate delegate = sManager.getDelegate(native_object); 873 if (delegate == null) { 874 return 0; 875 } 876 877 delegate.mTypeface = Typeface_Delegate.getDelegate(typeface); 878 delegate.updateFontObject(); 879 return typeface; 880 } 881 882 @LayoutlibDelegate 883 /*package*/ static long native_setRasterizer(long native_object, long rasterizer) { 884 // get the delegate from the native int. 885 Paint_Delegate delegate = sManager.getDelegate(native_object); 886 if (delegate == null) { 887 return rasterizer; 888 } 889 890 delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer); 891 892 // since none of those are supported, display a fidelity warning right away 893 if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) { 894 Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER, 895 delegate.mRasterizer.getSupportMessage(), null, null /*data*/); 896 } 897 898 return rasterizer; 899 } 900 901 @LayoutlibDelegate 902 /*package*/ static int native_getTextAlign(long native_object) { 903 // get the delegate from the native int. 904 Paint_Delegate delegate = sManager.getDelegate(native_object); 905 if (delegate == null) { 906 return 0; 907 } 908 909 return delegate.mTextAlign; 910 } 911 912 @LayoutlibDelegate 913 /*package*/ static void native_setTextAlign(long native_object, int align) { 914 // get the delegate from the native int. 915 Paint_Delegate delegate = sManager.getDelegate(native_object); 916 if (delegate == null) { 917 return; 918 } 919 920 delegate.mTextAlign = align; 921 } 922 923 @LayoutlibDelegate 924 /*package*/ static void native_setTextLocale(long native_object, String locale) { 925 // get the delegate from the native int. 926 Paint_Delegate delegate = sManager.getDelegate(native_object); 927 if (delegate == null) { 928 return; 929 } 930 931 delegate.setTextLocale(locale); 932 } 933 934 @LayoutlibDelegate 935 /*package*/ static int native_getTextWidths(long native_object, char[] text, int index, 936 int count, int bidiFlags, float[] widths) { 937 // get the delegate from the native int. 938 Paint_Delegate delegate = sManager.getDelegate(native_object); 939 if (delegate == null) { 940 return 0; 941 } 942 943 if (delegate.mFonts.size() > 0) { 944 // FIXME: handle multi-char characters (see measureText) 945 float totalAdvance = 0; 946 for (int i = 0; i < count; i++) { 947 char c = text[i + index]; 948 boolean found = false; 949 for (FontInfo info : delegate.mFonts) { 950 if (info.mFont.canDisplay(c)) { 951 float adv = info.mMetrics.charWidth(c); 952 totalAdvance += adv; 953 if (widths != null) { 954 widths[i] = adv; 955 } 956 957 found = true; 958 break; 959 } 960 } 961 962 if (found == false) { 963 // no advance for this char. 964 if (widths != null) { 965 widths[i] = 0.f; 966 } 967 } 968 } 969 970 return (int) totalAdvance; 971 } 972 973 return 0; 974 } 975 976 @LayoutlibDelegate 977 /*package*/ static int native_getTextWidths(long native_object, String text, int start, 978 int end, int bidiFlags, float[] widths) { 979 return native_getTextWidths(native_object, text.toCharArray(), start, end - start, 980 bidiFlags, widths); 981 } 982 983 @LayoutlibDelegate 984 /* package */static int native_getTextGlyphs(long native_object, String text, int start, 985 int end, int contextStart, int contextEnd, int flags, char[] glyphs) { 986 // FIXME 987 return 0; 988 } 989 990 @LayoutlibDelegate 991 /*package*/ static float native_getTextRunAdvances(long native_object, 992 char[] text, int index, int count, int contextIndex, int contextCount, 993 int flags, float[] advances, int advancesIndex) { 994 995 if (advances != null) 996 for (int i = advancesIndex; i< advancesIndex+count; i++) 997 advances[i]=0; 998 // get the delegate from the native int. 999 Paint_Delegate delegate = sManager.getDelegate(native_object); 1000 if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) { 1001 return 0.f; 1002 } 1003 boolean isRtl = isRtl(flags); 1004 1005 int limit = index + count; 1006 RectF bounds = new BidiRenderer(null, delegate, text).renderText( 1007 index, limit, isRtl, advances, advancesIndex, false, 0, 0); 1008 return bounds.right - bounds.left; 1009 } 1010 1011 @LayoutlibDelegate 1012 /*package*/ static float native_getTextRunAdvances(long native_object, 1013 String text, int start, int end, int contextStart, int contextEnd, 1014 int flags, float[] advances, int advancesIndex) { 1015 // FIXME: support contextStart and contextEnd 1016 int count = end - start; 1017 char[] buffer = TemporaryBuffer.obtain(count); 1018 TextUtils.getChars(text, start, end, buffer, 0); 1019 1020 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart, 1021 contextEnd - contextStart, flags, advances, advancesIndex); 1022 } 1023 1024 @LayoutlibDelegate 1025 /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, char[] text, 1026 int contextStart, int contextLength, int flags, int offset, int cursorOpt) { 1027 // FIXME 1028 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1029 "Paint.getTextRunCursor is not supported.", null, null /*data*/); 1030 return 0; 1031 } 1032 1033 @LayoutlibDelegate 1034 /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, String text, 1035 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { 1036 // FIXME 1037 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1038 "Paint.getTextRunCursor is not supported.", null, null /*data*/); 1039 return 0; 1040 } 1041 1042 @LayoutlibDelegate 1043 /*package*/ static void native_getTextPath(long native_object, int bidiFlags, 1044 char[] text, int index, int count, float x, float y, long path) { 1045 // FIXME 1046 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1047 "Paint.getTextPath is not supported.", null, null /*data*/); 1048 } 1049 1050 @LayoutlibDelegate 1051 /*package*/ static void native_getTextPath(long native_object, int bidiFlags, 1052 String text, int start, int end, float x, float y, long path) { 1053 // FIXME 1054 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1055 "Paint.getTextPath is not supported.", null, null /*data*/); 1056 } 1057 1058 @LayoutlibDelegate 1059 /*package*/ static void nativeGetStringBounds(long nativePaint, String text, int start, 1060 int end, int bidiFlags, Rect bounds) { 1061 nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bidiFlags, 1062 bounds); 1063 } 1064 1065 @LayoutlibDelegate 1066 /*package*/ static void nativeGetCharArrayBounds(long nativePaint, char[] text, int index, 1067 int count, int bidiFlags, Rect bounds) { 1068 1069 // get the delegate from the native int. 1070 Paint_Delegate delegate = sManager.getDelegate(nativePaint); 1071 if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) { 1072 return; 1073 } 1074 delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds); 1075 } 1076 1077 @LayoutlibDelegate 1078 /*package*/ static void finalizer(long nativePaint) { 1079 sManager.removeJavaReferenceFor(nativePaint); 1080 } 1081 1082 // ---- Private delegate/helper methods ---- 1083 1084 /*package*/ Paint_Delegate() { 1085 reset(); 1086 } 1087 1088 private Paint_Delegate(Paint_Delegate paint) { 1089 set(paint); 1090 } 1091 1092 private void set(Paint_Delegate paint) { 1093 mFlags = paint.mFlags; 1094 mColor = paint.mColor; 1095 mStyle = paint.mStyle; 1096 mCap = paint.mCap; 1097 mJoin = paint.mJoin; 1098 mTextAlign = paint.mTextAlign; 1099 mTypeface = paint.mTypeface; 1100 mStrokeWidth = paint.mStrokeWidth; 1101 mStrokeMiter = paint.mStrokeMiter; 1102 mTextSize = paint.mTextSize; 1103 mTextScaleX = paint.mTextScaleX; 1104 mTextSkewX = paint.mTextSkewX; 1105 mXfermode = paint.mXfermode; 1106 mColorFilter = paint.mColorFilter; 1107 mShader = paint.mShader; 1108 mPathEffect = paint.mPathEffect; 1109 mMaskFilter = paint.mMaskFilter; 1110 mRasterizer = paint.mRasterizer; 1111 mHintingMode = paint.mHintingMode; 1112 updateFontObject(); 1113 } 1114 1115 private void reset() { 1116 mFlags = Paint.DEFAULT_PAINT_FLAGS; 1117 mColor = 0xFF000000; 1118 mStyle = Paint.Style.FILL.nativeInt; 1119 mCap = Paint.Cap.BUTT.nativeInt; 1120 mJoin = Paint.Join.MITER.nativeInt; 1121 mTextAlign = 0; 1122 mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance); 1123 mStrokeWidth = 1.f; 1124 mStrokeMiter = 4.f; 1125 mTextSize = 20.f; 1126 mTextScaleX = 1.f; 1127 mTextSkewX = 0.f; 1128 mXfermode = null; 1129 mColorFilter = null; 1130 mShader = null; 1131 mPathEffect = null; 1132 mMaskFilter = null; 1133 mRasterizer = null; 1134 updateFontObject(); 1135 mHintingMode = Paint.HINTING_ON; 1136 } 1137 1138 /** 1139 * Update the {@link Font} object from the typeface, text size and scaling 1140 */ 1141 @SuppressWarnings("deprecation") 1142 private void updateFontObject() { 1143 if (mTypeface != null) { 1144 // Get the fonts from the TypeFace object. 1145 List<Font> fonts = mTypeface.getFonts(); 1146 1147 // create new font objects as well as FontMetrics, based on the current text size 1148 // and skew info. 1149 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); 1150 for (Font font : fonts) { 1151 FontInfo info = new FontInfo(); 1152 info.mFont = font.deriveFont(mTextSize); 1153 if (mTextScaleX != 1.0 || mTextSkewX != 0) { 1154 // TODO: support skew 1155 info.mFont = info.mFont.deriveFont(new AffineTransform( 1156 mTextScaleX, mTextSkewX, 0, 1, 0, 0)); 1157 } 1158 // The metrics here don't have anti-aliasing set. 1159 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); 1160 1161 infoList.add(info); 1162 } 1163 1164 mFonts = Collections.unmodifiableList(infoList); 1165 } 1166 } 1167 1168 /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) { 1169 return new BidiRenderer(null, this, text).renderText( 1170 index, index + count, isRtl, null, 0, false, 0, 0); 1171 } 1172 1173 private float getFontMetrics(FontMetrics metrics) { 1174 if (mFonts.size() > 0) { 1175 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; 1176 if (metrics != null) { 1177 // Android expects negative ascent so we invert the value from Java. 1178 metrics.top = - javaMetrics.getMaxAscent(); 1179 metrics.ascent = - javaMetrics.getAscent(); 1180 metrics.descent = javaMetrics.getDescent(); 1181 metrics.bottom = javaMetrics.getMaxDescent(); 1182 metrics.leading = javaMetrics.getLeading(); 1183 } 1184 1185 return javaMetrics.getHeight(); 1186 } 1187 1188 return 0; 1189 } 1190 1191 private void setTextLocale(String locale) { 1192 mLocale = new Locale(locale); 1193 } 1194 1195 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) { 1196 // get the delegate from the native int. 1197 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 1198 if (delegate == null) { 1199 return; 1200 } 1201 1202 if (flagValue) { 1203 delegate.mFlags |= flagMask; 1204 } else { 1205 delegate.mFlags &= ~flagMask; 1206 } 1207 } 1208 1209 private static boolean isRtl(int flag) { 1210 switch(flag) { 1211 case Paint.BIDI_RTL: 1212 case Paint.BIDI_FORCE_RTL: 1213 case Paint.BIDI_DEFAULT_RTL: 1214 return true; 1215 default: 1216 return false; 1217 } 1218 } 1219} 1220