• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.graphics;
18 
19 import com.android.ide.common.rendering.api.LayoutLog;
20 import com.android.layoutlib.bridge.Bridge;
21 import com.android.layoutlib.bridge.impl.DelegateManager;
22 import com.android.layoutlib.bridge.impl.GcSnapshot;
23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
24 
25 import android.annotation.Nullable;
26 import android.graphics.Bitmap.Config;
27 
28 import java.awt.Graphics2D;
29 import java.awt.Rectangle;
30 import java.awt.geom.AffineTransform;
31 
32 import libcore.util.NativeAllocationRegistry_Delegate;
33 
34 
35 /**
36  * Delegate implementing the native methods of android.graphics.Canvas
37  *
38  * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
39  * by calls to methods of the same name in this delegate class.
40  *
41  * This class behaves like the original native implementation, but in Java, keeping previously
42  * native data into its own objects and mapping them to int that are sent back and forth between
43  * it and the original Canvas class.
44  *
45  * @see DelegateManager
46  *
47  */
48 public final class Canvas_Delegate extends BaseCanvas_Delegate {
49 
50     // ---- delegate manager ----
51     private static long sFinalizer = -1;
52 
53     private DrawFilter_Delegate mDrawFilter = null;
54 
55     // ---- Public Helper methods ----
56 
57     /**
58      * Returns the native delegate associated to a given {@link Canvas} object.
59      */
getDelegate(Canvas canvas)60     public static Canvas_Delegate getDelegate(Canvas canvas) {
61         return (Canvas_Delegate) sManager.getDelegate(canvas.getNativeCanvasWrapper());
62     }
63 
64     /**
65      * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
66      */
getDelegate(long native_canvas)67     public static Canvas_Delegate getDelegate(long native_canvas) {
68         return (Canvas_Delegate) sManager.getDelegate(native_canvas);
69     }
70 
71     /**
72      * Returns the current {@link Graphics2D} used to draw.
73      */
getSnapshot()74     public GcSnapshot getSnapshot() {
75         return mSnapshot;
76     }
77 
78     /**
79      * Returns the {@link DrawFilter} delegate or null if none have been set.
80      *
81      * @return the delegate or null.
82      */
getDrawFilter()83     public DrawFilter_Delegate getDrawFilter() {
84         return mDrawFilter;
85     }
86 
87     // ---- native methods ----
88 
89     @LayoutlibDelegate
nFreeCaches()90     /*package*/ static void nFreeCaches() {
91         // nothing to be done here.
92     }
93 
94     @LayoutlibDelegate
nFreeTextLayoutCaches()95     /*package*/ static void nFreeTextLayoutCaches() {
96         // nothing to be done here yet.
97     }
98 
99     @LayoutlibDelegate
nInitRaster(@ullable Bitmap bitmap)100     /*package*/ static long nInitRaster(@Nullable Bitmap bitmap) {
101         long nativeBitmapOrZero = 0;
102         if (bitmap != null) {
103             nativeBitmapOrZero = bitmap.getNativeInstance();
104         }
105         if (nativeBitmapOrZero > 0) {
106             // get the Bitmap from the int
107             Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
108 
109             // create a new Canvas_Delegate with the given bitmap and return its new native int.
110             Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
111 
112             return sManager.addNewDelegate(newDelegate);
113         }
114 
115         // create a new Canvas_Delegate and return its new native int.
116         Canvas_Delegate newDelegate = new Canvas_Delegate();
117 
118         return sManager.addNewDelegate(newDelegate);
119     }
120 
121     @LayoutlibDelegate
nSetBitmap(long canvas, Bitmap bitmap)122     public static void nSetBitmap(long canvas, Bitmap bitmap) {
123         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
124         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
125         if (canvasDelegate == null || bitmapDelegate==null) {
126             return;
127         }
128         canvasDelegate.mBitmap = bitmapDelegate;
129         canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate);
130     }
131 
132     @LayoutlibDelegate
nIsOpaque(long nativeCanvas)133     public static boolean nIsOpaque(long nativeCanvas) {
134         // get the delegate from the native int.
135         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
136         if (canvasDelegate == null) {
137             return false;
138         }
139 
140         return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
141     }
142 
143     @LayoutlibDelegate
nGetWidth(long nativeCanvas)144     public static int nGetWidth(long nativeCanvas) {
145         // get the delegate from the native int.
146         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
147         if (canvasDelegate == null) {
148             return 0;
149         }
150 
151         return canvasDelegate.mBitmap.getImage().getWidth();
152     }
153 
154     @LayoutlibDelegate
nGetHeight(long nativeCanvas)155     public static int nGetHeight(long nativeCanvas) {
156         // get the delegate from the native int.
157         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
158         if (canvasDelegate == null) {
159             return 0;
160         }
161 
162         return canvasDelegate.mBitmap.getImage().getHeight();
163     }
164 
165     @LayoutlibDelegate
nSave(long nativeCanvas, int saveFlags)166     public static int nSave(long nativeCanvas, int saveFlags) {
167         // get the delegate from the native int.
168         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
169         if (canvasDelegate == null) {
170             return 0;
171         }
172 
173         return canvasDelegate.save(saveFlags);
174     }
175 
176     @LayoutlibDelegate
nSaveLayer(long nativeCanvas, float l, float t, float r, float b, long paint, int layerFlags)177     public static int nSaveLayer(long nativeCanvas, float l,
178                                                float t, float r, float b,
179                                                long paint, int layerFlags) {
180         // get the delegate from the native int.
181         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
182         if (canvasDelegate == null) {
183             return 0;
184         }
185 
186         Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
187         if (paintDelegate == null) {
188             return 0;
189         }
190 
191         return canvasDelegate.saveLayer(new RectF(l, t, r, b),
192                 paintDelegate, layerFlags);
193     }
194 
195     @LayoutlibDelegate
nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, int alpha, int layerFlags)196     public static int nSaveLayerAlpha(long nativeCanvas, float l,
197                                                     float t, float r, float b,
198                                                     int alpha, int layerFlags) {
199         // get the delegate from the native int.
200         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
201         if (canvasDelegate == null) {
202             return 0;
203         }
204 
205         return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
206     }
207 
208     @LayoutlibDelegate
nRestore(long nativeCanvas)209     public static boolean nRestore(long nativeCanvas) {
210         // FIXME: implement throwOnUnderflow.
211         // get the delegate from the native int.
212         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
213         if (canvasDelegate == null) {
214             return false;
215         }
216 
217         canvasDelegate.restore();
218         return true;
219     }
220 
221     @LayoutlibDelegate
nRestoreToCount(long nativeCanvas, int saveCount)222     public static void nRestoreToCount(long nativeCanvas, int saveCount) {
223         // FIXME: implement throwOnUnderflow.
224         // get the delegate from the native int.
225         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
226         if (canvasDelegate == null) {
227             return;
228         }
229 
230         canvasDelegate.restoreTo(saveCount);
231     }
232 
233     @LayoutlibDelegate
nGetSaveCount(long nativeCanvas)234     public static int nGetSaveCount(long nativeCanvas) {
235         // get the delegate from the native int.
236         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
237         if (canvasDelegate == null) {
238             return 0;
239         }
240 
241         return canvasDelegate.getSnapshot().size();
242     }
243 
244     @LayoutlibDelegate
nTranslate(long nativeCanvas, float dx, float dy)245    public static void nTranslate(long nativeCanvas, float dx, float dy) {
246         // get the delegate from the native int.
247         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
248         if (canvasDelegate == null) {
249             return;
250         }
251 
252         canvasDelegate.getSnapshot().translate(dx, dy);
253     }
254 
255     @LayoutlibDelegate
nScale(long nativeCanvas, float sx, float sy)256        public static void nScale(long nativeCanvas, float sx, float sy) {
257             // get the delegate from the native int.
258             Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
259             if (canvasDelegate == null) {
260                 return;
261             }
262 
263             canvasDelegate.getSnapshot().scale(sx, sy);
264         }
265 
266     @LayoutlibDelegate
nRotate(long nativeCanvas, float degrees)267     public static void nRotate(long nativeCanvas, float degrees) {
268         // get the delegate from the native int.
269         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
270         if (canvasDelegate == null) {
271             return;
272         }
273 
274         canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
275     }
276 
277     @LayoutlibDelegate
nSkew(long nativeCanvas, float kx, float ky)278    public static void nSkew(long nativeCanvas, float kx, float ky) {
279         // get the delegate from the native int.
280         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
281         if (canvasDelegate == null) {
282             return;
283         }
284 
285         // get the current top graphics2D object.
286         GcSnapshot g = canvasDelegate.getSnapshot();
287 
288         // get its current matrix
289         AffineTransform currentTx = g.getTransform();
290         // get the AffineTransform for the given skew.
291         float[] mtx = Matrix_Delegate.getSkew(kx, ky);
292         AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
293 
294         // combine them so that the given matrix is applied after.
295         currentTx.preConcatenate(matrixTx);
296 
297         // give it to the graphics2D as a new matrix replacing all previous transform
298         g.setTransform(currentTx);
299     }
300 
301     @LayoutlibDelegate
nConcat(long nCanvas, long nMatrix)302     public static void nConcat(long nCanvas, long nMatrix) {
303         // get the delegate from the native int.
304         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
305         if (canvasDelegate == null) {
306             return;
307         }
308 
309         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
310         if (matrixDelegate == null) {
311             return;
312         }
313 
314         // get the current top graphics2D object.
315         GcSnapshot snapshot = canvasDelegate.getSnapshot();
316 
317         // get its current matrix
318         AffineTransform currentTx = snapshot.getTransform();
319         // get the AffineTransform of the given matrix
320         AffineTransform matrixTx = matrixDelegate.getAffineTransform();
321 
322         // combine them so that the given matrix is applied after.
323         currentTx.concatenate(matrixTx);
324 
325         // give it to the graphics2D as a new matrix replacing all previous transform
326         snapshot.setTransform(currentTx);
327     }
328 
329     @LayoutlibDelegate
nSetMatrix(long nCanvas, long nMatrix)330     public static void nSetMatrix(long nCanvas, long nMatrix) {
331         // get the delegate from the native int.
332         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
333         if (canvasDelegate == null) {
334             return;
335         }
336 
337         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
338         if (matrixDelegate == null) {
339             return;
340         }
341 
342         // get the current top graphics2D object.
343         GcSnapshot snapshot = canvasDelegate.getSnapshot();
344 
345         // get the AffineTransform of the given matrix
346         AffineTransform matrixTx = matrixDelegate.getAffineTransform();
347 
348         // give it to the graphics2D as a new matrix replacing all previous transform
349         snapshot.setTransform(matrixTx);
350 
351         if (matrixDelegate.hasPerspective()) {
352             assert false;
353             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
354                     "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
355                     "supports affine transformations.", null, null /*data*/);
356         }
357     }
358 
359     @LayoutlibDelegate
nClipRect(long nCanvas, float left, float top, float right, float bottom, int regionOp)360     public static boolean nClipRect(long nCanvas,
361                                                   float left, float top,
362                                                   float right, float bottom,
363                                                   int regionOp) {
364         // get the delegate from the native int.
365         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
366         if (canvasDelegate == null) {
367             return false;
368         }
369 
370         return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
371     }
372 
373     @LayoutlibDelegate
nClipPath(long nativeCanvas, long nativePath, int regionOp)374     public static boolean nClipPath(long nativeCanvas,
375                                                   long nativePath,
376                                                   int regionOp) {
377         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
378         if (canvasDelegate == null) {
379             return true;
380         }
381 
382         Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
383         if (pathDelegate == null) {
384             return true;
385         }
386 
387         return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
388     }
389 
390     @LayoutlibDelegate
nSetDrawFilter(long nativeCanvas, long nativeFilter)391     public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) {
392         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
393         if (canvasDelegate == null) {
394             return;
395         }
396 
397         canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
398 
399         if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) {
400             Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
401                     canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
402         }
403     }
404 
405     @LayoutlibDelegate
nGetClipBounds(long nativeCanvas, Rect bounds)406     public static boolean nGetClipBounds(long nativeCanvas,
407                                                        Rect bounds) {
408         // get the delegate from the native int.
409         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
410         if (canvasDelegate == null) {
411             return false;
412         }
413 
414         Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
415         if (rect != null && !rect.isEmpty()) {
416             bounds.left = rect.x;
417             bounds.top = rect.y;
418             bounds.right = rect.x + rect.width;
419             bounds.bottom = rect.y + rect.height;
420             return true;
421         }
422 
423         return false;
424     }
425 
426     @LayoutlibDelegate
nGetMatrix(long canvas, long matrix)427     public static void nGetMatrix(long canvas, long matrix) {
428         // get the delegate from the native int.
429         Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
430         if (canvasDelegate == null) {
431             return;
432         }
433 
434         Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
435         if (matrixDelegate == null) {
436             return;
437         }
438 
439         AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
440         matrixDelegate.set(Matrix_Delegate.makeValues(transform));
441     }
442 
443     @LayoutlibDelegate
nQuickReject(long nativeCanvas, long path)444     public static boolean nQuickReject(long nativeCanvas, long path) {
445         // FIXME properly implement quickReject
446         return false;
447     }
448 
449     @LayoutlibDelegate
nQuickReject(long nativeCanvas, float left, float top, float right, float bottom)450     public static boolean nQuickReject(long nativeCanvas,
451                                                      float left, float top,
452                                                      float right, float bottom) {
453         // FIXME properly implement quickReject
454         return false;
455     }
456 
457     @LayoutlibDelegate
nGetNativeFinalizer()458     /*package*/ static long nGetNativeFinalizer() {
459         synchronized (Canvas_Delegate.class) {
460             if (sFinalizer == -1) {
461                 sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> {
462                     Canvas_Delegate delegate = Canvas_Delegate.getDelegate(nativePtr);
463                     if (delegate != null) {
464                         delegate.dispose();
465                     }
466                     sManager.removeJavaReferenceFor(nativePtr);
467                 });
468             }
469         }
470         return sFinalizer;
471     }
472 
473     @LayoutlibDelegate
nSetCompatibilityVersion(int apiLevel)474     /*package*/ static void nSetCompatibilityVersion(int apiLevel) {
475         // Unsupported by layoutlib, do nothing
476     }
477 
Canvas_Delegate(Bitmap_Delegate bitmap)478     private Canvas_Delegate(Bitmap_Delegate bitmap) {
479         super(bitmap);
480     }
481 
Canvas_Delegate()482     private Canvas_Delegate() {
483         super();
484     }
485 }
486 
487