Merge "Add APIs to make Android Path queryable and more useful"
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.perftests;
|
||||
|
||||
import static android.graphics.PathIterator.VERB_DONE;
|
||||
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PathIterator;
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
@LargeTest
|
||||
public class PathIteratorPerfTest {
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
private Path constructCircularPath(int numSegments) {
|
||||
Path path = new Path();
|
||||
float angleIncrement = (float) (2 * Math.PI / numSegments);
|
||||
float radius = 200f;
|
||||
float prevX = 0f, prevY = 0f;
|
||||
float angle = 0f;
|
||||
for (int i = 0; i <= numSegments; ++i) {
|
||||
float x = (float) Math.cos(angle) * radius;
|
||||
float y = (float) Math.sin(angle) * radius;
|
||||
if (i > 0) {
|
||||
path.cubicTo(prevX, prevY, x, y, x, y);
|
||||
} else {
|
||||
path.moveTo(x, y);
|
||||
}
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
angle += angleIncrement;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private void testNextSegmentImpl(int numSegments) {
|
||||
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
Path path = constructCircularPath(numSegments);
|
||||
while (state.keepRunning()) {
|
||||
PathIterator iterator = path.iterator();
|
||||
PathIterator.Segment segment = iterator.next();
|
||||
while (segment.getVerb() != VERB_DONE) {
|
||||
segment = iterator.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testNextFloatsImpl(int numSegments) {
|
||||
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
float[] points = new float[8];
|
||||
Path path = constructCircularPath(numSegments);
|
||||
while (state.keepRunning()) {
|
||||
PathIterator iterator = path.iterator();
|
||||
int verb = iterator.next(points, 0);
|
||||
while (verb != VERB_DONE) {
|
||||
verb = iterator.next(points, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSegment10() {
|
||||
testNextSegmentImpl(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSegment100() {
|
||||
testNextSegmentImpl(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextSegment1000() {
|
||||
testNextSegmentImpl(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextArray10() {
|
||||
testNextFloatsImpl(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextArray100() {
|
||||
testNextFloatsImpl(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextArray1000() {
|
||||
testNextFloatsImpl(1000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15124,7 +15124,7 @@ package android.graphics {
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.graphics.ParcelableColorSpace> CREATOR;
|
||||
}
|
||||
|
||||
public class Path {
|
||||
public class Path implements java.lang.Iterable<android.graphics.PathIterator.Segment> {
|
||||
ctor public Path();
|
||||
ctor public Path(@Nullable android.graphics.Path);
|
||||
method public void addArc(@NonNull android.graphics.RectF, float, float);
|
||||
@@ -15147,13 +15147,18 @@ package android.graphics {
|
||||
method public void arcTo(float, float, float, float, float, float, boolean);
|
||||
method public void close();
|
||||
method public void computeBounds(@NonNull android.graphics.RectF, boolean);
|
||||
method public void conicTo(float, float, float, float, float);
|
||||
method public void cubicTo(float, float, float, float, float, float);
|
||||
method @NonNull public android.graphics.Path.FillType getFillType();
|
||||
method public int getGenerationId();
|
||||
method public void incReserve(int);
|
||||
method public boolean interpolate(@NonNull android.graphics.Path, float, @NonNull android.graphics.Path);
|
||||
method @Deprecated public boolean isConvex();
|
||||
method public boolean isEmpty();
|
||||
method public boolean isInterpolatable(@NonNull android.graphics.Path);
|
||||
method public boolean isInverseFillType();
|
||||
method public boolean isRect(@Nullable android.graphics.RectF);
|
||||
method @NonNull public android.graphics.PathIterator iterator();
|
||||
method public void lineTo(float, float);
|
||||
method public void moveTo(float, float);
|
||||
method public void offset(float, float, @Nullable android.graphics.Path);
|
||||
@@ -15161,6 +15166,7 @@ package android.graphics {
|
||||
method public boolean op(@NonNull android.graphics.Path, @NonNull android.graphics.Path.Op);
|
||||
method public boolean op(@NonNull android.graphics.Path, @NonNull android.graphics.Path, @NonNull android.graphics.Path.Op);
|
||||
method public void quadTo(float, float, float, float);
|
||||
method public void rConicTo(float, float, float, float, float);
|
||||
method public void rCubicTo(float, float, float, float, float, float);
|
||||
method public void rLineTo(float, float);
|
||||
method public void rMoveTo(float, float);
|
||||
@@ -15209,6 +15215,27 @@ package android.graphics {
|
||||
ctor public PathEffect();
|
||||
}
|
||||
|
||||
public class PathIterator implements java.util.Iterator<android.graphics.PathIterator.Segment> {
|
||||
method public boolean hasNext();
|
||||
method @NonNull public int next(@NonNull float[], int);
|
||||
method @NonNull public android.graphics.PathIterator.Segment next();
|
||||
method @NonNull public int peek();
|
||||
field public static final int VERB_CLOSE = 5; // 0x5
|
||||
field public static final int VERB_CONIC = 3; // 0x3
|
||||
field public static final int VERB_CUBIC = 4; // 0x4
|
||||
field public static final int VERB_DONE = 6; // 0x6
|
||||
field public static final int VERB_LINE = 1; // 0x1
|
||||
field public static final int VERB_MOVE = 0; // 0x0
|
||||
field public static final int VERB_QUAD = 2; // 0x2
|
||||
}
|
||||
|
||||
public static class PathIterator.Segment {
|
||||
ctor public PathIterator.Segment(@NonNull int, @NonNull float[], float);
|
||||
method public float getConicWeight();
|
||||
method @NonNull public float[] getPoints();
|
||||
method @NonNull public int getVerb();
|
||||
}
|
||||
|
||||
public class PathMeasure {
|
||||
ctor public PathMeasure();
|
||||
ctor public PathMeasure(android.graphics.Path, boolean);
|
||||
|
||||
@@ -33,7 +33,7 @@ import libcore.util.NativeAllocationRegistry;
|
||||
* (based on the paint's Style), or it can be used for clipping or to draw
|
||||
* text on a path.
|
||||
*/
|
||||
public class Path {
|
||||
public class Path implements Iterable<PathIterator.Segment> {
|
||||
|
||||
private static final NativeAllocationRegistry sRegistry =
|
||||
NativeAllocationRegistry.createMalloced(
|
||||
@@ -91,6 +91,17 @@ public class Path {
|
||||
nSet(mNativePath, src.mNativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the segments of this path.
|
||||
*
|
||||
* @return the Iterator object
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public PathIterator iterator() {
|
||||
return new PathIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The logical operations that can be performed when combining two paths.
|
||||
*
|
||||
@@ -382,6 +393,49 @@ public class Path {
|
||||
nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a quadratic bezier from the last point, approaching control point
|
||||
* (x1,y1), and ending at (x2,y2), weighted by <code>weight</code>. If no
|
||||
* moveTo() call has been made for this contour, the first point is
|
||||
* automatically set to (0,0).
|
||||
*
|
||||
* A weight of 1 is equivalent to calling {@link #quadTo(float, float, float, float)}.
|
||||
* A weight of 0 is equivalent to calling {@link #lineTo(float, float)} to
|
||||
* <code>(x1, y1)</code> followed by {@link #lineTo(float, float)} to <code>(x2, y2)</code>.
|
||||
*
|
||||
* @param x1 The x-coordinate of the control point on a conic curve
|
||||
* @param y1 The y-coordinate of the control point on a conic curve
|
||||
* @param x2 The x-coordinate of the end point on a conic curve
|
||||
* @param y2 The y-coordinate of the end point on a conic curve
|
||||
* @param weight The weight of the conic applied to the curve. A value of 1 is equivalent
|
||||
* to a quadratic with the given control and anchor points and a value of 0 is
|
||||
* equivalent to a line to the first and another line to the second point.
|
||||
*/
|
||||
public void conicTo(float x1, float y1, float x2, float y2, float weight) {
|
||||
nConicTo(mNativePath, x1, y1, x2, y2, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as conicTo, but the coordinates are considered relative to the last
|
||||
* point on this contour. If there is no previous point, then a moveTo(0,0)
|
||||
* is inserted automatically.
|
||||
*
|
||||
* @param dx1 The amount to add to the x-coordinate of the last point on
|
||||
* this contour, for the control point of a conic curve
|
||||
* @param dy1 The amount to add to the y-coordinate of the last point on
|
||||
* this contour, for the control point of a conic curve
|
||||
* @param dx2 The amount to add to the x-coordinate of the last point on
|
||||
* this contour, for the end point of a conic curve
|
||||
* @param dy2 The amount to add to the y-coordinate of the last point on
|
||||
* this contour, for the end point of a conic curve
|
||||
* @param weight The weight of the conic applied to the curve. A value of 1 is equivalent
|
||||
* to a quadratic with the given control and anchor points and a value of 0 is
|
||||
* equivalent to a line to the first and another line to the second point.
|
||||
*/
|
||||
public void rConicTo(float dx1, float dy1, float dx2, float dy2, float weight) {
|
||||
nRConicTo(mNativePath, dx1, dy1, dx2, dy2, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a cubic bezier from the last point, approaching control points
|
||||
* (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
|
||||
@@ -736,6 +790,46 @@ public class Path {
|
||||
return nApproximate(mNativePath, acceptableError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generation ID of this path. The generation ID changes
|
||||
* whenever the path is modified. This can be used as an efficient way to
|
||||
* check if a path has changed.
|
||||
*
|
||||
* @return The current generation ID for this path
|
||||
*/
|
||||
public int getGenerationId() {
|
||||
return nGetGenerationID(mNativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Two paths can be interpolated, by calling {@link #interpolate(Path, float, Path)}, if they
|
||||
* have exactly the same structure. That is, both paths must have the same
|
||||
* operations, in the same order. If any of the operations are
|
||||
* of type {@link PathIterator#VERB_CONIC}, then the weights of those conics must also match.
|
||||
*
|
||||
* @param otherPath The other <code>Path</code> being interpolated to from this one.
|
||||
* @return true if interpolation is possible, false otherwise
|
||||
*/
|
||||
public boolean isInterpolatable(@NonNull Path otherPath) {
|
||||
return nIsInterpolatable(mNativePath, otherPath.mNativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will linearly interpolate from this path to <code>otherPath</code> given
|
||||
* the interpolation parameter <code>t</code>, returning the result in
|
||||
* <code>interpolatedPath</code>. Interpolation will only succeed if the structures of the
|
||||
* two paths match exactly, as discussed in {@link #isInterpolatable(Path)}.
|
||||
*
|
||||
* @param otherPath The other <code>Path</code> being interpolated to.
|
||||
* @param t The interpolation parameter. A value of 0 results in a <code>Path</code>
|
||||
* equivalent to this path, a value of 1 results in one equivalent to
|
||||
* <code>otherPath</code>.
|
||||
* @param interpolatedPath The interpolated results.
|
||||
*/
|
||||
public boolean interpolate(@NonNull Path otherPath, float t, @NonNull Path interpolatedPath) {
|
||||
return nInterpolate(mNativePath, otherPath.mNativePath, t, interpolatedPath.mNativePath);
|
||||
}
|
||||
|
||||
// ------------------ Regular JNI ------------------------
|
||||
|
||||
private static native long nInit();
|
||||
@@ -750,6 +844,10 @@ public class Path {
|
||||
private static native void nRLineTo(long nPath, float dx, float dy);
|
||||
private static native void nQuadTo(long nPath, float x1, float y1, float x2, float y2);
|
||||
private static native void nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2);
|
||||
private static native void nConicTo(long nPath, float x1, float y1, float x2, float y2,
|
||||
float weight);
|
||||
private static native void nRConicTo(long nPath, float dx1, float dy1, float dx2, float dy2,
|
||||
float weight);
|
||||
private static native void nCubicTo(long nPath, float x1, float y1, float x2, float y2,
|
||||
float x3, float y3);
|
||||
private static native void nRCubicTo(long nPath, float x1, float y1, float x2, float y2,
|
||||
@@ -777,6 +875,8 @@ public class Path {
|
||||
private static native void nTransform(long nPath, long matrix);
|
||||
private static native boolean nOp(long path1, long path2, int op, long result);
|
||||
private static native float[] nApproximate(long nPath, float error);
|
||||
private static native boolean nInterpolate(long startPath, long endPath, float t,
|
||||
long interpolatedPath);
|
||||
|
||||
// ------------------ Fast JNI ------------------------
|
||||
|
||||
@@ -785,6 +885,10 @@ public class Path {
|
||||
|
||||
// ------------------ Critical JNI ------------------------
|
||||
|
||||
@CriticalNative
|
||||
private static native int nGetGenerationID(long nativePath);
|
||||
@CriticalNative
|
||||
private static native boolean nIsInterpolatable(long startPath, long endPath);
|
||||
@CriticalNative
|
||||
private static native void nReset(long nPath);
|
||||
@CriticalNative
|
||||
|
||||
303
graphics/java/android/graphics/PathIterator.java
Normal file
303
graphics/java/android/graphics/PathIterator.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
||||
/**
|
||||
* <code>PathIterator</code> can be used to query a given {@link Path} object, to discover its
|
||||
* operations and point values.
|
||||
*/
|
||||
public class PathIterator implements Iterator<PathIterator.Segment> {
|
||||
|
||||
private final float[] mPointsArray;
|
||||
private final long mPointsAddress;
|
||||
private int mCachedVerb = -1;
|
||||
private boolean mDone = false;
|
||||
private final long mNativeIterator;
|
||||
private final Path mPath;
|
||||
private final int mPathGenerationId;
|
||||
private static final int POINT_ARRAY_SIZE = 8;
|
||||
|
||||
private static final NativeAllocationRegistry sRegistry =
|
||||
NativeAllocationRegistry.createMalloced(
|
||||
PathIterator.class.getClassLoader(), nGetFinalizer());
|
||||
|
||||
/**
|
||||
* The <code>Verb</code> indicates the operation for a given segment of a path. These
|
||||
* operations correspond exactly to the primitive operations on {@link Path}, such as
|
||||
* {@link Path#moveTo(float, float)} and {@link Path#lineTo(float, float)}.
|
||||
*/
|
||||
@Retention(SOURCE)
|
||||
@IntDef({VERB_MOVE, VERB_LINE, VERB_QUAD, VERB_CONIC, VERB_CUBIC, VERB_CLOSE, VERB_DONE})
|
||||
@interface Verb {}
|
||||
// these must match the values in SkPath.h
|
||||
public static final int VERB_MOVE = 0;
|
||||
public static final int VERB_LINE = 1;
|
||||
public static final int VERB_QUAD = 2;
|
||||
public static final int VERB_CONIC = 3;
|
||||
public static final int VERB_CUBIC = 4;
|
||||
public static final int VERB_CLOSE = 5;
|
||||
public static final int VERB_DONE = 6;
|
||||
|
||||
/**
|
||||
* Returns a {@link PathIterator} object for this path, which can be used to query the
|
||||
* data (operations and points) in the path. Iterators can only be used on Path objects
|
||||
* that have not been modified since the iterator was created. Calling
|
||||
* {@link #next(float[], int)}, {@link #next()}, or {@link #hasNext()} on an
|
||||
* iterator for a modified path will result in a {@link ConcurrentModificationException}.
|
||||
*
|
||||
* @param path The {@link Path} for which this iterator can be queried.
|
||||
*/
|
||||
PathIterator(@NonNull Path path) {
|
||||
mPath = path;
|
||||
mNativeIterator = nCreate(mPath.mNativePath);
|
||||
mPathGenerationId = mPath.getGenerationId();
|
||||
final VMRuntime runtime = VMRuntime.getRuntime();
|
||||
mPointsArray = (float[]) runtime.newNonMovableArray(float.class, POINT_ARRAY_SIZE);
|
||||
mPointsAddress = runtime.addressOf(mPointsArray);
|
||||
sRegistry.registerNativeAllocation(this, mNativeIterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next verb in this iterator's {@link Path}, and fills entries in the
|
||||
* <code>points</code> array with the point data (if any) for that operation.
|
||||
* Each two floats represent the data for a single point of that operation.
|
||||
* The number of pairs of floats supplied in the resulting array depends on the verb:
|
||||
* <ul>
|
||||
* <li>{@link #VERB_MOVE}: 1 pair (indices 0 to 1)</li>
|
||||
* <li>{@link #VERB_LINE}: 2 pairs (indices 0 to 3)</li>
|
||||
* <li>{@link #VERB_QUAD}: 3 pairs (indices 0 to 5)</li>
|
||||
* <li>{@link #VERB_CONIC}: 3.5 pairs (indices 0 to 6), the seventh entry has the conic
|
||||
* weight</li>
|
||||
* <li>{@link #VERB_CUBIC}: 4 pairs (indices 0 to 7)</li>
|
||||
* <li>{@link #VERB_CLOSE}: 0 pairs</li>
|
||||
* <li>{@link #VERB_DONE}: 0 pairs</li>
|
||||
* </ul>
|
||||
* @param points The point data for this operation, must have at least
|
||||
* 8 items available to hold up to 4 pairs of point values
|
||||
* @param offset An offset into the <code>points</code> array where entries should be placed.
|
||||
* @return the operation for the next element in the iteration
|
||||
* @throws ArrayIndexOutOfBoundsException if the points array is too small
|
||||
* @throws ConcurrentModificationException if the underlying path was modified
|
||||
* since this iterator was created.
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
@NonNull
|
||||
public @Verb int next(@NonNull float[] points, int offset) {
|
||||
if (points.length < offset + POINT_ARRAY_SIZE) {
|
||||
throw new ArrayIndexOutOfBoundsException("points array must be able to "
|
||||
+ "hold at least 8 entries");
|
||||
}
|
||||
@Verb int returnVerb = getReturnVerb(mCachedVerb);
|
||||
mCachedVerb = -1;
|
||||
System.arraycopy(mPointsArray, 0, points, offset, POINT_ARRAY_SIZE);
|
||||
return returnVerb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the there are more elements in this iterator to be returned.
|
||||
* A return value of <code>false</code> means there are no more elements, and an
|
||||
* ensuing call to {@link #next()} or {@link #next(float[], int)} )} will throw a
|
||||
* {@link NoSuchElementException}.
|
||||
*
|
||||
* @return true if there are more elements to be iterated through, false otherwise
|
||||
* @throws ConcurrentModificationException if the underlying path was modified
|
||||
* since this iterator was created.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
if (mCachedVerb == -1) {
|
||||
mCachedVerb = nextInternal();
|
||||
}
|
||||
return true;
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next verb in the iteration, or {@link #VERB_DONE} if there are no more
|
||||
* elements.
|
||||
*
|
||||
* @return the next verb in the iteration, or {@link #VERB_DONE} if there are no more
|
||||
* elements
|
||||
* @throws ConcurrentModificationException if the underlying path was modified
|
||||
* since this iterator was created.
|
||||
*/
|
||||
@NonNull
|
||||
public @Verb int peek() {
|
||||
if (mPathGenerationId != mPath.getGenerationId()) {
|
||||
throw new ConcurrentModificationException(
|
||||
"Iterator cannot be used on modified Path");
|
||||
}
|
||||
if (mDone) {
|
||||
return VERB_DONE;
|
||||
}
|
||||
return nPeek(mNativeIterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is where the work is done for {@link #next()}. Using this internal method
|
||||
* is helfpul for managing the cached segment used by {@link #hasNext()}.
|
||||
*
|
||||
* @return the segment to be returned by {@link #next()}
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
@NonNull
|
||||
private @Verb int nextInternal() {
|
||||
if (mDone) {
|
||||
throw new NoSuchElementException("No more path segments to iterate");
|
||||
}
|
||||
if (mPathGenerationId != mPath.getGenerationId()) {
|
||||
throw new ConcurrentModificationException(
|
||||
"Iterator cannot be used on modified Path");
|
||||
}
|
||||
@Verb int verb = nNext(mNativeIterator, mPointsAddress);
|
||||
if (verb == VERB_DONE) {
|
||||
mDone = true;
|
||||
}
|
||||
return verb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next {@link Segment} element in this iterator.
|
||||
*
|
||||
* There are two versions of <code>next()</code>. This version is slightly more
|
||||
* expensive at runtime, since it allocates a new {@link Segment} object with
|
||||
* every call. The other version, {@link #next(float[], int)} requires no such allocation, but
|
||||
* requires a little more manual effort to use.
|
||||
*
|
||||
* @return the next segment in this iterator
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
* @throws ConcurrentModificationException if the underlying path was modified
|
||||
* since this iterator was created.
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public Segment next() {
|
||||
@Verb int returnVerb = getReturnVerb(mCachedVerb);
|
||||
mCachedVerb = -1;
|
||||
float conicWeight = 0f;
|
||||
if (returnVerb == VERB_CONIC) {
|
||||
conicWeight = mPointsArray[6];
|
||||
}
|
||||
float[] returnPoints = new float[8];
|
||||
System.arraycopy(mPointsArray, 0, returnPoints, 0, POINT_ARRAY_SIZE);
|
||||
return new Segment(returnVerb, returnPoints, conicWeight);
|
||||
}
|
||||
|
||||
private @Verb int getReturnVerb(int cachedVerb) {
|
||||
switch (cachedVerb) {
|
||||
case VERB_MOVE: return VERB_MOVE;
|
||||
case VERB_LINE: return VERB_LINE;
|
||||
case VERB_QUAD: return VERB_QUAD;
|
||||
case VERB_CONIC: return VERB_CONIC;
|
||||
case VERB_CUBIC: return VERB_CUBIC;
|
||||
case VERB_CLOSE: return VERB_CLOSE;
|
||||
case VERB_DONE: return VERB_DONE;
|
||||
}
|
||||
return nextInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds the data for a given segment in a path, as returned by
|
||||
* {@link #next()}.
|
||||
*/
|
||||
public static class Segment {
|
||||
private final @Verb int mVerb;
|
||||
private final float[] mPoints;
|
||||
private final float mConicWeight;
|
||||
|
||||
/**
|
||||
* The operation for this segment.
|
||||
*
|
||||
* @return the verb which indicates the operation happening in this segment
|
||||
*/
|
||||
@NonNull
|
||||
public @Verb int getVerb() {
|
||||
return mVerb;
|
||||
}
|
||||
|
||||
/**
|
||||
* The point data for this segment.
|
||||
*
|
||||
* Each two floats represent the data for a single point of that operation.
|
||||
* The number of pairs of floats supplied in the resulting array depends on the verb:
|
||||
* <ul>
|
||||
* <li>{@link #VERB_MOVE}: 1 pair (indices 0 to 1)</li>
|
||||
* <li>{@link #VERB_LINE}: 2 pairs (indices 0 to 3)</li>
|
||||
* <li>{@link #VERB_QUAD}: 3 pairs (indices 0 to 5)</li>
|
||||
* <li>{@link #VERB_CONIC}: 4 pairs (indices 0 to 7), the last pair contains the
|
||||
* conic weight twice</li>
|
||||
* <li>{@link #VERB_CUBIC}: 4 pairs (indices 0 to 7)</li>
|
||||
* <li>{@link #VERB_CLOSE}: 0 pairs</li>
|
||||
* <li>{@link #VERB_DONE}: 0 pairs</li>
|
||||
* </ul>
|
||||
* @return the point data for this segment
|
||||
*/
|
||||
@NonNull
|
||||
public float[] getPoints() {
|
||||
return mPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* The weight for the conic operation in this segment. If the verb in this segment
|
||||
* is not equal to {@link #VERB_CONIC}, the weight value is undefined.
|
||||
*
|
||||
* @see Path#conicTo(float, float, float, float, float)
|
||||
* @return the weight for the conic operation in this segment, if any
|
||||
*/
|
||||
public float getConicWeight() {
|
||||
return mConicWeight;
|
||||
}
|
||||
|
||||
public Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
|
||||
mVerb = verb;
|
||||
mPoints = points;
|
||||
mConicWeight = conicWeight;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ Regular JNI ------------------------
|
||||
|
||||
private static native long nCreate(long nativePath);
|
||||
private static native long nGetFinalizer();
|
||||
|
||||
// ------------------ Critical JNI ------------------------
|
||||
|
||||
@CriticalNative
|
||||
private static native int nNext(long nativeIterator, long pointsAddress);
|
||||
|
||||
@CriticalNative
|
||||
private static native int nPeek(long nativeIterator);
|
||||
}
|
||||
@@ -345,6 +345,7 @@ cc_defaults {
|
||||
"jni/PaintFilter.cpp",
|
||||
"jni/Path.cpp",
|
||||
"jni/PathEffect.cpp",
|
||||
"jni/PathIterator.cpp",
|
||||
"jni/PathMeasure.cpp",
|
||||
"jni/Picture.cpp",
|
||||
"jni/Region.cpp",
|
||||
|
||||
@@ -53,6 +53,7 @@ extern int register_android_graphics_FontFamily(JNIEnv* env);
|
||||
extern int register_android_graphics_Matrix(JNIEnv* env);
|
||||
extern int register_android_graphics_Paint(JNIEnv* env);
|
||||
extern int register_android_graphics_Path(JNIEnv* env);
|
||||
extern int register_android_graphics_PathIterator(JNIEnv* env);
|
||||
extern int register_android_graphics_PathMeasure(JNIEnv* env);
|
||||
extern int register_android_graphics_Picture(JNIEnv* env);
|
||||
extern int register_android_graphics_Region(JNIEnv* env);
|
||||
@@ -100,6 +101,7 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
|
||||
{"android.graphics.Paint", REG_JNI(register_android_graphics_Paint)},
|
||||
{"android.graphics.Path", REG_JNI(register_android_graphics_Path)},
|
||||
{"android.graphics.PathEffect", REG_JNI(register_android_graphics_PathEffect)},
|
||||
{"android.graphics.PathIterator", REG_JNI(register_android_graphics_PathIterator)},
|
||||
{"android.graphics.PathMeasure", REG_JNI(register_android_graphics_PathMeasure)},
|
||||
{"android.graphics.Picture", REG_JNI(register_android_graphics_Picture)},
|
||||
{"android.graphics.RecordingCanvas", REG_JNI(register_android_view_DisplayListCanvas)},
|
||||
|
||||
@@ -59,6 +59,7 @@ extern int register_android_graphics_HardwareRendererObserver(JNIEnv* env);
|
||||
extern int register_android_graphics_Matrix(JNIEnv* env);
|
||||
extern int register_android_graphics_Paint(JNIEnv* env);
|
||||
extern int register_android_graphics_Path(JNIEnv* env);
|
||||
extern int register_android_graphics_PathIterator(JNIEnv* env);
|
||||
extern int register_android_graphics_PathMeasure(JNIEnv* env);
|
||||
extern int register_android_graphics_Picture(JNIEnv*);
|
||||
extern int register_android_graphics_Region(JNIEnv* env);
|
||||
@@ -94,59 +95,60 @@ extern int register_android_view_ThreadedRenderer(JNIEnv* env);
|
||||
};
|
||||
#endif
|
||||
|
||||
static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_graphics_Canvas),
|
||||
// This needs to be before register_android_graphics_Graphics, or the latter
|
||||
// will not be able to find the jmethodID for ColorSpace.get().
|
||||
REG_JNI(register_android_graphics_ColorSpace),
|
||||
REG_JNI(register_android_graphics_Graphics),
|
||||
REG_JNI(register_android_graphics_Bitmap),
|
||||
REG_JNI(register_android_graphics_BitmapFactory),
|
||||
REG_JNI(register_android_graphics_BitmapRegionDecoder),
|
||||
REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
|
||||
REG_JNI(register_android_graphics_Camera),
|
||||
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
|
||||
REG_JNI(register_android_graphics_CanvasProperty),
|
||||
REG_JNI(register_android_graphics_ColorFilter),
|
||||
REG_JNI(register_android_graphics_DrawFilter),
|
||||
REG_JNI(register_android_graphics_FontFamily),
|
||||
REG_JNI(register_android_graphics_HardwareRendererObserver),
|
||||
REG_JNI(register_android_graphics_ImageDecoder),
|
||||
REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
|
||||
REG_JNI(register_android_graphics_Interpolator),
|
||||
REG_JNI(register_android_graphics_MaskFilter),
|
||||
REG_JNI(register_android_graphics_Matrix),
|
||||
REG_JNI(register_android_graphics_Movie),
|
||||
REG_JNI(register_android_graphics_NinePatch),
|
||||
REG_JNI(register_android_graphics_Paint),
|
||||
REG_JNI(register_android_graphics_Path),
|
||||
REG_JNI(register_android_graphics_PathMeasure),
|
||||
REG_JNI(register_android_graphics_PathEffect),
|
||||
REG_JNI(register_android_graphics_Picture),
|
||||
REG_JNI(register_android_graphics_Region),
|
||||
REG_JNI(register_android_graphics_Shader),
|
||||
REG_JNI(register_android_graphics_RenderEffect),
|
||||
REG_JNI(register_android_graphics_TextureLayer),
|
||||
REG_JNI(register_android_graphics_Typeface),
|
||||
REG_JNI(register_android_graphics_YuvImage),
|
||||
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory),
|
||||
REG_JNI(register_android_graphics_animation_RenderNodeAnimator),
|
||||
REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
|
||||
REG_JNI(register_android_graphics_drawable_VectorDrawable),
|
||||
REG_JNI(register_android_graphics_fonts_Font),
|
||||
REG_JNI(register_android_graphics_fonts_FontFamily),
|
||||
REG_JNI(register_android_graphics_pdf_PdfDocument),
|
||||
REG_JNI(register_android_graphics_pdf_PdfEditor),
|
||||
REG_JNI(register_android_graphics_pdf_PdfRenderer),
|
||||
REG_JNI(register_android_graphics_text_MeasuredText),
|
||||
REG_JNI(register_android_graphics_text_LineBreaker),
|
||||
REG_JNI(register_android_graphics_text_TextShaper),
|
||||
static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_graphics_Canvas),
|
||||
// This needs to be before register_android_graphics_Graphics, or the latter
|
||||
// will not be able to find the jmethodID for ColorSpace.get().
|
||||
REG_JNI(register_android_graphics_ColorSpace),
|
||||
REG_JNI(register_android_graphics_Graphics),
|
||||
REG_JNI(register_android_graphics_Bitmap),
|
||||
REG_JNI(register_android_graphics_BitmapFactory),
|
||||
REG_JNI(register_android_graphics_BitmapRegionDecoder),
|
||||
REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
|
||||
REG_JNI(register_android_graphics_Camera),
|
||||
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
|
||||
REG_JNI(register_android_graphics_CanvasProperty),
|
||||
REG_JNI(register_android_graphics_ColorFilter),
|
||||
REG_JNI(register_android_graphics_DrawFilter),
|
||||
REG_JNI(register_android_graphics_FontFamily),
|
||||
REG_JNI(register_android_graphics_HardwareRendererObserver),
|
||||
REG_JNI(register_android_graphics_ImageDecoder),
|
||||
REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
|
||||
REG_JNI(register_android_graphics_Interpolator),
|
||||
REG_JNI(register_android_graphics_MaskFilter),
|
||||
REG_JNI(register_android_graphics_Matrix),
|
||||
REG_JNI(register_android_graphics_Movie),
|
||||
REG_JNI(register_android_graphics_NinePatch),
|
||||
REG_JNI(register_android_graphics_Paint),
|
||||
REG_JNI(register_android_graphics_Path),
|
||||
REG_JNI(register_android_graphics_PathIterator),
|
||||
REG_JNI(register_android_graphics_PathMeasure),
|
||||
REG_JNI(register_android_graphics_PathEffect),
|
||||
REG_JNI(register_android_graphics_Picture),
|
||||
REG_JNI(register_android_graphics_Region),
|
||||
REG_JNI(register_android_graphics_Shader),
|
||||
REG_JNI(register_android_graphics_RenderEffect),
|
||||
REG_JNI(register_android_graphics_TextureLayer),
|
||||
REG_JNI(register_android_graphics_Typeface),
|
||||
REG_JNI(register_android_graphics_YuvImage),
|
||||
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory),
|
||||
REG_JNI(register_android_graphics_animation_RenderNodeAnimator),
|
||||
REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
|
||||
REG_JNI(register_android_graphics_drawable_VectorDrawable),
|
||||
REG_JNI(register_android_graphics_fonts_Font),
|
||||
REG_JNI(register_android_graphics_fonts_FontFamily),
|
||||
REG_JNI(register_android_graphics_pdf_PdfDocument),
|
||||
REG_JNI(register_android_graphics_pdf_PdfEditor),
|
||||
REG_JNI(register_android_graphics_pdf_PdfRenderer),
|
||||
REG_JNI(register_android_graphics_text_MeasuredText),
|
||||
REG_JNI(register_android_graphics_text_LineBreaker),
|
||||
REG_JNI(register_android_graphics_text_TextShaper),
|
||||
|
||||
REG_JNI(register_android_util_PathParser),
|
||||
REG_JNI(register_android_view_RenderNode),
|
||||
REG_JNI(register_android_view_DisplayListCanvas),
|
||||
REG_JNI(register_android_view_ThreadedRenderer),
|
||||
};
|
||||
REG_JNI(register_android_util_PathParser),
|
||||
REG_JNI(register_android_view_RenderNode),
|
||||
REG_JNI(register_android_view_DisplayListCanvas),
|
||||
REG_JNI(register_android_view_ThreadedRenderer),
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
|
||||
@@ -102,6 +102,18 @@ public:
|
||||
obj->rQuadTo(dx1, dy1, dx2, dy2);
|
||||
}
|
||||
|
||||
static void conicTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2,
|
||||
jfloat y2, jfloat weight) {
|
||||
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
|
||||
obj->conicTo(x1, y1, x2, y2, weight);
|
||||
}
|
||||
|
||||
static void rConicTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx1, jfloat dy1,
|
||||
jfloat dx2, jfloat dy2, jfloat weight) {
|
||||
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
|
||||
obj->rConicTo(dx1, dy1, dx2, dy2, weight);
|
||||
}
|
||||
|
||||
static void cubicTo__FFFFFF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
|
||||
jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
|
||||
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
|
||||
@@ -209,6 +221,14 @@ public:
|
||||
obj->setLastPt(dx, dy);
|
||||
}
|
||||
|
||||
static jboolean interpolate(JNIEnv* env, jclass clazz, jlong startHandle, jlong endHandle,
|
||||
jfloat t, jlong interpolatedHandle) {
|
||||
SkPath* startPath = reinterpret_cast<SkPath*>(startHandle);
|
||||
SkPath* endPath = reinterpret_cast<SkPath*>(endHandle);
|
||||
SkPath* interpolatedPath = reinterpret_cast<SkPath*>(interpolatedHandle);
|
||||
return startPath->interpolate(*endPath, t, interpolatedPath);
|
||||
}
|
||||
|
||||
static void transform__MatrixPath(JNIEnv* env, jclass clazz, jlong objHandle, jlong matrixHandle,
|
||||
jlong dstHandle) {
|
||||
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
|
||||
@@ -473,6 +493,16 @@ public:
|
||||
|
||||
// ---------------- @CriticalNative -------------------------
|
||||
|
||||
static jint getGenerationID(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle) {
|
||||
return (reinterpret_cast<SkPath*>(pathHandle)->getGenerationID());
|
||||
}
|
||||
|
||||
static jboolean isInterpolatable(CRITICAL_JNI_PARAMS_COMMA jlong startHandle, jlong endHandle) {
|
||||
SkPath* startPath = reinterpret_cast<SkPath*>(startHandle);
|
||||
SkPath* endPath = reinterpret_cast<SkPath*>(endHandle);
|
||||
return startPath->isInterpolatable(*endPath);
|
||||
}
|
||||
|
||||
static void reset(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
|
||||
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
|
||||
obj->reset();
|
||||
@@ -506,48 +536,53 @@ public:
|
||||
};
|
||||
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nInit","()J", (void*) SkPathGlue::init},
|
||||
{"nInit","(J)J", (void*) SkPathGlue::init_Path},
|
||||
{"nGetFinalizer", "()J", (void*) SkPathGlue::getFinalizer},
|
||||
{"nSet","(JJ)V", (void*) SkPathGlue::set},
|
||||
{"nComputeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds},
|
||||
{"nIncReserve","(JI)V", (void*) SkPathGlue::incReserve},
|
||||
{"nMoveTo","(JFF)V", (void*) SkPathGlue::moveTo__FF},
|
||||
{"nRMoveTo","(JFF)V", (void*) SkPathGlue::rMoveTo},
|
||||
{"nLineTo","(JFF)V", (void*) SkPathGlue::lineTo__FF},
|
||||
{"nRLineTo","(JFF)V", (void*) SkPathGlue::rLineTo},
|
||||
{"nQuadTo","(JFFFF)V", (void*) SkPathGlue::quadTo__FFFF},
|
||||
{"nRQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo},
|
||||
{"nCubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
|
||||
{"nRCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
|
||||
{"nArcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo},
|
||||
{"nClose","(J)V", (void*) SkPathGlue::close},
|
||||
{"nAddRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
|
||||
{"nAddOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
|
||||
{"nAddCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
|
||||
{"nAddArc","(JFFFFFF)V", (void*) SkPathGlue::addArc},
|
||||
{"nAddRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY},
|
||||
{"nAddRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8},
|
||||
{"nAddPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
|
||||
{"nAddPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
|
||||
{"nAddPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
|
||||
{"nOffset","(JFF)V", (void*) SkPathGlue::offset__FF},
|
||||
{"nSetLastPoint","(JFF)V", (void*) SkPathGlue::setLastPoint},
|
||||
{"nTransform","(JJJ)V", (void*) SkPathGlue::transform__MatrixPath},
|
||||
{"nTransform","(JJ)V", (void*) SkPathGlue::transform__Matrix},
|
||||
{"nOp","(JJIJ)Z", (void*) SkPathGlue::op},
|
||||
{"nApproximate", "(JF)[F", (void*) SkPathGlue::approximate},
|
||||
{"nInit", "()J", (void*)SkPathGlue::init},
|
||||
{"nInit", "(J)J", (void*)SkPathGlue::init_Path},
|
||||
{"nGetFinalizer", "()J", (void*)SkPathGlue::getFinalizer},
|
||||
{"nSet", "(JJ)V", (void*)SkPathGlue::set},
|
||||
{"nComputeBounds", "(JLandroid/graphics/RectF;)V", (void*)SkPathGlue::computeBounds},
|
||||
{"nIncReserve", "(JI)V", (void*)SkPathGlue::incReserve},
|
||||
{"nMoveTo", "(JFF)V", (void*)SkPathGlue::moveTo__FF},
|
||||
{"nRMoveTo", "(JFF)V", (void*)SkPathGlue::rMoveTo},
|
||||
{"nLineTo", "(JFF)V", (void*)SkPathGlue::lineTo__FF},
|
||||
{"nRLineTo", "(JFF)V", (void*)SkPathGlue::rLineTo},
|
||||
{"nQuadTo", "(JFFFF)V", (void*)SkPathGlue::quadTo__FFFF},
|
||||
{"nRQuadTo", "(JFFFF)V", (void*)SkPathGlue::rQuadTo},
|
||||
{"nConicTo", "(JFFFFF)V", (void*)SkPathGlue::conicTo},
|
||||
{"nRConicTo", "(JFFFFF)V", (void*)SkPathGlue::rConicTo},
|
||||
{"nCubicTo", "(JFFFFFF)V", (void*)SkPathGlue::cubicTo__FFFFFF},
|
||||
{"nRCubicTo", "(JFFFFFF)V", (void*)SkPathGlue::rCubicTo},
|
||||
{"nArcTo", "(JFFFFFFZ)V", (void*)SkPathGlue::arcTo},
|
||||
{"nClose", "(J)V", (void*)SkPathGlue::close},
|
||||
{"nAddRect", "(JFFFFI)V", (void*)SkPathGlue::addRect},
|
||||
{"nAddOval", "(JFFFFI)V", (void*)SkPathGlue::addOval},
|
||||
{"nAddCircle", "(JFFFI)V", (void*)SkPathGlue::addCircle},
|
||||
{"nAddArc", "(JFFFFFF)V", (void*)SkPathGlue::addArc},
|
||||
{"nAddRoundRect", "(JFFFFFFI)V", (void*)SkPathGlue::addRoundRectXY},
|
||||
{"nAddRoundRect", "(JFFFF[FI)V", (void*)SkPathGlue::addRoundRect8},
|
||||
{"nAddPath", "(JJFF)V", (void*)SkPathGlue::addPath__PathFF},
|
||||
{"nAddPath", "(JJ)V", (void*)SkPathGlue::addPath__Path},
|
||||
{"nAddPath", "(JJJ)V", (void*)SkPathGlue::addPath__PathMatrix},
|
||||
{"nInterpolate", "(JJFJ)Z", (void*)SkPathGlue::interpolate},
|
||||
{"nOffset", "(JFF)V", (void*)SkPathGlue::offset__FF},
|
||||
{"nSetLastPoint", "(JFF)V", (void*)SkPathGlue::setLastPoint},
|
||||
{"nTransform", "(JJJ)V", (void*)SkPathGlue::transform__MatrixPath},
|
||||
{"nTransform", "(JJ)V", (void*)SkPathGlue::transform__Matrix},
|
||||
{"nOp", "(JJIJ)Z", (void*)SkPathGlue::op},
|
||||
{"nApproximate", "(JF)[F", (void*)SkPathGlue::approximate},
|
||||
|
||||
// ------- @FastNative below here ----------------------
|
||||
{"nIsRect","(JLandroid/graphics/RectF;)Z", (void*) SkPathGlue::isRect},
|
||||
// ------- @FastNative below here ----------------------
|
||||
{"nIsRect", "(JLandroid/graphics/RectF;)Z", (void*)SkPathGlue::isRect},
|
||||
|
||||
// ------- @CriticalNative below here ------------------
|
||||
{"nReset","(J)V", (void*) SkPathGlue::reset},
|
||||
{"nRewind","(J)V", (void*) SkPathGlue::rewind},
|
||||
{"nIsEmpty","(J)Z", (void*) SkPathGlue::isEmpty},
|
||||
{"nIsConvex","(J)Z", (void*) SkPathGlue::isConvex},
|
||||
{"nGetFillType","(J)I", (void*) SkPathGlue::getFillType},
|
||||
{"nSetFillType","(JI)V", (void*) SkPathGlue::setFillType},
|
||||
// ------- @CriticalNative below here ------------------
|
||||
{"nGetGenerationID", "(J)I", (void*)SkPathGlue::getGenerationID},
|
||||
{"nIsInterpolatable", "(JJ)Z", (void*)SkPathGlue::isInterpolatable},
|
||||
{"nReset", "(J)V", (void*)SkPathGlue::reset},
|
||||
{"nRewind", "(J)V", (void*)SkPathGlue::rewind},
|
||||
{"nIsEmpty", "(J)Z", (void*)SkPathGlue::isEmpty},
|
||||
{"nIsConvex", "(J)Z", (void*)SkPathGlue::isConvex},
|
||||
{"nGetFillType", "(J)I", (void*)SkPathGlue::getFillType},
|
||||
{"nSetFillType", "(JI)V", (void*)SkPathGlue::setFillType},
|
||||
};
|
||||
|
||||
int register_android_graphics_Path(JNIEnv* env) {
|
||||
|
||||
81
libs/hwui/jni/PathIterator.cpp
Normal file
81
libs/hwui/jni/PathIterator.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/* libs/android_runtime/android/graphics/PathMeasure.cpp
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
#include "GraphicsJNI.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPoint.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class SkPathIteratorGlue {
|
||||
public:
|
||||
static void finalizer(SkPath::RawIter* obj) { delete obj; }
|
||||
|
||||
static jlong getFinalizer(JNIEnv* env, jclass clazz) {
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer));
|
||||
}
|
||||
|
||||
static jlong create(JNIEnv* env, jobject clazz, jlong pathHandle) {
|
||||
const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
|
||||
return reinterpret_cast<jlong>(new SkPath::RawIter(*path));
|
||||
}
|
||||
|
||||
// ---------------- @CriticalNative -------------------------
|
||||
|
||||
static jint peek(CRITICAL_JNI_PARAMS_COMMA jlong iteratorHandle) {
|
||||
SkPath::RawIter* iterator = reinterpret_cast<SkPath::RawIter*>(iteratorHandle);
|
||||
return iterator->peek();
|
||||
}
|
||||
|
||||
static jint next(CRITICAL_JNI_PARAMS_COMMA jlong iteratorHandle, jlong pointsArray) {
|
||||
static_assert(SkPath::kMove_Verb == 0, "SkPath::Verb unexpected index");
|
||||
static_assert(SkPath::kLine_Verb == 1, "SkPath::Verb unexpected index");
|
||||
static_assert(SkPath::kQuad_Verb == 2, "SkPath::Verb unexpected index");
|
||||
static_assert(SkPath::kConic_Verb == 3, "SkPath::Verb unexpected index");
|
||||
static_assert(SkPath::kCubic_Verb == 4, "SkPath::Verb unexpected index");
|
||||
static_assert(SkPath::kClose_Verb == 5, "SkPath::Verb unexpected index");
|
||||
static_assert(SkPath::kDone_Verb == 6, "SkPath::Verb unexpected index");
|
||||
|
||||
SkPath::RawIter* iterator = reinterpret_cast<SkPath::RawIter*>(iteratorHandle);
|
||||
float* points = reinterpret_cast<float*>(pointsArray);
|
||||
SkPath::Verb verb =
|
||||
static_cast<SkPath::Verb>(iterator->next(reinterpret_cast<SkPoint*>(points)));
|
||||
if (verb == SkPath::kConic_Verb) {
|
||||
float weight = iterator->conicWeight();
|
||||
points[6] = weight;
|
||||
}
|
||||
return static_cast<int>(verb);
|
||||
}
|
||||
};
|
||||
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nCreate", "(J)J", (void*)SkPathIteratorGlue::create},
|
||||
{"nGetFinalizer", "()J", (void*)SkPathIteratorGlue::getFinalizer},
|
||||
|
||||
// ------- @CriticalNative below here ------------------
|
||||
|
||||
{"nPeek", "(J)I", (void*)SkPathIteratorGlue::peek},
|
||||
{"nNext", "(JJ)I", (void*)SkPathIteratorGlue::next},
|
||||
};
|
||||
|
||||
int register_android_graphics_PathIterator(JNIEnv* env) {
|
||||
return RegisterMethodsOrDie(env, "android/graphics/PathIterator", methods, NELEM(methods));
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
Reference in New Issue
Block a user