9dac0d8216
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>
187 lines
5.4 KiB
C++
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
|