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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.util.Pools.SynchronizedPool;
22 import android.view.DisplayListCanvas;
23 import android.view.TextureLayer;
24 
25 import dalvik.annotation.optimization.CriticalNative;
26 import dalvik.annotation.optimization.FastNative;
27 
28 /**
29  * A Canvas implementation that records view system drawing operations for deferred rendering.
30  * This is used in combination with RenderNode. This class keeps a list of all the Paint and
31  * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while
32  * the RecordingCanvas is still holding a native reference to the memory.
33  *
34  * This is obtained by calling {@link RenderNode#beginRecording()} and is valid until the matching
35  * {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is
36  * internally reused.
37  */
38 public final class RecordingCanvas extends DisplayListCanvas {
39     // The recording canvas pool should be large enough to handle a deeply nested
40     // view hierarchy because display lists are generated recursively.
41     private static final int POOL_LIMIT = 25;
42 
43     /** @hide */
44     public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
45 
46     private static final SynchronizedPool<RecordingCanvas> sPool =
47             new SynchronizedPool<>(POOL_LIMIT);
48 
49     /**
50      * TODO: Temporarily exposed for RenderNodeAnimator(Set)
51      * @hide */
52     public RenderNode mNode;
53     private int mWidth;
54     private int mHeight;
55 
56     /** @hide */
obtain(@onNull RenderNode node, int width, int height)57     static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
58         if (node == null) throw new IllegalArgumentException("node cannot be null");
59         RecordingCanvas canvas = sPool.acquire();
60         if (canvas == null) {
61             canvas = new RecordingCanvas(node, width, height);
62         } else {
63             nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode,
64                     width, height);
65         }
66         canvas.mNode = node;
67         canvas.mWidth = width;
68         canvas.mHeight = height;
69         return canvas;
70     }
71 
72     /** @hide */
recycle()73     void recycle() {
74         mNode = null;
75         sPool.release(this);
76     }
77 
78     /** @hide */
finishRecording()79     long finishRecording() {
80         return nFinishRecording(mNativeCanvasWrapper);
81     }
82 
83     /** @hide */
84     @Override
isRecordingFor(Object o)85     public boolean isRecordingFor(Object o) {
86         return o == mNode;
87     }
88 
89     ///////////////////////////////////////////////////////////////////////////
90     // Constructors
91     ///////////////////////////////////////////////////////////////////////////
92 
93     /** @hide */
RecordingCanvas(@onNull RenderNode node, int width, int height)94     protected RecordingCanvas(@NonNull RenderNode node, int width, int height) {
95         super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
96         mDensity = 0; // disable bitmap density scaling
97     }
98 
99     ///////////////////////////////////////////////////////////////////////////
100     // Canvas management
101     ///////////////////////////////////////////////////////////////////////////
102 
103 
104     @Override
setDensity(int density)105     public void setDensity(int density) {
106         // drop silently, since RecordingCanvas doesn't perform density scaling
107     }
108 
109     @Override
isHardwareAccelerated()110     public boolean isHardwareAccelerated() {
111         return true;
112     }
113 
114     @Override
setBitmap(Bitmap bitmap)115     public void setBitmap(Bitmap bitmap) {
116         throw new UnsupportedOperationException();
117     }
118 
119     @Override
isOpaque()120     public boolean isOpaque() {
121         return false;
122     }
123 
124     @Override
getWidth()125     public int getWidth() {
126         return mWidth;
127     }
128 
129     @Override
getHeight()130     public int getHeight() {
131         return mHeight;
132     }
133 
134     @Override
getMaximumBitmapWidth()135     public int getMaximumBitmapWidth() {
136         return nGetMaximumTextureWidth();
137     }
138 
139     @Override
getMaximumBitmapHeight()140     public int getMaximumBitmapHeight() {
141         return nGetMaximumTextureHeight();
142     }
143 
144     ///////////////////////////////////////////////////////////////////////////
145     // Setup
146     ///////////////////////////////////////////////////////////////////////////
147 
148     @Override
enableZ()149     public void enableZ() {
150         nInsertReorderBarrier(mNativeCanvasWrapper, true);
151     }
152 
153     @Override
disableZ()154     public void disableZ() {
155         nInsertReorderBarrier(mNativeCanvasWrapper, false);
156     }
157 
158     ///////////////////////////////////////////////////////////////////////////
159     // Functor
160     ///////////////////////////////////////////////////////////////////////////
161 
162     /**
163      * Records the functor specified with the drawGLFunction function pointer. This is
164      * functionality used by webview for calling into their renderer from our display lists.
165      *
166      * @param drawGLFunction A native function pointer
167      *
168      * @hide
169      * @deprecated Use {@link #drawWebViewFunctor(int)}
170      */
171     @Deprecated
callDrawGLFunction2(long drawGLFunction)172     public void callDrawGLFunction2(long drawGLFunction) {
173         nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null);
174     }
175 
176     /**
177      * Records the functor specified with the drawGLFunction function pointer. This is
178      * functionality used by webview for calling into their renderer from our display lists.
179      *
180      * @param drawGLFunctor A native function pointer
181      * @param releasedCallback Called when the display list is destroyed, and thus
182      * the functor is no longer referenced by this canvas's display list.
183      *
184      * NOTE: The callback does *not* necessarily mean that there are no longer
185      * any references to the functor, just that the reference from this specific
186      * canvas's display list has been released.
187      *
188      * @hide
189      * @deprecated Use {@link #drawWebViewFunctor(int)}
190      */
191     @Deprecated
drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback)192     public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) {
193         nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
194     }
195 
196     /**
197      * Calls the provided functor that was created via WebViewFunctor_create()
198      * @hide
199      */
drawWebViewFunctor(int functor)200     public void drawWebViewFunctor(int functor) {
201         nDrawWebViewFunctor(mNativeCanvasWrapper, functor);
202     }
203 
204     ///////////////////////////////////////////////////////////////////////////
205     // Display list
206     ///////////////////////////////////////////////////////////////////////////
207 
208     /**
209      * Draws the specified display list onto this canvas.
210      *
211      * @param renderNode The RenderNode to draw.
212      */
213     @Override
drawRenderNode(@onNull RenderNode renderNode)214     public void drawRenderNode(@NonNull RenderNode renderNode) {
215         nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode);
216     }
217 
218     ///////////////////////////////////////////////////////////////////////////
219     // Hardware layer
220     ///////////////////////////////////////////////////////////////////////////
221 
222     /**
223      * Draws the specified layer onto this canvas.
224      *
225      * @param layer The layer to composite on this canvas
226      * @hide
227      */
drawTextureLayer(TextureLayer layer)228     public void drawTextureLayer(TextureLayer layer) {
229         nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle());
230     }
231 
232     ///////////////////////////////////////////////////////////////////////////
233     // Drawing
234     ///////////////////////////////////////////////////////////////////////////
235 
236     /**
237      * Draws a circle
238      *
239      * @param cx
240      * @param cy
241      * @param radius
242      * @param paint
243      *
244      * @hide
245      */
drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint)246     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
247             CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
248         nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
249                 radius.getNativeContainer(), paint.getNativeContainer());
250     }
251 
252     /**
253      * Draws a round rect
254      *
255      * @param left
256      * @param top
257      * @param right
258      * @param bottom
259      * @param rx
260      * @param ry
261      * @param paint
262      *
263      * @hide
264      */
drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, CanvasProperty<Float> ry, CanvasProperty<Paint> paint)265     public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
266             CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
267             CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
268         nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(),
269                 right.getNativeContainer(), bottom.getNativeContainer(),
270                 rx.getNativeContainer(), ry.getNativeContainer(),
271                 paint.getNativeContainer());
272     }
273 
274     /** @hide */
275     @Override
throwIfCannotDraw(Bitmap bitmap)276     protected void throwIfCannotDraw(Bitmap bitmap) {
277         super.throwIfCannotDraw(bitmap);
278         int bitmapSize = bitmap.getByteCount();
279         if (bitmapSize > MAX_BITMAP_SIZE) {
280             throw new RuntimeException(
281                     "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
282         }
283     }
284 
285 
286     // ------------------ Fast JNI ------------------------
287 
288     @FastNative
nCallDrawGLFunction(long renderer, long drawGLFunction, Runnable releasedCallback)289     private static native void nCallDrawGLFunction(long renderer,
290             long drawGLFunction, Runnable releasedCallback);
291 
292 
293     // ------------------ Critical JNI ------------------------
294 
295     @CriticalNative
nCreateDisplayListCanvas(long node, int width, int height)296     private static native long nCreateDisplayListCanvas(long node, int width, int height);
297     @CriticalNative
nResetDisplayListCanvas(long canvas, long node, int width, int height)298     private static native void nResetDisplayListCanvas(long canvas, long node,
299             int width, int height);
300     @CriticalNative
nGetMaximumTextureWidth()301     private static native int nGetMaximumTextureWidth();
302     @CriticalNative
nGetMaximumTextureHeight()303     private static native int nGetMaximumTextureHeight();
304     @CriticalNative
nInsertReorderBarrier(long renderer, boolean enableReorder)305     private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
306     @CriticalNative
nFinishRecording(long renderer)307     private static native long nFinishRecording(long renderer);
308     @CriticalNative
nDrawRenderNode(long renderer, long renderNode)309     private static native void nDrawRenderNode(long renderer, long renderNode);
310     @CriticalNative
nDrawTextureLayer(long renderer, long layer)311     private static native void nDrawTextureLayer(long renderer, long layer);
312     @CriticalNative
nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint)313     private static native void nDrawCircle(long renderer, long propCx,
314             long propCy, long propRadius, long propPaint);
315     @CriticalNative
nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint)316     private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
317             long propRight, long propBottom, long propRx, long propRy, long propPaint);
318     @CriticalNative
nDrawWebViewFunctor(long canvas, int functor)319     private static native void nDrawWebViewFunctor(long canvas, int functor);
320 }
321