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