Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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"
25
26namespace impeller {
27
28struct 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
41template <typename Type>
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
68struct CaptureProperty : public CaptureCursorListElement<CaptureProperty> {
70
71 struct Options {
72 struct Range {
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
88
89 CaptureProperty(const std::string& label, Options options);
90
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
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
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
132
133template <typename Type>
135 public:
137
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
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.
199struct CaptureElement final : public CaptureCursorListElement<CaptureElement> {
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
231class Capture {
232 public:
233 explicit Capture(const std::string& label);
234
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
261
262 private:
263#ifdef IMPELLER_ENABLE_CAPTURE
264 std::shared_ptr<CaptureElement> element_;
265 bool active_ = false;
266#endif
267};
268
270 public:
272
274
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_
#define _FOR_EACH_CAPTURE_PROPERTY(PROPERTY_V)
Definition capture.h:30
#define _CAPTURE_PROPERTY_CAST_DECLARATION(type_name, pascal_name, lower_name)
Definition capture.h:64
#define _CAPTURE_PROC(type_name, pascal_name, lower_name)
Definition capture.h:125
#define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, lower_name)
Definition capture.h:223
#define _CAPTURE_TYPE(type_name, pascal_name, lower_name)
Definition capture.h:62
#define _CAPTURE_PROPERTY_DECLARATION(type_name, pascal_name, lower_name)
Definition capture.h:102
bool IsActive() const
Definition capture.cc:164
bool DoesDocumentExist(const std::string &label) const
Definition capture.cc:209
static CaptureContext MakeInactive()
Definition capture.cc:155
Capture GetDocument(const std::string &label)
Definition capture.cc:182
static CaptureContext MakeAllowlist(std::initializer_list< std::string > allowlist)
Definition capture.cc:159
std::shared_ptr< Type > FindFirstByLabel(const std::string &label)
Definition capture.h:173
void Iterate(std::function< void(Type &)> iterator) const
Definition capture.h:182
std::shared_ptr< Type > GetNext(std::shared_ptr< Type > captured, bool force_overwrite)
Definition capture.h:150
Capture CreateChild(std::string_view label)
Definition capture.h:239
std::shared_ptr< CaptureElement > GetElement() const
Definition capture.cc:105
static Capture MakeInactive()
Definition capture.cc:101
uint8_t value
GAsyncResult * result
float Scalar
Definition scalar.h:18
virtual ~CaptureCursorListElement()=default
CaptureCursorListElement(const std::string &label)
Definition capture.h:45
virtual bool MatchesCloselyEnough(const Type &other) const =0
Determines if previously captured data matches closely enough with newly recorded data to safely emit...
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
CapturePlaybackList< CaptureElement > children
Definition capture.h:201
CapturePlaybackList< CaptureProperty > properties
Definition capture.h:200
static std::shared_ptr< CaptureElement > Make(const std::string &label)
Definition capture.cc:73
std::optional< Range > range
Definition capture.h:84
A capturable property type.
Definition capture.h:68
virtual Type GetType() const =0
virtual void Invoke(const CaptureProcTable &proc_table)=0
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