blob: 072130b4fc8a6d57cc35cbf64aa88eebfd29cf9b [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "modules/particles/include/SkReflected.h"
Brian Osman7c979f52019-02-12 13:27:51 -050012
Brian Osmanfb32ddf2019-06-18 10:14:20 -040013#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/private/SkTArray.h"
15#include "src/utils/SkJSON.h"
16#include "src/utils/SkJSONWriter.h"
Brian Osman7c979f52019-02-12 13:27:51 -050017
18class SkToJsonVisitor : public SkFieldVisitor {
19public:
20 SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {}
21
22 // Primitives
Brian Osman2991cbe2019-02-19 10:45:56 -050023 void visit(const char* name, float& f) override {
Brian Osman7c979f52019-02-12 13:27:51 -050024 fWriter.appendFloat(name, f);
25 }
Brian Osman2991cbe2019-02-19 10:45:56 -050026 void visit(const char* name, int& i) override {
Brian Osman7c979f52019-02-12 13:27:51 -050027 fWriter.appendS32(name, i);
28 }
Brian Osman2991cbe2019-02-19 10:45:56 -050029 void visit(const char* name, bool& b) override {
Brian Osman7c979f52019-02-12 13:27:51 -050030 fWriter.appendBool(name, b);
31 }
Brian Osman2991cbe2019-02-19 10:45:56 -050032 void visit(const char* name, SkString& s) override {
Brian Osman7c979f52019-02-12 13:27:51 -050033 fWriter.appendString(name, s.c_str());
34 }
Brian Osmane5d532e2019-02-26 14:58:40 -050035 void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
36 fWriter.appendString(name, EnumToString(i, map, count));
37 }
Brian Osman7c979f52019-02-12 13:27:51 -050038
39 // Compound types
Brian Osman2991cbe2019-02-19 10:45:56 -050040 void visit(const char* name, SkPoint& p) override {
Brian Osman7c979f52019-02-12 13:27:51 -050041 fWriter.beginObject(name, false);
42 fWriter.appendFloat("x", p.fX);
43 fWriter.appendFloat("y", p.fY);
44 fWriter.endObject();
45 }
46
Brian Osman2991cbe2019-02-19 10:45:56 -050047 void visit(const char* name, SkColor4f& c) override {
Brian Osman7c979f52019-02-12 13:27:51 -050048 fWriter.beginArray(name, false);
49 fWriter.appendFloat(c.fR);
50 fWriter.appendFloat(c.fG);
51 fWriter.appendFloat(c.fB);
52 fWriter.appendFloat(c.fA);
53 fWriter.endArray();
54 }
55
56 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
57 fWriter.appendString("Type", e ? e->getType()->fName : "Null");
58 }
59
60 void enterObject(const char* name) override { fWriter.beginObject(name); }
61 void exitObject() override { fWriter.endObject(); }
62
Brian Osman5de7ea42019-02-14 13:23:51 -050063 int enterArray(const char* name, int oldCount) override {
Brian Osman7c979f52019-02-12 13:27:51 -050064 fWriter.beginArray(name);
Brian Osman5de7ea42019-02-14 13:23:51 -050065 return oldCount;
66 }
67 ArrayEdit exitArray() override {
Brian Osman7c979f52019-02-12 13:27:51 -050068 fWriter.endArray();
Brian Osman5de7ea42019-02-14 13:23:51 -050069 return ArrayEdit();
Brian Osman7c979f52019-02-12 13:27:51 -050070 }
71
72private:
73 SkJSONWriter& fWriter;
74};
75
76class SkFromJsonVisitor : public SkFieldVisitor {
77public:
78 SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) {
79 fStack.push_back(&fRoot);
80 }
81
Brian Osman2991cbe2019-02-19 10:45:56 -050082 void visit(const char* name, float& f) override {
Brian Osman7c979f52019-02-12 13:27:51 -050083 TryParse(get(name), f);
84 }
Brian Osman2991cbe2019-02-19 10:45:56 -050085 void visit(const char* name, int& i) override {
Brian Osman7c979f52019-02-12 13:27:51 -050086 TryParse(get(name), i);
87 }
Brian Osman2991cbe2019-02-19 10:45:56 -050088 void visit(const char* name, bool& b) override {
Brian Osman7c979f52019-02-12 13:27:51 -050089 TryParse(get(name), b);
90 }
Brian Osman2991cbe2019-02-19 10:45:56 -050091 void visit(const char* name, SkString& s) override {
Brian Osman7c979f52019-02-12 13:27:51 -050092 TryParse(get(name), s);
93 }
Brian Osmane5d532e2019-02-26 14:58:40 -050094 void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
95 SkString str;
96 if (TryParse(get(name), str)) {
97 i = StringToEnum(str.c_str(), map, count);
98 }
99 }
Brian Osman7c979f52019-02-12 13:27:51 -0500100
Brian Osman2991cbe2019-02-19 10:45:56 -0500101 void visit(const char* name, SkPoint& p) override {
Brian Osman7c979f52019-02-12 13:27:51 -0500102 if (const skjson::ObjectValue* obj = get(name)) {
103 TryParse((*obj)["x"], p.fX);
104 TryParse((*obj)["y"], p.fY);
105 }
106 }
107
Brian Osman2991cbe2019-02-19 10:45:56 -0500108 void visit(const char* name, SkColor4f& c) override {
Brian Osman7c979f52019-02-12 13:27:51 -0500109 const skjson::ArrayValue* arr = get(name);
110 if (arr && arr->size() == 4) {
111 TryParse((*arr)[0], c.fR);
112 TryParse((*arr)[1], c.fG);
113 TryParse((*arr)[2], c.fB);
114 TryParse((*arr)[3], c.fA);
115 }
116 }
117
Brian Osman7c979f52019-02-12 13:27:51 -0500118 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
119 const skjson::StringValue* typeString = get("Type");
120 const char* type = typeString ? typeString->begin() : "Null";
121 e = SkReflected::CreateInstance(type);
122 }
123
124 void enterObject(const char* name) override {
125 fStack.push_back((const skjson::ObjectValue*)get(name));
126 }
127 void exitObject() override {
128 fStack.pop_back();
129 }
130
Brian Osman5de7ea42019-02-14 13:23:51 -0500131 int enterArray(const char* name, int oldCount) override {
132 const skjson::ArrayValue* arrVal = get(name);
133 fStack.push_back(arrVal);
134 fArrayIndexStack.push_back(0);
135 return arrVal ? arrVal->size() : 0;
136 }
137 ArrayEdit exitArray() override {
138 fStack.pop_back();
139 fArrayIndexStack.pop_back();
140 return ArrayEdit();
Brian Osman7c979f52019-02-12 13:27:51 -0500141 }
142
143private:
Brian Osman5de7ea42019-02-14 13:23:51 -0500144 const skjson::Value& get(const char* name) {
Brian Osman7c979f52019-02-12 13:27:51 -0500145 if (const skjson::Value* cur = fStack.back()) {
Brian Osman5de7ea42019-02-14 13:23:51 -0500146 if (cur->is<skjson::ArrayValue>()) {
147 SkASSERT(!name);
148 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++];
149 } else if (!name) {
Brian Osman7c979f52019-02-12 13:27:51 -0500150 return *cur;
151 } else if (cur->is<skjson::ObjectValue>()) {
152 return cur->as<skjson::ObjectValue>()[name];
153 }
154 }
155 static skjson::NullValue gNull;
156 return gNull;
157 }
158
159 static bool TryParse(const skjson::Value& v, float& f) {
160 if (const skjson::NumberValue* num = v) {
161 f = static_cast<float>(**num);
162 return true;
163 }
164 return false;
165 }
166
167 static bool TryParse(const skjson::Value& v, int& i) {
168 if (const skjson::NumberValue* num = v) {
169 double dbl = **num;
170 i = static_cast<int>(dbl);
171 return static_cast<double>(i) == dbl;
172 }
173 return false;
174 }
175
176 static bool TryParse(const skjson::Value& v, SkString& s) {
177 if (const skjson::StringValue* str = v) {
178 s.set(str->begin(), str->size());
179 return true;
180 }
181 return false;
182 }
183
184 static bool TryParse(const skjson::Value& v, bool& b) {
185 switch (v.getType()) {
186 case skjson::Value::Type::kNumber:
187 b = SkToBool(*v.as<skjson::NumberValue>());
188 return true;
189 case skjson::Value::Type::kBool:
190 b = *v.as<skjson::BoolValue>();
191 return true;
192 default:
193 break;
194 }
195
196 return false;
197 }
198
199 const skjson::Value& fRoot;
200 SkSTArray<16, const skjson::Value*, true> fStack;
Brian Osman5de7ea42019-02-14 13:23:51 -0500201 SkSTArray<16, size_t, true> fArrayIndexStack;
Brian Osman7c979f52019-02-12 13:27:51 -0500202};
203
204#endif // SkParticleSerialization_DEFINED