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

Commit 6952063e authored by Diego Perez's avatar Diego Perez Committed by android-build-merger
Browse files

New path interpolation to paint vector drawables

am: b9c48d8f

* commit 'b9c48d8f':
  New path interpolation to paint vector drawables
parents 14df39f9 b9c48d8f
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

@@ -713,8 +712,27 @@ public final class Canvas_Delegate {
                        if (bounds.isEmpty()) {
                            // Apple JRE 1.6 doesn't like drawing empty shapes.
                            // http://b.android.com/178278

                            if (pathDelegate.isEmpty()) {
                                // This means that the path doesn't have any lines or curves so
                                // nothing to draw.
                                return;
                            }

                            // The stroke width is not consider for the size of the bounds so,
                            // for example, a horizontal line, would be considered as an empty
                            // rectangle.
                            // If the strokeWidth is not 0, we use it to consider the size of the
                            // path as well.
                            float strokeWidth = paintDelegate.getStrokeWidth();
                            if (strokeWidth <= 0.0f) {
                                return;
                            }
                            bounds.setRect(bounds.getX(), bounds.getY(),
                                    Math.max(strokeWidth, bounds.getWidth()),
                                    Math.max(strokeWidth, bounds.getHeight()));
                        }

                        int style = paintDelegate.getStyle();

                        if (style == Paint.Style.FILL.nativeInt ||
+1 −5
Original line number Diff line number Diff line
@@ -152,11 +152,7 @@ public class Paint_Delegate {
     * returns the value of stroke miter needed by the java api.
     */
    public float getJavaStrokeMiter() {
        float miter = mStrokeMiter * mStrokeWidth;
        if (miter < 1.f) {
            miter = 1.f;
        }
        return miter;
        return mStrokeMiter;
    }

    public int getJavaCap() {
+76 −63
Original line number Diff line number Diff line
@@ -19,10 +19,12 @@ 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.util.CachedPathIteratorFactory;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;

import com.android.layoutlib.bridge.util.CachedPathIteratorFactory.CachedPathIterator;

import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;

/**
 * Delegate implementing the native methods of {@link android.graphics.PathMeasure}
@@ -38,35 +40,30 @@ import java.awt.geom.Point2D;
 * @see DelegateManager
 */
public final class PathMeasure_Delegate {

    // ---- delegate manager ----
    private static final DelegateManager<PathMeasure_Delegate> sManager =
            new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class);

    // ---- delegate data ----
    // This governs how accurate the approximation of the Path is.
    private static final float PRECISION = 0.0002f;
    private CachedPathIteratorFactory mOriginalPathIterator;

    /**
     * Array containing the path points components. There are three components for each point:
     * <ul>
     *     <li>Fraction along the length of the path that the point resides</li>
     *     <li>The x coordinate of the point</li>
     *     <li>The y coordinate of the point</li>
     * </ul>
     */
    private float mPathPoints[];
    private long mNativePath;


    private PathMeasure_Delegate(long native_path, boolean forceClosed) {
        mNativePath = native_path;
        if (forceClosed && mNativePath != 0) {
        if (native_path != 0) {
            if (forceClosed) {
                // Copy the path and call close
            mNativePath = Path_Delegate.init2(native_path);
            Path_Delegate.native_close(mNativePath);
                native_path = Path_Delegate.init2(native_path);
                Path_Delegate.native_close(native_path);
            }

        mPathPoints =
                mNativePath != 0 ? Path_Delegate.native_approximate(mNativePath, PRECISION) : null;
            Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
            mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
                    .getPathIterator(null));
        }
    }

    @LayoutlibDelegate
@@ -108,13 +105,19 @@ public final class PathMeasure_Delegate {
        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
        assert pathMeasure != null;

        if (forceClosed && native_path != 0) {
        if (native_path != 0) {
            if (forceClosed) {
                // Copy the path and call close
                native_path = Path_Delegate.init2(native_path);
                Path_Delegate.native_close(native_path);
            }

            Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
            pathMeasure.mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
                    .getPathIterator(null));
        }

        pathMeasure.mNativePath = native_path;
        pathMeasure.mPathPoints = Path_Delegate.native_approximate(native_path, PRECISION);
    }

    @LayoutlibDelegate
@@ -122,21 +125,11 @@ public final class PathMeasure_Delegate {
        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
        assert pathMeasure != null;

        if (pathMeasure.mPathPoints == null) {
        if (pathMeasure.mOriginalPathIterator == null) {
            return 0;
        }

        float length = 0;
        int nPoints = pathMeasure.mPathPoints.length / 3;
        for (int i = 1; i < nPoints; i++) {
            length += Point2D.distance(
                    pathMeasure.mPathPoints[(i - 1) * 3 + 1],
                    pathMeasure.mPathPoints[(i - 1) * 3 + 2],
                    pathMeasure.mPathPoints[i*3 + 1],
                    pathMeasure.mPathPoints[i*3 + 2]);
        }

        return length;
        return pathMeasure.mOriginalPathIterator.iterator().getTotalLength();
    }

    @LayoutlibDelegate
@@ -149,13 +142,10 @@ public final class PathMeasure_Delegate {
            return false;
        }

        PathIterator pathIterator = path.getJavaShape().getPathIterator(null);

        int type = 0;
        float segment[] = new float[6];
        while (!pathIterator.isDone()) {
            type = pathIterator.currentSegment(segment);
            pathIterator.next();
        for (PathIterator pi = path.getJavaShape().getPathIterator(null); !pi.isDone(); pi.next()) {
            type = pi.currentSegment(segment);
        }

        // A path is a closed path if the last element is SEG_CLOSE
@@ -176,33 +166,56 @@ public final class PathMeasure_Delegate {
        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
        assert pathMeasure != null;

        if (pathMeasure.mPathPoints == null) {
            return false;
        }

        float accLength = 0;
        CachedPathIterator iterator = pathMeasure.mOriginalPathIterator.iterator();
        float accLength = startD;
        boolean isZeroLength = true; // Whether the output has zero length or not
        int nPoints = pathMeasure.mPathPoints.length / 3;
        for (int i = 0; i < nPoints; i++) {
            float x = pathMeasure.mPathPoints[i * 3 + 1];
            float y = pathMeasure.mPathPoints[i * 3 + 2];
            if (accLength >= startD && accLength <= stopD) {
        float[] points = new float[6];

        iterator.jumpToSegment(accLength);
        while (!iterator.isDone() && (stopD - accLength > 0.1f)) {
            int type = iterator.currentSegment(points, stopD - accLength);

            if (accLength - iterator.getCurrentSegmentLength() <= stopD) {
                if (startWithMoveTo) {
                    startWithMoveTo = false;
                    Path_Delegate.native_moveTo(native_dst_path, x, y);
                } else {
                    isZeroLength = false;
                    Path_Delegate.native_lineTo(native_dst_path, x, y);
                }
            }

            if (i > 0) {
                accLength += Point2D.distance(
                        pathMeasure.mPathPoints[(i - 1) * 3 + 1],
                        pathMeasure.mPathPoints[(i - 1) * 3 + 2],
                        pathMeasure.mPathPoints[i * 3 + 1],
                        pathMeasure.mPathPoints[i * 3 + 2]);
            }
                    // If this segment is a MOVETO, then we just use that one. If not, then we issue
                    // a first moveto
                    if (type != PathIterator.SEG_MOVETO) {
                        float[] lastPoint = new float[2];
                        iterator.getCurrentSegmentEnd(lastPoint);
                        Path_Delegate.native_moveTo(native_dst_path, lastPoint[0], lastPoint[1]);
                    }
                }

                isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
                switch (type) {
                    case PathIterator.SEG_MOVETO:
                        Path_Delegate.native_moveTo(native_dst_path, points[0], points[1]);
                        break;
                    case PathIterator.SEG_LINETO:
                        Path_Delegate.native_lineTo(native_dst_path, points[0], points[1]);
                        break;
                    case PathIterator.SEG_CLOSE:
                        Path_Delegate.native_close(native_dst_path);
                        break;
                    case PathIterator.SEG_CUBICTO:
                        Path_Delegate.native_cubicTo(native_dst_path, points[0], points[1],
                                points[2], points[3],
                                points[4], points[5]);
                        break;
                    case PathIterator.SEG_QUADTO:
                        Path_Delegate.native_quadTo(native_dst_path, points[0], points[1],
                                points[2],
                                points[3]);
                        break;
                    default:
                        assert false;
                }
            }

            accLength += iterator.getCurrentSegmentLength();
            iterator.next();
        }

        return !isZeroLength;
+48 −11
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ public final class Path_Delegate {
    private static final DelegateManager<Path_Delegate> sManager =
            new DelegateManager<Path_Delegate>(Path_Delegate.class);

    private static final float EPSILON = 1e-4f;

    // ---- delegate data ----
    private FillType mFillType = FillType.WINDING;
    private Path2D mPath = new Path2D.Double();
@@ -64,6 +66,9 @@ public final class Path_Delegate {
    private float mLastX = 0;
    private float mLastY = 0;

    // true if the path contains does not contain a curve or line.
    private boolean mCachedIsEmpty = true;

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

    public static Path_Delegate getDelegate(long nPath) {
@@ -75,7 +80,7 @@ public final class Path_Delegate {
    }

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

@@ -84,7 +89,7 @@ public final class Path_Delegate {
    }

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

@@ -591,11 +596,37 @@ public final class Path_Delegate {


    /**
     * Returns whether the path is empty.
     * @return true if the path is empty.
     * Returns whether the path already contains any points.
     * Note that this is different to
     * {@link #isEmpty} because if all elements are {@link PathIterator#SEG_MOVETO},
     * {@link #isEmpty} will return true while hasPoints will return false.
     */
    public boolean hasPoints() {
        return !mPath.getPathIterator(null).isDone();
    }

    /**
     * Returns whether the path is empty (contains no lines or curves).
     * @see Path#isEmpty
     */
    private boolean isEmpty() {
        return mPath.getCurrentPoint() == null;
    public boolean isEmpty() {
        if (!mCachedIsEmpty) {
            return false;
        }

        float[] coords = new float[6];
        mCachedIsEmpty = Boolean.TRUE;
        for (PathIterator it = mPath.getPathIterator(null); !it.isDone(); it.next()) {
            int type = it.currentSegment(coords);
            if (type != PathIterator.SEG_MOVETO) {
                // Once we know that the path is not empty, we do not need to check again unless
                // Path#reset is called.
                mCachedIsEmpty = false;
                return false;
            }
        }

        return true;
    }

    /**
@@ -645,7 +676,7 @@ public final class Path_Delegate {
     * @param y The y-coordinate of the end of a line
     */
    private void lineTo(float x, float y) {
        if (isEmpty()) {
        if (!hasPoints()) {
            mPath.moveTo(mLastX = 0, mLastY = 0);
        }
        mPath.lineTo(mLastX = x, mLastY = y);
@@ -662,9 +693,15 @@ public final class Path_Delegate {
     *           this contour, to specify a line
     */
    private void rLineTo(float dx, float dy) {
        if (isEmpty()) {
        if (!hasPoints()) {
            mPath.moveTo(mLastX = 0, mLastY = 0);
        }

        if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON) {
            // The delta is so small that this shouldn't generate a line
            return;
        }

        dx += mLastX;
        dy += mLastY;
        mPath.lineTo(mLastX = dx, mLastY = dy);
@@ -699,7 +736,7 @@ public final class Path_Delegate {
     *            this contour, for the end point of a quadratic curve
     */
    private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
        if (isEmpty()) {
        if (!hasPoints()) {
            mPath.moveTo(mLastX = 0, mLastY = 0);
        }
        dx1 += mLastX;
@@ -723,7 +760,7 @@ public final class Path_Delegate {
     */
    private void cubicTo(float x1, float y1, float x2, float y2,
                        float x3, float y3) {
        if (isEmpty()) {
        if (!hasPoints()) {
            mPath.moveTo(0, 0);
        }
        mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
@@ -736,7 +773,7 @@ public final class Path_Delegate {
     */
    private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
                         float dx3, float dy3) {
        if (isEmpty()) {
        if (!hasPoints()) {
            mPath.moveTo(mLastX = 0, mLastY = 0);
        }
        dx1 += mLastX;
+485 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading