blob: 6074bd3c8aa1286cf53e5821bc3d5d85f835530a [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
Xavier Ducroheta313b652010-11-01 18:45:20 -070080 private int mXfermode;
81 private int mColorFilter;
82 private int mShader;
83 private int mPathEffect;
84 private int mMaskFilter;
85
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070086
87 // ---- Public Helper methods ----
88
Xavier Ducrohet37f21802010-11-01 16:17:18 -070089 public static Paint_Delegate getDelegate(int native_paint) {
90 return sManager.getDelegate(native_paint);
91 }
92
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070093 /**
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
Xavier Ducroheta313b652010-11-01 18:45:20 -0700101 public boolean isAntiAliased() {
102 return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
103 }
104
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700105 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 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700156
157 // ---- native methods ----
158
159 /*package*/ static int getFlags(Paint thisPaint) {
160 // get the delegate from the native int.
161 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
162 if (delegate == null) {
163 assert false;
164 return 0;
165 }
166
167 return delegate.mFlags;
168 }
169
170 /*package*/ static void setFlags(Paint thisPaint, int flags) {
171 // get the delegate from the native int.
172 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
173 if (delegate == null) {
174 assert false;
175 return;
176 }
177
178 delegate.mFlags = flags;
179 }
180
181 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700182 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700183 }
184
185 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
186 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
187 }
188
189 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
190 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
191 }
192
193 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
194 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
195 }
196
197 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
198 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
199 }
200
201 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
202 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
203 }
204
205 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
206 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
207 }
208
209 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
210 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
211 }
212
213 /*package*/ static int getColor(Paint thisPaint) {
214 // get the delegate from the native int.
215 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
216 if (delegate == null) {
217 assert false;
218 return 0;
219 }
220
221 return delegate.mColor;
222 }
223
224 /*package*/ static void setColor(Paint thisPaint, int color) {
225 // get the delegate from the native int.
226 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
227 if (delegate == null) {
228 assert false;
229 return;
230 }
231
232 delegate.mColor = color;
233 }
234
235 /*package*/ static int getAlpha(Paint thisPaint) {
236 // get the delegate from the native int.
237 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
238 if (delegate == null) {
239 assert false;
240 return 0;
241 }
242
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700243 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700244 }
245
246 /*package*/ static void setAlpha(Paint thisPaint, int a) {
247 // get the delegate from the native int.
248 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
249 if (delegate == null) {
250 assert false;
251 return;
252 }
253
254 delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF);
255 }
256
257 /*package*/ static float getStrokeWidth(Paint thisPaint) {
258 // get the delegate from the native int.
259 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
260 if (delegate == null) {
261 assert false;
262 return 1.f;
263 }
264
265 return delegate.mStrokeWidth;
266 }
267
268 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
269 // get the delegate from the native int.
270 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
271 if (delegate == null) {
272 assert false;
273 return;
274 }
275
276 delegate.mStrokeWidth = width;
277 }
278
279 /*package*/ static float getStrokeMiter(Paint thisPaint) {
280 // get the delegate from the native int.
281 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
282 if (delegate == null) {
283 assert false;
284 return 1.f;
285 }
286
287 return delegate.mStrokeMiter;
288 }
289
290 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
291 // get the delegate from the native int.
292 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
293 if (delegate == null) {
294 assert false;
295 return;
296 }
297
298 delegate.mStrokeMiter = miter;
299 }
300
301 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
302 int color) {
303 // FIXME
304 throw new UnsupportedOperationException();
305 }
306
307 /*package*/ static float getTextSize(Paint thisPaint) {
308 // get the delegate from the native int.
309 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
310 if (delegate == null) {
311 assert false;
312 return 1.f;
313 }
314
315 return delegate.mTextSize;
316 }
317
318 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
319 // get the delegate from the native int.
320 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
321 if (delegate == null) {
322 assert false;
323 return;
324 }
325
326 delegate.mTextSize = textSize;
327 }
328
329 /*package*/ static float getTextScaleX(Paint thisPaint) {
330 // get the delegate from the native int.
331 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
332 if (delegate == null) {
333 assert false;
334 return 1.f;
335 }
336
337 return delegate.mTextScaleX;
338 }
339
340 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
341 // get the delegate from the native int.
342 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
343 if (delegate == null) {
344 assert false;
345 return;
346 }
347
348 delegate.mTextScaleX = scaleX;
349 }
350
351 /*package*/ static float getTextSkewX(Paint thisPaint) {
352 // get the delegate from the native int.
353 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
354 if (delegate == null) {
355 assert false;
356 return 1.f;
357 }
358
359 return delegate.mTextSkewX;
360 }
361
362 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
363 // get the delegate from the native int.
364 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
365 if (delegate == null) {
366 assert false;
367 return;
368 }
369
370 delegate.mTextSkewX = skewX;
371 }
372
373 /*package*/ static float ascent(Paint thisPaint) {
374 // FIXME
375 throw new UnsupportedOperationException();
376 }
377
378 /*package*/ static float descent(Paint thisPaint) {
379 // FIXME
380 throw new UnsupportedOperationException();
381 }
382
383 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700384 // get the delegate
385 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
386 if (delegate == null) {
387 assert false;
388 return 0;
389 }
390
391 if (delegate.mFonts.size() > 0) {
392 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
393 if (metrics != null) {
394 // Android expects negative ascent so we invert the value from Java.
395 metrics.top = - javaMetrics.getMaxAscent();
396 metrics.ascent = - javaMetrics.getAscent();
397 metrics.descent = javaMetrics.getDescent();
398 metrics.bottom = javaMetrics.getMaxDescent();
399 metrics.leading = javaMetrics.getLeading();
400 }
401
402 return javaMetrics.getHeight();
403 }
404
405 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700406 }
407
408 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700409 // get the delegate
410 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
411 if (delegate == null) {
412 assert false;
413 return 0;
414 }
415
416 if (delegate.mFonts.size() > 0) {
417 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
418 if (fmi != null) {
419 // Android expects negative ascent so we invert the value from Java.
420 fmi.top = - javaMetrics.getMaxAscent();
421 fmi.ascent = - javaMetrics.getAscent();
422 fmi.descent = javaMetrics.getDescent();
423 fmi.bottom = javaMetrics.getMaxDescent();
424 fmi.leading = javaMetrics.getLeading();
425 }
426
427 return javaMetrics.getHeight();
428 }
429
430 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700431 }
432
433 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
434 int count) {
435 // WARNING: the logic in this method is similar to Canvas.drawText.
436 // Any change to this method should be reflected in Canvas.drawText
437
438 // get the delegate
439 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
440 if (delegate == null) {
441 assert false;
442 return 0;
443 }
444
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700445 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700446 }
447
448 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
449 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
450 }
451
452 /*package*/ static float native_measureText(Paint thisPaint, String text) {
453 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
454 }
455
456 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
457 float maxWidth, float[] measuredWidth) {
458 // FIXME
459 throw new UnsupportedOperationException();
460 }
461
462 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
463 float maxWidth, float[] measuredWidth) {
464 // FIXME
465 throw new UnsupportedOperationException();
466 }
467
468
469 /*package*/ static int native_init() {
470 Paint_Delegate newDelegate = new Paint_Delegate();
471 return sManager.addDelegate(newDelegate);
472 }
473
474 /*package*/ static int native_initWithPaint(int paint) {
475 // get the delegate from the native int.
476 Paint_Delegate delegate = sManager.getDelegate(paint);
477 if (delegate == null) {
478 assert false;
479 return 0;
480 }
481
482 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
483 return sManager.addDelegate(newDelegate);
484 }
485
486 /*package*/ static void native_reset(int native_object) {
487 // get the delegate from the native int.
488 Paint_Delegate delegate = sManager.getDelegate(native_object);
489 if (delegate == null) {
490 assert false;
491 return;
492 }
493
494 delegate.reset();
495 }
496
497 /*package*/ static void native_set(int native_dst, int native_src) {
498 // get the delegate from the native int.
499 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
500 if (delegate_dst == null) {
501 assert false;
502 return;
503 }
504
505 // get the delegate from the native int.
506 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
507 if (delegate_src == null) {
508 assert false;
509 return;
510 }
511
512 delegate_dst.set(delegate_src);
513 }
514
515 /*package*/ static int native_getStyle(int native_object) {
516 // get the delegate from the native int.
517 Paint_Delegate delegate = sManager.getDelegate(native_object);
518 if (delegate == null) {
519 assert false;
520 return 0;
521 }
522
523 return delegate.mStyle;
524 }
525
526 /*package*/ static void native_setStyle(int native_object, int style) {
527 // get the delegate from the native int.
528 Paint_Delegate delegate = sManager.getDelegate(native_object);
529 if (delegate == null) {
530 assert false;
531 return;
532 }
533
534 delegate.mStyle = style;
535 }
536
537 /*package*/ static int native_getStrokeCap(int native_object) {
538 // get the delegate from the native int.
539 Paint_Delegate delegate = sManager.getDelegate(native_object);
540 if (delegate == null) {
541 assert false;
542 return 0;
543 }
544
545 return delegate.mCap;
546 }
547
548 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
549 // get the delegate from the native int.
550 Paint_Delegate delegate = sManager.getDelegate(native_object);
551 if (delegate == null) {
552 assert false;
553 return;
554 }
555
556 delegate.mCap = cap;
557 }
558
559 /*package*/ static int native_getStrokeJoin(int native_object) {
560 // get the delegate from the native int.
561 Paint_Delegate delegate = sManager.getDelegate(native_object);
562 if (delegate == null) {
563 assert false;
564 return 0;
565 }
566
567 return delegate.mJoin;
568 }
569
570 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
571 // get the delegate from the native int.
572 Paint_Delegate delegate = sManager.getDelegate(native_object);
573 if (delegate == null) {
574 assert false;
575 return;
576 }
577
578 delegate.mJoin = join;
579 }
580
581 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
582 // FIXME
583 throw new UnsupportedOperationException();
584 }
585
586 /*package*/ static int native_setShader(int native_object, int shader) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700587 // get the delegate from the native int.
588 Paint_Delegate delegate = sManager.getDelegate(native_object);
589 if (delegate == null) {
590 assert false;
591 return shader;
592 }
593
594 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700595 }
596
597 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700598 // get the delegate from the native int.
599 Paint_Delegate delegate = sManager.getDelegate(native_object);
600 if (delegate == null) {
601 assert false;
602 return filter;
603 }
604
605 return delegate.mColorFilter = filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700606 }
607
608 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700609 // get the delegate from the native int.
610 Paint_Delegate delegate = sManager.getDelegate(native_object);
611 if (delegate == null) {
612 assert false;
613 return xfermode;
614 }
615
616 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700617 }
618
619 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700620 // get the delegate from the native int.
621 Paint_Delegate delegate = sManager.getDelegate(native_object);
622 if (delegate == null) {
623 assert false;
624 return effect;
625 }
626
627 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700628 }
629
630 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700631 // get the delegate from the native int.
632 Paint_Delegate delegate = sManager.getDelegate(native_object);
633 if (delegate == null) {
634 assert false;
635 return maskfilter;
636 }
637
638 return delegate.mMaskFilter = maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700639 }
640
641 /*package*/ static int native_setTypeface(int native_object, int typeface) {
642 // get the delegate from the native int.
643 Paint_Delegate delegate = sManager.getDelegate(native_object);
644 if (delegate == null) {
645 assert false;
646 return 0;
647 }
648
649 return delegate.mTypeface = typeface;
650 }
651
652 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
653 // FIXME
654 throw new UnsupportedOperationException();
655 }
656
657
658 /*package*/ static int native_getTextAlign(int native_object) {
659 // get the delegate from the native int.
660 Paint_Delegate delegate = sManager.getDelegate(native_object);
661 if (delegate == null) {
662 assert false;
663 return 0;
664 }
665
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700666 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700667 }
668
669 /*package*/ static void native_setTextAlign(int native_object, int align) {
670 // get the delegate from the native int.
671 Paint_Delegate delegate = sManager.getDelegate(native_object);
672 if (delegate == null) {
673 assert false;
674 return;
675 }
676
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700677 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700678 }
679
680 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
681 // FIXME
682 throw new UnsupportedOperationException();
683 }
684
685 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
686 int count, float[] widths) {
687 // FIXME
688 throw new UnsupportedOperationException();
689 }
690
691 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
692 int end, float[] widths) {
693 // FIXME
694 throw new UnsupportedOperationException();
695 }
696
697 /*package*/ static float native_getTextRunAdvances(int native_object,
698 char[] text, int index, int count, int contextIndex, int contextCount,
699 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700700 // get the delegate from the native int.
701 Paint_Delegate delegate = sManager.getDelegate(native_object);
702 if (delegate == null) {
703 assert false;
704 return 0.f;
705 }
706
707 if (delegate.mFonts.size() > 0) {
708 // FIXME: handle multi-char characters.
709 // see measureText.
710 float totalAdvance = 0;
711 for (int i = 0; i < count; i++) {
712 char c = text[i + index];
713 boolean found = false;
714 for (FontInfo info : delegate.mFonts) {
715 if (info.mFont.canDisplay(c)) {
716 float adv = info.mMetrics.charWidth(c);
717 totalAdvance += adv;
718 if (advances != null) {
719 advances[i] = adv;
720 }
721
722 found = true;
723 break;
724 }
725 }
726
727 if (found == false) {
728 // no advance for this char.
729 if (advances != null) {
730 advances[i] = 0.f;
731 }
732 }
733 }
734
735 return totalAdvance;
736 }
737
738 return 0;
739
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700740 }
741
742 /*package*/ static float native_getTextRunAdvances(int native_object,
743 String text, int start, int end, int contextStart, int contextEnd,
744 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700745 // FIXME: support contextStart, contextEnd and direction flag
746 int count = end - start;
747 char[] buffer = TemporaryBuffer.obtain(count);
748 TextUtils.getChars(text, start, end, buffer, 0);
749
750 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
751 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700752 }
753
754 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
755 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
756 // FIXME
757 throw new UnsupportedOperationException();
758 }
759
760 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
761 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
762 // FIXME
763 throw new UnsupportedOperationException();
764 }
765
766 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
767 char[] text, int index, int count, float x, float y, int path) {
768 // FIXME
769 throw new UnsupportedOperationException();
770 }
771
772 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
773 String text, int start, int end, float x, float y, int path) {
774 // FIXME
775 throw new UnsupportedOperationException();
776 }
777
778 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
779 int end, Rect bounds) {
780 // FIXME
781 throw new UnsupportedOperationException();
782 }
783
784 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
785 int count, Rect bounds) {
786 // FIXME
787 throw new UnsupportedOperationException();
788 }
789
790 /*package*/ static void finalizer(int nativePaint) {
791 sManager.removeDelegate(nativePaint);
792 }
793
794 // ---- Private delegate/helper methods ----
795
796 private Paint_Delegate() {
797 reset();
798
799 mTypeface = Typeface.sDefaults[0].native_instance;
800 updateFontObject();
801 }
802
803 private Paint_Delegate(Paint_Delegate paint) {
804 set(paint);
805 updateFontObject();
806 }
807
808 private void set(Paint_Delegate paint) {
809 mFlags = paint.mFlags;
810 mColor = paint.mColor;
811 mStyle = paint.mStyle;
812 mCap = paint.mCap;
813 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700814 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700815 mTypeface = paint.mTypeface;
816 mStrokeWidth = paint.mStrokeWidth;
817 mStrokeMiter = paint.mStrokeMiter;
818 mTextSize = paint.mTextSize;
819 mTextScaleX = paint.mTextScaleX;
820 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700821 mXfermode = paint.mXfermode;
822 mColorFilter = paint.mColorFilter;
823 mShader = paint.mShader;
824 mPathEffect = paint.mPathEffect;
825 mMaskFilter = paint.mMaskFilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700826 }
827
828 private void reset() {
829 mFlags = Paint.DEFAULT_PAINT_FLAGS;
830 mColor = 0;
831 mStyle = 0;
832 mCap = 0;
833 mJoin = 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700834 mTextAlign = 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700835 mTypeface = 0;
836 mStrokeWidth = 1.f;
837 mStrokeMiter = 2.f;
838 mTextSize = 20.f;
839 mTextScaleX = 1.f;
840 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700841 mXfermode = 0;
842 mColorFilter = 0;
843 mShader = 0;
844 mPathEffect = 0;
845 mMaskFilter = 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700846 }
847
848 /**
849 * Update the {@link Font} object from the typeface, text size and scaling
850 */
851 private void updateFontObject() {
852 if (mTypeface != 0) {
853 // Get the fonts from the TypeFace object.
854 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
855
856 // create new font objects as well as FontMetrics, based on the current text size
857 // and skew info.
858 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
859 for (Font font : fonts) {
860 FontInfo info = new FontInfo();
861 info.mFont = font.deriveFont(mTextSize);
862 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
863 // TODO: support skew
864 info.mFont = info.mFont.deriveFont(new AffineTransform(
865 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
866 }
867 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
868
869 infoList.add(info);
870 }
871
872 mFonts = Collections.unmodifiableList(infoList);
873 }
874 }
875
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700876 /*package*/ float measureText(char[] text, int index, int count) {
877 if (mFonts.size() > 0) {
878 FontInfo mainFont = mFonts.get(0);
879 int i = index;
880 int lastIndex = index + count;
881 float total = 0f;
882 while (i < lastIndex) {
883 // always start with the main font.
884 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
885 if (upTo == -1) {
886 // shortcut to exit
887 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
888 } else if (upTo > 0) {
889 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
890 i = upTo;
891 // don't call continue at this point. Since it is certain the main font
892 // cannot display the font a index upTo (now ==i), we move on to the
893 // fallback fonts directly.
894 }
895
896 // no char supported, attempt to read the next char(s) with the
897 // fallback font. In this case we only test the first character
898 // and then go back to test with the main font.
899 // Special test for 2-char characters.
900 boolean foundFont = false;
901 for (int f = 1 ; f < mFonts.size() ; f++) {
902 FontInfo fontInfo = mFonts.get(f);
903
904 // need to check that the font can display the character. We test
905 // differently if the char is a high surrogate.
906 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
907 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
908 if (upTo == -1) {
909 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
910 i += charCount;
911 foundFont = true;
912 break;
913
914 }
915 }
916
917 // in case no font can display the char, measure it with the main font.
918 if (foundFont == false) {
919 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
920 total += mainFont.mMetrics.charsWidth(text, i, size);
921 i += size;
922 }
923 }
924 }
925
926 return 0;
927
928 }
929
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700930 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
931 // get the delegate from the native int.
932 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
933 if (delegate == null) {
934 assert false;
935 return;
936 }
937
938 if (flagValue) {
939 delegate.mFlags |= flagMask;
940 } else {
941 delegate.mFlags &= ~flagMask;
942 }
943 }
944}