blob: 0cb057de8682e430e3c4d65cb4458f61bdbdf053 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/private/SkTArray.h"
14#include "src/utils/SkJSON.h"
15#include "src/utils/SkJSONWriter.h"
Brian Osman7c979f52019-02-12 13:27:51 -050016
17class SkToJsonVisitor : public SkFieldVisitor {
18public:
19 SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {}
20
21 // Primitives
Brian Osman2991cbe2019-02-19 10:45:56 -050022 void visit(const char* name, float& f) override {
Brian Osman7c979f52019-02-12 13:27:51 -050023 fWriter.appendFloat(name, f);
24 }
Brian Osman2991cbe2019-02-19 10:45:56 -050025 void visit(const char* name, int& i) override {
Brian Osman7c979f52019-02-12 13:27:51 -050026 fWriter.appendS32(name, i);
27 }
Brian Osman2991cbe2019-02-19 10:45:56 -050028 void visit(const char* name, bool& b) override {
Brian Osman7c979f52019-02-12 13:27:51 -050029 fWriter.appendBool(name, b);
30 }
Brian Osman2991cbe2019-02-19 10:45:56 -050031 void visit(const char* name, SkString& s) override {
Brian Osman7c979f52019-02-12 13:27:51 -050032 fWriter.appendString(name, s.c_str());
33 }
Brian Osmane5d532e2019-02-26 14:58:40 -050034 void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
35 fWriter.appendString(name, EnumToString(i, map, count));
36 }
Brian Osman7c979f52019-02-12 13:27:51 -050037
38 // Compound types
Brian Osman2991cbe2019-02-19 10:45:56 -050039 void visit(const char* name, SkPoint& p) override {
Brian Osman7c979f52019-02-12 13:27:51 -050040 fWriter.beginObject(name, false);
41 fWriter.appendFloat("x", p.fX);
42 fWriter.appendFloat("y", p.fY);
43 fWriter.endObject();
44 }
45
Brian Osman2991cbe2019-02-19 10:45:56 -050046 void visit(const char* name, SkColor4f& c) override {
Brian Osman7c979f52019-02-12 13:27:51 -050047 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
55 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
56 fWriter.appendString("Type", e ? e->getType()->fName : "Null");
57 }
58
59 void enterObject(const char* name) override { fWriter.beginObject(name); }
60 void exitObject() override { fWriter.endObject(); }
61
Brian Osman5de7ea42019-02-14 13:23:51 -050062 int enterArray(const char* name, int oldCount) override {
Brian Osman7c979f52019-02-12 13:27:51 -050063 fWriter.beginArray(name);
Brian Osman5de7ea42019-02-14 13:23:51 -050064 return oldCount;
65 }
66 ArrayEdit exitArray() override {
Brian Osman7c979f52019-02-12 13:27:51 -050067 fWriter.endArray();
Brian Osman5de7ea42019-02-14 13:23:51 -050068 return ArrayEdit();
Brian Osman7c979f52019-02-12 13:27:51 -050069 }
70
71private:
72 SkJSONWriter& fWriter;
73};
74
75class SkFromJsonVisitor : public SkFieldVisitor {
76public:
77 SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) {
78 fStack.push_back(&fRoot);
79 }
80
Brian Osman2991cbe2019-02-19 10:45:56 -050081 void visit(const char* name, float& f) override {
Brian Osman7c979f52019-02-12 13:27:51 -050082 TryParse(get(name), f);
83 }
Brian Osman2991cbe2019-02-19 10:45:56 -050084 void visit(const char* name, int& i) override {
Brian Osman7c979f52019-02-12 13:27:51 -050085 TryParse(get(name), i);
86 }
Brian Osman2991cbe2019-02-19 10:45:56 -050087 void visit(const char* name, bool& b) override {
Brian Osman7c979f52019-02-12 13:27:51 -050088 TryParse(get(name), b);
89 }
Brian Osman2991cbe2019-02-19 10:45:56 -050090 void visit(const char* name, SkString& s) override {
Brian Osman7c979f52019-02-12 13:27:51 -050091 TryParse(get(name), s);
92 }
Brian Osmane5d532e2019-02-26 14:58:40 -050093 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 }
Brian Osman7c979f52019-02-12 13:27:51 -050099
Brian Osman2991cbe2019-02-19 10:45:56 -0500100 void visit(const char* name, SkPoint& p) override {
Brian Osman7c979f52019-02-12 13:27:51 -0500101 if (const skjson::ObjectValue* obj = get(name)) {
102 TryParse((*obj)["x"], p.fX);
103 TryParse((*obj)["y"], p.fY);
104 }
105 }
106
Brian Osman2991cbe2019-02-19 10:45:56 -0500107 void visit(const char* name, SkColor4f& c) override {
Brian Osman7c979f52019-02-12 13:27:51 -0500108 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
Brian Osman7c979f52019-02-12 13:27:51 -0500117 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
123 void enterObject(const char* name) override {
124 fStack.push_back((const skjson::ObjectValue*)get(name));
125 }
126 void exitObject() override {
127 fStack.pop_back();
128 }
129
Brian Osman5de7ea42019-02-14 13:23:51 -0500130 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 }
136 ArrayEdit exitArray() override {
137 fStack.pop_back();
138 fArrayIndexStack.pop_back();
139 return ArrayEdit();
Brian Osman7c979f52019-02-12 13:27:51 -0500140 }
141
142private:
Brian Osman5de7ea42019-02-14 13:23:51 -0500143 const skjson::Value& get(const char* name) {
Brian Osman7c979f52019-02-12 13:27:51 -0500144 if (const skjson::Value* cur = fStack.back()) {
Brian Osman5de7ea42019-02-14 13:23:51 -0500145 if (cur->is<skjson::ArrayValue>()) {
146 SkASSERT(!name);
147 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++];
148 } else if (!name) {
Brian Osman7c979f52019-02-12 13:27:51 -0500149 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
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
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
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
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;
Brian Osman5de7ea42019-02-14 13:23:51 -0500200 SkSTArray<16, size_t, true> fArrayIndexStack;
Brian Osman7c979f52019-02-12 13:27:51 -0500201};
202
203#endif // SkParticleSerialization_DEFINED