blob: a5b9f37102523b5e67bb5608a1bfc343548bc06d [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 Osman112aa2d2019-02-15 10:45:56 -050012#include "SkCurve.h"
Brian Osman7c979f52019-02-12 13:27:51 -050013#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
Brian Osman7c979f52019-02-12 13:27:51 -050093struct SkPoint;
94
95class SkFieldVisitor {
96public:
97 virtual ~SkFieldVisitor() {}
98
Brian Osman2991cbe2019-02-19 10:45:56 -050099 virtual void visit(const char*, float&) = 0;
100 virtual void visit(const char*, int&) = 0;
101 virtual void visit(const char*, bool&) = 0;
102 virtual void visit(const char*, SkString&) = 0;
Brian Osman7c979f52019-02-12 13:27:51 -0500103
Brian Osman2991cbe2019-02-19 10:45:56 -0500104 virtual void visit(const char*, SkPoint&) = 0;
105 virtual void visit(const char*, SkColor4f&) = 0;
Brian Osman7c979f52019-02-12 13:27:51 -0500106
Brian Osman2991cbe2019-02-19 10:45:56 -0500107 virtual void visit(const char* name, SkCurve& c) {
Brian Osman112aa2d2019-02-15 10:45:56 -0500108 this->enterObject(name);
109 c.visitFields(this);
110 this->exitObject();
111 }
112
Brian Osman7c979f52019-02-12 13:27:51 -0500113 template <typename T>
114 void visit(const char* name, T& value) {
115 this->enterObject(name);
116 value.visitFields(this);
117 this->exitObject();
118 }
119
Brian Osman5de7ea42019-02-14 13:23:51 -0500120 template <typename T, bool MEM_MOVE>
121 void visit(const char* name, SkTArray<T, MEM_MOVE>& arr) {
122 arr.resize_back(this->enterArray(name, arr.count()));
123 for (int i = 0; i < arr.count(); ++i) {
124 this->visit(nullptr, arr[i]);
Brian Osman7c979f52019-02-12 13:27:51 -0500125 }
Brian Osman5de7ea42019-02-14 13:23:51 -0500126 this->exitArray().apply(arr);
Brian Osman7c979f52019-02-12 13:27:51 -0500127 }
128
129 template <typename T>
130 void visit(const char* name, sk_sp<T>& obj) {
131 this->enterObject(name);
132
133 sk_sp<SkReflected> newObj = obj;
134 this->visit(newObj, T::GetType());
135 if (newObj != obj) {
136 if (!newObj || newObj->isOfType(T::GetType())) {
137 obj.reset(static_cast<T*>(newObj.release()));
138 } else {
139 obj.reset();
140 }
141 }
142
143 if (obj) {
144 obj->visitFields(this);
145 }
146 this->exitObject();
147 }
148
149protected:
Brian Osman5de7ea42019-02-14 13:23:51 -0500150 struct ArrayEdit {
151 enum class Verb {
152 kNone,
153 kRemove,
154 kMoveForward,
155 };
156
157 Verb fVerb = Verb::kNone;
158 int fIndex = 0;
159
160 template <typename T, bool MEM_MOVE>
161 void apply(SkTArray<T, MEM_MOVE>& arr) const {
162 switch (fVerb) {
163 case Verb::kNone:
164 break;
165 case Verb::kRemove:
166 for (int i = fIndex; i < arr.count() - 1; ++i) {
167 arr[i] = arr[i + 1];
168 }
169 arr.pop_back();
170 break;
171 case Verb::kMoveForward:
172 if (fIndex > 0 && fIndex < arr.count()) {
173 std::swap(arr[fIndex - 1], arr[fIndex]);
174 }
175 break;
176 }
177 }
178 };
179
Brian Osman7c979f52019-02-12 13:27:51 -0500180 virtual void enterObject(const char* name) = 0;
181 virtual void exitObject() = 0;
Brian Osman5de7ea42019-02-14 13:23:51 -0500182
183 virtual int enterArray(const char* name, int oldCount) = 0;
184 virtual ArrayEdit exitArray() = 0;
185
Brian Osman7c979f52019-02-12 13:27:51 -0500186 virtual void visit(sk_sp<SkReflected>&, const SkReflected::Type* baseType) = 0;
Brian Osman7c979f52019-02-12 13:27:51 -0500187};
188
189#endif // SkReflected_DEFINED