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"
22 #include "impeller/geometry/rect.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>
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> {
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 
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 
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 
131 };
132 
133 template <typename Type>
135  public:
136  CapturePlaybackList() = default;
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 
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> {
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 
261 
262  private:
263 #ifdef IMPELLER_ENABLE_CAPTURE
264  std::shared_ptr<CaptureElement> element_;
265  bool active_ = false;
266 #endif
267 };
268 
270  public:
271  CaptureContext();
272 
273  static CaptureContext MakeInactive();
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_
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_blur_unittests.cc:20
impeller::CaptureElement::properties
CapturePlaybackList< CaptureProperty > properties
Definition: capture.h:200
impeller::CaptureProperty::GetType
virtual Type GetType() const =0