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