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