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