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

Commit 8018c8db authored by Romain Guy's avatar Romain Guy
Browse files

Add path ops API

Path ops can be used to combine two paths instances in a single path
object. The following operations can be used:

- Difference
- Reverse difference
- Union
- XOR
- Intersection

To use the API:

Path p1 = createCircle();
Path p2 = createRect();

Path result = new Path();
result.op(p1, p2, Path.Op.DIFFERENCE);

This code will subtract the rectangle from the circle and generate
the resulting path in "result."

Change-Id: Ic25244665b6691a7df0b0002a09da73d937b553b
parent 93d34a61
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -9432,6 +9432,8 @@ package android.graphics {
    method public void moveTo(float, float);
    method public void offset(float, float, android.graphics.Path);
    method public void offset(float, float);
    method public boolean op(android.graphics.Path, android.graphics.Path.Op);
    method public boolean op(android.graphics.Path, android.graphics.Path, android.graphics.Path.Op);
    method public void quadTo(float, float, float, float);
    method public void rCubicTo(float, float, float, float, float, float);
    method public void rLineTo(float, float);
@@ -9463,6 +9465,16 @@ package android.graphics {
    enum_constant public static final android.graphics.Path.FillType WINDING;
  }
  public static final class Path.Op extends java.lang.Enum {
    method public static android.graphics.Path.Op valueOf(java.lang.String);
    method public static final android.graphics.Path.Op[] values();
    enum_constant public static final android.graphics.Path.Op DIFFERENCE;
    enum_constant public static final android.graphics.Path.Op INTERSECT;
    enum_constant public static final android.graphics.Path.Op REVERSE_DIFFERENCE;
    enum_constant public static final android.graphics.Path.Op UNION;
    enum_constant public static final android.graphics.Path.Op XOR;
  }
  public class PathDashPathEffect extends android.graphics.PathEffect {
    ctor public PathDashPathEffect(android.graphics.Path, float, float, android.graphics.PathDashPathEffect.Style);
  }
+10 −6
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <android_runtime/AndroidRuntime.h>

#include "SkPath.h"
#include "pathops/SkPathOps.h"

#include <Caches.h>

@@ -67,8 +68,7 @@ public:
        return obj->getFillType();
    }
 
    static void setFillType(JNIEnv* env, jobject clazz, SkPath* path,
                            SkPath::FillType ft) {
    static void setFillType(JNIEnv* env, jobject clazz, SkPath* path, SkPath::FillType ft) {
        path->setFillType(ft);
    }
 
@@ -262,6 +262,9 @@ public:
        obj->transform(*matrix);
    }

    static jboolean op(JNIEnv* env, jobject clazz, SkPath* p1, SkPath* p2, SkPathOp op, SkPath* r) {
         return Op(*p1, *p2, op, r);
     }
};

static JNINativeMethod methods[] = {
@@ -301,7 +304,8 @@ static JNINativeMethod methods[] = {
    {"native_offset","(IFF)V", (void*) SkPathGlue::offset__FF},
    {"native_setLastPoint","(IFF)V", (void*) SkPathGlue::setLastPoint},
    {"native_transform","(III)V", (void*) SkPathGlue::transform__MatrixPath},
    {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix}
    {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix},
    {"native_op","(IIII)Z", (void*) SkPathGlue::op}
};

int register_android_graphics_Path(JNIEnv* env) {
+94 −13
Original line number Diff line number Diff line
@@ -103,18 +103,103 @@ public class Path {
        }
    }

    /** Enum for the ways a path may be filled
    /**
     * The logical operations that can be performed when combining two paths.
     *
     * @see #op(Path, android.graphics.Path.Op)
     * @see #op(Path, Path, android.graphics.Path.Op)
     */
    public enum Op {
        /**
         * Subtract the second path from the first path.
         */
        DIFFERENCE,
        /**
         * Intersect the two paths.
         */
        INTERSECT,
        /**
         * Union (inclusive-or) the two paths.
         */
        UNION,
        /**
         * Exclusive-or the two paths.
         */
        XOR,
        /**
         * Subtract the first path from the second path.
         */
        REVERSE_DIFFERENCE
    }

    /**
     * Set this path to the result of applying the Op to this path and the specified path.
     * The resulting path will be constructed from non-overlapping contours.
     * The curve order is reduced where possible so that cubics may be turned
     * into quadratics, and quadratics maybe turned into lines.
     *
     * @param path The second operand (for difference, the subtrahend)
     *
     * @return True if operation succeeded, false otherwise and this path remains unmodified.
     *
     * @see Op
     * @see #op(Path, Path, android.graphics.Path.Op)
     */
    public boolean op(Path path, Op op) {
        return op(this, path, op);
    }

    /**
     * Set this path to the result of applying the Op to the two specified paths.
     * The resulting path will be constructed from non-overlapping contours.
     * The curve order is reduced where possible so that cubics may be turned
     * into quadratics, and quadratics maybe turned into lines.
     *
     * @param path1 The first operand (for difference, the minuend)
     * @param path2 The second operand (for difference, the subtrahend)
     *
     * @return True if operation succeeded, false otherwise and this path remains unmodified.
     *
     * @see Op
     * @see #op(Path, android.graphics.Path.Op)
     */
    public boolean op(Path path1, Path path2, Op op) {
        if (native_op(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
            isSimplePath = false;
            rects = null;
            return true;
        }
        return false;
    }

    /**
     * Enum for the ways a path may be filled.
     */
    public enum FillType {
        // these must match the values in SkPath.h
        /**
         * Specifies that "inside" is computed by a non-zero sum of signed
         * edge crossings.
         */
        WINDING         (0),
        /**
         * Specifies that "inside" is computed by an odd number of edge
         * crossings.
         */
        EVEN_ODD        (1),
        /**
         * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
         */
        INVERSE_WINDING (2),
        /**
         * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
         */
        INVERSE_EVEN_ODD(3);
        
        FillType(int ni) {
            nativeInt = ni;
        }

        final int nativeInt;
    }

@@ -644,24 +729,20 @@ public class Path {
    private static native void native_addRect(int nPath, float left, float top,
                                            float right, float bottom, int dir);
    private static native void native_addOval(int nPath, RectF oval, int dir);
    private static native void native_addCircle(int nPath, float x, float y,
                                                float radius, int dir);
    private static native void native_addCircle(int nPath, float x, float y, float radius, int dir);
    private static native void native_addArc(int nPath, RectF oval,
                                            float startAngle, float sweepAngle);
    private static native void native_addRoundRect(int nPath, RectF rect,
                                                   float rx, float ry, int dir);
    private static native void native_addRoundRect(int nPath, RectF r,
                                                   float[] radii, int dir);
    private static native void native_addPath(int nPath, int src, float dx,
                                              float dy);
    private static native void native_addRoundRect(int nPath, RectF r, float[] radii, int dir);
    private static native void native_addPath(int nPath, int src, float dx, float dy);
    private static native void native_addPath(int nPath, int src);
    private static native void native_addPath(int nPath, int src, int matrix);
    private static native void native_offset(int nPath, float dx, float dy,
                                             int dst_path);
    private static native void native_offset(int nPath, float dx, float dy, int dst_path);
    private static native void native_offset(int nPath, float dx, float dy);
    private static native void native_setLastPoint(int nPath, float dx, float dy);
    private static native void native_transform(int nPath, int matrix,
                                                int dst_path);
    private static native void native_transform(int nPath, int matrix, int dst_path);
    private static native void native_transform(int nPath, int matrix);
    private static native boolean native_op(int path1, int path2, int op, int result);
    private static native void finalizer(int nPath);
}
+11 −1
Original line number Diff line number Diff line
@@ -40,6 +40,16 @@
            </intent-filter>
        </activity>

        <activity
                android:name="PathOpsActivity"
                android:label="Path/Ops"
                android:theme="@android:style/Theme.Holo.Light">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="com.android.test.hwui.TEST" />
            </intent-filter>
        </activity>

        <activity
                android:name="AssetsAtlasActivity"
                android:label="Atlas/Framework"
@@ -735,7 +745,7 @@
                android:name="PathsCacheActivity"
                android:label="Path/Cache">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.MAIN" />`
                <category android:name="com.android.test.hwui.TEST" />
            </intent-filter>
        </activity>
+87 −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 com.android.test.hwui;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

@SuppressWarnings({"UnusedDeclaration"})
public class PathOpsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final PathsView view = new PathsView(this);
        setContentView(view);
    }

    public static class PathsView extends View {
        private final Paint mPaint;
        private Path[] mPaths;
        private float mSize;


        public PathsView(Context c) {
            super(c);

            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(Color.RED);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);

            Path.Op[] ops = Path.Op.values();
            mPaths = new Path[ops.length];

            mSize = w / (ops.length * 2.0f);

            Path p1 = new Path();
            p1.addRect(0.0f, 0.0f, mSize, mSize, Path.Direction.CW);

            Path p2 = new Path();
            p2.addCircle(mSize, mSize, mSize / 2.0f, Path.Direction.CW);

            for (int i = 0; i < ops.length; i++) {
                mPaths[i] = new Path();
                if (!mPaths[i].op(p1, p2, ops[i])) {
                    Log.d("PathOps", ops[i].name() + " failed!");
                }
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            canvas.translate(mSize * 0.2f, getHeight() / 2.0f);
            for (Path path : mPaths) {
                canvas.drawPath(path, mPaint);
                canvas.translate(mSize * 1.8f, 0.0f);
            }
        }
    }
}