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