| package com.airbnb.lottie.parser; |
| |
| import android.graphics.PointF; |
| |
| import com.airbnb.lottie.model.CubicCurveData; |
| import com.airbnb.lottie.model.content.ShapeData; |
| import com.airbnb.lottie.parser.moshi.JsonReader; |
| 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 static final JsonReader.Options NAMES = JsonReader.Options.of( |
| "c", |
| "v", |
| "i", |
| "o" |
| ); |
| |
| 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() == JsonReader.Token.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.selectName(NAMES)) { |
| case 0: |
| closed = reader.nextBoolean(); |
| break; |
| case 1: |
| pointsArray = JsonUtils.jsonToPoints(reader, scale); |
| break; |
| case 2: |
| inTangents = JsonUtils.jsonToPoints(reader, scale); |
| break; |
| case 3: |
| outTangents = JsonUtils.jsonToPoints(reader, scale); |
| break; |
| default: |
| reader.skipName(); |
| reader.skipValue(); |
| } |
| } |
| |
| reader.endObject(); |
| |
| if (reader.peek() == JsonReader.Token.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); |
| } |
| } |