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.view; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.graphics.Bitmap; 22 import android.graphics.CanvasProperty; 23 import android.graphics.Paint; 24 import android.util.Pools.SynchronizedPool; 25 26 import dalvik.annotation.optimization.CriticalNative; 27 import dalvik.annotation.optimization.FastNative; 28 29 /** 30 * A Canvas implementation that records view system drawing operations for deferred rendering. 31 * This is intended for use with a DisplayList. This class keeps a list of all the Paint and 32 * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while 33 * the DisplayList is still holding a native reference to the memory. 34 * 35 * @hide 36 */ 37 public final class DisplayListCanvas extends RecordingCanvas { 38 // The recording canvas pool should be large enough to handle a deeply nested 39 // view hierarchy because display lists are generated recursively. 40 private static final int POOL_LIMIT = 25; 41 42 private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB 43 44 private static final SynchronizedPool<DisplayListCanvas> sPool = 45 new SynchronizedPool<>(POOL_LIMIT); 46 47 RenderNode mNode; 48 private int mWidth; 49 private int mHeight; 50 obtain(@onNull RenderNode node, int width, int height)51 static DisplayListCanvas obtain(@NonNull RenderNode node, int width, int height) { 52 if (node == null) throw new IllegalArgumentException("node cannot be null"); 53 DisplayListCanvas canvas = sPool.acquire(); 54 if (canvas == null) { 55 canvas = new DisplayListCanvas(node, width, height); 56 } else { 57 nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode, 58 width, height); 59 } 60 canvas.mNode = node; 61 canvas.mWidth = width; 62 canvas.mHeight = height; 63 return canvas; 64 } 65 recycle()66 void recycle() { 67 mNode = null; 68 sPool.release(this); 69 } 70 finishRecording()71 long finishRecording() { 72 return nFinishRecording(mNativeCanvasWrapper); 73 } 74 75 @Override isRecordingFor(Object o)76 public boolean isRecordingFor(Object o) { 77 return o == mNode; 78 } 79 80 /////////////////////////////////////////////////////////////////////////// 81 // Constructors 82 /////////////////////////////////////////////////////////////////////////// 83 DisplayListCanvas(@onNull RenderNode node, int width, int height)84 private DisplayListCanvas(@NonNull RenderNode node, int width, int height) { 85 super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height)); 86 mDensity = 0; // disable bitmap density scaling 87 } 88 89 /////////////////////////////////////////////////////////////////////////// 90 // Canvas management 91 /////////////////////////////////////////////////////////////////////////// 92 93 94 @Override setDensity(int density)95 public void setDensity(int density) { 96 // drop silently, since DisplayListCanvas doesn't perform density scaling 97 } 98 99 @Override isHardwareAccelerated()100 public boolean isHardwareAccelerated() { 101 return true; 102 } 103 104 @Override setBitmap(Bitmap bitmap)105 public void setBitmap(Bitmap bitmap) { 106 throw new UnsupportedOperationException(); 107 } 108 109 @Override isOpaque()110 public boolean isOpaque() { 111 return false; 112 } 113 114 @Override getWidth()115 public int getWidth() { 116 return mWidth; 117 } 118 119 @Override getHeight()120 public int getHeight() { 121 return mHeight; 122 } 123 124 @Override getMaximumBitmapWidth()125 public int getMaximumBitmapWidth() { 126 return nGetMaximumTextureWidth(); 127 } 128 129 @Override getMaximumBitmapHeight()130 public int getMaximumBitmapHeight() { 131 return nGetMaximumTextureHeight(); 132 } 133 134 /////////////////////////////////////////////////////////////////////////// 135 // Setup 136 /////////////////////////////////////////////////////////////////////////// 137 138 @Override insertReorderBarrier()139 public void insertReorderBarrier() { 140 nInsertReorderBarrier(mNativeCanvasWrapper, true); 141 } 142 143 @Override insertInorderBarrier()144 public void insertInorderBarrier() { 145 nInsertReorderBarrier(mNativeCanvasWrapper, false); 146 } 147 148 /////////////////////////////////////////////////////////////////////////// 149 // Functor 150 /////////////////////////////////////////////////////////////////////////// 151 152 /** 153 * Records the functor specified with the drawGLFunction function pointer. This is 154 * functionality used by webview for calling into their renderer from our display lists. 155 * 156 * @param drawGLFunction A native function pointer 157 */ callDrawGLFunction2(long drawGLFunction)158 public void callDrawGLFunction2(long drawGLFunction) { 159 nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null); 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 * @param releasedCallback Called when the display list is destroyed, and thus 168 * the functor is no longer referenced by this canvas's display list. 169 * 170 * NOTE: The callback does *not* necessarily mean that there are no longer 171 * any references to the functor, just that the reference from this specific 172 * canvas's display list has been released. 173 */ drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback)174 public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) { 175 nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); 176 } 177 178 /////////////////////////////////////////////////////////////////////////// 179 // Display list 180 /////////////////////////////////////////////////////////////////////////// 181 182 /** 183 * Draws the specified display list onto this canvas. The display list can only 184 * be drawn if {@link android.view.RenderNode#isValid()} returns true. 185 * 186 * @param renderNode The RenderNode to draw. 187 */ drawRenderNode(RenderNode renderNode)188 public void drawRenderNode(RenderNode renderNode) { 189 nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList()); 190 } 191 192 /////////////////////////////////////////////////////////////////////////// 193 // Hardware layer 194 /////////////////////////////////////////////////////////////////////////// 195 196 /** 197 * Draws the specified layer onto this canvas. 198 * 199 * @param layer The layer to composite on this canvas 200 */ drawTextureLayer(TextureLayer layer)201 void drawTextureLayer(TextureLayer layer) { 202 nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle()); 203 } 204 205 /////////////////////////////////////////////////////////////////////////// 206 // Drawing 207 /////////////////////////////////////////////////////////////////////////// 208 drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint)209 public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, 210 CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { 211 nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), 212 radius.getNativeContainer(), paint.getNativeContainer()); 213 } 214 drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, CanvasProperty<Float> ry, CanvasProperty<Paint> paint)215 public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, 216 CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, 217 CanvasProperty<Float> ry, CanvasProperty<Paint> paint) { 218 nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(), 219 right.getNativeContainer(), bottom.getNativeContainer(), 220 rx.getNativeContainer(), ry.getNativeContainer(), 221 paint.getNativeContainer()); 222 } 223 224 @Override throwIfCannotDraw(Bitmap bitmap)225 protected void throwIfCannotDraw(Bitmap bitmap) { 226 super.throwIfCannotDraw(bitmap); 227 int bitmapSize = bitmap.getByteCount(); 228 if (bitmapSize > MAX_BITMAP_SIZE) { 229 throw new RuntimeException( 230 "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap."); 231 } 232 } 233 234 235 // ------------------ Fast JNI ------------------------ 236 237 @FastNative nCallDrawGLFunction(long renderer, long drawGLFunction, Runnable releasedCallback)238 private static native void nCallDrawGLFunction(long renderer, 239 long drawGLFunction, Runnable releasedCallback); 240 241 242 // ------------------ Critical JNI ------------------------ 243 244 @CriticalNative nCreateDisplayListCanvas(long node, int width, int height)245 private static native long nCreateDisplayListCanvas(long node, int width, int height); 246 @CriticalNative nResetDisplayListCanvas(long canvas, long node, int width, int height)247 private static native void nResetDisplayListCanvas(long canvas, long node, 248 int width, int height); 249 @CriticalNative nGetMaximumTextureWidth()250 private static native int nGetMaximumTextureWidth(); 251 @CriticalNative nGetMaximumTextureHeight()252 private static native int nGetMaximumTextureHeight(); 253 @CriticalNative nInsertReorderBarrier(long renderer, boolean enableReorder)254 private static native void nInsertReorderBarrier(long renderer, boolean enableReorder); 255 @CriticalNative nFinishRecording(long renderer)256 private static native long nFinishRecording(long renderer); 257 @CriticalNative nDrawRenderNode(long renderer, long renderNode)258 private static native void nDrawRenderNode(long renderer, long renderNode); 259 @CriticalNative nDrawTextureLayer(long renderer, long layer)260 private static native void nDrawTextureLayer(long renderer, long layer); 261 @CriticalNative nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint)262 private static native void nDrawCircle(long renderer, long propCx, 263 long propCy, long propRadius, long propPaint); 264 @CriticalNative nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint)265 private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, 266 long propRight, long propBottom, long propRx, long propRy, long propPaint); 267 } 268