blob: 9d4970f4150cfe49c7f328e457521c523cd18897 [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 Ducroheta6e51d52010-12-23 07:16:21 -080019import com.android.layoutlib.bridge.Bridge;
Xavier Ducrohet3bd98982010-11-09 18:25:03 -080020import com.android.layoutlib.bridge.impl.DelegateManager;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070021
22import android.graphics.Paint.FontMetrics;
23import android.graphics.Paint.FontMetricsInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070024import android.text.TextUtils;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070025
Xavier Ducrohet37f21802010-11-01 16:17:18 -070026import java.awt.BasicStroke;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070027import java.awt.Font;
Xavier Ducrohetb9761242010-12-23 10:22:14 -080028import java.awt.Shape;
29import java.awt.Stroke;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070030import java.awt.Toolkit;
31import java.awt.font.FontRenderContext;
32import java.awt.geom.AffineTransform;
33import java.util.ArrayList;
34import java.util.Collections;
35import java.util.List;
36
37/**
38 * Delegate implementing the native methods of android.graphics.Paint
39 *
40 * Through the layoutlib_create tool, the original native methods of Paint have been replaced
41 * by calls to methods of the same name in this delegate class.
42 *
43 * This class behaves like the original native implementation, but in Java, keeping previously
44 * native data into its own objects and mapping them to int that are sent back and forth between
45 * it and the original Paint class.
46 *
47 * @see DelegateManager
48 *
49 */
50public class Paint_Delegate {
51
52 /**
53 * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
54 */
Xavier Ducrohet37f21802010-11-01 16:17:18 -070055 /*package*/ static final class FontInfo {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070056 Font mFont;
57 java.awt.FontMetrics mMetrics;
58 }
59
60 // ---- delegate manager ----
61 private static final DelegateManager<Paint_Delegate> sManager =
62 new DelegateManager<Paint_Delegate>();
63
64 // ---- delegate helper data ----
65 private List<FontInfo> mFonts;
66 private final FontRenderContext mFontContext = new FontRenderContext(
67 new AffineTransform(), true, true);
68
69 // ---- delegate data ----
70 private int mFlags;
71 private int mColor;
72 private int mStyle;
73 private int mCap;
74 private int mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070075 private int mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070076 private int mTypeface;
77 private float mStrokeWidth;
78 private float mStrokeMiter;
79 private float mTextSize;
80 private float mTextScaleX;
81 private float mTextSkewX;
82
Xavier Ducroheta313b652010-11-01 18:45:20 -070083 private int mXfermode;
84 private int mColorFilter;
85 private int mShader;
86 private int mPathEffect;
87 private int mMaskFilter;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -080088 private int mRasterizer;
Xavier Ducroheta313b652010-11-01 18:45:20 -070089
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070090
91 // ---- Public Helper methods ----
92
Xavier Ducrohet37f21802010-11-01 16:17:18 -070093 public static Paint_Delegate getDelegate(int native_paint) {
94 return sManager.getDelegate(native_paint);
95 }
96
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070097 /**
98 * Returns the list of {@link Font} objects. The first item is the main font, the rest
99 * are fall backs for characters not present in the main font.
100 */
101 public List<FontInfo> getFonts() {
102 return mFonts;
103 }
104
Xavier Ducroheta313b652010-11-01 18:45:20 -0700105 public boolean isAntiAliased() {
106 return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
107 }
108
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700109 public boolean isFilterBitmap() {
110 return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
111 }
112
113 public int getStyle() {
114 return mStyle;
115 }
116
117 public int getColor() {
118 return mColor;
119 }
120
Xavier Ducrohet66225222010-12-21 01:33:04 -0800121 public int getAlpha() {
122 return mColor >>> 24;
123 }
124
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800125 public void setAlpha(int alpha) {
126 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
127 }
128
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700129 public int getTextAlign() {
130 return mTextAlign;
131 }
132
133 public float getStrokeWidth() {
134 return mStrokeWidth;
135 }
136
Xavier Ducrohet66225222010-12-21 01:33:04 -0800137 /**
138 * returns the value of stroke miter needed by the java api.
139 */
140 public float getJavaStrokeMiter() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800141 float miter = mStrokeMiter * mStrokeWidth;
142 if (miter < 1.f) {
143 miter = 1.f;
144 }
145 return miter;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700146 }
147
148 public int getJavaCap() {
149 switch (Paint.sCapArray[mCap]) {
150 case BUTT:
151 return BasicStroke.CAP_BUTT;
152 case ROUND:
153 return BasicStroke.CAP_ROUND;
154 default:
155 case SQUARE:
156 return BasicStroke.CAP_SQUARE;
157 }
158 }
159
160 public int getJavaJoin() {
161 switch (Paint.sJoinArray[mJoin]) {
162 default:
163 case MITER:
164 return BasicStroke.JOIN_MITER;
165 case ROUND:
166 return BasicStroke.JOIN_ROUND;
167 case BEVEL:
168 return BasicStroke.JOIN_BEVEL;
169 }
170 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700171
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800172 public Stroke getJavaStroke() {
173 PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
174 if (effectDelegate != null) {
175 if (effectDelegate.isSupported()) {
176 Stroke stroke = effectDelegate.getStroke(this);
177 assert stroke != null;
178 if (stroke != null) {
179 return stroke;
180 }
181 } else {
182 Bridge.getLog().fidelityWarning(null,
183 effectDelegate.getSupportMessage(),
184 null);
185 }
186 }
187
188 // if no custom stroke as been set, set the default one.
189 return new BasicStroke(
190 getStrokeWidth(),
191 getJavaCap(),
192 getJavaJoin(),
193 getJavaStrokeMiter());
194 }
195
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800196 /**
197 * Returns the {@link Xfermode} delegate or null if none have been set
198 *
199 * @return the delegate or null.
200 */
201 public Xfermode_Delegate getXfermode() {
202 return Xfermode_Delegate.getDelegate(mXfermode);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700203 }
204
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800205 /**
206 * Returns the {@link ColorFilter} delegate or null if none have been set
207 *
208 * @return the delegate or null.
209 */
210 public ColorFilter_Delegate getColorFilter() {
211 return ColorFilter_Delegate.getDelegate(mColorFilter);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700212 }
213
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800214 /**
215 * Returns the {@link Shader} delegate or null if none have been set
216 *
217 * @return the delegate or null.
218 */
219 public Shader_Delegate getShader() {
220 return Shader_Delegate.getDelegate(mShader);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700221 }
222
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800223 /**
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800224 * Returns the {@link MaskFilter} delegate or null if none have been set
225 *
226 * @return the delegate or null.
227 */
228 public MaskFilter_Delegate getMaskFilter() {
229 return MaskFilter_Delegate.getDelegate(mMaskFilter);
230 }
231
232 /**
233 * Returns the {@link Rasterizer} delegate or null if none have been set
234 *
235 * @return the delegate or null.
236 */
237 public Rasterizer_Delegate getRasterizer() {
238 return Rasterizer_Delegate.getDelegate(mRasterizer);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700239 }
240
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700241 // ---- native methods ----
242
243 /*package*/ static int getFlags(Paint thisPaint) {
244 // get the delegate from the native int.
245 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
246 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700247 return 0;
248 }
249
250 return delegate.mFlags;
251 }
252
253 /*package*/ static void setFlags(Paint thisPaint, int flags) {
254 // get the delegate from the native int.
255 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
256 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700257 return;
258 }
259
260 delegate.mFlags = flags;
261 }
262
263 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700264 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700265 }
266
267 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
268 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
269 }
270
271 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
272 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
273 }
274
275 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
276 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
277 }
278
279 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
280 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
281 }
282
283 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
284 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
285 }
286
287 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
288 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
289 }
290
291 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
292 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
293 }
294
295 /*package*/ static int getColor(Paint thisPaint) {
296 // get the delegate from the native int.
297 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
298 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700299 return 0;
300 }
301
302 return delegate.mColor;
303 }
304
305 /*package*/ static void setColor(Paint thisPaint, int color) {
306 // get the delegate from the native int.
307 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
308 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700309 return;
310 }
311
312 delegate.mColor = color;
313 }
314
315 /*package*/ static int getAlpha(Paint thisPaint) {
316 // get the delegate from the native int.
317 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
318 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700319 return 0;
320 }
321
Xavier Ducrohet66225222010-12-21 01:33:04 -0800322 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700323 }
324
325 /*package*/ static void setAlpha(Paint thisPaint, int a) {
326 // get the delegate from the native int.
327 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
328 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700329 return;
330 }
331
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800332 delegate.setAlpha(a);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700333 }
334
335 /*package*/ static float getStrokeWidth(Paint thisPaint) {
336 // get the delegate from the native int.
337 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
338 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700339 return 1.f;
340 }
341
342 return delegate.mStrokeWidth;
343 }
344
345 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
346 // get the delegate from the native int.
347 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
348 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700349 return;
350 }
351
352 delegate.mStrokeWidth = width;
353 }
354
355 /*package*/ static float getStrokeMiter(Paint thisPaint) {
356 // get the delegate from the native int.
357 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
358 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700359 return 1.f;
360 }
361
362 return delegate.mStrokeMiter;
363 }
364
365 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
366 // get the delegate from the native int.
367 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
368 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700369 return;
370 }
371
372 delegate.mStrokeMiter = miter;
373 }
374
375 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
376 int color) {
377 // FIXME
378 throw new UnsupportedOperationException();
379 }
380
381 /*package*/ static float getTextSize(Paint thisPaint) {
382 // get the delegate from the native int.
383 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
384 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700385 return 1.f;
386 }
387
388 return delegate.mTextSize;
389 }
390
391 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
392 // get the delegate from the native int.
393 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
394 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700395 return;
396 }
397
398 delegate.mTextSize = textSize;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800399 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700400 }
401
402 /*package*/ static float getTextScaleX(Paint thisPaint) {
403 // get the delegate from the native int.
404 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
405 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700406 return 1.f;
407 }
408
409 return delegate.mTextScaleX;
410 }
411
412 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
413 // get the delegate from the native int.
414 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
415 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700416 return;
417 }
418
419 delegate.mTextScaleX = scaleX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800420 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700421 }
422
423 /*package*/ static float getTextSkewX(Paint thisPaint) {
424 // get the delegate from the native int.
425 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
426 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700427 return 1.f;
428 }
429
430 return delegate.mTextSkewX;
431 }
432
433 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
434 // get the delegate from the native int.
435 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
436 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700437 return;
438 }
439
440 delegate.mTextSkewX = skewX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800441 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700442 }
443
444 /*package*/ static float ascent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800445 // get the delegate
446 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
447 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800448 return 0;
449 }
450
451 if (delegate.mFonts.size() > 0) {
452 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
453 // Android expects negative ascent so we invert the value from Java.
454 return - javaMetrics.getAscent();
455 }
456
457 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700458 }
459
460 /*package*/ static float descent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800461 // get the delegate
462 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
463 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800464 return 0;
465 }
466
467 if (delegate.mFonts.size() > 0) {
468 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
469 return javaMetrics.getDescent();
470 }
471
472 return 0;
473
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700474 }
475
476 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700477 // get the delegate
478 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
479 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700480 return 0;
481 }
482
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800483 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700484 }
485
486 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700487 // get the delegate
488 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
489 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700490 return 0;
491 }
492
493 if (delegate.mFonts.size() > 0) {
494 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
495 if (fmi != null) {
496 // Android expects negative ascent so we invert the value from Java.
497 fmi.top = - javaMetrics.getMaxAscent();
498 fmi.ascent = - javaMetrics.getAscent();
499 fmi.descent = javaMetrics.getDescent();
500 fmi.bottom = javaMetrics.getMaxDescent();
501 fmi.leading = javaMetrics.getLeading();
502 }
503
504 return javaMetrics.getHeight();
505 }
506
507 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700508 }
509
510 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
511 int count) {
512 // WARNING: the logic in this method is similar to Canvas.drawText.
513 // Any change to this method should be reflected in Canvas.drawText
514
515 // get the delegate
516 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
517 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700518 return 0;
519 }
520
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700521 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700522 }
523
524 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
525 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
526 }
527
528 /*package*/ static float native_measureText(Paint thisPaint, String text) {
529 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
530 }
531
532 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
533 float maxWidth, float[] measuredWidth) {
534 // FIXME
535 throw new UnsupportedOperationException();
536 }
537
538 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
539 float maxWidth, float[] measuredWidth) {
540 // FIXME
541 throw new UnsupportedOperationException();
542 }
543
544
545 /*package*/ static int native_init() {
546 Paint_Delegate newDelegate = new Paint_Delegate();
547 return sManager.addDelegate(newDelegate);
548 }
549
550 /*package*/ static int native_initWithPaint(int paint) {
551 // get the delegate from the native int.
552 Paint_Delegate delegate = sManager.getDelegate(paint);
553 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700554 return 0;
555 }
556
557 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
558 return sManager.addDelegate(newDelegate);
559 }
560
561 /*package*/ static void native_reset(int native_object) {
562 // get the delegate from the native int.
563 Paint_Delegate delegate = sManager.getDelegate(native_object);
564 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700565 return;
566 }
567
568 delegate.reset();
569 }
570
571 /*package*/ static void native_set(int native_dst, int native_src) {
572 // get the delegate from the native int.
573 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
574 if (delegate_dst == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700575 return;
576 }
577
578 // get the delegate from the native int.
579 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
580 if (delegate_src == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700581 return;
582 }
583
584 delegate_dst.set(delegate_src);
585 }
586
587 /*package*/ static int native_getStyle(int native_object) {
588 // get the delegate from the native int.
589 Paint_Delegate delegate = sManager.getDelegate(native_object);
590 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700591 return 0;
592 }
593
594 return delegate.mStyle;
595 }
596
597 /*package*/ static void native_setStyle(int native_object, int style) {
598 // get the delegate from the native int.
599 Paint_Delegate delegate = sManager.getDelegate(native_object);
600 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700601 return;
602 }
603
604 delegate.mStyle = style;
605 }
606
607 /*package*/ static int native_getStrokeCap(int native_object) {
608 // get the delegate from the native int.
609 Paint_Delegate delegate = sManager.getDelegate(native_object);
610 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700611 return 0;
612 }
613
614 return delegate.mCap;
615 }
616
617 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
618 // get the delegate from the native int.
619 Paint_Delegate delegate = sManager.getDelegate(native_object);
620 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700621 return;
622 }
623
624 delegate.mCap = cap;
625 }
626
627 /*package*/ static int native_getStrokeJoin(int native_object) {
628 // get the delegate from the native int.
629 Paint_Delegate delegate = sManager.getDelegate(native_object);
630 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700631 return 0;
632 }
633
634 return delegate.mJoin;
635 }
636
637 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
638 // get the delegate from the native int.
639 Paint_Delegate delegate = sManager.getDelegate(native_object);
640 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700641 return;
642 }
643
644 delegate.mJoin = join;
645 }
646
647 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800648 Paint_Delegate paint = sManager.getDelegate(native_object);
649 if (paint == null) {
650 return false;
651 }
652
653 Path_Delegate srcPath = Path_Delegate.getDelegate(src);
654 if (srcPath == null) {
655 return true;
656 }
657
658 Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
659 if (dstPath == null) {
660 return true;
661 }
662
663 Stroke stroke = paint.getJavaStroke();
664 Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
665
666 dstPath.setJavaShape(strokeShape);
667
668 // FIXME figure out the return value?
669 return true;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700670 }
671
672 /*package*/ static int native_setShader(int native_object, int shader) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700673 // get the delegate from the native int.
674 Paint_Delegate delegate = sManager.getDelegate(native_object);
675 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700676 return shader;
677 }
678
679 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700680 }
681
682 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700683 // get the delegate from the native int.
684 Paint_Delegate delegate = sManager.getDelegate(native_object);
685 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700686 return filter;
687 }
688
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800689 delegate.mColorFilter = filter;
690
691 // since none of those are supported, display a fidelity warning right away
692 ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
693 if (filterDelegate != null && filterDelegate.isSupported() == false) {
694 Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
695 }
696
697 return filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700698 }
699
700 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700701 // get the delegate from the native int.
702 Paint_Delegate delegate = sManager.getDelegate(native_object);
703 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700704 return xfermode;
705 }
706
707 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700708 }
709
710 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700711 // get the delegate from the native int.
712 Paint_Delegate delegate = sManager.getDelegate(native_object);
713 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700714 return effect;
715 }
716
717 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700718 }
719
720 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700721 // get the delegate from the native int.
722 Paint_Delegate delegate = sManager.getDelegate(native_object);
723 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700724 return maskfilter;
725 }
726
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800727 delegate.mMaskFilter = maskfilter;
728
729 // since none of those are supported, display a fidelity warning right away
730 MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
731 if (filterDelegate != null && filterDelegate.isSupported() == false) {
732 Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
733 }
734
735 return maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700736 }
737
738 /*package*/ static int native_setTypeface(int native_object, int typeface) {
739 // get the delegate from the native int.
740 Paint_Delegate delegate = sManager.getDelegate(native_object);
741 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700742 return 0;
743 }
744
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800745 delegate.mTypeface = typeface;
746 delegate.updateFontObject();
747 return delegate.mTypeface;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700748 }
749
750 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800751 // get the delegate from the native int.
752 Paint_Delegate delegate = sManager.getDelegate(native_object);
753 if (delegate == null) {
754 return rasterizer;
755 }
756
757 delegate.mRasterizer = rasterizer;
758
759 // since none of those are supported, display a fidelity warning right away
760 Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
761 if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
762 Bridge.getLog().fidelityWarning(null, rasterizerDelegate.getSupportMessage(), null);
763 }
764
765 return rasterizer;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700766 }
767
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700768 /*package*/ static int native_getTextAlign(int native_object) {
769 // get the delegate from the native int.
770 Paint_Delegate delegate = sManager.getDelegate(native_object);
771 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700772 return 0;
773 }
774
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700775 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700776 }
777
778 /*package*/ static void native_setTextAlign(int native_object, int align) {
779 // get the delegate from the native int.
780 Paint_Delegate delegate = sManager.getDelegate(native_object);
781 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700782 return;
783 }
784
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700785 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700786 }
787
788 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800789 // get the delegate from the native int.
790 Paint_Delegate delegate = sManager.getDelegate(native_paint);
791 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800792 return 0.f;
793 }
794
795 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700796 }
797
798 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
799 int count, float[] widths) {
800 // FIXME
801 throw new UnsupportedOperationException();
802 }
803
804 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
805 int end, float[] widths) {
806 // FIXME
807 throw new UnsupportedOperationException();
808 }
809
810 /*package*/ static float native_getTextRunAdvances(int native_object,
811 char[] text, int index, int count, int contextIndex, int contextCount,
812 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700813 // get the delegate from the native int.
814 Paint_Delegate delegate = sManager.getDelegate(native_object);
815 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700816 return 0.f;
817 }
818
819 if (delegate.mFonts.size() > 0) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700820 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700821 float totalAdvance = 0;
822 for (int i = 0; i < count; i++) {
823 char c = text[i + index];
824 boolean found = false;
825 for (FontInfo info : delegate.mFonts) {
826 if (info.mFont.canDisplay(c)) {
827 float adv = info.mMetrics.charWidth(c);
828 totalAdvance += adv;
829 if (advances != null) {
830 advances[i] = adv;
831 }
832
833 found = true;
834 break;
835 }
836 }
837
838 if (found == false) {
839 // no advance for this char.
840 if (advances != null) {
841 advances[i] = 0.f;
842 }
843 }
844 }
845
846 return totalAdvance;
847 }
848
849 return 0;
850
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700851 }
852
853 /*package*/ static float native_getTextRunAdvances(int native_object,
854 String text, int start, int end, int contextStart, int contextEnd,
855 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700856 // FIXME: support contextStart, contextEnd and direction flag
857 int count = end - start;
858 char[] buffer = TemporaryBuffer.obtain(count);
859 TextUtils.getChars(text, start, end, buffer, 0);
860
861 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
862 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700863 }
864
865 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
866 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
867 // FIXME
868 throw new UnsupportedOperationException();
869 }
870
871 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
872 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
873 // FIXME
874 throw new UnsupportedOperationException();
875 }
876
877 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
878 char[] text, int index, int count, float x, float y, int path) {
879 // FIXME
880 throw new UnsupportedOperationException();
881 }
882
883 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
884 String text, int start, int end, float x, float y, int path) {
885 // FIXME
886 throw new UnsupportedOperationException();
887 }
888
889 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
890 int end, Rect bounds) {
891 // FIXME
892 throw new UnsupportedOperationException();
893 }
894
895 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
896 int count, Rect bounds) {
897 // FIXME
898 throw new UnsupportedOperationException();
899 }
900
901 /*package*/ static void finalizer(int nativePaint) {
902 sManager.removeDelegate(nativePaint);
903 }
904
905 // ---- Private delegate/helper methods ----
906
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800907 /*package*/ Paint_Delegate() {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700908 reset();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700909 }
910
911 private Paint_Delegate(Paint_Delegate paint) {
912 set(paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700913 }
914
915 private void set(Paint_Delegate paint) {
916 mFlags = paint.mFlags;
917 mColor = paint.mColor;
918 mStyle = paint.mStyle;
919 mCap = paint.mCap;
920 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700921 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700922 mTypeface = paint.mTypeface;
923 mStrokeWidth = paint.mStrokeWidth;
924 mStrokeMiter = paint.mStrokeMiter;
925 mTextSize = paint.mTextSize;
926 mTextScaleX = paint.mTextScaleX;
927 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700928 mXfermode = paint.mXfermode;
929 mColorFilter = paint.mColorFilter;
930 mShader = paint.mShader;
931 mPathEffect = paint.mPathEffect;
932 mMaskFilter = paint.mMaskFilter;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800933 mRasterizer = paint.mRasterizer;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800934 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700935 }
936
937 private void reset() {
938 mFlags = Paint.DEFAULT_PAINT_FLAGS;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800939 mColor = 0xFF000000;
Xavier Ducrohet66225222010-12-21 01:33:04 -0800940 mStyle = Paint.Style.FILL.nativeInt;
941 mCap = Paint.Cap.BUTT.nativeInt;
942 mJoin = Paint.Join.MITER.nativeInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700943 mTextAlign = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800944 mTypeface = Typeface.sDefaults[0].native_instance;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700945 mStrokeWidth = 1.f;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800946 mStrokeMiter = 4.f;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700947 mTextSize = 20.f;
948 mTextScaleX = 1.f;
949 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700950 mXfermode = 0;
951 mColorFilter = 0;
952 mShader = 0;
953 mPathEffect = 0;
954 mMaskFilter = 0;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800955 mRasterizer = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800956 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700957 }
958
959 /**
960 * Update the {@link Font} object from the typeface, text size and scaling
961 */
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800962 @SuppressWarnings("deprecation")
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700963 private void updateFontObject() {
964 if (mTypeface != 0) {
965 // Get the fonts from the TypeFace object.
966 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
967
968 // create new font objects as well as FontMetrics, based on the current text size
969 // and skew info.
970 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
971 for (Font font : fonts) {
972 FontInfo info = new FontInfo();
973 info.mFont = font.deriveFont(mTextSize);
974 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
975 // TODO: support skew
976 info.mFont = info.mFont.deriveFont(new AffineTransform(
977 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
978 }
979 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
980
981 infoList.add(info);
982 }
983
984 mFonts = Collections.unmodifiableList(infoList);
985 }
986 }
987
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700988 /*package*/ float measureText(char[] text, int index, int count) {
989 if (mFonts.size() > 0) {
990 FontInfo mainFont = mFonts.get(0);
991 int i = index;
992 int lastIndex = index + count;
993 float total = 0f;
994 while (i < lastIndex) {
995 // always start with the main font.
996 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
997 if (upTo == -1) {
998 // shortcut to exit
999 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
1000 } else if (upTo > 0) {
1001 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
1002 i = upTo;
1003 // don't call continue at this point. Since it is certain the main font
1004 // cannot display the font a index upTo (now ==i), we move on to the
1005 // fallback fonts directly.
1006 }
1007
1008 // no char supported, attempt to read the next char(s) with the
1009 // fallback font. In this case we only test the first character
1010 // and then go back to test with the main font.
1011 // Special test for 2-char characters.
1012 boolean foundFont = false;
1013 for (int f = 1 ; f < mFonts.size() ; f++) {
1014 FontInfo fontInfo = mFonts.get(f);
1015
1016 // need to check that the font can display the character. We test
1017 // differently if the char is a high surrogate.
1018 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
1019 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
1020 if (upTo == -1) {
1021 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
1022 i += charCount;
1023 foundFont = true;
1024 break;
1025
1026 }
1027 }
1028
1029 // in case no font can display the char, measure it with the main font.
1030 if (foundFont == false) {
1031 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
1032 total += mainFont.mMetrics.charsWidth(text, i, size);
1033 i += size;
1034 }
1035 }
1036 }
1037
1038 return 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001039 }
1040
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -08001041 private float getFontMetrics(FontMetrics metrics) {
1042 if (mFonts.size() > 0) {
1043 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
1044 if (metrics != null) {
1045 // Android expects negative ascent so we invert the value from Java.
1046 metrics.top = - javaMetrics.getMaxAscent();
1047 metrics.ascent = - javaMetrics.getAscent();
1048 metrics.descent = javaMetrics.getDescent();
1049 metrics.bottom = javaMetrics.getMaxDescent();
1050 metrics.leading = javaMetrics.getLeading();
1051 }
1052
1053 return javaMetrics.getHeight();
1054 }
1055
1056 return 0;
1057 }
1058
1059
1060
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001061 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
1062 // get the delegate from the native int.
1063 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
1064 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001065 return;
1066 }
1067
1068 if (flagValue) {
1069 delegate.mFlags |= flagMask;
1070 } else {
1071 delegate.mFlags &= ~flagMask;
1072 }
1073 }
1074}