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