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

Commit 7fe03a26 authored by George Mount's avatar George Mount
Browse files

Add Path trimming.

Change-Id: Iafcf127a5136883ad4c0185d3c15f96d67f38d0d
parent 3732f8d0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9712,6 +9712,8 @@ package android.graphics {
    method public void toggleInverseFillType();
    method public void transform(android.graphics.Matrix, android.graphics.Path);
    method public void transform(android.graphics.Matrix);
    method public void trim(float, float, float);
    method public void trim(float, float, float, android.graphics.Path);
  }
  public static final class Path.Direction extends java.lang.Enum {
+50 −2
Original line number Diff line number Diff line
@@ -268,7 +268,6 @@ public:
         return Op(*p1, *p2, op, r);
     }


    typedef SkPoint (*bezierCalculation)(float t, const SkPoint* points);

    static void addMove(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths,
@@ -396,6 +395,8 @@ public:
                addMove(segmentPoints, lengths, points[0]);
                break;
            case SkPath::kClose_Verb:
                addLine(segmentPoints, lengths, points[0]);
                break;
            case SkPath::kLine_Verb:
                addLine(segmentPoints, lengths, points[1]);
                break;
@@ -445,7 +446,7 @@ public:
        float totalLength = lengths.back();

        int approximationIndex = 0;
        for (int i = 0; i < numPoints; i++) {
        for (size_t i = 0; i < numPoints; i++) {
            const SkPoint& point = segmentPoints[i];
            approximation[approximationIndex++] = lengths[i] / totalLength;
            approximation[approximationIndex++] = point.x();
@@ -457,6 +458,51 @@ public:
        delete[] approximation;
        return result;
    }

    static SkPathMeasure* trim(JNIEnv* env, jobject clazz, SkPath* inPath, SkPath* outPath,
            SkPathMeasure* pathMeasure, jfloat trimStart, jfloat trimEnd, jfloat trimOffset) {
        if (trimStart == 0 && trimEnd == 1) {
            if (outPath != NULL) {
                *outPath = *inPath;
            }
            return pathMeasure;
        }

        bool modifyPath = (outPath == NULL);
        if (modifyPath) {
            outPath = new SkPath();
        } else {
            outPath->reset();
        }
        if (pathMeasure == NULL) {
            pathMeasure = new SkPathMeasure(*inPath, false);
        }
        float length = pathMeasure->getLength();
        float start = (trimStart + trimOffset) * length;
        float end = (trimEnd + trimOffset) * length;

        if (end > length && start <= length) {
            pathMeasure->getSegment(start, length, outPath, true);
            pathMeasure->getSegment(0, end - length, outPath, true);
        } else {
            if (start > length) {
                start -= length;
                end -= length;
            }
            pathMeasure->getSegment(start, end, outPath, true);
        }
        if (modifyPath) {
            delete pathMeasure;
            pathMeasure = NULL;
            *inPath = *outPath;
            delete outPath;
        }
        return pathMeasure;
    }

    static void destroyMeasure(JNIEnv* env, jobject clazz, SkPathMeasure* measure) {
        delete measure;
    }
};

static JNINativeMethod methods[] = {
@@ -499,6 +545,8 @@ static JNINativeMethod methods[] = {
    {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix},
    {"native_op","(IIII)Z", (void*) SkPathGlue::op},
    {"native_approximate", "(IF)[F", (void*) SkPathGlue::approximate},
    {"native_destroyMeasure","(I)V", (void*) SkPathGlue::destroyMeasure},
    {"native_trim","(IIIFFF)I", (void*) SkPathGlue::trim},
};

int register_android_graphics_Path(JNIEnv* env) {
+117 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ public class Path {
     * @hide
     */
    public final int mNativePath;
    private int mNativePathMeasure;

    /**
     * @hide
@@ -76,6 +77,14 @@ public class Path {
        final FillType fillType = getFillType();
        native_reset(mNativePath);
        setFillType(fillType);
        clearMeasure();
    }

    private void clearMeasure() {
        if (mNativePathMeasure != 0) {
            native_destroyMeasure(mNativePathMeasure);
            mNativePathMeasure = 0;
        }
    }

    /**
@@ -87,6 +96,7 @@ public class Path {
        mLastDirection = null;
        if (rects != null) rects.setEmpty();
        native_rewind(mNativePath);
        clearMeasure();
    }

    /** Replace the contents of this with the contents of src.
@@ -95,6 +105,7 @@ public class Path {
        if (this != src) {
            isSimplePath = src.isSimplePath;
            native_set(mNativePath, src.mNativePath);
            clearMeasure();
        }
    }

@@ -223,6 +234,7 @@ public class Path {
     */
    public void setFillType(FillType ft) {
        native_setFillType(mNativePath, ft.nativeInt);
        clearMeasure();
    }
    
    /**
@@ -242,6 +254,7 @@ public class Path {
        int ft = native_getFillType(mNativePath);
        ft ^= 2;
        native_setFillType(mNativePath, ft);
        clearMeasure();
    }
    
    /**
@@ -298,6 +311,7 @@ public class Path {
     */
    public void moveTo(float x, float y) {
        native_moveTo(mNativePath, x, y);
        clearMeasure();
    }

    /**
@@ -312,6 +326,7 @@ public class Path {
     */
    public void rMoveTo(float dx, float dy) {
        native_rMoveTo(mNativePath, dx, dy);
        clearMeasure();
    }

    /**
@@ -325,6 +340,7 @@ public class Path {
    public void lineTo(float x, float y) {
        isSimplePath = false;
        native_lineTo(mNativePath, x, y);
        clearMeasure();
    }

    /**
@@ -340,6 +356,7 @@ public class Path {
    public void rLineTo(float dx, float dy) {
        isSimplePath = false;
        native_rLineTo(mNativePath, dx, dy);
        clearMeasure();
    }

    /**
@@ -355,6 +372,7 @@ public class Path {
    public void quadTo(float x1, float y1, float x2, float y2) {
        isSimplePath = false;
        native_quadTo(mNativePath, x1, y1, x2, y2);
        clearMeasure();
    }

    /**
@@ -374,6 +392,7 @@ public class Path {
    public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
        isSimplePath = false;
        native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
        clearMeasure();
    }

    /**
@@ -392,6 +411,7 @@ public class Path {
                        float x3, float y3) {
        isSimplePath = false;
        native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
        clearMeasure();
    }

    /**
@@ -403,6 +423,7 @@ public class Path {
                         float x3, float y3) {
        isSimplePath = false;
        native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
        clearMeasure();
    }

    /**
@@ -422,6 +443,7 @@ public class Path {
                      boolean forceMoveTo) {
        isSimplePath = false;
        native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
        clearMeasure();
    }
    
    /**
@@ -438,6 +460,7 @@ public class Path {
    public void arcTo(RectF oval, float startAngle, float sweepAngle) {
        isSimplePath = false;
        native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
        clearMeasure();
    }
    
    /**
@@ -447,6 +470,7 @@ public class Path {
    public void close() {
        isSimplePath = false;
        native_close(mNativePath);
        clearMeasure();
    }

    /**
@@ -489,6 +513,7 @@ public class Path {
        }
        detectSimplePath(rect.left, rect.top, rect.right, rect.bottom, dir);
        native_addRect(mNativePath, rect, dir.nativeInt);
        clearMeasure();
    }

    /**
@@ -503,6 +528,7 @@ public class Path {
    public void addRect(float left, float top, float right, float bottom, Direction dir) {
        detectSimplePath(left, top, right, bottom, dir);
        native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
        clearMeasure();
    }

    /**
@@ -517,6 +543,7 @@ public class Path {
        }
        isSimplePath = false;
        native_addOval(mNativePath, oval, dir.nativeInt);
        clearMeasure();
    }

    /**
@@ -530,6 +557,7 @@ public class Path {
    public void addCircle(float x, float y, float radius, Direction dir) {
        isSimplePath = false;
        native_addCircle(mNativePath, x, y, radius, dir.nativeInt);
        clearMeasure();
    }

    /**
@@ -545,6 +573,7 @@ public class Path {
        }
        isSimplePath = false;
        native_addArc(mNativePath, oval, startAngle, sweepAngle);
        clearMeasure();
    }

    /**
@@ -561,6 +590,7 @@ public class Path {
        }
        isSimplePath = false;
        native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
        clearMeasure();
    }
    
    /**
@@ -581,6 +611,7 @@ public class Path {
        }
        isSimplePath = false;
        native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
        clearMeasure();
    }
    
    /**
@@ -592,6 +623,7 @@ public class Path {
    public void addPath(Path src, float dx, float dy) {
        isSimplePath = false;
        native_addPath(mNativePath, src.mNativePath, dx, dy);
        clearMeasure();
    }

    /**
@@ -602,6 +634,7 @@ public class Path {
    public void addPath(Path src) {
        isSimplePath = false;
        native_addPath(mNativePath, src.mNativePath);
        clearMeasure();
    }

    /**
@@ -612,6 +645,7 @@ public class Path {
    public void addPath(Path src, Matrix matrix) {
        if (!src.isSimplePath) isSimplePath = false;
        native_addPath(mNativePath, src.mNativePath, matrix.native_instance);
        clearMeasure();
    }

    /**
@@ -629,6 +663,11 @@ public class Path {
            dst.isSimplePath = false;
        }
        native_offset(mNativePath, dx, dy, dstNative);
        if (dst != null) {
            dst.clearMeasure();
        } else {
            clearMeasure();
        }
    }

    /**
@@ -640,6 +679,7 @@ public class Path {
    public void offset(float dx, float dy) {
        isSimplePath = false;
        native_offset(mNativePath, dx, dy);
        clearMeasure();
    }

    /**
@@ -651,6 +691,7 @@ public class Path {
    public void setLastPoint(float dx, float dy) {
        isSimplePath = false;
        native_setLastPoint(mNativePath, dx, dy);
        clearMeasure();
    }

    /**
@@ -668,6 +709,11 @@ public class Path {
            dstNative = dst.mNativePath;
        }
        native_transform(mNativePath, matrix.native_instance, dstNative);
        if (dst != null) {
            dst.clearMeasure();
        } else {
            clearMeasure();
        }
    }

    /**
@@ -678,10 +724,14 @@ public class Path {
    public void transform(Matrix matrix) {
        isSimplePath = false;
        native_transform(mNativePath, matrix.native_instance);
        clearMeasure();
    }

    protected void finalize() throws Throwable {
        try {
            if (mNativePathMeasure != 0) {
                native_destroyMeasure(mNativePathMeasure);
            }
            finalizer(mNativePath);
        } finally {
            super.finalize();
@@ -714,6 +764,70 @@ public class Path {
        return native_approximate(mNativePath, acceptableError);
    }

    /**
     * Modifies the <code>Path</code> by extracting a portion of it.
     * The portion of the <code>Path</code> used is between <code>trimStart</code> and
     * <code>trimEnd</code> with the value offset by <code>trimOffset</code>. When
     * <code>trimOffset</code> added to <code>trimEnd</code> is greater than 1, the
     * trimmed portion "wraps" to the start of the <code>Path</code>.
     * <p>For example, if <code>Path</code> is a circle and <code>trimStart</code> is 0
     * and <code>trimEnd</code> is 0.5, the resulting <code>Path</code> is the arc of
     * a semicircle. If <code>trimOffset</code> is set to 0.75, the arc will start at
     * 3/4 of the circle and continue to the end of the circle, then start again at the
     * beginning of the circle and end at 1/4 of the way around. It will appear as if
     * the semicircle arc wrapped around the <code>Path</code> start and end.</p>
     * @param trimStart A number between 0 and <code>trimEnd</code> indicating the fraction of the
     *                  <code>Path</code> to start. A value of 0 trims nothing from the start.
     * @param trimEnd A number between <code>trimStart</code> and 1 indicating the fraction of the
     *                <code>Path</code> to end. A value of 1 trims nothing from the end.
     * @param trimOffset A fraction between 0 and 1 indicating the offset of the trimmed
     *                   portion of the <code>Path</code>.
     * @see #trim(float, float, float, Path)
     */
    public void trim(float trimStart, float trimEnd, float trimOffset) {
        trim(trimStart, trimEnd, trimOffset, null);
    }

    /**
     * Extracts a portion of the <code>Path</code> and writes it to <code>dst</code>.
     * The portion of the <code>Path</code> used is between <code>trimStart</code> and
     * <code>trimEnd</code> with the value offset by <code>trimOffset</code>. When
     * <code>trimOffset</code> added to <code>trimEnd</code> is greater than 1, the
     * trimmed portion "wraps" to the start of the <code>Path</code>.
     * <p>For example, if <code>Path</code> is a circle and <code>trimStart</code> is 0
     * and <code>trimEnd</code> is 0.5, the resulting <code>Path</code> is the arc of
     * a semicircle. If <code>trimOffset</code> is set to 0.75, the arc will start at
     * 3/4 of the circle and continue to the end of the circle, then start again at the
     * beginning of the circle and end at 1/4 of the way around. It will appear as if
     * the semicircle arc wrapped around the <code>Path</code> start and end.</p>
     * @param trimStart A number between 0 and <code>trimEnd</code> indicating the fraction of the
     *                  <code>Path</code> to start. A value of 0 trims nothing from the start.
     * @param trimEnd A number between <code>trimStart</code> and 1 indicating the fraction of the
     *                <code>Path</code> to end. A value of 1 trims nothing from the end.
     * @param trimOffset A fraction between 0 and 1 indicating the offset of the trimmed
     *                   portion of the <code>Path</code>.
     * @param dst The trimmed <code>Path</code> is written here. If <code>dst</code> is null,
     *            then the original <code>Path</code> is modified.
     * @see #trim(float, float, float)
     */
    public void trim(float trimStart, float trimEnd, float trimOffset, Path dst) {
        if (trimStart > 1 || trimEnd > 1 || trimOffset > 1
                || trimStart < 0 || trimEnd < 0 || trimOffset < 0) {
            throw new IllegalArgumentException("trim must be between 0 and 1");
        }
        if (trimStart > trimEnd) {
            throw new IllegalArgumentException("trim end cannot be less than start");
        }
        int dstNative = 0;
        if (dst != null) {
            dstNative = dst.mNativePath;
            dst.isSimplePath = false;
            dst.clearMeasure();
        }
        mNativePathMeasure = native_trim(mNativePath, dstNative, mNativePathMeasure,
                trimStart, trimEnd, trimOffset);
    }

    private static native int init1();
    private static native int init2(int nPath);
    private static native void native_reset(int nPath);
@@ -761,4 +875,7 @@ public class Path {
    private static native boolean native_op(int path1, int path2, int op, int result);
    private static native void finalizer(int nPath);
    private static native float[] native_approximate(int nPath, float error);
    private static native int native_trim(int nPath, int nTargetPath, int nPathMeasure,
            float trimStart, float trimEnd, float trimOffset);
    private static native void native_destroyMeasure(int nPathMeasure);
}