blob: ed9d0257bce108e584c3a855be63d806d998633d [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
Brian Osman5de7ea42019-02-14 13:23:51 -0500135 template <typename T, bool MEM_MOVE>
136 void visit(const char* name, SkTArray<T, MEM_MOVE>& arr) {
137 arr.resize_back(this->enterArray(name, arr.count()));
138 for (int i = 0; i < arr.count(); ++i) {
139 this->visit(nullptr, arr[i]);
Brian Osman7c979f52019-02-12 13:27:51 -0500140 }
Brian Osman5de7ea42019-02-14 13:23:51 -0500141 this->exitArray().apply(arr);
Brian Osman7c979f52019-02-12 13:27:51 -0500142 }
143
144 template <typename T>
145 void visit(const char* name, sk_sp<T>& obj) {
146 this->enterObject(name);
147
148 sk_sp<SkReflected> newObj = obj;
149 this->visit(newObj, T::GetType());
150 if (newObj != obj) {
151 if (!newObj || newObj->isOfType(T::GetType())) {
152 obj.reset(static_cast<T*>(newObj.release()));
153 } else {
154 obj.reset();
155 }
156 }
157
158 if (obj) {
159 obj->visitFields(this);
160 }
161 this->exitObject();
162 }
163
164protected:
Brian Osman5de7ea42019-02-14 13:23:51 -0500165 struct ArrayEdit {
166 enum class Verb {
167 kNone,
168 kRemove,
169 kMoveForward,
170 };
171
172 Verb fVerb = Verb::kNone;
173 int fIndex = 0;
174
175 template <typename T, bool MEM_MOVE>
176 void apply(SkTArray<T, MEM_MOVE>& arr) const {
177 switch (fVerb) {
178 case Verb::kNone:
179 break;
180 case Verb::kRemove:
181 for (int i = fIndex; i < arr.count() - 1; ++i) {
182 arr[i] = arr[i + 1];
183 }
184 arr.pop_back();
185 break;
186 case Verb::kMoveForward:
187 if (fIndex > 0 && fIndex < arr.count()) {
188 std::swap(arr[fIndex - 1], arr[fIndex]);
189 }
190 break;
191 }
192 }
193 };
194
Brian Osman7c979f52019-02-12 13:27:51 -0500195 virtual void enterObject(const char* name) = 0;
196 virtual void exitObject() = 0;
Brian Osman5de7ea42019-02-14 13:23:51 -0500197
198 virtual int enterArray(const char* name, int oldCount) = 0;
199 virtual ArrayEdit exitArray() = 0;
200
Brian Osman7c979f52019-02-12 13:27:51 -0500201 virtual void visit(sk_sp<SkReflected>&, const SkReflected::Type* baseType) = 0;
Brian Osman7c979f52019-02-12 13:27:51 -0500202};
203
204#endif // SkReflected_DEFINED