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