1 /*
2 * Copyright 2020 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 "experimental/skrive/src/reader/StreamReader.h"
9 #include "include/core/SkString.h"
10 #include "src/utils/SkJSON.h"
11
12 #include <algorithm>
13 #include <iterator>
14 #include <memory>
15
16 namespace skrive::internal {
17 namespace {
18
block_type(const char * type_name)19 StreamReader::BlockType block_type(const char* type_name) {
20 static constexpr struct TypeMapEntry {
21 const char* name;
22 StreamReader::BlockType block_type;
23 } gTypeMap[] = {
24 {"artboard" , StreamReader::BlockType::kActorArtboard },
25 {"artboards" , StreamReader::BlockType::kArtboards },
26 {"colorFill" , StreamReader::BlockType::kColorFill },
27 {"colorStroke" , StreamReader::BlockType::kColorStroke },
28 {"ellipse" , StreamReader::BlockType::kActorEllipse },
29 {"gradientFill" , StreamReader::BlockType::kGradientFill },
30 {"gradientStroke" , StreamReader::BlockType::kGradientStroke },
31 {"node" , StreamReader::BlockType::kActorNode },
32 {"nodes" , StreamReader::BlockType::kComponents },
33 {"path" , StreamReader::BlockType::kActorPath },
34 {"polygon" , StreamReader::BlockType::kActorPolygon },
35 {"radialGradientFill" , StreamReader::BlockType::kRadialGradientFill },
36 {"radialGradientStroke", StreamReader::BlockType::kRadialGradientStroke },
37 {"rectangle" , StreamReader::BlockType::kActorRectangle },
38 {"shape" , StreamReader::BlockType::kActorShape },
39 {"star" , StreamReader::BlockType::kActorStar },
40 {"triangle" , StreamReader::BlockType::kActorTriangle },
41 };
42
43 const TypeMapEntry key = { type_name, StreamReader::BlockType::kUnknown };
44 const auto* map_entry = std::lower_bound(std::begin(gTypeMap),
45 std::end (gTypeMap),
46 key,
47 [](const TypeMapEntry& a, const TypeMapEntry& b) {
48 return strcmp(a.name, b.name) < 0;
49 });
50
51 return (map_entry != std::end(gTypeMap) && !strcmp(map_entry->name, key.name))
52 ? map_entry->block_type
53 : StreamReader::BlockType::kUnknown;
54 }
55
56 class JsonReader final : public StreamReader {
57 public:
JsonReader(std::unique_ptr<skjson::DOM> dom)58 explicit JsonReader(std::unique_ptr<skjson::DOM> dom)
59 : fDom(std::move(dom)) {
60 fContextStack.push_back({&fDom->root(), 0});
61 }
62
~JsonReader()63 ~JsonReader() override {
64 SkASSERT(fContextStack.size() == 1);
65 }
66
67 private:
68 template <typename T>
readProp(const char label[])69 const T* readProp(const char label[]) {
70 auto& ctx = fContextStack.back();
71
72 if (ctx.fContainer->is<skjson::ObjectValue>()) {
73 return static_cast<const T*>(ctx.fContainer->as<skjson::ObjectValue>()[label]);
74 }
75
76 const skjson::ArrayValue* jarr = *ctx.fContainer;
77 SkASSERT(jarr);
78
79 return ctx.fMemberIndex < jarr->size()
80 ? static_cast<const T*>((*jarr)[ctx.fMemberIndex++])
81 : nullptr;
82 }
83
readId(const char label[])84 uint16_t readId(const char label[]) override {
85 // unlike binary, json IDs are 0-based
86 return this->readUInt16(label) + 1;
87 }
88
readBool(const char label[])89 bool readBool(const char label[]) override {
90 const auto* jbool = this->readProp<skjson::BoolValue>(label);
91
92 return jbool ? **jbool : false;
93 }
94
readFloat(const char label[])95 float readFloat(const char label[]) override {
96 const auto* jnum = this->readProp<skjson::NumberValue>(label);
97
98 return jnum ? static_cast<float>(**jnum) : 0.0f;
99 }
100
readUInt8(const char label[])101 uint8_t readUInt8(const char label[]) override {
102 return static_cast<uint8_t>(this->readUInt32(label));
103 }
104
readUInt16(const char label[])105 uint16_t readUInt16(const char label[]) override {
106 return static_cast<uint16_t>(this->readUInt32(label));
107 }
108
readUInt32(const char label[])109 uint32_t readUInt32(const char label[]) override {
110 const auto* jnum = this->readProp<skjson::NumberValue>(label);
111
112 return jnum ? static_cast<uint32_t>(**jnum) : 0;
113 }
114
readString(const char label[])115 SkString readString(const char label[]) override {
116 const auto* jstr = this->readProp<skjson::StringValue>(label);
117
118 return SkString(jstr ? jstr->begin() : nullptr);
119 }
120
readFloatArray(const char label[],float dst[],size_t count)121 size_t readFloatArray(const char label[], float dst[], size_t count) override {
122 const auto* jarr = this->readProp<skjson::ArrayValue>(label);
123
124 if (!jarr) {
125 return 0;
126 }
127
128 count = std::min(count, jarr->size());
129
130 for (size_t i = 0; i < count; ++i) {
131 const skjson::NumberValue* jnum = (*jarr)[i];
132 dst[i] = jnum ? static_cast<float>(**jnum) : 0.0f;
133 }
134
135 return count;
136 }
137
readLength8()138 uint8_t readLength8() override {
139 return SkToU8(this->currentLength());
140 }
141
readLength16()142 uint16_t readLength16() override {
143 return SkToU16(this->currentLength());
144 }
145
currentLength() const146 size_t currentLength() const {
147 const auto& ctx = fContextStack.back();
148 return ctx.fContainer->is<skjson::ObjectValue>()
149 ? ctx.fContainer->as<skjson::ObjectValue>().size()
150 : ctx.fContainer->as<skjson:: ArrayValue>().size();
151 }
152
openArray(const char label[])153 bool openArray(const char label[]) override {
154 const auto* jarr = this->readProp<skjson::ArrayValue>(label);
155 if (!jarr) {
156 return false;
157 }
158
159 fContextStack.push_back({jarr, 0});
160 return true;
161 }
162
closeArray()163 void closeArray() override {
164 SkASSERT(fContextStack.back().fContainer->is<skjson::ArrayValue>());
165 fContextStack.pop_back();
166 }
167
openObject(const char label[])168 bool openObject(const char label[]) override {
169 const auto* jobj = this->readProp<skjson::ObjectValue>(label);
170 if (!jobj) {
171 return false;
172 }
173
174 fContextStack.push_back({jobj, 0});
175 return true;
176 }
177
closeObject()178 void closeObject() override {
179 SkASSERT(fContextStack.back().fContainer->is<skjson::ObjectValue>());
180 fContextStack.pop_back();
181 }
182
183 // "Blocks" map to either objects or arrays. For object containers, the block type is encoded
184 // as the key; for array containers, the type is an explicit "type" property *inside* the block
185 // entry - which must be an object in this case.
openBlock()186 BlockType openBlock() override {
187 switch (fContextStack.back().fContainer->getType()) {
188 case skjson::Value::Type::kObject: return this->openObjectBlock();
189 case skjson::Value::Type::kArray: return this->openArrayBlock();
190 default: break;
191 }
192 SkUNREACHABLE;
193 }
194
openObjectBlock()195 BlockType openObjectBlock() {
196 auto& ctx = fContextStack.back();
197 const auto& container = ctx.fContainer->as<skjson::ObjectValue>();
198
199 while (ctx.fMemberIndex < container.size()) {
200 const auto& m = container[ctx.fMemberIndex];
201 if (m.fValue.is<skjson::ObjectValue>() || m.fValue.is<skjson::ArrayValue>()) {
202 const auto btype = block_type(m.fKey.begin());
203 if (btype != BlockType::kUnknown) {
204 fContextStack.push_back({&m.fValue, 0});
205 return btype;
206 }
207 }
208
209 ctx.fMemberIndex++;
210 }
211
212 return BlockType::kEoB;
213 }
214
openArrayBlock()215 BlockType openArrayBlock() {
216 auto& ctx = fContextStack.back();
217 const auto& container = ctx.fContainer->as<skjson::ArrayValue>();
218
219 while (ctx.fMemberIndex < container.size()) {
220 const auto& m = container[ctx.fMemberIndex];
221 if (m.is<skjson::ObjectValue>()) {
222 if (const skjson::StringValue* jtype = m.as<skjson::ObjectValue>()["type"]) {
223 fContextStack.push_back({&m, 0});
224 return block_type(jtype->begin());
225 }
226 }
227
228 ctx.fMemberIndex++;
229 }
230
231 return BlockType::kEoB;
232 }
233
closeBlock()234 void closeBlock() override {
235 SkASSERT(fContextStack.size() > 1);
236 fContextStack.pop_back();
237 fContextStack.back().fMemberIndex++;
238 }
239
240 struct ContextRec {
241 const skjson::Value* fContainer;
242 size_t fMemberIndex;
243 };
244
245 const std::unique_ptr<skjson::DOM> fDom;
246
247 std::vector<ContextRec> fContextStack;
248 };
249
250 } // namespace
251
MakeJsonStreamReader(const char json[],size_t len)252 std::unique_ptr<StreamReader> MakeJsonStreamReader(const char json[], size_t len) {
253 auto dom = std::make_unique<skjson::DOM>(json, len);
254
255 return dom->root().is<skjson::ObjectValue>() ? std::make_unique<JsonReader>(std::move(dom))
256 : nullptr;
257 }
258
259 } // namespace skrive::internal
260