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: SkToJsonVisitor(SkJSONWriter & writer)19 SkToJsonVisitor(SkJSONWriter& writer) : fWriter(writer) {} 20 21 // Primitives visit(const char * name,float & f)22 void visit(const char* name, float& f) override { 23 fWriter.appendFloat(name, f); 24 } visit(const char * name,int & i)25 void visit(const char* name, int& i) override { 26 fWriter.appendS32(name, i); 27 } visit(const char * name,bool & b)28 void visit(const char* name, bool& b) override { 29 fWriter.appendBool(name, b); 30 } visit(const char * name,SkString & s)31 void visit(const char* name, SkString& s) override { 32 fWriter.appendString(name, s.c_str()); 33 } visit(const char * name,int & i,const EnumStringMapping * map,int count)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 visit(const char * name,SkPoint & p)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 visit(const char * name,SkColor4f & c)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 visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)55 void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override { 56 fWriter.appendString("Type", e ? e->getType()->fName : "Null"); 57 } 58 enterObject(const char * name)59 void enterObject(const char* name) override { fWriter.beginObject(name); } exitObject()60 void exitObject() override { fWriter.endObject(); } 61 enterArray(const char * name,int oldCount)62 int enterArray(const char* name, int oldCount) override { 63 fWriter.beginArray(name); 64 return oldCount; 65 } exitArray()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: SkFromJsonVisitor(const skjson::Value & v)77 SkFromJsonVisitor(const skjson::Value& v) : fRoot(v) { 78 fStack.push_back(&fRoot); 79 } 80 visit(const char * name,float & f)81 void visit(const char* name, float& f) override { 82 TryParse(get(name), f); 83 } visit(const char * name,int & i)84 void visit(const char* name, int& i) override { 85 TryParse(get(name), i); 86 } visit(const char * name,bool & b)87 void visit(const char* name, bool& b) override { 88 TryParse(get(name), b); 89 } visit(const char * name,SkString & s)90 void visit(const char* name, SkString& s) override { 91 TryParse(get(name), s); 92 } visit(const char * name,int & i,const EnumStringMapping * map,int count)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 visit(const char * name,SkPoint & p)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 visit(const char * name,SkColor4f & c)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 visit(sk_sp<SkReflected> & e,const SkReflected::Type * baseType)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 enterObject(const char * name)123 void enterObject(const char* name) override { 124 fStack.push_back((const skjson::ObjectValue*)get(name)); 125 } exitObject()126 void exitObject() override { 127 fStack.pop_back(); 128 } 129 enterArray(const char * name,int oldCount)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 } exitArray()136 ArrayEdit exitArray() override { 137 fStack.pop_back(); 138 fArrayIndexStack.pop_back(); 139 return ArrayEdit(); 140 } 141 142 private: get(const char * name)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 TryParse(const skjson::Value & v,float & f)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 TryParse(const skjson::Value & v,int & i)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 TryParse(const skjson::Value & v,SkString & s)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 TryParse(const skjson::Value & v,bool & b)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