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.graphics.Bitmap;
20import android.graphics.BitmapShader;
21import android.graphics.Matrix;
22import android.graphics.Paint;
23import android.graphics.Path;
24import android.graphics.Rect;
25import android.graphics.RectF;
26import android.graphics.Shader;
27import android.util.Pool;
28import android.util.Poolable;
29import android.util.PoolableManager;
30import android.util.Pools;
31
32/**
33 * An implementation of a GL canvas that records drawing operations.
34 * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
35 * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
36 * the DisplayList is still holding a native reference to the memory.
37 */
38class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
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    private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
44            Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
45                public GLES20RecordingCanvas newInstance() {
46                    return new GLES20RecordingCanvas();
47                }
48                @Override
49                public void onAcquired(GLES20RecordingCanvas element) {
50                }
51                @Override
52                public void onReleased(GLES20RecordingCanvas element) {
53                }
54            }, POOL_LIMIT));
55
56    private GLES20RecordingCanvas mNextPoolable;
57    private boolean mIsPooled;
58
59    private GLES20DisplayList mDisplayList;
60
61    private GLES20RecordingCanvas() {
62        super(true /*record*/, true /*translucent*/);
63    }
64
65    static GLES20RecordingCanvas obtain(GLES20DisplayList displayList) {
66        GLES20RecordingCanvas canvas = sPool.acquire();
67        canvas.mDisplayList = displayList;
68        return canvas;
69    }
70
71    void recycle() {
72        mDisplayList = null;
73        resetDisplayListRenderer();
74        sPool.release(this);
75    }
76
77    void start() {
78        mDisplayList.mBitmaps.clear();
79        mDisplayList.mChildDisplayLists.clear();
80    }
81
82    int end(int nativeDisplayList) {
83        return getDisplayList(nativeDisplayList);
84    }
85
86    private void recordShaderBitmap(Paint paint) {
87        if (paint != null) {
88            final Shader shader = paint.getShader();
89            if (shader instanceof BitmapShader) {
90                mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap);
91            }
92        }
93    }
94
95    @Override
96    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
97        super.drawPatch(bitmap, chunks, dst, paint);
98        mDisplayList.mBitmaps.add(bitmap);
99        // Shaders in the Paint are ignored when drawing a Bitmap
100    }
101
102    @Override
103    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
104        super.drawBitmap(bitmap, left, top, paint);
105        mDisplayList.mBitmaps.add(bitmap);
106        // Shaders in the Paint are ignored when drawing a Bitmap
107    }
108
109    @Override
110    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
111        super.drawBitmap(bitmap, matrix, paint);
112        mDisplayList.mBitmaps.add(bitmap);
113        // Shaders in the Paint are ignored when drawing a Bitmap
114    }
115
116    @Override
117    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
118        super.drawBitmap(bitmap, src, dst, paint);
119        mDisplayList.mBitmaps.add(bitmap);
120        // Shaders in the Paint are ignored when drawing a Bitmap
121    }
122
123    @Override
124    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
125        super.drawBitmap(bitmap, src, dst, paint);
126        mDisplayList.mBitmaps.add(bitmap);
127        // Shaders in the Paint are ignored when drawing a Bitmap
128    }
129
130    @Override
131    public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width,
132            int height, boolean hasAlpha, Paint paint) {
133        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
134        // Shaders in the Paint are ignored when drawing a Bitmap
135    }
136
137    @Override
138    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
139            int height, boolean hasAlpha, Paint paint) {
140        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
141        // Shaders in the Paint are ignored when drawing a Bitmap
142    }
143
144    @Override
145    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
146            int vertOffset, int[] colors, int colorOffset, Paint paint) {
147        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset,
148                colors, colorOffset, paint);
149        mDisplayList.mBitmaps.add(bitmap);
150        // Shaders in the Paint are ignored when drawing a Bitmap
151    }
152
153    @Override
154    public void drawCircle(float cx, float cy, float radius, Paint paint) {
155        super.drawCircle(cx, cy, radius, paint);
156        recordShaderBitmap(paint);
157    }
158
159    @Override
160    public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
161        int status = super.drawDisplayList(displayList, dirty, flags);
162        mDisplayList.mChildDisplayLists.add(displayList);
163        return status;
164    }
165
166    @Override
167    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
168        super.drawLine(startX, startY, stopX, stopY, paint);
169        recordShaderBitmap(paint);
170    }
171
172    @Override
173    public void drawLines(float[] pts, int offset, int count, Paint paint) {
174        super.drawLines(pts, offset, count, paint);
175        recordShaderBitmap(paint);
176    }
177
178    @Override
179    public void drawLines(float[] pts, Paint paint) {
180        super.drawLines(pts, paint);
181        recordShaderBitmap(paint);
182    }
183
184    @Override
185    public void drawOval(RectF oval, Paint paint) {
186        super.drawOval(oval, paint);
187        recordShaderBitmap(paint);
188    }
189
190    @Override
191    public void drawPaint(Paint paint) {
192        super.drawPaint(paint);
193        recordShaderBitmap(paint);
194    }
195
196    @Override
197    public void drawPath(Path path, Paint paint) {
198        super.drawPath(path, paint);
199        recordShaderBitmap(paint);
200    }
201
202    @Override
203    public void drawPoint(float x, float y, Paint paint) {
204        super.drawPoint(x, y, paint);
205        recordShaderBitmap(paint);
206    }
207
208    @Override
209    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
210        super.drawPoints(pts, offset, count, paint);
211        recordShaderBitmap(paint);
212    }
213
214    @Override
215    public void drawPoints(float[] pts, Paint paint) {
216        super.drawPoints(pts, paint);
217        recordShaderBitmap(paint);
218    }
219
220    @Override
221    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
222        super.drawPosText(text, index, count, pos, paint);
223        recordShaderBitmap(paint);
224    }
225
226    @Override
227    public void drawPosText(String text, float[] pos, Paint paint) {
228        super.drawPosText(text, pos, paint);
229        recordShaderBitmap(paint);
230    }
231
232    @Override
233    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
234        super.drawRect(left, top, right, bottom, paint);
235        recordShaderBitmap(paint);
236    }
237
238    @Override
239    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
240        super.drawRoundRect(rect, rx, ry, paint);
241        recordShaderBitmap(paint);
242    }
243
244    @Override
245    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
246        super.drawText(text, index, count, x, y, paint);
247        recordShaderBitmap(paint);
248    }
249
250    @Override
251    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
252        super.drawText(text, start, end, x, y, paint);
253        recordShaderBitmap(paint);
254    }
255
256    @Override
257    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
258        super.drawText(text, start, end, x, y, paint);
259        recordShaderBitmap(paint);
260    }
261
262    @Override
263    public void drawText(String text, float x, float y, Paint paint) {
264        super.drawText(text, x, y, paint);
265        recordShaderBitmap(paint);
266    }
267
268    @Override
269    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
270            float vOffset, Paint paint) {
271        super.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint);
272        recordShaderBitmap(paint);
273    }
274
275    @Override
276    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
277        super.drawTextOnPath(text, path, hOffset, vOffset, paint);
278        recordShaderBitmap(paint);
279    }
280
281    @Override
282    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
283            float x, float y, int dir, Paint paint) {
284        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
285        recordShaderBitmap(paint);
286    }
287
288    @Override
289    public void drawTextRun(CharSequence text, int start, int end, int contextStart,
290            int contextEnd, float x, float y, int dir, Paint paint) {
291        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
292        recordShaderBitmap(paint);
293    }
294
295    @Override
296    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
297            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
298            int indexOffset, int indexCount, Paint paint) {
299        super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors,
300                colorOffset, indices, indexOffset, indexCount, paint);
301        recordShaderBitmap(paint);
302    }
303
304    @Override
305    public GLES20RecordingCanvas getNextPoolable() {
306        return mNextPoolable;
307    }
308
309    @Override
310    public void setNextPoolable(GLES20RecordingCanvas element) {
311        mNextPoolable = element;
312    }
313
314    @Override
315    public boolean isPooled() {
316        return mIsPooled;
317    }
318
319    @Override
320    public void setPooled(boolean isPooled) {
321        mIsPooled = isPooled;
322    }
323}
324