Flutter Engine
The Flutter Engine
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(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(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, 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) __attribute__((cf_audited_transfer));
214
215 void SetFlutterViewController(UIViewController<FlutterViewResponder>* flutter_view_controller)
216 __attribute__((cf_audited_transfer));
217
218 UIViewController<FlutterViewResponder>* getFlutterViewController()
219 __attribute__((cf_audited_transfer));
220
221 void RegisterViewFactory(
222 NSObject<FlutterPlatformViewFactory>* factory,
223 NSString* factoryId,
224 FlutterPlatformViewGestureRecognizersBlockingPolicy gestureRecognizerBlockingPolicy)
225 __attribute__((cf_audited_transfer));
226
227 // Called at the beginning of each frame.
228 void BeginFrame(SkISize frame_size);
229
230 // Indicates that we don't compisite any platform views or overlays during this frame.
231 // Also reverts the composition_order_ to its original state at the beginning of the frame.
232 void CancelFrame();
233
234 void PrerollCompositeEmbeddedView(int64_t view_id,
235 std::unique_ptr<flutter::EmbeddedViewParams> params);
236
237 size_t EmbeddedViewCount();
238
239 // Returns the `FlutterPlatformView`'s `view` object associated with the view_id.
240 //
241 // If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or
242 // a `FlutterPlatformView` object associated with the view_id cannot be found, the method
243 // returns nil.
244 UIView* GetPlatformViewByID(int64_t view_id);
245
246 // Returns the `FlutterTouchInterceptingView` with the view_id.
247 //
248 // If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or
249 // a `FlutterPlatformView` object associated with the view_id cannot be found, the method
250 // returns nil.
251 FlutterTouchInterceptingView* GetFlutterTouchInterceptingViewByID(int64_t view_id);
252
253 PostPrerollResult PostPrerollAction(
254 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger);
255
256 void EndFrame(bool should_resubmit_frame,
257 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger);
258
259 DlCanvas* CompositeEmbeddedView(int64_t view_id);
260
261 // The rect of the platform view at index view_id. This rect has been translated into the
262 // host view coordinate system. Units are device screen pixels.
263 SkRect GetPlatformViewRect(int64_t view_id);
264
265 // Discards all platform views instances and auxiliary resources.
266 void Reset();
267
268 bool SubmitFrame(GrDirectContext* gr_context,
269 const std::shared_ptr<IOSContext>& ios_context,
270 std::unique_ptr<SurfaceFrame> frame);
271
272 void OnMethodCall(FlutterMethodCall* call, FlutterResult result)
273 __attribute__((cf_audited_transfer));
274
275 // Returns the platform view id if the platform view (or any of its descendant view) is the first
276 // responder. Returns -1 if no such platform view is found.
277 long FindFirstResponderPlatformViewId();
278
279 // Pushes backdrop filter mutation to the mutator stack of each visited platform view.
280 void PushFilterToVisitedPlatformViews(const std::shared_ptr<const DlImageFilter>& filter,
281 const SkRect& filter_rect);
282
283 // Pushes the view id of a visted platform view to the list of visied platform views.
284 void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); }
285
286 private:
287 static const size_t kMaxLayerAllocations = 2;
288
289 using LayersMap = std::map<int64_t, std::vector<std::shared_ptr<FlutterPlatformViewLayer>>>;
290
291 void OnCreate(FlutterMethodCall* call, FlutterResult result) __attribute__((cf_audited_transfer));
293 __attribute__((cf_audited_transfer));
294 void OnAcceptGesture(FlutterMethodCall* call, FlutterResult result)
295 __attribute__((cf_audited_transfer));
296 void OnRejectGesture(FlutterMethodCall* call, FlutterResult result)
297 __attribute__((cf_audited_transfer));
298 // Dispose the views in `views_to_dispose_`.
299 void DisposeViews();
300
301 // Returns true if there are embedded views in the scene at current frame
302 // Or there will be embedded views in the next frame.
303 // TODO(cyanglaz): https://github.com/flutter/flutter/issues/56474
304 // Make this method check if there are pending view operations instead.
305 // Also rename it to `HasPendingViewOperations`.
306 bool HasPlatformViewThisOrNextFrame();
307
308 // Traverse the `mutators_stack` and return the number of clip operations.
309 int CountClips(const MutatorsStack& mutators_stack);
310
311 void ClipViewSetMaskView(UIView* clipView) __attribute__((cf_audited_transfer));
312
313 // Applies the mutators in the mutators_stack to the UIView chain that was constructed by
314 // `ReconstructClipViewsChain`
315 //
316 // Clips are applied to the `embedded_view`'s super view(|ChildClippingView|) using a
317 // |FlutterClippingMaskView|. Transforms are applied to `embedded_view`
318 //
319 // The `bounding_rect` is the final bounding rect of the PlatformView
320 // (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding
321 // rect of the PlatformView, the clip mutator is not applied for performance optimization.
322 void ApplyMutators(const MutatorsStack& mutators_stack,
323 UIView* embedded_view,
324 const SkRect& bounding_rect) __attribute__((cf_audited_transfer));
325
326 void CompositeWithParams(int64_t view_id, const EmbeddedViewParams& params);
327
328 // Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from
329 // the picture on the layer's canvas.
330 std::shared_ptr<FlutterPlatformViewLayer> GetLayer(GrDirectContext* gr_context,
331 const std::shared_ptr<IOSContext>& ios_context,
332 EmbedderViewSlice* slice,
334 int64_t view_id,
335 int64_t overlay_id,
336 MTLPixelFormat pixel_format);
337 // Removes overlay views and platform views that aren't needed in the current frame.
338 // Must run on the platform thread.
339 void RemoveUnusedLayers();
340 // Appends the overlay views and platform view and sets their z index based on the composition
341 // order.
342 void BringLayersIntoView(LayersMap layer_map);
343
344 // Begin a CATransaction.
345 // This transaction needs to be balanced with |CommitCATransactionIfNeeded|.
346 void BeginCATransaction();
347
348 // Commit a CATransaction if |BeginCATransaction| has been called during the frame.
349 void CommitCATransactionIfNeeded();
350
351 // Resets the state of the frame.
352 void ResetFrameState();
353
354 // The pool of reusable view layers. The pool allows to recycle layer in each frame.
355 std::unique_ptr<FlutterPlatformViewLayerPool> layer_pool_;
356
357 // The platform view's |EmbedderViewSlice| keyed off the view id, which contains any subsequent
358 // operation until the next platform view or the end of the last leaf node in the layer tree.
359 //
360 // The Slices are deleted by the FlutterPlatformViewsController.reset().
361 std::map<int64_t, std::unique_ptr<EmbedderViewSlice>> slices_;
362
364 fml::scoped_nsobject<UIView> flutter_view_;
367 std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> factories_;
368 std::map<int64_t, fml::scoped_nsobject<NSObject<FlutterPlatformView>>> views_;
369 std::map<int64_t, fml::scoped_nsobject<FlutterTouchInterceptingView>> touch_interceptors_;
370 // Mapping a platform view ID to the top most parent view (root_view) of a platform view. In
371 // |SubmitFrame|, root_views_ are added to flutter_view_ as child views.
372 //
373 // The platform view with the view ID is a child of the root view; If the platform view is not
374 // clipped, and no clipping view is added, the root view will be the intercepting view.
375 std::map<int64_t, fml::scoped_nsobject<UIView>> root_views_;
376 // Mapping a platform view ID to its latest composition params.
377 std::map<int64_t, EmbeddedViewParams> current_composition_params_;
378 // Mapping a platform view ID to the count of the clipping operations that were applied to the
379 // platform view last time it was composited.
380 std::map<int64_t, int64_t> clip_count_;
381 SkISize frame_size_;
382
383 // The number of frames the rasterizer task runner will continue
384 // to run on the platform thread after no platform view is rendered.
385 //
386 // Note: this is an arbitrary number that attempts to account for cases
387 // where the platform view might be momentarily off the screen.
388 static const int kDefaultMergedLeaseDuration = 10;
389
390 // Method channel `OnDispose` calls adds the views to be disposed to this set to be disposed on
391 // the next frame.
392 std::unordered_set<int64_t> views_to_dispose_;
393
394 // A vector of embedded view IDs according to their composition order.
395 // The last ID in this vector belond to the that is composited on top of all others.
396 std::vector<int64_t> composition_order_;
397
398 // A vector of visited platform view IDs.
399 std::vector<int64_t> visited_platform_views_;
400
401 // The latest composition order that was presented in Present().
402 std::vector<int64_t> active_composition_order_;
403
404 // Only compoiste platform views in this set.
405 std::unordered_set<int64_t> views_to_recomposite_;
406
407 // The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view.
408 std::map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
409 gesture_recognizers_blocking_policies_;
410
411 bool catransaction_added_ = false;
412
413 // WeakPtrFactory must be the last member.
414 std::unique_ptr<fml::WeakPtrFactory<FlutterPlatformViewsController>> weak_factory_;
415
416#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
417 // A set to keep track of embedded views that does not have (0, 0) origin.
418 // An insertion triggers a warning message about non-zero origin logged on the debug console.
419 // See https://github.com/flutter/flutter/issues/109700 for details.
420 std::unordered_set<int64_t> non_zero_origin_views_;
421#endif
422
424};
425
426} // namespace flutter
427
428// A UIView that is used as the parent for embedded UIViews.
429//
430// This view has 2 roles:
431// 1. Delay or prevent touch events from arriving the embedded view.
432// 2. Dispatching all events that are hittested to the embedded view to the FlutterView.
433@interface FlutterTouchInterceptingView : UIView
434- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
435 platformViewsController:
436 (fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController
437 gestureRecognizersBlockingPolicy:
439
440// Stop delaying any active touch sequence (and let it arrive the embedded view).
441- (void)releaseGesture;
442
443// Prevent the touch sequence from ever arriving to the embedded view.
444- (void)blockGesture;
445
446// Get embedded view
447- (UIView*)embeddedView;
448
449// Sets flutterAccessibilityContainer as this view's accessibilityContainer.
450@property(nonatomic, retain) id flutterAccessibilityContainer;
451@end
452
454// Returns YES if a view or any of its descendant view is the first responder. Returns NO otherwise.
455@property(nonatomic, readonly) BOOL flt_hasFirstResponderInViewHierarchySubtree;
456@end
457
458#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
m reset()
void(^ FlutterResult)(id _Nullable result)
FlutterPlatformViewGestureRecognizersBlockingPolicy
Definition: SkPath.h:59
Developer-facing API for rendering anything within the engine.
Definition: dl_canvas.h:38
Manages the lifetime of the on-screen and off-screen rendering contexts on iOS. On-screen contexts ar...
Definition: ios_context.h:39
const EmbeddedViewParams * params
VkSurfaceKHR surface
Definition: main.cc:49
GAsyncResult * result
HWND(* FlutterPlatformViewFactory)(const FlutterPlatformViewCreationParameters *)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:27
NSMutableArray * backdropFilterSubviews()
instancetype NS_UNAVAILABLE()
UIVisualEffectView * backdropFilterView
instancetype initWithFrame
__attribute__((visibility("default"))) int RunBenchmarks(int argc
static bool init()
clipRRect(r.rrect, r.opAA.op(), r.opAA.aa())) DRAW(ClipRect
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
clipPath(r.path, r.opAA.op(), r.opAA.aa())) DRAW(ClipRRect
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
def call(args)
Definition: dom.py:159
auto WeakPtr(std::shared_ptr< T > pointer)
BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2)
void ResetAnchor(CALayer *layer)
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix &matrix)
CGRect GetCGRectFromSkRect(const SkRect &clipSkRect)
void Reset(SkPath *path)
Definition: path_ops.cc:40
Definition: ascii_trie.cc:9
Definition: ref_ptr.h:256
Definition: SkRect.h:32
Definition: SkSize.h:16
fml::scoped_nsobject< UIView > overlay_view
fml::scoped_nsobject< UIView > overlay_view_wrapper
int BOOL
Definition: windows_types.h:37