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