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