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