• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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