Paint_Delegate.java revision 42e2b28e65114175e208565d62ee0041fcd50d25
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 getTextAlign() { 118 return mTextAlign; 119 } 120 121 public float getStrokeWidth() { 122 return mStrokeWidth; 123 } 124 125 public float getStrokeMiter() { 126 return mStrokeMiter; 127 } 128 129 public int getJavaCap() { 130 switch (Paint.sCapArray[mCap]) { 131 case BUTT: 132 return BasicStroke.CAP_BUTT; 133 case ROUND: 134 return BasicStroke.CAP_ROUND; 135 default: 136 case SQUARE: 137 return BasicStroke.CAP_SQUARE; 138 } 139 } 140 141 public int getJavaJoin() { 142 switch (Paint.sJoinArray[mJoin]) { 143 default: 144 case MITER: 145 return BasicStroke.JOIN_MITER; 146 case ROUND: 147 return BasicStroke.JOIN_ROUND; 148 case BEVEL: 149 return BasicStroke.JOIN_BEVEL; 150 } 151 } 152 153 public int getXfermode() { 154 return mXfermode; 155 } 156 157 public int getColorFilter() { 158 return mColorFilter; 159 } 160 161 public int getShader() { 162 return mShader; 163 } 164 165 public int getPathEffect() { 166 return mPathEffect; 167 } 168 169 public int getMaskFilter() { 170 return mMaskFilter; 171 } 172 173 // ---- native methods ---- 174 175 /*package*/ static int getFlags(Paint thisPaint) { 176 // get the delegate from the native int. 177 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 178 if (delegate == null) { 179 assert false; 180 return 0; 181 } 182 183 return delegate.mFlags; 184 } 185 186 /*package*/ static void setFlags(Paint thisPaint, int flags) { 187 // get the delegate from the native int. 188 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 189 if (delegate == null) { 190 assert false; 191 return; 192 } 193 194 delegate.mFlags = flags; 195 } 196 197 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) { 198 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter); 199 } 200 201 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) { 202 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa); 203 } 204 205 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) { 206 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText); 207 } 208 209 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) { 210 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText); 211 } 212 213 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) { 214 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText); 215 } 216 217 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) { 218 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText); 219 } 220 221 /*package*/ static void setDither(Paint thisPaint, boolean dither) { 222 setFlag(thisPaint, Paint.DITHER_FLAG, dither); 223 } 224 225 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) { 226 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText); 227 } 228 229 /*package*/ static int getColor(Paint thisPaint) { 230 // get the delegate from the native int. 231 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 232 if (delegate == null) { 233 assert false; 234 return 0; 235 } 236 237 return delegate.mColor; 238 } 239 240 /*package*/ static void setColor(Paint thisPaint, int color) { 241 // get the delegate from the native int. 242 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 243 if (delegate == null) { 244 assert false; 245 return; 246 } 247 248 delegate.mColor = color; 249 } 250 251 /*package*/ static int getAlpha(Paint thisPaint) { 252 // get the delegate from the native int. 253 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 254 if (delegate == null) { 255 assert false; 256 return 0; 257 } 258 259 return delegate.mColor >>> 24; 260 } 261 262 /*package*/ static void setAlpha(Paint thisPaint, int a) { 263 // get the delegate from the native int. 264 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 265 if (delegate == null) { 266 assert false; 267 return; 268 } 269 270 delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF); 271 } 272 273 /*package*/ static float getStrokeWidth(Paint thisPaint) { 274 // get the delegate from the native int. 275 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 276 if (delegate == null) { 277 assert false; 278 return 1.f; 279 } 280 281 return delegate.mStrokeWidth; 282 } 283 284 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) { 285 // get the delegate from the native int. 286 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 287 if (delegate == null) { 288 assert false; 289 return; 290 } 291 292 delegate.mStrokeWidth = width; 293 } 294 295 /*package*/ static float getStrokeMiter(Paint thisPaint) { 296 // get the delegate from the native int. 297 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 298 if (delegate == null) { 299 assert false; 300 return 1.f; 301 } 302 303 return delegate.mStrokeMiter; 304 } 305 306 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) { 307 // get the delegate from the native int. 308 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 309 if (delegate == null) { 310 assert false; 311 return; 312 } 313 314 delegate.mStrokeMiter = miter; 315 } 316 317 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy, 318 int color) { 319 // FIXME 320 throw new UnsupportedOperationException(); 321 } 322 323 /*package*/ static float getTextSize(Paint thisPaint) { 324 // get the delegate from the native int. 325 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 326 if (delegate == null) { 327 assert false; 328 return 1.f; 329 } 330 331 return delegate.mTextSize; 332 } 333 334 /*package*/ static void setTextSize(Paint thisPaint, float textSize) { 335 // get the delegate from the native int. 336 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 337 if (delegate == null) { 338 assert false; 339 return; 340 } 341 342 delegate.mTextSize = textSize; 343 delegate.updateFontObject(); 344 } 345 346 /*package*/ static float getTextScaleX(Paint thisPaint) { 347 // get the delegate from the native int. 348 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 349 if (delegate == null) { 350 assert false; 351 return 1.f; 352 } 353 354 return delegate.mTextScaleX; 355 } 356 357 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) { 358 // get the delegate from the native int. 359 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 360 if (delegate == null) { 361 assert false; 362 return; 363 } 364 365 delegate.mTextScaleX = scaleX; 366 delegate.updateFontObject(); 367 } 368 369 /*package*/ static float getTextSkewX(Paint thisPaint) { 370 // get the delegate from the native int. 371 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 372 if (delegate == null) { 373 assert false; 374 return 1.f; 375 } 376 377 return delegate.mTextSkewX; 378 } 379 380 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) { 381 // get the delegate from the native int. 382 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 383 if (delegate == null) { 384 assert false; 385 return; 386 } 387 388 delegate.mTextSkewX = skewX; 389 delegate.updateFontObject(); 390 } 391 392 /*package*/ static float ascent(Paint thisPaint) { 393 // FIXME 394 throw new UnsupportedOperationException(); 395 } 396 397 /*package*/ static float descent(Paint thisPaint) { 398 // FIXME 399 throw new UnsupportedOperationException(); 400 } 401 402 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) { 403 // get the delegate 404 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 405 if (delegate == null) { 406 assert false; 407 return 0; 408 } 409 410 if (delegate.mFonts.size() > 0) { 411 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 412 if (metrics != null) { 413 // Android expects negative ascent so we invert the value from Java. 414 metrics.top = - javaMetrics.getMaxAscent(); 415 metrics.ascent = - javaMetrics.getAscent(); 416 metrics.descent = javaMetrics.getDescent(); 417 metrics.bottom = javaMetrics.getMaxDescent(); 418 metrics.leading = javaMetrics.getLeading(); 419 } 420 421 return javaMetrics.getHeight(); 422 } 423 424 return 0; 425 } 426 427 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { 428 // get the delegate 429 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 430 if (delegate == null) { 431 assert false; 432 return 0; 433 } 434 435 if (delegate.mFonts.size() > 0) { 436 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics; 437 if (fmi != null) { 438 // Android expects negative ascent so we invert the value from Java. 439 fmi.top = - javaMetrics.getMaxAscent(); 440 fmi.ascent = - javaMetrics.getAscent(); 441 fmi.descent = javaMetrics.getDescent(); 442 fmi.bottom = javaMetrics.getMaxDescent(); 443 fmi.leading = javaMetrics.getLeading(); 444 } 445 446 return javaMetrics.getHeight(); 447 } 448 449 return 0; 450 } 451 452 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, 453 int count) { 454 // WARNING: the logic in this method is similar to Canvas.drawText. 455 // Any change to this method should be reflected in Canvas.drawText 456 457 // get the delegate 458 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 459 if (delegate == null) { 460 assert false; 461 return 0; 462 } 463 464 return delegate.measureText(text, index, count); 465 } 466 467 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) { 468 return native_measureText(thisPaint, text.toCharArray(), start, end - start); 469 } 470 471 /*package*/ static float native_measureText(Paint thisPaint, String text) { 472 return native_measureText(thisPaint, text.toCharArray(), 0, text.length()); 473 } 474 475 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count, 476 float maxWidth, float[] measuredWidth) { 477 // FIXME 478 throw new UnsupportedOperationException(); 479 } 480 481 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards, 482 float maxWidth, float[] measuredWidth) { 483 // FIXME 484 throw new UnsupportedOperationException(); 485 } 486 487 488 /*package*/ static int native_init() { 489 Paint_Delegate newDelegate = new Paint_Delegate(); 490 return sManager.addDelegate(newDelegate); 491 } 492 493 /*package*/ static int native_initWithPaint(int paint) { 494 // get the delegate from the native int. 495 Paint_Delegate delegate = sManager.getDelegate(paint); 496 if (delegate == null) { 497 assert false; 498 return 0; 499 } 500 501 Paint_Delegate newDelegate = new Paint_Delegate(delegate); 502 return sManager.addDelegate(newDelegate); 503 } 504 505 /*package*/ static void native_reset(int native_object) { 506 // get the delegate from the native int. 507 Paint_Delegate delegate = sManager.getDelegate(native_object); 508 if (delegate == null) { 509 assert false; 510 return; 511 } 512 513 delegate.reset(); 514 } 515 516 /*package*/ static void native_set(int native_dst, int native_src) { 517 // get the delegate from the native int. 518 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst); 519 if (delegate_dst == null) { 520 assert false; 521 return; 522 } 523 524 // get the delegate from the native int. 525 Paint_Delegate delegate_src = sManager.getDelegate(native_src); 526 if (delegate_src == null) { 527 assert false; 528 return; 529 } 530 531 delegate_dst.set(delegate_src); 532 } 533 534 /*package*/ static int native_getStyle(int native_object) { 535 // get the delegate from the native int. 536 Paint_Delegate delegate = sManager.getDelegate(native_object); 537 if (delegate == null) { 538 assert false; 539 return 0; 540 } 541 542 return delegate.mStyle; 543 } 544 545 /*package*/ static void native_setStyle(int native_object, int style) { 546 // get the delegate from the native int. 547 Paint_Delegate delegate = sManager.getDelegate(native_object); 548 if (delegate == null) { 549 assert false; 550 return; 551 } 552 553 delegate.mStyle = style; 554 } 555 556 /*package*/ static int native_getStrokeCap(int native_object) { 557 // get the delegate from the native int. 558 Paint_Delegate delegate = sManager.getDelegate(native_object); 559 if (delegate == null) { 560 assert false; 561 return 0; 562 } 563 564 return delegate.mCap; 565 } 566 567 /*package*/ static void native_setStrokeCap(int native_object, int cap) { 568 // get the delegate from the native int. 569 Paint_Delegate delegate = sManager.getDelegate(native_object); 570 if (delegate == null) { 571 assert false; 572 return; 573 } 574 575 delegate.mCap = cap; 576 } 577 578 /*package*/ static int native_getStrokeJoin(int native_object) { 579 // get the delegate from the native int. 580 Paint_Delegate delegate = sManager.getDelegate(native_object); 581 if (delegate == null) { 582 assert false; 583 return 0; 584 } 585 586 return delegate.mJoin; 587 } 588 589 /*package*/ static void native_setStrokeJoin(int native_object, int join) { 590 // get the delegate from the native int. 591 Paint_Delegate delegate = sManager.getDelegate(native_object); 592 if (delegate == null) { 593 assert false; 594 return; 595 } 596 597 delegate.mJoin = join; 598 } 599 600 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) { 601 // FIXME 602 throw new UnsupportedOperationException(); 603 } 604 605 /*package*/ static int native_setShader(int native_object, int shader) { 606 // get the delegate from the native int. 607 Paint_Delegate delegate = sManager.getDelegate(native_object); 608 if (delegate == null) { 609 assert false; 610 return shader; 611 } 612 613 return delegate.mShader = shader; 614 } 615 616 /*package*/ static int native_setColorFilter(int native_object, int filter) { 617 // get the delegate from the native int. 618 Paint_Delegate delegate = sManager.getDelegate(native_object); 619 if (delegate == null) { 620 assert false; 621 return filter; 622 } 623 624 return delegate.mColorFilter = filter; 625 } 626 627 /*package*/ static int native_setXfermode(int native_object, int xfermode) { 628 // get the delegate from the native int. 629 Paint_Delegate delegate = sManager.getDelegate(native_object); 630 if (delegate == null) { 631 assert false; 632 return xfermode; 633 } 634 635 return delegate.mXfermode = xfermode; 636 } 637 638 /*package*/ static int native_setPathEffect(int native_object, int effect) { 639 // get the delegate from the native int. 640 Paint_Delegate delegate = sManager.getDelegate(native_object); 641 if (delegate == null) { 642 assert false; 643 return effect; 644 } 645 646 return delegate.mPathEffect = effect; 647 } 648 649 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) { 650 // get the delegate from the native int. 651 Paint_Delegate delegate = sManager.getDelegate(native_object); 652 if (delegate == null) { 653 assert false; 654 return maskfilter; 655 } 656 657 return delegate.mMaskFilter = maskfilter; 658 } 659 660 /*package*/ static int native_setTypeface(int native_object, int typeface) { 661 // get the delegate from the native int. 662 Paint_Delegate delegate = sManager.getDelegate(native_object); 663 if (delegate == null) { 664 assert false; 665 return 0; 666 } 667 668 delegate.mTypeface = typeface; 669 delegate.updateFontObject(); 670 return delegate.mTypeface; 671 } 672 673 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) { 674 // FIXME 675 throw new UnsupportedOperationException(); 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 819 private Paint_Delegate(Paint_Delegate paint) { 820 set(paint); 821 } 822 823 private void set(Paint_Delegate paint) { 824 mFlags = paint.mFlags; 825 mColor = paint.mColor; 826 mStyle = paint.mStyle; 827 mCap = paint.mCap; 828 mJoin = paint.mJoin; 829 mTextAlign = paint.mTextAlign; 830 mTypeface = paint.mTypeface; 831 mStrokeWidth = paint.mStrokeWidth; 832 mStrokeMiter = paint.mStrokeMiter; 833 mTextSize = paint.mTextSize; 834 mTextScaleX = paint.mTextScaleX; 835 mTextSkewX = paint.mTextSkewX; 836 mXfermode = paint.mXfermode; 837 mColorFilter = paint.mColorFilter; 838 mShader = paint.mShader; 839 mPathEffect = paint.mPathEffect; 840 mMaskFilter = paint.mMaskFilter; 841 updateFontObject(); 842 } 843 844 private void reset() { 845 mFlags = Paint.DEFAULT_PAINT_FLAGS; 846 mColor = 0; 847 mStyle = 0; 848 mCap = 0; 849 mJoin = 0; 850 mTextAlign = 0; 851 mTypeface = Typeface.sDefaults[0].native_instance; 852 mStrokeWidth = 1.f; 853 mStrokeMiter = 2.f; 854 mTextSize = 20.f; 855 mTextScaleX = 1.f; 856 mTextSkewX = 0.f; 857 mXfermode = 0; 858 mColorFilter = 0; 859 mShader = 0; 860 mPathEffect = 0; 861 mMaskFilter = 0; 862 updateFontObject(); 863 } 864 865 /** 866 * Update the {@link Font} object from the typeface, text size and scaling 867 */ 868 private void updateFontObject() { 869 if (mTypeface != 0) { 870 // Get the fonts from the TypeFace object. 871 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); 872 873 // create new font objects as well as FontMetrics, based on the current text size 874 // and skew info. 875 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); 876 for (Font font : fonts) { 877 FontInfo info = new FontInfo(); 878 info.mFont = font.deriveFont(mTextSize); 879 if (mTextScaleX != 1.0 || mTextSkewX != 0) { 880 // TODO: support skew 881 info.mFont = info.mFont.deriveFont(new AffineTransform( 882 mTextScaleX, mTextSkewX, 0, 0, 1, 0)); 883 } 884 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); 885 886 infoList.add(info); 887 } 888 889 mFonts = Collections.unmodifiableList(infoList); 890 } 891 } 892 893 /*package*/ float measureText(char[] text, int index, int count) { 894 if (mFonts.size() > 0) { 895 FontInfo mainFont = mFonts.get(0); 896 int i = index; 897 int lastIndex = index + count; 898 float total = 0f; 899 while (i < lastIndex) { 900 // always start with the main font. 901 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); 902 if (upTo == -1) { 903 // shortcut to exit 904 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); 905 } else if (upTo > 0) { 906 total += mainFont.mMetrics.charsWidth(text, i, upTo - i); 907 i = upTo; 908 // don't call continue at this point. Since it is certain the main font 909 // cannot display the font a index upTo (now ==i), we move on to the 910 // fallback fonts directly. 911 } 912 913 // no char supported, attempt to read the next char(s) with the 914 // fallback font. In this case we only test the first character 915 // and then go back to test with the main font. 916 // Special test for 2-char characters. 917 boolean foundFont = false; 918 for (int f = 1 ; f < mFonts.size() ; f++) { 919 FontInfo fontInfo = mFonts.get(f); 920 921 // need to check that the font can display the character. We test 922 // differently if the char is a high surrogate. 923 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; 924 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); 925 if (upTo == -1) { 926 total += fontInfo.mMetrics.charsWidth(text, i, charCount); 927 i += charCount; 928 foundFont = true; 929 break; 930 931 } 932 } 933 934 // in case no font can display the char, measure it with the main font. 935 if (foundFont == false) { 936 int size = Character.isHighSurrogate(text[i]) ? 2 : 1; 937 total += mainFont.mMetrics.charsWidth(text, i, size); 938 i += size; 939 } 940 } 941 } 942 943 return 0; 944 945 } 946 947 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) { 948 // get the delegate from the native int. 949 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); 950 if (delegate == null) { 951 assert false; 952 return; 953 } 954 955 if (flagValue) { 956 delegate.mFlags |= flagMask; 957 } else { 958 delegate.mFlags &= ~flagMask; 959 } 960 } 961} 962