Home | History | Annotate | Download | only in include
      1 /*
      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 
     11 #include "SkReflected.h"
     12 
     13 #include "SkJSON.h"
     14 #include "SkJSONWriter.h"
     15 #include "SkTArray.h"
     16 
     17 class SkToJsonVisitor : public SkFieldVisitor {
     18 public:
     19     SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {}
     20 
     21     // Primitives
     22     void visit(const char* name, float& f) override {
     23         fWriter.appendFloat(name, f);
     24     }
     25     void visit(const char* name, int& i) override {
     26         fWriter.appendS32(name, i);
     27     }
     28     void visit(const char* name, bool& b) override {
     29         fWriter.appendBool(name, b);
     30     }
     31     void visit(const char* name, SkString& s) override {
     32         fWriter.appendString(name, s.c_str());
     33     }
     34     void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
     35         fWriter.appendString(name, EnumToString(i, map, count));
     36     }
     37 
     38     // Compound types
     39     void visit(const char* name, SkPoint& p) override {
     40         fWriter.beginObject(name, false);
     41         fWriter.appendFloat("x", p.fX);
     42         fWriter.appendFloat("y", p.fY);
     43         fWriter.endObject();
     44     }
     45 
     46     void visit(const char* name, SkColor4f& c) override {
     47         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 
     62     int enterArray(const char* name, int oldCount) override {
     63         fWriter.beginArray(name);
     64         return oldCount;
     65     }
     66     ArrayEdit exitArray() override {
     67         fWriter.endArray();
     68         return ArrayEdit();
     69     }
     70 
     71 private:
     72     SkJSONWriter& fWriter;
     73 };
     74 
     75 class SkFromJsonVisitor : public SkFieldVisitor {
     76 public:
     77     SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) {
     78         fStack.push_back(&fRoot);
     79     }
     80 
     81     void visit(const char* name, float& f) override {
     82         TryParse(get(name), f);
     83     }
     84     void visit(const char* name, int& i) override {
     85         TryParse(get(name), i);
     86     }
     87     void visit(const char* name, bool& b) override {
     88         TryParse(get(name), b);
     89     }
     90     void visit(const char* name, SkString& s) override {
     91         TryParse(get(name), s);
     92     }
     93     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     }
     99 
    100     void visit(const char* name, SkPoint& p) override {
    101         if (const skjson::ObjectValue* obj = get(name)) {
    102             TryParse((*obj)["x"], p.fX);
    103             TryParse((*obj)["y"], p.fY);
    104         }
    105     }
    106 
    107     void visit(const char* name, SkColor4f& c) override {
    108         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 
    117     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 
    130     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();
    140     }
    141 
    142 private:
    143     const skjson::Value& get(const char* name) {
    144         if (const skjson::Value* cur = fStack.back()) {
    145             if (cur->is<skjson::ArrayValue>()) {
    146                 SkASSERT(!name);
    147                 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++];
    148             } else if (!name) {
    149                 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;
    200     SkSTArray<16, size_t, true>               fArrayIndexStack;
    201 };
    202 
    203 #endif // SkParticleSerialization_DEFINED
    204