skia2/modules/particles/include/SkParticleSerialization.h
Brian Osman 9dac0d8216 Particles: Better integration for ResourceProvider
This untangles some of the dirty state tracking and dynamic rebuilding
support (that's only needed for the GUI editor), so the core code is
more streamlined. It also paves the way for feeding the RP to bindings.

Change-Id: I208ec59622154fdb2845c3ae8f7efb070d1abfc7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/257476
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-12-03 14:12:50 +00:00

187 lines
5.4 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());
}
}
// Compound types
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(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