d6108add51
Change-Id: Ic81b3433b485ca9ce0e60bd10ec12706e673ee89 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/229917 Commit-Queue: Brian Osman <brianosman@google.com> Commit-Queue: Mike Klein <mtklein@google.com> Auto-Submit: Brian Osman <brianosman@google.com> Reviewed-by: Mike Reed <reed@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
229 lines
6.8 KiB
C++
229 lines
6.8 KiB
C++
/*
|
|
* 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<SkString> 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<SkReflected>& 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<SkReflected>& 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<skjson::ArrayValue>()) {
|
|
SkASSERT(!name);
|
|
return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++];
|
|
} else if (!name) {
|
|
return *cur;
|
|
} else if (cur->is<skjson::ObjectValue>()) {
|
|
return cur->as<skjson::ObjectValue>()[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<float>(**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<int>(dbl);
|
|
return static_cast<double>(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<skjson::NumberValue>());
|
|
return true;
|
|
case skjson::Value::Type::kBool:
|
|
b = *v.as<skjson::BoolValue>();
|
|
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
|