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 "modules/particles/include/SkReflected.h" 12 13 #include "include/core/SkString.h" 14 #include "include/private/SkTArray.h" 15 #include "src/utils/SkJSON.h" 16 #include "src/utils/SkJSONWriter.h" 17 18 class SkToJsonVisitor : public SkFieldVisitor { 19 public: SkToJsonVisitor(SkJSONWriter & writer)20 SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {} 21 22 // Primitives visit(const char * name,float & f)23 void visit(const char* name, float& f) override { 24 fWriter.appendFloat(name, f); 25 } visit(const char * name,int & i)26 void visit(const char* name, int& i) override { 27 fWriter.appendS32(name, i); 28 } visit(const char * name,bool & b)29 void visit(const char* name, bool& b) override { 30 fWriter.appendBool(name, b); 31 } visit(const char * name,SkString & s)32 void visit(const char* name, SkString& s) override { 33 if (s.contains('\n')) { 34 SkTArray<SkString> lines; 35 SkStrSplit(s.c_str(), "\n", kStrict_SkStrSplitMode, &lines); 36 fWriter.beginArray(name); 37 for (const auto& line : lines) { 38 fWriter.appendString(line.c_str()); 39 } 40 fWriter.endArray(); 41 } else { 42 fWriter.appendString(name, s.c_str()); 43 } 44 } 45 46 // Compound types visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)47 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override { 48 fWriter.appendString("Type", e ? e->getType()->fName : "Null"); 49 } 50 enterObject(const char * name)51 void enterObject(const char* name) override { fWriter.beginObject(name); } exitObject()52 void exitObject() override { fWriter.endObject(); } 53 enterArray(const char * name,int oldCount)54 int enterArray(const char* name, int oldCount) override { 55 fWriter.beginArray(name); 56 return oldCount; 57 } exitArray()58 ArrayEdit exitArray() override { 59 fWriter.endArray(); 60 return ArrayEdit(); 61 } 62 63 private: 64 SkJSONWriter& fWriter; 65 }; 66 67 class SkFromJsonVisitor : public SkFieldVisitor { 68 public: SkFromJsonVisitor(const skjson::Value & v)69 SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) { 70 fStack.push_back(&fRoot); 71 } 72 visit(const char * name,float & f)73 void visit(const char* name, float& f) override { 74 TryParse(get(name), f); 75 } visit(const char * name,int & i)76 void visit(const char* name, int& i) override { 77 TryParse(get(name), i); 78 } visit(const char * name,bool & b)79 void visit(const char* name, bool& b) override { 80 TryParse(get(name), b); 81 } visit(const char * name,SkString & s)82 void visit(const char* name, SkString& s) override { 83 if (const skjson::ArrayValue* lines = get(name)) { 84 s.reset(); 85 bool first = true; 86 for (const skjson::StringValue* line : *lines) { 87 if (line) { 88 if (!first) { 89 s.append("\n"); 90 } 91 s.append(line->begin(), line->size()); 92 first = false; 93 } 94 } 95 } else { 96 TryParse(get(name), s); 97 } 98 } 99 visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)100 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override { 101 const skjson::StringValue* typeString = get("Type"); 102 const char* type = typeString ? typeString->begin() : "Null"; 103 e = SkReflected::CreateInstance(type); 104 } 105 enterObject(const char * name)106 void enterObject(const char* name) override { 107 fStack.push_back((const skjson::ObjectValue*)get(name)); 108 } exitObject()109 void exitObject() override { 110 fStack.pop_back(); 111 } 112 enterArray(const char * name,int oldCount)113 int enterArray(const char* name, int oldCount) override { 114 const skjson::ArrayValue* arrVal = get(name); 115 fStack.push_back(arrVal); 116 fArrayIndexStack.push_back(0); 117 return arrVal ? arrVal->size() : 0; 118 } exitArray()119 ArrayEdit exitArray() override { 120 fStack.pop_back(); 121 fArrayIndexStack.pop_back(); 122 return ArrayEdit(); 123 } 124 125 private: get(const char * name)126 const skjson::Value& get(const char* name) { 127 if (const skjson::Value* cur = fStack.back()) { 128 if (cur->is<skjson::ArrayValue>()) { 129 SkASSERT(!name); 130 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++]; 131 } else if (!name) { 132 return *cur; 133 } else if (cur->is<skjson::ObjectValue>()) { 134 return cur->as<skjson::ObjectValue>()[name]; 135 } 136 } 137 static skjson::NullValue gNull; 138 return gNull; 139 } 140 TryParse(const skjson::Value & v,float & f)141 static bool TryParse(const skjson::Value& v, float& f) { 142 if (const skjson::NumberValue* num = v) { 143 f = static_cast<float>(**num); 144 return true; 145 } 146 return false; 147 } 148 TryParse(const skjson::Value & v,int & i)149 static bool TryParse(const skjson::Value& v, int& i) { 150 if (const skjson::NumberValue* num = v) { 151 double dbl = **num; 152 i = static_cast<int>(dbl); 153 return static_cast<double>(i) == dbl; 154 } 155 return false; 156 } 157 TryParse(const skjson::Value & v,SkString & s)158 static bool TryParse(const skjson::Value& v, SkString& s) { 159 if (const skjson::StringValue* str = v) { 160 s.set(str->begin(), str->size()); 161 return true; 162 } 163 return false; 164 } 165 TryParse(const skjson::Value & v,bool & b)166 static bool TryParse(const skjson::Value& v, bool& b) { 167 switch (v.getType()) { 168 case skjson::Value::Type::kNumber: 169 b = SkToBool(*v.as<skjson::NumberValue>()); 170 return true; 171 case skjson::Value::Type::kBool: 172 b = *v.as<skjson::BoolValue>(); 173 return true; 174 default: 175 break; 176 } 177 178 return false; 179 } 180 181 const skjson::Value& fRoot; 182 SkSTArray<16, const skjson::Value*, true> fStack; 183 SkSTArray<16, size_t, true> fArrayIndexStack; 184 }; 185 186 #endif // SkParticleSerialization_DEFINED 187