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