Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b44b43b1 authored by Xavier Ducrohet's avatar Xavier Ducrohet
Browse files

LayoutLib: Support Region through delegates.

also finish supporting some clip operation
on the canvas.

Change-Id: I743b9e52a7aa6e9340506f1c904cc1cfbf3ff81f
parent d43909c7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -384,7 +384,7 @@ public final class Bitmap_Delegate {
        // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
        // used during aidl call so really this should not be called.
        Bridge.getLog().error(null,
                "AIDL is not suppored, and therefore bitmap cannot be created from parcels");
                "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.");
        return null;
    }

@@ -393,7 +393,7 @@ public final class Bitmap_Delegate {
        // This is only called when sending a bitmap through aidl, so really this should not
        // be called.
        Bridge.getLog().error(null,
                "AIDL is not suppored, and therefore bitmap cannot be written to parcels");
                "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.");
        return false;
    }

+23 −6
Original line number Diff line number Diff line
@@ -271,8 +271,7 @@ public final class Canvas_Delegate {
    }

    /*package*/ static void freeCaches() {
        // FIXME
        throw new UnsupportedOperationException();
        // nothing to be done here.
    }

    /*package*/ static int initRaster(int nativeBitmapOrZero) {
@@ -440,15 +439,33 @@ public final class Canvas_Delegate {
    /*package*/ static boolean native_clipPath(int nativeCanvas,
                                                  int nativePath,
                                                  int regionOp) {
        // FIXME
        throw new UnsupportedOperationException();
        Canvas_Delegate canvasDelegate = sManager.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);
    }

    /*package*/ static boolean native_clipRegion(int nativeCanvas,
                                                    int nativeRegion,
                                                    int regionOp) {
        // FIXME
        throw new UnsupportedOperationException();
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            return true;
        }

        Region_Delegate region = Region_Delegate.getDelegate(nativeRegion);
        if (region == null) {
            return true;
        }

        return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
    }

    /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
+48 −11
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.text.TextUtils;

import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
@@ -167,6 +169,30 @@ public class Paint_Delegate {
        }
    }

    public Stroke getJavaStroke() {
        PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
        if (effectDelegate != null) {
            if (effectDelegate.isSupported()) {
                Stroke stroke = effectDelegate.getStroke(this);
                assert stroke != null;
                if (stroke != null) {
                    return stroke;
                }
            } else {
                Bridge.getLog().fidelityWarning(null,
                        effectDelegate.getSupportMessage(),
                        null);
            }
        }

        // if no custom stroke as been set, set the default one.
        return new BasicStroke(
                    getStrokeWidth(),
                    getJavaCap(),
                    getJavaJoin(),
                    getJavaStrokeMiter());
    }

    /**
     * Returns the {@link Xfermode} delegate or null if none have been set
     *
@@ -194,15 +220,6 @@ public class Paint_Delegate {
        return Shader_Delegate.getDelegate(mShader);
    }

    /**
     * Returns the {@link PathEffect} delegate or null if none have been set
     *
     * @return the delegate or null.
     */
    public PathEffect_Delegate getPathEffect() {
        return PathEffect_Delegate.getDelegate(mPathEffect);
    }

    /**
     * Returns the {@link MaskFilter} delegate or null if none have been set
     *
@@ -628,8 +645,28 @@ public class Paint_Delegate {
    }

    /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
        // FIXME
        throw new UnsupportedOperationException();
        Paint_Delegate paint = sManager.getDelegate(native_object);
        if (paint == null) {
            return false;
        }

        Path_Delegate srcPath = Path_Delegate.getDelegate(src);
        if (srcPath == null) {
            return true;
        }

        Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
        if (dstPath == null) {
            return true;
        }

        Stroke stroke = paint.getJavaStroke();
        Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());

        dstPath.setJavaShape(strokeShape);

        // FIXME figure out the return value?
        return true;
    }

    /*package*/ static int native_setShader(int native_object, int shader) {
+14 −0
Original line number Diff line number Diff line
@@ -67,6 +67,20 @@ public final class Path_Delegate {
        return mPath;
    }

    public void setJavaShape(Shape shape) {
        mPath.reset();
        mPath.append(shape, false /*connect*/);
    }

    public void reset() {
        mPath.reset();
    }

    public void setPathIterator(PathIterator iterator) {
        mPath.reset();
        mPath.append(iterator, false /*connect*/);
    }

    // ---- native methods ----

    /*package*/ static int init1() {
+306 −0
Original line number Diff line number Diff line
/*
 * 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.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;

import android.os.Parcel;

import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;

/**
 * Delegate implementing the native methods of android.graphics.Region
 *
 * Through the layoutlib_create tool, the original native methods of Region 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 Region class.
 *
 * This also serve as a base class for all Region delegate classes.
 *
 * @see DelegateManager
 *
 */
public class Region_Delegate {

    // ---- delegate manager ----
    protected static final DelegateManager<Region_Delegate> sManager =
            new DelegateManager<Region_Delegate>();

    // ---- delegate helper data ----

    // ---- delegate data ----
    private Area mArea = new Area();

    // ---- Public Helper methods ----

    public static Region_Delegate getDelegate(int nativeShader) {
        return sManager.getDelegate(nativeShader);
    }

    public Area getJavaArea() {
        return mArea;
    }

    /**
     * Combines two {@link Shape} into another one (actually an {@link Area}), according
     * to the given {@link Region.Op}.
     *
     * If the Op is not one that combines two shapes, then this return null
     *
     * @param shape1 the firt shape to combine
     * @param shape2 the 2nd shape to combine
     * @param regionOp the operande for the combine
     * @return a new area or null.
     */
    public static Area combineShapes(Shape shape1, Shape shape2, int regionOp) {
        if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
            // result is always a new area.
            Area result = new Area(shape1);
            result.subtract(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
            return result;

        } else if (regionOp == Region.Op.INTERSECT.nativeInt) {
            // result is always a new area.
            Area result = new Area(shape1);
            result.intersect(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
            return result;

        } else if (regionOp == Region.Op.UNION.nativeInt) {
            // result is always a new area.
            Area result = new Area(shape1);
            result.add(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
            return result;

        } else if (regionOp == Region.Op.XOR.nativeInt) {
            // result is always a new area.
            Area result = new Area(shape1);
            result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));

        } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
            // result is always a new area.
            Area result = new Area(shape2);
            result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1));
            return result;
        }

        return null;
    }

    // ---- native methods ----

    /*package*/ static int nativeConstructor() {
        Region_Delegate newDelegate = new Region_Delegate();
        return sManager.addDelegate(newDelegate);
    }

    /*package*/ static void nativeDestructor(int native_region) {
        sManager.removeDelegate(native_region);
    }

    /*package*/ static boolean nativeSetRegion(int native_dst, int native_src) {
        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
        if (dstRegion == null) {
            return true;
        }

        Region_Delegate srcRegion = sManager.getDelegate(native_src);
        if (srcRegion == null) {
            return true;
        }

        dstRegion.mArea.reset();
        dstRegion.mArea.add(srcRegion.mArea);

        return true;
    }

    /*package*/ static boolean nativeSetRect(int native_dst,
            int left, int top, int right, int bottom) {
        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
        if (dstRegion == null) {
            return true;
        }

        dstRegion.mArea = new Area(new Rectangle2D.Float(left, top, right - left, bottom - top));
        return dstRegion.mArea.getBounds().isEmpty() == false;
    }

    /*package*/ static boolean nativeSetPath(int native_dst, int native_path, int native_clip) {
        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
        if (dstRegion == null) {
            return true;
        }

        Path_Delegate path = Path_Delegate.getDelegate(native_path);
        if (path == null) {
            return true;
        }

        dstRegion.mArea = new Area(path.getJavaShape());

        Region_Delegate clip = sManager.getDelegate(native_clip);
        if (clip != null) {
            dstRegion.mArea.subtract(clip.getJavaArea());
        }

        return dstRegion.mArea.getBounds().isEmpty() == false;
    }

    /*package*/ static boolean nativeGetBounds(int native_region, Rect rect) {
        Region_Delegate region = sManager.getDelegate(native_region);
        if (region == null) {
            return true;
        }

        Rectangle bounds = region.mArea.getBounds();
        if (bounds.isEmpty()) {
            rect.left = rect.top = rect.right = rect.bottom = 0;
            return false;
        }

        rect.left = bounds.x;
        rect.top = bounds.y;
        rect.right = bounds.x + bounds.width;
        rect.bottom = bounds.y + bounds.height;
        return true;
    }

    /*package*/ static boolean nativeGetBoundaryPath(int native_region, int native_path) {
        Region_Delegate region = sManager.getDelegate(native_region);
        if (region == null) {
            return false;
        }

        Path_Delegate path = Path_Delegate.getDelegate(native_path);
        if (path == null) {
            return false;
        }

        if (region.mArea.isEmpty()) {
            path.reset();
            return false;
        }

        path.setPathIterator(region.mArea.getPathIterator(new AffineTransform()));
        return true;
    }

    /*package*/ static boolean nativeOp(int native_dst,
            int left, int top, int right, int bottom, int op) {
        Region_Delegate region = sManager.getDelegate(native_dst);
        if (region == null) {
            return false;
        }

        region.mArea = combineShapes(region.mArea,
                new Rectangle2D.Float(left, top, right - left, bottom - top), op);

        assert region.mArea != null;
        if (region.mArea != null) {
            region.mArea = new Area();
        }

        return region.mArea.getBounds().isEmpty() == false;
    }

    /*package*/ static boolean nativeOp(int native_dst, Rect rect, int native_region, int op) {
        Region_Delegate region = sManager.getDelegate(native_dst);
        if (region == null) {
            return false;
        }

        region.mArea = combineShapes(region.mArea,
                new Rectangle2D.Float(rect.left, rect.top, rect.width(), rect.height()), op);

        assert region.mArea != null;
        if (region.mArea != null) {
            region.mArea = new Area();
        }

        return region.mArea.getBounds().isEmpty() == false;
    }

    /*package*/ static boolean nativeOp(int native_dst,
            int native_region1, int native_region2, int op) {
        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
        if (dstRegion == null) {
            return true;
        }

        Region_Delegate region1 = sManager.getDelegate(native_region1);
        if (region1 == null) {
            return false;
        }

        Region_Delegate region2 = sManager.getDelegate(native_region2);
        if (region2 == null) {
            return false;
        }

        dstRegion.mArea = combineShapes(region1.mArea, region2.mArea, op);

        assert dstRegion.mArea != null;
        if (dstRegion.mArea != null) {
            dstRegion.mArea = new Area();
        }

        return dstRegion.mArea.getBounds().isEmpty() == false;

    }

    /*package*/ static int nativeCreateFromParcel(Parcel p) {
        // This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only
        // used during aidl call so really this should not be called.
        Bridge.getLog().error(null,
                "AIDL is not suppored, and therefore Regions cannot be created from parcels.");
        return 0;
    }

    /*package*/ static boolean nativeWriteToParcel(int native_region,
                                                      Parcel p) {
        // This is only called when sending a region through aidl, so really this should not
        // be called.
        Bridge.getLog().error(null,
                "AIDL is not suppored, and therefore Regions cannot be written to parcels.");
        return false;
    }

    /*package*/ static boolean nativeEquals(int native_r1, int native_r2) {
        Region_Delegate region1 = sManager.getDelegate(native_r1);
        if (region1 == null) {
            return false;
        }

        Region_Delegate region2 = sManager.getDelegate(native_r2);
        if (region2 == null) {
            return false;
        }

        return region1.mArea.equals(region2.mArea);
    }

    // ---- Private delegate/helper methods ----

}
Loading