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