• 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.view;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.CanvasProperty;
24 import android.graphics.Paint;
25 import android.util.Pools.SynchronizedPool;
26 
27 /**
28  * An implementation of a GL canvas that records drawing operations.
29  * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
30  * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
31  * the DisplayList is still holding a native reference to the memory.
32  *
33  * @hide
34  */
35 public class DisplayListCanvas extends Canvas {
36     // The recording canvas pool should be large enough to handle a deeply nested
37     // view hierarchy because display lists are generated recursively.
38     private static final int POOL_LIMIT = 25;
39 
40     private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
41 
42     private static final SynchronizedPool<DisplayListCanvas> sPool =
43             new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT);
44 
45     RenderNode mNode;
46     private int mWidth;
47     private int mHeight;
48 
obtain(@onNull RenderNode node, int width, int height)49     static DisplayListCanvas obtain(@NonNull RenderNode node, int width, int height) {
50         if (node == null) throw new IllegalArgumentException("node cannot be null");
51         DisplayListCanvas canvas = sPool.acquire();
52         if (canvas == null) {
53             canvas = new DisplayListCanvas(width, height);
54         } else {
55             nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, width, height);
56         }
57         canvas.mNode = node;
58         canvas.mWidth = width;
59         canvas.mHeight = height;
60         return canvas;
61     }
62 
recycle()63     void recycle() {
64         mNode = null;
65         sPool.release(this);
66     }
67 
finishRecording()68     long finishRecording() {
69         return nFinishRecording(mNativeCanvasWrapper);
70     }
71 
72     @Override
isRecordingFor(Object o)73     public boolean isRecordingFor(Object o) {
74         return o == mNode;
75     }
76 
77     ///////////////////////////////////////////////////////////////////////////
78     // JNI
79     ///////////////////////////////////////////////////////////////////////////
80 
nIsAvailable()81     private static native boolean nIsAvailable();
82     private static boolean sIsAvailable = nIsAvailable();
83 
isAvailable()84     static boolean isAvailable() {
85         return sIsAvailable;
86     }
87 
88     ///////////////////////////////////////////////////////////////////////////
89     // Constructors
90     ///////////////////////////////////////////////////////////////////////////
91 
DisplayListCanvas(int width, int height)92     private DisplayListCanvas(int width, int height) {
93         super(nCreateDisplayListCanvas(width, height));
94         mDensity = 0; // disable bitmap density scaling
95     }
96 
nCreateDisplayListCanvas(int width, int height)97     private static native long nCreateDisplayListCanvas(int width, int height);
nResetDisplayListCanvas(long canvas, int width, int height)98     private static native void nResetDisplayListCanvas(long canvas, int width, int height);
99 
100     ///////////////////////////////////////////////////////////////////////////
101     // Canvas management
102     ///////////////////////////////////////////////////////////////////////////
103 
104 
105     @Override
setDensity(int density)106     public void setDensity(int density) {
107         // drop silently, since DisplayListCanvas doesn't perform density scaling
108     }
109 
110     @Override
isHardwareAccelerated()111     public boolean isHardwareAccelerated() {
112         return true;
113     }
114 
115     @Override
setBitmap(Bitmap bitmap)116     public void setBitmap(Bitmap bitmap) {
117         throw new UnsupportedOperationException();
118     }
119 
120     @Override
isOpaque()121     public boolean isOpaque() {
122         return false;
123     }
124 
125     @Override
getWidth()126     public int getWidth() {
127         return mWidth;
128     }
129 
130     @Override
getHeight()131     public int getHeight() {
132         return mHeight;
133     }
134 
135     @Override
getMaximumBitmapWidth()136     public int getMaximumBitmapWidth() {
137         return nGetMaximumTextureWidth();
138     }
139 
140     @Override
getMaximumBitmapHeight()141     public int getMaximumBitmapHeight() {
142         return nGetMaximumTextureHeight();
143     }
144 
nGetMaximumTextureWidth()145     private static native int nGetMaximumTextureWidth();
nGetMaximumTextureHeight()146     private static native int nGetMaximumTextureHeight();
147 
148     ///////////////////////////////////////////////////////////////////////////
149     // Setup
150     ///////////////////////////////////////////////////////////////////////////
151 
152     @Override
insertReorderBarrier()153     public void insertReorderBarrier() {
154         nInsertReorderBarrier(mNativeCanvasWrapper, true);
155     }
156 
157     @Override
insertInorderBarrier()158     public void insertInorderBarrier() {
159         nInsertReorderBarrier(mNativeCanvasWrapper, false);
160     }
161 
nInsertReorderBarrier(long renderer, boolean enableReorder)162     private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
163 
164     ///////////////////////////////////////////////////////////////////////////
165     // Functor
166     ///////////////////////////////////////////////////////////////////////////
167 
168     /**
169      * Records the functor specified with the drawGLFunction function pointer. This is
170      * functionality used by webview for calling into their renderer from our display lists.
171      *
172      * @param drawGLFunction A native function pointer
173      */
callDrawGLFunction2(long drawGLFunction)174     public void callDrawGLFunction2(long drawGLFunction) {
175         nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null);
176     }
177 
178     /**
179      * Records the functor specified with the drawGLFunction function pointer. This is
180      * functionality used by webview for calling into their renderer from our display lists.
181      *
182      * @param drawGLFunction A native function pointer
183      * @param releasedCallback Called when the display list is destroyed, and thus
184      * the functor is no longer referenced by this canvas's display list.
185      *
186      * NOTE: The callback does *not* necessarily mean that there are no longer
187      * any references to the functor, just that the reference from this specific
188      * canvas's display list has been released.
189      */
drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback)190     public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) {
191         nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
192     }
193 
nCallDrawGLFunction(long renderer, long drawGLFunction, Runnable releasedCallback)194     private static native void nCallDrawGLFunction(long renderer,
195             long drawGLFunction, Runnable releasedCallback);
196 
197     ///////////////////////////////////////////////////////////////////////////
198     // Display list
199     ///////////////////////////////////////////////////////////////////////////
200 
nFinishRecording(long renderer)201     protected static native long nFinishRecording(long renderer);
202 
203     /**
204      * Draws the specified display list onto this canvas. The display list can only
205      * be drawn if {@link android.view.RenderNode#isValid()} returns true.
206      *
207      * @param renderNode The RenderNode to draw.
208      */
drawRenderNode(RenderNode renderNode)209     public void drawRenderNode(RenderNode renderNode) {
210         nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList());
211     }
212 
nDrawRenderNode(long renderer, long renderNode)213     private static native void nDrawRenderNode(long renderer, long renderNode);
214 
215     ///////////////////////////////////////////////////////////////////////////
216     // Hardware layer
217     ///////////////////////////////////////////////////////////////////////////
218 
219     /**
220      * Draws the specified layer onto this canvas.
221      *
222      * @param layer The layer to composite on this canvas
223      */
drawHardwareLayer(HardwareLayer layer)224     void drawHardwareLayer(HardwareLayer layer) {
225         nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle());
226     }
227 
nDrawLayer(long renderer, long layer)228     private static native void nDrawLayer(long renderer, long layer);
229 
230     ///////////////////////////////////////////////////////////////////////////
231     // Drawing
232     ///////////////////////////////////////////////////////////////////////////
233 
drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint)234     public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
235             CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
236         nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
237                 radius.getNativeContainer(), paint.getNativeContainer());
238     }
239 
nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint)240     private static native void nDrawCircle(long renderer, long propCx,
241             long propCy, long propRadius, long propPaint);
242 
drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, CanvasProperty<Float> ry, CanvasProperty<Paint> paint)243     public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
244             CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
245             CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
246         nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(),
247                 right.getNativeContainer(), bottom.getNativeContainer(),
248                 rx.getNativeContainer(), ry.getNativeContainer(),
249                 paint.getNativeContainer());
250     }
251 
nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint)252     private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
253             long propRight, long propBottom, long propRx, long propRy, long propPaint);
254 
255     @Override
throwIfCannotDraw(Bitmap bitmap)256     protected void throwIfCannotDraw(Bitmap bitmap) {
257         super.throwIfCannotDraw(bitmap);
258         int bitmapSize = bitmap.getByteCount();
259         if (bitmapSize > MAX_BITMAP_SIZE) {
260             throw new RuntimeException(
261                     "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
262         }
263     }
264 }
265