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