blob: fa26bcf5feb924d4a912ab1dd0652a6638c8c9ca [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 Ducrohet37f21802010-11-01 16:17:18 -0700117 public int getTextAlign() {
118 return mTextAlign;
119 }
120
121 public float getStrokeWidth() {
122 return mStrokeWidth;
123 }
124
125 public float getStrokeMiter() {
126 return mStrokeMiter;
127 }
128
129 public int getJavaCap() {
130 switch (Paint.sCapArray[mCap]) {
131 case BUTT:
132 return BasicStroke.CAP_BUTT;
133 case ROUND:
134 return BasicStroke.CAP_ROUND;
135 default:
136 case SQUARE:
137 return BasicStroke.CAP_SQUARE;
138 }
139 }
140
141 public int getJavaJoin() {
142 switch (Paint.sJoinArray[mJoin]) {
143 default:
144 case MITER:
145 return BasicStroke.JOIN_MITER;
146 case ROUND:
147 return BasicStroke.JOIN_ROUND;
148 case BEVEL:
149 return BasicStroke.JOIN_BEVEL;
150 }
151 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700152
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700153 public int getXfermode() {
154 return mXfermode;
155 }
156
157 public int getColorFilter() {
158 return mColorFilter;
159 }
160
161 public int getShader() {
162 return mShader;
163 }
164
165 public int getPathEffect() {
166 return mPathEffect;
167 }
168
169 public int getMaskFilter() {
170 return mMaskFilter;
171 }
172
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700173 // ---- native methods ----
174
175 /*package*/ static int getFlags(Paint thisPaint) {
176 // get the delegate from the native int.
177 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
178 if (delegate == null) {
179 assert false;
180 return 0;
181 }
182
183 return delegate.mFlags;
184 }
185
186 /*package*/ static void setFlags(Paint thisPaint, int flags) {
187 // get the delegate from the native int.
188 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
189 if (delegate == null) {
190 assert false;
191 return;
192 }
193
194 delegate.mFlags = flags;
195 }
196
197 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700198 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700199 }
200
201 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
202 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
203 }
204
205 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
206 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
207 }
208
209 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
210 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
211 }
212
213 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
214 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
215 }
216
217 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
218 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
219 }
220
221 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
222 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
223 }
224
225 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
226 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
227 }
228
229 /*package*/ static int getColor(Paint thisPaint) {
230 // get the delegate from the native int.
231 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
232 if (delegate == null) {
233 assert false;
234 return 0;
235 }
236
237 return delegate.mColor;
238 }
239
240 /*package*/ static void setColor(Paint thisPaint, int color) {
241 // get the delegate from the native int.
242 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
243 if (delegate == null) {
244 assert false;
245 return;
246 }
247
248 delegate.mColor = color;
249 }
250
251 /*package*/ static int getAlpha(Paint thisPaint) {
252 // get the delegate from the native int.
253 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
254 if (delegate == null) {
255 assert false;
256 return 0;
257 }
258
Xavier Ducrohet70a04aa2010-11-12 14:20:45 -0800259 return delegate.mColor >>> 24;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700260 }
261
262 /*package*/ static void setAlpha(Paint thisPaint, int a) {
263 // get the delegate from the native int.
264 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
265 if (delegate == null) {
266 assert false;
267 return;
268 }
269
270 delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF);
271 }
272
273 /*package*/ static float getStrokeWidth(Paint thisPaint) {
274 // get the delegate from the native int.
275 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
276 if (delegate == null) {
277 assert false;
278 return 1.f;
279 }
280
281 return delegate.mStrokeWidth;
282 }
283
284 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
285 // get the delegate from the native int.
286 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
287 if (delegate == null) {
288 assert false;
289 return;
290 }
291
292 delegate.mStrokeWidth = width;
293 }
294
295 /*package*/ static float getStrokeMiter(Paint thisPaint) {
296 // get the delegate from the native int.
297 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
298 if (delegate == null) {
299 assert false;
300 return 1.f;
301 }
302
303 return delegate.mStrokeMiter;
304 }
305
306 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
307 // get the delegate from the native int.
308 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
309 if (delegate == null) {
310 assert false;
311 return;
312 }
313
314 delegate.mStrokeMiter = miter;
315 }
316
317 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
318 int color) {
319 // FIXME
320 throw new UnsupportedOperationException();
321 }
322
323 /*package*/ static float getTextSize(Paint thisPaint) {
324 // get the delegate from the native int.
325 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
326 if (delegate == null) {
327 assert false;
328 return 1.f;
329 }
330
331 return delegate.mTextSize;
332 }
333
334 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
335 // get the delegate from the native int.
336 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
337 if (delegate == null) {
338 assert false;
339 return;
340 }
341
342 delegate.mTextSize = textSize;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800343 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700344 }
345
346 /*package*/ static float getTextScaleX(Paint thisPaint) {
347 // get the delegate from the native int.
348 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
349 if (delegate == null) {
350 assert false;
351 return 1.f;
352 }
353
354 return delegate.mTextScaleX;
355 }
356
357 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
358 // get the delegate from the native int.
359 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
360 if (delegate == null) {
361 assert false;
362 return;
363 }
364
365 delegate.mTextScaleX = scaleX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800366 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700367 }
368
369 /*package*/ static float getTextSkewX(Paint thisPaint) {
370 // get the delegate from the native int.
371 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
372 if (delegate == null) {
373 assert false;
374 return 1.f;
375 }
376
377 return delegate.mTextSkewX;
378 }
379
380 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
381 // get the delegate from the native int.
382 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
383 if (delegate == null) {
384 assert false;
385 return;
386 }
387
388 delegate.mTextSkewX = skewX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800389 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700390 }
391
392 /*package*/ static float ascent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800393 // get the delegate
394 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
395 if (delegate == null) {
396 assert false;
397 return 0;
398 }
399
400 if (delegate.mFonts.size() > 0) {
401 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
402 // Android expects negative ascent so we invert the value from Java.
403 return - javaMetrics.getAscent();
404 }
405
406 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700407 }
408
409 /*package*/ static float descent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800410 // get the delegate
411 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
412 if (delegate == null) {
413 assert false;
414 return 0;
415 }
416
417 if (delegate.mFonts.size() > 0) {
418 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
419 return javaMetrics.getDescent();
420 }
421
422 return 0;
423
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700424 }
425
426 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700427 // get the delegate
428 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
429 if (delegate == null) {
430 assert false;
431 return 0;
432 }
433
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800434 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700435 }
436
437 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700438 // get the delegate
439 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
440 if (delegate == null) {
441 assert false;
442 return 0;
443 }
444
445 if (delegate.mFonts.size() > 0) {
446 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
447 if (fmi != null) {
448 // Android expects negative ascent so we invert the value from Java.
449 fmi.top = - javaMetrics.getMaxAscent();
450 fmi.ascent = - javaMetrics.getAscent();
451 fmi.descent = javaMetrics.getDescent();
452 fmi.bottom = javaMetrics.getMaxDescent();
453 fmi.leading = javaMetrics.getLeading();
454 }
455
456 return javaMetrics.getHeight();
457 }
458
459 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700460 }
461
462 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
463 int count) {
464 // WARNING: the logic in this method is similar to Canvas.drawText.
465 // Any change to this method should be reflected in Canvas.drawText
466
467 // get the delegate
468 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
469 if (delegate == null) {
470 assert false;
471 return 0;
472 }
473
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700474 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700475 }
476
477 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
478 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
479 }
480
481 /*package*/ static float native_measureText(Paint thisPaint, String text) {
482 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
483 }
484
485 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
486 float maxWidth, float[] measuredWidth) {
487 // FIXME
488 throw new UnsupportedOperationException();
489 }
490
491 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
492 float maxWidth, float[] measuredWidth) {
493 // FIXME
494 throw new UnsupportedOperationException();
495 }
496
497
498 /*package*/ static int native_init() {
499 Paint_Delegate newDelegate = new Paint_Delegate();
500 return sManager.addDelegate(newDelegate);
501 }
502
503 /*package*/ static int native_initWithPaint(int paint) {
504 // get the delegate from the native int.
505 Paint_Delegate delegate = sManager.getDelegate(paint);
506 if (delegate == null) {
507 assert false;
508 return 0;
509 }
510
511 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
512 return sManager.addDelegate(newDelegate);
513 }
514
515 /*package*/ static void native_reset(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;
521 }
522
523 delegate.reset();
524 }
525
526 /*package*/ static void native_set(int native_dst, int native_src) {
527 // get the delegate from the native int.
528 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
529 if (delegate_dst == null) {
530 assert false;
531 return;
532 }
533
534 // get the delegate from the native int.
535 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
536 if (delegate_src == null) {
537 assert false;
538 return;
539 }
540
541 delegate_dst.set(delegate_src);
542 }
543
544 /*package*/ static int native_getStyle(int native_object) {
545 // get the delegate from the native int.
546 Paint_Delegate delegate = sManager.getDelegate(native_object);
547 if (delegate == null) {
548 assert false;
549 return 0;
550 }
551
552 return delegate.mStyle;
553 }
554
555 /*package*/ static void native_setStyle(int native_object, int style) {
556 // get the delegate from the native int.
557 Paint_Delegate delegate = sManager.getDelegate(native_object);
558 if (delegate == null) {
559 assert false;
560 return;
561 }
562
563 delegate.mStyle = style;
564 }
565
566 /*package*/ static int native_getStrokeCap(int native_object) {
567 // get the delegate from the native int.
568 Paint_Delegate delegate = sManager.getDelegate(native_object);
569 if (delegate == null) {
570 assert false;
571 return 0;
572 }
573
574 return delegate.mCap;
575 }
576
577 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
578 // get the delegate from the native int.
579 Paint_Delegate delegate = sManager.getDelegate(native_object);
580 if (delegate == null) {
581 assert false;
582 return;
583 }
584
585 delegate.mCap = cap;
586 }
587
588 /*package*/ static int native_getStrokeJoin(int native_object) {
589 // get the delegate from the native int.
590 Paint_Delegate delegate = sManager.getDelegate(native_object);
591 if (delegate == null) {
592 assert false;
593 return 0;
594 }
595
596 return delegate.mJoin;
597 }
598
599 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
600 // get the delegate from the native int.
601 Paint_Delegate delegate = sManager.getDelegate(native_object);
602 if (delegate == null) {
603 assert false;
604 return;
605 }
606
607 delegate.mJoin = join;
608 }
609
610 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
611 // FIXME
612 throw new UnsupportedOperationException();
613 }
614
615 /*package*/ static int native_setShader(int native_object, int shader) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700616 // get the delegate from the native int.
617 Paint_Delegate delegate = sManager.getDelegate(native_object);
618 if (delegate == null) {
619 assert false;
620 return shader;
621 }
622
623 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700624 }
625
626 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700627 // get the delegate from the native int.
628 Paint_Delegate delegate = sManager.getDelegate(native_object);
629 if (delegate == null) {
630 assert false;
631 return filter;
632 }
633
634 return delegate.mColorFilter = filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700635 }
636
637 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700638 // get the delegate from the native int.
639 Paint_Delegate delegate = sManager.getDelegate(native_object);
640 if (delegate == null) {
641 assert false;
642 return xfermode;
643 }
644
645 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700646 }
647
648 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700649 // get the delegate from the native int.
650 Paint_Delegate delegate = sManager.getDelegate(native_object);
651 if (delegate == null) {
652 assert false;
653 return effect;
654 }
655
656 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700657 }
658
659 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700660 // get the delegate from the native int.
661 Paint_Delegate delegate = sManager.getDelegate(native_object);
662 if (delegate == null) {
663 assert false;
664 return maskfilter;
665 }
666
667 return delegate.mMaskFilter = maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700668 }
669
670 /*package*/ static int native_setTypeface(int native_object, int typeface) {
671 // get the delegate from the native int.
672 Paint_Delegate delegate = sManager.getDelegate(native_object);
673 if (delegate == null) {
674 assert false;
675 return 0;
676 }
677
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800678 delegate.mTypeface = typeface;
679 delegate.updateFontObject();
680 return delegate.mTypeface;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700681 }
682
683 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
684 // FIXME
685 throw new UnsupportedOperationException();
686 }
687
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700688 /*package*/ static int native_getTextAlign(int native_object) {
689 // get the delegate from the native int.
690 Paint_Delegate delegate = sManager.getDelegate(native_object);
691 if (delegate == null) {
692 assert false;
693 return 0;
694 }
695
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700696 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700697 }
698
699 /*package*/ static void native_setTextAlign(int native_object, int align) {
700 // get the delegate from the native int.
701 Paint_Delegate delegate = sManager.getDelegate(native_object);
702 if (delegate == null) {
703 assert false;
704 return;
705 }
706
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700707 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700708 }
709
710 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800711 // get the delegate from the native int.
712 Paint_Delegate delegate = sManager.getDelegate(native_paint);
713 if (delegate == null) {
714 assert false;
715 return 0.f;
716 }
717
718 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700719 }
720
721 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
722 int count, float[] widths) {
723 // FIXME
724 throw new UnsupportedOperationException();
725 }
726
727 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
728 int end, float[] widths) {
729 // FIXME
730 throw new UnsupportedOperationException();
731 }
732
733 /*package*/ static float native_getTextRunAdvances(int native_object,
734 char[] text, int index, int count, int contextIndex, int contextCount,
735 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700736 // get the delegate from the native int.
737 Paint_Delegate delegate = sManager.getDelegate(native_object);
738 if (delegate == null) {
739 assert false;
740 return 0.f;
741 }
742
743 if (delegate.mFonts.size() > 0) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700744 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700745 float totalAdvance = 0;
746 for (int i = 0; i < count; i++) {
747 char c = text[i + index];
748 boolean found = false;
749 for (FontInfo info : delegate.mFonts) {
750 if (info.mFont.canDisplay(c)) {
751 float adv = info.mMetrics.charWidth(c);
752 totalAdvance += adv;
753 if (advances != null) {
754 advances[i] = adv;
755 }
756
757 found = true;
758 break;
759 }
760 }
761
762 if (found == false) {
763 // no advance for this char.
764 if (advances != null) {
765 advances[i] = 0.f;
766 }
767 }
768 }
769
770 return totalAdvance;
771 }
772
773 return 0;
774
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700775 }
776
777 /*package*/ static float native_getTextRunAdvances(int native_object,
778 String text, int start, int end, int contextStart, int contextEnd,
779 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700780 // FIXME: support contextStart, contextEnd and direction flag
781 int count = end - start;
782 char[] buffer = TemporaryBuffer.obtain(count);
783 TextUtils.getChars(text, start, end, buffer, 0);
784
785 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
786 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700787 }
788
789 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
790 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
791 // FIXME
792 throw new UnsupportedOperationException();
793 }
794
795 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
796 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
797 // FIXME
798 throw new UnsupportedOperationException();
799 }
800
801 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
802 char[] text, int index, int count, float x, float y, int path) {
803 // FIXME
804 throw new UnsupportedOperationException();
805 }
806
807 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
808 String text, int start, int end, float x, float y, int path) {
809 // FIXME
810 throw new UnsupportedOperationException();
811 }
812
813 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
814 int end, Rect bounds) {
815 // FIXME
816 throw new UnsupportedOperationException();
817 }
818
819 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
820 int count, Rect bounds) {
821 // FIXME
822 throw new UnsupportedOperationException();
823 }
824
825 /*package*/ static void finalizer(int nativePaint) {
826 sManager.removeDelegate(nativePaint);
827 }
828
829 // ---- Private delegate/helper methods ----
830
831 private Paint_Delegate() {
832 reset();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700833 }
834
835 private Paint_Delegate(Paint_Delegate paint) {
836 set(paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700837 }
838
839 private void set(Paint_Delegate paint) {
840 mFlags = paint.mFlags;
841 mColor = paint.mColor;
842 mStyle = paint.mStyle;
843 mCap = paint.mCap;
844 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700845 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700846 mTypeface = paint.mTypeface;
847 mStrokeWidth = paint.mStrokeWidth;
848 mStrokeMiter = paint.mStrokeMiter;
849 mTextSize = paint.mTextSize;
850 mTextScaleX = paint.mTextScaleX;
851 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700852 mXfermode = paint.mXfermode;
853 mColorFilter = paint.mColorFilter;
854 mShader = paint.mShader;
855 mPathEffect = paint.mPathEffect;
856 mMaskFilter = paint.mMaskFilter;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800857 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700858 }
859
860 private void reset() {
861 mFlags = Paint.DEFAULT_PAINT_FLAGS;
862 mColor = 0;
863 mStyle = 0;
864 mCap = 0;
865 mJoin = 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700866 mTextAlign = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800867 mTypeface = Typeface.sDefaults[0].native_instance;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700868 mStrokeWidth = 1.f;
869 mStrokeMiter = 2.f;
870 mTextSize = 20.f;
871 mTextScaleX = 1.f;
872 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700873 mXfermode = 0;
874 mColorFilter = 0;
875 mShader = 0;
876 mPathEffect = 0;
877 mMaskFilter = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800878 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700879 }
880
881 /**
882 * Update the {@link Font} object from the typeface, text size and scaling
883 */
884 private void updateFontObject() {
885 if (mTypeface != 0) {
886 // Get the fonts from the TypeFace object.
887 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
888
889 // create new font objects as well as FontMetrics, based on the current text size
890 // and skew info.
891 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
892 for (Font font : fonts) {
893 FontInfo info = new FontInfo();
894 info.mFont = font.deriveFont(mTextSize);
895 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
896 // TODO: support skew
897 info.mFont = info.mFont.deriveFont(new AffineTransform(
898 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
899 }
900 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
901
902 infoList.add(info);
903 }
904
905 mFonts = Collections.unmodifiableList(infoList);
906 }
907 }
908
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700909 /*package*/ float measureText(char[] text, int index, int count) {
910 if (mFonts.size() > 0) {
911 FontInfo mainFont = mFonts.get(0);
912 int i = index;
913 int lastIndex = index + count;
914 float total = 0f;
915 while (i < lastIndex) {
916 // always start with the main font.
917 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
918 if (upTo == -1) {
919 // shortcut to exit
920 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
921 } else if (upTo > 0) {
922 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
923 i = upTo;
924 // don't call continue at this point. Since it is certain the main font
925 // cannot display the font a index upTo (now ==i), we move on to the
926 // fallback fonts directly.
927 }
928
929 // no char supported, attempt to read the next char(s) with the
930 // fallback font. In this case we only test the first character
931 // and then go back to test with the main font.
932 // Special test for 2-char characters.
933 boolean foundFont = false;
934 for (int f = 1 ; f < mFonts.size() ; f++) {
935 FontInfo fontInfo = mFonts.get(f);
936
937 // need to check that the font can display the character. We test
938 // differently if the char is a high surrogate.
939 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
940 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
941 if (upTo == -1) {
942 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
943 i += charCount;
944 foundFont = true;
945 break;
946
947 }
948 }
949
950 // in case no font can display the char, measure it with the main font.
951 if (foundFont == false) {
952 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
953 total += mainFont.mMetrics.charsWidth(text, i, size);
954 i += size;
955 }
956 }
957 }
958
959 return 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700960 }
961
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800962 private float getFontMetrics(FontMetrics metrics) {
963 if (mFonts.size() > 0) {
964 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
965 if (metrics != null) {
966 // Android expects negative ascent so we invert the value from Java.
967 metrics.top = - javaMetrics.getMaxAscent();
968 metrics.ascent = - javaMetrics.getAscent();
969 metrics.descent = javaMetrics.getDescent();
970 metrics.bottom = javaMetrics.getMaxDescent();
971 metrics.leading = javaMetrics.getLeading();
972 }
973
974 return javaMetrics.getHeight();
975 }
976
977 return 0;
978 }
979
980
981
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700982 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
983 // get the delegate from the native int.
984 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
985 if (delegate == null) {
986 assert false;
987 return;
988 }
989
990 if (flagValue) {
991 delegate.mFlags |= flagMask;
992 } else {
993 delegate.mFlags &= ~flagMask;
994 }
995 }
996}