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

Commit b10a1d8a authored by Doris Liu's avatar Doris Liu Committed by Android (Google) Code Review
Browse files

Merge "VectorDrawable native rendering - Step 2 of MANY"

parents 4d859fdb 804618d0
Loading
Loading
Loading
Loading
+27 −56
Original line number Diff line number Diff line
@@ -250,50 +250,19 @@ public class AnimatorInflater {
    /**
     * PathDataEvaluator is used to interpolate between two paths which are
     * represented in the same format but different control points' values.
     * The path is represented as an array of PathDataNode here, which is
     * fundamentally an array of floating point numbers.
     * The path is represented as verbs and points for each of the verbs.
     */
    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> {
        private PathParser.PathDataNode[] mNodeArray;

        /**
         * Create a PathParser.PathDataNode[] that does not reuse the animated value.
         * Care must be taken when using this option because on every evaluation
         * a new <code>PathParser.PathDataNode[]</code> will be allocated.
         */
        private PathDataEvaluator() {}

        /**
         * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
         * Caution must be taken to ensure that the value returned from
         * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
         * used across threads. The value will be modified on each <code>evaluate()</code> call.
         *
         * @param nodeArray The array to modify and return from <code>evaluate</code>.
         */
        public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) {
            mNodeArray = nodeArray;
        }
    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathData> {
        private final PathParser.PathData mPathData = new PathParser.PathData();

        @Override
        public PathParser.PathDataNode[] evaluate(float fraction,
                PathParser.PathDataNode[] startPathData,
                PathParser.PathDataNode[] endPathData) {
            if (!PathParser.canMorph(startPathData, endPathData)) {
        public PathParser.PathData evaluate(float fraction, PathParser.PathData startPathData,
                    PathParser.PathData endPathData) {
            if (!PathParser.interpolatePathData(mPathData, startPathData, endPathData, fraction)) {
                throw new IllegalArgumentException("Can't interpolate between"
                        + " two incompatible pathData");
            }

            if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) {
                mNodeArray = PathParser.deepCopyNodes(startPathData);
            }

            for (int i = 0; i < startPathData.length; i++) {
                mNodeArray[i].interpolatePathDataNode(startPathData[i],
                        endPathData[i], fraction);
            }

            return mNodeArray;
            return mPathData;
        }
    }

@@ -323,13 +292,14 @@ public class AnimatorInflater {
        if (valueType == VALUE_TYPE_PATH) {
            String fromString = styledAttributes.getString(valueFromId);
            String toString = styledAttributes.getString(valueToId);
            PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
            PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
            PathParser.PathData nodesFrom = fromString == null
                    ? null : new PathParser.PathData(fromString);
            PathParser.PathData nodesTo = toString == null
                    ? null : new PathParser.PathData(toString);

            if (nodesFrom != null || nodesTo != null) {
                if (nodesFrom != null) {
                    TypeEvaluator evaluator =
                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
                    TypeEvaluator evaluator = new PathDataEvaluator();
                    if (nodesTo != null) {
                        if (!PathParser.canMorph(nodesFrom, nodesTo)) {
                            throw new InflateException(" Can't morph from " + fromString + " to " +
@@ -342,8 +312,7 @@ public class AnimatorInflater {
                                (Object) nodesFrom);
                    }
                } else if (nodesTo != null) {
                    TypeEvaluator evaluator =
                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
                    TypeEvaluator evaluator = new PathDataEvaluator();
                    returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
                            (Object) nodesTo);
                }
@@ -484,23 +453,25 @@ public class AnimatorInflater {
        TypeEvaluator evaluator = null;
        String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
        String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
        PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
        PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);

        if (nodesFrom != null) {
            if (nodesTo != null) {
                anim.setObjectValues(nodesFrom, nodesTo);
                if (!PathParser.canMorph(nodesFrom, nodesTo)) {
        PathParser.PathData pathDataFrom = fromString == null
                ? null : new PathParser.PathData(fromString);
        PathParser.PathData pathDataTo = toString == null
                ? null : new PathParser.PathData(toString);

        if (pathDataFrom != null) {
            if (pathDataTo != null) {
                anim.setObjectValues(pathDataFrom, pathDataTo);
                if (!PathParser.canMorph(pathDataFrom, pathDataTo)) {
                    throw new InflateException(arrayAnimator.getPositionDescription()
                            + " Can't morph from " + fromString + " to " + toString);
                }
            } else {
                anim.setObjectValues((Object)nodesFrom);
                anim.setObjectValues((Object)pathDataFrom);
            }
            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
        } else if (nodesTo != null) {
            anim.setObjectValues((Object)nodesTo);
            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
            evaluator = new PathDataEvaluator();
        } else if (pathDataTo != null) {
            anim.setObjectValues((Object)pathDataTo);
            evaluator = new PathDataEvaluator();
        }

        if (DBG_ANIMATOR_INFLATER && evaluator != null) {
+61 −634

File changed.

Preview size limit exceeded, changes collapsed.

+72 −3
Original line number Diff line number Diff line
@@ -18,19 +18,22 @@

#include <PathParser.h>
#include <SkPath.h>
#include <utils/VectorDrawableUtils.h>

#include <android/log.h>
#include "core_jni_helpers.h"

namespace android {

using namespace uirenderer;

static bool parseStringForPath(JNIEnv* env, jobject, jlong skPathHandle, jstring inputPathStr,
        jint strLength) {
    const char* pathString = env->GetStringUTFChars(inputPathStr, NULL);
    SkPath* skPath = reinterpret_cast<SkPath*>(skPathHandle);

    android::uirenderer::PathParser::ParseResult result;
    android::uirenderer::PathParser::parseStringForSkPath(skPath, &result, pathString, strLength);
    PathParser::ParseResult result;
    PathParser::parseStringForSkPath(skPath, &result, pathString, strLength);
    env->ReleaseStringUTFChars(inputPathStr, pathString);
    if (result.failureOccurred) {
        ALOGE(result.failureMessage.c_str());
@@ -38,8 +41,74 @@ static bool parseStringForPath(JNIEnv* env, jobject, jlong skPathHandle, jstring
    return !result.failureOccurred;
}

static long createEmptyPathData(JNIEnv*, jobject) {
    PathData* pathData = new PathData();
    return reinterpret_cast<jlong>(pathData);
}

static long createPathData(JNIEnv*, jobject, jlong pathDataPtr) {
    PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
    PathData* newPathData = new PathData(*pathData);
    return reinterpret_cast<jlong>(newPathData);
}

static long createPathDataFromStringPath(JNIEnv* env, jobject, jstring inputStr, jint strLength) {
    const char* pathString = env->GetStringUTFChars(inputStr, NULL);
    PathData* pathData = new PathData();
    PathParser::ParseResult result;
    PathParser::getPathDataFromString(pathData, &result, pathString, strLength);
    env->ReleaseStringUTFChars(inputStr, pathString);
    if (!result.failureOccurred) {
        return reinterpret_cast<jlong>(pathData);
    } else {
        delete pathData;
        ALOGE(result.failureMessage.c_str());
        return NULL;
    }
}

static bool interpolatePathData(JNIEnv*, jobject, jlong outPathDataPtr, jlong fromPathDataPtr,
        jlong toPathDataPtr, jfloat fraction) {
    PathData* outPathData = reinterpret_cast<PathData*>(outPathDataPtr);
    PathData* fromPathData = reinterpret_cast<PathData*>(fromPathDataPtr);
    PathData* toPathData = reinterpret_cast<PathData*>(toPathDataPtr);
    return VectorDrawableUtils::interpolatePathData(outPathData, *fromPathData,
            *toPathData, fraction);
}

static void deletePathData(JNIEnv*, jobject, jlong pathDataHandle) {
    PathData* pathData = reinterpret_cast<PathData*>(pathDataHandle);
    delete pathData;
}

static bool canMorphPathData(JNIEnv*, jobject, jlong fromPathDataPtr, jlong toPathDataPtr) {
    PathData* fromPathData = reinterpret_cast<PathData*>(fromPathDataPtr);
    PathData* toPathData = reinterpret_cast<PathData*>(toPathDataPtr);
    return VectorDrawableUtils::canMorph(*fromPathData, *toPathData);
}

static void setPathData(JNIEnv*, jobject, jlong outPathDataPtr, jlong fromPathDataPtr) {
    PathData* fromPathData = reinterpret_cast<PathData*>(fromPathDataPtr);
    PathData* outPathData = reinterpret_cast<PathData*>(outPathDataPtr);
    *outPathData = *fromPathData;
}

static void setSkPathFromPathData(JNIEnv*, jobject, jlong outPathPtr, jlong pathDataPtr) {
    PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
    SkPath* skPath = reinterpret_cast<SkPath*>(outPathPtr);
    VectorDrawableUtils::verbsToPath(skPath, *pathData);
}

static const JNINativeMethod gMethods[] = {
    {"nParseStringForPath", "(JLjava/lang/String;I)Z", (void*)parseStringForPath}
    {"nParseStringForPath", "(JLjava/lang/String;I)Z", (void*)parseStringForPath},
    {"nCreateEmptyPathData", "!()J", (void*)createEmptyPathData},
    {"nCreatePathData", "!(J)J", (void*)createPathData},
    {"nCreatePathDataFromString", "(Ljava/lang/String;I)J", (void*)createPathDataFromStringPath},
    {"nInterpolatePathData", "!(JJJF)Z", (void*)interpolatePathData},
    {"nFinalize", "!(J)V", (void*)deletePathData},
    {"nCanMorph", "!(JJ)Z", (void*)canMorphPathData},
    {"nSetPathData", "!(JJ)V", (void*)setPathData},
    {"nCreatePathFromPathData", "!(JJ)V", (void*)setSkPathFromPathData},
};

int register_android_util_PathParser(JNIEnv* env) {
+15 −19
Original line number Diff line number Diff line
@@ -1321,7 +1321,7 @@ public class VectorDrawable extends Drawable {
     * Common Path information for clip path and normal path.
     */
    private static abstract class VPath implements VObject {
        protected PathParser.PathDataNode[] mNodes = null;
        protected PathParser.PathData mPathData = null;
        String mPathName;
        int mChangingConfigurations;

@@ -1332,7 +1332,7 @@ public class VectorDrawable extends Drawable {
        public VPath(VPath copy) {
            mPathName = copy.mPathName;
            mChangingConfigurations = copy.mChangingConfigurations;
            mNodes = PathParser.deepCopyNodes(copy.mNodes);
            mPathData = copy.mPathData == null ? null : new PathParser.PathData(copy.mPathData);
        }

        public String getPathName() {
@@ -1345,18 +1345,14 @@ public class VectorDrawable extends Drawable {

        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
        @SuppressWarnings("unused")
        public PathParser.PathDataNode[] getPathData() {
            return mNodes;
        public PathParser.PathData getPathData() {
            return mPathData;
        }

        // TODO: Move the PathEvaluator and this setter and the getter above into native.
        @SuppressWarnings("unused")
        public void setPathData(PathParser.PathDataNode[] nodes) {
            if (!PathParser.canMorph(mNodes, nodes)) {
                // This should not happen in the middle of animation.
                mNodes = PathParser.deepCopyNodes(nodes);
            } else {
                PathParser.updateNodes(mNodes, nodes);
            }
        public void setPathData(PathParser.PathData pathData) {
            mPathData.setPathData(pathData);
        }

        @Override
@@ -1392,8 +1388,8 @@ public class VectorDrawable extends Drawable {
         * @param outPath the output path
         */
        protected void toPath(TempState temp, Path outPath) {
            if (mNodes != null) {
                PathParser.PathDataNode.nodesToPath(mNodes, outPath);
            if (mPathData != null) {
                PathParser.createPathFromPathData(outPath, mPathData);
            }
        }

@@ -1488,9 +1484,9 @@ public class VectorDrawable extends Drawable {
                mPathName = pathName;
            }

            final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
            if (pathData != null) {
                mNodes = PathParser.createNodesFromPathData(pathData);
            final String pathDataString = a.getString(R.styleable.VectorDrawableClipPath_pathData);
            if (pathDataString != null) {
                mPathData = new PathParser.PathData(pathDataString);
            }
        }

@@ -1719,9 +1715,9 @@ public class VectorDrawable extends Drawable {
                mPathName = pathName;
            }

            final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
            if (pathData != null) {
                mNodes = PathParser.createNodesFromPathData(pathData);
            final String pathString = a.getString(R.styleable.VectorDrawablePath_pathData);
            if (pathString != null) {
                mPathData = new PathParser.PathData(pathString);
            }

            final ColorStateList fillColors = a.getColorStateList(
+2 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ hwui_src_files := \
    utils/NinePatchImpl.cpp \
    utils/StringUtils.cpp \
    utils/TestWindowContext.cpp \
    utils/VectorDrawableUtils.cpp \
    AmbientShadow.cpp \
    AnimationContext.cpp \
    Animator.cpp \
@@ -218,7 +219,7 @@ LOCAL_SRC_FILES += \
    unit_tests/FatVectorTests.cpp \
    unit_tests/LayerUpdateQueueTests.cpp \
    unit_tests/LinearAllocatorTests.cpp \
    unit_tests/PathParserTests.cpp \
    unit_tests/VectorDrawableTests.cpp \
    unit_tests/OffscreenBufferPoolTests.cpp \
    unit_tests/StringUtilsTests.cpp

Loading