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