• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     }
visit(const char * name,int & i,const EnumStringMapping * map,int count)45     void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
46         fWriter.appendString(name, EnumToString(i, map, count));
47     }
48 
49     // Compound types
visit(const char * name,SkPoint & p)50     void visit(const char* name, SkPoint& p) override {
51         fWriter.beginObject(name, false);
52         fWriter.appendFloat("x", p.fX);
53         fWriter.appendFloat("y", p.fY);
54         fWriter.endObject();
55     }
56 
visit(const char * name,SkColor4f & c)57     void visit(const char* name, SkColor4f& c) override {
58         fWriter.beginArray(name, false);
59         fWriter.appendFloat(c.fR);
60         fWriter.appendFloat(c.fG);
61         fWriter.appendFloat(c.fB);
62         fWriter.appendFloat(c.fA);
63         fWriter.endArray();
64     }
65 
visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)66     void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
67         fWriter.appendString("Type", e ? e->getType()->fName : "Null");
68     }
69 
enterObject(const char * name)70     void enterObject(const char* name) override { fWriter.beginObject(name); }
exitObject()71     void exitObject()                  override { fWriter.endObject(); }
72 
enterArray(const char * name,int oldCount)73     int enterArray(const char* name, int oldCount) override {
74         fWriter.beginArray(name);
75         return oldCount;
76     }
exitArray()77     ArrayEdit exitArray() override {
78         fWriter.endArray();
79         return ArrayEdit();
80     }
81 
82 private:
83     SkJSONWriter& fWriter;
84 };
85 
86 class SkFromJsonVisitor : public SkFieldVisitor {
87 public:
SkFromJsonVisitor(const skjson::Value & v)88     SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) {
89         fStack.push_back(&fRoot);
90     }
91 
visit(const char * name,float & f)92     void visit(const char* name, float& f) override {
93         TryParse(get(name), f);
94     }
visit(const char * name,int & i)95     void visit(const char* name, int& i) override {
96         TryParse(get(name), i);
97     }
visit(const char * name,bool & b)98     void visit(const char* name, bool& b) override {
99         TryParse(get(name), b);
100     }
visit(const char * name,SkString & s)101     void visit(const char* name, SkString& s) override {
102         if (const skjson::ArrayValue* lines = get(name)) {
103             s.reset();
104             bool first = true;
105             for (const skjson::StringValue* line : *lines) {
106                 if (line) {
107                     if (!first) {
108                         s.append("\n");
109                     }
110                     s.append(line->begin(), line->size());
111                     first = false;
112                 }
113             }
114         } else {
115             TryParse(get(name), s);
116         }
117     }
visit(const char * name,int & i,const EnumStringMapping * map,int count)118     void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
119         SkString str;
120         if (TryParse(get(name), str)) {
121             i = StringToEnum(str.c_str(), map, count);
122         }
123     }
124 
visit(const char * name,SkPoint & p)125     void visit(const char* name, SkPoint& p) override {
126         if (const skjson::ObjectValue* obj = get(name)) {
127             TryParse((*obj)["x"], p.fX);
128             TryParse((*obj)["y"], p.fY);
129         }
130     }
131 
visit(const char * name,SkColor4f & c)132     void visit(const char* name, SkColor4f& c) override {
133         const skjson::ArrayValue* arr = get(name);
134         if (arr && arr->size() == 4) {
135             TryParse((*arr)[0], c.fR);
136             TryParse((*arr)[1], c.fG);
137             TryParse((*arr)[2], c.fB);
138             TryParse((*arr)[3], c.fA);
139         }
140     }
141 
visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)142     void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
143         const skjson::StringValue* typeString = get("Type");
144         const char* type = typeString ? typeString->begin() : "Null";
145         e = SkReflected::CreateInstance(type);
146     }
147 
enterObject(const char * name)148     void enterObject(const char* name) override {
149         fStack.push_back((const skjson::ObjectValue*)get(name));
150     }
exitObject()151     void exitObject() override {
152         fStack.pop_back();
153     }
154 
enterArray(const char * name,int oldCount)155     int enterArray(const char* name, int oldCount) override {
156         const skjson::ArrayValue* arrVal = get(name);
157         fStack.push_back(arrVal);
158         fArrayIndexStack.push_back(0);
159         return arrVal ? arrVal->size() : 0;
160     }
exitArray()161     ArrayEdit exitArray() override {
162         fStack.pop_back();
163         fArrayIndexStack.pop_back();
164         return ArrayEdit();
165     }
166 
167 private:
get(const char * name)168     const skjson::Value& get(const char* name) {
169         if (const skjson::Value* cur = fStack.back()) {
170             if (cur->is<skjson::ArrayValue>()) {
171                 SkASSERT(!name);
172                 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++];
173             } else if (!name) {
174                 return *cur;
175             } else if (cur->is<skjson::ObjectValue>()) {
176                 return cur->as<skjson::ObjectValue>()[name];
177             }
178         }
179         static skjson::NullValue gNull;
180         return gNull;
181     }
182 
TryParse(const skjson::Value & v,float & f)183     static bool TryParse(const skjson::Value& v, float& f) {
184         if (const skjson::NumberValue* num = v) {
185             f = static_cast<float>(**num);
186             return true;
187         }
188         return false;
189     }
190 
TryParse(const skjson::Value & v,int & i)191     static bool TryParse(const skjson::Value& v, int& i) {
192         if (const skjson::NumberValue* num = v) {
193             double dbl = **num;
194             i = static_cast<int>(dbl);
195             return static_cast<double>(i) == dbl;
196         }
197         return false;
198     }
199 
TryParse(const skjson::Value & v,SkString & s)200     static bool TryParse(const skjson::Value& v, SkString& s) {
201         if (const skjson::StringValue* str = v) {
202             s.set(str->begin(), str->size());
203             return true;
204         }
205         return false;
206     }
207 
TryParse(const skjson::Value & v,bool & b)208     static bool TryParse(const skjson::Value& v, bool& b) {
209         switch (v.getType()) {
210         case skjson::Value::Type::kNumber:
211             b = SkToBool(*v.as<skjson::NumberValue>());
212             return true;
213         case skjson::Value::Type::kBool:
214             b = *v.as<skjson::BoolValue>();
215             return true;
216         default:
217             break;
218         }
219 
220         return false;
221     }
222 
223     const skjson::Value& fRoot;
224     SkSTArray<16, const skjson::Value*, true> fStack;
225     SkSTArray<16, size_t, true>               fArrayIndexStack;
226 };
227 
228 #endif // SkParticleSerialization_DEFINED
229