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