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 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 66 void recycle() { 67 mNode = null; 68 sPool.release(this); 69 } 70 71 long finishRecording() { 72 return nFinishRecording(mNativeCanvasWrapper); 73 } 74 75 @Override 76 public boolean isRecordingFor(Object o) { 77 return o == mNode; 78 } 79 80 /////////////////////////////////////////////////////////////////////////// 81 // Constructors 82 /////////////////////////////////////////////////////////////////////////// 83 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 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 /////////////////////////////////////////////////////////////////////////// 135 // Setup 136 /////////////////////////////////////////////////////////////////////////// 137 138 @Override 139 public void insertReorderBarrier() { 140 nInsertReorderBarrier(mNativeCanvasWrapper, true); 141 } 142 143 @Override 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 */ 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 */ 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 */ 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 */ 201 void drawHardwareLayer(HardwareLayer layer) { 202 nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle()); 203 } 204 205 /////////////////////////////////////////////////////////////////////////// 206 // Drawing 207 /////////////////////////////////////////////////////////////////////////// 208 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 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 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 238 private static native void nCallDrawGLFunction(long renderer, 239 long drawGLFunction, Runnable releasedCallback); 240 241 242 // ------------------ Critical JNI ------------------------ 243 244 @CriticalNative 245 private static native long nCreateDisplayListCanvas(long node, int width, int height); 246 @CriticalNative 247 private static native void nResetDisplayListCanvas(long canvas, long node, 248 int width, int height); 249 @CriticalNative 250 private static native int nGetMaximumTextureWidth(); 251 @CriticalNative 252 private static native int nGetMaximumTextureHeight(); 253 @CriticalNative 254 private static native void nInsertReorderBarrier(long renderer, boolean enableReorder); 255 @CriticalNative 256 private static native long nFinishRecording(long renderer); 257 @CriticalNative 258 private static native void nDrawRenderNode(long renderer, long renderNode); 259 @CriticalNative 260 private static native void nDrawLayer(long renderer, long layer); 261 @CriticalNative 262 private static native void nDrawCircle(long renderer, long propCx, 263 long propCy, long propRadius, long propPaint); 264 @CriticalNative 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