Moved AnimatableValue parsing to Parser classes
diff --git a/lottie/src/main/java/com/airbnb/lottie/animation/keyframe/PathKeyframe.java b/lottie/src/main/java/com/airbnb/lottie/animation/keyframe/PathKeyframe.java index 375143c..ac161dc 100644 --- a/lottie/src/main/java/com/airbnb/lottie/animation/keyframe/PathKeyframe.java +++ b/lottie/src/main/java/com/airbnb/lottie/animation/keyframe/PathKeyframe.java
@@ -8,8 +8,8 @@ import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; -import com.airbnb.lottie.model.animatable.AnimatableValue; import com.airbnb.lottie.parser.KeyframeParser; +import com.airbnb.lottie.parser.ValueParser; import com.airbnb.lottie.utils.Utils; import java.io.IOException; @@ -36,10 +36,10 @@ } public static PathKeyframe newInstance(JsonReader reader, LottieComposition composition, - AnimatableValue.Factory<PointF> valueFactory) throws IOException { + ValueParser<PointF> valueParser) throws IOException { boolean animated = reader.peek() == JsonToken.BEGIN_OBJECT; Keyframe<PointF> keyframe = KeyframeParser.parse( - reader, composition, Utils.dpScale(), valueFactory, animated); + reader, composition, Utils.dpScale(), valueParser, animated); return new PathKeyframe(composition, keyframe); }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableColorValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableColorValue.java index 0ef8568..a6302e5 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableColorValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableColorValue.java
@@ -1,33 +1,17 @@ package com.airbnb.lottie.model.animatable; -import android.util.JsonReader; - -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.ColorKeyframeAnimation; -import com.airbnb.lottie.model.ColorFactory; -import java.io.IOException; import java.util.List; public class AnimatableColorValue extends BaseAnimatableValue<Integer, Integer> { - private AnimatableColorValue(List<Keyframe<Integer>> keyframes) { + public AnimatableColorValue(List<Keyframe<Integer>> keyframes) { super(keyframes); } @Override public BaseKeyframeAnimation<Integer, Integer> createAnimation() { return new ColorKeyframeAnimation(keyframes); } - - public static final class Factory { - private Factory() { - } - - public static AnimatableColorValue newInstance( - JsonReader reader, LottieComposition composition) throws IOException { - return new AnimatableColorValue( - AnimatableValueParser.newInstance(reader, 1f, composition, ColorFactory.INSTANCE)); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableFloatValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableFloatValue.java index b887665..0d372dd 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableFloatValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableFloatValue.java
@@ -1,20 +1,14 @@ package com.airbnb.lottie.model.animatable; -import android.util.JsonReader; - -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.FloatKeyframeAnimation; -import com.airbnb.lottie.utils.JsonUtils; -import com.airbnb.lottie.utils.Utils; -import java.io.IOException; import java.util.List; public class AnimatableFloatValue extends BaseAnimatableValue<Float, Float> { - private AnimatableFloatValue() { + AnimatableFloatValue() { this(0f); } @@ -22,43 +16,11 @@ super(value); } - private AnimatableFloatValue(List<Keyframe<Float>> keyframes) { + public AnimatableFloatValue(List<Keyframe<Float>> keyframes) { super(keyframes); } @Override public BaseKeyframeAnimation<Float, Float> createAnimation() { return new FloatKeyframeAnimation(keyframes); } - - private static class ValueFactory implements AnimatableValue.Factory<Float> { - static final ValueFactory INSTANCE = new ValueFactory(); - - private ValueFactory() { - } - - @Override public Float valueFromObject(JsonReader reader, float scale) throws IOException { - return JsonUtils.valueFromObject(reader) * scale; - } - } - - public static final class Factory { - private Factory() { - } - - static AnimatableFloatValue newInstance() { - return new AnimatableFloatValue(); - } - - public static AnimatableFloatValue newInstance(JsonReader reader, LottieComposition composition) - throws IOException { - return newInstance(reader, composition, true); - } - - public static AnimatableFloatValue newInstance( - JsonReader reader, LottieComposition composition, boolean isDp) throws IOException { - float scale = isDp ? Utils.dpScale() : 1f; - return new AnimatableFloatValue( - AnimatableValueParser.newInstance(reader, scale, composition, ValueFactory.INSTANCE)); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableGradientColorValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableGradientColorValue.java index 91d8558..66cc706 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableGradientColorValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableGradientColorValue.java
@@ -1,26 +1,15 @@ package com.airbnb.lottie.model.animatable; -import android.graphics.Color; -import android.support.annotation.IntRange; -import android.util.JsonReader; -import android.util.JsonToken; -import android.util.Log; - -import com.airbnb.lottie.L; -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.GradientColorKeyframeAnimation; import com.airbnb.lottie.model.content.GradientColor; -import com.airbnb.lottie.utils.MiscUtils; -import java.io.IOException; -import java.util.ArrayList; import java.util.List; public class AnimatableGradientColorValue extends BaseAnimatableValue<GradientColor, GradientColor> { - private AnimatableGradientColorValue( + public AnimatableGradientColorValue( List<Keyframe<GradientColor>> keyframes) { super(keyframes); } @@ -28,154 +17,4 @@ @Override public BaseKeyframeAnimation<GradientColor, GradientColor> createAnimation() { return new GradientColorKeyframeAnimation(keyframes); } - - public static final class Factory { - private Factory() { - } - - public static AnimatableGradientColorValue newInstance( - JsonReader reader, LottieComposition composition, int points) throws IOException { - return new AnimatableGradientColorValue( - AnimatableValueParser.newInstance(reader, 1, composition, new ValueFactory(points)) - ); - } - } - - private static class ValueFactory implements AnimatableValue.Factory<GradientColor> { - /** The number of colors if it exists in the json or -1 if it doesn't (legacy bodymovin) */ - private int colorPoints; - - private ValueFactory(int colorPoints) { - this.colorPoints = colorPoints; - } - - /** - * Both the color stops and opacity stops are in the same array. - * There are {@link #colorPoints} colors sequentially as: - * [ - * ..., - * position, - * red, - * green, - * blue, - * ... - * ] - * - * The remainder of the array is the opacity stops sequentially as: - * [ - * ..., - * position, - * opacity, - * ... - * ] - */ - @Override public GradientColor valueFromObject(JsonReader reader, float scale) - throws IOException { - List<Float> array = new ArrayList<>(); - // The array was started by Keyframe because it thought that this may be an array of keyframes - // but peek returned a number so it considered it a static array of numbers. - boolean isArray = reader.peek() == JsonToken.BEGIN_ARRAY; - if (isArray) { - reader.beginArray(); - } - while (reader.hasNext()) { - array.add((float) reader.nextDouble()); - } - if(isArray) { - reader.endArray(); - } - if (colorPoints == -1) { - colorPoints = array.size() / 4; - } - - float[] positions = new float[colorPoints]; - int[] colors = new int[colorPoints]; - - int r = 0; - int g = 0; - if (array.size() != colorPoints * 4) { - Log.w(L.TAG, "Unexpected gradient length: " + array.size() + - ". Expected " + (colorPoints * 4) + ". This may affect the appearance of the gradient. " + - "Make sure to save your After Effects file before exporting an animation with " + - "gradients."); - } - for (int i = 0; i < colorPoints * 4; i++) { - int colorIndex = i / 4; - double value = array.get(i); - switch (i % 4) { - case 0: - // position - positions[colorIndex] = (float) value; - break; - case 1: - r = (int) (value * 255); - break; - case 2: - g = (int) (value * 255); - break; - case 3: - int b = (int) (value * 255); - colors[colorIndex] = Color.argb(255, r, g, b); - break; - } - } - - GradientColor gradientColor = new GradientColor(positions, colors); - addOpacityStopsToGradientIfNeeded(gradientColor, array); - return gradientColor; - } - - /** - * This cheats a little bit. - * Opacity stops can be at arbitrary intervals independent of color stops. - * This uses the existing color stops and modifies the opacity at each existing color stop - * based on what the opacity would be. - * - * This should be a good approximation is nearly all cases. However, if there are many more - * opacity stops than color stops, information will be lost. - */ - private void addOpacityStopsToGradientIfNeeded(GradientColor gradientColor, List<Float> array) { - int startIndex = colorPoints * 4; - if (array.size() <= startIndex) { - return; - } - - int opacityStops = (array.size() - startIndex) / 2; - double[] positions = new double[opacityStops]; - double[] opacities = new double[opacityStops]; - - for (int i = startIndex, j = 0; i < array.size(); i++) { - if (i % 2 == 0) { - positions[j] = array.get(i); - } else { - opacities[j] = array.get(i); - j++; - } - } - - for (int i = 0; i < gradientColor.getSize(); i++) { - int color = gradientColor.getColors()[i]; - color = Color.argb( - getOpacityAtPosition(gradientColor.getPositions()[i], positions, opacities), - Color.red(color), - Color.green(color), - Color.blue(color) - ); - gradientColor.getColors()[i] = color; - } - } - - @IntRange(from=0, to=255) - private int getOpacityAtPosition(double position, double[] positions, double[] opacities) { - for (int i = 1; i < positions.length; i++) { - double lastPosition = positions[i - 1]; - double thisPosition = positions[i]; - if (positions[i] >= position) { - double progress = (position - lastPosition) / (thisPosition - lastPosition); - return (int) (255 * MiscUtils.lerp(opacities[i - 1], opacities[i], progress)); - } - } - return (int) (255 * opacities[opacities.length - 1]); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableIntegerValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableIntegerValue.java index 642d3a3..3d0311a 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableIntegerValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableIntegerValue.java
@@ -1,19 +1,14 @@ package com.airbnb.lottie.model.animatable; -import android.util.JsonReader; - -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.IntegerKeyframeAnimation; -import com.airbnb.lottie.utils.JsonUtils; -import java.io.IOException; import java.util.List; public class AnimatableIntegerValue extends BaseAnimatableValue<Integer, Integer> { - private AnimatableIntegerValue() { + public AnimatableIntegerValue() { this(100); } @@ -21,38 +16,11 @@ super(value); } - AnimatableIntegerValue(List<Keyframe<Integer>> keyframes) { + public AnimatableIntegerValue(List<Keyframe<Integer>> keyframes) { super(keyframes); } @Override public BaseKeyframeAnimation<Integer, Integer> createAnimation() { return new IntegerKeyframeAnimation(keyframes); } - - public static final class Factory { - private Factory() { - } - - static AnimatableIntegerValue newInstance() { - return new AnimatableIntegerValue(); - } - - public static AnimatableIntegerValue newInstance( - JsonReader reader, LottieComposition composition) throws IOException { - return new AnimatableIntegerValue( - AnimatableValueParser.newInstance(reader, 1, composition, ValueFactory.INSTANCE) - ); - } - } - - private static class ValueFactory implements AnimatableValue.Factory<Integer> { - private static final ValueFactory INSTANCE = new ValueFactory(); - - private ValueFactory() { - } - - @Override public Integer valueFromObject(JsonReader reader, float scale) throws IOException { - return Math.round(JsonUtils.valueFromObject(reader) * scale); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePathValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePathValue.java index 458b7c2..945f3e3 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePathValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePathValue.java
@@ -10,7 +10,9 @@ import com.airbnb.lottie.animation.keyframe.PathKeyframe; import com.airbnb.lottie.animation.keyframe.PathKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.PointKeyframeAnimation; +import com.airbnb.lottie.parser.AnimatableValueParser; import com.airbnb.lottie.parser.KeyframesParser; +import com.airbnb.lottie.parser.PathParser; import com.airbnb.lottie.utils.JsonUtils; import com.airbnb.lottie.utils.Utils; @@ -39,7 +41,7 @@ hasExpressions = true; reader.skipValue(); } else { - xAnimation = AnimatableFloatValue.Factory.newInstance(reader, composition); + xAnimation = AnimatableValueParser.parseFloat(reader, composition); } break; case "y": @@ -47,7 +49,7 @@ hasExpressions = true; reader.skipValue(); } else { - yAnimation = AnimatableFloatValue.Factory.newInstance(reader, composition); + yAnimation = AnimatableValueParser.parseFloat(reader, composition); } break; default: @@ -80,7 +82,7 @@ reader.beginArray(); while (reader.hasNext()) { PathKeyframe keyframe = - PathKeyframe.Factory.newInstance(reader, composition, ValueFactory.INSTANCE); + PathKeyframe.Factory.newInstance(reader, composition, PathParser.INSTANCE); keyframes.add(keyframe); } reader.endArray(); @@ -97,15 +99,4 @@ } return new PathKeyframeAnimation(keyframes); } - - private static class ValueFactory implements AnimatableValue.Factory<PointF> { - private static final Factory<PointF> INSTANCE = new ValueFactory(); - - private ValueFactory() { - } - - @Override public PointF valueFromObject(JsonReader reader, float scale) throws IOException { - return JsonUtils.jsonToPoint(reader, scale); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePointValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePointValue.java index e01be61..4f48692 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePointValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatablePointValue.java
@@ -1,36 +1,19 @@ package com.airbnb.lottie.model.animatable; import android.graphics.PointF; -import android.util.JsonReader; -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.PointKeyframeAnimation; -import com.airbnb.lottie.model.PointFFactory; -import com.airbnb.lottie.utils.Utils; -import java.io.IOException; import java.util.List; public class AnimatablePointValue extends BaseAnimatableValue<PointF, PointF> { - private AnimatablePointValue(List<Keyframe<PointF>> keyframes) { + public AnimatablePointValue(List<Keyframe<PointF>> keyframes) { super(keyframes); } @Override public BaseKeyframeAnimation<PointF, PointF> createAnimation() { return new PointKeyframeAnimation(keyframes); } - - public static final class Factory { - private Factory() { - } - - public static AnimatablePointValue newInstance( - JsonReader reader, LottieComposition composition) throws IOException { - return new AnimatablePointValue(AnimatableValueParser - .newInstance(reader, Utils.dpScale(), composition, PointFFactory.INSTANCE) - ); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableScaleValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableScaleValue.java index 322ad2c..af2c0b3 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableScaleValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableScaleValue.java
@@ -1,19 +1,15 @@ package com.airbnb.lottie.model.animatable; -import android.util.JsonReader; - -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.ScaleKeyframeAnimation; import com.airbnb.lottie.value.ScaleXY; -import java.io.IOException; import java.util.List; public class AnimatableScaleValue extends BaseAnimatableValue<ScaleXY, ScaleXY> { - private AnimatableScaleValue() { + AnimatableScaleValue() { this(new ScaleXY(1f, 1f)); } @@ -21,27 +17,11 @@ super(value); } - AnimatableScaleValue(List<Keyframe<ScaleXY>> keyframes) { + public AnimatableScaleValue(List<Keyframe<ScaleXY>> keyframes) { super(keyframes); } @Override public BaseKeyframeAnimation<ScaleXY, ScaleXY> createAnimation() { return new ScaleKeyframeAnimation(keyframes); } - - static final class Factory { - private Factory() { - } - - static AnimatableScaleValue newInstance( - JsonReader reader, LottieComposition composition) throws IOException { - return new AnimatableScaleValue( - AnimatableValueParser.newInstance(reader, 1, composition, ScaleXY.Factory.INSTANCE) - ); - } - - static AnimatableScaleValue newInstance() { - return new AnimatableScaleValue(); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableShapeValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableShapeValue.java index 37e5cf4..d5c3236 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableShapeValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableShapeValue.java
@@ -1,37 +1,21 @@ package com.airbnb.lottie.model.animatable; import android.graphics.Path; -import android.util.JsonReader; -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; import com.airbnb.lottie.animation.keyframe.ShapeKeyframeAnimation; import com.airbnb.lottie.model.content.ShapeData; -import com.airbnb.lottie.utils.Utils; -import java.io.IOException; import java.util.List; public class AnimatableShapeValue extends BaseAnimatableValue<ShapeData, Path> { - private AnimatableShapeValue(List<Keyframe<ShapeData>> keyframes) { + public AnimatableShapeValue(List<Keyframe<ShapeData>> keyframes) { super(keyframes); } @Override public BaseKeyframeAnimation<ShapeData, Path> createAnimation() { return new ShapeKeyframeAnimation(keyframes); } - - public static final class Factory { - private Factory() { - } - - public static AnimatableShapeValue newInstance( - JsonReader reader, LottieComposition composition) throws IOException { - return new AnimatableShapeValue(AnimatableValueParser - .newInstance(reader, Utils.dpScale(), composition, ShapeData.Factory.INSTANCE) - ); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableSplitDimensionPathValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableSplitDimensionPathValue.java index 442ac03..3fbf5a6 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableSplitDimensionPathValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableSplitDimensionPathValue.java
@@ -20,5 +20,4 @@ return new SplitDimensionPathKeyframeAnimation( animatableXDimension.createAnimation(), animatableYDimension.createAnimation()); } - }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextFrame.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextFrame.java index 8edb499..054e6a3 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextFrame.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextFrame.java
@@ -1,48 +1,18 @@ package com.airbnb.lottie.model.animatable; -import android.util.JsonReader; - -import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; import com.airbnb.lottie.animation.keyframe.TextKeyframeAnimation; import com.airbnb.lottie.model.DocumentData; -import com.airbnb.lottie.parser.DocumentDataParser; -import java.io.IOException; import java.util.List; public class AnimatableTextFrame extends BaseAnimatableValue<DocumentData, DocumentData> { - AnimatableTextFrame(List<Keyframe<DocumentData>> keyframes) { + public AnimatableTextFrame(List<Keyframe<DocumentData>> keyframes) { super(keyframes); } @Override public TextKeyframeAnimation createAnimation() { return new TextKeyframeAnimation(keyframes); } - - public static final class Factory { - private Factory() { - } - - public static AnimatableTextFrame newInstance( - JsonReader reader, LottieComposition composition) throws IOException { - return new AnimatableTextFrame( - AnimatableValueParser - .newInstance(reader, 1, composition, AnimatableTextFrame.ValueFactory.INSTANCE)); - } - } - - private static class ValueFactory implements AnimatableValue.Factory<DocumentData> { - private static final AnimatableTextFrame.ValueFactory INSTANCE = - new AnimatableTextFrame.ValueFactory(); - - private ValueFactory() { - } - - @Override - public DocumentData valueFromObject(JsonReader reader, float scale) throws IOException { - return DocumentDataParser.parse(reader); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java index 6ffa4a8..6e3a8a5 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java
@@ -4,6 +4,7 @@ import android.util.JsonReader; import com.airbnb.lottie.LottieComposition; +import com.airbnb.lottie.parser.AnimatableValueParser; import java.io.IOException; @@ -61,16 +62,16 @@ while (reader.hasNext()) { switch (reader.nextName()) { case "fc": - color = AnimatableColorValue.Factory.newInstance(reader, composition); + color = AnimatableValueParser.parseColor(reader, composition); break; case "sc": - stroke = AnimatableColorValue.Factory.newInstance(reader, composition); + stroke = AnimatableValueParser.parseColor(reader, composition); break; case "sw": - strokeWidth = AnimatableFloatValue.Factory.newInstance(reader, composition); + strokeWidth = AnimatableValueParser.parseFloat(reader, composition); break; case "t": - tracking = AnimatableFloatValue.Factory.newInstance(reader, composition); + tracking = AnimatableValueParser.parseFloat(reader, composition); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTransform.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTransform.java index 5aa5aac..c448934 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTransform.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTransform.java
@@ -14,6 +14,7 @@ import com.airbnb.lottie.animation.keyframe.TransformKeyframeAnimation; import com.airbnb.lottie.model.content.ContentModel; import com.airbnb.lottie.model.layer.BaseLayer; +import com.airbnb.lottie.parser.AnimatableValueParser; import com.airbnb.lottie.value.ScaleXY; import java.io.IOException; @@ -85,11 +86,11 @@ public static AnimatableTransform newInstance() { AnimatablePathValue anchorPoint = new AnimatablePathValue(); AnimatableValue<PointF, PointF> position = new AnimatablePathValue(); - AnimatableScaleValue scale = AnimatableScaleValue.Factory.newInstance(); - AnimatableFloatValue rotation = AnimatableFloatValue.Factory.newInstance(); - AnimatableIntegerValue opacity = AnimatableIntegerValue.Factory.newInstance(); - AnimatableFloatValue startOpacity = AnimatableFloatValue.Factory.newInstance(); - AnimatableFloatValue endOpacity = AnimatableFloatValue.Factory.newInstance(); + AnimatableScaleValue scale = new AnimatableScaleValue(); + AnimatableFloatValue rotation = new AnimatableFloatValue(); + AnimatableIntegerValue opacity = new AnimatableIntegerValue(); + AnimatableFloatValue startOpacity = new AnimatableFloatValue(); + AnimatableFloatValue endOpacity = new AnimatableFloatValue(); return new AnimatableTransform(anchorPoint, position, scale, rotation, opacity, startOpacity, endOpacity); } @@ -126,23 +127,21 @@ AnimatablePathValue.createAnimatablePathOrSplitDimensionPath(reader, composition); break; case "s": - scale = AnimatableScaleValue.Factory.newInstance(reader, composition); + scale = AnimatableValueParser.parseScale(reader, composition); break; case "rz": composition.addWarning("Lottie doesn't support 3D layers."); case "r": - rotation = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + rotation = AnimatableValueParser.parseFloat(reader, composition, false); break; case "o": - opacity = AnimatableIntegerValue.Factory.newInstance(reader, composition); + opacity = AnimatableValueParser.parseInteger(reader, composition); break; case "so": - startOpacity = - AnimatableFloatValue.Factory.newInstance(reader, composition, false); + startOpacity = AnimatableValueParser.parseFloat(reader, composition, false); break; case "eo": - endOpacity = - AnimatableFloatValue.Factory.newInstance(reader, composition, false); + endOpacity = AnimatableValueParser.parseFloat(reader, composition, false); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValue.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValue.java index 4da1429..b8fb1cb 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValue.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValue.java
@@ -1,15 +1,7 @@ package com.airbnb.lottie.model.animatable; -import android.util.JsonReader; - import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation; -import java.io.IOException; - public interface AnimatableValue<K, A> { BaseKeyframeAnimation<K, A> createAnimation(); - - interface Factory<V> { - V valueFromObject(JsonReader reader, float scale) throws IOException; - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValueParser.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValueParser.java deleted file mode 100644 index 45cfaa9..0000000 --- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableValueParser.java +++ /dev/null
@@ -1,43 +0,0 @@ -package com.airbnb.lottie.model.animatable; - -import android.support.annotation.Nullable; -import android.util.JsonReader; - -import com.airbnb.lottie.LottieComposition; -import com.airbnb.lottie.animation.Keyframe; -import com.airbnb.lottie.parser.KeyframesParser; - -import java.io.IOException; -import java.util.List; - -class AnimatableValueParser<T> { - private final JsonReader reader; - private final float scale; - private final LottieComposition composition; - private final AnimatableValue.Factory<T> valueFactory; - - private AnimatableValueParser(JsonReader reader, float scale, LottieComposition - composition, AnimatableValue.Factory<T> valueFactory) { - this.reader = reader; - this.scale = scale; - this.composition = composition; - this.valueFactory = valueFactory; - } - - /** - * Will return null if the animation can't be played such as if it has expressions. - */ - @Nullable static <T> List<Keyframe<T>> newInstance(JsonReader reader, float scale, - LottieComposition composition, AnimatableValue.Factory<T> valueFactory) throws IOException { - AnimatableValueParser<T> parser = - new AnimatableValueParser<>(reader, scale, composition, valueFactory); - return parser.parseKeyframes(); - } - - /** - * Will return null if the animation can't be played such as if it has expressions. - */ - private List<Keyframe<T>> parseKeyframes() throws IOException { - return KeyframesParser.parse(reader, composition, scale, valueFactory); - } -}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java b/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java index 051afe2..849b286 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java
@@ -7,6 +7,7 @@ import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.model.animatable.AnimatableIntegerValue; import com.airbnb.lottie.model.animatable.AnimatableShapeValue; +import com.airbnb.lottie.parser.AnimatableValueParser; import java.io.IOException; @@ -58,10 +59,10 @@ } break; case "pt": - maskPath = AnimatableShapeValue.Factory.newInstance(reader, composition); + maskPath = AnimatableValueParser.parseShapeData(reader, composition); break; case "o": - opacity = AnimatableIntegerValue.Factory.newInstance(reader, composition); + opacity = AnimatableValueParser.parseInteger(reader, composition); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java b/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java index f09404b..4c9b0b2 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/content/ShapeData.java
@@ -2,17 +2,11 @@ import android.graphics.PointF; import android.support.annotation.FloatRange; -import android.util.JsonReader; -import android.util.JsonToken; import com.airbnb.lottie.model.CubicCurveData; -import com.airbnb.lottie.model.animatable.AnimatableValue; -import com.airbnb.lottie.utils.JsonUtils; import com.airbnb.lottie.utils.MiscUtils; -import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class ShapeData { @@ -20,7 +14,7 @@ private PointF initialPoint; private boolean closed; - private ShapeData(PointF initialPoint, boolean closed, List<CubicCurveData> curves) { + public ShapeData(PointF initialPoint, boolean closed, List<CubicCurveData> curves) { this.initialPoint = initialPoint; this.closed = closed; this.curves.addAll(curves); @@ -102,84 +96,4 @@ "closed=" + closed + '}'; } - - public static class Factory implements AnimatableValue.Factory<ShapeData> { - public static final ShapeData.Factory INSTANCE = new Factory(); - - private Factory() { - } - - @Override public ShapeData valueFromObject(JsonReader reader, float scale) throws IOException { - // Sometimes the points data is in a array of length 1. Sometimes the data is at the top - // level. - if (reader.peek() == JsonToken.BEGIN_ARRAY) { - reader.beginArray(); - } - - boolean closed = false; - List<PointF> pointsArray = null; - List<PointF> inTangents = null; - List<PointF> outTangents = null; - reader.beginObject(); - - while (reader.hasNext()) { - switch (reader.nextName()) { - case "c": - closed = reader.nextBoolean(); - break; - case "v": - pointsArray = JsonUtils.jsonToPoints(reader, scale); - break; - case "i": - inTangents = JsonUtils.jsonToPoints(reader, scale); - break; - case "o": - outTangents = JsonUtils.jsonToPoints(reader, scale); - break; - } - } - - reader.endObject(); - - if (reader.peek() == JsonToken.END_ARRAY) { - reader.endArray(); - } - - if (pointsArray == null || inTangents == null || outTangents == null) { - throw new IllegalArgumentException("Shape data was missing information."); - } - - if (pointsArray.isEmpty()) { - return new ShapeData(new PointF(), false, Collections.<CubicCurveData>emptyList()); - } - - int length = pointsArray.size(); - PointF vertex = pointsArray.get(0); - PointF initialPoint = vertex; - List<CubicCurveData> curves = new ArrayList<>(length); - - for (int i = 1; i < length; i++) { - vertex = pointsArray.get(i); - PointF previousVertex = pointsArray.get(i - 1); - PointF cp1 = outTangents.get(i - 1); - PointF cp2 = inTangents.get(i); - PointF shapeCp1 = MiscUtils.addPoints(previousVertex, cp1); - PointF shapeCp2 = MiscUtils.addPoints(vertex, cp2); - curves.add(new CubicCurveData(shapeCp1, shapeCp2, vertex)); - } - - if (closed) { - vertex = pointsArray.get(0); - PointF previousVertex = pointsArray.get(length - 1); - PointF cp1 = outTangents.get(length - 1); - PointF cp2 = inTangents.get(0); - - PointF shapeCp1 = MiscUtils.addPoints(previousVertex, cp1); - PointF shapeCp2 = MiscUtils.addPoints(vertex, cp2); - - curves.add(new CubicCurveData(shapeCp1, shapeCp2, vertex)); - } - return new ShapeData(initialPoint, closed, curves); - } - } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableValueParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableValueParser.java new file mode 100644 index 0000000..231788e --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableValueParser.java
@@ -0,0 +1,89 @@ +package com.airbnb.lottie.parser; + +import android.support.annotation.Nullable; +import android.util.JsonReader; + +import com.airbnb.lottie.LottieComposition; +import com.airbnb.lottie.animation.Keyframe; +import com.airbnb.lottie.model.animatable.AnimatableColorValue; +import com.airbnb.lottie.model.animatable.AnimatableFloatValue; +import com.airbnb.lottie.model.animatable.AnimatableGradientColorValue; +import com.airbnb.lottie.model.animatable.AnimatableIntegerValue; +import com.airbnb.lottie.model.animatable.AnimatablePointValue; +import com.airbnb.lottie.model.animatable.AnimatableScaleValue; +import com.airbnb.lottie.model.animatable.AnimatableShapeValue; +import com.airbnb.lottie.model.animatable.AnimatableTextFrame; +import com.airbnb.lottie.utils.Utils; + +import java.io.IOException; +import java.util.List; + +public class AnimatableValueParser { + private AnimatableValueParser() { + } + + public static AnimatableFloatValue parseFloat( + JsonReader reader, LottieComposition composition) throws IOException { + return parseFloat(reader, composition, true); + } + + public static AnimatableFloatValue parseFloat( + JsonReader reader, LottieComposition composition, boolean isDp) throws IOException { + return new AnimatableFloatValue( + parse(reader, isDp ? Utils.dpScale() : 1f, composition, FloatParser.INSTANCE)); + } + + public static AnimatableIntegerValue parseInteger( + JsonReader reader, LottieComposition composition) throws IOException { + return new AnimatableIntegerValue(parse(reader, composition, IntegerParser.INSTANCE)); + } + + public static AnimatablePointValue parsePoint( + JsonReader reader, LottieComposition composition) throws IOException { + return new AnimatablePointValue( + parse(reader, Utils.dpScale(), composition, PointFParser.INSTANCE)); + } + + public static AnimatableScaleValue parseScale( + JsonReader reader, LottieComposition composition) throws IOException { + return new AnimatableScaleValue(parse(reader, composition, ScaleXYParser.INSTANCE)); + } + + public static AnimatableShapeValue parseShapeData( + JsonReader reader, LottieComposition composition) throws IOException { + return new AnimatableShapeValue( + parse(reader, Utils.dpScale(), composition, ShapeDataParser.INSTANCE)); + } + + public static AnimatableTextFrame parseDocumentData( + JsonReader reader, LottieComposition composition) throws IOException { + return new AnimatableTextFrame(parse(reader, composition, DocumentDataParser.INSTANCE)); + } + + public static AnimatableColorValue parseColor( + JsonReader reader, LottieComposition composition) throws IOException { + return new AnimatableColorValue(parse(reader, composition, ColorParser.INSTANCE)); + } + + public static AnimatableGradientColorValue parseGradientColor( + JsonReader reader, LottieComposition composition, int points) throws IOException { + return new AnimatableGradientColorValue( + parse(reader, composition, new GradientColorParser(points))); + } + + /** + * Will return null if the animation can't be played such as if it has expressions. + */ + @Nullable private static <T> List<Keyframe<T>> parse(JsonReader reader, + LottieComposition composition, ValueParser<T> valueParser) throws IOException { + return KeyframesParser.parse(reader, composition, 1, valueParser); + } + + /** + * Will return null if the animation can't be played such as if it has expressions. + */ + @Nullable private static <T> List<Keyframe<T>> parse(JsonReader reader, float scale, + LottieComposition composition, ValueParser<T> valueParser) throws IOException { + return KeyframesParser.parse(reader, composition, scale, valueParser); + } +}
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/CircleShapeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/CircleShapeParser.java index 8165086..8a56358 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/CircleShapeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/CircleShapeParser.java
@@ -32,7 +32,7 @@ .createAnimatablePathOrSplitDimensionPath(reader, composition); break; case "s": - size = AnimatablePointValue.Factory.newInstance(reader, composition); + size = AnimatableValueParser.parsePoint(reader, composition); break; case "d": // "d" is 2 for normal and 3 for reversed.
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/ColorFactory.java b/lottie/src/main/java/com/airbnb/lottie/parser/ColorParser.java similarity index 65% rename from lottie/src/main/java/com/airbnb/lottie/model/ColorFactory.java rename to lottie/src/main/java/com/airbnb/lottie/parser/ColorParser.java index 2cd6b80..c3193e3 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/ColorFactory.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ColorParser.java
@@ -1,17 +1,17 @@ -package com.airbnb.lottie.model; +package com.airbnb.lottie.parser; import android.graphics.Color; import android.util.JsonReader; import android.util.JsonToken; -import com.airbnb.lottie.model.animatable.AnimatableValue; - import java.io.IOException; -public class ColorFactory implements AnimatableValue.Factory<Integer> { - public static final ColorFactory INSTANCE = new ColorFactory(); +public class ColorParser implements ValueParser<Integer> { + public static final ColorParser INSTANCE = new ColorParser(); - @Override public Integer valueFromObject(JsonReader reader, float scale) throws IOException { + private ColorParser() {} + + @Override public Integer parse(JsonReader reader, float scale) throws IOException { boolean isArray = reader.peek() == JsonToken.BEGIN_ARRAY; if (isArray) { reader.beginArray();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/DocumentDataParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/DocumentDataParser.java index 37b51c8..1321023 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/DocumentDataParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/DocumentDataParser.java
@@ -7,11 +7,16 @@ import java.io.IOException; -public class DocumentDataParser { +public class DocumentDataParser implements ValueParser<DocumentData> { + public static DocumentDataParser INSTANCE = new DocumentDataParser(); private DocumentDataParser() {} public static DocumentData parse(JsonReader reader) throws IOException { + return INSTANCE.parse(reader, 1f); + } + + @Override public DocumentData parse(JsonReader reader, float scale) throws IOException { String text = null; String fontName = null; double size = 0;
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/FloatParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/FloatParser.java new file mode 100644 index 0000000..4525928 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/FloatParser.java
@@ -0,0 +1,17 @@ +package com.airbnb.lottie.parser; + +import android.util.JsonReader; + +import com.airbnb.lottie.utils.JsonUtils; + +import java.io.IOException; + +public class FloatParser implements ValueParser<Float> { + public static final FloatParser INSTANCE = new FloatParser(); + + private FloatParser() {} + + @Override public Float parse(JsonReader reader, float scale) throws IOException { + return JsonUtils.valueFromObject(reader) * scale; + } +} \ No newline at end of file
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/GradientColorParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/GradientColorParser.java new file mode 100644 index 0000000..bf380e5 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/GradientColorParser.java
@@ -0,0 +1,153 @@ +package com.airbnb.lottie.parser; + +import android.graphics.Color; +import android.support.annotation.IntRange; +import android.util.JsonReader; +import android.util.JsonToken; +import android.util.Log; + +import com.airbnb.lottie.L; +import com.airbnb.lottie.model.content.GradientColor; +import com.airbnb.lottie.utils.MiscUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class GradientColorParser implements com.airbnb.lottie.parser.ValueParser<GradientColor> { + /** The number of colors if it exists in the json or -1 if it doesn't (legacy bodymovin) */ + private int colorPoints; + + public GradientColorParser(int colorPoints) { + this.colorPoints = colorPoints; + } + + /** + * Both the color stops and opacity stops are in the same array. + * There are {@link #colorPoints} colors sequentially as: + * [ + * ..., + * position, + * red, + * green, + * blue, + * ... + * ] + * + * The remainder of the array is the opacity stops sequentially as: + * [ + * ..., + * position, + * opacity, + * ... + * ] + */ + @Override public GradientColor parse(JsonReader reader, float scale) + throws IOException { + List<Float> array = new ArrayList<>(); + // The array was started by Keyframe because it thought that this may be an array of keyframes + // but peek returned a number so it considered it a static array of numbers. + boolean isArray = reader.peek() == JsonToken.BEGIN_ARRAY; + if (isArray) { + reader.beginArray(); + } + while (reader.hasNext()) { + array.add((float) reader.nextDouble()); + } + if(isArray) { + reader.endArray(); + } + if (colorPoints == -1) { + colorPoints = array.size() / 4; + } + + float[] positions = new float[colorPoints]; + int[] colors = new int[colorPoints]; + + int r = 0; + int g = 0; + if (array.size() != colorPoints * 4) { + Log.w(L.TAG, "Unexpected gradient length: " + array.size() + + ". Expected " + (colorPoints * 4) + ". This may affect the appearance of the gradient. " + + "Make sure to save your After Effects file before exporting an animation with " + + "gradients."); + } + for (int i = 0; i < colorPoints * 4; i++) { + int colorIndex = i / 4; + double value = array.get(i); + switch (i % 4) { + case 0: + // position + positions[colorIndex] = (float) value; + break; + case 1: + r = (int) (value * 255); + break; + case 2: + g = (int) (value * 255); + break; + case 3: + int b = (int) (value * 255); + colors[colorIndex] = Color.argb(255, r, g, b); + break; + } + } + + GradientColor gradientColor = new GradientColor(positions, colors); + addOpacityStopsToGradientIfNeeded(gradientColor, array); + return gradientColor; + } + + /** + * This cheats a little bit. + * Opacity stops can be at arbitrary intervals independent of color stops. + * This uses the existing color stops and modifies the opacity at each existing color stop + * based on what the opacity would be. + * + * This should be a good approximation is nearly all cases. However, if there are many more + * opacity stops than color stops, information will be lost. + */ + private void addOpacityStopsToGradientIfNeeded(GradientColor gradientColor, List<Float> array) { + int startIndex = colorPoints * 4; + if (array.size() <= startIndex) { + return; + } + + int opacityStops = (array.size() - startIndex) / 2; + double[] positions = new double[opacityStops]; + double[] opacities = new double[opacityStops]; + + for (int i = startIndex, j = 0; i < array.size(); i++) { + if (i % 2 == 0) { + positions[j] = array.get(i); + } else { + opacities[j] = array.get(i); + j++; + } + } + + for (int i = 0; i < gradientColor.getSize(); i++) { + int color = gradientColor.getColors()[i]; + color = Color.argb( + getOpacityAtPosition(gradientColor.getPositions()[i], positions, opacities), + Color.red(color), + Color.green(color), + Color.blue(color) + ); + gradientColor.getColors()[i] = color; + } + } + + @IntRange(from=0, to=255) + private int getOpacityAtPosition(double position, double[] positions, double[] opacities) { + for (int i = 1; i < positions.length; i++) { + double lastPosition = positions[i - 1]; + double thisPosition = positions[i]; + if (positions[i] >= position) { + double progress = (position - lastPosition) / (thisPosition - lastPosition); + return (int) (255 * MiscUtils.lerp(opacities[i - 1], opacities[i], progress)); + } + } + return (int) (255 * opacities[opacities.length - 1]); + } +} \ No newline at end of file
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/GradientFillParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/GradientFillParser.java index 3392632..1fa5a32 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/GradientFillParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/GradientFillParser.java
@@ -40,8 +40,7 @@ points = reader.nextInt(); break; case "k": - color = AnimatableGradientColorValue.Factory - .newInstance(reader, composition, points); + color = AnimatableValueParser.parseGradientColor(reader, composition, points); break; default: reader.skipValue(); @@ -50,16 +49,16 @@ reader.endObject(); break; case "o": - opacity = AnimatableIntegerValue.Factory.newInstance(reader, composition); + opacity = AnimatableValueParser.parseInteger(reader, composition); break; case "t": gradientType = reader.nextInt() == 1 ? GradientType.Linear : GradientType.Radial; break; case "s": - startPoint = AnimatablePointValue.Factory.newInstance(reader, composition); + startPoint = AnimatableValueParser.parsePoint(reader, composition); break; case "e": - endPoint = AnimatablePointValue.Factory.newInstance(reader, composition); + endPoint = AnimatableValueParser.parsePoint(reader, composition); break; case "r": fillType = reader.nextInt() == 1 ? Path.FillType.WINDING : Path.FillType.EVEN_ODD;
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/GradientStrokeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/GradientStrokeParser.java index f612a4c..b182624 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/GradientStrokeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/GradientStrokeParser.java
@@ -49,8 +49,7 @@ points = reader.nextInt(); break; case "k": - color = AnimatableGradientColorValue.Factory - .newInstance(reader, composition, points); + color = AnimatableValueParser.parseGradientColor(reader, composition, points); break; default: reader.skipValue(); @@ -59,19 +58,19 @@ reader.endObject(); break; case "o": - opacity = AnimatableIntegerValue.Factory.newInstance(reader, composition); + opacity = AnimatableValueParser.parseInteger(reader, composition); break; case "t": gradientType = reader.nextInt() == 1 ? GradientType.Linear : GradientType.Radial; break; case "s": - startPoint = AnimatablePointValue.Factory.newInstance(reader, composition); + startPoint = AnimatableValueParser.parsePoint(reader, composition); break; case "e": - endPoint = AnimatablePointValue.Factory.newInstance(reader, composition); + endPoint = AnimatableValueParser.parsePoint(reader, composition); break; case "w": - width = AnimatableFloatValue.Factory.newInstance(reader, composition); + width = AnimatableValueParser.parseFloat(reader, composition); break; case "lc": capType = ShapeStroke.LineCapType.values()[reader.nextInt() - 1]; @@ -91,7 +90,7 @@ n = reader.nextString(); break; case "v": - val = AnimatableFloatValue.Factory.newInstance(reader, composition); + val = AnimatableValueParser.parseFloat(reader, composition); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/IntegerParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/IntegerParser.java new file mode 100644 index 0000000..6f30557 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/IntegerParser.java
@@ -0,0 +1,17 @@ +package com.airbnb.lottie.parser; + +import android.util.JsonReader; + +import com.airbnb.lottie.utils.JsonUtils; + +import java.io.IOException; + +public class IntegerParser implements ValueParser<Integer> { + public static final IntegerParser INSTANCE = new IntegerParser(); + + private IntegerParser() {} + + @Override public Integer parse(JsonReader reader, float scale) throws IOException { + return Math.round(JsonUtils.valueFromObject(reader) * scale); + } +}
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java index 10f8b01..0dfcba9 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/KeyframeParser.java
@@ -10,7 +10,6 @@ import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; -import com.airbnb.lottie.model.animatable.AnimatableValue; import com.airbnb.lottie.utils.JsonUtils; import com.airbnb.lottie.utils.MiscUtils; import com.airbnb.lottie.utils.Utils; @@ -54,12 +53,12 @@ } public static <T> Keyframe<T> parse(JsonReader reader, LottieComposition composition, - float scale, AnimatableValue.Factory<T> valueFactory, boolean animated) throws IOException { + float scale, ValueParser<T> valueParser, boolean animated) throws IOException { if (animated) { - return parseKeyframe(composition, reader, scale, valueFactory); + return parseKeyframe(composition, reader, scale, valueParser); } else { - return parseStaticValue(reader, scale, valueFactory); + return parseStaticValue(reader, scale, valueParser); } } @@ -68,7 +67,7 @@ * a non animated value. */ private static <T> Keyframe<T> parseKeyframe(LottieComposition composition, JsonReader reader, - float scale, AnimatableValue.Factory<T> valueFactory) throws IOException { + float scale, ValueParser<T> valueParser) throws IOException { PointF cp1 = null; PointF cp2 = null; float startFrame = 0; @@ -88,10 +87,10 @@ startFrame = (float) reader.nextDouble(); break; case "s": - startValue = valueFactory.valueFromObject(reader, scale); + startValue = valueParser.parse(reader, scale); break; case "e": - endValue = valueFactory.valueFromObject(reader, scale); + endValue = valueParser.parse(reader, scale); break; case "o": cp1 = JsonUtils.jsonToPoint(reader, scale); @@ -153,8 +152,8 @@ } private static <T> Keyframe<T> parseStaticValue(JsonReader reader, - float scale, AnimatableValue.Factory<T> valueFactory) throws IOException { - T value = valueFactory.valueFromObject(reader, scale); + float scale, ValueParser<T> valueParser) throws IOException { + T value = valueParser.parse(reader, scale); return new Keyframe<>(value); } }
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/KeyframesParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/KeyframesParser.java index 0197f23..3282ced 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/KeyframesParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/KeyframesParser.java
@@ -5,7 +5,6 @@ import com.airbnb.lottie.LottieComposition; import com.airbnb.lottie.animation.Keyframe; -import com.airbnb.lottie.model.animatable.AnimatableValue; import java.io.IOException; import java.util.ArrayList; @@ -16,7 +15,7 @@ private KeyframesParser() {} public static <T> List<Keyframe<T>> parse(JsonReader reader, - LottieComposition composition, float scale, AnimatableValue.Factory<T> valueFactory) + LottieComposition composition, float scale, ValueParser<T> valueParser) throws IOException { List<Keyframe<T>> keyframes = new ArrayList<>(); @@ -35,15 +34,15 @@ if (reader.peek() == JsonToken.NUMBER) { // For properties in which the static value is an array of numbers. keyframes.add( - KeyframeParser.parse(reader, composition, scale, valueFactory, false)); + KeyframeParser.parse(reader, composition, scale, valueParser, false)); } else { while (reader.hasNext()) { - keyframes.add(KeyframeParser.parse(reader, composition, scale, valueFactory, true)); + keyframes.add(KeyframeParser.parse(reader, composition, scale, valueParser, true)); } } reader.endArray(); } else { - keyframes.add(KeyframeParser.parse(reader, composition, scale, valueFactory, false)); + keyframes.add(KeyframeParser.parse(reader, composition, scale, valueParser, false)); } break; default:
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java index 367c3aa..ca4f770 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java
@@ -120,7 +120,7 @@ while (reader.hasNext()) { switch (reader.nextName()) { case "d": - text = AnimatableTextFrame.Factory.newInstance(reader, composition); + text = AnimatableValueParser.parseDocumentData(reader, composition); break; case "a": reader.beginArray(); @@ -179,7 +179,7 @@ outFrame = (float) reader.nextDouble(); break; case "tm": - timeRemapping = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + timeRemapping = AnimatableValueParser.parseFloat(reader, composition, false); break; case "cl": cl = reader.nextString();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/PathParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/PathParser.java new file mode 100644 index 0000000..3ac33a2 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/PathParser.java
@@ -0,0 +1,18 @@ +package com.airbnb.lottie.parser; + +import android.graphics.PointF; +import android.util.JsonReader; + +import com.airbnb.lottie.utils.JsonUtils; + +import java.io.IOException; + +public class PathParser implements ValueParser<PointF> { + public static final PathParser INSTANCE = new PathParser(); + + private PathParser() {} + + @Override public PointF parse(JsonReader reader, float scale) throws IOException { + return JsonUtils.jsonToPoint(reader, scale); + } +}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/PointFFactory.java b/lottie/src/main/java/com/airbnb/lottie/parser/PointFParser.java similarity index 72% rename from lottie/src/main/java/com/airbnb/lottie/model/PointFFactory.java rename to lottie/src/main/java/com/airbnb/lottie/parser/PointFParser.java index 85f63c0..7bd19c4 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/PointFFactory.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/PointFParser.java
@@ -1,21 +1,19 @@ -package com.airbnb.lottie.model; +package com.airbnb.lottie.parser; import android.graphics.PointF; import android.util.JsonReader; import android.util.JsonToken; -import com.airbnb.lottie.model.animatable.AnimatableValue; import com.airbnb.lottie.utils.JsonUtils; import java.io.IOException; -public class PointFFactory implements AnimatableValue.Factory<PointF> { - public static final PointFFactory INSTANCE = new PointFFactory(); +public class PointFParser implements ValueParser<PointF> { + public static final PointFParser INSTANCE = new PointFParser(); - private PointFFactory() { - } + private PointFParser() {} - @Override public PointF valueFromObject(JsonReader reader, float scale) throws IOException { + @Override public PointF parse(JsonReader reader, float scale) throws IOException { JsonToken token = reader.peek(); if (token == JsonToken.BEGIN_ARRAY) { return JsonUtils.jsonToPoint(reader, scale);
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/PolystarShapeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/PolystarShapeParser.java index 2855346..376a8a9 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/PolystarShapeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/PolystarShapeParser.java
@@ -36,26 +36,26 @@ type = PolystarShape.Type.forValue(reader.nextInt()); break; case "pt": - points = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + points = AnimatableValueParser.parseFloat(reader, composition, false); break; case "p": position = AnimatablePathValue .createAnimatablePathOrSplitDimensionPath(reader, composition); break; case "r": - rotation = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + rotation = AnimatableValueParser.parseFloat(reader, composition, false); break; case "or": - outerRadius = AnimatableFloatValue.Factory.newInstance(reader, composition); + outerRadius = AnimatableValueParser.parseFloat(reader, composition); break; case "os": - outerRoundedness = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + outerRoundedness = AnimatableValueParser.parseFloat(reader, composition, false); break; case "ir": - innerRadius = AnimatableFloatValue.Factory.newInstance(reader, composition); + innerRadius = AnimatableValueParser.parseFloat(reader, composition); break; case "is": - innerRoundedness = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + innerRoundedness = AnimatableValueParser.parseFloat(reader, composition, false); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/RectangleShapeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/RectangleShapeParser.java index e077e06..487d3c5 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/RectangleShapeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/RectangleShapeParser.java
@@ -33,10 +33,10 @@ AnimatablePathValue.createAnimatablePathOrSplitDimensionPath(reader, composition); break; case "s": - size = AnimatablePointValue.Factory.newInstance(reader, composition); + size = AnimatableValueParser.parsePoint(reader, composition); break; case "r": - roundedness = AnimatableFloatValue.Factory.newInstance(reader, composition); + roundedness = AnimatableValueParser.parseFloat(reader, composition); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/RepeaterParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/RepeaterParser.java index 7664812..68b9ca8 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/RepeaterParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/RepeaterParser.java
@@ -26,10 +26,10 @@ name = reader.nextString(); break; case "c": - copies = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + copies = AnimatableValueParser.parseFloat(reader, composition, false); break; case "o": - offset = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + offset = AnimatableValueParser.parseFloat(reader, composition, false); break; case "tr": transform = AnimatableTransform.Factory.newInstance(reader, composition);
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ScaleXYParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ScaleXYParser.java new file mode 100644 index 0000000..b0bdd9d --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ScaleXYParser.java
@@ -0,0 +1,31 @@ +package com.airbnb.lottie.parser; + +import android.util.JsonReader; +import android.util.JsonToken; + +import com.airbnb.lottie.value.ScaleXY; + +import java.io.IOException; + +public class ScaleXYParser implements ValueParser<ScaleXY> { + public static final ScaleXYParser INSTANCE = new ScaleXYParser(); + + private ScaleXYParser() { + } + + @Override public ScaleXY parse(JsonReader reader, float scale) throws IOException { + boolean isArray = reader.peek() == JsonToken.BEGIN_ARRAY; + if (isArray) { + reader.beginArray(); + } + float sx = (float) reader.nextDouble(); + float sy = (float) reader.nextDouble(); + while (reader.hasNext()) { + reader.skipValue(); + } + if (isArray) { + reader.endArray(); + } + return new ScaleXY(sx / 100f * scale, sy / 100f * scale); + } +}
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeDataParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeDataParser.java new file mode 100644 index 0000000..1abe7a1 --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeDataParser.java
@@ -0,0 +1,94 @@ +package com.airbnb.lottie.parser; + +import android.graphics.PointF; +import android.util.JsonReader; +import android.util.JsonToken; + +import com.airbnb.lottie.model.CubicCurveData; +import com.airbnb.lottie.model.content.ShapeData; +import com.airbnb.lottie.utils.JsonUtils; +import com.airbnb.lottie.utils.MiscUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ShapeDataParser implements ValueParser<ShapeData> { + public static final ShapeDataParser INSTANCE = new ShapeDataParser(); + + private ShapeDataParser() {} + + @Override public ShapeData parse(JsonReader reader, float scale) throws IOException { + // Sometimes the points data is in a array of length 1. Sometimes the data is at the top + // level. + if (reader.peek() == JsonToken.BEGIN_ARRAY) { + reader.beginArray(); + } + + boolean closed = false; + List<PointF> pointsArray = null; + List<PointF> inTangents = null; + List<PointF> outTangents = null; + reader.beginObject(); + + while (reader.hasNext()) { + switch (reader.nextName()) { + case "c": + closed = reader.nextBoolean(); + break; + case "v": + pointsArray = JsonUtils.jsonToPoints(reader, scale); + break; + case "i": + inTangents = JsonUtils.jsonToPoints(reader, scale); + break; + case "o": + outTangents = JsonUtils.jsonToPoints(reader, scale); + break; + } + } + + reader.endObject(); + + if (reader.peek() == JsonToken.END_ARRAY) { + reader.endArray(); + } + + if (pointsArray == null || inTangents == null || outTangents == null) { + throw new IllegalArgumentException("Shape data was missing information."); + } + + if (pointsArray.isEmpty()) { + return new ShapeData(new PointF(), false, Collections.<CubicCurveData>emptyList()); + } + + int length = pointsArray.size(); + PointF vertex = pointsArray.get(0); + PointF initialPoint = vertex; + List<CubicCurveData> curves = new ArrayList<>(length); + + for (int i = 1; i < length; i++) { + vertex = pointsArray.get(i); + PointF previousVertex = pointsArray.get(i - 1); + PointF cp1 = outTangents.get(i - 1); + PointF cp2 = inTangents.get(i); + PointF shapeCp1 = MiscUtils.addPoints(previousVertex, cp1); + PointF shapeCp2 = MiscUtils.addPoints(vertex, cp2); + curves.add(new CubicCurveData(shapeCp1, shapeCp2, vertex)); + } + + if (closed) { + vertex = pointsArray.get(0); + PointF previousVertex = pointsArray.get(length - 1); + PointF cp1 = outTangents.get(length - 1); + PointF cp2 = inTangents.get(0); + + PointF shapeCp1 = MiscUtils.addPoints(previousVertex, cp1); + PointF shapeCp2 = MiscUtils.addPoints(vertex, cp2); + + curves.add(new CubicCurveData(shapeCp1, shapeCp2, vertex)); + } + return new ShapeData(initialPoint, closed, curves); + } +}
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeFillParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeFillParser.java index dedce47..f530622 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeFillParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeFillParser.java
@@ -28,10 +28,10 @@ name = reader.nextString(); break; case "c": - color = AnimatableColorValue.Factory.newInstance(reader, composition); + color = AnimatableValueParser.parseColor(reader, composition); break; case "o": - opacity = AnimatableIntegerValue.Factory.newInstance(reader, composition); + opacity = AnimatableValueParser.parseInteger(reader, composition); break; case "fillEnabled": fillEnabled = reader.nextBoolean();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ShapePathParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ShapePathParser.java index 37b1fca..e3f7083 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/ShapePathParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ShapePathParser.java
@@ -27,7 +27,7 @@ ind = reader.nextInt(); break; case "ks": - shape = AnimatableShapeValue.Factory.newInstance(reader, composition); + shape = AnimatableValueParser.parseShapeData(reader, composition); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeStrokeParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeStrokeParser.java index 46b6cdc..59a6181 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeStrokeParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeStrokeParser.java
@@ -34,13 +34,13 @@ name = reader.nextString(); break; case "c": - color = AnimatableColorValue.Factory.newInstance(reader, composition); + color = AnimatableValueParser.parseColor(reader, composition); break; case "w": - width = AnimatableFloatValue.Factory.newInstance(reader, composition); + width = AnimatableValueParser.parseFloat(reader, composition); break; case "o": - opacity = AnimatableIntegerValue.Factory.newInstance(reader, composition); + opacity = AnimatableValueParser.parseInteger(reader, composition); break; case "lc": capType = ShapeStroke.LineCapType.values()[reader.nextInt() - 1]; @@ -61,7 +61,7 @@ n = reader.nextString(); break; case "v": - val = AnimatableFloatValue.Factory.newInstance(reader, composition); + val = AnimatableValueParser.parseFloat(reader, composition); break; default: reader.skipValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeTrimPathParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeTrimPathParser.java index e88a429..ff449d6 100644 --- a/lottie/src/main/java/com/airbnb/lottie/parser/ShapeTrimPathParser.java +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ShapeTrimPathParser.java
@@ -23,13 +23,13 @@ while (reader.hasNext()) { switch (reader.nextName()) { case "s": - start = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + start = AnimatableValueParser.parseFloat(reader, composition, false); break; case "e": - end = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + end = AnimatableValueParser.parseFloat(reader, composition, false); break; case "o": - offset = AnimatableFloatValue.Factory.newInstance(reader, composition, false); + offset = AnimatableValueParser.parseFloat(reader, composition, false); break; case "nm": name = reader.nextString();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/ValueParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/ValueParser.java new file mode 100644 index 0000000..3e61e2d --- /dev/null +++ b/lottie/src/main/java/com/airbnb/lottie/parser/ValueParser.java
@@ -0,0 +1,9 @@ +package com.airbnb.lottie.parser; + +import android.util.JsonReader; + +import java.io.IOException; + +public interface ValueParser<V> { + V parse(JsonReader reader, float scale) throws IOException; +}
diff --git a/lottie/src/main/java/com/airbnb/lottie/value/ScaleXY.java b/lottie/src/main/java/com/airbnb/lottie/value/ScaleXY.java index 069545f..4d8c348 100644 --- a/lottie/src/main/java/com/airbnb/lottie/value/ScaleXY.java +++ b/lottie/src/main/java/com/airbnb/lottie/value/ScaleXY.java
@@ -1,12 +1,5 @@ package com.airbnb.lottie.value; -import android.util.JsonReader; -import android.util.JsonToken; - -import com.airbnb.lottie.model.animatable.AnimatableValue; - -import java.io.IOException; - public class ScaleXY { private final float scaleX; private final float scaleY; @@ -31,27 +24,4 @@ @Override public String toString() { return getScaleX() + "x" + getScaleY(); } - - public static class Factory implements AnimatableValue.Factory<ScaleXY> { - public static final Factory INSTANCE = new Factory(); - - private Factory() { - } - - @Override public ScaleXY valueFromObject(JsonReader reader, float scale) throws IOException { - boolean isArray = reader.peek() == JsonToken.BEGIN_ARRAY; - if (isArray) { - reader.beginArray(); - } - float sx = (float) reader.nextDouble(); - float sy = (float) reader.nextDouble(); - while (reader.hasNext()) { - reader.skipValue(); - } - if (isArray) { - reader.endArray(); - } - return new ScaleXY(sx / 100f * scale, sy / 100f * scale); - } - } }