diff options
| author | Romain Guy <romainguy@google.com> | 2013-07-29 19:17:59 -0700 |
|---|---|---|
| committer | Romain Guy <romainguy@google.com> | 2013-07-30 10:51:24 -0700 |
| commit | 8018c8db8221aa604b3c083e09d173cc27e53d83 (patch) | |
| tree | 60cbc26ddde4fa65a476a7e869d88f358b734210 | |
| parent | 93d34a61dbdfd9ece9ac4a53d78e896638172895 (diff) | |
| download | frameworks_base-8018c8db8221aa604b3c083e09d173cc27e53d83.zip frameworks_base-8018c8db8221aa604b3c083e09d173cc27e53d83.tar.gz frameworks_base-8018c8db8221aa604b3c083e09d173cc27e53d83.tar.bz2 | |
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
| -rw-r--r-- | api/current.txt | 12 | ||||
| -rw-r--r-- | core/jni/android/graphics/Path.cpp | 16 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Path.java | 107 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 12 | ||||
| -rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java | 87 |
5 files changed, 214 insertions, 20 deletions
diff --git a/api/current.txt b/api/current.txt index 6bb40e1..4bacfa8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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); } diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index eb9e004..ab7f1dc 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -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); } @@ -200,7 +200,7 @@ public: } static void addRoundRectXY(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect, - jfloat rx, jfloat ry, SkPath::Direction dir) { + jfloat rx, jfloat ry, SkPath::Direction dir) { SkRect rect_; GraphicsJNI::jrectf_to_rect(env, rect, &rect_); SkScalar rx_ = SkFloatToScalar(rx); @@ -209,7 +209,7 @@ public: } static void addRoundRect8(JNIEnv* env, jobject, SkPath* obj, jobject rect, - jfloatArray array, SkPath::Direction dir) { + jfloatArray array, SkPath::Direction dir) { SkRect rect_; GraphicsJNI::jrectf_to_rect(env, rect, &rect_); AutoJavaFloatArray afa(env, array, 8); @@ -261,7 +261,10 @@ public: static void transform__Matrix(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix) { 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) { diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java index 157c7d1..ef858eb 100644 --- a/graphics/java/android/graphics/Path.java +++ b/graphics/java/android/graphics/Path.java @@ -103,21 +103,106 @@ 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; } - + // these must be in the same order as their native values static final FillType[] sFillTypeArray = { FillType.WINDING, @@ -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); } diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index bdd8aa6..1bb0db0 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -41,6 +41,16 @@ </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" android:theme="@android:style/Theme.Holo.Light"> @@ -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> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java new file mode 100644 index 0000000..b9927ac --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java @@ -0,0 +1,87 @@ +/* + * 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); + } + } + } +} |
