blob: 1cc8ea54a8f81a5e93496fc5011452dce6b183c8 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001/*
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
19import com.android.ide.common.rendering.api.LayoutLog;
20import com.android.layoutlib.bridge.Bridge;
21import com.android.layoutlib.bridge.impl.DelegateManager;
22import com.android.layoutlib.bridge.impl.GcSnapshot;
23import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
24
25import android.graphics.Bitmap.Config;
Adam Lesinski282e1812014-01-23 18:17:42 -080026import android.text.TextUtils;
27
28import java.awt.Color;
29import java.awt.Composite;
30import java.awt.Graphics2D;
31import java.awt.Rectangle;
32import java.awt.RenderingHints;
33import java.awt.Shape;
34import java.awt.geom.AffineTransform;
35import java.awt.geom.Arc2D;
36import java.awt.image.BufferedImage;
Adam Lesinski282e1812014-01-23 18:17:42 -080037
38
39/**
40 * Delegate implementing the native methods of android.graphics.Canvas
41 *
42 * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
43 * by calls to methods of the same name in this delegate class.
44 *
45 * This class behaves like the original native implementation, but in Java, keeping previously
46 * native data into its own objects and mapping them to int that are sent back and forth between
47 * it and the original Canvas class.
48 *
49 * @see DelegateManager
50 *
51 */
52public final class Canvas_Delegate {
53
54 // ---- delegate manager ----
55 private static final DelegateManager<Canvas_Delegate> sManager =
56 new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
57
58 // ---- delegate helper data ----
59
60 private final static boolean[] sBoolOut = new boolean[1];
61
62 // ---- delegate data ----
63 private Bitmap_Delegate mBitmap;
64 private GcSnapshot mSnapshot;
65
66 private DrawFilter_Delegate mDrawFilter = null;
67
68 // ---- Public Helper methods ----
69
70 /**
71 * Returns the native delegate associated to a given {@link Canvas} object.
72 */
73 public static Canvas_Delegate getDelegate(Canvas canvas) {
74 return sManager.getDelegate(canvas.mNativeCanvas);
75 }
76
77 /**
78 * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
79 */
Narayan Kamath88a83642014-01-27 14:24:16 +000080 public static Canvas_Delegate getDelegate(long native_canvas) {
Adam Lesinski282e1812014-01-23 18:17:42 -080081 return sManager.getDelegate(native_canvas);
82 }
83
84 /**
85 * Returns the current {@link Graphics2D} used to draw.
86 */
87 public GcSnapshot getSnapshot() {
88 return mSnapshot;
89 }
90
91 /**
92 * Returns the {@link DrawFilter} delegate or null if none have been set.
93 *
94 * @return the delegate or null.
95 */
96 public DrawFilter_Delegate getDrawFilter() {
97 return mDrawFilter;
98 }
99
100 // ---- native methods ----
101
102 @LayoutlibDelegate
103 /*package*/ static boolean isOpaque(Canvas thisCanvas) {
104 // get the delegate from the native int.
105 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
106 if (canvasDelegate == null) {
107 return false;
108 }
109
110 return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
111 }
112
113 @LayoutlibDelegate
114 /*package*/ static int getWidth(Canvas thisCanvas) {
115 // get the delegate from the native int.
116 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
117 if (canvasDelegate == null) {
118 return 0;
119 }
120
121 return canvasDelegate.mBitmap.getImage().getWidth();
122 }
123
124 @LayoutlibDelegate
125 /*package*/ static int getHeight(Canvas thisCanvas) {
126 // get the delegate from the native int.
127 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
128 if (canvasDelegate == null) {
129 return 0;
130 }
131
132 return canvasDelegate.mBitmap.getImage().getHeight();
133 }
134
135 @LayoutlibDelegate
136 /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
137 // get the delegate from the native int.
138 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
139 if (canvasDelegate == null) {
140 return;
141 }
142
143 canvasDelegate.getSnapshot().translate(dx, dy);
144 }
145
146 @LayoutlibDelegate
147 /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
148 // get the delegate from the native int.
149 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
150 if (canvasDelegate == null) {
151 return;
152 }
153
154 canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
155 }
156
157 @LayoutlibDelegate
158 /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
159 // get the delegate from the native int.
160 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
161 if (canvasDelegate == null) {
162 return;
163 }
164
165 canvasDelegate.getSnapshot().scale(sx, sy);
166 }
167
168 @LayoutlibDelegate
169 /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
170 // get the delegate from the native int.
171 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
172 if (canvasDelegate == null) {
173 return;
174 }
175
176 // get the current top graphics2D object.
177 GcSnapshot g = canvasDelegate.getSnapshot();
178
179 // get its current matrix
180 AffineTransform currentTx = g.getTransform();
181 // get the AffineTransform for the given skew.
182 float[] mtx = Matrix_Delegate.getSkew(kx, ky);
183 AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
184
185 // combine them so that the given matrix is applied after.
186 currentTx.preConcatenate(matrixTx);
187
188 // give it to the graphics2D as a new matrix replacing all previous transform
189 g.setTransform(currentTx);
190 }
191
192 @LayoutlibDelegate
193 /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
194 return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
195 }
196
197 @LayoutlibDelegate
198 /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
199 return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
200 (float) rect.right, (float) rect.bottom);
201 }
202
203 @LayoutlibDelegate
204 /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
205 float bottom) {
206 // get the delegate from the native int.
207 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
208 if (canvasDelegate == null) {
209 return false;
210 }
211
212 return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
213 }
214
215 @LayoutlibDelegate
216 /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
217 int bottom) {
218
219 return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
220 }
221
222 @LayoutlibDelegate
223 /*package*/ static int save(Canvas thisCanvas) {
224 return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
225 }
226
227 @LayoutlibDelegate
228 /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
229 // get the delegate from the native int.
230 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
231 if (canvasDelegate == null) {
232 return 0;
233 }
234
235 return canvasDelegate.save(saveFlags);
236 }
237
238 @LayoutlibDelegate
239 /*package*/ static void restore(Canvas thisCanvas) {
240 // get the delegate from the native int.
241 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
242 if (canvasDelegate == null) {
243 return;
244 }
245
246 canvasDelegate.restore();
247 }
248
249 @LayoutlibDelegate
250 /*package*/ static int getSaveCount(Canvas thisCanvas) {
251 // get the delegate from the native int.
252 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
253 if (canvasDelegate == null) {
254 return 0;
255 }
256
257 return canvasDelegate.getSnapshot().size();
258 }
259
260 @LayoutlibDelegate
261 /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
262 // get the delegate from the native int.
263 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
264 if (canvasDelegate == null) {
265 return;
266 }
267
268 canvasDelegate.restoreTo(saveCount);
269 }
270
271 @LayoutlibDelegate
272 /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
273 Paint paint) {
274 // FIXME
275 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
276 "Canvas.drawPoint is not supported.", null, null /*data*/);
277 }
278
279 @LayoutlibDelegate
280 /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
281 // FIXME
282 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
283 "Canvas.drawPoint is not supported.", null, null /*data*/);
284 }
285
286 @LayoutlibDelegate
287 /*package*/ static void drawLines(Canvas thisCanvas,
288 final float[] pts, final int offset, final int count,
289 Paint paint) {
290 draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
291 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
292 @Override
293 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
294 for (int i = 0 ; i < count ; i += 4) {
295 graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
296 (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
297 }
298 }
299 });
300 }
301
302 @LayoutlibDelegate
303 /*package*/ static void freeCaches() {
304 // nothing to be done here.
305 }
306
307 @LayoutlibDelegate
308 /*package*/ static void freeTextLayoutCaches() {
309 // nothing to be done here yet.
310 }
311
312 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000313 /*package*/ static long initRaster(long nativeBitmapOrZero) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800314 if (nativeBitmapOrZero > 0) {
315 // get the Bitmap from the int
316 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
317
318 // create a new Canvas_Delegate with the given bitmap and return its new native int.
319 Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
320
321 return sManager.addNewDelegate(newDelegate);
322 }
323
324 // create a new Canvas_Delegate and return its new native int.
325 Canvas_Delegate newDelegate = new Canvas_Delegate();
326
327 return sManager.addNewDelegate(newDelegate);
328 }
329
330 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000331 /*package*/ static void copyNativeCanvasState(long srcCanvas, long dstCanvas) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800332 // get the delegate from the native int.
333 Canvas_Delegate srcCanvasDelegate = sManager.getDelegate(srcCanvas);
334 if (srcCanvasDelegate == null) {
335 return;
336 }
337
338 // get the delegate from the native int.
339 Canvas_Delegate dstCanvasDelegate = sManager.getDelegate(dstCanvas);
340 if (dstCanvasDelegate == null) {
341 return;
342 }
343 // TODO: actually copy the canvas state.
344 }
345
346 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000347 /*package*/ static long native_saveLayer(long nativeCanvas, RectF bounds,
348 long paint, int layerFlags) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800349 // get the delegate from the native int.
350 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
351 if (canvasDelegate == null) {
352 return 0;
353 }
354
355 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
356 if (paintDelegate == null) {
357 return 0;
358 }
359
360 return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
361 }
362
363 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000364 /*package*/ static long native_saveLayer(long nativeCanvas, float l,
Adam Lesinski282e1812014-01-23 18:17:42 -0800365 float t, float r, float b,
Narayan Kamath88a83642014-01-27 14:24:16 +0000366 long paint, int layerFlags) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800367 // get the delegate from the native int.
368 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
369 if (canvasDelegate == null) {
370 return 0;
371 }
372
373 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
374 if (paintDelegate == null) {
375 return 0;
376 }
377
378 return canvasDelegate.saveLayer(new RectF(l, t, r, b),
379 paintDelegate, layerFlags);
380 }
381
382 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000383 /*package*/ static long native_saveLayerAlpha(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800384 RectF bounds, int alpha,
385 int layerFlags) {
386 // get the delegate from the native int.
387 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
388 if (canvasDelegate == null) {
389 return 0;
390 }
391
392 return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
393 }
394
395 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000396 /*package*/ static long native_saveLayerAlpha(long nativeCanvas, float l,
Adam Lesinski282e1812014-01-23 18:17:42 -0800397 float t, float r, float b,
398 int alpha, int layerFlags) {
399 // get the delegate from the native int.
400 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
401 if (canvasDelegate == null) {
402 return 0;
403 }
404
405 return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
406 }
407
408
409 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000410 /*package*/ static void native_concat(long nCanvas, long nMatrix) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800411 // get the delegate from the native int.
412 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
413 if (canvasDelegate == null) {
414 return;
415 }
416
417 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
418 if (matrixDelegate == null) {
419 return;
420 }
421
422 // get the current top graphics2D object.
423 GcSnapshot snapshot = canvasDelegate.getSnapshot();
424
425 // get its current matrix
426 AffineTransform currentTx = snapshot.getTransform();
427 // get the AffineTransform of the given matrix
428 AffineTransform matrixTx = matrixDelegate.getAffineTransform();
429
430 // combine them so that the given matrix is applied after.
431 currentTx.concatenate(matrixTx);
432
433 // give it to the graphics2D as a new matrix replacing all previous transform
434 snapshot.setTransform(currentTx);
435 }
436
437 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000438 /*package*/ static void native_setMatrix(long nCanvas, long nMatrix) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800439 // get the delegate from the native int.
440 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
441 if (canvasDelegate == null) {
442 return;
443 }
444
445 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
446 if (matrixDelegate == null) {
447 return;
448 }
449
450 // get the current top graphics2D object.
451 GcSnapshot snapshot = canvasDelegate.getSnapshot();
452
453 // get the AffineTransform of the given matrix
454 AffineTransform matrixTx = matrixDelegate.getAffineTransform();
455
456 // give it to the graphics2D as a new matrix replacing all previous transform
457 snapshot.setTransform(matrixTx);
458
459 if (matrixDelegate.hasPerspective()) {
460 assert false;
461 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
462 "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
463 "supports affine transformations.", null, null /*data*/);
464 }
465 }
466
467 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000468 /*package*/ static boolean native_clipRect(long nCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800469 float left, float top,
470 float right, float bottom,
471 int regionOp) {
472
473 // get the delegate from the native int.
474 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
475 if (canvasDelegate == null) {
476 return false;
477 }
478
479 return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
480 }
481
482 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000483 /*package*/ static boolean native_clipPath(long nativeCanvas,
484 long nativePath,
Adam Lesinski282e1812014-01-23 18:17:42 -0800485 int regionOp) {
486 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
487 if (canvasDelegate == null) {
488 return true;
489 }
490
491 Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
492 if (pathDelegate == null) {
493 return true;
494 }
495
496 return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
497 }
498
499 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000500 /*package*/ static boolean native_clipRegion(long nativeCanvas,
501 long nativeRegion,
Adam Lesinski282e1812014-01-23 18:17:42 -0800502 int regionOp) {
503 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
504 if (canvasDelegate == null) {
505 return true;
506 }
507
508 Region_Delegate region = Region_Delegate.getDelegate(nativeRegion);
509 if (region == null) {
510 return true;
511 }
512
513 return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
514 }
515
516 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000517 /*package*/ static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800518 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
519 if (canvasDelegate == null) {
520 return;
521 }
522
523 canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
524
525 if (canvasDelegate.mDrawFilter != null &&
526 canvasDelegate.mDrawFilter.isSupported() == false) {
527 Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
528 canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
529 }
530 }
531
532 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000533 /*package*/ static boolean native_getClipBounds(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800534 Rect bounds) {
535 // get the delegate from the native int.
536 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
537 if (canvasDelegate == null) {
538 return false;
539 }
540
541 Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
542 if (rect != null && rect.isEmpty() == false) {
543 bounds.left = rect.x;
544 bounds.top = rect.y;
545 bounds.right = rect.x + rect.width;
546 bounds.bottom = rect.y + rect.height;
547 return true;
548 }
549
550 return false;
551 }
552
553 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000554 /*package*/ static void native_getCTM(long canvas, long matrix) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800555 // get the delegate from the native int.
556 Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
557 if (canvasDelegate == null) {
558 return;
559 }
560
561 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
562 if (matrixDelegate == null) {
563 return;
564 }
565
566 AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
567 matrixDelegate.set(Matrix_Delegate.makeValues(transform));
568 }
569
570 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000571 /*package*/ static boolean native_quickReject(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800572 RectF rect) {
573 // FIXME properly implement quickReject
574 return false;
575 }
576
577 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000578 /*package*/ static boolean native_quickReject(long nativeCanvas,
579 long path) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800580 // FIXME properly implement quickReject
581 return false;
582 }
583
584 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000585 /*package*/ static boolean native_quickReject(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800586 float left, float top,
587 float right, float bottom) {
588 // FIXME properly implement quickReject
589 return false;
590 }
591
592 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000593 /*package*/ static void native_drawRGB(long nativeCanvas, int r, int g, int b) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800594 native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF),
595 PorterDuff.Mode.SRC_OVER.nativeInt);
596
597 }
598
599 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000600 /*package*/ static void native_drawARGB(long nativeCanvas, int a, int r, int g, int b) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800601 native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF),
602 PorterDuff.Mode.SRC_OVER.nativeInt);
603 }
604
605 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000606 /*package*/ static void native_drawColor(long nativeCanvas, int color) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800607 native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
608 }
609
610 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000611 /*package*/ static void native_drawColor(long nativeCanvas, final int color, final int mode) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800612 // get the delegate from the native int.
613 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
614 if (canvasDelegate == null) {
615 return;
616 }
617
618 final int w = canvasDelegate.mBitmap.getImage().getWidth();
619 final int h = canvasDelegate.mBitmap.getImage().getHeight();
620 draw(nativeCanvas, new GcSnapshot.Drawable() {
621
622 @Override
623 public void draw(Graphics2D graphics, Paint_Delegate paint) {
624 // reset its transform just in case
625 graphics.setTransform(new AffineTransform());
626
627 // set the color
628 graphics.setColor(new Color(color, true /*alpha*/));
629
630 Composite composite = PorterDuffXfermode_Delegate.getComposite(
631 PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF);
632 if (composite != null) {
633 graphics.setComposite(composite);
634 }
635
636 graphics.fillRect(0, 0, w, h);
637 }
638 });
639 }
640
641 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000642 /*package*/ static void native_drawPaint(long nativeCanvas, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800643 // FIXME
644 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
645 "Canvas.drawPaint is not supported.", null, null /*data*/);
646 }
647
648 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000649 /*package*/ static void native_drawLine(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800650 final float startX, final float startY, final float stopX, final float stopY,
Narayan Kamath88a83642014-01-27 14:24:16 +0000651 long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800652
653 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
654 new GcSnapshot.Drawable() {
655 @Override
656 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
657 graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
658 }
659 });
660 }
661
662 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000663 /*package*/ static void native_drawRect(long nativeCanvas, RectF rect, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800664 native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
665 }
666
667 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000668 /*package*/ static void native_drawRect(long nativeCanvas,
669 final float left, final float top, final float right, final float bottom, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800670
671 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
672 new GcSnapshot.Drawable() {
673 @Override
674 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
675 int style = paintDelegate.getStyle();
676
677 // draw
678 if (style == Paint.Style.FILL.nativeInt ||
679 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
680 graphics.fillRect((int)left, (int)top,
681 (int)(right-left), (int)(bottom-top));
682 }
683
684 if (style == Paint.Style.STROKE.nativeInt ||
685 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
686 graphics.drawRect((int)left, (int)top,
687 (int)(right-left), (int)(bottom-top));
688 }
689 }
690 });
691 }
692
693 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000694 /*package*/ static void native_drawOval(long nativeCanvas, final RectF oval, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800695 if (oval.right > oval.left && oval.bottom > oval.top) {
696 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
697 new GcSnapshot.Drawable() {
698 @Override
699 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
700 int style = paintDelegate.getStyle();
701
702 // draw
703 if (style == Paint.Style.FILL.nativeInt ||
704 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
705 graphics.fillOval((int)oval.left, (int)oval.top,
706 (int)oval.width(), (int)oval.height());
707 }
708
709 if (style == Paint.Style.STROKE.nativeInt ||
710 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
711 graphics.drawOval((int)oval.left, (int)oval.top,
712 (int)oval.width(), (int)oval.height());
713 }
714 }
715 });
716 }
717 }
718
719 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000720 /*package*/ static void native_drawCircle(long nativeCanvas,
721 float cx, float cy, float radius, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800722 native_drawOval(nativeCanvas,
723 new RectF(cx - radius, cy - radius, cx + radius, cy + radius),
724 paint);
725 }
726
727 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000728 /*package*/ static void native_drawArc(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800729 final RectF oval, final float startAngle, final float sweep,
Narayan Kamath88a83642014-01-27 14:24:16 +0000730 final boolean useCenter, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800731 if (oval.right > oval.left && oval.bottom > oval.top) {
732 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
733 new GcSnapshot.Drawable() {
734 @Override
735 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
736 int style = paintDelegate.getStyle();
737
738 Arc2D.Float arc = new Arc2D.Float(
739 oval.left, oval.top, oval.width(), oval.height(),
740 -startAngle, -sweep,
741 useCenter ? Arc2D.PIE : Arc2D.OPEN);
742
743 // draw
744 if (style == Paint.Style.FILL.nativeInt ||
745 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
746 graphics.fill(arc);
747 }
748
749 if (style == Paint.Style.STROKE.nativeInt ||
750 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
751 graphics.draw(arc);
752 }
753 }
754 });
755 }
756 }
757
758 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000759 /*package*/ static void native_drawRoundRect(long nativeCanvas,
760 final RectF rect, final float rx, final float ry, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800761
762 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
763 new GcSnapshot.Drawable() {
764 @Override
765 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
766 int style = paintDelegate.getStyle();
767
768 // draw
769 if (style == Paint.Style.FILL.nativeInt ||
770 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
771 graphics.fillRoundRect(
772 (int)rect.left, (int)rect.top,
773 (int)rect.width(), (int)rect.height(),
774 (int)rx, (int)ry);
775 }
776
777 if (style == Paint.Style.STROKE.nativeInt ||
778 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
779 graphics.drawRoundRect(
780 (int)rect.left, (int)rect.top,
781 (int)rect.width(), (int)rect.height(),
782 (int)rx, (int)ry);
783 }
784 }
785 });
786 }
787
788 @LayoutlibDelegate
Deepanshu Guptae05bb952014-01-28 18:55:33 -0800789 /*package*/ static void native_drawPath(long nativeCanvas, long path, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800790 final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
791 if (pathDelegate == null) {
792 return;
793 }
794
795 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
796 new GcSnapshot.Drawable() {
797 @Override
798 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
799 Shape shape = pathDelegate.getJavaShape();
800 int style = paintDelegate.getStyle();
801
802 if (style == Paint.Style.FILL.nativeInt ||
803 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
804 graphics.fill(shape);
805 }
806
807 if (style == Paint.Style.STROKE.nativeInt ||
808 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
809 graphics.draw(shape);
810 }
811 }
812 });
813 }
814
815 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000816 /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap,
Adam Lesinski282e1812014-01-23 18:17:42 -0800817 float left, float top,
Narayan Kamath88a83642014-01-27 14:24:16 +0000818 long nativePaintOrZero,
Adam Lesinski282e1812014-01-23 18:17:42 -0800819 int canvasDensity,
820 int screenDensity,
821 int bitmapDensity) {
822 // get the delegate from the native int.
823 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
824 if (bitmapDelegate == null) {
825 return;
826 }
827
828 BufferedImage image = bitmapDelegate.getImage();
829 float right = left + image.getWidth();
830 float bottom = top + image.getHeight();
831
832 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
833 0, 0, image.getWidth(), image.getHeight(),
834 (int)left, (int)top, (int)right, (int)bottom);
835 }
836
837 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000838 /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap,
Adam Lesinski282e1812014-01-23 18:17:42 -0800839 Rect src, RectF dst,
Narayan Kamath88a83642014-01-27 14:24:16 +0000840 long nativePaintOrZero,
Adam Lesinski282e1812014-01-23 18:17:42 -0800841 int screenDensity,
842 int bitmapDensity) {
843 // get the delegate from the native int.
844 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
845 if (bitmapDelegate == null) {
846 return;
847 }
848
849 BufferedImage image = bitmapDelegate.getImage();
850
851 if (src == null) {
852 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
853 0, 0, image.getWidth(), image.getHeight(),
854 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
855 } else {
856 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
857 src.left, src.top, src.width(), src.height(),
858 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
859 }
860 }
861
862 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000863 /*package*/ static void native_drawBitmap(long nativeCanvas, long bitmap,
Adam Lesinski282e1812014-01-23 18:17:42 -0800864 Rect src, Rect dst,
Narayan Kamath88a83642014-01-27 14:24:16 +0000865 long nativePaintOrZero,
Adam Lesinski282e1812014-01-23 18:17:42 -0800866 int screenDensity,
867 int bitmapDensity) {
868 // get the delegate from the native int.
869 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
870 if (bitmapDelegate == null) {
871 return;
872 }
873
874 BufferedImage image = bitmapDelegate.getImage();
875
876 if (src == null) {
877 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
878 0, 0, image.getWidth(), image.getHeight(),
879 dst.left, dst.top, dst.right, dst.bottom);
880 } else {
881 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
882 src.left, src.top, src.width(), src.height(),
883 dst.left, dst.top, dst.right, dst.bottom);
884 }
885 }
886
887 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000888 /*package*/ static void native_drawBitmap(long nativeCanvas, int[] colors,
Adam Lesinski282e1812014-01-23 18:17:42 -0800889 int offset, int stride, final float x,
890 final float y, int width, int height,
891 boolean hasAlpha,
Narayan Kamath88a83642014-01-27 14:24:16 +0000892 long nativePaintOrZero) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800893
894 // create a temp BufferedImage containing the content.
895 final BufferedImage image = new BufferedImage(width, height,
896 hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
897 image.setRGB(0, 0, width, height, colors, offset, stride);
898
899 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
900 new GcSnapshot.Drawable() {
901 @Override
902 public void draw(Graphics2D graphics, Paint_Delegate paint) {
903 if (paint != null && paint.isFilterBitmap()) {
904 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
905 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
906 }
907
908 graphics.drawImage(image, (int) x, (int) y, null);
909 }
910 });
911 }
912
913 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000914 /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, long nBitmap,
915 long nMatrix, long nPaint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800916 // get the delegate from the native int.
917 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
918 if (canvasDelegate == null) {
919 return;
920 }
921
922 // get the delegate from the native int, which can be null
923 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
924
925 // get the delegate from the native int.
926 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
927 if (bitmapDelegate == null) {
928 return;
929 }
930
931 final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);
932
933 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
934 if (matrixDelegate == null) {
935 return;
936 }
937
938 final AffineTransform mtx = matrixDelegate.getAffineTransform();
939
940 canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
941 @Override
942 public void draw(Graphics2D graphics, Paint_Delegate paint) {
943 if (paint != null && paint.isFilterBitmap()) {
944 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
945 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
946 }
947
948 //FIXME add support for canvas, screen and bitmap densities.
949 graphics.drawImage(image, mtx, null);
950 }
951 }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
952 }
953
954 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000955 /*package*/ static void nativeDrawBitmapMesh(long nCanvas, long nBitmap,
Adam Lesinski282e1812014-01-23 18:17:42 -0800956 int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
Narayan Kamath88a83642014-01-27 14:24:16 +0000957 int colorOffset, long nPaint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800958 // FIXME
959 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
960 "Canvas.drawBitmapMesh is not supported.", null, null /*data*/);
961 }
962
963 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000964 /*package*/ static void nativeDrawVertices(long nCanvas, int mode, int n,
Adam Lesinski282e1812014-01-23 18:17:42 -0800965 float[] verts, int vertOffset,
966 float[] texs, int texOffset,
967 int[] colors, int colorOffset,
968 short[] indices, int indexOffset,
Narayan Kamath88a83642014-01-27 14:24:16 +0000969 int indexCount, long nPaint) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800970 // FIXME
971 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
972 "Canvas.drawVertices is not supported.", null, null /*data*/);
973 }
974
975 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +0000976 /*package*/ static void native_drawText(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -0800977 final char[] text, final int index, final int count,
Deepanshu Guptae05bb952014-01-28 18:55:33 -0800978 final float startX, final float startY, final int flags, long paint,
979 long typeface) {
Deepanshu Gupta19acfb82013-09-05 13:49:17 -0700980
Deepanshu Guptae05bb952014-01-28 18:55:33 -0800981 // TODO: use typeface.
Adam Lesinski282e1812014-01-23 18:17:42 -0800982 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
983 new GcSnapshot.Drawable() {
984 @Override
985 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
986 // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
987 // Any change to this method should be reflected in Paint.measureText
988 // Paint.TextAlign indicates how the text is positioned relative to X.
989 // LEFT is the default and there's nothing to do.
990 float x = startX;
Deepanshu Gupta19acfb82013-09-05 13:49:17 -0700991 int limit = index + count;
992 boolean isRtl = flags == Canvas.DIRECTION_RTL;
Adam Lesinski282e1812014-01-23 18:17:42 -0800993 if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
Deepanshu Gupta5ad7c182014-01-07 11:58:44 -0800994 RectF bounds = paintDelegate.measureText(text, index, count, isRtl);
995 float m = bounds.right - bounds.left;
Adam Lesinski282e1812014-01-23 18:17:42 -0800996 if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
997 x -= m / 2;
998 } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
999 x -= m;
1000 }
1001 }
1002
Deepanshu Gupta19acfb82013-09-05 13:49:17 -07001003 new BidiRenderer(graphics, paintDelegate, text).renderText(
1004 index, limit, isRtl, null, 0, true, x, startY);
Adam Lesinski282e1812014-01-23 18:17:42 -08001005 }
1006 });
1007 }
1008
1009 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001010 /*package*/ static void native_drawText(long nativeCanvas, String text,
Deepanshu Guptae05bb952014-01-28 18:55:33 -08001011 int start, int end, float x, float y, final int flags, long paint,
1012 long typeface) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001013 int count = end - start;
1014 char[] buffer = TemporaryBuffer.obtain(count);
1015 TextUtils.getChars(text, start, end, buffer, 0);
1016
Deepanshu Guptae05bb952014-01-28 18:55:33 -08001017 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
Adam Lesinski282e1812014-01-23 18:17:42 -08001018 }
1019
1020 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001021 /*package*/ static void native_drawTextRun(long nativeCanvas, String text,
Adam Lesinski282e1812014-01-23 18:17:42 -08001022 int start, int end, int contextStart, int contextEnd,
Deepanshu Guptae05bb952014-01-28 18:55:33 -08001023 float x, float y, int flags, long paint, long typeface) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001024 int count = end - start;
1025 char[] buffer = TemporaryBuffer.obtain(count);
1026 TextUtils.getChars(text, start, end, buffer, 0);
1027
Deepanshu Guptae05bb952014-01-28 18:55:33 -08001028 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
Adam Lesinski282e1812014-01-23 18:17:42 -08001029 }
1030
1031 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001032 /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
Adam Lesinski282e1812014-01-23 18:17:42 -08001033 int start, int count, int contextStart, int contextCount,
Deepanshu Guptae05bb952014-01-28 18:55:33 -08001034 float x, float y, int flags, long paint, long typeface) {
1035 native_drawText(nativeCanvas, text, start, count, x, y, flags, paint, typeface);
Adam Lesinski282e1812014-01-23 18:17:42 -08001036 }
1037
1038 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001039 /*package*/ static void native_drawPosText(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -08001040 char[] text, int index,
1041 int count, float[] pos,
Narayan Kamath88a83642014-01-27 14:24:16 +00001042 long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001043 // FIXME
1044 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1045 "Canvas.drawPosText is not supported.", null, null /*data*/);
1046 }
1047
1048 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001049 /*package*/ static void native_drawPosText(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -08001050 String text, float[] pos,
Narayan Kamath88a83642014-01-27 14:24:16 +00001051 long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001052 // FIXME
1053 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1054 "Canvas.drawPosText is not supported.", null, null /*data*/);
1055 }
1056
1057 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001058 /*package*/ static void native_drawTextOnPath(long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -08001059 char[] text, int index,
Narayan Kamath88a83642014-01-27 14:24:16 +00001060 int count, long path,
Adam Lesinski282e1812014-01-23 18:17:42 -08001061 float hOffset,
1062 float vOffset, int bidiFlags,
Narayan Kamath88a83642014-01-27 14:24:16 +00001063 long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001064 // FIXME
1065 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1066 "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
1067 }
1068
1069 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001070 /*package*/ static void native_drawTextOnPath(long nativeCanvas,
1071 String text, long path,
Adam Lesinski282e1812014-01-23 18:17:42 -08001072 float hOffset,
1073 float vOffset,
Narayan Kamath88a83642014-01-27 14:24:16 +00001074 int flags, long paint) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001075 // FIXME
1076 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1077 "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
1078 }
1079
1080 @LayoutlibDelegate
Narayan Kamath88a83642014-01-27 14:24:16 +00001081 /*package*/ static void finalizer(long nativeCanvas) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001082 // get the delegate from the native int so that it can be disposed.
1083 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
1084 if (canvasDelegate == null) {
1085 return;
1086 }
1087
1088 canvasDelegate.dispose();
1089
1090 // remove it from the manager.
1091 sManager.removeJavaReferenceFor(nativeCanvas);
1092 }
1093
1094 // ---- Private delegate/helper methods ----
1095
1096 /**
1097 * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
1098 * <p>Note that the drawable may actually be executed several times if there are
1099 * layers involved (see {@link #saveLayer(RectF, int, int)}.
1100 */
Narayan Kamath88a83642014-01-27 14:24:16 +00001101 private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode,
Adam Lesinski282e1812014-01-23 18:17:42 -08001102 GcSnapshot.Drawable drawable) {
1103 // get the delegate from the native int.
1104 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
1105 if (canvasDelegate == null) {
1106 return;
1107 }
1108
1109 // get the paint which can be null if nPaint is 0;
1110 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
1111
1112 canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
1113 }
1114
1115 /**
1116 * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
1117 * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
1118 * <p>Note that the drawable may actually be executed several times if there are
1119 * layers involved (see {@link #saveLayer(RectF, int, int)}.
1120 */
Narayan Kamath88a83642014-01-27 14:24:16 +00001121 private static void draw(long nCanvas, GcSnapshot.Drawable drawable) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001122 // get the delegate from the native int.
1123 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
1124 if (canvasDelegate == null) {
1125 return;
1126 }
1127
1128 canvasDelegate.mSnapshot.draw(drawable);
1129 }
1130
1131 private Canvas_Delegate(Bitmap_Delegate bitmap) {
1132 mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
1133 }
1134
1135 private Canvas_Delegate() {
1136 mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
1137 }
1138
1139 /**
1140 * Disposes of the {@link Graphics2D} stack.
1141 */
1142 private void dispose() {
1143 mSnapshot.dispose();
1144 }
1145
1146 private int save(int saveFlags) {
1147 // get the current save count
1148 int count = mSnapshot.size();
1149
1150 mSnapshot = mSnapshot.save(saveFlags);
1151
1152 // return the old save count
1153 return count;
1154 }
1155
1156 private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) {
1157 Paint_Delegate paint = new Paint_Delegate();
1158 paint.setAlpha(alpha);
1159 return saveLayer(rect, paint, saveFlags);
1160 }
1161
1162 private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) {
1163 // get the current save count
1164 int count = mSnapshot.size();
1165
1166 mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);
1167
1168 // return the old save count
1169 return count;
1170 }
1171
1172 /**
1173 * Restores the {@link GcSnapshot} to <var>saveCount</var>
1174 * @param saveCount the saveCount
1175 */
1176 private void restoreTo(int saveCount) {
1177 mSnapshot = mSnapshot.restoreTo(saveCount);
1178 }
1179
1180 /**
1181 * Restores the {@link GcSnapshot} to <var>saveCount</var>
1182 * @param saveCount the saveCount
1183 */
1184 private void restore() {
1185 mSnapshot = mSnapshot.restore();
1186 }
1187
1188 private boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
1189 return mSnapshot.clipRect(left, top, right, bottom, regionOp);
1190 }
1191
1192 private void setBitmap(Bitmap_Delegate bitmap) {
1193 mBitmap = bitmap;
1194 assert mSnapshot.size() == 1;
1195 mSnapshot.setBitmap(mBitmap);
1196 }
1197
1198 private static void drawBitmap(
Narayan Kamath88a83642014-01-27 14:24:16 +00001199 long nativeCanvas,
Adam Lesinski282e1812014-01-23 18:17:42 -08001200 Bitmap_Delegate bitmap,
Narayan Kamath88a83642014-01-27 14:24:16 +00001201 long nativePaintOrZero,
Adam Lesinski282e1812014-01-23 18:17:42 -08001202 final int sleft, final int stop, final int sright, final int sbottom,
1203 final int dleft, final int dtop, final int dright, final int dbottom) {
1204 // get the delegate from the native int.
1205 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
1206 if (canvasDelegate == null) {
1207 return;
1208 }
1209
1210 // get the paint, which could be null if the int is 0
1211 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
1212
1213 final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
1214
1215 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
1216 new GcSnapshot.Drawable() {
1217 @Override
1218 public void draw(Graphics2D graphics, Paint_Delegate paint) {
1219 if (paint != null && paint.isFilterBitmap()) {
1220 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
1221 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
1222 }
1223
1224 //FIXME add support for canvas, screen and bitmap densities.
1225 graphics.drawImage(image, dleft, dtop, dright, dbottom,
1226 sleft, stop, sright, sbottom, null);
1227 }
1228 });
1229 }
1230
1231
1232 /**
1233 * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate.
1234 * The image returns, through a 1-size boolean array, whether the drawing code should
1235 * use a SRC composite no matter what the paint says.
1236 *
1237 * @param bitmap the bitmap
1238 * @param paint the paint that will be used to draw
1239 * @param forceSrcMode whether the composite will have to be SRC
1240 * @return the image to draw
1241 */
1242 private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint,
1243 boolean[] forceSrcMode) {
1244 BufferedImage image = bitmap.getImage();
1245 forceSrcMode[0] = false;
1246
1247 // if the bitmap config is alpha_8, then we erase all color value from it
1248 // before drawing it.
1249 if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
1250 fixAlpha8Bitmap(image);
1251 } else if (bitmap.hasAlpha() == false) {
1252 // hasAlpha is merely a rendering hint. There can in fact be alpha values
1253 // in the bitmap but it should be ignored at drawing time.
1254 // There is two ways to do this:
1255 // - override the composite to be SRC. This can only be used if the composite
1256 // was going to be SRC or SRC_OVER in the first place
1257 // - Create a different bitmap to draw in which all the alpha channel values is set
1258 // to 0xFF.
1259 if (paint != null) {
1260 Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
1261 if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
1262 PorterDuff.Mode mode =
1263 ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
1264
1265 forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
1266 mode == PorterDuff.Mode.SRC;
1267 }
1268 }
1269
1270 // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
1271 if (forceSrcMode[0] == false) {
1272 image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
1273 }
1274 }
1275
1276 return image;
1277 }
1278
1279 private static void fixAlpha8Bitmap(final BufferedImage image) {
1280 int w = image.getWidth();
1281 int h = image.getHeight();
1282 int[] argb = new int[w * h];
1283 image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
1284
1285 final int length = argb.length;
1286 for (int i = 0 ; i < length; i++) {
1287 argb[i] &= 0xFF000000;
1288 }
1289 image.setRGB(0, 0, w, h, argb, 0, w);
1290 }
1291}
1292