blob: b4f51d70ee647e79a856e079a830f45d9da0f0e6 [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
59 void visit(const char* name, SkTArray<sk_sp<SkReflected>>& arr,
60 const SkReflected::Type* baseType) override {
61 fWriter.beginArray(name);
62 for (auto ptr : arr) {
63 SkFieldVisitor::visit(nullptr, ptr);
64 }
65 fWriter.endArray();
66 }
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
108 void visit(const char* name, SkCurve& c, SkField field) override {
109 if (get(name).is<skjson::ObjectValue>()) {
110 SkFieldVisitor::visit(name, c, field);
111 }
112 }
113
114 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
115 const skjson::StringValue* typeString = get("Type");
116 const char* type = typeString ? typeString->begin() : "Null";
117 e = SkReflected::CreateInstance(type);
118 }
119
120 void enterObject(const char* name) override {
121 fStack.push_back((const skjson::ObjectValue*)get(name));
122 }
123 void exitObject() override {
124 fStack.pop_back();
125 }
126
127 void visit(const char* name, SkTArray<sk_sp<SkReflected>>& arr,
128 const SkReflected::Type* baseType) override {
129 arr.reset();
130
131 if (const skjson::ArrayValue* arrVal = get(name)) {
132 arr.reserve(arrVal->size());
133
134 for (const skjson::ObjectValue* obj : *arrVal) {
135 sk_sp<SkReflected> ptr = nullptr;
136 if (obj) {
137 fStack.push_back(obj);
138 this->visit(ptr, baseType);
139 if (ptr) {
140 ptr->visitFields(this);
141 }
142 fStack.pop_back();
143 }
144 if (ptr && ptr->isOfType(baseType)) {
145 arr.push_back(ptr);
146 }
147 }
148 }
149 }
150
151private:
152 const skjson::Value& get(const char* name) const {
153 if (const skjson::Value* cur = fStack.back()) {
154 if (!name) {
155 return *cur;
156 } else if (cur->is<skjson::ObjectValue>()) {
157 return cur->as<skjson::ObjectValue>()[name];
158 }
159 }
160 static skjson::NullValue gNull;
161 return gNull;
162 }
163
164 static bool TryParse(const skjson::Value& v, float& f) {
165 if (const skjson::NumberValue* num = v) {
166 f = static_cast<float>(**num);
167 return true;
168 }
169 return false;
170 }
171
172 static bool TryParse(const skjson::Value& v, int& i) {
173 if (const skjson::NumberValue* num = v) {
174 double dbl = **num;
175 i = static_cast<int>(dbl);
176 return static_cast<double>(i) == dbl;
177 }
178 return false;
179 }
180
181 static bool TryParse(const skjson::Value& v, SkString& s) {
182 if (const skjson::StringValue* str = v) {
183 s.set(str->begin(), str->size());
184 return true;
185 }
186 return false;
187 }
188
189 static bool TryParse(const skjson::Value& v, bool& b) {
190 switch (v.getType()) {
191 case skjson::Value::Type::kNumber:
192 b = SkToBool(*v.as<skjson::NumberValue>());
193 return true;
194 case skjson::Value::Type::kBool:
195 b = *v.as<skjson::BoolValue>();
196 return true;
197 default:
198 break;
199 }
200
201 return false;
202 }
203
204 const skjson::Value& fRoot;
205 SkSTArray<16, const skjson::Value*, true> fStack;
206};
207
208#endif // SkParticleSerialization_DEFINED