blob: fc58475a0214c2ab0d811ef6708933a90501d79e [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;
28import java.awt.Toolkit;
29import java.awt.font.FontRenderContext;
30import java.awt.geom.AffineTransform;
31import java.util.ArrayList;
32import java.util.Collections;
33import java.util.List;
34
35/**
36 * Delegate implementing the native methods of android.graphics.Paint
37 *
38 * Through the layoutlib_create tool, the original native methods of Paint have been replaced
39 * by calls to methods of the same name in this delegate class.
40 *
41 * This class behaves like the original native implementation, but in Java, keeping previously
42 * native data into its own objects and mapping them to int that are sent back and forth between
43 * it and the original Paint class.
44 *
45 * @see DelegateManager
46 *
47 */
48public class Paint_Delegate {
49
50 /**
51 * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
52 */
Xavier Ducrohet37f21802010-11-01 16:17:18 -070053 /*package*/ static final class FontInfo {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070054 Font mFont;
55 java.awt.FontMetrics mMetrics;
56 }
57
58 // ---- delegate manager ----
59 private static final DelegateManager<Paint_Delegate> sManager =
60 new DelegateManager<Paint_Delegate>();
61
62 // ---- delegate helper data ----
63 private List<FontInfo> mFonts;
64 private final FontRenderContext mFontContext = new FontRenderContext(
65 new AffineTransform(), true, true);
66
67 // ---- delegate data ----
68 private int mFlags;
69 private int mColor;
70 private int mStyle;
71 private int mCap;
72 private int mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070073 private int mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070074 private int mTypeface;
75 private float mStrokeWidth;
76 private float mStrokeMiter;
77 private float mTextSize;
78 private float mTextScaleX;
79 private float mTextSkewX;
80
Xavier Ducroheta313b652010-11-01 18:45:20 -070081 private int mXfermode;
82 private int mColorFilter;
83 private int mShader;
84 private int mPathEffect;
85 private int mMaskFilter;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -080086 private int mRasterizer;
Xavier Ducroheta313b652010-11-01 18:45:20 -070087
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070088
89 // ---- Public Helper methods ----
90
Xavier Ducrohet37f21802010-11-01 16:17:18 -070091 public static Paint_Delegate getDelegate(int native_paint) {
92 return sManager.getDelegate(native_paint);
93 }
94
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070095 /**
96 * Returns the list of {@link Font} objects. The first item is the main font, the rest
97 * are fall backs for characters not present in the main font.
98 */
99 public List<FontInfo> getFonts() {
100 return mFonts;
101 }
102
Xavier Ducroheta313b652010-11-01 18:45:20 -0700103 public boolean isAntiAliased() {
104 return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
105 }
106
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700107 public boolean isFilterBitmap() {
108 return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
109 }
110
111 public int getStyle() {
112 return mStyle;
113 }
114
115 public int getColor() {
116 return mColor;
117 }
118
Xavier Ducrohet66225222010-12-21 01:33:04 -0800119 public int getAlpha() {
120 return mColor >>> 24;
121 }
122
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800123 public void setAlpha(int alpha) {
124 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
125 }
126
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700127 public int getTextAlign() {
128 return mTextAlign;
129 }
130
131 public float getStrokeWidth() {
132 return mStrokeWidth;
133 }
134
Xavier Ducrohet66225222010-12-21 01:33:04 -0800135 /**
136 * returns the value of stroke miter needed by the java api.
137 */
138 public float getJavaStrokeMiter() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800139 float miter = mStrokeMiter * mStrokeWidth;
140 if (miter < 1.f) {
141 miter = 1.f;
142 }
143 return miter;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700144 }
145
146 public int getJavaCap() {
147 switch (Paint.sCapArray[mCap]) {
148 case BUTT:
149 return BasicStroke.CAP_BUTT;
150 case ROUND:
151 return BasicStroke.CAP_ROUND;
152 default:
153 case SQUARE:
154 return BasicStroke.CAP_SQUARE;
155 }
156 }
157
158 public int getJavaJoin() {
159 switch (Paint.sJoinArray[mJoin]) {
160 default:
161 case MITER:
162 return BasicStroke.JOIN_MITER;
163 case ROUND:
164 return BasicStroke.JOIN_ROUND;
165 case BEVEL:
166 return BasicStroke.JOIN_BEVEL;
167 }
168 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700169
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800170 /**
171 * Returns the {@link Xfermode} delegate or null if none have been set
172 *
173 * @return the delegate or null.
174 */
175 public Xfermode_Delegate getXfermode() {
176 return Xfermode_Delegate.getDelegate(mXfermode);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700177 }
178
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800179 /**
180 * Returns the {@link ColorFilter} delegate or null if none have been set
181 *
182 * @return the delegate or null.
183 */
184 public ColorFilter_Delegate getColorFilter() {
185 return ColorFilter_Delegate.getDelegate(mColorFilter);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700186 }
187
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800188 /**
189 * Returns the {@link Shader} delegate or null if none have been set
190 *
191 * @return the delegate or null.
192 */
193 public Shader_Delegate getShader() {
194 return Shader_Delegate.getDelegate(mShader);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700195 }
196
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800197 /**
198 * Returns the {@link PathEffect} delegate or null if none have been set
199 *
200 * @return the delegate or null.
201 */
202 public PathEffect_Delegate getPathEffect() {
203 return PathEffect_Delegate.getDelegate(mPathEffect);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700204 }
205
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800206 /**
207 * Returns the {@link MaskFilter} delegate or null if none have been set
208 *
209 * @return the delegate or null.
210 */
211 public MaskFilter_Delegate getMaskFilter() {
212 return MaskFilter_Delegate.getDelegate(mMaskFilter);
213 }
214
215 /**
216 * Returns the {@link Rasterizer} delegate or null if none have been set
217 *
218 * @return the delegate or null.
219 */
220 public Rasterizer_Delegate getRasterizer() {
221 return Rasterizer_Delegate.getDelegate(mRasterizer);
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700222 }
223
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700224 // ---- native methods ----
225
226 /*package*/ static int getFlags(Paint thisPaint) {
227 // get the delegate from the native int.
228 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
229 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700230 return 0;
231 }
232
233 return delegate.mFlags;
234 }
235
236 /*package*/ static void setFlags(Paint thisPaint, int flags) {
237 // get the delegate from the native int.
238 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
239 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700240 return;
241 }
242
243 delegate.mFlags = flags;
244 }
245
246 /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700247 setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700248 }
249
250 /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
251 setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
252 }
253
254 /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
255 setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
256 }
257
258 /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
259 setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
260 }
261
262 /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
263 setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
264 }
265
266 /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
267 setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
268 }
269
270 /*package*/ static void setDither(Paint thisPaint, boolean dither) {
271 setFlag(thisPaint, Paint.DITHER_FLAG, dither);
272 }
273
274 /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
275 setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
276 }
277
278 /*package*/ static int getColor(Paint thisPaint) {
279 // get the delegate from the native int.
280 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
281 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700282 return 0;
283 }
284
285 return delegate.mColor;
286 }
287
288 /*package*/ static void setColor(Paint thisPaint, int color) {
289 // get the delegate from the native int.
290 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
291 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700292 return;
293 }
294
295 delegate.mColor = color;
296 }
297
298 /*package*/ static int getAlpha(Paint thisPaint) {
299 // get the delegate from the native int.
300 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
301 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700302 return 0;
303 }
304
Xavier Ducrohet66225222010-12-21 01:33:04 -0800305 return delegate.getAlpha();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700306 }
307
308 /*package*/ static void setAlpha(Paint thisPaint, int a) {
309 // get the delegate from the native int.
310 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
311 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700312 return;
313 }
314
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800315 delegate.setAlpha(a);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700316 }
317
318 /*package*/ static float getStrokeWidth(Paint thisPaint) {
319 // get the delegate from the native int.
320 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
321 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700322 return 1.f;
323 }
324
325 return delegate.mStrokeWidth;
326 }
327
328 /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
329 // get the delegate from the native int.
330 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
331 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700332 return;
333 }
334
335 delegate.mStrokeWidth = width;
336 }
337
338 /*package*/ static float getStrokeMiter(Paint thisPaint) {
339 // get the delegate from the native int.
340 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
341 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700342 return 1.f;
343 }
344
345 return delegate.mStrokeMiter;
346 }
347
348 /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
349 // get the delegate from the native int.
350 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
351 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700352 return;
353 }
354
355 delegate.mStrokeMiter = miter;
356 }
357
358 /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
359 int color) {
360 // FIXME
361 throw new UnsupportedOperationException();
362 }
363
364 /*package*/ static float getTextSize(Paint thisPaint) {
365 // get the delegate from the native int.
366 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
367 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700368 return 1.f;
369 }
370
371 return delegate.mTextSize;
372 }
373
374 /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
375 // get the delegate from the native int.
376 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
377 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700378 return;
379 }
380
381 delegate.mTextSize = textSize;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800382 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700383 }
384
385 /*package*/ static float getTextScaleX(Paint thisPaint) {
386 // get the delegate from the native int.
387 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
388 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700389 return 1.f;
390 }
391
392 return delegate.mTextScaleX;
393 }
394
395 /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
396 // get the delegate from the native int.
397 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
398 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700399 return;
400 }
401
402 delegate.mTextScaleX = scaleX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800403 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700404 }
405
406 /*package*/ static float getTextSkewX(Paint thisPaint) {
407 // get the delegate from the native int.
408 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
409 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700410 return 1.f;
411 }
412
413 return delegate.mTextSkewX;
414 }
415
416 /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
417 // get the delegate from the native int.
418 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
419 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700420 return;
421 }
422
423 delegate.mTextSkewX = skewX;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800424 delegate.updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700425 }
426
427 /*package*/ static float ascent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800428 // get the delegate
429 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
430 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800431 return 0;
432 }
433
434 if (delegate.mFonts.size() > 0) {
435 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
436 // Android expects negative ascent so we invert the value from Java.
437 return - javaMetrics.getAscent();
438 }
439
440 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700441 }
442
443 /*package*/ static float descent(Paint thisPaint) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800444 // get the delegate
445 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
446 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800447 return 0;
448 }
449
450 if (delegate.mFonts.size() > 0) {
451 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
452 return javaMetrics.getDescent();
453 }
454
455 return 0;
456
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700457 }
458
459 /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700460 // get the delegate
461 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
462 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700463 return 0;
464 }
465
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800466 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700467 }
468
469 /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700470 // get the delegate
471 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
472 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700473 return 0;
474 }
475
476 if (delegate.mFonts.size() > 0) {
477 java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
478 if (fmi != null) {
479 // Android expects negative ascent so we invert the value from Java.
480 fmi.top = - javaMetrics.getMaxAscent();
481 fmi.ascent = - javaMetrics.getAscent();
482 fmi.descent = javaMetrics.getDescent();
483 fmi.bottom = javaMetrics.getMaxDescent();
484 fmi.leading = javaMetrics.getLeading();
485 }
486
487 return javaMetrics.getHeight();
488 }
489
490 return 0;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700491 }
492
493 /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
494 int count) {
495 // WARNING: the logic in this method is similar to Canvas.drawText.
496 // Any change to this method should be reflected in Canvas.drawText
497
498 // get the delegate
499 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
500 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700501 return 0;
502 }
503
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700504 return delegate.measureText(text, index, count);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700505 }
506
507 /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
508 return native_measureText(thisPaint, text.toCharArray(), start, end - start);
509 }
510
511 /*package*/ static float native_measureText(Paint thisPaint, String text) {
512 return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
513 }
514
515 /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
516 float maxWidth, float[] measuredWidth) {
517 // FIXME
518 throw new UnsupportedOperationException();
519 }
520
521 /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
522 float maxWidth, float[] measuredWidth) {
523 // FIXME
524 throw new UnsupportedOperationException();
525 }
526
527
528 /*package*/ static int native_init() {
529 Paint_Delegate newDelegate = new Paint_Delegate();
530 return sManager.addDelegate(newDelegate);
531 }
532
533 /*package*/ static int native_initWithPaint(int paint) {
534 // get the delegate from the native int.
535 Paint_Delegate delegate = sManager.getDelegate(paint);
536 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700537 return 0;
538 }
539
540 Paint_Delegate newDelegate = new Paint_Delegate(delegate);
541 return sManager.addDelegate(newDelegate);
542 }
543
544 /*package*/ static void native_reset(int native_object) {
545 // get the delegate from the native int.
546 Paint_Delegate delegate = sManager.getDelegate(native_object);
547 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700548 return;
549 }
550
551 delegate.reset();
552 }
553
554 /*package*/ static void native_set(int native_dst, int native_src) {
555 // get the delegate from the native int.
556 Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
557 if (delegate_dst == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700558 return;
559 }
560
561 // get the delegate from the native int.
562 Paint_Delegate delegate_src = sManager.getDelegate(native_src);
563 if (delegate_src == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700564 return;
565 }
566
567 delegate_dst.set(delegate_src);
568 }
569
570 /*package*/ static int native_getStyle(int native_object) {
571 // get the delegate from the native int.
572 Paint_Delegate delegate = sManager.getDelegate(native_object);
573 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700574 return 0;
575 }
576
577 return delegate.mStyle;
578 }
579
580 /*package*/ static void native_setStyle(int native_object, int style) {
581 // get the delegate from the native int.
582 Paint_Delegate delegate = sManager.getDelegate(native_object);
583 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700584 return;
585 }
586
587 delegate.mStyle = style;
588 }
589
590 /*package*/ static int native_getStrokeCap(int native_object) {
591 // get the delegate from the native int.
592 Paint_Delegate delegate = sManager.getDelegate(native_object);
593 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700594 return 0;
595 }
596
597 return delegate.mCap;
598 }
599
600 /*package*/ static void native_setStrokeCap(int native_object, int cap) {
601 // get the delegate from the native int.
602 Paint_Delegate delegate = sManager.getDelegate(native_object);
603 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700604 return;
605 }
606
607 delegate.mCap = cap;
608 }
609
610 /*package*/ static int native_getStrokeJoin(int native_object) {
611 // get the delegate from the native int.
612 Paint_Delegate delegate = sManager.getDelegate(native_object);
613 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700614 return 0;
615 }
616
617 return delegate.mJoin;
618 }
619
620 /*package*/ static void native_setStrokeJoin(int native_object, int join) {
621 // get the delegate from the native int.
622 Paint_Delegate delegate = sManager.getDelegate(native_object);
623 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700624 return;
625 }
626
627 delegate.mJoin = join;
628 }
629
630 /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
631 // FIXME
632 throw new UnsupportedOperationException();
633 }
634
635 /*package*/ static int native_setShader(int native_object, int shader) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700636 // get the delegate from the native int.
637 Paint_Delegate delegate = sManager.getDelegate(native_object);
638 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700639 return shader;
640 }
641
642 return delegate.mShader = shader;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700643 }
644
645 /*package*/ static int native_setColorFilter(int native_object, int filter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700646 // get the delegate from the native int.
647 Paint_Delegate delegate = sManager.getDelegate(native_object);
648 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700649 return filter;
650 }
651
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800652 delegate.mColorFilter = filter;
653
654 // since none of those are supported, display a fidelity warning right away
655 ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
656 if (filterDelegate != null && filterDelegate.isSupported() == false) {
657 Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
658 }
659
660 return filter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700661 }
662
663 /*package*/ static int native_setXfermode(int native_object, int xfermode) {
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) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700667 return xfermode;
668 }
669
670 return delegate.mXfermode = xfermode;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700671 }
672
673 /*package*/ static int native_setPathEffect(int native_object, int effect) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700674 // get the delegate from the native int.
675 Paint_Delegate delegate = sManager.getDelegate(native_object);
676 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700677 return effect;
678 }
679
680 return delegate.mPathEffect = effect;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700681 }
682
683 /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700684 // get the delegate from the native int.
685 Paint_Delegate delegate = sManager.getDelegate(native_object);
686 if (delegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700687 return maskfilter;
688 }
689
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800690 delegate.mMaskFilter = maskfilter;
691
692 // since none of those are supported, display a fidelity warning right away
693 MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
694 if (filterDelegate != null && filterDelegate.isSupported() == false) {
695 Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
696 }
697
698 return maskfilter;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700699 }
700
701 /*package*/ static int native_setTypeface(int native_object, int typeface) {
702 // get the delegate from the native int.
703 Paint_Delegate delegate = sManager.getDelegate(native_object);
704 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700705 return 0;
706 }
707
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800708 delegate.mTypeface = typeface;
709 delegate.updateFontObject();
710 return delegate.mTypeface;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700711 }
712
713 /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800714 // get the delegate from the native int.
715 Paint_Delegate delegate = sManager.getDelegate(native_object);
716 if (delegate == null) {
717 return rasterizer;
718 }
719
720 delegate.mRasterizer = rasterizer;
721
722 // since none of those are supported, display a fidelity warning right away
723 Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
724 if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
725 Bridge.getLog().fidelityWarning(null, rasterizerDelegate.getSupportMessage(), null);
726 }
727
728 return rasterizer;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700729 }
730
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700731 /*package*/ static int native_getTextAlign(int native_object) {
732 // get the delegate from the native int.
733 Paint_Delegate delegate = sManager.getDelegate(native_object);
734 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700735 return 0;
736 }
737
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700738 return delegate.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700739 }
740
741 /*package*/ static void native_setTextAlign(int native_object, int align) {
742 // get the delegate from the native int.
743 Paint_Delegate delegate = sManager.getDelegate(native_object);
744 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700745 return;
746 }
747
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700748 delegate.mTextAlign = align;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700749 }
750
751 /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800752 // get the delegate from the native int.
753 Paint_Delegate delegate = sManager.getDelegate(native_paint);
754 if (delegate == null) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800755 return 0.f;
756 }
757
758 return delegate.getFontMetrics(metrics);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700759 }
760
761 /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
762 int count, float[] widths) {
763 // FIXME
764 throw new UnsupportedOperationException();
765 }
766
767 /*package*/ static int native_getTextWidths(int native_object, String text, int start,
768 int end, float[] widths) {
769 // FIXME
770 throw new UnsupportedOperationException();
771 }
772
773 /*package*/ static float native_getTextRunAdvances(int native_object,
774 char[] text, int index, int count, int contextIndex, int contextCount,
775 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700776 // get the delegate from the native int.
777 Paint_Delegate delegate = sManager.getDelegate(native_object);
778 if (delegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700779 return 0.f;
780 }
781
782 if (delegate.mFonts.size() > 0) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700783 // FIXME: handle multi-char characters (see measureText)
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700784 float totalAdvance = 0;
785 for (int i = 0; i < count; i++) {
786 char c = text[i + index];
787 boolean found = false;
788 for (FontInfo info : delegate.mFonts) {
789 if (info.mFont.canDisplay(c)) {
790 float adv = info.mMetrics.charWidth(c);
791 totalAdvance += adv;
792 if (advances != null) {
793 advances[i] = adv;
794 }
795
796 found = true;
797 break;
798 }
799 }
800
801 if (found == false) {
802 // no advance for this char.
803 if (advances != null) {
804 advances[i] = 0.f;
805 }
806 }
807 }
808
809 return totalAdvance;
810 }
811
812 return 0;
813
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700814 }
815
816 /*package*/ static float native_getTextRunAdvances(int native_object,
817 String text, int start, int end, int contextStart, int contextEnd,
818 int flags, float[] advances, int advancesIndex) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700819 // FIXME: support contextStart, contextEnd and direction flag
820 int count = end - start;
821 char[] buffer = TemporaryBuffer.obtain(count);
822 TextUtils.getChars(text, start, end, buffer, 0);
823
824 return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
825 contextEnd - contextStart, flags, advances, advancesIndex);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700826 }
827
828 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
829 int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
830 // FIXME
831 throw new UnsupportedOperationException();
832 }
833
834 /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
835 int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
836 // FIXME
837 throw new UnsupportedOperationException();
838 }
839
840 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
841 char[] text, int index, int count, float x, float y, int path) {
842 // FIXME
843 throw new UnsupportedOperationException();
844 }
845
846 /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
847 String text, int start, int end, float x, float y, int path) {
848 // FIXME
849 throw new UnsupportedOperationException();
850 }
851
852 /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
853 int end, Rect bounds) {
854 // FIXME
855 throw new UnsupportedOperationException();
856 }
857
858 /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
859 int count, Rect bounds) {
860 // FIXME
861 throw new UnsupportedOperationException();
862 }
863
864 /*package*/ static void finalizer(int nativePaint) {
865 sManager.removeDelegate(nativePaint);
866 }
867
868 // ---- Private delegate/helper methods ----
869
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800870 /*package*/ Paint_Delegate() {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700871 reset();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700872 }
873
874 private Paint_Delegate(Paint_Delegate paint) {
875 set(paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700876 }
877
878 private void set(Paint_Delegate paint) {
879 mFlags = paint.mFlags;
880 mColor = paint.mColor;
881 mStyle = paint.mStyle;
882 mCap = paint.mCap;
883 mJoin = paint.mJoin;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700884 mTextAlign = paint.mTextAlign;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700885 mTypeface = paint.mTypeface;
886 mStrokeWidth = paint.mStrokeWidth;
887 mStrokeMiter = paint.mStrokeMiter;
888 mTextSize = paint.mTextSize;
889 mTextScaleX = paint.mTextScaleX;
890 mTextSkewX = paint.mTextSkewX;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700891 mXfermode = paint.mXfermode;
892 mColorFilter = paint.mColorFilter;
893 mShader = paint.mShader;
894 mPathEffect = paint.mPathEffect;
895 mMaskFilter = paint.mMaskFilter;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800896 mRasterizer = paint.mRasterizer;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800897 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700898 }
899
900 private void reset() {
901 mFlags = Paint.DEFAULT_PAINT_FLAGS;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800902 mColor = 0xFF000000;
Xavier Ducrohet66225222010-12-21 01:33:04 -0800903 mStyle = Paint.Style.FILL.nativeInt;
904 mCap = Paint.Cap.BUTT.nativeInt;
905 mJoin = Paint.Join.MITER.nativeInt;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700906 mTextAlign = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800907 mTypeface = Typeface.sDefaults[0].native_instance;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700908 mStrokeWidth = 1.f;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800909 mStrokeMiter = 4.f;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700910 mTextSize = 20.f;
911 mTextScaleX = 1.f;
912 mTextSkewX = 0.f;
Xavier Ducroheta313b652010-11-01 18:45:20 -0700913 mXfermode = 0;
914 mColorFilter = 0;
915 mShader = 0;
916 mPathEffect = 0;
917 mMaskFilter = 0;
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800918 mRasterizer = 0;
Xavier Ducrohet42e2b282010-12-06 11:08:37 -0800919 updateFontObject();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700920 }
921
922 /**
923 * Update the {@link Font} object from the typeface, text size and scaling
924 */
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800925 @SuppressWarnings("deprecation")
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700926 private void updateFontObject() {
927 if (mTypeface != 0) {
928 // Get the fonts from the TypeFace object.
929 List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
930
931 // create new font objects as well as FontMetrics, based on the current text size
932 // and skew info.
933 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
934 for (Font font : fonts) {
935 FontInfo info = new FontInfo();
936 info.mFont = font.deriveFont(mTextSize);
937 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
938 // TODO: support skew
939 info.mFont = info.mFont.deriveFont(new AffineTransform(
940 mTextScaleX, mTextSkewX, 0, 0, 1, 0));
941 }
942 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
943
944 infoList.add(info);
945 }
946
947 mFonts = Collections.unmodifiableList(infoList);
948 }
949 }
950
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700951 /*package*/ float measureText(char[] text, int index, int count) {
952 if (mFonts.size() > 0) {
953 FontInfo mainFont = mFonts.get(0);
954 int i = index;
955 int lastIndex = index + count;
956 float total = 0f;
957 while (i < lastIndex) {
958 // always start with the main font.
959 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
960 if (upTo == -1) {
961 // shortcut to exit
962 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
963 } else if (upTo > 0) {
964 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
965 i = upTo;
966 // don't call continue at this point. Since it is certain the main font
967 // cannot display the font a index upTo (now ==i), we move on to the
968 // fallback fonts directly.
969 }
970
971 // no char supported, attempt to read the next char(s) with the
972 // fallback font. In this case we only test the first character
973 // and then go back to test with the main font.
974 // Special test for 2-char characters.
975 boolean foundFont = false;
976 for (int f = 1 ; f < mFonts.size() ; f++) {
977 FontInfo fontInfo = mFonts.get(f);
978
979 // need to check that the font can display the character. We test
980 // differently if the char is a high surrogate.
981 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
982 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
983 if (upTo == -1) {
984 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
985 i += charCount;
986 foundFont = true;
987 break;
988
989 }
990 }
991
992 // in case no font can display the char, measure it with the main font.
993 if (foundFont == false) {
994 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
995 total += mainFont.mMetrics.charsWidth(text, i, size);
996 i += size;
997 }
998 }
999 }
1000
1001 return 0;
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001002 }
1003
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -08001004 private float getFontMetrics(FontMetrics metrics) {
1005 if (mFonts.size() > 0) {
1006 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
1007 if (metrics != null) {
1008 // Android expects negative ascent so we invert the value from Java.
1009 metrics.top = - javaMetrics.getMaxAscent();
1010 metrics.ascent = - javaMetrics.getAscent();
1011 metrics.descent = javaMetrics.getDescent();
1012 metrics.bottom = javaMetrics.getMaxDescent();
1013 metrics.leading = javaMetrics.getLeading();
1014 }
1015
1016 return javaMetrics.getHeight();
1017 }
1018
1019 return 0;
1020 }
1021
1022
1023
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001024 private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
1025 // get the delegate from the native int.
1026 Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
1027 if (delegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001028 return;
1029 }
1030
1031 if (flagValue) {
1032 delegate.mFlags |= flagMask;
1033 } else {
1034 delegate.mFlags &= ~flagMask;
1035 }
1036 }
1037}