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 } visit(const char * name,int & i,const EnumStringMapping * map,int count)45 void visit(const char* name, int& i, const EnumStringMapping* map, int count) override { 46 fWriter.appendString(name, EnumToString(i, map, count)); 47 } 48 49 // Compound types visit(const char * name,SkPoint & p)50 void visit(const char* name, SkPoint& p) override { 51 fWriter.beginObject(name, false); 52 fWriter.appendFloat("x", p.fX); 53 fWriter.appendFloat("y", p.fY); 54 fWriter.endObject(); 55 } 56 visit(const char * name,SkColor4f & c)57 void visit(const char* name, SkColor4f& c) override { 58 fWriter.beginArray(name, false); 59 fWriter.appendFloat(c.fR); 60 fWriter.appendFloat(c.fG); 61 fWriter.appendFloat(c.fB); 62 fWriter.appendFloat(c.fA); 63 fWriter.endArray(); 64 } 65 visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)66 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override { 67 fWriter.appendString("Type", e ? e->getType()->fName : "Null"); 68 } 69 enterObject(const char * name)70 void enterObject(const char* name) override { fWriter.beginObject(name); } exitObject()71 void exitObject() override { fWriter.endObject(); } 72 enterArray(const char * name,int oldCount)73 int enterArray(const char* name, int oldCount) override { 74 fWriter.beginArray(name); 75 return oldCount; 76 } exitArray()77 ArrayEdit exitArray() override { 78 fWriter.endArray(); 79 return ArrayEdit(); 80 } 81 82 private: 83 SkJSONWriter& fWriter; 84 }; 85 86 class SkFromJsonVisitor : public SkFieldVisitor { 87 public: SkFromJsonVisitor(const skjson::Value & v)88 SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) { 89 fStack.push_back(&fRoot); 90 } 91 visit(const char * name,float & f)92 void visit(const char* name, float& f) override { 93 TryParse(get(name), f); 94 } visit(const char * name,int & i)95 void visit(const char* name, int& i) override { 96 TryParse(get(name), i); 97 } visit(const char * name,bool & b)98 void visit(const char* name, bool& b) override { 99 TryParse(get(name), b); 100 } visit(const char * name,SkString & s)101 void visit(const char* name, SkString& s) override { 102 if (const skjson::ArrayValue* lines = get(name)) { 103 s.reset(); 104 bool first = true; 105 for (const skjson::StringValue* line : *lines) { 106 if (line) { 107 if (!first) { 108 s.append("\n"); 109 } 110 s.append(line->begin(), line->size()); 111 first = false; 112 } 113 } 114 } else { 115 TryParse(get(name), s); 116 } 117 } visit(const char * name,int & i,const EnumStringMapping * map,int count)118 void visit(const char* name, int& i, const EnumStringMapping* map, int count) override { 119 SkString str; 120 if (TryParse(get(name), str)) { 121 i = StringToEnum(str.c_str(), map, count); 122 } 123 } 124 visit(const char * name,SkPoint & p)125 void visit(const char* name, SkPoint& p) override { 126 if (const skjson::ObjectValue* obj = get(name)) { 127 TryParse((*obj)["x"], p.fX); 128 TryParse((*obj)["y"], p.fY); 129 } 130 } 131 visit(const char * name,SkColor4f & c)132 void visit(const char* name, SkColor4f& c) override { 133 const skjson::ArrayValue* arr = get(name); 134 if (arr && arr->size() == 4) { 135 TryParse((*arr)[0], c.fR); 136 TryParse((*arr)[1], c.fG); 137 TryParse((*arr)[2], c.fB); 138 TryParse((*arr)[3], c.fA); 139 } 140 } 141 visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)142 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override { 143 const skjson::StringValue* typeString = get("Type"); 144 const char* type = typeString ? typeString->begin() : "Null"; 145 e = SkReflected::CreateInstance(type); 146 } 147 enterObject(const char * name)148 void enterObject(const char* name) override { 149 fStack.push_back((const skjson::ObjectValue*)get(name)); 150 } exitObject()151 void exitObject() override { 152 fStack.pop_back(); 153 } 154 enterArray(const char * name,int oldCount)155 int enterArray(const char* name, int oldCount) override { 156 const skjson::ArrayValue* arrVal = get(name); 157 fStack.push_back(arrVal); 158 fArrayIndexStack.push_back(0); 159 return arrVal ? arrVal->size() : 0; 160 } exitArray()161 ArrayEdit exitArray() override { 162 fStack.pop_back(); 163 fArrayIndexStack.pop_back(); 164 return ArrayEdit(); 165 } 166 167 private: get(const char * name)168 const skjson::Value& get(const char* name) { 169 if (const skjson::Value* cur = fStack.back()) { 170 if (cur->is<skjson::ArrayValue>()) { 171 SkASSERT(!name); 172 return cur->as<skjson::ArrayValue>()[fArrayIndexStack.back()++]; 173 } else if (!name) { 174 return *cur; 175 } else if (cur->is<skjson::ObjectValue>()) { 176 return cur->as<skjson::ObjectValue>()[name]; 177 } 178 } 179 static skjson::NullValue gNull; 180 return gNull; 181 } 182 TryParse(const skjson::Value & v,float & f)183 static bool TryParse(const skjson::Value& v, float& f) { 184 if (const skjson::NumberValue* num = v) { 185 f = static_cast<float>(**num); 186 return true; 187 } 188 return false; 189 } 190 TryParse(const skjson::Value & v,int & i)191 static bool TryParse(const skjson::Value& v, int& i) { 192 if (const skjson::NumberValue* num = v) { 193 double dbl = **num; 194 i = static_cast<int>(dbl); 195 return static_cast<double>(i) == dbl; 196 } 197 return false; 198 } 199 TryParse(const skjson::Value & v,SkString & s)200 static bool TryParse(const skjson::Value& v, SkString& s) { 201 if (const skjson::StringValue* str = v) { 202 s.set(str->begin(), str->size()); 203 return true; 204 } 205 return false; 206 } 207 TryParse(const skjson::Value & v,bool & b)208 static bool TryParse(const skjson::Value& v, bool& b) { 209 switch (v.getType()) { 210 case skjson::Value::Type::kNumber: 211 b = SkToBool(*v.as<skjson::NumberValue>()); 212 return true; 213 case skjson::Value::Type::kBool: 214 b = *v.as<skjson::BoolValue>(); 215 return true; 216 default: 217 break; 218 } 219 220 return false; 221 } 222 223 const skjson::Value& fRoot; 224 SkSTArray<16, const skjson::Value*, true> fStack; 225 SkSTArray<16, size_t, true> fArrayIndexStack; 226 }; 227 228 #endif // SkParticleSerialization_DEFINED 229