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 17package android.view; 18 19import android.annotation.NonNull; 20import android.graphics.Bitmap; 21import android.graphics.Canvas; 22import android.graphics.CanvasProperty; 23import android.graphics.NinePatch; 24import android.graphics.Paint; 25import android.graphics.Path; 26import android.graphics.Picture; 27import android.graphics.Rect; 28import android.graphics.RectF; 29import 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 */ 39public 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 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 61 void recycle() { 62 mNode = null; 63 sPool.release(this); 64 } 65 66 long finishRecording() { 67 return nFinishRecording(mNativeCanvasWrapper); 68 } 69 70 @Override 71 public boolean isRecordingFor(Object o) { 72 return o == mNode; 73 } 74 75 /////////////////////////////////////////////////////////////////////////// 76 // JNI 77 /////////////////////////////////////////////////////////////////////////// 78 79 private static native boolean nIsAvailable(); 80 private static boolean sIsAvailable = nIsAvailable(); 81 82 static boolean isAvailable() { 83 return sIsAvailable; 84 } 85 86 /////////////////////////////////////////////////////////////////////////// 87 // Constructors 88 /////////////////////////////////////////////////////////////////////////// 89 90 private DisplayListCanvas() { 91 super(nCreateDisplayListCanvas()); 92 mDensity = 0; // disable bitmap density scaling 93 } 94 95 private static native long nCreateDisplayListCanvas(); 96 97 /////////////////////////////////////////////////////////////////////////// 98 // Canvas management 99 /////////////////////////////////////////////////////////////////////////// 100 101 102 @Override 103 public void setDensity(int density) { 104 // drop silently, since DisplayListCanvas doesn't perform density scaling 105 } 106 107 @Override 108 public boolean isHardwareAccelerated() { 109 return true; 110 } 111 112 @Override 113 public void setBitmap(Bitmap bitmap) { 114 throw new UnsupportedOperationException(); 115 } 116 117 @Override 118 public boolean isOpaque() { 119 return false; 120 } 121 122 @Override 123 public int getWidth() { 124 return mWidth; 125 } 126 127 @Override 128 public int getHeight() { 129 return mHeight; 130 } 131 132 @Override 133 public int getMaximumBitmapWidth() { 134 return nGetMaximumTextureWidth(); 135 } 136 137 @Override 138 public int getMaximumBitmapHeight() { 139 return nGetMaximumTextureHeight(); 140 } 141 142 private static native int nGetMaximumTextureWidth(); 143 private static native int nGetMaximumTextureHeight(); 144 145 /** 146 * Returns the native OpenGLRenderer object. 147 */ 148 long getRenderer() { 149 return mNativeCanvasWrapper; 150 } 151 152 /////////////////////////////////////////////////////////////////////////// 153 // Setup 154 /////////////////////////////////////////////////////////////////////////// 155 156 @Override 157 public void setViewport(int width, int height) { 158 mWidth = width; 159 mHeight = height; 160 161 nSetViewport(mNativeCanvasWrapper, width, height); 162 } 163 164 private static native void nSetViewport(long renderer, 165 int width, int height); 166 167 @Override 168 public void setHighContrastText(boolean highContrastText) { 169 nSetHighContrastText(mNativeCanvasWrapper, highContrastText); 170 } 171 172 private static native void nSetHighContrastText(long renderer, boolean highContrastText); 173 174 @Override 175 public void insertReorderBarrier() { 176 nInsertReorderBarrier(mNativeCanvasWrapper, true); 177 } 178 179 @Override 180 public void insertInorderBarrier() { 181 nInsertReorderBarrier(mNativeCanvasWrapper, false); 182 } 183 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 */ 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 199 private static native void nPrepare(long renderer); 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 */ 205 public void onPostDraw() { 206 nFinish(mNativeCanvasWrapper); 207 } 208 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 */ 222 public void callDrawGLFunction2(long drawGLFunction) { 223 nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction); 224 } 225 226 private static native void nCallDrawGLFunction(long renderer, long drawGLFunction); 227 228 /////////////////////////////////////////////////////////////////////////// 229 // Display list 230 /////////////////////////////////////////////////////////////////////////// 231 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 */ 240 public void drawRenderNode(RenderNode renderNode) { 241 nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList()); 242 } 243 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 */ 258 void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { 259 layer.setLayerPaint(paint); 260 nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle(), x, y); 261 } 262 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 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 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 289 private static native void nDrawPatch(long renderer, Bitmap bitmap, long chunk, 290 float left, float top, float right, float bottom, long paint); 291 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 298 private static native void nDrawCircle(long renderer, long propCx, 299 long propCy, long propRadius, long propPaint); 300 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 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 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 325 private static native void nDrawRects(long renderer, long region, long paint); 326} 327