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    }
80
81    int end(int nativeDisplayList) {
82        return getDisplayList(nativeDisplayList);
83    }
84
85    private void recordShaderBitmap(Paint paint) {
86        if (paint != null) {
87            final Shader shader = paint.getShader();
88            if (shader instanceof BitmapShader) {
89                mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap);
90            }
91        }
92    }
93
94    @Override
95    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
96        super.drawPatch(bitmap, chunks, dst, paint);
97        mDisplayList.mBitmaps.add(bitmap);
98        // Shaders in the Paint are ignored when drawing a Bitmap
99    }
100
101    @Override
102    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
103        super.drawBitmap(bitmap, left, top, paint);
104        mDisplayList.mBitmaps.add(bitmap);
105        // Shaders in the Paint are ignored when drawing a Bitmap
106    }
107
108    @Override
109    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
110        super.drawBitmap(bitmap, matrix, paint);
111        mDisplayList.mBitmaps.add(bitmap);
112        // Shaders in the Paint are ignored when drawing a Bitmap
113    }
114
115    @Override
116    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
117        super.drawBitmap(bitmap, src, dst, paint);
118        mDisplayList.mBitmaps.add(bitmap);
119        // Shaders in the Paint are ignored when drawing a Bitmap
120    }
121
122    @Override
123    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
124        super.drawBitmap(bitmap, src, dst, paint);
125        mDisplayList.mBitmaps.add(bitmap);
126        // Shaders in the Paint are ignored when drawing a Bitmap
127    }
128
129    @Override
130    public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width,
131            int height, boolean hasAlpha, Paint paint) {
132        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
133        // Shaders in the Paint are ignored when drawing a Bitmap
134    }
135
136    @Override
137    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
138            int height, boolean hasAlpha, Paint paint) {
139        super.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
140        // Shaders in the Paint are ignored when drawing a Bitmap
141    }
142
143    @Override
144    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
145            int vertOffset, int[] colors, int colorOffset, Paint paint) {
146        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
147                paint);
148        mDisplayList.mBitmaps.add(bitmap);
149        // Shaders in the Paint are ignored when drawing a Bitmap
150    }
151
152    @Override
153    public void drawCircle(float cx, float cy, float radius, Paint paint) {
154        super.drawCircle(cx, cy, radius, paint);
155        recordShaderBitmap(paint);
156    }
157
158    @Override
159    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
160        super.drawLine(startX, startY, stopX, stopY, paint);
161        recordShaderBitmap(paint);
162    }
163
164    @Override
165    public void drawLines(float[] pts, int offset, int count, Paint paint) {
166        super.drawLines(pts, offset, count, paint);
167        recordShaderBitmap(paint);
168    }
169
170    @Override
171    public void drawLines(float[] pts, Paint paint) {
172        super.drawLines(pts, paint);
173        recordShaderBitmap(paint);
174    }
175
176    @Override
177    public void drawOval(RectF oval, Paint paint) {
178        super.drawOval(oval, paint);
179        recordShaderBitmap(paint);
180    }
181
182    @Override
183    public void drawPaint(Paint paint) {
184        super.drawPaint(paint);
185        recordShaderBitmap(paint);
186    }
187
188    @Override
189    public void drawPath(Path path, Paint paint) {
190        super.drawPath(path, paint);
191        recordShaderBitmap(paint);
192    }
193
194    @Override
195    public void drawPoint(float x, float y, Paint paint) {
196        super.drawPoint(x, y, paint);
197        recordShaderBitmap(paint);
198    }
199
200    @Override
201    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
202        super.drawPoints(pts, offset, count, paint);
203        recordShaderBitmap(paint);
204    }
205
206    @Override
207    public void drawPoints(float[] pts, Paint paint) {
208        super.drawPoints(pts, paint);
209        recordShaderBitmap(paint);
210    }
211
212    @Override
213    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
214        super.drawPosText(text, index, count, pos, paint);
215        recordShaderBitmap(paint);
216    }
217
218    @Override
219    public void drawPosText(String text, float[] pos, Paint paint) {
220        super.drawPosText(text, pos, paint);
221        recordShaderBitmap(paint);
222    }
223
224    @Override
225    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
226        super.drawRect(left, top, right, bottom, paint);
227        recordShaderBitmap(paint);
228    }
229
230    @Override
231    public void drawRect(Rect r, Paint paint) {
232        super.drawRect(r, paint);
233        recordShaderBitmap(paint);
234    }
235
236    @Override
237    public void drawRect(RectF r, Paint paint) {
238        super.drawRect(r, paint);
239        recordShaderBitmap(paint);
240    }
241
242    @Override
243    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
244        super.drawRoundRect(rect, rx, ry, paint);
245        recordShaderBitmap(paint);
246    }
247
248    @Override
249    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
250        super.drawText(text, index, count, x, y, paint);
251        recordShaderBitmap(paint);
252    }
253
254    @Override
255    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
256        super.drawText(text, start, end, x, y, paint);
257        recordShaderBitmap(paint);
258    }
259
260    @Override
261    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
262        super.drawText(text, start, end, x, y, paint);
263        recordShaderBitmap(paint);
264    }
265
266    @Override
267    public void drawText(String text, float x, float y, Paint paint) {
268        super.drawText(text, x, y, paint);
269        recordShaderBitmap(paint);
270    }
271
272    @Override
273    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
274            float vOffset, Paint paint) {
275        super.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint);
276        recordShaderBitmap(paint);
277    }
278
279    @Override
280    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
281        super.drawTextOnPath(text, path, hOffset, vOffset, paint);
282        recordShaderBitmap(paint);
283    }
284
285    @Override
286    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
287            float x, float y, int dir, Paint paint) {
288        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
289        recordShaderBitmap(paint);
290    }
291
292    @Override
293    public void drawTextRun(CharSequence text, int start, int end, int contextStart,
294            int contextEnd, float x, float y, int dir, Paint paint) {
295        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
296        recordShaderBitmap(paint);
297    }
298
299    @Override
300    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
301            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
302            int indexOffset, int indexCount, Paint paint) {
303        super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors,
304                colorOffset, indices, indexOffset, indexCount, paint);
305        recordShaderBitmap(paint);
306    }
307
308    @Override
309    public GLES20RecordingCanvas getNextPoolable() {
310        return mNextPoolable;
311    }
312
313    @Override
314    public void setNextPoolable(GLES20RecordingCanvas element) {
315        mNextPoolable = element;
316    }
317
318    @Override
319    public boolean isPooled() {
320        return mIsPooled;
321    }
322
323    @Override
324    public void setPooled(boolean isPooled) {
325        mIsPooled = isPooled;
326    }
327}
328