blob: 0a597ca2f5f7721f4eb5d8f0628c05e4f6c57ba5 [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
Xavier Ducrohet3bd98982010-11-09 18:25:03 -080019import com.android.layoutlib.bridge.impl.DelegateManager;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070020
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
Xavier Ducrohet66225222010-12-21 01:33:04 -0800117 public int getAlpha() {
118 return mColor >>> 24;
119 }
120
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700121 public int getTextAlign() {
122 return mTextAlign;
123 }
124
125 public float getStrokeWidth() {
126 return mStrokeWidth;
127 }
128
Xavier Ducrohet66225222010-12-21 01:33:04 -0800129 /**
130 * returns the value of stroke miter needed by the java api.
131 */
132 public float getJavaStrokeMiter() {
133 return mStrokeMiter * mStrokeWidth;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700134 }
135
136 public int getJavaCap() {
137 switch (Paint.sCapArray[mCap]) {
138 case BUTT:
139 return BasicStroke.CAP_BUTT;
140 case ROUND:
141 return BasicStroke.CAP_ROUND;
142 default:
143 case SQUARE:
144 return BasicStroke.CAP_SQUARE;
145 }
146 }
147
148 public int getJavaJoin() {
149 switch (Paint.sJoinArray[mJoin]) {
150 default:
151 case MITER:
152 return BasicStroke.JOIN_MITER;
153 case ROUND:
154 return BasicStroke.JOIN_ROUND;
155 case BEVEL:
156 return BasicStroke.JOIN_BEVEL;
157 }
158 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700159
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700160 public int getXfermode() {
161 return mXfermode;
162 }
163
164 public int getColorFilter() {
165 return mColorFilter;
166 }
167
168 public int getShader() {
169 return mShader;
170 }
171
172 public int getPathEffect() {
173 return mPathEffect;
174 }
175
176 public int getMaskFilter() {
177 return mMaskFilter;
178 }
179
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700180 // ---- native methods ----
181
182 /*package*/ static int getFlags(Paint thisPaint) {
183 // get the delegate from the native int.
184 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
185 if (delegate == null) {
186 assert false;
187 return 0;
188 }
189
190 return delegate.mFlags;
191 }
192
193 /*package*/ static void setFlags(Paint thisPaint, int flags) {
194 // get the delegate from the native int.
195 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
196 if (delegate == null) {
197 assert false;
198 return;
199 }
200
201 delegate.mFlags = flags;
202 }
203
204 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700205 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700206 }
207
208 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
209 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
210 }
211
212 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
213 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
214 }
215
216 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
217 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
218 }
219
220 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
221 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
222 }
223
224 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
225 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
226 }
227
228 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
229 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
230 }
231
232 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
233 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
234 }
235
236 /*package*/ static int getColor(Paint thisPaint) {
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 0;
242 }
243
244 return delegate.mColor;
245 }
246
247 /*package*/ static void setColor(Paint thisPaint, int color) {
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;
253 }
254
255 delegate.mColor = color;
256 }
257
258 /*package*/ static int getAlpha(Paint thisPaint) {
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 0;
264 }
265
Xavier Ducrohet66225222010-12-21 01:33:04 -0800266 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700267 }
268
269 /*package*/ static void setAlpha(Paint thisPaint, int a) {
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;
275 }
276
277 delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF);
278 }
279
280 /*package*/ static float getStrokeWidth(Paint thisPaint) {
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 1.f;
286 }
287
288 return delegate.mStrokeWidth;
289 }
290
291 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
292 // get the delegate from the native int.
293 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
294 if (delegate == null) {
295 assert false;
296 return;
297 }
298
299 delegate.mStrokeWidth = width;
300 }
301
302 /*package*/ static float getStrokeMiter(Paint thisPaint) {
303 // get the delegate from the native int.
304 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
305 if (delegate == null) {
306 assert false;
307 return 1.f;
308 }
309
310 return delegate.mStrokeMiter;
311 }
312
313 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
314 // get the delegate from the native int.
315 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
316 if (delegate == null) {
317 assert false;
318 return;
319 }
320
321 delegate.mStrokeMiter = miter;
322 }
323
324 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
325 int color) {
326 // FIXME
327 throw new UnsupportedOperationException();
328 }
329
330 /*package*/ static float getTextSize(Paint thisPaint) {
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 1.f;
336 }
337
338 return delegate.mTextSize;
339 }
340
341 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
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;
347 }
348
349 delegate.mTextSize = textSize;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800350 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700351 }
352
353 /*package*/ static float getTextScaleX(Paint thisPaint) {
354 // get the delegate from the native int.
355 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
356 if (delegate == null) {
357 assert false;
358 return 1.f;
359 }
360
361 return delegate.mTextScaleX;
362 }
363
364 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
365 // get the delegate from the native int.
366 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
367 if (delegate == null) {
368 assert false;
369 return;
370 }
371
372 delegate.mTextScaleX = scaleX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800373 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700374 }
375
376 /*package*/ static float getTextSkewX(Paint thisPaint) {
377 // get the delegate from the native int.
378 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
379 if (delegate == null) {
380 assert false;
381 return 1.f;
382 }
383
384 return delegate.mTextSkewX;
385 }
386
387 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
388 // get the delegate from the native int.
389 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
390 if (delegate == null) {
391 assert false;
392 return;
393 }
394
395 delegate.mTextSkewX = skewX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800396 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700397 }
398
399 /*package*/ static float ascent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800400 // get the delegate
401 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
402 if (delegate == null) {
403 assert false;
404 return 0;
405 }
406
407 if (delegate.mFonts.size() > 0) {
408 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
409 // Android expects negative ascent so we invert the value from Java.
410 return - javaMetrics.getAscent();
411 }
412
413 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700414 }
415
416 /*package*/ static float descent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800417 // get the delegate
418 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
419 if (delegate == null) {
420 assert false;
421 return 0;
422 }
423
424 if (delegate.mFonts.size() > 0) {
425 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
426 return javaMetrics.getDescent();
427 }
428
429 return 0;
430
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700431 }
432
433 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700434 // get the delegate
435 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
436 if (delegate == null) {
437 assert false;
438 return 0;
439 }
440
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800441 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700442 }
443
444 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700445 // get the delegate
446 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
447 if (delegate == null) {
448 assert false;
449 return 0;
450 }
451
452 if (delegate.mFonts.size() > 0) {
453 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
454 if (fmi != null) {
455 // Android expects negative ascent so we invert the value from Java.
456 fmi.top = - javaMetrics.getMaxAscent();
457 fmi.ascent = - javaMetrics.getAscent();
458 fmi.descent = javaMetrics.getDescent();
459 fmi.bottom = javaMetrics.getMaxDescent();
460 fmi.leading = javaMetrics.getLeading();
461 }
462
463 return javaMetrics.getHeight();
464 }
465
466 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700467 }
468
469 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
470 int count) {
471 // WARNING: the logic in this method is similar to Canvas.drawText.
472 // Any change to this method should be reflected in Canvas.drawText
473
474 // get the delegate
475 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
476 if (delegate == null) {
477 assert false;
478 return 0;
479 }
480
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700481 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700482 }
483
484 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
485 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
486 }
487
488 /*package*/ static float native_measureText(Paint thisPaint, String text) {
489 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
490 }
491
492 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
493 float maxWidth, float[] measuredWidth) {
494 // FIXME
495 throw new UnsupportedOperationException();
496 }
497
498 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
499 float maxWidth, float[] measuredWidth) {
500 // FIXME
501 throw new UnsupportedOperationException();
502 }
503
504
505 /*package*/ static int native_init() {
506 Paint_Delegate newDelegate = new Paint_Delegate();
507 return sManager.addDelegate(newDelegate);
508 }
509
510 /*package*/ static int native_initWithPaint(int paint) {
511 // get the delegate from the native int.
512 Paint_Delegate delegate = sManager.getDelegate(paint);
513 if (delegate == null) {
514 assert false;
515 return 0;
516 }
517
518 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
519 return sManager.addDelegate(newDelegate);
520 }
521
522 /*package*/ static void native_reset(int native_object) {
523 // get the delegate from the native int.
524 Paint_Delegate delegate = sManager.getDelegate(native_object);
525 if (delegate == null) {
526 assert false;
527 return;
528 }
529
530 delegate.reset();
531 }
532
533 /*package*/ static void native_set(int native_dst, int native_src) {
534 // get the delegate from the native int.
535 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
536 if (delegate_dst == null) {
537 assert false;
538 return;
539 }
540
541 // get the delegate from the native int.
542 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
543 if (delegate_src == null) {
544 assert false;
545 return;
546 }
547
548 delegate_dst.set(delegate_src);
549 }
550
551 /*package*/ static int native_getStyle(int native_object) {
552 // get the delegate from the native int.
553 Paint_Delegate delegate = sManager.getDelegate(native_object);
554 if (delegate == null) {
555 assert false;
556 return 0;
557 }
558
559 return delegate.mStyle;
560 }
561
562 /*package*/ static void native_setStyle(int native_object, int style) {
563 // get the delegate from the native int.
564 Paint_Delegate delegate = sManager.getDelegate(native_object);
565 if (delegate == null) {
566 assert false;
567 return;
568 }
569
570 delegate.mStyle = style;
571 }
572
573 /*package*/ static int native_getStrokeCap(int native_object) {
574 // get the delegate from the native int.
575 Paint_Delegate delegate = sManager.getDelegate(native_object);
576 if (delegate == null) {
577 assert false;
578 return 0;
579 }
580
581 return delegate.mCap;
582 }
583
584 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
585 // get the delegate from the native int.
586 Paint_Delegate delegate = sManager.getDelegate(native_object);
587 if (delegate == null) {
588 assert false;
589 return;
590 }
591
592 delegate.mCap = cap;
593 }
594
595 /*package*/ static int native_getStrokeJoin(int native_object) {
596 // get the delegate from the native int.
597 Paint_Delegate delegate = sManager.getDelegate(native_object);
598 if (delegate == null) {
599 assert false;
600 return 0;
601 }
602
603 return delegate.mJoin;
604 }
605
606 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
607 // get the delegate from the native int.
608 Paint_Delegate delegate = sManager.getDelegate(native_object);
609 if (delegate == null) {
610 assert false;
611 return;
612 }
613
614 delegate.mJoin = join;
615 }
616
617 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
618 // FIXME
619 throw new UnsupportedOperationException();
620 }
621
622 /*package*/ static int native_setShader(int native_object, int shader) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700623 // get the delegate from the native int.
624 Paint_Delegate delegate = sManager.getDelegate(native_object);
625 if (delegate == null) {
626 assert false;
627 return shader;
628 }
629
630 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700631 }
632
633 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700634 // get the delegate from the native int.
635 Paint_Delegate delegate = sManager.getDelegate(native_object);
636 if (delegate == null) {
637 assert false;
638 return filter;
639 }
640
641 return delegate.mColorFilter = filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700642 }
643
644 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700645 // get the delegate from the native int.
646 Paint_Delegate delegate = sManager.getDelegate(native_object);
647 if (delegate == null) {
648 assert false;
649 return xfermode;
650 }
651
652 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700653 }
654
655 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700656 // get the delegate from the native int.
657 Paint_Delegate delegate = sManager.getDelegate(native_object);
658 if (delegate == null) {
659 assert false;
660 return effect;
661 }
662
663 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700664 }
665
666 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700667 // get the delegate from the native int.
668 Paint_Delegate delegate = sManager.getDelegate(native_object);
669 if (delegate == null) {
670 assert false;
671 return maskfilter;
672 }
673
674 return delegate.mMaskFilter = maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700675 }
676
677 /*package*/ static int native_setTypeface(int native_object, int typeface) {
678 // get the delegate from the native int.
679 Paint_Delegate delegate = sManager.getDelegate(native_object);
680 if (delegate == null) {
681 assert false;
682 return 0;
683 }
684
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800685 delegate.mTypeface = typeface;
686 delegate.updateFontObject();
687 return delegate.mTypeface;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700688 }
689
690 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
691 // FIXME
692 throw new UnsupportedOperationException();
693 }
694
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700695 /*package*/ static int native_getTextAlign(int native_object) {
696 // get the delegate from the native int.
697 Paint_Delegate delegate = sManager.getDelegate(native_object);
698 if (delegate == null) {
699 assert false;
700 return 0;
701 }
702
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700703 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700704 }
705
706 /*package*/ static void native_setTextAlign(int native_object, int align) {
707 // get the delegate from the native int.
708 Paint_Delegate delegate = sManager.getDelegate(native_object);
709 if (delegate == null) {
710 assert false;
711 return;
712 }
713
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700714 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700715 }
716
717 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800718 // get the delegate from the native int.
719 Paint_Delegate delegate = sManager.getDelegate(native_paint);
720 if (delegate == null) {
721 assert false;
722 return 0.f;
723 }
724
725 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700726 }
727
728 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
729 int count, float[] widths) {
730 // FIXME
731 throw new UnsupportedOperationException();
732 }
733
734 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
735 int end, float[] widths) {
736 // FIXME
737 throw new UnsupportedOperationException();
738 }
739
740 /*package*/ static float native_getTextRunAdvances(int native_object,
741 char[] text, int index, int count, int contextIndex, int contextCount,
742 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700743 // get the delegate from the native int.
744 Paint_Delegate delegate = sManager.getDelegate(native_object);
745 if (delegate == null) {
746 assert false;
747 return 0.f;
748 }
749
750 if (delegate.mFonts.size() > 0) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700751 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700752 float totalAdvance = 0;
753 for (int i = 0; i < count; i++) {
754 char c = text[i + index];
755 boolean found = false;
756 for (FontInfo info : delegate.mFonts) {
757 if (info.mFont.canDisplay(c)) {
758 float adv = info.mMetrics.charWidth(c);
759 totalAdvance += adv;
760 if (advances != null) {
761 advances[i] = adv;
762 }
763
764 found = true;
765 break;
766 }
767 }
768
769 if (found == false) {
770 // no advance for this char.
771 if (advances != null) {
772 advances[i] = 0.f;
773 }
774 }
775 }
776
777 return totalAdvance;
778 }
779
780 return 0;
781
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700782 }
783
784 /*package*/ static float native_getTextRunAdvances(int native_object,
785 String text, int start, int end, int contextStart, int contextEnd,
786 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700787 // FIXME: support contextStart, contextEnd and direction flag
788 int count = end - start;
789 char[] buffer = TemporaryBuffer.obtain(count);
790 TextUtils.getChars(text, start, end, buffer, 0);
791
792 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
793 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700794 }
795
796 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
797 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
798 // FIXME
799 throw new UnsupportedOperationException();
800 }
801
802 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
803 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
804 // FIXME
805 throw new UnsupportedOperationException();
806 }
807
808 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
809 char[] text, int index, int count, float x, float y, int path) {
810 // FIXME
811 throw new UnsupportedOperationException();
812 }
813
814 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
815 String text, int start, int end, float x, float y, int path) {
816 // FIXME
817 throw new UnsupportedOperationException();
818 }
819
820 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
821 int end, Rect bounds) {
822 // FIXME
823 throw new UnsupportedOperationException();
824 }
825
826 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
827 int count, Rect bounds) {
828 // FIXME
829 throw new UnsupportedOperationException();
830 }
831
832 /*package*/ static void finalizer(int nativePaint) {
833 sManager.removeDelegate(nativePaint);
834 }
835
836 // ---- Private delegate/helper methods ----
837
838 private Paint_Delegate() {
839 reset();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700840 }
841
842 private Paint_Delegate(Paint_Delegate paint) {
843 set(paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700844 }
845
846 private void set(Paint_Delegate paint) {
847 mFlags = paint.mFlags;
848 mColor = paint.mColor;
849 mStyle = paint.mStyle;
850 mCap = paint.mCap;
851 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700852 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700853 mTypeface = paint.mTypeface;
854 mStrokeWidth = paint.mStrokeWidth;
855 mStrokeMiter = paint.mStrokeMiter;
856 mTextSize = paint.mTextSize;
857 mTextScaleX = paint.mTextScaleX;
858 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700859 mXfermode = paint.mXfermode;
860 mColorFilter = paint.mColorFilter;
861 mShader = paint.mShader;
862 mPathEffect = paint.mPathEffect;
863 mMaskFilter = paint.mMaskFilter;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800864 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700865 }
866
867 private void reset() {
868 mFlags = Paint.DEFAULT_PAINT_FLAGS;
869 mColor = 0;
Xavier Ducrohet66225222010-12-21 01:33:04 -0800870 mStyle = Paint.Style.FILL.nativeInt;
871 mCap = Paint.Cap.BUTT.nativeInt;
872 mJoin = Paint.Join.MITER.nativeInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700873 mTextAlign = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800874 mTypeface = Typeface.sDefaults[0].native_instance;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700875 mStrokeWidth = 1.f;
876 mStrokeMiter = 2.f;
877 mTextSize = 20.f;
878 mTextScaleX = 1.f;
879 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700880 mXfermode = 0;
881 mColorFilter = 0;
882 mShader = 0;
883 mPathEffect = 0;
884 mMaskFilter = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800885 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700886 }
887
888 /**
889 * Update the {@link Font} object from the typeface, text size and scaling
890 */
891 private void updateFontObject() {
892 if (mTypeface != 0) {
893 // Get the fonts from the TypeFace object.
894 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
895
896 // create new font objects as well as FontMetrics, based on the current text size
897 // and skew info.
898 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
899 for (Font font : fonts) {
900 FontInfo info = new FontInfo();
901 info.mFont = font.deriveFont(mTextSize);
902 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
903 // TODO: support skew
904 info.mFont = info.mFont.deriveFont(new AffineTransform(
905 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
906 }
907 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
908
909 infoList.add(info);
910 }
911
912 mFonts = Collections.unmodifiableList(infoList);
913 }
914 }
915
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700916 /*package*/ float measureText(char[] text, int index, int count) {
917 if (mFonts.size() > 0) {
918 FontInfo mainFont = mFonts.get(0);
919 int i = index;
920 int lastIndex = index + count;
921 float total = 0f;
922 while (i < lastIndex) {
923 // always start with the main font.
924 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
925 if (upTo == -1) {
926 // shortcut to exit
927 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
928 } else if (upTo > 0) {
929 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
930 i = upTo;
931 // don't call continue at this point. Since it is certain the main font
932 // cannot display the font a index upTo (now ==i), we move on to the
933 // fallback fonts directly.
934 }
935
936 // no char supported, attempt to read the next char(s) with the
937 // fallback font. In this case we only test the first character
938 // and then go back to test with the main font.
939 // Special test for 2-char characters.
940 boolean foundFont = false;
941 for (int f = 1 ; f < mFonts.size() ; f++) {
942 FontInfo fontInfo = mFonts.get(f);
943
944 // need to check that the font can display the character. We test
945 // differently if the char is a high surrogate.
946 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
947 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
948 if (upTo == -1) {
949 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
950 i += charCount;
951 foundFont = true;
952 break;
953
954 }
955 }
956
957 // in case no font can display the char, measure it with the main font.
958 if (foundFont == false) {
959 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
960 total += mainFont.mMetrics.charsWidth(text, i, size);
961 i += size;
962 }
963 }
964 }
965
966 return 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700967 }
968
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800969 private float getFontMetrics(FontMetrics metrics) {
970 if (mFonts.size() > 0) {
971 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
972 if (metrics != null) {
973 // Android expects negative ascent so we invert the value from Java.
974 metrics.top = - javaMetrics.getMaxAscent();
975 metrics.ascent = - javaMetrics.getAscent();
976 metrics.descent = javaMetrics.getDescent();
977 metrics.bottom = javaMetrics.getMaxDescent();
978 metrics.leading = javaMetrics.getLeading();
979 }
980
981 return javaMetrics.getHeight();
982 }
983
984 return 0;
985 }
986
987
988
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700989 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
990 // get the delegate from the native int.
991 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
992 if (delegate == null) {
993 assert false;
994 return;
995 }
996
997 if (flagValue) {
998 delegate.mFlags |= flagMask;
999 } else {
1000 delegate.mFlags &= ~flagMask;
1001 }
1002 }
1003}