blob: 7cb30dd5349ef77ba207aa4dbd3d01e9399a5ce6 [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 Ducrohetcf2030c2010-12-21 06:20:28 -0800121 public void setAlpha(int alpha) {
122 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
123 }
124
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700125 public int getTextAlign() {
126 return mTextAlign;
127 }
128
129 public float getStrokeWidth() {
130 return mStrokeWidth;
131 }
132
Xavier Ducrohet66225222010-12-21 01:33:04 -0800133 /**
134 * returns the value of stroke miter needed by the java api.
135 */
136 public float getJavaStrokeMiter() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800137 float miter = mStrokeMiter * mStrokeWidth;
138 if (miter < 1.f) {
139 miter = 1.f;
140 }
141 return miter;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700142 }
143
144 public int getJavaCap() {
145 switch (Paint.sCapArray[mCap]) {
146 case BUTT:
147 return BasicStroke.CAP_BUTT;
148 case ROUND:
149 return BasicStroke.CAP_ROUND;
150 default:
151 case SQUARE:
152 return BasicStroke.CAP_SQUARE;
153 }
154 }
155
156 public int getJavaJoin() {
157 switch (Paint.sJoinArray[mJoin]) {
158 default:
159 case MITER:
160 return BasicStroke.JOIN_MITER;
161 case ROUND:
162 return BasicStroke.JOIN_ROUND;
163 case BEVEL:
164 return BasicStroke.JOIN_BEVEL;
165 }
166 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700167
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700168 public int getXfermode() {
169 return mXfermode;
170 }
171
172 public int getColorFilter() {
173 return mColorFilter;
174 }
175
176 public int getShader() {
177 return mShader;
178 }
179
180 public int getPathEffect() {
181 return mPathEffect;
182 }
183
184 public int getMaskFilter() {
185 return mMaskFilter;
186 }
187
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700188 // ---- native methods ----
189
190 /*package*/ static int getFlags(Paint thisPaint) {
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 0;
196 }
197
198 return delegate.mFlags;
199 }
200
201 /*package*/ static void setFlags(Paint thisPaint, int flags) {
202 // get the delegate from the native int.
203 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
204 if (delegate == null) {
205 assert false;
206 return;
207 }
208
209 delegate.mFlags = flags;
210 }
211
212 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700213 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700214 }
215
216 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
217 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
218 }
219
220 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
221 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
222 }
223
224 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
225 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
226 }
227
228 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
229 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
230 }
231
232 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
233 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
234 }
235
236 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
237 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
238 }
239
240 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
241 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
242 }
243
244 /*package*/ static int getColor(Paint thisPaint) {
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 0;
250 }
251
252 return delegate.mColor;
253 }
254
255 /*package*/ static void setColor(Paint thisPaint, int color) {
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;
261 }
262
263 delegate.mColor = color;
264 }
265
266 /*package*/ static int getAlpha(Paint thisPaint) {
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 0;
272 }
273
Xavier Ducrohet66225222010-12-21 01:33:04 -0800274 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700275 }
276
277 /*package*/ static void setAlpha(Paint thisPaint, int a) {
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;
283 }
284
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800285 delegate.setAlpha(a);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700286 }
287
288 /*package*/ static float getStrokeWidth(Paint thisPaint) {
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 1.f;
294 }
295
296 return delegate.mStrokeWidth;
297 }
298
299 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
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;
305 }
306
307 delegate.mStrokeWidth = width;
308 }
309
310 /*package*/ static float getStrokeMiter(Paint thisPaint) {
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 1.f;
316 }
317
318 return delegate.mStrokeMiter;
319 }
320
321 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
322 // get the delegate from the native int.
323 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
324 if (delegate == null) {
325 assert false;
326 return;
327 }
328
329 delegate.mStrokeMiter = miter;
330 }
331
332 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
333 int color) {
334 // FIXME
335 throw new UnsupportedOperationException();
336 }
337
338 /*package*/ static float getTextSize(Paint thisPaint) {
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 1.f;
344 }
345
346 return delegate.mTextSize;
347 }
348
349 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
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;
355 }
356
357 delegate.mTextSize = textSize;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800358 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700359 }
360
361 /*package*/ static float getTextScaleX(Paint thisPaint) {
362 // get the delegate from the native int.
363 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
364 if (delegate == null) {
365 assert false;
366 return 1.f;
367 }
368
369 return delegate.mTextScaleX;
370 }
371
372 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
373 // get the delegate from the native int.
374 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
375 if (delegate == null) {
376 assert false;
377 return;
378 }
379
380 delegate.mTextScaleX = scaleX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800381 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700382 }
383
384 /*package*/ static float getTextSkewX(Paint thisPaint) {
385 // get the delegate from the native int.
386 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
387 if (delegate == null) {
388 assert false;
389 return 1.f;
390 }
391
392 return delegate.mTextSkewX;
393 }
394
395 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
396 // get the delegate from the native int.
397 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
398 if (delegate == null) {
399 assert false;
400 return;
401 }
402
403 delegate.mTextSkewX = skewX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800404 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700405 }
406
407 /*package*/ static float ascent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800408 // get the delegate
409 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
410 if (delegate == null) {
411 assert false;
412 return 0;
413 }
414
415 if (delegate.mFonts.size() > 0) {
416 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
417 // Android expects negative ascent so we invert the value from Java.
418 return - javaMetrics.getAscent();
419 }
420
421 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700422 }
423
424 /*package*/ static float descent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800425 // get the delegate
426 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
427 if (delegate == null) {
428 assert false;
429 return 0;
430 }
431
432 if (delegate.mFonts.size() > 0) {
433 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
434 return javaMetrics.getDescent();
435 }
436
437 return 0;
438
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700439 }
440
441 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700442 // get the delegate
443 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
444 if (delegate == null) {
445 assert false;
446 return 0;
447 }
448
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800449 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700450 }
451
452 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700453 // get the delegate
454 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
455 if (delegate == null) {
456 assert false;
457 return 0;
458 }
459
460 if (delegate.mFonts.size() > 0) {
461 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
462 if (fmi != null) {
463 // Android expects negative ascent so we invert the value from Java.
464 fmi.top = - javaMetrics.getMaxAscent();
465 fmi.ascent = - javaMetrics.getAscent();
466 fmi.descent = javaMetrics.getDescent();
467 fmi.bottom = javaMetrics.getMaxDescent();
468 fmi.leading = javaMetrics.getLeading();
469 }
470
471 return javaMetrics.getHeight();
472 }
473
474 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700475 }
476
477 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
478 int count) {
479 // WARNING: the logic in this method is similar to Canvas.drawText.
480 // Any change to this method should be reflected in Canvas.drawText
481
482 // get the delegate
483 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
484 if (delegate == null) {
485 assert false;
486 return 0;
487 }
488
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700489 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700490 }
491
492 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
493 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
494 }
495
496 /*package*/ static float native_measureText(Paint thisPaint, String text) {
497 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
498 }
499
500 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
501 float maxWidth, float[] measuredWidth) {
502 // FIXME
503 throw new UnsupportedOperationException();
504 }
505
506 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
507 float maxWidth, float[] measuredWidth) {
508 // FIXME
509 throw new UnsupportedOperationException();
510 }
511
512
513 /*package*/ static int native_init() {
514 Paint_Delegate newDelegate = new Paint_Delegate();
515 return sManager.addDelegate(newDelegate);
516 }
517
518 /*package*/ static int native_initWithPaint(int paint) {
519 // get the delegate from the native int.
520 Paint_Delegate delegate = sManager.getDelegate(paint);
521 if (delegate == null) {
522 assert false;
523 return 0;
524 }
525
526 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
527 return sManager.addDelegate(newDelegate);
528 }
529
530 /*package*/ static void native_reset(int native_object) {
531 // get the delegate from the native int.
532 Paint_Delegate delegate = sManager.getDelegate(native_object);
533 if (delegate == null) {
534 assert false;
535 return;
536 }
537
538 delegate.reset();
539 }
540
541 /*package*/ static void native_set(int native_dst, int native_src) {
542 // get the delegate from the native int.
543 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
544 if (delegate_dst == null) {
545 assert false;
546 return;
547 }
548
549 // get the delegate from the native int.
550 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
551 if (delegate_src == null) {
552 assert false;
553 return;
554 }
555
556 delegate_dst.set(delegate_src);
557 }
558
559 /*package*/ static int native_getStyle(int native_object) {
560 // get the delegate from the native int.
561 Paint_Delegate delegate = sManager.getDelegate(native_object);
562 if (delegate == null) {
563 assert false;
564 return 0;
565 }
566
567 return delegate.mStyle;
568 }
569
570 /*package*/ static void native_setStyle(int native_object, int style) {
571 // get the delegate from the native int.
572 Paint_Delegate delegate = sManager.getDelegate(native_object);
573 if (delegate == null) {
574 assert false;
575 return;
576 }
577
578 delegate.mStyle = style;
579 }
580
581 /*package*/ static int native_getStrokeCap(int native_object) {
582 // get the delegate from the native int.
583 Paint_Delegate delegate = sManager.getDelegate(native_object);
584 if (delegate == null) {
585 assert false;
586 return 0;
587 }
588
589 return delegate.mCap;
590 }
591
592 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
593 // get the delegate from the native int.
594 Paint_Delegate delegate = sManager.getDelegate(native_object);
595 if (delegate == null) {
596 assert false;
597 return;
598 }
599
600 delegate.mCap = cap;
601 }
602
603 /*package*/ static int native_getStrokeJoin(int native_object) {
604 // get the delegate from the native int.
605 Paint_Delegate delegate = sManager.getDelegate(native_object);
606 if (delegate == null) {
607 assert false;
608 return 0;
609 }
610
611 return delegate.mJoin;
612 }
613
614 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
615 // get the delegate from the native int.
616 Paint_Delegate delegate = sManager.getDelegate(native_object);
617 if (delegate == null) {
618 assert false;
619 return;
620 }
621
622 delegate.mJoin = join;
623 }
624
625 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
626 // FIXME
627 throw new UnsupportedOperationException();
628 }
629
630 /*package*/ static int native_setShader(int native_object, int shader) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700631 // get the delegate from the native int.
632 Paint_Delegate delegate = sManager.getDelegate(native_object);
633 if (delegate == null) {
634 assert false;
635 return shader;
636 }
637
638 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700639 }
640
641 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700642 // get the delegate from the native int.
643 Paint_Delegate delegate = sManager.getDelegate(native_object);
644 if (delegate == null) {
645 assert false;
646 return filter;
647 }
648
649 return delegate.mColorFilter = filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700650 }
651
652 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700653 // get the delegate from the native int.
654 Paint_Delegate delegate = sManager.getDelegate(native_object);
655 if (delegate == null) {
656 assert false;
657 return xfermode;
658 }
659
660 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700661 }
662
663 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700664 // get the delegate from the native int.
665 Paint_Delegate delegate = sManager.getDelegate(native_object);
666 if (delegate == null) {
667 assert false;
668 return effect;
669 }
670
671 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700672 }
673
674 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700675 // get the delegate from the native int.
676 Paint_Delegate delegate = sManager.getDelegate(native_object);
677 if (delegate == null) {
678 assert false;
679 return maskfilter;
680 }
681
682 return delegate.mMaskFilter = maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700683 }
684
685 /*package*/ static int native_setTypeface(int native_object, int typeface) {
686 // get the delegate from the native int.
687 Paint_Delegate delegate = sManager.getDelegate(native_object);
688 if (delegate == null) {
689 assert false;
690 return 0;
691 }
692
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800693 delegate.mTypeface = typeface;
694 delegate.updateFontObject();
695 return delegate.mTypeface;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700696 }
697
698 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
699 // FIXME
700 throw new UnsupportedOperationException();
701 }
702
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700703 /*package*/ static int native_getTextAlign(int native_object) {
704 // get the delegate from the native int.
705 Paint_Delegate delegate = sManager.getDelegate(native_object);
706 if (delegate == null) {
707 assert false;
708 return 0;
709 }
710
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700711 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700712 }
713
714 /*package*/ static void native_setTextAlign(int native_object, int align) {
715 // get the delegate from the native int.
716 Paint_Delegate delegate = sManager.getDelegate(native_object);
717 if (delegate == null) {
718 assert false;
719 return;
720 }
721
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700722 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700723 }
724
725 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800726 // get the delegate from the native int.
727 Paint_Delegate delegate = sManager.getDelegate(native_paint);
728 if (delegate == null) {
729 assert false;
730 return 0.f;
731 }
732
733 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700734 }
735
736 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
737 int count, float[] widths) {
738 // FIXME
739 throw new UnsupportedOperationException();
740 }
741
742 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
743 int end, float[] widths) {
744 // FIXME
745 throw new UnsupportedOperationException();
746 }
747
748 /*package*/ static float native_getTextRunAdvances(int native_object,
749 char[] text, int index, int count, int contextIndex, int contextCount,
750 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700751 // get the delegate from the native int.
752 Paint_Delegate delegate = sManager.getDelegate(native_object);
753 if (delegate == null) {
754 assert false;
755 return 0.f;
756 }
757
758 if (delegate.mFonts.size() > 0) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700759 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700760 float totalAdvance = 0;
761 for (int i = 0; i < count; i++) {
762 char c = text[i + index];
763 boolean found = false;
764 for (FontInfo info : delegate.mFonts) {
765 if (info.mFont.canDisplay(c)) {
766 float adv = info.mMetrics.charWidth(c);
767 totalAdvance += adv;
768 if (advances != null) {
769 advances[i] = adv;
770 }
771
772 found = true;
773 break;
774 }
775 }
776
777 if (found == false) {
778 // no advance for this char.
779 if (advances != null) {
780 advances[i] = 0.f;
781 }
782 }
783 }
784
785 return totalAdvance;
786 }
787
788 return 0;
789
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700790 }
791
792 /*package*/ static float native_getTextRunAdvances(int native_object,
793 String text, int start, int end, int contextStart, int contextEnd,
794 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700795 // FIXME: support contextStart, contextEnd and direction flag
796 int count = end - start;
797 char[] buffer = TemporaryBuffer.obtain(count);
798 TextUtils.getChars(text, start, end, buffer, 0);
799
800 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
801 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700802 }
803
804 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
805 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
806 // FIXME
807 throw new UnsupportedOperationException();
808 }
809
810 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
811 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
812 // FIXME
813 throw new UnsupportedOperationException();
814 }
815
816 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
817 char[] text, int index, int count, float x, float y, int path) {
818 // FIXME
819 throw new UnsupportedOperationException();
820 }
821
822 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
823 String text, int start, int end, float x, float y, int path) {
824 // FIXME
825 throw new UnsupportedOperationException();
826 }
827
828 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
829 int end, Rect bounds) {
830 // FIXME
831 throw new UnsupportedOperationException();
832 }
833
834 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
835 int count, Rect bounds) {
836 // FIXME
837 throw new UnsupportedOperationException();
838 }
839
840 /*package*/ static void finalizer(int nativePaint) {
841 sManager.removeDelegate(nativePaint);
842 }
843
844 // ---- Private delegate/helper methods ----
845
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800846 /*package*/ Paint_Delegate() {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700847 reset();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700848 }
849
850 private Paint_Delegate(Paint_Delegate paint) {
851 set(paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700852 }
853
854 private void set(Paint_Delegate paint) {
855 mFlags = paint.mFlags;
856 mColor = paint.mColor;
857 mStyle = paint.mStyle;
858 mCap = paint.mCap;
859 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700860 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700861 mTypeface = paint.mTypeface;
862 mStrokeWidth = paint.mStrokeWidth;
863 mStrokeMiter = paint.mStrokeMiter;
864 mTextSize = paint.mTextSize;
865 mTextScaleX = paint.mTextScaleX;
866 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700867 mXfermode = paint.mXfermode;
868 mColorFilter = paint.mColorFilter;
869 mShader = paint.mShader;
870 mPathEffect = paint.mPathEffect;
871 mMaskFilter = paint.mMaskFilter;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800872 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700873 }
874
875 private void reset() {
876 mFlags = Paint.DEFAULT_PAINT_FLAGS;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800877 mColor = 0xFF000000;
Xavier Ducrohet66225222010-12-21 01:33:04 -0800878 mStyle = Paint.Style.FILL.nativeInt;
879 mCap = Paint.Cap.BUTT.nativeInt;
880 mJoin = Paint.Join.MITER.nativeInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700881 mTextAlign = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800882 mTypeface = Typeface.sDefaults[0].native_instance;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700883 mStrokeWidth = 1.f;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800884 mStrokeMiter = 4.f;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700885 mTextSize = 20.f;
886 mTextScaleX = 1.f;
887 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700888 mXfermode = 0;
889 mColorFilter = 0;
890 mShader = 0;
891 mPathEffect = 0;
892 mMaskFilter = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800893 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700894 }
895
896 /**
897 * Update the {@link Font} object from the typeface, text size and scaling
898 */
899 private void updateFontObject() {
900 if (mTypeface != 0) {
901 // Get the fonts from the TypeFace object.
902 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
903
904 // create new font objects as well as FontMetrics, based on the current text size
905 // and skew info.
906 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
907 for (Font font : fonts) {
908 FontInfo info = new FontInfo();
909 info.mFont = font.deriveFont(mTextSize);
910 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
911 // TODO: support skew
912 info.mFont = info.mFont.deriveFont(new AffineTransform(
913 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
914 }
915 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
916
917 infoList.add(info);
918 }
919
920 mFonts = Collections.unmodifiableList(infoList);
921 }
922 }
923
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700924 /*package*/ float measureText(char[] text, int index, int count) {
925 if (mFonts.size() > 0) {
926 FontInfo mainFont = mFonts.get(0);
927 int i = index;
928 int lastIndex = index + count;
929 float total = 0f;
930 while (i < lastIndex) {
931 // always start with the main font.
932 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
933 if (upTo == -1) {
934 // shortcut to exit
935 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
936 } else if (upTo > 0) {
937 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
938 i = upTo;
939 // don't call continue at this point. Since it is certain the main font
940 // cannot display the font a index upTo (now ==i), we move on to the
941 // fallback fonts directly.
942 }
943
944 // no char supported, attempt to read the next char(s) with the
945 // fallback font. In this case we only test the first character
946 // and then go back to test with the main font.
947 // Special test for 2-char characters.
948 boolean foundFont = false;
949 for (int f = 1 ; f < mFonts.size() ; f++) {
950 FontInfo fontInfo = mFonts.get(f);
951
952 // need to check that the font can display the character. We test
953 // differently if the char is a high surrogate.
954 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
955 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
956 if (upTo == -1) {
957 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
958 i += charCount;
959 foundFont = true;
960 break;
961
962 }
963 }
964
965 // in case no font can display the char, measure it with the main font.
966 if (foundFont == false) {
967 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
968 total += mainFont.mMetrics.charsWidth(text, i, size);
969 i += size;
970 }
971 }
972 }
973
974 return 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700975 }
976
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800977 private float getFontMetrics(FontMetrics metrics) {
978 if (mFonts.size() > 0) {
979 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
980 if (metrics != null) {
981 // Android expects negative ascent so we invert the value from Java.
982 metrics.top = - javaMetrics.getMaxAscent();
983 metrics.ascent = - javaMetrics.getAscent();
984 metrics.descent = javaMetrics.getDescent();
985 metrics.bottom = javaMetrics.getMaxDescent();
986 metrics.leading = javaMetrics.getLeading();
987 }
988
989 return javaMetrics.getHeight();
990 }
991
992 return 0;
993 }
994
995
996
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700997 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
998 // get the delegate from the native int.
999 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
1000 if (delegate == null) {
1001 assert false;
1002 return;
1003 }
1004
1005 if (flagValue) {
1006 delegate.mFlags |= flagMask;
1007 } else {
1008 delegate.mFlags &= ~flagMask;
1009 }
1010 }
1011}