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_FLOW_EMBEDDED_VIEWS_H_
6#define FLUTTER_FLOW_EMBEDDED_VIEWS_H_
7
8#include <vector>
9
10#include "flutter/flow/surface_frame.h"
11#include "flutter/fml/memory/ref_counted.h"
12#include "flutter/fml/raster_thread_merger.h"
13#include "third_party/skia/include/core/SkCanvas.h"
14#include "third_party/skia/include/core/SkPath.h"
15#include "third_party/skia/include/core/SkPoint.h"
16#include "third_party/skia/include/core/SkRRect.h"
17#include "third_party/skia/include/core/SkRect.h"
18#include "third_party/skia/include/core/SkSize.h"
19#include "third_party/skia/include/core/SkSurface.h"
20
21namespace flutter {
22
23// TODO(chinmaygarde): Make these enum names match the style guide.
24enum MutatorType { clip_rect, clip_rrect, clip_path, transform, opacity };
25
26// Stores mutation information like clipping or transform.
27//
28// The `type` indicates the type of the mutation: clip_rect, transform and etc.
29// Each `type` is paired with an object that supports the mutation. For example,
30// if the `type` is clip_rect, `rect()` is used the represent the rect to be
31// clipped. One mutation object must only contain one type of mutation.
32class Mutator {
33 public:
34 Mutator(const Mutator& other) {
35 type_ = other.type_;
36 switch (other.type_) {
37 case clip_rect:
38 rect_ = other.rect_;
39 break;
40 case clip_rrect:
41 rrect_ = other.rrect_;
42 break;
43 case clip_path:
44 path_ = new SkPath(*other.path_);
45 break;
46 case transform:
47 matrix_ = other.matrix_;
48 break;
49 case opacity:
50 alpha_ = other.alpha_;
51 break;
52 default:
53 break;
54 }
55 }
56
57 explicit Mutator(const SkRect& rect) : type_(clip_rect), rect_(rect) {}
58 explicit Mutator(const SkRRect& rrect) : type_(clip_rrect), rrect_(rrect) {}
59 explicit Mutator(const SkPath& path)
60 : type_(clip_path), path_(new SkPath(path)) {}
61 explicit Mutator(const SkMatrix& matrix)
62 : type_(transform), matrix_(matrix) {}
63 explicit Mutator(const int& alpha) : type_(opacity), alpha_(alpha) {}
64
65 const MutatorType& GetType() const { return type_; }
66 const SkRect& GetRect() const { return rect_; }
67 const SkRRect& GetRRect() const { return rrect_; }
68 const SkPath& GetPath() const { return *path_; }
69 const SkMatrix& GetMatrix() const { return matrix_; }
70 const int& GetAlpha() const { return alpha_; }
71 float GetAlphaFloat() const { return (alpha_ / 255.0); }
72
73 bool operator==(const Mutator& other) const {
74 if (type_ != other.type_) {
75 return false;
76 }
77 switch (type_) {
78 case clip_rect:
79 return rect_ == other.rect_;
80 case clip_rrect:
81 return rrect_ == other.rrect_;
82 case clip_path:
83 return *path_ == *other.path_;
84 case transform:
85 return matrix_ == other.matrix_;
86 case opacity:
87 return alpha_ == other.alpha_;
88 }
89
90 return false;
91 }
92
93 bool operator!=(const Mutator& other) const { return !operator==(other); }
94
95 bool IsClipType() {
96 return type_ == clip_rect || type_ == clip_rrect || type_ == clip_path;
97 }
98
99 ~Mutator() {
100 if (type_ == clip_path) {
101 delete path_;
102 }
103 };
104
105 private:
106 MutatorType type_;
107
108 union {
109 SkRect rect_;
110 SkRRect rrect_;
111 SkMatrix matrix_;
112 SkPath* path_;
113 int alpha_;
114 };
115
116}; // Mutator
117
118// A stack of mutators that can be applied to an embedded platform view.
119//
120// The stack may include mutators like transforms and clips, each mutator
121// applies to all the mutators that are below it in the stack and to the
122// embedded view.
123//
124// For example consider the following stack: [T1, T2, T3], where T1 is the top
125// of the stack and T3 is the bottom of the stack. Applying this mutators stack
126// to a platform view P1 will result in T1(T2(T2(P1))).
127class MutatorsStack {
128 public:
129 MutatorsStack() = default;
130
131 void PushClipRect(const SkRect& rect);
132 void PushClipRRect(const SkRRect& rrect);
133 void PushClipPath(const SkPath& path);
134 void PushTransform(const SkMatrix& matrix);
135 void PushOpacity(const int& alpha);
136
137 // Removes the `Mutator` on the top of the stack
138 // and destroys it.
139 void Pop();
140
141 // Returns a reverse iterator pointing to the top of the stack, which is the
142 // mutator that is furtherest from the leaf node.
143 const std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator Top()
144 const;
145 // Returns a reverse iterator pointing to the bottom of the stack, which is
146 // the mutator that is closeset from the leaf node.
147 const std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator Bottom()
148 const;
149
150 // Returns an iterator pointing to the begining of the mutator vector, which
151 // is the mutator that is furtherest from the leaf node.
152 const std::vector<std::shared_ptr<Mutator>>::const_iterator Begin() const;
153
154 // Returns an iterator pointing to the end of the mutator vector, which is the
155 // mutator that is closest from the leaf node.
156 const std::vector<std::shared_ptr<Mutator>>::const_iterator End() const;
157
158 bool is_empty() const { return vector_.empty(); }
159
160 bool operator==(const MutatorsStack& other) const {
161 if (vector_.size() != other.vector_.size()) {
162 return false;
163 }
164 for (size_t i = 0; i < vector_.size(); i++) {
165 if (*vector_[i] != *other.vector_[i]) {
166 return false;
167 }
168 }
169 return true;
170 }
171
172 bool operator==(const std::vector<Mutator>& other) const {
173 if (vector_.size() != other.size()) {
174 return false;
175 }
176 for (size_t i = 0; i < vector_.size(); i++) {
177 if (*vector_[i] != other[i]) {
178 return false;
179 }
180 }
181 return true;
182 }
183
184 bool operator!=(const MutatorsStack& other) const {
185 return !operator==(other);
186 }
187
188 bool operator!=(const std::vector<Mutator>& other) const {
189 return !operator==(other);
190 }
191
192 private:
193 std::vector<std::shared_ptr<Mutator>> vector_;
194}; // MutatorsStack
195
196class EmbeddedViewParams {
197 public:
198 EmbeddedViewParams() = default;
199
200 EmbeddedViewParams(SkMatrix matrix,
201 SkSize size_points,
202 MutatorsStack mutators_stack)
203 : matrix_(matrix),
204 size_points_(size_points),
205 mutators_stack_(mutators_stack) {
206 SkPath path;
207 SkRect starting_rect = SkRect::MakeSize(size_points);
208 path.addRect(starting_rect);
209 path.transform(matrix);
210 final_bounding_rect_ = path.getBounds();
211 }
212
213 EmbeddedViewParams(const EmbeddedViewParams& other) {
214 size_points_ = other.size_points_;
215 mutators_stack_ = other.mutators_stack_;
216 matrix_ = other.matrix_;
217 final_bounding_rect_ = other.final_bounding_rect_;
218 };
219
220 // The original size of the platform view before any mutation matrix is
221 // applied.
222 const SkSize& sizePoints() const { return size_points_; };
223 // The mutators stack contains the detailed step by step mutations for this
224 // platform view.
225 const MutatorsStack& mutatorsStack() const { return mutators_stack_; };
226 // The bounding rect of the platform view after applying all the mutations.
227 //
228 // Clippings are ignored.
229 const SkRect& finalBoundingRect() const { return final_bounding_rect_; }
230
231 bool operator==(const EmbeddedViewParams& other) const {
232 return size_points_ == other.size_points_ &&
233 mutators_stack_ == other.mutators_stack_ &&
234 final_bounding_rect_ == other.final_bounding_rect_ &&
235 matrix_ == other.matrix_;
236 }
237
238 private:
239 SkMatrix matrix_;
240 SkSize size_points_;
241 MutatorsStack mutators_stack_;
242 SkRect final_bounding_rect_;
243};
244
245enum class PostPrerollResult { kResubmitFrame, kSuccess };
246
247// Facilitates embedding of platform views within the flow layer tree.
248//
249// Used on iOS, Android (hybrid composite mode), and on embedded platforms
250// that provide a system compositor as part of the project arguments.
251class ExternalViewEmbedder {
252 // TODO(cyanglaz): Make embedder own the `EmbeddedViewParams`.
253
254 public:
255 ExternalViewEmbedder() = default;
256
257 virtual ~ExternalViewEmbedder() = default;
258
259 // Usually, the root canvas is not owned by the view embedder. However, if
260 // the view embedder wants to provide a canvas to the rasterizer, it may
261 // return one here. This canvas takes priority over the canvas materialized
262 // from the on-screen render target.
263 virtual SkCanvas* GetRootCanvas() = 0;
264
265 // Call this in-lieu of |SubmitFrame| to clear pre-roll state and
266 // sets the stage for the next pre-roll.
267 virtual void CancelFrame() = 0;
268
269 virtual void BeginFrame(
270 SkISize frame_size,
271 GrDirectContext* context,
272 double device_pixel_ratio,
273 fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) = 0;
274
275 virtual void PrerollCompositeEmbeddedView(
276 int view_id,
277 std::unique_ptr<EmbeddedViewParams> params) = 0;
278
279 // This needs to get called after |Preroll| finishes on the layer tree.
280 // Returns kResubmitFrame if the frame needs to be processed again, this is
281 // after it does any requisite tasks needed to bring itself to a valid state.
282 // Returns kSuccess if the view embedder is already in a valid state.
283 virtual PostPrerollResult PostPrerollAction(
284 fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
285 return PostPrerollResult::kSuccess;
286 }
287
288 virtual std::vector<SkCanvas*> GetCurrentCanvases() = 0;
289
290 // Must be called on the UI thread.
291 virtual SkCanvas* CompositeEmbeddedView(int view_id) = 0;
292
293 // Implementers must submit the frame by calling frame.Submit().
294 //
295 // This method can mutate the root Skia canvas before submitting the frame.
296 //
297 // It can also allocate frames for overlay surfaces to compose hybrid views.
298 virtual void SubmitFrame(GrDirectContext* context,
299 std::unique_ptr<SurfaceFrame> frame);
300
301 // This method provides the embedder a way to do additional tasks after
302 // |SubmitFrame|. For example, merge task runners if `should_resubmit_frame`
303 // is true.
304 //
305 // For example on the iOS embedder, threads are merged in this call.
306 // A new frame on the platform thread starts immediately. If the GPU thread
307 // still has some task running, there could be two frames being rendered
308 // concurrently, which causes undefined behaviors.
309 virtual void EndFrame(
310 bool should_resubmit_frame,
311 fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {}
312
313 FML_DISALLOW_COPY_AND_ASSIGN(ExternalViewEmbedder);
314
315}; // ExternalViewEmbedder
316
317} // namespace flutter
318
319#endif // FLUTTER_FLOW_EMBEDDED_VIEWS_H_
320