blob: 6b9d689e4d5be448de3614b01f9c93f45e42dc33 [file] [log] [blame]
Brian Osman7c979f52019-02-12 13:27:51 -05001/*
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 SkReflected_DEFINED
9#define SkReflected_DEFINED
10
11#include "SkColor.h"
12#include "SkCurve.h"
13#include "SkRefCnt.h"
14#include "SkString.h"
15#include "SkTArray.h"
16
17class SkFieldVisitor;
18class SkRandom;
19
20class SkReflected : public SkRefCnt {
21public:
22 typedef sk_sp<SkReflected>(*Factory)();
23 struct Type {
24 const char* fName;
25 const Type* fBase;
26 Factory fFactory;
27
28 bool isDerivedFrom(const Type* t) const {
29 const Type* base = fBase;
30 while (base) {
31 if (base == t) {
32 return true;
33 }
34 base = base->fBase;
35 }
36 return false;
37 }
38 };
39
40 virtual const Type* getType() const = 0;
41 static const Type* GetType() {
42 static Type gType{ "SkReflected", nullptr, nullptr };
43 return &gType;
44 }
45
46 bool isOfType(const Type* t) const {
47 const Type* thisType = this->getType();
48 return thisType == t || thisType->isDerivedFrom(t);
49 }
50
51 static void Register(const Type* type) {
52 gTypes.push_back(type);
53 }
54
55 static sk_sp<SkReflected> CreateInstance(const char* name) {
56 for (const Type* type : gTypes) {
57 if (0 == strcmp(name, type->fName)) {
58 return type->fFactory();
59 }
60 }
61 return nullptr;
62 }
63
64 virtual void visitFields(SkFieldVisitor*) = 0;
65
66 static void VisitTypes(std::function<void(const Type*)> visitor,
67 const Type* baseType = nullptr);
68private:
69 static SkSTArray<16, const Type*, true> gTypes;
70};
71
72#define REFLECTED(TYPE, BASE) \
73 static sk_sp<SkReflected> CreateProc() { \
74 return sk_sp<SkReflected>(new TYPE()); \
75 } \
76 static const Type* GetType() { \
77 static Type gType{ #TYPE, BASE::GetType(), CreateProc }; \
78 return &gType; \
79 } \
80 const Type* getType() const override { return GetType(); }
81
82#define REFLECTED_ABSTRACT(TYPE, BASE) \
83 static const Type* GetType() { \
84 static Type gType{ #TYPE, BASE::GetType(), nullptr }; \
85 return &gType; \
86 } \
87 const Type* getType() const override { return GetType(); }
88
89#define REGISTER_REFLECTED(TYPE) SkReflected::Register(TYPE::GetType())
90
91///////////////////////////////////////////////////////////////////////////////
92
93struct SkField {
94 // Other useful flags/properties:
95 // No UI (to avoid editing dangerous things)
96 // Point vs. vector
97 // Range limits
98 enum SkFieldFlags {
99 kAngle_Field = 0x1,
100 };
101
102 SkField(uint32_t flags = 0)
103 : fFlags(flags) {}
104
105 uint32_t fFlags;
106};
107
108struct SkPoint;
109
110class SkFieldVisitor {
111public:
112 virtual ~SkFieldVisitor() {}
113
114 virtual void visit(const char*, float&, SkField = SkField()) = 0;
115 virtual void visit(const char*, int&, SkField = SkField()) = 0;
116 virtual void visit(const char*, bool&, SkField = SkField()) = 0;
117 virtual void visit(const char*, SkString&, SkField = SkField()) = 0;
118
119 virtual void visit(const char*, SkPoint&, SkField = SkField()) = 0;
120 virtual void visit(const char*, SkColor4f&, SkField = SkField()) = 0;
121
122 virtual void visit(const char* name, SkCurve& curve, SkField = SkField()) {
123 this->enterObject(name);
124 curve.visitFields(this);
125 this->exitObject();
126 }
127
128 template <typename T>
129 void visit(const char* name, T& value) {
130 this->enterObject(name);
131 value.visitFields(this);
132 this->exitObject();
133 }
134
135 template <typename T>
136 void visit(const char* name, SkTArray<sk_sp<T>>& arr) {
137 SkTArray<sk_sp<SkReflected>> newArr;
138 for (auto ptr : arr) {
139 newArr.push_back(ptr);
140 }
141
142 this->visit(name, newArr, T::GetType());
143
144 arr.reset();
145 for (auto ptr : newArr) {
146 if (ptr && !ptr->isOfType(T::GetType())) {
147 ptr.reset();
148 }
149 sk_sp<T> newPtr(static_cast<T*>(ptr.release()));
150 arr.push_back(std::move(newPtr));
151 }
152 }
153
154 template <typename T>
155 void visit(const char* name, sk_sp<T>& obj) {
156 this->enterObject(name);
157
158 sk_sp<SkReflected> newObj = obj;
159 this->visit(newObj, T::GetType());
160 if (newObj != obj) {
161 if (!newObj || newObj->isOfType(T::GetType())) {
162 obj.reset(static_cast<T*>(newObj.release()));
163 } else {
164 obj.reset();
165 }
166 }
167
168 if (obj) {
169 obj->visitFields(this);
170 }
171 this->exitObject();
172 }
173
174protected:
175 virtual void enterObject(const char* name) = 0;
176 virtual void exitObject() = 0;
177 virtual void visit(sk_sp<SkReflected>&, const SkReflected::Type* baseType) = 0;
178 virtual void visit(const char* name, SkTArray<sk_sp<SkReflected>>&,
179 const SkReflected::Type* baseType) = 0;
180};
181
182#endif // SkReflected_DEFINED