blob: 6e90bddc426dcdc28cfc8cc83fb00e5d1e0d1b16 [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
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700157 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
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700177 // ---- 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) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700202 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700203 }
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
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700263 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700264 }
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) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700404 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700426 }
427
428 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700429 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700451 }
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
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700465 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700466 }
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) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700607 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700615 }
616
617 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700618 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700626 }
627
628 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700629 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700637 }
638
639 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700640 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700648 }
649
650 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700651 // 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;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700659 }
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
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700686 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700687 }
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
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700697 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700698 }
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) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700720 // 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) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700728 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700729 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
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700759 }
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) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700764 // 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);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700771 }
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;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700833 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700834 mTypeface = paint.mTypeface;
835 mStrokeWidth = paint.mStrokeWidth;
836 mStrokeMiter = paint.mStrokeMiter;
837 mTextSize = paint.mTextSize;
838 mTextScaleX = paint.mTextScaleX;
839 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700840 mXfermode = paint.mXfermode;
841 mColorFilter = paint.mColorFilter;
842 mShader = paint.mShader;
843 mPathEffect = paint.mPathEffect;
844 mMaskFilter = paint.mMaskFilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700845 }
846
847 private void reset() {
848 mFlags = Paint.DEFAULT_PAINT_FLAGS;
849 mColor = 0;
850 mStyle = 0;
851 mCap = 0;
852 mJoin = 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700853 mTextAlign = 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700854 mTypeface = 0;
855 mStrokeWidth = 1.f;
856 mStrokeMiter = 2.f;
857 mTextSize = 20.f;
858 mTextScaleX = 1.f;
859 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700860 mXfermode = 0;
861 mColorFilter = 0;
862 mShader = 0;
863 mPathEffect = 0;
864 mMaskFilter = 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700865 }
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
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700895 /*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
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700949 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}