/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.util.Pools.SynchronizedPool;

import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;

A Canvas implementation that records view system drawing operations for deferred rendering. This is intended for use with a DisplayList. This class keeps a list of all the Paint and Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while the DisplayList is still holding a native reference to the memory.
@hide
/** * A Canvas implementation that records view system drawing operations for deferred rendering. * This is intended for use with a DisplayList. This class keeps a list of all the Paint and * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while * the DisplayList is still holding a native reference to the memory. * * @hide */
public final class DisplayListCanvas extends RecordingCanvas { // The recording canvas pool should be large enough to handle a deeply nested // view hierarchy because display lists are generated recursively. private static final int POOL_LIMIT = 25; private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB private static final SynchronizedPool<DisplayListCanvas> sPool = new SynchronizedPool<>(POOL_LIMIT); RenderNode mNode; private int mWidth; private int mHeight; static DisplayListCanvas obtain(@NonNull RenderNode node, int width, int height) { if (node == null) throw new IllegalArgumentException("node cannot be null"); DisplayListCanvas canvas = sPool.acquire(); if (canvas == null) { canvas = new DisplayListCanvas(node, width, height); } else { nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode, width, height); } canvas.mNode = node; canvas.mWidth = width; canvas.mHeight = height; return canvas; } void recycle() { mNode = null; sPool.release(this); } long finishRecording() { return nFinishRecording(mNativeCanvasWrapper); } @Override public boolean isRecordingFor(Object o) { return o == mNode; } /////////////////////////////////////////////////////////////////////////// // Constructors /////////////////////////////////////////////////////////////////////////// private DisplayListCanvas(@NonNull RenderNode node, int width, int height) { super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height)); mDensity = 0; // disable bitmap density scaling } /////////////////////////////////////////////////////////////////////////// // Canvas management /////////////////////////////////////////////////////////////////////////// @Override public void setDensity(int density) { // drop silently, since DisplayListCanvas doesn't perform density scaling } @Override public boolean isHardwareAccelerated() { return true; } @Override public void setBitmap(Bitmap bitmap) { throw new UnsupportedOperationException(); } @Override public boolean isOpaque() { return false; } @Override public int getWidth() { return mWidth; } @Override public int getHeight() { return mHeight; } @Override public int getMaximumBitmapWidth() { return nGetMaximumTextureWidth(); } @Override public int getMaximumBitmapHeight() { return nGetMaximumTextureHeight(); } /////////////////////////////////////////////////////////////////////////// // Setup /////////////////////////////////////////////////////////////////////////// @Override public void insertReorderBarrier() { nInsertReorderBarrier(mNativeCanvasWrapper, true); } @Override public void insertInorderBarrier() { nInsertReorderBarrier(mNativeCanvasWrapper, false); } /////////////////////////////////////////////////////////////////////////// // Functor ///////////////////////////////////////////////////////////////////////////
Records the functor specified with the drawGLFunction function pointer. This is functionality used by webview for calling into their renderer from our display lists.
Params:
  • drawGLFunction – A native function pointer
/** * Records the functor specified with the drawGLFunction function pointer. This is * functionality used by webview for calling into their renderer from our display lists. * * @param drawGLFunction A native function pointer */
public void callDrawGLFunction2(long drawGLFunction) { nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null); }
Records the functor specified with the drawGLFunction function pointer. This is functionality used by webview for calling into their renderer from our display lists.
Params:
  • drawGLFunction – A native function pointer
  • releasedCallback – Called when the display list is destroyed, and thus the functor is no longer referenced by this canvas's display list. NOTE: The callback does *not* necessarily mean that there are no longer any references to the functor, just that the reference from this specific canvas's display list has been released.
/** * Records the functor specified with the drawGLFunction function pointer. This is * functionality used by webview for calling into their renderer from our display lists. * * @param drawGLFunction A native function pointer * @param releasedCallback Called when the display list is destroyed, and thus * the functor is no longer referenced by this canvas's display list. * * NOTE: The callback does *not* necessarily mean that there are no longer * any references to the functor, just that the reference from this specific * canvas's display list has been released. */
public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) { nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); } /////////////////////////////////////////////////////////////////////////// // Display list ///////////////////////////////////////////////////////////////////////////
Draws the specified display list onto this canvas. The display list can only be drawn if RenderNode.isValid() returns true.
Params:
  • renderNode – The RenderNode to draw.
/** * Draws the specified display list onto this canvas. The display list can only * be drawn if {@link android.view.RenderNode#isValid()} returns true. * * @param renderNode The RenderNode to draw. */
public void drawRenderNode(RenderNode renderNode) { nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList()); } /////////////////////////////////////////////////////////////////////////// // Hardware layer ///////////////////////////////////////////////////////////////////////////
Draws the specified layer onto this canvas.
Params:
  • layer – The layer to composite on this canvas
/** * Draws the specified layer onto this canvas. * * @param layer The layer to composite on this canvas */
void drawTextureLayer(TextureLayer layer) { nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle()); } /////////////////////////////////////////////////////////////////////////// // Drawing /////////////////////////////////////////////////////////////////////////// public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), radius.getNativeContainer(), paint.getNativeContainer()); } public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top, CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx, CanvasProperty<Float> ry, CanvasProperty<Paint> paint) { nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(), right.getNativeContainer(), bottom.getNativeContainer(), rx.getNativeContainer(), ry.getNativeContainer(), paint.getNativeContainer()); } @Override protected void throwIfCannotDraw(Bitmap bitmap) { super.throwIfCannotDraw(bitmap); int bitmapSize = bitmap.getByteCount(); if (bitmapSize > MAX_BITMAP_SIZE) { throw new RuntimeException( "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap."); } } // ------------------ Fast JNI ------------------------ @FastNative private static native void nCallDrawGLFunction(long renderer, long drawGLFunction, Runnable releasedCallback); // ------------------ Critical JNI ------------------------ @CriticalNative private static native long nCreateDisplayListCanvas(long node, int width, int height); @CriticalNative private static native void nResetDisplayListCanvas(long canvas, long node, int width, int height); @CriticalNative private static native int nGetMaximumTextureWidth(); @CriticalNative private static native int nGetMaximumTextureHeight(); @CriticalNative private static native void nInsertReorderBarrier(long renderer, boolean enableReorder); @CriticalNative private static native long nFinishRecording(long renderer); @CriticalNative private static native void nDrawRenderNode(long renderer, long renderNode); @CriticalNative private static native void nDrawTextureLayer(long renderer, long layer); @CriticalNative private static native void nDrawCircle(long renderer, long propCx, long propCy, long propRadius, long propPaint); @CriticalNative private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint); }