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