| /* |
| * 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.ILayoutLog; |
| 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.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(ILayoutLog.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(ILayoutLog.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(); |
| } |
| } |
| |