blob: afcb40ca19007de7cdf7a7862ad9b7de24e7f855 [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 com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.GcSnapshot;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.annotation.Nullable;
import android.graphics.Bitmap.Config;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import libcore.util.NativeAllocationRegistry_Delegate;
/**
* Delegate implementing the native methods of android.graphics.Canvas
*
* Through the layoutlib_create tool, the original native methods of Canvas have been replaced
* by calls to methods of the same name in this delegate class.
*
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between
* it and the original Canvas class.
*
* @see DelegateManager
*
*/
public final class Canvas_Delegate extends BaseCanvas_Delegate {
// ---- delegate manager ----
private static long sFinalizer = -1;
private DrawFilter_Delegate mDrawFilter = null;
// ---- Public Helper methods ----
/**
* Returns the native delegate associated to a given {@link Canvas} object.
*/
public static Canvas_Delegate getDelegate(Canvas canvas) {
return (Canvas_Delegate) sManager.getDelegate(canvas.getNativeCanvasWrapper());
}
/**
* Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
*/
public static Canvas_Delegate getDelegate(long native_canvas) {
return (Canvas_Delegate) sManager.getDelegate(native_canvas);
}
/**
* Returns the current {@link Graphics2D} used to draw.
*/
public GcSnapshot getSnapshot() {
return mSnapshot;
}
/**
* Returns the {@link DrawFilter} delegate or null if none have been set.
*
* @return the delegate or null.
*/
public DrawFilter_Delegate getDrawFilter() {
return mDrawFilter;
}
// ---- native methods ----
@LayoutlibDelegate
/*package*/ static void nFreeCaches() {
// nothing to be done here.
}
@LayoutlibDelegate
/*package*/ static void nFreeTextLayoutCaches() {
// nothing to be done here yet.
}
@LayoutlibDelegate
/*package*/ static long nInitRaster(long bitmapHandle) {
if (bitmapHandle > 0) {
// get the Bitmap from the int
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
// create a new Canvas_Delegate with the given bitmap and return its new native int.
Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
return sManager.addNewDelegate(newDelegate);
}
// create a new Canvas_Delegate and return its new native int.
Canvas_Delegate newDelegate = new Canvas_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
public static void nSetBitmap(long canvas, long bitmapHandle) {
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
if (canvasDelegate == null || bitmapDelegate == null) {
return;
}
canvasDelegate.mBitmap = bitmapDelegate;
canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate);
}
@LayoutlibDelegate
public static boolean nIsOpaque(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return false;
}
return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
}
@LayoutlibDelegate
public static int nGetWidth(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
return canvasDelegate.mBitmap.getImage().getWidth();
}
@LayoutlibDelegate
public static int nGetHeight(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
return canvasDelegate.mBitmap.getImage().getHeight();
}
@LayoutlibDelegate
public static int nSave(long nativeCanvas, int saveFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
return canvasDelegate.save(saveFlags);
}
@LayoutlibDelegate
public static int nSaveLayer(long nativeCanvas, float l,
float t, float r, float b,
long paint, int layerFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
return canvasDelegate.saveLayer(new RectF(l, t, r, b),
paintDelegate, layerFlags);
}
@LayoutlibDelegate
public static int nSaveUnclippedLayer(long nativeCanvas, int l, int t, int r, int b) {
return nSaveLayer(nativeCanvas, l, t, r, b, 0, 0);
}
@LayoutlibDelegate
public static int nSaveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
}
@LayoutlibDelegate
public static void nRestoreUnclippedLayer(long nativeCanvas, int saveCount,
long nativePaint) {
nRestoreToCount(nativeCanvas, saveCount);
}
@LayoutlibDelegate
public static boolean nRestore(long nativeCanvas) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return false;
}
canvasDelegate.restore();
return true;
}
@LayoutlibDelegate
public static void nRestoreToCount(long nativeCanvas, int saveCount) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
canvasDelegate.restoreTo(saveCount);
}
@LayoutlibDelegate
public static int nGetSaveCount(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return 0;
}
return canvasDelegate.getSnapshot().size();
}
@LayoutlibDelegate
public static void nTranslate(long nativeCanvas, float dx, float dy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
canvasDelegate.getSnapshot().translate(dx, dy);
}
@LayoutlibDelegate
public static void nScale(long nativeCanvas, float sx, float sy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
canvasDelegate.getSnapshot().scale(sx, sy);
}
@LayoutlibDelegate
public static void nRotate(long nativeCanvas, float degrees) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
}
@LayoutlibDelegate
public static void nSkew(long nativeCanvas, float kx, float ky) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
// get the current top graphics2D object.
GcSnapshot g = canvasDelegate.getSnapshot();
// get its current matrix
AffineTransform currentTx = g.getTransform();
// get the AffineTransform for the given skew.
float[] mtx = Matrix_Delegate.getSkew(kx, ky);
AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
// combine them so that the given matrix is applied after.
currentTx.preConcatenate(matrixTx);
// give it to the graphics2D as a new matrix replacing all previous transform
g.setTransform(currentTx);
}
@LayoutlibDelegate
public static void nConcat(long nCanvas, long nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
if (canvasDelegate == null) {
return;
}
Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
if (matrixDelegate == null) {
return;
}
// get the current top graphics2D object.
GcSnapshot snapshot = canvasDelegate.getSnapshot();
// get its current matrix
AffineTransform currentTx = snapshot.getTransform();
// get the AffineTransform of the given matrix
AffineTransform matrixTx = matrixDelegate.getAffineTransform();
// combine them so that the given matrix is applied after.
currentTx.concatenate(matrixTx);
// give it to the graphics2D as a new matrix replacing all previous transform
snapshot.setTransform(currentTx);
}
@LayoutlibDelegate
public static void nSetMatrix(long nCanvas, long nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
if (canvasDelegate == null) {
return;
}
Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
if (matrixDelegate == null) {
return;
}
// get the current top graphics2D object.
GcSnapshot snapshot = canvasDelegate.getSnapshot();
// get the AffineTransform of the given matrix
AffineTransform matrixTx = matrixDelegate.getAffineTransform();
// give it to the graphics2D as a new matrix replacing all previous transform
snapshot.setTransform(matrixTx);
if (matrixDelegate.hasPerspective()) {
assert false;
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
"android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
"supports affine transformations.", null, null, null /*data*/);
}
}
@LayoutlibDelegate
public static boolean nClipRect(long nCanvas,
float left, float top,
float right, float bottom,
int regionOp) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
if (canvasDelegate == null) {
return false;
}
return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
}
@LayoutlibDelegate
public static boolean nClipPath(long nativeCanvas,
long nativePath,
int regionOp) {
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return true;
}
Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
if (pathDelegate == null) {
return true;
}
return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
}
@LayoutlibDelegate
public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) {
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
canvasDelegate.mDrawFilter.getSupportMessage(), null, null, null /*data*/);
}
}
@LayoutlibDelegate
public static boolean nGetClipBounds(long nativeCanvas,
Rect bounds) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return false;
}
Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
if (rect != null && !rect.isEmpty()) {
bounds.left = rect.x;
bounds.top = rect.y;
bounds.right = rect.x + rect.width;
bounds.bottom = rect.y + rect.height;
return true;
}
return false;
}
@LayoutlibDelegate
public static void nGetMatrix(long canvas, long matrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
if (canvasDelegate == null) {
return;
}
Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
if (matrixDelegate == null) {
return;
}
AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
matrixDelegate.set(Matrix_Delegate.makeValues(transform));
}
@LayoutlibDelegate
public static boolean nQuickReject(long nativeCanvas, long path) {
// FIXME properly implement quickReject
return false;
}
@LayoutlibDelegate
public static boolean nQuickReject(long nativeCanvas,
float left, float top,
float right, float bottom) {
// FIXME properly implement quickReject
return false;
}
@LayoutlibDelegate
/*package*/ static long nGetNativeFinalizer() {
synchronized (Canvas_Delegate.class) {
if (sFinalizer == -1) {
sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> {
Canvas_Delegate delegate = Canvas_Delegate.getDelegate(nativePtr);
if (delegate != null) {
delegate.dispose();
}
sManager.removeJavaReferenceFor(nativePtr);
});
}
}
return sFinalizer;
}
@LayoutlibDelegate
/*package*/ static void nSetCompatibilityVersion(int apiLevel) {
// Unsupported by layoutlib, do nothing
}
private Canvas_Delegate(Bitmap_Delegate bitmap) {
super(bitmap);
}
private Canvas_Delegate() {
super();
}
}