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.graphics; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.util.Pools.SynchronizedPool; 22 import android.view.DisplayListCanvas; 23 import android.view.TextureLayer; 24 25 import dalvik.annotation.optimization.CriticalNative; 26 import dalvik.annotation.optimization.FastNative; 27 28 /** 29 * A Canvas implementation that records view system drawing operations for deferred rendering. 30 * This is used in combination with RenderNode. This class keeps a list of all the Paint and 31 * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while 32 * the RecordingCanvas is still holding a native reference to the memory. 33 * 34 * This is obtained by calling {@link RenderNode#beginRecording()} and is valid until the matching 35 * {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is 36 * internally reused. 37 */ 38 public final class RecordingCanvas extends DisplayListCanvas { 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 /** @hide */ 44 public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB 45 46 private static final SynchronizedPool<RecordingCanvas> sPool = 47 new SynchronizedPool<>(POOL_LIMIT); 48 49 /** 50 * TODO: Temporarily exposed for RenderNodeAnimator(Set) 51 * @hide */ 52 public RenderNode mNode; 53 private int mWidth; 54 private int mHeight; 55 56 /** @hide */ obtain(@onNull RenderNode node, int width, int height)57 static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) { 58 if (node == null) throw new IllegalArgumentException("node cannot be null"); 59 RecordingCanvas canvas = sPool.acquire(); 60 if (canvas == null) { 61 canvas = new RecordingCanvas(node, width, height); 62 } else { 63 nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode, 64 width, height); 65 } 66 canvas.mNode = node; 67 canvas.mWidth = width; 68 canvas.mHeight = height; 69 return canvas; 70 } 71 72 /** @hide */ recycle()73 void recycle() { 74 mNode = null; 75 sPool.release(this); 76 } 77 78 /** @hide */ finishRecording()79 long finishRecording() { 80 return nFinishRecording(mNativeCanvasWrapper); 81 } 82 83 /** @hide */ 84 @Override isRecordingFor(Object o)85 public boolean isRecordingFor(Object o) { 86 return o == mNode; 87 } 88 89 /////////////////////////////////////////////////////////////////////////// 90 // Constructors 91 /////////////////////////////////////////////////////////////////////////// 92 93 /** @hide */ RecordingCanvas(@onNull RenderNode node, int width, int height)94 protected RecordingCanvas(@NonNull RenderNode node, int width, int height) { 95 super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height)); 96 mDensity = 0; // disable bitmap density scaling 97 } 98 99 /////////////////////////////////////////////////////////////////////////// 100 // Canvas management 101 /////////////////////////////////////////////////////////////////////////// 102 103 104 @Override setDensity(int density)105 public void setDensity(int density) { 106 // drop silently, since RecordingCanvas doesn't perform density scaling 107 } 108 109 @Override isHardwareAccelerated()110 public boolean isHardwareAccelerated() { 111 return true; 112 } 113 114 @Override setBitmap(Bitmap bitmap)115 public void setBitmap(Bitmap bitmap) { 116 throw new UnsupportedOperationException(); 117 } 118 119 @Override isOpaque()120 public boolean isOpaque() { 121 return false; 122 } 123 124 @Override getWidth()125 public int getWidth() { 126 return mWidth; 127 } 128 129 @Override getHeight()130 public int getHeight() { 131 return mHeight; 132 } 133 134 @Override getMaximumBitmapWidth()135 public int getMaximumBitmapWidth() { 136 return nGetMaximumTextureWidth(); 137 } 138 139 @Override getMaximumBitmapHeight()140 public int getMaximumBitmapHeight() { 141 return nGetMaximumTextureHeight(); 142 } 143 144 /////////////////////////////////////////////////////////////////////////// 145 // Setup 146 /////////////////////////////////////////////////////////////////////////// 147 148 @Override enableZ()149 public void enableZ() { 150 nInsertReorderBarrier(mNativeCanvasWrapper, true); 151 } 152 153 @Override disableZ()154 public void disableZ() { 155 nInsertReorderBarrier(mNativeCanvasWrapper, false); 156 } 157 158 /////////////////////////////////////////////////////////////////////////// 159 // Functor 160 /////////////////////////////////////////////////////////////////////////// 161 162 /** 163 * Records the functor specified with the drawGLFunction function pointer. This is 164 * functionality used by webview for calling into their renderer from our display lists. 165 * 166 * @param drawGLFunction A native function pointer 167 * 168 * @hide 169 * @deprecated Use {@link #drawWebViewFunctor(int)} 170 */ 171 @Deprecated callDrawGLFunction2(long drawGLFunction)172 public void callDrawGLFunction2(long drawGLFunction) { 173 nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null); 174 } 175 176 /** 177 * Records the functor specified with the drawGLFunction function pointer. This is 178 * functionality used by webview for calling into their renderer from our display lists. 179 * 180 * @param drawGLFunctor A native function pointer 181 * @param releasedCallback Called when the display list is destroyed, and thus 182 * the functor is no longer referenced by this canvas's display list. 183 * 184 * NOTE: The callback does *not* necessarily mean that there are no longer 185 * any references to the functor, just that the reference from this specific 186 * canvas's display list has been released. 187 * 188 * @hide 189 * @deprecated Use {@link #drawWebViewFunctor(int)} 190 */ 191 @Deprecated drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback)192 public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) { 193 nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); 194 } 195 196 /** 197 * Calls the provided functor that was created via WebViewFunctor_create() 198 * @hide 199 */ drawWebViewFunctor(int functor)200 public void drawWebViewFunctor(int functor) { 201 nDrawWebViewFunctor(mNativeCanvasWrapper, functor); 202 } 203 204 /////////////////////////////////////////////////////////////////////////// 205 // Display list 206 /////////////////////////////////////////////////////////////////////////// 207 208 /** 209 * Draws the specified display list onto this canvas. 210 * 211 * @param renderNode The RenderNode to draw. 212 */ 213 @Override drawRenderNode(@onNull RenderNode renderNode)214 public void drawRenderNode(@NonNull RenderNode renderNode) { 215 nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode); 216 } 217 218 /////////////////////////////////////////////////////////////////////////// 219 // Hardware layer 220 /////////////////////////////////////////////////////////////////////////// 221 222 /** 223 * Draws the specified layer onto this canvas. 224 * 225 * @param layer The layer to composite on this canvas 226 * @hide 227 */ drawTextureLayer(TextureLayer layer)228 public void drawTextureLayer(TextureLayer layer) { 229 nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle()); 230 } 231 232 /////////////////////////////////////////////////////////////////////////// 233 // Drawing 234 /////////////////////////////////////////////////////////////////////////// 235 236 /** 237 * Draws a circle 238 * 239 * @param cx 240 * @param cy 241 * @param radius 242 * @param paint 243 * 244 * @hide 245 */ drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint)246 public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, 247 CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { 248 nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), 249 radius.getNativeContainer(), paint.getNativeContainer()); 250 } 251 252 /** 253 * Draws a round rect 254 * 255 * @param left 256 * @param top 257 * @param right 258 * @param bottom 259 * @param rx 260 * @param ry 261 * @param paint 262 * 263 * @hide 264 */ drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, CanvasProperty<Float> ry, CanvasProperty<Paint> paint)265 public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, 266 CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, 267 CanvasProperty<Float> ry, CanvasProperty<Paint> paint) { 268 nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(), 269 right.getNativeContainer(), bottom.getNativeContainer(), 270 rx.getNativeContainer(), ry.getNativeContainer(), 271 paint.getNativeContainer()); 272 } 273 274 /** @hide */ 275 @Override throwIfCannotDraw(Bitmap bitmap)276 protected void throwIfCannotDraw(Bitmap bitmap) { 277 super.throwIfCannotDraw(bitmap); 278 int bitmapSize = bitmap.getByteCount(); 279 if (bitmapSize > MAX_BITMAP_SIZE) { 280 throw new RuntimeException( 281 "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap."); 282 } 283 } 284 285 286 // ------------------ Fast JNI ------------------------ 287 288 @FastNative nCallDrawGLFunction(long renderer, long drawGLFunction, Runnable releasedCallback)289 private static native void nCallDrawGLFunction(long renderer, 290 long drawGLFunction, Runnable releasedCallback); 291 292 293 // ------------------ Critical JNI ------------------------ 294 295 @CriticalNative nCreateDisplayListCanvas(long node, int width, int height)296 private static native long nCreateDisplayListCanvas(long node, int width, int height); 297 @CriticalNative nResetDisplayListCanvas(long canvas, long node, int width, int height)298 private static native void nResetDisplayListCanvas(long canvas, long node, 299 int width, int height); 300 @CriticalNative nGetMaximumTextureWidth()301 private static native int nGetMaximumTextureWidth(); 302 @CriticalNative nGetMaximumTextureHeight()303 private static native int nGetMaximumTextureHeight(); 304 @CriticalNative nInsertReorderBarrier(long renderer, boolean enableReorder)305 private static native void nInsertReorderBarrier(long renderer, boolean enableReorder); 306 @CriticalNative nFinishRecording(long renderer)307 private static native long nFinishRecording(long renderer); 308 @CriticalNative nDrawRenderNode(long renderer, long renderNode)309 private static native void nDrawRenderNode(long renderer, long renderNode); 310 @CriticalNative nDrawTextureLayer(long renderer, long layer)311 private static native void nDrawTextureLayer(long renderer, long layer); 312 @CriticalNative nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint)313 private static native void nDrawCircle(long renderer, long propCx, 314 long propCy, long propRadius, long propPaint); 315 @CriticalNative nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint)316 private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, 317 long propRight, long propBottom, long propRx, long propRy, long propPaint); 318 @CriticalNative nDrawWebViewFunctor(long canvas, int functor)319 private static native void nDrawWebViewFunctor(long canvas, int functor); 320 } 321