Flutter iOS Embedder
FlutterPlatformViews_Internal.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_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
6 #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
7 
8 #include "flutter/flow/embedded_views.h"
9 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
10 #include "flutter/shell/common/shell.h"
17 
19 
20 // A UIView that acts as a clipping mask for the |ChildClippingView|.
21 //
22 // On the [UIView drawRect:] method, this view performs a series of clipping operations and sets the
23 // alpha channel to the final resulting area to be 1; it also sets the "clipped out" area's alpha
24 // channel to be 0.
25 //
26 // When a UIView sets a |FlutterClippingMaskView| as its `maskView`, the alpha channel of the UIView
27 // is replaced with the alpha channel of the |FlutterClippingMaskView|.
28 @interface FlutterClippingMaskView : UIView
29 
30 - (instancetype)initWithFrame:(CGRect)frame screenScale:(CGFloat)screenScale;
31 
32 - (void)reset;
33 
34 // Adds a clip rect operation to the queue.
35 //
36 // The `clipSkRect` is transformed with the `matrix` before adding to the queue.
37 - (void)clipRect:(const SkRect&)clipSkRect matrix:(const SkMatrix&)matrix;
38 
39 // Adds a clip rrect operation to the queue.
40 //
41 // The `clipSkRRect` is transformed with the `matrix` before adding to the queue.
42 - (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const SkMatrix&)matrix;
43 
44 // Adds a clip path operation to the queue.
45 //
46 // The `path` is transformed with the `matrix` before adding to the queue.
47 - (void)clipPath:(const SkPath&)path matrix:(const SkMatrix&)matrix;
48 
49 @end
50 
51 // A pool that provides |FlutterClippingMaskView|s.
52 //
53 // The pool has a capacity that can be set in the initializer.
54 // When requesting a FlutterClippingMaskView, the pool will first try to reuse an available maskView
55 // in the pool. If there are none available, a new FlutterClippingMaskView is constructed. If the
56 // capacity is reached, the newly constructed FlutterClippingMaskView is not added to the pool.
57 //
58 // Call |insertViewToPoolIfNeeded:| to return a maskView to the pool.
59 @interface FlutterClippingMaskViewPool : NSObject
60 
61 // Initialize the pool with `capacity`. When the `capacity` is reached, a FlutterClippingMaskView is
62 // constructed when requested, and it is not added to the pool.
63 - (instancetype)initWithCapacity:(NSInteger)capacity;
64 
65 // Reuse a maskView from the pool, or allocate a new one.
66 - (FlutterClippingMaskView*)getMaskViewWithFrame:(CGRect)frame;
67 
68 // Insert the `maskView` into the pool.
69 - (void)insertViewToPoolIfNeeded:(FlutterClippingMaskView*)maskView;
70 
71 @end
72 
73 // An object represents a blur filter.
74 //
75 // This object produces a `backdropFilterView`.
76 // To blur a View, add `backdropFilterView` as a subView of the View.
77 @interface PlatformViewFilter : NSObject
78 
79 // Determines the rect of the blur effect in the coordinate system of `backdropFilterView`'s
80 // parentView.
81 @property(assign, nonatomic, readonly) CGRect frame;
82 
83 // Determines the blur intensity.
84 //
85 // It is set as the value of `inputRadius` of the `gaussianFilter` that is internally used.
86 @property(assign, nonatomic, readonly) CGFloat blurRadius;
87 
88 // This is the view to use to blur the PlatformView.
89 //
90 // It is a modified version of UIKit's `UIVisualEffectView`.
91 // The inputRadius can be customized and it doesn't add any color saturation to the blurred view.
92 @property(nonatomic, retain, readonly) UIVisualEffectView* backdropFilterView;
93 
94 // For testing only.
95 + (void)resetPreparation;
96 
97 - (instancetype)init NS_UNAVAILABLE;
98 
99 // Initialize the filter object.
100 //
101 // The `frame` determines the rect of the blur effect in the coordinate system of
102 // `backdropFilterView`'s parentView. The `blurRadius` determines the blur intensity. It is set as
103 // the value of `inputRadius` of the `gaussianFilter` that is internally used. The
104 // `UIVisualEffectView` is the view that is used to add the blur effects. It is modified to become
105 // `backdropFilterView`, which better supports the need of Flutter.
106 //
107 // Note: if the implementation of UIVisualEffectView changes in a way that affects the
108 // implementation in `PlatformViewFilter`, this method will return nil.
109 - (instancetype)initWithFrame:(CGRect)frame
110  blurRadius:(CGFloat)blurRadius
111  visualEffectView:(UIVisualEffectView*)visualEffectView NS_DESIGNATED_INITIALIZER;
112 
113 @end
114 
115 // The parent view handles clipping to its subViews.
116 @interface ChildClippingView : UIView
117 
118 // Applies blur backdrop filters to the ChildClippingView with blur values from
119 // filters.
120 - (void)applyBlurBackdropFilters:(NSArray<PlatformViewFilter*>*)filters;
121 
122 @end
123 
124 namespace flutter {
125 // Converts a SkMatrix to CATransform3D.
126 // Certain fields are ignored in CATransform3D since SkMatrix is 3x3 and CATransform3D is 4x4.
127 CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix);
128 
129 // Reset the anchor of `layer` to match the transform operation from flow.
130 // The position of the `layer` should be unchanged after resetting the anchor.
131 void ResetAnchor(CALayer* layer);
132 
133 CGRect GetCGRectFromSkRect(const SkRect& clipSkRect);
134 BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2);
135 
136 class IOSContextGL;
137 class IOSSurface;
138 
140  FlutterPlatformViewLayer(const fml::scoped_nsobject<UIView>& overlay_view,
141  const fml::scoped_nsobject<UIView>& overlay_view_wrapper,
142  std::unique_ptr<IOSSurface> ios_surface,
143  std::unique_ptr<Surface> surface);
144 
146 
147  fml::scoped_nsobject<UIView> overlay_view;
148  fml::scoped_nsobject<UIView> overlay_view_wrapper;
149  std::unique_ptr<IOSSurface> ios_surface;
150  std::unique_ptr<Surface> surface;
151 
152  // Whether a frame for this layer was submitted.
154 
155  // The GrContext that is currently used by the overlay surfaces.
156  // We track this to know when the GrContext for the Flutter app has changed
157  // so we can update the overlay with the new context.
158  GrDirectContext* gr_context;
159 };
160 
161 // This class isn't thread safe.
163  public:
164  FlutterPlatformViewLayerPool() = default;
165 
166  ~FlutterPlatformViewLayerPool() = default;
167 
168  // Gets a layer from the pool if available, or allocates a new one.
169  // Finally, it marks the layer as used. That is, it increments `available_layer_index_`.
170  std::shared_ptr<FlutterPlatformViewLayer> GetLayer(
171  GrDirectContext* gr_context,
172  const std::shared_ptr<IOSContext>& ios_context);
173 
174  // Gets the layers in the pool that aren't currently used.
175  // This method doesn't mark the layers as unused.
176  std::vector<std::shared_ptr<FlutterPlatformViewLayer>> GetUnusedLayers();
177 
178  // Marks the layers in the pool as available for reuse.
179  void RecycleLayers();
180 
181  private:
182  // The index of the entry in the layers_ vector that determines the beginning of the unused
183  // layers. For example, consider the following vector:
184  // _____
185  // | 0 |
186  /// |---|
187  /// | 1 | <-- available_layer_index_
188  /// |---|
189  /// | 2 |
190  /// |---|
191  ///
192  /// This indicates that entries starting from 1 can be reused meanwhile the entry at position 0
193  /// cannot be reused.
194  size_t available_layer_index_ = 0;
195  std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers_;
196 
197  FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewLayerPool);
198 };
199 
201  public:
203 
205 
206  fml::WeakPtr<flutter::FlutterPlatformViewsController> GetWeakPtr();
207 
208  void SetFlutterView(UIView* flutter_view);
209 
210  void SetFlutterViewController(UIViewController* flutter_view_controller);
211 
212  UIViewController* getFlutterViewController();
213 
214  void RegisterViewFactory(
215  NSObject<FlutterPlatformViewFactory>* factory,
216  NSString* factoryId,
217  FlutterPlatformViewGestureRecognizersBlockingPolicy gestureRecognizerBlockingPolicy);
218 
219  // Called at the beginning of each frame.
220  void BeginFrame(SkISize frame_size);
221 
222  // Indicates that we don't compisite any platform views or overlays during this frame.
223  // Also reverts the composition_order_ to its original state at the beginning of the frame.
224  void CancelFrame();
225 
226  void PrerollCompositeEmbeddedView(int64_t view_id,
227  std::unique_ptr<flutter::EmbeddedViewParams> params);
228 
229  size_t EmbeddedViewCount();
230 
231  // Returns the `FlutterPlatformView`'s `view` object associated with the view_id.
232  //
233  // If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or
234  // a `FlutterPlatformView` object associated with the view_id cannot be found, the method
235  // returns nil.
236  UIView* GetPlatformViewByID(int64_t view_id);
237 
238  // Returns the `FlutterTouchInterceptingView` with the view_id.
239  //
240  // If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or
241  // a `FlutterPlatformView` object associated with the view_id cannot be found, the method
242  // returns nil.
243  FlutterTouchInterceptingView* GetFlutterTouchInterceptingViewByID(int64_t view_id);
244 
245  PostPrerollResult PostPrerollAction(
246  const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger);
247 
248  void EndFrame(bool should_resubmit_frame,
249  const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger);
250 
251  DlCanvas* CompositeEmbeddedView(int64_t view_id);
252 
253  // The rect of the platform view at index view_id. This rect has been translated into the
254  // host view coordinate system. Units are device screen pixels.
255  SkRect GetPlatformViewRect(int64_t view_id);
256 
257  // Discards all platform views instances and auxiliary resources.
258  void Reset();
259 
260  bool SubmitFrame(GrDirectContext* gr_context,
261  const std::shared_ptr<IOSContext>& ios_context,
262  std::unique_ptr<SurfaceFrame> frame);
263 
264  void OnMethodCall(FlutterMethodCall* call, FlutterResult& result);
265 
266  // Returns the platform view id if the platform view (or any of its descendant view) is the first
267  // responder. Returns -1 if no such platform view is found.
268  long FindFirstResponderPlatformViewId();
269 
270  // Pushes backdrop filter mutation to the mutator stack of each visited platform view.
271  void PushFilterToVisitedPlatformViews(const std::shared_ptr<const DlImageFilter>& filter,
272  const SkRect& filter_rect);
273 
274  // Pushes the view id of a visted platform view to the list of visied platform views.
275  void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); }
276 
277  private:
278  static const size_t kMaxLayerAllocations = 2;
279 
280  using LayersMap = std::map<int64_t, std::vector<std::shared_ptr<FlutterPlatformViewLayer>>>;
281 
282  void OnCreate(FlutterMethodCall* call, FlutterResult& result);
283  void OnDispose(FlutterMethodCall* call, FlutterResult& result);
284  void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result);
285  void OnRejectGesture(FlutterMethodCall* call, FlutterResult& result);
286  // Dispose the views in `views_to_dispose_`.
287  void DisposeViews();
288 
289  // Returns true if there are embedded views in the scene at current frame
290  // Or there will be embedded views in the next frame.
291  // TODO(cyanglaz): https://github.com/flutter/flutter/issues/56474
292  // Make this method check if there are pending view operations instead.
293  // Also rename it to `HasPendingViewOperations`.
294  bool HasPlatformViewThisOrNextFrame();
295 
296  // Traverse the `mutators_stack` and return the number of clip operations.
297  int CountClips(const MutatorsStack& mutators_stack);
298 
299  void ClipViewSetMaskView(UIView* clipView);
300 
301  // Applies the mutators in the mutators_stack to the UIView chain that was constructed by
302  // `ReconstructClipViewsChain`
303  //
304  // Clips are applied to the `embedded_view`'s super view(|ChildClippingView|) using a
305  // |FlutterClippingMaskView|. Transforms are applied to `embedded_view`
306  //
307  // The `bounding_rect` is the final bounding rect of the PlatformView
308  // (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding
309  // rect of the PlatformView, the clip mutator is not applied for performance optimization.
310  void ApplyMutators(const MutatorsStack& mutators_stack,
311  UIView* embedded_view,
312  const SkRect& bounding_rect);
313 
314  void CompositeWithParams(int64_t view_id, const EmbeddedViewParams& params);
315 
316  // Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from
317  // the picture on the layer's canvas.
318  std::shared_ptr<FlutterPlatformViewLayer> GetLayer(GrDirectContext* gr_context,
319  const std::shared_ptr<IOSContext>& ios_context,
320  EmbedderViewSlice* slice,
321  SkRect rect,
322  int64_t view_id,
323  int64_t overlay_id);
324  // Removes overlay views and platform views that aren't needed in the current frame.
325  // Must run on the platform thread.
326  void RemoveUnusedLayers();
327  // Appends the overlay views and platform view and sets their z index based on the composition
328  // order.
329  void BringLayersIntoView(LayersMap layer_map);
330 
331  // Begin a CATransaction.
332  // This transaction needs to be balanced with |CommitCATransactionIfNeeded|.
333  void BeginCATransaction();
334 
335  // Commit a CATransaction if |BeginCATransaction| has been called during the frame.
336  void CommitCATransactionIfNeeded();
337 
338  // Resets the state of the frame.
339  void ResetFrameState();
340 
341  // The pool of reusable view layers. The pool allows to recycle layer in each frame.
342  std::unique_ptr<FlutterPlatformViewLayerPool> layer_pool_;
343 
344  // The platform view's |EmbedderViewSlice| keyed off the view id, which contains any subsequent
345  // operation until the next platform view or the end of the last leaf node in the layer tree.
346  //
347  // The Slices are deleted by the FlutterPlatformViewsController.reset().
348  std::map<int64_t, std::unique_ptr<EmbedderViewSlice>> slices_;
349 
350  fml::scoped_nsobject<FlutterMethodChannel> channel_;
351  fml::scoped_nsobject<UIView> flutter_view_;
352  fml::scoped_nsobject<UIViewController> flutter_view_controller_;
353  fml::scoped_nsobject<FlutterClippingMaskViewPool> mask_view_pool_;
354  std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> factories_;
355  std::map<int64_t, fml::scoped_nsobject<NSObject<FlutterPlatformView>>> views_;
356  std::map<int64_t, fml::scoped_nsobject<FlutterTouchInterceptingView>> touch_interceptors_;
357  // Mapping a platform view ID to the top most parent view (root_view) of a platform view. In
358  // |SubmitFrame|, root_views_ are added to flutter_view_ as child views.
359  //
360  // The platform view with the view ID is a child of the root view; If the platform view is not
361  // clipped, and no clipping view is added, the root view will be the intercepting view.
362  std::map<int64_t, fml::scoped_nsobject<UIView>> root_views_;
363  // Mapping a platform view ID to its latest composition params.
364  std::map<int64_t, EmbeddedViewParams> current_composition_params_;
365  // Mapping a platform view ID to the count of the clipping operations that were applied to the
366  // platform view last time it was composited.
367  std::map<int64_t, int64_t> clip_count_;
368  SkISize frame_size_;
369 
370  // The number of frames the rasterizer task runner will continue
371  // to run on the platform thread after no platform view is rendered.
372  //
373  // Note: this is an arbitrary number that attempts to account for cases
374  // where the platform view might be momentarily off the screen.
375  static const int kDefaultMergedLeaseDuration = 10;
376 
377  // Method channel `OnDispose` calls adds the views to be disposed to this set to be disposed on
378  // the next frame.
379  std::unordered_set<int64_t> views_to_dispose_;
380 
381  // A vector of embedded view IDs according to their composition order.
382  // The last ID in this vector belond to the that is composited on top of all others.
383  std::vector<int64_t> composition_order_;
384 
385  // A vector of visited platform view IDs.
386  std::vector<int64_t> visited_platform_views_;
387 
388  // The latest composition order that was presented in Present().
389  std::vector<int64_t> active_composition_order_;
390 
391  // Only compoiste platform views in this set.
392  std::unordered_set<int64_t> views_to_recomposite_;
393 
394  // The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view.
395  std::map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
396  gesture_recognizers_blocking_policies;
397 
398  bool catransaction_added_ = false;
399 
400  // WeakPtrFactory must be the last member.
401  std::unique_ptr<fml::WeakPtrFactory<FlutterPlatformViewsController>> weak_factory_;
402 
403 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
404  // A set to keep track of embedded views that does not have (0, 0) origin.
405  // An insertion triggers a warning message about non-zero origin logged on the debug console.
406  // See https://github.com/flutter/flutter/issues/109700 for details.
407  std::unordered_set<int64_t> non_zero_origin_views_;
408 #endif
409 
410  FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController);
411 };
412 
413 } // namespace flutter
414 
415 // A UIView that is used as the parent for embedded UIViews.
416 //
417 // This view has 2 roles:
418 // 1. Delay or prevent touch events from arriving the embedded view.
419 // 2. Dispatching all events that are hittested to the embedded view to the FlutterView.
420 @interface FlutterTouchInterceptingView : UIView
421 - (instancetype)initWithEmbeddedView:(UIView*)embeddedView
422  platformViewsController:
423  (fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController
424  gestureRecognizersBlockingPolicy:
426 
427 // Stop delaying any active touch sequence (and let it arrive the embedded view).
428 - (void)releaseGesture;
429 
430 // Prevent the touch sequence from ever arriving to the embedded view.
431 - (void)blockGesture;
432 
433 // Get embedded view
434 - (UIView*)embeddedView;
435 
436 // Sets flutterAccessibilityContainer as this view's accessibilityContainer.
437 - (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer;
438 @end
439 
440 @interface UIView (FirstResponder)
441 // Returns YES if a view or any of its descendant view is the first responder. Returns NO otherwise.
442 @property(nonatomic, readonly) BOOL flt_hasFirstResponderInViewHierarchySubtree;
443 @end
444 
445 #endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
UIView(FirstResponder)::flt_hasFirstResponderInViewHierarchySubtree
BOOL flt_hasFirstResponderInViewHierarchySubtree
Definition: FlutterPlatformViews_Internal.h:442
FlutterPlatformViews.h
flutter::FlutterPlatformViewLayer::ios_surface
std::unique_ptr< IOSSurface > ios_surface
Definition: FlutterPlatformViews_Internal.h:149
-[FlutterTouchInterceptingView blockGesture]
void blockGesture()
Definition: FlutterPlatformViews.mm:1008
-[FlutterTouchInterceptingView releaseGesture]
void releaseGesture()
Definition: FlutterPlatformViews.mm:1004
PlatformViewFilter::frame
CGRect frame
Definition: FlutterPlatformViews_Internal.h:81
flutter::FlutterPlatformViewLayer::did_submit_last_frame
bool did_submit_last_frame
Definition: FlutterPlatformViews_Internal.h:153
flutter::BlurRadiusEqualToBlurRadius
BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2)
Definition: FlutterPlatformViews_Internal.mm:67
FlutterChannels.h
-[FlutterTouchInterceptingView embeddedView]
UIView * embeddedView()
Definition: FlutterPlatformViews.mm:1000
flutter::FlutterPlatformViewLayer::overlay_view_wrapper
fml::scoped_nsobject< UIView > overlay_view_wrapper
Definition: FlutterPlatformViews_Internal.h:148
initWithFrame
instancetype initWithFrame
Definition: FlutterTextInputPlugin.h:164
flutter::FlutterPlatformViewLayer::gr_context
GrDirectContext * gr_context
Definition: FlutterPlatformViews_Internal.h:158
flutter::ResetAnchor
void ResetAnchor(CALayer *layer)
Definition: FlutterPlatformViews_Internal.mm:56
FlutterPlugin.h
PlatformViewFilter::blurRadius
CGFloat blurRadius
Definition: FlutterPlatformViews_Internal.h:86
flutter::FlutterPlatformViewLayerPool
Definition: FlutterPlatformViews_Internal.h:162
flutter::FlutterPlatformViewLayer::overlay_view
fml::scoped_nsobject< UIView > overlay_view
Definition: FlutterPlatformViews_Internal.h:147
-[PlatformViewFilter NS_UNAVAILABLE]
instancetype NS_UNAVAILABLE()
FlutterMethodCall
Definition: FlutterCodecs.h:220
-[FlutterClippingMaskView reset]
void reset()
Definition: FlutterPlatformViews_Internal.mm:278
PlatformViewFilter::backdropFilterView
UIVisualEffectView * backdropFilterView
Definition: FlutterPlatformViews_Internal.h:92
flutter
Definition: accessibility_bridge.h:28
FlutterBinaryMessenger.h
flutter::FlutterPlatformViewLayer
Definition: FlutterPlatformViews_Internal.h:139
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:196
flutter::FlutterPlatformViewLayer::surface
std::unique_ptr< Surface > surface
Definition: FlutterPlatformViews_Internal.h:150
FlutterPlatformViewGestureRecognizersBlockingPolicy
FlutterPlatformViewGestureRecognizersBlockingPolicy
Definition: FlutterPlugin.h:252
FlutterClippingMaskViewPool
Definition: FlutterPlatformViews_Internal.h:59
UIView(FirstResponder)
Definition: FlutterPlatformViews.mm:20
ChildClippingView
Definition: FlutterPlatformViews_Internal.h:116
-[flutter::FlutterPlatformViewsController PushVisitedPlatformView]
void PushVisitedPlatformView(int64_t view_id)
Definition: FlutterPlatformViews_Internal.h:275
SemanticsObject.h
+[PlatformViewFilter resetPreparation]
void resetPreparation()
Definition: FlutterPlatformViews_Internal.mm:114
FlutterTouchInterceptingView
Definition: FlutterPlatformViews.mm:961
flutter::GetCATransform3DFromSkMatrix
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix &matrix)
Definition: FlutterPlatformViews_Internal.mm:41
flutter::GetCGRectFromSkRect
CGRect GetCGRectFromSkRect(const SkRect &clipSkRect)
Definition: FlutterPlatformViews_Internal.mm:62
PlatformViewFilter
Definition: FlutterPlatformViews_Internal.h:77
ios_context.h
flutter::FlutterPlatformViewsController
Definition: FlutterPlatformViews_Internal.h:200
FlutterClippingMaskView
Definition: FlutterPlatformViews_Internal.h:28