/* * Copyright 2019 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkParticleSerialization_DEFINED #define SkParticleSerialization_DEFINED #include "modules/particles/include/SkReflected.h" #include "include/core/SkString.h" #include "include/private/SkTArray.h" #include "src/utils/SkJSON.h" #include "src/utils/SkJSONWriter.h" class SkToJsonVisitor : public SkFieldVisitor { public: SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {} // Primitives void visit(const char* name, float& f) override { fWriter.appendFloat(name, f); } void visit(const char* name, int& i) override { fWriter.appendS32(name, i); } void visit(const char* name, bool& b) override { fWriter.appendBool(name, b); } void visit(const char* name, SkString& s) override { if (s.contains('\n')) { SkTArray lines; SkStrSplit(s.c_str(), "\n", kStrict_SkStrSplitMode, &lines); fWriter.beginArray(name); for (const auto& line : lines) { fWriter.appendString(line.c_str()); } fWriter.endArray(); } else { fWriter.appendString(name, s.c_str()); } } void visit(const char* name, int& i, const EnumStringMapping* map, int count) override { fWriter.appendString(name, EnumToString(i, map, count)); } // Compound types void visit(const char* name, SkPoint& p) override { fWriter.beginObject(name, false); fWriter.appendFloat("x", p.fX); fWriter.appendFloat("y", p.fY); fWriter.endObject(); } void visit(const char* name, SkColor4f& c) override { fWriter.beginArray(name, false); fWriter.appendFloat(c.fR); fWriter.appendFloat(c.fG); fWriter.appendFloat(c.fB); fWriter.appendFloat(c.fA); fWriter.endArray(); } void visit(sk_sp& e, const SkReflected::Type* baseType) override { fWriter.appendString("Type", e ? e->getType()->fName : "Null"); } void enterObject(const char* name) override { fWriter.beginObject(name); } void exitObject() override { fWriter.endObject(); } int enterArray(const char* name, int oldCount) override { fWriter.beginArray(name); return oldCount; } ArrayEdit exitArray() override { fWriter.endArray(); return ArrayEdit(); } private: SkJSONWriter& fWriter; }; class SkFromJsonVisitor : public SkFieldVisitor { public: SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) { fStack.push_back(&fRoot); } void visit(const char* name, float& f) override { TryParse(get(name), f); } void visit(const char* name, int& i) override { TryParse(get(name), i); } void visit(const char* name, bool& b) override { TryParse(get(name), b); } void visit(const char* name, SkString& s) override { if (const skjson::ArrayValue* lines = get(name)) { s.reset(); bool first = true; for (const skjson::StringValue* line : *lines) { if (line) { if (!first) { s.append("\n"); } s.append(line->begin(), line->size()); first = false; } } } else { TryParse(get(name), s); } } void visit(const char* name, int& i, const EnumStringMapping* map, int count) override { SkString str; if (TryParse(get(name), str)) { i = StringToEnum(str.c_str(), map, count); } } void visit(const char* name, SkPoint& p) override { if (const skjson::ObjectValue* obj = get(name)) { TryParse((*obj)["x"], p.fX); TryParse((*obj)["y"], p.fY); } } void visit(const char* name, SkColor4f& c) override { const skjson::ArrayValue* arr = get(name); if (arr && arr->size() == 4) { TryParse((*arr)[0], c.fR); TryParse((*arr)[1], c.fG); TryParse((*arr)[2], c.fB); TryParse((*arr)[3], c.fA); } } void visit(sk_sp& e, const SkReflected::Type* baseType) override { const skjson::StringValue* typeString = get("Type"); const char* type = typeString ? typeString->begin() : "Null"; e = SkReflected::CreateInstance(type); } void enterObject(const char* name) override { fStack.push_back((const skjson::ObjectValue*)get(name)); } void exitObject() override { fStack.pop_back(); } int enterArray(const char* name, int oldCount) override { const skjson::ArrayValue* arrVal = get(name); fStack.push_back(arrVal); fArrayIndexStack.push_back(0); return arrVal ? arrVal->size() : 0; } ArrayEdit exitArray() override { fStack.pop_back(); fArrayIndexStack.pop_back(); return ArrayEdit(); } private: const skjson::Value& get(const char* name) { if (const skjson::Value* cur = fStack.back()) { if (cur->is()) { SkASSERT(!name); return cur->as()[fArrayIndexStack.back()++]; } else if (!name) { return *cur; } else if (cur->is()) { return cur->as()[name]; } } static skjson::NullValue gNull; return gNull; } static bool TryParse(const skjson::Value& v, float& f) { if (const skjson::NumberValue* num = v) { f = static_cast(**num); return true; } return false; } static bool TryParse(const skjson::Value& v, int& i) { if (const skjson::NumberValue* num = v) { double dbl = **num; i = static_cast(dbl); return static_cast(i) == dbl; } return false; } static bool TryParse(const skjson::Value& v, SkString& s) { if (const skjson::StringValue* str = v) { s.set(str->begin(), str->size()); return true; } return false; } static bool TryParse(const skjson::Value& v, bool& b) { switch (v.getType()) { case skjson::Value::Type::kNumber: b = SkToBool(*v.as()); return true; case skjson::Value::Type::kBool: b = *v.as(); return true; default: break; } return false; } const skjson::Value& fRoot; SkSTArray<16, const skjson::Value*, true> fStack; SkSTArray<16, size_t, true> fArrayIndexStack; }; #endif // SkParticleSerialization_DEFINED