1 /*
2 * Copyright 2019 Google LLC
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 #ifndef SkParticleSerialization_DEFINED
9 #define SkParticleSerialization_DEFINED
10 
11 #include "modules/particles/include/SkReflected.h"
12 
13 #include "include/core/SkString.h"
14 #include "include/private/SkTArray.h"
15 #include "src/utils/SkJSON.h"
16 #include "src/utils/SkJSONWriter.h"
17 
18 class SkToJsonVisitor : public SkFieldVisitor {
19 public:
SkToJsonVisitor(SkJSONWriter & writer)20     SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {}
21 
22     // Primitives
visit(const char * name,float & f)23     void visit(const char* name, float& f) override {
24         fWriter.appendFloat(name, f);
25     }
visit(const char * name,int & i)26     void visit(const char* name, int& i) override {
27         fWriter.appendS32(name, i);
28     }
visit(const char * name,bool & b)29     void visit(const char* name, bool& b) override {
30         fWriter.appendBool(name, b);
31     }
visit(const char * name,SkString & s)32     void visit(const char* name, SkString& s) override {
33         if (s.contains('\n')) {
34             SkTArray<SkString> lines;
35             SkStrSplit(s.c_str(), "\n", kStrict_SkStrSplitMode, &lines);
36             fWriter.beginArray(name);
37             for (const auto& line : lines) {
38                 fWriter.appendString(line.c_str());
39             }
40             fWriter.endArray();
41         } else {
42             fWriter.appendString(name, s.c_str());
43         }
44     }
45 
46     // Compound types
visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)47     void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
48         fWriter.appendString("Type", e ? e->getType()->fName : "Null");
49     }
50 
enterObject(const char * name)51     void enterObject(const char* name) override { fWriter.beginObject(name); }
exitObject()52     void exitObject()                  override { fWriter.endObject(); }
53 
enterArray(const char * name,int oldCount)54     int enterArray(const char* name, int oldCount) override {
55         fWriter.beginArray(name);
56         return oldCount;
57     }
exitArray()58     ArrayEdit exitArray() override {
59         fWriter.endArray();
60         return ArrayEdit();
61     }
62 
63 private:
64     SkJSONWriter& fWriter;
65 };
66 
67 class SkFromJsonVisitor : public SkFieldVisitor {
68 public:
SkFromJsonVisitor(const skjson::Value & v)69     SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) {
70         fStack.push_back(&fRoot);
71     }
72 
visit(const char * name,float & f)73     void visit(const char* name, float& f) override {
74         TryParse(get(name), f);
75     }
visit(const char * name,int & i)76     void visit(const char* name, int& i) override {
77         TryParse(get(name), i);
78     }
visit(const char * name,bool & b)79     void visit(const char* name, bool& b) override {
80         TryParse(get(name), b);
81     }
visit(const char * name,SkString & s)82     void visit(const char* name, SkString& s) override {
83         if (const skjson::ArrayValue* lines = get(name)) {
84             s.reset();
85             bool first = true;
86             for (const skjson::StringValue* line : *lines) {
87                 if (line) {
88                     if (!first) {
89                         s.append("\n");
90                     }
91                     s.append(line->begin(), line->size());
92                     first = false;
93                 }
94             }
95         } else {
96             TryParse(get(name), s);
97         }
98     }
99 
visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)100     void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
101         const skjson::StringValue* typeString = get("Type");
102         const char* type = typeString ? typeString->begin() : "Null";
103         e = SkReflected::CreateInstance(type);
104     }
105 
enterObject(const char * name)106     void enterObject(const char* name) override {
107         fStack.push_back((const skjson::ObjectValue*)get(name));
108     }
exitObject()109     void exitObject() override {
110         fStack.pop_back();
111     }
112 
enterArray(const char * name,int oldCount)113     int enterArray(const char* name, int oldCount) override {
114         const skjson::ArrayValue* arrVal = get(name);
115         fStack.push_back(arrVal);
116         fArrayIndexStack.push_back(0);
117         return arrVal ? arrVal->size() : 0;
118     }
exitArray()119     ArrayEdit exitArray() override {
120         fStack.pop_back();
121         fArrayIndexStack.pop_back();
122         return ArrayEdit();
123     }
124 
125 private:
get(const char * name)126     const skjson::Value& get(const char* name) {
127         if (const skjson::Value* cur = fStack.back()) {
128             if (cur->is<skjson::ArrayValue>()) {
129                 SkASSERT(!name);
130                 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++];
131             } else if (!name) {
132                 return *cur;
133             } else if (cur->is<skjson::ObjectValue>()) {
134                 return cur->as<skjson::ObjectValue>()[name];
135             }
136         }
137         static skjson::NullValue gNull;
138         return gNull;
139     }
140 
TryParse(const skjson::Value & v,float & f)141     static bool TryParse(const skjson::Value& v, float& f) {
142         if (const skjson::NumberValue* num = v) {
143             f = static_cast<float>(**num);
144             return true;
145         }
146         return false;
147     }
148 
TryParse(const skjson::Value & v,int & i)149     static bool TryParse(const skjson::Value& v, int& i) {
150         if (const skjson::NumberValue* num = v) {
151             double dbl = **num;
152             i = static_cast<int>(dbl);
153             return static_cast<double>(i) == dbl;
154         }
155         return false;
156     }
157 
TryParse(const skjson::Value & v,SkString & s)158     static bool TryParse(const skjson::Value& v, SkString& s) {
159         if (const skjson::StringValue* str = v) {
160             s.set(str->begin(), str->size());
161             return true;
162         }
163         return false;
164     }
165 
TryParse(const skjson::Value & v,bool & b)166     static bool TryParse(const skjson::Value& v, bool& b) {
167         switch (v.getType()) {
168         case skjson::Value::Type::kNumber:
169             b = SkToBool(*v.as<skjson::NumberValue>());
170             return true;
171         case skjson::Value::Type::kBool:
172             b = *v.as<skjson::BoolValue>();
173             return true;
174         default:
175             break;
176         }
177 
178         return false;
179     }
180 
181     const skjson::Value& fRoot;
182     SkSTArray<16, const skjson::Value*, true> fStack;
183     SkSTArray<16, size_t, true>               fArrayIndexStack;
184 };
185 
186 #endif // SkParticleSerialization_DEFINED
187