blob: 186cd42c31e66d2f9c263052674d02477c47bee1 [file] [log] [blame]
Florin Malitafa7e9a82018-05-04 15:10:54 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkottieJson.h"
9
10#include "SkData.h"
11#include "SkScalar.h"
12#include "SkPath.h"
13#include "SkPoint.h"
14#include "SkStream.h"
15#include "SkString.h"
16#include "SkottieValue.h"
Florin Malitafa7e9a82018-05-04 15:10:54 -040017#include <vector>
18
19namespace skottie {
20
Florin Malita7d42c442018-06-14 16:16:01 -040021using namespace skjson;
Florin Malitafa7e9a82018-05-04 15:10:54 -040022
23template <>
Florin Malita7d42c442018-06-14 16:16:01 -040024bool Parse<SkScalar>(const Value& v, SkScalar* s) {
Florin Malitafa7e9a82018-05-04 15:10:54 -040025 // Some versions wrap values as single-element arrays.
Florin Malita7d42c442018-06-14 16:16:01 -040026 if (const skjson::ArrayValue* array = v) {
27 if (array->size() == 1) {
28 return Parse((*array)[0], s);
29 }
Florin Malitafa7e9a82018-05-04 15:10:54 -040030 }
31
Florin Malita7d42c442018-06-14 16:16:01 -040032 if (const skjson::NumberValue* num = v) {
33 *s = static_cast<SkScalar>(**num);
34 return true;
35 }
Florin Malitafa7e9a82018-05-04 15:10:54 -040036
Florin Malita7d42c442018-06-14 16:16:01 -040037 return false;
Florin Malitafa7e9a82018-05-04 15:10:54 -040038}
39
40template <>
Florin Malita7d42c442018-06-14 16:16:01 -040041bool Parse<bool>(const Value& v, bool* b) {
42 switch(v.getType()) {
43 case Value::Type::kNumber:
44 *b = SkToBool(*v.as<NumberValue>());
Florin Malitafa7e9a82018-05-04 15:10:54 -040045 return true;
Florin Malita7d42c442018-06-14 16:16:01 -040046 case Value::Type::kBool:
47 *b = *v.as<BoolValue>();
Florin Malitafa7e9a82018-05-04 15:10:54 -040048 return true;
49 default:
50 break;
51 }
52
53 return false;
54}
55
56template <>
Florin Malita7d42c442018-06-14 16:16:01 -040057bool Parse<int>(const Value& v, int* i) {
58 if (const skjson::NumberValue* num = v) {
59 const auto dbl = **num;
60 *i = dbl;
61 return *i == dbl;
62 }
Florin Malitafa7e9a82018-05-04 15:10:54 -040063
Florin Malita7d42c442018-06-14 16:16:01 -040064 return false;
Florin Malitafa7e9a82018-05-04 15:10:54 -040065}
66
67template <>
Florin Malita7d42c442018-06-14 16:16:01 -040068bool Parse<SkString>(const Value& v, SkString* s) {
69 if (const skjson::StringValue* sv = v) {
70 s->set(sv->begin(), sv->size());
71 return true;
72 }
Florin Malitafa7e9a82018-05-04 15:10:54 -040073
Florin Malita7d42c442018-06-14 16:16:01 -040074 return false;
Florin Malitafa7e9a82018-05-04 15:10:54 -040075}
76
77template <>
Florin Malita7d42c442018-06-14 16:16:01 -040078bool Parse<SkPoint>(const Value& v, SkPoint* pt) {
79 if (!v.is<ObjectValue>())
Florin Malitafa7e9a82018-05-04 15:10:54 -040080 return false;
Florin Malita7d42c442018-06-14 16:16:01 -040081 const auto& ov = v.as<ObjectValue>();
Florin Malitafa7e9a82018-05-04 15:10:54 -040082
Florin Malita7d42c442018-06-14 16:16:01 -040083 const auto& jvx = ov["x"];
84 const auto& jvy = ov["y"];
Florin Malitafa7e9a82018-05-04 15:10:54 -040085
Florin Malita20880782018-05-09 11:35:00 -040086 // Some BM versions seem to store x/y as single-element arrays.
Florin Malita94d4d3e2018-06-18 13:10:51 -040087 // TODO: We should be able to check size == 1 below, or just delegate to Parse<SkScalar>,
88 // but that change introduces diffs. Investigate.
89 const ArrayValue* jvxa = jvx;
90 const ArrayValue* jvya = jvy;
91 return Parse<SkScalar>(jvxa && jvxa->size() > 0 ? (*jvxa)[0] : jvx, &pt->fX)
92 && Parse<SkScalar>(jvya && jvya->size() > 0 ? (*jvya)[0] : jvy, &pt->fY);
Florin Malitafa7e9a82018-05-04 15:10:54 -040093}
94
95template <>
Florin Malita7d42c442018-06-14 16:16:01 -040096bool Parse<std::vector<float>>(const Value& v, std::vector<float>* vec) {
97 if (!v.is<ArrayValue>())
Florin Malitafa7e9a82018-05-04 15:10:54 -040098 return false;
Florin Malita7d42c442018-06-14 16:16:01 -040099 const auto& av = v.as<ArrayValue>();
Florin Malitafa7e9a82018-05-04 15:10:54 -0400100
Florin Malita7d42c442018-06-14 16:16:01 -0400101 vec->resize(av.size());
102 for (size_t i = 0; i < av.size(); ++i) {
103 if (!Parse(av[i], vec->data() + i)) {
Florin Malitafa7e9a82018-05-04 15:10:54 -0400104 return false;
105 }
106 }
107
108 return true;
109}
110
111namespace {
112
Florin Malita7d42c442018-06-14 16:16:01 -0400113bool ParsePointVec(const Value& v, std::vector<SkPoint>* pts) {
114 if (!v.is<ArrayValue>())
Florin Malitafa7e9a82018-05-04 15:10:54 -0400115 return false;
Florin Malita7d42c442018-06-14 16:16:01 -0400116 const auto& av = v.as<ArrayValue>();
Florin Malitafa7e9a82018-05-04 15:10:54 -0400117
118 pts->clear();
Florin Malita7d42c442018-06-14 16:16:01 -0400119 pts->reserve(av.size());
Florin Malitafa7e9a82018-05-04 15:10:54 -0400120
121 std::vector<float> vec;
Florin Malita7d42c442018-06-14 16:16:01 -0400122 for (size_t i = 0; i < av.size(); ++i) {
123 if (!Parse(av[i], &vec) || vec.size() != 2)
Florin Malitafa7e9a82018-05-04 15:10:54 -0400124 return false;
125 pts->push_back(SkPoint::Make(vec[0], vec[1]));
126 }
127
128 return true;
129}
130
131} // namespace
132
133template <>
Florin Malita7d42c442018-06-14 16:16:01 -0400134bool Parse<ShapeValue>(const Value& v, ShapeValue* sh) {
135 SkASSERT(sh->fVertices.empty());
Florin Malitafa7e9a82018-05-04 15:10:54 -0400136
137 // Some versions wrap values as single-element arrays.
Florin Malita7d42c442018-06-14 16:16:01 -0400138 if (const skjson::ArrayValue* av = v) {
139 if (av->size() == 1) {
140 return Parse((*av)[0], sh);
141 }
Florin Malitafa7e9a82018-05-04 15:10:54 -0400142 }
143
Florin Malita7d42c442018-06-14 16:16:01 -0400144 if (!v.is<skjson::ObjectValue>())
145 return false;
146 const auto& ov = v.as<ObjectValue>();
147
Florin Malitafa7e9a82018-05-04 15:10:54 -0400148 std::vector<SkPoint> inPts, // Cubic Bezier "in" control points, relative to vertices.
149 outPts, // Cubic Bezier "out" control points, relative to vertices.
150 verts; // Cubic Bezier vertices.
151
Florin Malita7d42c442018-06-14 16:16:01 -0400152 if (!ParsePointVec(ov["i"], &inPts) ||
153 !ParsePointVec(ov["o"], &outPts) ||
154 !ParsePointVec(ov["v"], &verts) ||
Florin Malitafa7e9a82018-05-04 15:10:54 -0400155 inPts.size() != outPts.size() ||
156 inPts.size() != verts.size()) {
157
158 return false;
159 }
160
Florin Malita7d42c442018-06-14 16:16:01 -0400161 sh->fVertices.reserve(inPts.size());
Florin Malitafa7e9a82018-05-04 15:10:54 -0400162 for (size_t i = 0; i < inPts.size(); ++i) {
Florin Malita7d42c442018-06-14 16:16:01 -0400163 sh->fVertices.push_back(BezierVertex({inPts[i], outPts[i], verts[i]}));
Florin Malitafa7e9a82018-05-04 15:10:54 -0400164 }
Florin Malita7d42c442018-06-14 16:16:01 -0400165 sh->fClosed = ParseDefault<bool>(ov["c"], false);
Florin Malitafa7e9a82018-05-04 15:10:54 -0400166
167 return true;
168}
169
Florin Malitafa7e9a82018-05-04 15:10:54 -0400170} // namespace skottie