blob: c0e0a24583ec5d845d9e5a2dd7e017cb2f76bb93 [file] [log] [blame]
/*
* 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.graphics;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Pools.SynchronizedPool;
import android.view.DisplayListCanvas;
import android.view.TextureLayer;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
/**
* A Canvas implementation that records view system drawing operations for deferred rendering.
* This is used in combination with RenderNode. This class keeps a list of all the Paint and
* Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while
* the RecordingCanvas is still holding a native reference to the memory.
*
* This is obtained by calling {@link RenderNode#beginRecording()} and is valid until the matching
* {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is
* internally reused.
*/
public final class RecordingCanvas extends DisplayListCanvas {
// 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;
/** @hide */
public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
private static final SynchronizedPool<RecordingCanvas> sPool =
new SynchronizedPool<>(POOL_LIMIT);
/**
* TODO: Temporarily exposed for RenderNodeAnimator(Set)
* @hide */
public RenderNode mNode;
private int mWidth;
private int mHeight;
/** @hide */
static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
if (node == null) throw new IllegalArgumentException("node cannot be null");
RecordingCanvas canvas = sPool.acquire();
if (canvas == null) {
canvas = new RecordingCanvas(node, width, height);
} else {
nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode,
width, height);
}
canvas.mNode = node;
canvas.mWidth = width;
canvas.mHeight = height;
return canvas;
}
/** @hide */
void recycle() {
mNode = null;
sPool.release(this);
}
/** @hide */
long finishRecording() {
return nFinishRecording(mNativeCanvasWrapper);
}
/** @hide */
@Override
public boolean isRecordingFor(Object o) {
return o == mNode;
}
///////////////////////////////////////////////////////////////////////////
// Constructors
///////////////////////////////////////////////////////////////////////////
/** @hide */
protected RecordingCanvas(@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 RecordingCanvas 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 enableZ() {
nInsertReorderBarrier(mNativeCanvasWrapper, true);
}
@Override
public void disableZ() {
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.
*
* @param drawGLFunction A native function pointer
*
* @hide
* @deprecated Use {@link #drawWebViewFunctor(int)}
*/
@Deprecated
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.
*
* @param drawGLFunctor 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.
*
* @hide
* @deprecated Use {@link #drawWebViewFunctor(int)}
*/
@Deprecated
public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) {
nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
}
/**
* Calls the provided functor that was created via WebViewFunctor_create()
* @hide
*/
public void drawWebViewFunctor(int functor) {
nDrawWebViewFunctor(mNativeCanvasWrapper, functor);
}
///////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////
/**
* Draws the specified display list onto this canvas.
*
* @param renderNode The RenderNode to draw.
*/
@Override
public void drawRenderNode(@NonNull RenderNode renderNode) {
nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode);
}
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////
/**
* Draws the specified layer onto this canvas.
*
* @param layer The layer to composite on this canvas
* @hide
*/
public void drawTextureLayer(TextureLayer layer) {
nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle());
}
///////////////////////////////////////////////////////////////////////////
// Drawing
///////////////////////////////////////////////////////////////////////////
/**
* Draws a circle
*
* @param cx
* @param cy
* @param radius
* @param paint
*
* @hide
*/
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());
}
/**
* Draws a round rect
*
* @param left
* @param top
* @param right
* @param bottom
* @param rx
* @param ry
* @param paint
*
* @hide
*/
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());
}
/** @hide */
@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);
@CriticalNative
private static native void nDrawWebViewFunctor(long canvas, int functor);
}