| Flutter Impeller |

capture.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef FLUTTER_IMPELLER_CORE_CAPTURE_H_
6 #define FLUTTER_IMPELLER_CORE_CAPTURE_H_
7
8 #include <functional>
9 #include <initializer_list>
10 #include <memory>
11 #include <string>
12 #include <type_traits>
13 #include <unordered_map>
14 #include <unordered_set>
15 #include <vector>
16
17 #include "flutter/fml/logging.h"
18 #include "flutter/fml/macros.h"
19 #include "impeller/geometry/color.h"
20 #include "impeller/geometry/matrix.h"
21 #include "impeller/geometry/point.h"
22 #include "impeller/geometry/rect.h"
23 #include "impeller/geometry/scalar.h"
24 #include "impeller/geometry/vector.h"
25
26 namespace impeller {
27
28 struct CaptureProcTable;
29
30 #define _FOR_EACH_CAPTURE_PROPERTY(PROPERTY_V) \
31 PROPERTY_V(bool, Boolean, boolean) \
32 PROPERTY_V(int, Integer, integer) \
33 PROPERTY_V(Scalar, Scalar, scalar) \
34 PROPERTY_V(Point, Point, point) \
35 PROPERTY_V(Vector3, Vector3, vector3) \
36 PROPERTY_V(Rect, Rect, rect) \
37 PROPERTY_V(Color, Color, color) \
38 PROPERTY_V(Matrix, Matrix, matrix) \
39 PROPERTY_V(std::string, String, string)
40
41 template <typename Type>
42 struct CaptureCursorListElement {
43 std::string label;
44
45 explicit CaptureCursorListElement(const std::string& label) : label(label){};
46
47 virtual ~CaptureCursorListElement() = default;
48
49 //----------------------------------------------------------------------------
50 /// @brief Determines if previously captured data matches closely enough with
51 /// newly recorded data to safely emitted in its place. If this
52 /// returns `false`, then the remaining elements in the capture list
53 /// are discarded and re-recorded.
54 ///
55 /// This mechanism ensures that the UI of an interactive inspector can
56 /// never deviate from reality, even if the schema of the captured
57 /// data were to significantly deviate.
58 ///
59 virtual bool MatchesCloselyEnough(const Type& other) const = 0;
60 };
61
62 #define _CAPTURE_TYPE(type_name, pascal_name, lower_name) k##pascal_name,
63
64 #define _CAPTURE_PROPERTY_CAST_DECLARATION(type_name, pascal_name, lower_name) \
65 std::optional<type_name> As##pascal_name() const;
66
67 /// A capturable property type
68 struct CaptureProperty : public CaptureCursorListElement<CaptureProperty> {
69 enum class Type { _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_TYPE) };
70
71 struct Options {
72 struct Range {
73 Scalar min;
74 Scalar max;
75 };
76
77 /// Readonly properties are always re-recorded during capture. Any edits
78 /// made to readonly values in-between captures are overwritten during the
79 /// next capture.
80 bool readonly = false;
81
82 /// An inspector hint that can be used for displaying sliders. Only used for
83 /// numeric types. Rounded down for integer types.
84 std::optional<Range> range;
85 };
86
87 Options options;
88
89 CaptureProperty(const std::string& label, Options options);
90
91 virtual ~CaptureProperty();
92
93 virtual Type GetType() const = 0;
94
95 virtual void Invoke(const CaptureProcTable& proc_table) = 0;
96
97 bool MatchesCloselyEnough(const CaptureProperty& other) const override;
98
99 _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_CAST_DECLARATION)
100 };
101
102 #define _CAPTURE_PROPERTY_DECLARATION(type_name, pascal_name, lower_name) \
103 struct Capture##pascal_name##Property final : public CaptureProperty { \
104 type_name value; \
105 \
106 static std::shared_ptr<Capture##pascal_name##Property> \
107 Make(const std::string& label, type_name value, Options options); \
108 \
109 /* |CaptureProperty| */ \
110 Type GetType() const override; \
111 \
112 /* |CaptureProperty| */ \
113 void Invoke(const CaptureProcTable& proc_table) override; \
114 \
115 private: \
116 Capture##pascal_name##Property(const std::string& label, \
117 type_name value, \
118 Options options); \
119 \
120 FML_DISALLOW_COPY_AND_ASSIGN(Capture##pascal_name##Property); \
121 };
122
123 _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_DECLARATION);
124
125 #define _CAPTURE_PROC(type_name, pascal_name, lower_name) \
126 std::function<void(Capture##pascal_name##Property&)> lower_name = \
127 [](Capture##pascal_name##Property& value) {};
128
129 struct CaptureProcTable {
130 _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROC)
131 };
132
133 template <typename Type>
134 class CapturePlaybackList {
135 public:
136 CapturePlaybackList() = default;
137
138 ~CapturePlaybackList() {
139 // Force the list element type to inherit the CRTP type. We can't enforce
140 // this as a template requirement directly because `CaptureElement` has a
141 // recursive `CaptureCursorList<CaptureElement>` property, and so the
142 // compiler fails the check due to the type being incomplete.
143 static_assert(std::is_base_of_v<CaptureCursorListElement<Type>, Type>);
144 }
145
146 void Rewind() { cursor_ = 0; }
147
148 size_t Count() { return values_.size(); }
149
150 std::shared_ptr<Type> GetNext(std::shared_ptr<Type> captured,
151 bool force_overwrite) {
152 if (cursor_ < values_.size()) {
153 std::shared_ptr<Type>& result = values_[cursor_];
154
155 if (result->MatchesCloselyEnough(*captured)) {
156 if (force_overwrite) {
157 values_[cursor_] = captured;
158 }
159 // Safe playback is possible.
160 ++cursor_;
161 return result;
162 }
163 // The data has changed too much from the last capture to safely continue
164 // playback. Discard this and all subsequent elements to re-record.
165 values_.resize(cursor_);
166 }
167
168 ++cursor_;
169 values_.push_back(captured);
170 return captured;
171 }
172
173 std::shared_ptr<Type> FindFirstByLabel(const std::string& label) {
174 for (std::shared_ptr<Type>& value : values_) {
175 if (value->label == label) {
176 return value;
177 }
178 }
179 return nullptr;
180 }
181
182 void Iterate(std::function<void(Type&)> iterator) const {
183 for (auto& value : values_) {
184 iterator(*value);
185 }
186 }
187
188 private:
189 size_t cursor_ = 0;
190 std::vector<std::shared_ptr<Type>> values_;
191
192 CapturePlaybackList(const CapturePlaybackList&) = delete;
193
194 CapturePlaybackList& operator=(const CapturePlaybackList&) = delete;
195 };
196
197 /// A document of capture data, containing a list of properties and a list
198 /// of subdocuments.
199 struct CaptureElement final : public CaptureCursorListElement<CaptureElement> {
200 CapturePlaybackList<CaptureProperty> properties;
201 CapturePlaybackList<CaptureElement> children;
202
203 static std::shared_ptr<CaptureElement> Make(const std::string& label);
204
205 void Rewind();
206
207 bool MatchesCloselyEnough(const CaptureElement& other) const override;
208
209 private:
210 explicit CaptureElement(const std::string& label);
211
212 CaptureElement(const CaptureElement&) = delete;
213
214 CaptureElement& operator=(const CaptureElement&) = delete;
215 };
216
217 #ifdef IMPELLER_ENABLE_CAPTURE
218 #define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, \
219 lower_name) \
220 type_name Add##pascal_name(std::string_view label, type_name value, \
221 CaptureProperty::Options options = {});
222 #else
223 #define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, \
224 lower_name) \
225 inline type_name Add##pascal_name(std::string_view label, type_name value, \
226 CaptureProperty::Options options = {}) { \
227 return value; \
228 }
229 #endif
230
231 class Capture {
232 public:
233 explicit Capture(const std::string& label);
234
235 Capture();
236
237 static Capture MakeInactive();
238
239 inline Capture CreateChild(std::string_view label) {
240 #ifdef IMPELLER_ENABLE_CAPTURE
241 if (!active_) {
242 return Capture();
243 }
244
245 std::string label_copy = std::string(label);
246 auto new_capture = Capture(label_copy);
247 new_capture.element_ =
248 element_->children.GetNext(new_capture.element_, false);
249 new_capture.element_->Rewind();
250 return new_capture;
251 #else
252 return Capture();
253 #endif
254 }
255
256 std::shared_ptr<CaptureElement> GetElement() const;
257
258 void Rewind();
259
260 _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_RECORDER_DECLARATION)
261
262 private:
263 #ifdef IMPELLER_ENABLE_CAPTURE
264 std::shared_ptr<CaptureElement> element_;
265 bool active_ = false;
266 #endif
267 };
268
269 class CaptureContext {
270 public:
271 CaptureContext();
272
273 static CaptureContext MakeInactive();
274
275 static CaptureContext MakeAllowlist(
276 std::initializer_list<std::string> allowlist);
277
278 bool IsActive() const;
279
280 void Rewind();
281
282 Capture GetDocument(const std::string& label);
283
284 bool DoesDocumentExist(const std::string& label) const;
285
286 private:
287 struct InactiveFlag {};
288 explicit CaptureContext(InactiveFlag);
289 CaptureContext(std::initializer_list<std::string> allowlist);
290
291 #ifdef IMPELLER_ENABLE_CAPTURE
292 bool active_ = false;
293 std::optional<std::unordered_set<std::string>> allowlist_;
294 std::unordered_map<std::string, Capture> documents_;
295 #endif
296 };
297
298 } // namespace impeller
299
300 #endif // FLUTTER_IMPELLER_CORE_CAPTURE_H_
impeller::CapturePlaybackList::GetNext
std::shared_ptr< Type > GetNext(std::shared_ptr< Type > captured, bool force_overwrite)
Definition: capture.h:150
impeller::CaptureCursorListElement::MatchesCloselyEnough
virtual bool MatchesCloselyEnough(const Type &other) const =0
Determines if previously captured data matches closely enough with newly recorded data to safely emit...
impeller::Capture
Definition: capture.h:231
point.h
impeller::CaptureProperty::Options::Range::min
Scalar min
Definition: capture.h:73
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::CapturePlaybackList
Definition: capture.h:134
impeller::CaptureProperty::options
Options options
Definition: capture.h:87
_CAPTURE_PROC
#define _CAPTURE_PROC(type_name, pascal_name, lower_name)
Definition: capture.h:125
impeller::CapturePlaybackList::Iterate
void Iterate(std::function< void(Type &)> iterator) const
Definition: capture.h:182
impeller::CaptureElement::Rewind
void Rewind()
Definition: capture.cc:77
impeller::CaptureProperty::Options::Range
Definition: capture.h:72
impeller::Capture::MakeInactive
static Capture MakeInactive()
Definition: capture.cc:101
impeller::CapturePlaybackList::Count
size_t Count()
Definition: capture.h:148
impeller::CapturePlaybackList::FindFirstByLabel
std::shared_ptr< Type > FindFirstByLabel(const std::string &label)
Definition: capture.h:173
matrix.h
impeller::CaptureProperty::Options::Range::max
Scalar max
Definition: capture.h:74
impeller::Capture::GetElement
std::shared_ptr< CaptureElement > GetElement() const
Definition: capture.cc:105
impeller::CaptureCursorListElement::CaptureCursorListElement
CaptureCursorListElement(const std::string &label)
Definition: capture.h:45
impeller::CaptureContext::MakeAllowlist
static CaptureContext MakeAllowlist(std::initializer_list< std::string > allowlist)
Definition: capture.cc:159
impeller::CaptureElement::MatchesCloselyEnough
bool MatchesCloselyEnough(const CaptureElement &other) const override
Determines if previously captured data matches closely enough with newly recorded data to safely emit...
Definition: capture.cc:82
impeller::CaptureProperty::Options::range
std::optional< Range > range
Definition: capture.h:84
impeller::CaptureCursorListElement::label
std::string label
Definition: capture.h:43
impeller::CaptureContext
Definition: capture.h:269
impeller::CaptureProperty::Invoke
virtual void Invoke(const CaptureProcTable &proc_table)=0
impeller::CaptureCursorListElement::~CaptureCursorListElement
virtual ~CaptureCursorListElement()=default
impeller::CaptureContext::DoesDocumentExist
bool DoesDocumentExist(const std::string &label) const
Definition: capture.cc:209
impeller::CaptureProperty::Options::readonly
bool readonly
Definition: capture.h:80
impeller::CapturePlaybackList::Rewind
void Rewind()
Definition: capture.h:146
impeller::CaptureContext::Rewind
void Rewind()
Definition: capture.cc:172
impeller::_FOR_EACH_CAPTURE_PROPERTY
_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_CAST_DEFINITION)
impeller::CaptureElement::Make
static std::shared_ptr< CaptureElement > Make(const std::string &label)
Definition: capture.cc:73
_CAPTURE_TYPE
#define _CAPTURE_TYPE(type_name, pascal_name, lower_name)
Definition: capture.h:62
impeller::CapturePlaybackList::CapturePlaybackList
CapturePlaybackList()=default
impeller::CaptureElement::children
CapturePlaybackList< CaptureElement > children
Definition: capture.h:201
impeller::CaptureContext::MakeInactive
static CaptureContext MakeInactive()
Definition: capture.cc:155
impeller::CaptureElement
Definition: capture.h:199
impeller::CaptureProperty::MatchesCloselyEnough
bool MatchesCloselyEnough(const CaptureProperty &other) const override
Determines if previously captured data matches closely enough with newly recorded data to safely emit...
Definition: capture.cc:21
impeller::Capture::Rewind
void Rewind()
Definition: capture.cc:113
scalar.h
impeller::CaptureProperty::CaptureProperty
CaptureProperty(const std::string &label, Options options)
Definition: capture.cc:16
_FOR_EACH_CAPTURE_PROPERTY
#define _FOR_EACH_CAPTURE_PROPERTY(PROPERTY_V)
Definition: capture.h:30
impeller::CaptureProperty
A capturable property type.
Definition: capture.h:68
impeller::CaptureProperty::Type
Type
Definition: capture.h:69
_CAPTURE_PROPERTY_DECLARATION
#define _CAPTURE_PROPERTY_DECLARATION(type_name, pascal_name, lower_name)
Definition: capture.h:102
vector.h
impeller::CaptureProperty::~CaptureProperty
virtual ~CaptureProperty()
rect.h
impeller::CaptureContext::IsActive
bool IsActive() const
Definition: capture.cc:164
impeller::CaptureProcTable
Definition: capture.h:129
impeller::CaptureContext::CaptureContext
CaptureContext()
Definition: capture.cc:149
impeller::CaptureProperty::Type::_FOR_EACH_CAPTURE_PROPERTY
@ _FOR_EACH_CAPTURE_PROPERTY
impeller::CaptureProperty::Options
Definition: capture.h:71
color.h
impeller::CaptureCursorListElement
Definition: capture.h:42
impeller::Capture::Capture
Capture()
impeller::CapturePlaybackList::~CapturePlaybackList
~CapturePlaybackList()
Definition: capture.h:138
impeller::CaptureContext::GetDocument
Capture GetDocument(const std::string &label)
Definition: capture.cc:182
_CAPTURE_PROPERTY_CAST_DECLARATION
#define _CAPTURE_PROPERTY_CAST_DECLARATION(type_name, pascal_name, lower_name)
Definition: capture.h:64
impeller::Capture::CreateChild
Capture CreateChild(std::string_view label)
Definition: capture.h:239
_CAPTURE_PROPERTY_RECORDER_DECLARATION
#define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, lower_name)
Definition: capture.h:223
impeller
Definition: aiks_context.cc:10
impeller::CaptureElement::properties
CapturePlaybackList< CaptureProperty > properties
Definition: capture.h:200
impeller::CaptureProperty::GetType
virtual Type GetType() const =0