blob: 67afecae3493cc26a3b0b1c998da5a62c2bfb21b [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 Ducrohet3f9b0372011-01-13 10:59:34 -080019import com.android.ide.common.rendering.api.LayoutLog;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -080020import com.android.layoutlib.bridge.Bridge;
Xavier Ducrohet3bd98982010-11-09 18:25:03 -080021import com.android.layoutlib.bridge.impl.DelegateManager;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070022
23import android.graphics.Paint.FontMetrics;
24import android.graphics.Paint.FontMetricsInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070025import android.text.TextUtils;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070026
Xavier Ducrohet37f21802010-11-01 16:17:18 -070027import java.awt.BasicStroke;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070028import java.awt.Font;
Xavier Ducrohetb9761242010-12-23 10:22:14 -080029import java.awt.Shape;
30import java.awt.Stroke;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070031import java.awt.Toolkit;
32import java.awt.font.FontRenderContext;
33import java.awt.geom.AffineTransform;
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.List;
37
38/**
39 * Delegate implementing the native methods of android.graphics.Paint
40 *
41 * Through the layoutlib_create tool, the original native methods of Paint have been replaced
42 * by calls to methods of the same name in this delegate class.
43 *
44 * This class behaves like the original native implementation, but in Java, keeping previously
45 * native data into its own objects and mapping them to int that are sent back and forth between
46 * it and the original Paint class.
47 *
48 * @see DelegateManager
49 *
50 */
51public class Paint_Delegate {
52
53 /**
54 * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
55 */
Xavier Ducrohet37f21802010-11-01 16:17:18 -070056 /*package*/ static final class FontInfo {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070057 Font mFont;
58 java.awt.FontMetrics mMetrics;
59 }
60
61 // ---- delegate manager ----
62 private static final DelegateManager<Paint_Delegate> sManager =
63 new DelegateManager<Paint_Delegate>();
64
65 // ---- delegate helper data ----
66 private List<FontInfo> mFonts;
67 private final FontRenderContext mFontContext = new FontRenderContext(
68 new AffineTransform(), true, true);
69
70 // ---- delegate data ----
71 private int mFlags;
72 private int mColor;
73 private int mStyle;
74 private int mCap;
75 private int mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070076 private int mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070077 private int mTypeface;
78 private float mStrokeWidth;
79 private float mStrokeMiter;
80 private float mTextSize;
81 private float mTextScaleX;
82 private float mTextSkewX;
83
Xavier Ducroheta313b652010-11-01 18:45:20 -070084 private int mXfermode;
85 private int mColorFilter;
86 private int mShader;
87 private int mPathEffect;
88 private int mMaskFilter;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -080089 private int mRasterizer;
Xavier Ducroheta313b652010-11-01 18:45:20 -070090
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070091
92 // ---- Public Helper methods ----
93
Xavier Ducrohet37f21802010-11-01 16:17:18 -070094 public static Paint_Delegate getDelegate(int native_paint) {
95 return sManager.getDelegate(native_paint);
96 }
97
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070098 /**
99 * Returns the list of {@link Font} objects. The first item is the main font, the rest
100 * are fall backs for characters not present in the main font.
101 */
102 public List<FontInfo> getFonts() {
103 return mFonts;
104 }
105
Xavier Ducroheta313b652010-11-01 18:45:20 -0700106 public boolean isAntiAliased() {
107 return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
108 }
109
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700110 public boolean isFilterBitmap() {
111 return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
112 }
113
114 public int getStyle() {
115 return mStyle;
116 }
117
118 public int getColor() {
119 return mColor;
120 }
121
Xavier Ducrohet66225222010-12-21 01:33:04 -0800122 public int getAlpha() {
123 return mColor >>> 24;
124 }
125
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800126 public void setAlpha(int alpha) {
127 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
128 }
129
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700130 public int getTextAlign() {
131 return mTextAlign;
132 }
133
134 public float getStrokeWidth() {
135 return mStrokeWidth;
136 }
137
Xavier Ducrohet66225222010-12-21 01:33:04 -0800138 /**
139 * returns the value of stroke miter needed by the java api.
140 */
141 public float getJavaStrokeMiter() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800142 float miter = mStrokeMiter * mStrokeWidth;
143 if (miter < 1.f) {
144 miter = 1.f;
145 }
146 return miter;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700147 }
148
149 public int getJavaCap() {
150 switch (Paint.sCapArray[mCap]) {
151 case BUTT:
152 return BasicStroke.CAP_BUTT;
153 case ROUND:
154 return BasicStroke.CAP_ROUND;
155 default:
156 case SQUARE:
157 return BasicStroke.CAP_SQUARE;
158 }
159 }
160
161 public int getJavaJoin() {
162 switch (Paint.sJoinArray[mJoin]) {
163 default:
164 case MITER:
165 return BasicStroke.JOIN_MITER;
166 case ROUND:
167 return BasicStroke.JOIN_ROUND;
168 case BEVEL:
169 return BasicStroke.JOIN_BEVEL;
170 }
171 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700172
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800173 public Stroke getJavaStroke() {
174 PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
175 if (effectDelegate != null) {
176 if (effectDelegate.isSupported()) {
177 Stroke stroke = effectDelegate.getStroke(this);
178 assert stroke != null;
179 if (stroke != null) {
180 return stroke;
181 }
182 } else {
Xavier Ducrohet3f9b0372011-01-13 10:59:34 -0800183 Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800184 effectDelegate.getSupportMessage(),
185 null);
186 }
187 }
188
189 // if no custom stroke as been set, set the default one.
190 return new BasicStroke(
191 getStrokeWidth(),
192 getJavaCap(),
193 getJavaJoin(),
194 getJavaStrokeMiter());
195 }
196
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800197 /**
198 * Returns the {@link Xfermode} delegate or null if none have been set
199 *
200 * @return the delegate or null.
201 */
202 public Xfermode_Delegate getXfermode() {
203 return Xfermode_Delegate.getDelegate(mXfermode);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700204 }
205
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800206 /**
207 * Returns the {@link ColorFilter} delegate or null if none have been set
208 *
209 * @return the delegate or null.
210 */
211 public ColorFilter_Delegate getColorFilter() {
212 return ColorFilter_Delegate.getDelegate(mColorFilter);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700213 }
214
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800215 /**
216 * Returns the {@link Shader} delegate or null if none have been set
217 *
218 * @return the delegate or null.
219 */
220 public Shader_Delegate getShader() {
221 return Shader_Delegate.getDelegate(mShader);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700222 }
223
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800224 /**
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800225 * Returns the {@link MaskFilter} delegate or null if none have been set
226 *
227 * @return the delegate or null.
228 */
229 public MaskFilter_Delegate getMaskFilter() {
230 return MaskFilter_Delegate.getDelegate(mMaskFilter);
231 }
232
233 /**
234 * Returns the {@link Rasterizer} delegate or null if none have been set
235 *
236 * @return the delegate or null.
237 */
238 public Rasterizer_Delegate getRasterizer() {
239 return Rasterizer_Delegate.getDelegate(mRasterizer);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700240 }
241
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700242 // ---- native methods ----
243
244 /*package*/ static int getFlags(Paint thisPaint) {
245 // get the delegate from the native int.
246 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
247 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700248 return 0;
249 }
250
251 return delegate.mFlags;
252 }
253
254 /*package*/ static void setFlags(Paint thisPaint, int flags) {
255 // get the delegate from the native int.
256 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
257 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700258 return;
259 }
260
261 delegate.mFlags = flags;
262 }
263
264 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700265 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700266 }
267
268 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
269 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
270 }
271
272 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
273 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
274 }
275
276 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
277 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
278 }
279
280 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
281 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
282 }
283
284 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
285 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
286 }
287
288 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
289 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
290 }
291
292 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
293 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
294 }
295
296 /*package*/ static int getColor(Paint thisPaint) {
297 // get the delegate from the native int.
298 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
299 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700300 return 0;
301 }
302
303 return delegate.mColor;
304 }
305
306 /*package*/ static void setColor(Paint thisPaint, int color) {
307 // get the delegate from the native int.
308 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
309 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700310 return;
311 }
312
313 delegate.mColor = color;
314 }
315
316 /*package*/ static int getAlpha(Paint thisPaint) {
317 // get the delegate from the native int.
318 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
319 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700320 return 0;
321 }
322
Xavier Ducrohet66225222010-12-21 01:33:04 -0800323 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700324 }
325
326 /*package*/ static void setAlpha(Paint thisPaint, int a) {
327 // get the delegate from the native int.
328 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
329 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700330 return;
331 }
332
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800333 delegate.setAlpha(a);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700334 }
335
336 /*package*/ static float getStrokeWidth(Paint thisPaint) {
337 // get the delegate from the native int.
338 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
339 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700340 return 1.f;
341 }
342
343 return delegate.mStrokeWidth;
344 }
345
346 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
347 // get the delegate from the native int.
348 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
349 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700350 return;
351 }
352
353 delegate.mStrokeWidth = width;
354 }
355
356 /*package*/ static float getStrokeMiter(Paint thisPaint) {
357 // get the delegate from the native int.
358 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
359 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700360 return 1.f;
361 }
362
363 return delegate.mStrokeMiter;
364 }
365
366 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
367 // get the delegate from the native int.
368 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
369 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700370 return;
371 }
372
373 delegate.mStrokeMiter = miter;
374 }
375
376 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
377 int color) {
378 // FIXME
Xavier Ducrohet3f9b0372011-01-13 10:59:34 -0800379 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
Xavier Ducrohetef78fd22011-01-12 15:59:49 -0800380 "Paint.setShadowLayer is not supported.", null);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700381 }
382
383 /*package*/ static float getTextSize(Paint thisPaint) {
384 // get the delegate from the native int.
385 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
386 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700387 return 1.f;
388 }
389
390 return delegate.mTextSize;
391 }
392
393 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
394 // get the delegate from the native int.
395 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
396 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700397 return;
398 }
399
400 delegate.mTextSize = textSize;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800401 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700402 }
403
404 /*package*/ static float getTextScaleX(Paint thisPaint) {
405 // get the delegate from the native int.
406 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
407 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700408 return 1.f;
409 }
410
411 return delegate.mTextScaleX;
412 }
413
414 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
415 // get the delegate from the native int.
416 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
417 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700418 return;
419 }
420
421 delegate.mTextScaleX = scaleX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800422 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700423 }
424
425 /*package*/ static float getTextSkewX(Paint thisPaint) {
426 // get the delegate from the native int.
427 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
428 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700429 return 1.f;
430 }
431
432 return delegate.mTextSkewX;
433 }
434
435 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
436 // get the delegate from the native int.
437 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
438 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700439 return;
440 }
441
442 delegate.mTextSkewX = skewX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800443 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700444 }
445
446 /*package*/ static float ascent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800447 // get the delegate
448 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
449 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800450 return 0;
451 }
452
453 if (delegate.mFonts.size() > 0) {
454 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
455 // Android expects negative ascent so we invert the value from Java.
456 return - javaMetrics.getAscent();
457 }
458
459 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700460 }
461
462 /*package*/ static float descent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800463 // get the delegate
464 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
465 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800466 return 0;
467 }
468
469 if (delegate.mFonts.size() > 0) {
470 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
471 return javaMetrics.getDescent();
472 }
473
474 return 0;
475
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700476 }
477
478 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700479 // get the delegate
480 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
481 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700482 return 0;
483 }
484
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800485 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700486 }
487
488 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700489 // get the delegate
490 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
491 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700492 return 0;
493 }
494
495 if (delegate.mFonts.size() > 0) {
496 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
497 if (fmi != null) {
498 // Android expects negative ascent so we invert the value from Java.
499 fmi.top = - javaMetrics.getMaxAscent();
500 fmi.ascent = - javaMetrics.getAscent();
501 fmi.descent = javaMetrics.getDescent();
502 fmi.bottom = javaMetrics.getMaxDescent();
503 fmi.leading = javaMetrics.getLeading();
504 }
505
506 return javaMetrics.getHeight();
507 }
508
509 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700510 }
511
512 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
513 int count) {
514 // WARNING: the logic in this method is similar to Canvas.drawText.
515 // Any change to this method should be reflected in Canvas.drawText
516
517 // get the delegate
518 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
519 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700520 return 0;
521 }
522
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700523 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700524 }
525
526 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
527 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
528 }
529
530 /*package*/ static float native_measureText(Paint thisPaint, String text) {
531 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
532 }
533
534 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
535 float maxWidth, float[] measuredWidth) {
536 // FIXME
537 throw new UnsupportedOperationException();
538 }
539
540 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
541 float maxWidth, float[] measuredWidth) {
542 // FIXME
543 throw new UnsupportedOperationException();
544 }
545
546
547 /*package*/ static int native_init() {
548 Paint_Delegate newDelegate = new Paint_Delegate();
549 return sManager.addDelegate(newDelegate);
550 }
551
552 /*package*/ static int native_initWithPaint(int paint) {
553 // get the delegate from the native int.
554 Paint_Delegate delegate = sManager.getDelegate(paint);
555 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700556 return 0;
557 }
558
559 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
560 return sManager.addDelegate(newDelegate);
561 }
562
563 /*package*/ static void native_reset(int native_object) {
564 // get the delegate from the native int.
565 Paint_Delegate delegate = sManager.getDelegate(native_object);
566 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700567 return;
568 }
569
570 delegate.reset();
571 }
572
573 /*package*/ static void native_set(int native_dst, int native_src) {
574 // get the delegate from the native int.
575 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
576 if (delegate_dst == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700577 return;
578 }
579
580 // get the delegate from the native int.
581 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
582 if (delegate_src == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700583 return;
584 }
585
586 delegate_dst.set(delegate_src);
587 }
588
589 /*package*/ static int native_getStyle(int native_object) {
590 // get the delegate from the native int.
591 Paint_Delegate delegate = sManager.getDelegate(native_object);
592 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700593 return 0;
594 }
595
596 return delegate.mStyle;
597 }
598
599 /*package*/ static void native_setStyle(int native_object, int style) {
600 // get the delegate from the native int.
601 Paint_Delegate delegate = sManager.getDelegate(native_object);
602 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700603 return;
604 }
605
606 delegate.mStyle = style;
607 }
608
609 /*package*/ static int native_getStrokeCap(int native_object) {
610 // get the delegate from the native int.
611 Paint_Delegate delegate = sManager.getDelegate(native_object);
612 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700613 return 0;
614 }
615
616 return delegate.mCap;
617 }
618
619 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
620 // get the delegate from the native int.
621 Paint_Delegate delegate = sManager.getDelegate(native_object);
622 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700623 return;
624 }
625
626 delegate.mCap = cap;
627 }
628
629 /*package*/ static int native_getStrokeJoin(int native_object) {
630 // get the delegate from the native int.
631 Paint_Delegate delegate = sManager.getDelegate(native_object);
632 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700633 return 0;
634 }
635
636 return delegate.mJoin;
637 }
638
639 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
640 // get the delegate from the native int.
641 Paint_Delegate delegate = sManager.getDelegate(native_object);
642 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700643 return;
644 }
645
646 delegate.mJoin = join;
647 }
648
649 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800650 Paint_Delegate paint = sManager.getDelegate(native_object);
651 if (paint == null) {
652 return false;
653 }
654
655 Path_Delegate srcPath = Path_Delegate.getDelegate(src);
656 if (srcPath == null) {
657 return true;
658 }
659
660 Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
661 if (dstPath == null) {
662 return true;
663 }
664
665 Stroke stroke = paint.getJavaStroke();
666 Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
667
668 dstPath.setJavaShape(strokeShape);
669
670 // FIXME figure out the return value?
671 return true;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700672 }
673
674 /*package*/ static int native_setShader(int native_object, int shader) {
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) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700678 return shader;
679 }
680
681 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700682 }
683
684 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700685 // get the delegate from the native int.
686 Paint_Delegate delegate = sManager.getDelegate(native_object);
687 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700688 return filter;
689 }
690
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800691 delegate.mColorFilter = filter;
692
693 // since none of those are supported, display a fidelity warning right away
694 ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
695 if (filterDelegate != null && filterDelegate.isSupported() == false) {
Xavier Ducrohet3f9b0372011-01-13 10:59:34 -0800696 Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
Xavier Ducrohetef78fd22011-01-12 15:59:49 -0800697 filterDelegate.getSupportMessage(), null);
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800698 }
699
700 return filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700701 }
702
703 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700704 // get the delegate from the native int.
705 Paint_Delegate delegate = sManager.getDelegate(native_object);
706 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700707 return xfermode;
708 }
709
710 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700711 }
712
713 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700714 // get the delegate from the native int.
715 Paint_Delegate delegate = sManager.getDelegate(native_object);
716 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700717 return effect;
718 }
719
720 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700721 }
722
723 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700724 // get the delegate from the native int.
725 Paint_Delegate delegate = sManager.getDelegate(native_object);
726 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700727 return maskfilter;
728 }
729
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800730 delegate.mMaskFilter = maskfilter;
731
732 // since none of those are supported, display a fidelity warning right away
733 MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
734 if (filterDelegate != null && filterDelegate.isSupported() == false) {
Xavier Ducrohet3f9b0372011-01-13 10:59:34 -0800735 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
Xavier Ducrohetef78fd22011-01-12 15:59:49 -0800736 filterDelegate.getSupportMessage(), null);
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800737 }
738
739 return maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700740 }
741
742 /*package*/ static int native_setTypeface(int native_object, int typeface) {
743 // get the delegate from the native int.
744 Paint_Delegate delegate = sManager.getDelegate(native_object);
745 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700746 return 0;
747 }
748
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800749 delegate.mTypeface = typeface;
750 delegate.updateFontObject();
751 return delegate.mTypeface;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700752 }
753
754 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800755 // get the delegate from the native int.
756 Paint_Delegate delegate = sManager.getDelegate(native_object);
757 if (delegate == null) {
758 return rasterizer;
759 }
760
761 delegate.mRasterizer = rasterizer;
762
763 // since none of those are supported, display a fidelity warning right away
764 Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
765 if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
Xavier Ducrohet3f9b0372011-01-13 10:59:34 -0800766 Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
Xavier Ducrohetef78fd22011-01-12 15:59:49 -0800767 rasterizerDelegate.getSupportMessage(), null);
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800768 }
769
770 return rasterizer;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700771 }
772
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700773 /*package*/ static int native_getTextAlign(int native_object) {
774 // get the delegate from the native int.
775 Paint_Delegate delegate = sManager.getDelegate(native_object);
776 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700777 return 0;
778 }
779
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700780 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700781 }
782
783 /*package*/ static void native_setTextAlign(int native_object, int align) {
784 // get the delegate from the native int.
785 Paint_Delegate delegate = sManager.getDelegate(native_object);
786 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700787 return;
788 }
789
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700790 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700791 }
792
793 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800794 // get the delegate from the native int.
795 Paint_Delegate delegate = sManager.getDelegate(native_paint);
796 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800797 return 0.f;
798 }
799
800 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700801 }
802
803 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
804 int count, float[] widths) {
805 // FIXME
806 throw new UnsupportedOperationException();
807 }
808
809 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
810 int end, float[] widths) {
811 // FIXME
812 throw new UnsupportedOperationException();
813 }
814
815 /*package*/ static float native_getTextRunAdvances(int native_object,
816 char[] text, int index, int count, int contextIndex, int contextCount,
817 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700818 // get the delegate from the native int.
819 Paint_Delegate delegate = sManager.getDelegate(native_object);
820 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700821 return 0.f;
822 }
823
824 if (delegate.mFonts.size() > 0) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700825 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700826 float totalAdvance = 0;
827 for (int i = 0; i < count; i++) {
828 char c = text[i + index];
829 boolean found = false;
830 for (FontInfo info : delegate.mFonts) {
831 if (info.mFont.canDisplay(c)) {
832 float adv = info.mMetrics.charWidth(c);
833 totalAdvance += adv;
834 if (advances != null) {
835 advances[i] = adv;
836 }
837
838 found = true;
839 break;
840 }
841 }
842
843 if (found == false) {
844 // no advance for this char.
845 if (advances != null) {
846 advances[i] = 0.f;
847 }
848 }
849 }
850
851 return totalAdvance;
852 }
853
854 return 0;
855
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700856 }
857
858 /*package*/ static float native_getTextRunAdvances(int native_object,
859 String text, int start, int end, int contextStart, int contextEnd,
860 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700861 // FIXME: support contextStart, contextEnd and direction flag
862 int count = end - start;
863 char[] buffer = TemporaryBuffer.obtain(count);
864 TextUtils.getChars(text, start, end, buffer, 0);
865
866 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
867 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700868 }
869
870 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
871 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
872 // FIXME
873 throw new UnsupportedOperationException();
874 }
875
876 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
877 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
878 // FIXME
879 throw new UnsupportedOperationException();
880 }
881
882 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
883 char[] text, int index, int count, float x, float y, int path) {
884 // FIXME
885 throw new UnsupportedOperationException();
886 }
887
888 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
889 String text, int start, int end, float x, float y, int path) {
890 // FIXME
891 throw new UnsupportedOperationException();
892 }
893
894 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
895 int end, Rect bounds) {
896 // FIXME
897 throw new UnsupportedOperationException();
898 }
899
900 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
901 int count, Rect bounds) {
902 // FIXME
903 throw new UnsupportedOperationException();
904 }
905
906 /*package*/ static void finalizer(int nativePaint) {
907 sManager.removeDelegate(nativePaint);
908 }
909
910 // ---- Private delegate/helper methods ----
911
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800912 /*package*/ Paint_Delegate() {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700913 reset();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700914 }
915
916 private Paint_Delegate(Paint_Delegate paint) {
917 set(paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700918 }
919
920 private void set(Paint_Delegate paint) {
921 mFlags = paint.mFlags;
922 mColor = paint.mColor;
923 mStyle = paint.mStyle;
924 mCap = paint.mCap;
925 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700926 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700927 mTypeface = paint.mTypeface;
928 mStrokeWidth = paint.mStrokeWidth;
929 mStrokeMiter = paint.mStrokeMiter;
930 mTextSize = paint.mTextSize;
931 mTextScaleX = paint.mTextScaleX;
932 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700933 mXfermode = paint.mXfermode;
934 mColorFilter = paint.mColorFilter;
935 mShader = paint.mShader;
936 mPathEffect = paint.mPathEffect;
937 mMaskFilter = paint.mMaskFilter;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800938 mRasterizer = paint.mRasterizer;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800939 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700940 }
941
942 private void reset() {
943 mFlags = Paint.DEFAULT_PAINT_FLAGS;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800944 mColor = 0xFF000000;
Xavier Ducrohet66225222010-12-21 01:33:04 -0800945 mStyle = Paint.Style.FILL.nativeInt;
946 mCap = Paint.Cap.BUTT.nativeInt;
947 mJoin = Paint.Join.MITER.nativeInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700948 mTextAlign = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800949 mTypeface = Typeface.sDefaults[0].native_instance;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700950 mStrokeWidth = 1.f;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800951 mStrokeMiter = 4.f;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700952 mTextSize = 20.f;
953 mTextScaleX = 1.f;
954 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700955 mXfermode = 0;
956 mColorFilter = 0;
957 mShader = 0;
958 mPathEffect = 0;
959 mMaskFilter = 0;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800960 mRasterizer = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800961 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700962 }
963
964 /**
965 * Update the {@link Font} object from the typeface, text size and scaling
966 */
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800967 @SuppressWarnings("deprecation")
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700968 private void updateFontObject() {
969 if (mTypeface != 0) {
970 // Get the fonts from the TypeFace object.
971 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
972
973 // create new font objects as well as FontMetrics, based on the current text size
974 // and skew info.
975 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
976 for (Font font : fonts) {
977 FontInfo info = new FontInfo();
978 info.mFont = font.deriveFont(mTextSize);
979 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
980 // TODO: support skew
981 info.mFont = info.mFont.deriveFont(new AffineTransform(
982 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
983 }
984 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
985
986 infoList.add(info);
987 }
988
989 mFonts = Collections.unmodifiableList(infoList);
990 }
991 }
992
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700993 /*package*/ float measureText(char[] text, int index, int count) {
994 if (mFonts.size() > 0) {
995 FontInfo mainFont = mFonts.get(0);
996 int i = index;
997 int lastIndex = index + count;
998 float total = 0f;
999 while (i < lastIndex) {
1000 // always start with the main font.
1001 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
1002 if (upTo == -1) {
1003 // shortcut to exit
1004 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
1005 } else if (upTo > 0) {
1006 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
1007 i = upTo;
1008 // don't call continue at this point. Since it is certain the main font
1009 // cannot display the font a index upTo (now ==i), we move on to the
1010 // fallback fonts directly.
1011 }
1012
1013 // no char supported, attempt to read the next char(s) with the
1014 // fallback font. In this case we only test the first character
1015 // and then go back to test with the main font.
1016 // Special test for 2-char characters.
1017 boolean foundFont = false;
1018 for (int f = 1 ; f < mFonts.size() ; f++) {
1019 FontInfo fontInfo = mFonts.get(f);
1020
1021 // need to check that the font can display the character. We test
1022 // differently if the char is a high surrogate.
1023 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
1024 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
1025 if (upTo == -1) {
1026 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
1027 i += charCount;
1028 foundFont = true;
1029 break;
1030
1031 }
1032 }
1033
1034 // in case no font can display the char, measure it with the main font.
1035 if (foundFont == false) {
1036 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
1037 total += mainFont.mMetrics.charsWidth(text, i, size);
1038 i += size;
1039 }
1040 }
1041 }
1042
1043 return 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001044 }
1045
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -08001046 private float getFontMetrics(FontMetrics metrics) {
1047 if (mFonts.size() > 0) {
1048 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
1049 if (metrics != null) {
1050 // Android expects negative ascent so we invert the value from Java.
1051 metrics.top = - javaMetrics.getMaxAscent();
1052 metrics.ascent = - javaMetrics.getAscent();
1053 metrics.descent = javaMetrics.getDescent();
1054 metrics.bottom = javaMetrics.getMaxDescent();
1055 metrics.leading = javaMetrics.getLeading();
1056 }
1057
1058 return javaMetrics.getHeight();
1059 }
1060
1061 return 0;
1062 }
1063
1064
1065
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001066 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
1067 // get the delegate from the native int.
1068 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
1069 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001070 return;
1071 }
1072
1073 if (flagValue) {
1074 delegate.mFlags |= flagMask;
1075 } else {
1076 delegate.mFlags &= ~flagMask;
1077 }
1078 }
1079}