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