blob: def0f02b58d3135a46c849daaf81d679a8f1c07b [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 Ducrohet3054fe62010-12-06 10:11:44 -080019import com.android.layoutlib.bridge.Bridge;
Xavier Ducrohet3bd98982010-11-09 18:25:03 -080020import com.android.layoutlib.bridge.impl.DelegateManager;
Xavier Ducrohetcf021232010-12-14 18:05:22 -080021import com.android.layoutlib.bridge.impl.GcSnapshot;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070022
Xavier Ducrohet37f21802010-11-01 16:17:18 -070023import android.graphics.Paint_Delegate.FontInfo;
24import android.text.TextUtils;
25
Xavier Ducrohet37f21802010-11-01 16:17:18 -070026import java.awt.Color;
Xavier Ducrohetc810bea2010-12-20 08:22:47 -080027import java.awt.Composite;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070028import java.awt.Graphics2D;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070029import java.awt.Rectangle;
30import java.awt.RenderingHints;
Xavier Ducrohetc810bea2010-12-20 08:22:47 -080031import java.awt.Shape;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070032import java.awt.geom.AffineTransform;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070033import java.awt.image.BufferedImage;
Xavier Ducrohet37f21802010-11-01 16:17:18 -070034import java.util.List;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070035
Xavier Ducrohet37f21802010-11-01 16:17:18 -070036
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070037/**
38 * Delegate implementing the native methods of android.graphics.Canvas
39 *
40 * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
41 * by calls to methods of the same name in this delegate class.
42 *
43 * This class behaves like the original native implementation, but in Java, keeping previously
44 * native data into its own objects and mapping them to int that are sent back and forth between
45 * it and the original Canvas class.
46 *
47 * @see DelegateManager
48 *
49 */
Xavier Ducrohetc810bea2010-12-20 08:22:47 -080050public final class Canvas_Delegate {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070051
52 // ---- delegate manager ----
53 private static final DelegateManager<Canvas_Delegate> sManager =
54 new DelegateManager<Canvas_Delegate>();
55
56 // ---- delegate helper data ----
57
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -080058 private final static boolean[] sBoolOut = new boolean[1];
59
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070060 // ---- delegate data ----
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -080061 private Bitmap_Delegate mBitmap;
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -080062 private GcSnapshot mSnapshot;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070063
Xavier Ducroheta6e51d52010-12-23 07:16:21 -080064 private int mDrawFilter = 0;
65
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070066 // ---- Public Helper methods ----
67
68 /**
69 * Returns the native delegate associated to a given {@link Canvas} object.
70 */
71 public static Canvas_Delegate getDelegate(Canvas canvas) {
72 return sManager.getDelegate(canvas.mNativeCanvas);
73 }
74
75 /**
76 * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
77 */
78 public static Canvas_Delegate getDelegate(int native_canvas) {
79 return sManager.getDelegate(native_canvas);
80 }
81
82 /**
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070083 * Returns the current {@link Graphics2D} used to draw.
84 */
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -080085 public GcSnapshot getSnapshot() {
Xavier Ducrohetcf021232010-12-14 18:05:22 -080086 return mSnapshot;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070087 }
88
Xavier Ducroheta6e51d52010-12-23 07:16:21 -080089 /**
90 * Returns the {@link DrawFilter} delegate or null if none have been set.
91 *
92 * @return the delegate or null.
93 */
94 public DrawFilter_Delegate getDrawFilter() {
95 return DrawFilter_Delegate.getDelegate(mDrawFilter);
96 }
97
Xavier Ducrohetef44aea2010-10-28 11:52:00 -070098 // ---- native methods ----
99
100 /*package*/ static boolean isOpaque(Canvas thisCanvas) {
101 // FIXME
102 throw new UnsupportedOperationException();
103 }
104
105 /*package*/ static int getWidth(Canvas thisCanvas) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700106 // get the delegate from the native int.
107 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
108 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700109 return 0;
110 }
111
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800112 return canvasDelegate.mBitmap.getImage().getWidth();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700113 }
114
115 /*package*/ static int getHeight(Canvas thisCanvas) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700116 // get the delegate from the native int.
117 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
118 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700119 return 0;
120 }
121
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800122 return canvasDelegate.mBitmap.getImage().getHeight();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700123 }
124
125 /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700126 // get the delegate from the native int.
127 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
128 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700129 return;
130 }
131
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800132 canvasDelegate.getSnapshot().translate(dx, dy);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700133 }
134
135 /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700136 // get the delegate from the native int.
137 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
138 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700139 return;
140 }
141
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800142 canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700143 }
144
145 /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700146 // get the delegate from the native int.
147 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
148 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700149 return;
150 }
151
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800152 canvasDelegate.getSnapshot().scale(sx, sy);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700153 }
154
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700155 /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
156 // get the delegate from the native int.
157 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
158 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700159 return;
160 }
161
162 // get the current top graphics2D object.
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800163 GcSnapshot g = canvasDelegate.getSnapshot();
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700164
165 // get its current matrix
166 AffineTransform currentTx = g.getTransform();
167 // get the AffineTransform for the given skew.
168 float[] mtx = Matrix_Delegate.getSkew(kx, ky);
169 AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
170
171 // combine them so that the given matrix is applied after.
172 currentTx.preConcatenate(matrixTx);
173
174 // give it to the graphics2D as a new matrix replacing all previous transform
175 g.setTransform(currentTx);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700176 }
177
178 /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800179 return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700180 }
181
182 /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800183 return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
184 (float) rect.right, (float) rect.bottom);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700185 }
186
187 /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
188 float bottom) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700189 // get the delegate from the native int.
190 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
191 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700192 return false;
193 }
194
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800195 return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700196 }
197
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800198 /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
199 int bottom) {
200
201 return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
202 }
203
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700204 /*package*/ static int save(Canvas thisCanvas) {
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800205 return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
206 }
207
208 /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700209 // get the delegate from the native int.
210 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
211 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700212 return 0;
213 }
214
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800215 return canvasDelegate.save(saveFlags);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700216 }
217
218 /*package*/ static void restore(Canvas thisCanvas) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700219 // get the delegate from the native int.
220 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
221 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700222 return;
223 }
224
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800225 canvasDelegate.restore();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700226 }
227
228 /*package*/ static int getSaveCount(Canvas thisCanvas) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700229 // get the delegate from the native int.
230 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
231 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700232 return 0;
233 }
234
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800235 return canvasDelegate.getSnapshot().size();
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700236 }
237
238 /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700239 // get the delegate from the native int.
240 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
241 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700242 return;
243 }
244
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800245 canvasDelegate.restoreTo(saveCount);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700246 }
247
248 /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
249 Paint paint) {
250 // FIXME
251 throw new UnsupportedOperationException();
252 }
253
254 /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
255 // FIXME
256 throw new UnsupportedOperationException();
257 }
258
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800259 /*package*/ static void drawLines(Canvas thisCanvas,
260 final float[] pts, final int offset, final int count,
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700261 Paint paint) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800262 draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800263 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800264 public void draw(Graphics2D graphics, Paint_Delegate paint) {
265 for (int i = 0 ; i < count ; i += 4) {
266 graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
267 (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
268 }
269 }
270 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700271 }
272
273 /*package*/ static void freeCaches() {
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800274 // nothing to be done here.
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700275 }
276
277 /*package*/ static int initRaster(int nativeBitmapOrZero) {
278 if (nativeBitmapOrZero > 0) {
279 // get the Bitmap from the int
280 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
281
282 // create a new Canvas_Delegate with the given bitmap and return its new native int.
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800283 Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700284
285 return sManager.addDelegate(newDelegate);
286 } else {
287 // create a new Canvas_Delegate and return its new native int.
288 Canvas_Delegate newDelegate = new Canvas_Delegate();
289
290 return sManager.addDelegate(newDelegate);
291 }
292 }
293
294 /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
295 // get the delegate from the native int.
296 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
297 if (canvasDelegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700298 return;
299 }
300
301 // get the delegate from the native int.
302 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
303 if (bitmapDelegate == null) {
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700304 return;
305 }
306
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800307 canvasDelegate.setBitmap(bitmapDelegate);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700308 }
309
310 /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
311 int paint, int layerFlags) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800312 // get the delegate from the native int.
313 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
314 if (canvasDelegate == null) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800315 return 0;
316 }
317
318 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
319 if (paintDelegate == null) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800320 return 0;
321 }
322
323 return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700324 }
325
326 /*package*/ static int native_saveLayer(int nativeCanvas, float l,
327 float t, float r, float b,
328 int paint, int layerFlags) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800329 // get the delegate from the native int.
330 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
331 if (canvasDelegate == null) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800332 return 0;
333 }
334
335 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
336 if (paintDelegate == null) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800337 return 0;
338 }
339
340 return canvasDelegate.saveLayer(new RectF(l, t, r, b),
341 paintDelegate, layerFlags);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700342 }
343
344 /*package*/ static int native_saveLayerAlpha(int nativeCanvas,
345 RectF bounds, int alpha,
346 int layerFlags) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800347 // get the delegate from the native int.
348 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
349 if (canvasDelegate == null) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800350 return 0;
351 }
352
353 return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700354 }
355
356 /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
357 float t, float r, float b,
358 int alpha, int layerFlags) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800359 // get the delegate from the native int.
360 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
361 if (canvasDelegate == null) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800362 return 0;
363 }
364
365 return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700366 }
367
368
369 /*package*/ static void native_concat(int nCanvas, int nMatrix) {
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800370 // get the delegate from the native int.
371 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
372 if (canvasDelegate == null) {
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800373 return;
374 }
375
376 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
377 if (matrixDelegate == null) {
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800378 return;
379 }
380
381 // get the current top graphics2D object.
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800382 GcSnapshot snapshot = canvasDelegate.getSnapshot();
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800383
384 // get its current matrix
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800385 AffineTransform currentTx = snapshot.getTransform();
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800386 // get the AffineTransform of the given matrix
387 AffineTransform matrixTx = matrixDelegate.getAffineTransform();
388
389 // combine them so that the given matrix is applied after.
390 currentTx.preConcatenate(matrixTx);
391
392 // give it to the graphics2D as a new matrix replacing all previous transform
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800393 snapshot.setTransform(currentTx);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700394 }
395
396 /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800397 // get the delegate from the native int.
398 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
399 if (canvasDelegate == null) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800400 return;
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800401 }
402
403 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
404 if (matrixDelegate == null) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800405 return;
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800406 }
407
408 // get the current top graphics2D object.
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800409 GcSnapshot snapshot = canvasDelegate.getSnapshot();
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800410
411 // get the AffineTransform of the given matrix
412 AffineTransform matrixTx = matrixDelegate.getAffineTransform();
413
414 // give it to the graphics2D as a new matrix replacing all previous transform
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800415 snapshot.setTransform(matrixTx);
Xavier Ducrohetddea50d2010-11-24 11:26:40 -0800416
Xavier Ducrohet3054fe62010-12-06 10:11:44 -0800417 if (matrixDelegate.hasPerspective()) {
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800418 assert false;
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800419 Bridge.getLog().fidelityWarning(null,
Xavier Ducrohet3054fe62010-12-06 10:11:44 -0800420 "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800421 "supports affine transformations in the Layout Preview.", null);
Xavier Ducrohet3054fe62010-12-06 10:11:44 -0800422 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700423 }
424
425 /*package*/ static boolean native_clipRect(int nCanvas,
426 float left, float top,
427 float right, float bottom,
428 int regionOp) {
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800429
430 // get the delegate from the native int.
431 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
432 if (canvasDelegate == null) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800433 return false;
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -0800434 }
435
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800436 return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700437 }
438
439 /*package*/ static boolean native_clipPath(int nativeCanvas,
440 int nativePath,
441 int regionOp) {
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800442 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
443 if (canvasDelegate == null) {
444 return true;
445 }
446
447 Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
448 if (pathDelegate == null) {
449 return true;
450 }
451
452 return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700453 }
454
455 /*package*/ static boolean native_clipRegion(int nativeCanvas,
456 int nativeRegion,
457 int regionOp) {
Xavier Ducrohetb9761242010-12-23 10:22:14 -0800458 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
459 if (canvasDelegate == null) {
460 return true;
461 }
462
463 Region_Delegate region = Region_Delegate.getDelegate(nativeRegion);
464 if (region == null) {
465 return true;
466 }
467
468 return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700469 }
470
471 /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
472 int nativeFilter) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800473 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
474 if (canvasDelegate == null) {
475 return;
476 }
477
478 canvasDelegate.mDrawFilter = nativeFilter;
479
480 // get the delegate only because we don't support them at all for the moment, so
481 // we can display the message now.
482
483 DrawFilter_Delegate filterDelegate = DrawFilter_Delegate.getDelegate(nativeFilter);
484 if (canvasDelegate == null) {
485 return;
486 }
487
488 if (filterDelegate.isSupported() == false) {
489 Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
490 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700491 }
492
493 /*package*/ static boolean native_getClipBounds(int nativeCanvas,
494 Rect bounds) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700495 // get the delegate from the native int.
496 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
497 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700498 return false;
499 }
500
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800501 Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700502 if (rect != null) {
503 bounds.left = rect.x;
504 bounds.top = rect.y;
505 bounds.right = rect.x + rect.width;
506 bounds.bottom = rect.y + rect.height;
507 return true;
508 }
509 return false;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700510 }
511
512 /*package*/ static void native_getCTM(int canvas, int matrix) {
513 // FIXME
514 throw new UnsupportedOperationException();
515 }
516
517 /*package*/ static boolean native_quickReject(int nativeCanvas,
518 RectF rect,
519 int native_edgeType) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700520 // FIXME properly implement quickReject
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700521 return false;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700522 }
523
524 /*package*/ static boolean native_quickReject(int nativeCanvas,
525 int path,
526 int native_edgeType) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700527 // FIXME properly implement quickReject
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700528 return false;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700529 }
530
531 /*package*/ static boolean native_quickReject(int nativeCanvas,
532 float left, float top,
533 float right, float bottom,
534 int native_edgeType) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700535 // FIXME properly implement quickReject
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700536 return false;
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700537 }
538
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700539 /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, int b) {
540 native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF),
541 PorterDuff.Mode.SRC_OVER.nativeInt);
542
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700543 }
544
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700545 /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, int g, int b) {
546 native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF),
547 PorterDuff.Mode.SRC_OVER.nativeInt);
548 }
549
550 /*package*/ static void native_drawColor(int nativeCanvas, int color) {
551 native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
552 }
553
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800554 /*package*/ static void native_drawColor(int nativeCanvas, final int color, final int mode) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700555 // get the delegate from the native int.
556 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
557 if (canvasDelegate == null) {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700558 return;
559 }
560
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800561 final int w = canvasDelegate.mBitmap.getImage().getWidth();
562 final int h = canvasDelegate.mBitmap.getImage().getHeight();
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800563 draw(nativeCanvas, new GcSnapshot.Drawable() {
Xavier Ducroheta313b652010-11-01 18:45:20 -0700564
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800565 public void draw(Graphics2D graphics, Paint_Delegate paint) {
566 // reset its transform just in case
567 graphics.setTransform(new AffineTransform());
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700568
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800569 // set the color
570 graphics.setColor(new Color(color, true /*alpha*/));
571
572 Composite composite = PorterDuffXfermode_Delegate.getComposite(
573 PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF);
574 if (composite != null) {
575 graphics.setComposite(composite);
576 }
577
578 graphics.fillRect(0, 0, w, h);
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800579 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800580 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700581 }
582
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700583 /*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
584 // FIXME
585 throw new UnsupportedOperationException();
586 }
587
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800588 /*package*/ static void native_drawLine(int nativeCanvas,
589 final float startX, final float startY, final float stopX, final float stopY,
590 int paint) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700591
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800592 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
593 new GcSnapshot.Drawable() {
594 public void draw(Graphics2D graphics, Paint_Delegate paint) {
595 graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
596 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800597 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700598 }
599
600 /*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
601 int paint) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700602 native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700603 }
604
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800605 /*package*/ static void native_drawRect(int nativeCanvas,
606 final float left, final float top, final float right, final float bottom, int paint) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700607
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800608 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
609 new GcSnapshot.Drawable() {
610 public void draw(Graphics2D graphics, Paint_Delegate paint) {
611 int style = paint.getStyle();
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700612
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800613 // draw
614 if (style == Paint.Style.FILL.nativeInt ||
615 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
616 graphics.fillRect((int)left, (int)top,
617 (int)(right-left), (int)(bottom-top));
618 }
Xavier Ducrohetcf021232010-12-14 18:05:22 -0800619
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800620 if (style == Paint.Style.STROKE.nativeInt ||
621 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
622 graphics.drawRect((int)left, (int)top,
623 (int)(right-left), (int)(bottom-top));
624 }
625 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800626 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700627 }
628
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800629 /*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700630 if (oval.right > oval.left && oval.bottom > oval.top) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800631 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
632 new GcSnapshot.Drawable() {
633 public void draw(Graphics2D graphics, Paint_Delegate paint) {
634 int style = paint.getStyle();
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700635
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800636 // draw
637 if (style == Paint.Style.FILL.nativeInt ||
638 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
639 graphics.fillOval((int)oval.left, (int)oval.top,
640 (int)oval.width(), (int)oval.height());
641 }
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700642
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800643 if (style == Paint.Style.STROKE.nativeInt ||
644 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
645 graphics.drawOval((int)oval.left, (int)oval.top,
646 (int)oval.width(), (int)oval.height());
647 }
648 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800649 });
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700650 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700651 }
652
653 /*package*/ static void native_drawCircle(int nativeCanvas, float cx,
654 float cy, float radius,
655 int paint) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700656 native_drawOval(nativeCanvas,
657 new RectF(cx - radius, cy - radius, radius*2, radius*2),
658 paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700659 }
660
661 /*package*/ static void native_drawArc(int nativeCanvas, RectF oval,
662 float startAngle, float sweep,
663 boolean useCenter, int paint) {
664 // FIXME
665 throw new UnsupportedOperationException();
666 }
667
668 /*package*/ static void native_drawRoundRect(int nativeCanvas,
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800669 final RectF rect, final float rx, final float ry, int paint) {
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700670
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800671 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
672 new GcSnapshot.Drawable() {
673 public void draw(Graphics2D graphics, Paint_Delegate paint) {
674 int style = paint.getStyle();
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700675
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800676 // draw
677 if (style == Paint.Style.FILL.nativeInt ||
678 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
679 graphics.fillRoundRect(
680 (int)rect.left, (int)rect.top,
681 (int)rect.width(), (int)rect.height(),
682 (int)rx, (int)ry);
683 }
Xavier Ducrohetf1a174522010-11-01 22:02:08 -0700684
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800685 if (style == Paint.Style.STROKE.nativeInt ||
686 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
687 graphics.drawRoundRect(
688 (int)rect.left, (int)rect.top,
689 (int)rect.width(), (int)rect.height(),
690 (int)rx, (int)ry);
691 }
692 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800693 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700694 }
695
696 /*package*/ static void native_drawPath(int nativeCanvas, int path,
697 int paint) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800698 final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
699 if (pathDelegate == null) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800700 return;
701 }
702
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800703 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
704 new GcSnapshot.Drawable() {
705 public void draw(Graphics2D graphics, Paint_Delegate paint) {
706 Shape shape = pathDelegate.getJavaShape();
707 int style = paint.getStyle();
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800708
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800709 if (style == Paint.Style.FILL.nativeInt ||
710 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
711 graphics.fill(shape);
712 }
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800713
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800714 if (style == Paint.Style.STROKE.nativeInt ||
715 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
716 graphics.draw(shape);
717 }
718 }
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800719 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700720 }
721
722 /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
723 float left, float top,
724 int nativePaintOrZero,
725 int canvasDensity,
726 int screenDensity,
727 int bitmapDensity) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800728 // get the delegate from the native int.
729 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
730 if (bitmapDelegate == null) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800731 return;
732 }
733
734 BufferedImage image = bitmapDelegate.getImage();
735 float right = left + image.getWidth();
736 float bottom = top + image.getHeight();
737
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800738 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
Xavier Ducrohetc810bea2010-12-20 08:22:47 -0800739 0, 0, image.getWidth(), image.getHeight(),
740 (int)left, (int)top, (int)right, (int)bottom);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700741 }
742
743 /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
744 Rect src, RectF dst,
745 int nativePaintOrZero,
746 int screenDensity,
747 int bitmapDensity) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700748 // get the delegate from the native int.
749 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
750 if (bitmapDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700751 return;
752 }
753
754 BufferedImage image = bitmapDelegate.getImage();
755
756 if (src == null) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800757 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700758 0, 0, image.getWidth(), image.getHeight(),
759 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
760 } else {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800761 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700762 src.left, src.top, src.width(), src.height(),
763 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
764 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700765 }
766
767 /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
768 Rect src, Rect dst,
769 int nativePaintOrZero,
770 int screenDensity,
771 int bitmapDensity) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700772 // get the delegate from the native int.
773 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
774 if (bitmapDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700775 return;
776 }
777
778 BufferedImage image = bitmapDelegate.getImage();
779
780 if (src == null) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800781 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700782 0, 0, image.getWidth(), image.getHeight(),
783 dst.left, dst.top, dst.right, dst.bottom);
784 } else {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800785 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700786 src.left, src.top, src.width(), src.height(),
787 dst.left, dst.top, dst.right, dst.bottom);
788 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700789 }
790
791 /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800792 int offset, int stride, final float x,
793 final float y, int width, int height,
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700794 boolean hasAlpha,
795 int nativePaintOrZero) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800796
797 // create a temp BufferedImage containing the content.
798 final BufferedImage image = new BufferedImage(width, height,
799 hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
800 image.setRGB(0, 0, width, height, colors, offset, stride);
801
802 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
803 new GcSnapshot.Drawable() {
804 public void draw(Graphics2D graphics, Paint_Delegate paint) {
805 if (paint != null && paint.isFilterBitmap()) {
806 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
807 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
808 }
809
810 graphics.drawImage(image, (int) x, (int) y, null);
811 }
812 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700813 }
814
815 /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
816 int nMatrix, int nPaint) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800817 // get the delegate from the native int.
818 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
819 if (canvasDelegate == null) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800820 return;
821 }
822
Xavier Ducroheta6e51d52010-12-23 07:16:21 -0800823 // get the delegate from the native int, which can be null
824 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800825
826 // get the delegate from the native int.
827 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
828 if (bitmapDelegate == null) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800829 return;
830 }
831
832 final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);
833
834 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
835 if (matrixDelegate == null) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800836 return;
837 }
838
839 final AffineTransform mtx = matrixDelegate.getAffineTransform();
840
841 canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
842 public void draw(Graphics2D graphics, Paint_Delegate paint) {
843 if (paint != null && paint.isFilterBitmap()) {
844 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
845 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
846 }
847
848 //FIXME add support for canvas, screen and bitmap densities.
849 graphics.drawImage(image, mtx, null);
850 }
851 }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700852 }
853
854 /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
855 int meshWidth, int meshHeight,
856 float[] verts, int vertOffset,
857 int[] colors, int colorOffset, int nPaint) {
858 // FIXME
859 throw new UnsupportedOperationException();
860 }
861
862 /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n,
863 float[] verts, int vertOffset, float[] texs, int texOffset,
864 int[] colors, int colorOffset, short[] indices,
865 int indexOffset, int indexCount, int nPaint) {
866 // FIXME
867 throw new UnsupportedOperationException();
868 }
869
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800870 /*package*/ static void native_drawText(int nativeCanvas,
871 final char[] text, final int index, final int count,
872 final float startX, final float startY, int flags, int paint) {
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -0800873 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
874 new GcSnapshot.Drawable() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800875 public void draw(Graphics2D graphics, Paint_Delegate paint) {
876 // WARNING: the logic in this method is similar to Paint.measureText.
877 // Any change to this method should be reflected in Paint.measureText
878 // Paint.TextAlign indicates how the text is positioned relative to X.
879 // LEFT is the default and there's nothing to do.
880 float x = startX;
881 float y = startY;
882 if (paint.getTextAlign() != Paint.Align.LEFT.nativeInt) {
883 float m = paint.measureText(text, index, count);
884 if (paint.getTextAlign() == Paint.Align.CENTER.nativeInt) {
885 x -= m / 2;
886 } else if (paint.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
887 x -= m;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700888 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800889 }
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700890
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800891 List<FontInfo> fonts = paint.getFonts();
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700892
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800893 if (fonts.size() > 0) {
894 FontInfo mainFont = fonts.get(0);
895 int i = index;
896 int lastIndex = index + count;
897 while (i < lastIndex) {
898 // always start with the main font.
899 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700900 if (upTo == -1) {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800901 // draw all the rest and exit.
902 graphics.setFont(mainFont.mFont);
903 graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y);
904 return;
905 } else if (upTo > 0) {
906 // draw what's possible
907 graphics.setFont(mainFont.mFont);
908 graphics.drawChars(text, i, upTo - i, (int)x, (int)y);
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700909
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800910 // compute the width that was drawn to increase x
911 x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700912
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800913 // move index to the first non displayed char.
914 i = upTo;
915
916 // don't call continue at this point. Since it is certain the main font
917 // cannot display the font a index upTo (now ==i), we move on to the
918 // fallback fonts directly.
919 }
920
921 // no char supported, attempt to read the next char(s) with the
922 // fallback font. In this case we only test the first character
923 // and then go back to test with the main font.
924 // Special test for 2-char characters.
925 boolean foundFont = false;
926 for (int f = 1 ; f < fonts.size() ; f++) {
927 FontInfo fontInfo = fonts.get(f);
928
929 // need to check that the font can display the character. We test
930 // differently if the char is a high surrogate.
931 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
932 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
933 if (upTo == -1) {
934 // draw that char
935 graphics.setFont(fontInfo.mFont);
936 graphics.drawChars(text, i, charCount, (int)x, (int)y);
937
938 // update x
939 x += fontInfo.mMetrics.charsWidth(text, i, charCount);
940
941 // update the index in the text, and move on
942 i += charCount;
943 foundFont = true;
944 break;
945
946 }
947 }
948
949 // in case no font can display the char, display it with the main font.
950 // (it'll put a square probably)
951 if (foundFont == false) {
952 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
953
954 graphics.setFont(mainFont.mFont);
955 graphics.drawChars(text, i, charCount, (int)x, (int)y);
956
957 // measure it to advance x
958 x += mainFont.mMetrics.charsWidth(text, i, charCount);
959
960 // and move to the next chars.
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700961 i += charCount;
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700962 }
963 }
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700964 }
965 }
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -0800966 });
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700967 }
968
969 /*package*/ static void native_drawText(int nativeCanvas, String text,
970 int start, int end, float x,
971 float y, int flags, int paint) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -0700972 int count = end - start;
973 char[] buffer = TemporaryBuffer.obtain(count);
974 TextUtils.getChars(text, start, end, buffer, 0);
975
976 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700977 }
978
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700979 /*package*/ static void native_drawTextRun(int nativeCanvas, String text,
980 int start, int end, int contextStart, int contextEnd,
981 float x, float y, int flags, int paint) {
Xavier Ducrohet571dce72010-11-04 18:04:27 -0700982 int count = end - start;
983 char[] buffer = TemporaryBuffer.obtain(count);
984 TextUtils.getChars(text, start, end, buffer, 0);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700985
Xavier Ducrohet571dce72010-11-04 18:04:27 -0700986 native_drawText(nativeCanvas, buffer, start, end, x, y, flags, paint);
987 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700988
989 /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text,
990 int start, int count, int contextStart, int contextCount,
991 float x, float y, int flags, int paint) {
Xavier Ducrohet571dce72010-11-04 18:04:27 -0700992 native_drawText(nativeCanvas, text, 0, count, x, y, flags, paint);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700993 }
994
Xavier Ducrohetef44aea2010-10-28 11:52:00 -0700995 /*package*/ static void native_drawPosText(int nativeCanvas,
996 char[] text, int index,
997 int count, float[] pos,
998 int paint) {
999 // FIXME
1000 throw new UnsupportedOperationException();
1001 }
1002
1003 /*package*/ static void native_drawPosText(int nativeCanvas,
1004 String text, float[] pos,
1005 int paint) {
1006 // FIXME
1007 throw new UnsupportedOperationException();
1008 }
1009
1010 /*package*/ static void native_drawTextOnPath(int nativeCanvas,
1011 char[] text, int index,
1012 int count, int path,
1013 float hOffset,
1014 float vOffset, int bidiFlags,
1015 int paint) {
1016 // FIXME
1017 throw new UnsupportedOperationException();
1018 }
1019
1020 /*package*/ static void native_drawTextOnPath(int nativeCanvas,
1021 String text, int path,
1022 float hOffset,
1023 float vOffset,
1024 int flags, int paint) {
1025 // FIXME
1026 throw new UnsupportedOperationException();
1027 }
1028
1029 /*package*/ static void native_drawPicture(int nativeCanvas,
1030 int nativePicture) {
1031 // FIXME
1032 throw new UnsupportedOperationException();
1033 }
1034
1035 /*package*/ static void finalizer(int nativeCanvas) {
Xavier Ducrohet13926152010-12-01 12:28:43 -08001036 // get the delegate from the native int so that it can be disposed.
1037 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
1038 if (canvasDelegate == null) {
Xavier Ducrohet13926152010-12-01 12:28:43 -08001039 return;
1040 }
1041
1042 canvasDelegate.dispose();
1043
1044 // remove it from the manager.
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001045 sManager.removeDelegate(nativeCanvas);
1046 }
1047
1048 // ---- Private delegate/helper methods ----
1049
Xavier Ducrohetc810bea2010-12-20 08:22:47 -08001050 /**
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001051 * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001052 * <p>Note that the drawable may actually be executed several times if there are
1053 * layers involved (see {@link #saveLayer(RectF, int, int)}.
Xavier Ducrohetc810bea2010-12-20 08:22:47 -08001054 */
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001055 private static void draw(int nCanvas, int nPaint, boolean compositeOnly, boolean forceSrcMode,
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001056 GcSnapshot.Drawable drawable) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -08001057 // get the delegate from the native int.
1058 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
1059 if (canvasDelegate == null) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -08001060 return;
1061 }
1062
Xavier Ducroheta6e51d52010-12-23 07:16:21 -08001063 // get the paint which can be null if nPaint is 0;
1064 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001065
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001066 canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001067 }
1068
1069 /**
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001070 * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001071 * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
1072 * <p>Note that the drawable may actually be executed several times if there are
1073 * layers involved (see {@link #saveLayer(RectF, int, int)}.
1074 */
1075 private static void draw(int nCanvas, GcSnapshot.Drawable drawable) {
1076 // get the delegate from the native int.
1077 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
1078 if (canvasDelegate == null) {
Xavier Ducrohetc810bea2010-12-20 08:22:47 -08001079 return;
1080 }
1081
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001082 canvasDelegate.mSnapshot.draw(drawable);
Xavier Ducrohetc810bea2010-12-20 08:22:47 -08001083 }
1084
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001085 private Canvas_Delegate(Bitmap_Delegate bitmap) {
1086 mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001087 }
1088
1089 private Canvas_Delegate() {
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001090 mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001091 }
1092
Xavier Ducrohet13926152010-12-01 12:28:43 -08001093 /**
1094 * Disposes of the {@link Graphics2D} stack.
1095 */
1096 private void dispose() {
Xavier Ducrohetcf021232010-12-14 18:05:22 -08001097 mSnapshot.dispose();
Xavier Ducrohet13926152010-12-01 12:28:43 -08001098 }
1099
Xavier Ducrohetcf021232010-12-14 18:05:22 -08001100 private int save(int saveFlags) {
1101 // get the current save count
1102 int count = mSnapshot.size();
1103
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001104 mSnapshot = mSnapshot.save(saveFlags);
1105
1106 // return the old save count
1107 return count;
1108 }
1109
1110 private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) {
1111 Paint_Delegate paint = new Paint_Delegate();
1112 paint.setAlpha(alpha);
1113 return saveLayer(rect, paint, saveFlags);
1114 }
1115
1116 private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) {
1117 // get the current save count
1118 int count = mSnapshot.size();
1119
1120 mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);
Xavier Ducrohetcf021232010-12-14 18:05:22 -08001121
1122 // return the old save count
1123 return count;
1124 }
1125
1126 /**
1127 * Restores the {@link GcSnapshot} to <var>saveCount</var>
1128 * @param saveCount the saveCount
1129 */
1130 private void restoreTo(int saveCount) {
1131 mSnapshot = mSnapshot.restoreTo(saveCount);
1132 }
1133
1134 /**
1135 * Restores the {@link GcSnapshot} to <var>saveCount</var>
1136 * @param saveCount the saveCount
1137 */
1138 private void restore() {
1139 mSnapshot = mSnapshot.restore();
1140 }
1141
1142 private boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
1143 return mSnapshot.clipRect(left, top, right, bottom, regionOp);
Xavier Ducrohetdf67eab2010-12-13 16:42:01 -08001144 }
1145
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001146 private void setBitmap(Bitmap_Delegate bitmap) {
1147 mBitmap = bitmap;
Xavier Ducrohetcf021232010-12-14 18:05:22 -08001148 assert mSnapshot.size() == 1;
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001149 mSnapshot.setBitmap(mBitmap);
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001150 }
1151
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001152 private static void drawBitmap(
1153 int nativeCanvas,
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001154 Bitmap_Delegate bitmap,
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001155 int nativePaintOrZero,
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001156 final int sleft, final int stop, final int sright, final int sbottom,
1157 final int dleft, final int dtop, final int dright, final int dbottom) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001158 // get the delegate from the native int.
1159 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
1160 if (canvasDelegate == null) {
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001161 return;
1162 }
1163
Xavier Ducroheta6e51d52010-12-23 07:16:21 -08001164 // get the paint, which could be null if the int is 0
1165 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001166
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001167 final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001168
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001169 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
Xavier Ducrohetcf2030c2010-12-21 06:20:28 -08001170 new GcSnapshot.Drawable() {
1171 public void draw(Graphics2D graphics, Paint_Delegate paint) {
1172 if (paint != null && paint.isFilterBitmap()) {
1173 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
1174 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
1175 }
1176
1177 //FIXME add support for canvas, screen and bitmap densities.
1178 graphics.drawImage(image, dleft, dtop, dright, dbottom,
1179 sleft, stop, sright, sbottom, null);
1180 }
1181 });
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001182 }
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001183
1184
1185 /**
1186 * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate.
1187 * The image returns, through a 1-size boolean array, whether the drawing code should
1188 * use a SRC composite no matter what the paint says.
1189 *
1190 * @param bitmap the bitmap
1191 * @param paint the paint that will be used to draw
1192 * @param forceSrcMode whether the composite will have to be SRC
1193 * @return the image to draw
1194 */
1195 private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint,
1196 boolean[] forceSrcMode) {
1197 BufferedImage image = bitmap.getImage();
1198 forceSrcMode[0] = false;
1199
1200 // if the bitmap config is alpha_8, then we erase all color value from it
1201 // before drawing it.
1202 if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
1203 fixAlpha8Bitmap(image);
1204 } else if (bitmap.hasAlpha() == false) {
1205 // hasAlpha is merely a rendering hint. There can in fact be alpha values
1206 // in the bitmap but it should be ignored at drawing time.
1207 // There is two ways to do this:
1208 // - override the composite to be SRC. This can only be used if the composite
1209 // was going to be SRC or SRC_OVER in the first place
1210 // - Create a different bitmap to draw in which all the alpha channel values is set
1211 // to 0xFF.
1212 if (paint != null) {
Xavier Ducroheta6e51d52010-12-23 07:16:21 -08001213 Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
1214 if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
1215 PorterDuff.Mode mode =
1216 ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001217
Xavier Ducroheta6e51d52010-12-23 07:16:21 -08001218 forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
1219 mode == PorterDuff.Mode.SRC;
Xavier Ducrohetbe4eb822010-12-22 10:13:23 -08001220 }
1221 }
1222
1223 // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
1224 if (forceSrcMode[0] == false) {
1225 image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
1226 }
1227 }
1228
1229 return image;
1230 }
1231
1232 private static void fixAlpha8Bitmap(final BufferedImage image) {
1233 int w = image.getWidth();
1234 int h = image.getHeight();
1235 int[] argb = new int[w * h];
1236 image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
1237
1238 final int length = argb.length;
1239 for (int i = 0 ; i < length; i++) {
1240 argb[i] &= 0xFF000000;
1241 }
1242 image.setRGB(0, 0, w, h, argb, 0, w);
1243 }
Xavier Ducrohetef44aea2010-10-28 11:52:00 -07001244}
Xavier Ducrohet37f21802010-11-01 16:17:18 -07001245