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.graphics.Bitmap; 21 import android.graphics.Canvas; 22 import android.graphics.CanvasProperty; 23 import android.graphics.NinePatch; 24 import android.graphics.Paint; 25 import android.graphics.Path; 26 import android.graphics.Picture; 27 import android.graphics.Rect; 28 import android.graphics.RectF; 29 import android.util.Pools.SynchronizedPool; 30 31 /** 32 * An implementation of a GL canvas that records drawing operations. 33 * This is intended for use with a DisplayList. This class keeps a list of all the Paint and 34 * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while 35 * the DisplayList is still holding a native reference to the memory. 36 * 37 * @hide 38 */ 39 public class DisplayListCanvas extends Canvas { 40 // The recording canvas pool should be large enough to handle a deeply nested 41 // view hierarchy because display lists are generated recursively. 42 private static final int POOL_LIMIT = 25; 43 44 private static final SynchronizedPool<DisplayListCanvas> sPool = 45 new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT); 46 47 RenderNode mNode; 48 private int mWidth; 49 private int mHeight; 50 obtain(@onNull RenderNode node)51 static DisplayListCanvas obtain(@NonNull RenderNode node) { 52 if (node == null) throw new IllegalArgumentException("node cannot be null"); 53 DisplayListCanvas canvas = sPool.acquire(); 54 if (canvas == null) { 55 canvas = new DisplayListCanvas(); 56 } 57 canvas.mNode = node; 58 return canvas; 59 } 60 recycle()61 void recycle() { 62 mNode = null; 63 sPool.release(this); 64 } 65 finishRecording()66 long finishRecording() { 67 return nFinishRecording(mNativeCanvasWrapper); 68 } 69 70 @Override isRecordingFor(Object o)71 public boolean isRecordingFor(Object o) { 72 return o == mNode; 73 } 74 75 /////////////////////////////////////////////////////////////////////////// 76 // JNI 77 /////////////////////////////////////////////////////////////////////////// 78 nIsAvailable()79 private static native boolean nIsAvailable(); 80 private static boolean sIsAvailable = nIsAvailable(); 81 isAvailable()82 static boolean isAvailable() { 83 return sIsAvailable; 84 } 85 86 /////////////////////////////////////////////////////////////////////////// 87 // Constructors 88 /////////////////////////////////////////////////////////////////////////// 89 DisplayListCanvas()90 private DisplayListCanvas() { 91 super(nCreateDisplayListCanvas()); 92 mDensity = 0; // disable bitmap density scaling 93 } 94 nCreateDisplayListCanvas()95 private static native long nCreateDisplayListCanvas(); 96 97 /////////////////////////////////////////////////////////////////////////// 98 // Canvas management 99 /////////////////////////////////////////////////////////////////////////// 100 101 102 @Override setDensity(int density)103 public void setDensity(int density) { 104 // drop silently, since DisplayListCanvas 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 nGetMaximumTextureWidth()142 private static native int nGetMaximumTextureWidth(); nGetMaximumTextureHeight()143 private static native int nGetMaximumTextureHeight(); 144 145 /** 146 * Returns the native OpenGLRenderer object. 147 */ getRenderer()148 long getRenderer() { 149 return mNativeCanvasWrapper; 150 } 151 152 /////////////////////////////////////////////////////////////////////////// 153 // Setup 154 /////////////////////////////////////////////////////////////////////////// 155 156 @Override setViewport(int width, int height)157 public void setViewport(int width, int height) { 158 mWidth = width; 159 mHeight = height; 160 161 nSetViewport(mNativeCanvasWrapper, width, height); 162 } 163 nSetViewport(long renderer, int width, int height)164 private static native void nSetViewport(long renderer, 165 int width, int height); 166 167 @Override setHighContrastText(boolean highContrastText)168 public void setHighContrastText(boolean highContrastText) { 169 nSetHighContrastText(mNativeCanvasWrapper, highContrastText); 170 } 171 nSetHighContrastText(long renderer, boolean highContrastText)172 private static native void nSetHighContrastText(long renderer, boolean highContrastText); 173 174 @Override insertReorderBarrier()175 public void insertReorderBarrier() { 176 nInsertReorderBarrier(mNativeCanvasWrapper, true); 177 } 178 179 @Override insertInorderBarrier()180 public void insertInorderBarrier() { 181 nInsertReorderBarrier(mNativeCanvasWrapper, false); 182 } 183 nInsertReorderBarrier(long renderer, boolean enableReorder)184 private static native void nInsertReorderBarrier(long renderer, boolean enableReorder); 185 186 /** 187 * Invoked before any drawing operation is performed in this canvas. 188 * 189 * @param dirty The dirty rectangle to update, can be null. 190 */ onPreDraw(Rect dirty)191 public void onPreDraw(Rect dirty) { 192 if (dirty != null) { 193 nPrepareDirty(mNativeCanvasWrapper, dirty.left, dirty.top, dirty.right, dirty.bottom); 194 } else { 195 nPrepare(mNativeCanvasWrapper); 196 } 197 } 198 nPrepare(long renderer)199 private static native void nPrepare(long renderer); nPrepareDirty(long renderer, int left, int top, int right, int bottom)200 private static native void nPrepareDirty(long renderer, int left, int top, int right, int bottom); 201 202 /** 203 * Invoked after all drawing operation have been performed. 204 */ onPostDraw()205 public void onPostDraw() { 206 nFinish(mNativeCanvasWrapper); 207 } 208 nFinish(long renderer)209 private static native void nFinish(long renderer); 210 211 /////////////////////////////////////////////////////////////////////////// 212 // Functor 213 /////////////////////////////////////////////////////////////////////////// 214 215 /** 216 * Calls the function specified with the drawGLFunction function pointer. This is 217 * functionality used by webkit for calling into their renderer from our display lists. 218 * This function may return true if an invalidation is needed after the call. 219 * 220 * @param drawGLFunction A native function pointer 221 */ callDrawGLFunction2(long drawGLFunction)222 public void callDrawGLFunction2(long drawGLFunction) { 223 nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction); 224 } 225 nCallDrawGLFunction(long renderer, long drawGLFunction)226 private static native void nCallDrawGLFunction(long renderer, long drawGLFunction); 227 228 /////////////////////////////////////////////////////////////////////////// 229 // Display list 230 /////////////////////////////////////////////////////////////////////////// 231 nFinishRecording(long renderer)232 protected static native long nFinishRecording(long renderer); 233 234 /** 235 * Draws the specified display list onto this canvas. The display list can only 236 * be drawn if {@link android.view.RenderNode#isValid()} returns true. 237 * 238 * @param renderNode The RenderNode to draw. 239 */ drawRenderNode(RenderNode renderNode)240 public void drawRenderNode(RenderNode renderNode) { 241 nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList()); 242 } 243 nDrawRenderNode(long renderer, long renderNode)244 private static native void nDrawRenderNode(long renderer, long renderNode); 245 246 /////////////////////////////////////////////////////////////////////////// 247 // Hardware layer 248 /////////////////////////////////////////////////////////////////////////// 249 250 /** 251 * Draws the specified layer onto this canvas. 252 * 253 * @param layer The layer to composite on this canvas 254 * @param x The left coordinate of the layer 255 * @param y The top coordinate of the layer 256 * @param paint The paint used to draw the layer 257 */ drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint)258 void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { 259 layer.setLayerPaint(paint); 260 nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle(), x, y); 261 } 262 nDrawLayer(long renderer, long layer, float x, float y)263 private static native void nDrawLayer(long renderer, long layer, float x, float y); 264 265 /////////////////////////////////////////////////////////////////////////// 266 // Drawing 267 /////////////////////////////////////////////////////////////////////////// 268 269 // TODO: move to Canvas.java 270 @Override drawPatch(NinePatch patch, Rect dst, Paint paint)271 public void drawPatch(NinePatch patch, Rect dst, Paint paint) { 272 Bitmap bitmap = patch.getBitmap(); 273 throwIfCannotDraw(bitmap); 274 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 275 nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk, 276 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 277 } 278 279 // TODO: move to Canvas.java 280 @Override drawPatch(NinePatch patch, RectF dst, Paint paint)281 public void drawPatch(NinePatch patch, RectF dst, Paint paint) { 282 Bitmap bitmap = patch.getBitmap(); 283 throwIfCannotDraw(bitmap); 284 final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); 285 nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk, 286 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 287 } 288 nDrawPatch(long renderer, Bitmap bitmap, long chunk, float left, float top, float right, float bottom, long paint)289 private static native void nDrawPatch(long renderer, Bitmap bitmap, long chunk, 290 float left, float top, float right, float bottom, long paint); 291 drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint)292 public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, 293 CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { 294 nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), 295 radius.getNativeContainer(), paint.getNativeContainer()); 296 } 297 nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint)298 private static native void nDrawCircle(long renderer, long propCx, 299 long propCy, long propRadius, long propPaint); 300 drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, CanvasProperty<Float> ry, CanvasProperty<Paint> paint)301 public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, 302 CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, 303 CanvasProperty<Float> ry, CanvasProperty<Paint> paint) { 304 nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(), 305 right.getNativeContainer(), bottom.getNativeContainer(), 306 rx.getNativeContainer(), ry.getNativeContainer(), 307 paint.getNativeContainer()); 308 } 309 nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint)310 private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, 311 long propRight, long propBottom, long propRx, long propRy, long propPaint); 312 313 // TODO: move this optimization to Canvas.java 314 @Override drawPath(Path path, Paint paint)315 public void drawPath(Path path, Paint paint) { 316 if (path.isSimplePath) { 317 if (path.rects != null) { 318 nDrawRects(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance()); 319 } 320 } else { 321 super.drawPath(path, paint); 322 } 323 } 324 nDrawRects(long renderer, long region, long paint)325 private static native void nDrawRects(long renderer, long region, long paint); 326 } 327