| Flutter iOS Embedder |

FlutterPlatformViewsController.mm
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 #import "shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h"
6
7 #include "flutter/display_list/effects/image_filters/dl_blur_image_filter.h"
8 #include "flutter/flow/surface_frame.h"
9 #include "flutter/flow/view_slicer.h"
10 #include "flutter/fml/make_copyable.h"
11 #include "flutter/fml/synchronization/count_down_latch.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
14 #include "flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.h"
15 #import "flutter/shell/platform/darwin/ios/ios_surface.h"
16
17 // The number of frames the rasterizer task runner will continue
18 // to run on the platform thread after no platform view is rendered.
19 //
20 // Note: this is an arbitrary number.
21 static constexpr int kDefaultMergedLeaseDuration = 10;
22
23 static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5;
24
25 struct LayerData {
26 SkRect rect;
27 int64_t view_id;
28 int64_t overlay_id;
29 std::shared_ptr<flutter::OverlayLayer> layer;
30 };
31 using LayersMap = std::unordered_map<int64_t, LayerData>;
32
33 /// Each of the following structs stores part of the platform view hierarchy according to its
34 /// ID.
35 ///
36 /// This data must only be accessed on the platform thread.
37 struct PlatformViewData {
38 NSObject<FlutterPlatformView>* view;
39 FlutterTouchInterceptingView* touch_interceptor;
40 UIView* root_view;
41 };
42
43 // Converts a SkMatrix to CATransform3D.
44 //
45 // Certain fields are ignored in CATransform3D since SkMatrix is 3x3 and CATransform3D is 4x4.
46 static CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix) {
47 // Skia only supports 2D transform so we don't map z.
48 CATransform3D transform = CATransform3DIdentity;
49 transform.m11 = matrix.getScaleX();
50 transform.m21 = matrix.getSkewX();
51 transform.m41 = matrix.getTranslateX();
52 transform.m14 = matrix.getPerspX();
53
54 transform.m12 = matrix.getSkewY();
55 transform.m22 = matrix.getScaleY();
56 transform.m42 = matrix.getTranslateY();
57 transform.m24 = matrix.getPerspY();
58 return transform;
59 }
60
61 // Reset the anchor of `layer` to match the transform operation from flow.
62 //
63 // The position of the `layer` should be unchanged after resetting the anchor.
64 static void ResetAnchor(CALayer* layer) {
65 // Flow uses (0, 0) to apply transform matrix so we need to match that in Quartz.
66 layer.anchorPoint = CGPointZero;
67 layer.position = CGPointZero;
68 }
69
70 static CGRect GetCGRectFromSkRect(const SkRect& clipSkRect) {
71 return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft,
72 clipSkRect.fBottom - clipSkRect.fTop);
73 }
74
75 // Determines if the `clip_rect` from a clipRect mutator contains the
76 // `platformview_boundingrect`.
77 //
78 // `clip_rect` is in its own coordinate space. The rect needs to be transformed by
79 // `transform_matrix` to be in the coordinate space where the PlatformView is displayed.
80 //
81 // `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate
82 // space where the PlatformView is displayed.
83 static bool ClipRectContainsPlatformViewBoundingRect(const SkRect& clip_rect,
84 const SkRect& platformview_boundingrect,
85 const SkMatrix& transform_matrix) {
86 SkRect transformed_rect = transform_matrix.mapRect(clip_rect);
87 return transformed_rect.contains(platformview_boundingrect);
88 }
89
90 // Determines if the `clipRRect` from a clipRRect mutator contains the
91 // `platformview_boundingrect`.
92 //
93 // `clip_rrect` is in its own coordinate space. The rrect needs to be transformed by
94 // `transform_matrix` to be in the coordinate space where the PlatformView is displayed.
95 //
96 // `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate
97 // space where the PlatformView is displayed.
98 static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
99 const SkRect& platformview_boundingrect,
100 const SkMatrix& transform_matrix) {
101 SkVector upper_left = clip_rrect.radii(SkRRect::Corner::kUpperLeft_Corner);
102 SkVector upper_right = clip_rrect.radii(SkRRect::Corner::kUpperRight_Corner);
103 SkVector lower_right = clip_rrect.radii(SkRRect::Corner::kLowerRight_Corner);
104 SkVector lower_left = clip_rrect.radii(SkRRect::Corner::kLowerLeft_Corner);
105 SkScalar transformed_upper_left_x = transform_matrix.mapRadius(upper_left.x());
106 SkScalar transformed_upper_left_y = transform_matrix.mapRadius(upper_left.y());
107 SkScalar transformed_upper_right_x = transform_matrix.mapRadius(upper_right.x());
108 SkScalar transformed_upper_right_y = transform_matrix.mapRadius(upper_right.y());
109 SkScalar transformed_lower_right_x = transform_matrix.mapRadius(lower_right.x());
110 SkScalar transformed_lower_right_y = transform_matrix.mapRadius(lower_right.y());
111 SkScalar transformed_lower_left_x = transform_matrix.mapRadius(lower_left.x());
112 SkScalar transformed_lower_left_y = transform_matrix.mapRadius(lower_left.y());
113 SkRect transformed_clip_rect = transform_matrix.mapRect(clip_rrect.rect());
114 SkRRect transformed_rrect;
115 SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y},
116 {transformed_upper_right_x, transformed_upper_right_y},
117 {transformed_lower_right_x, transformed_lower_right_y},
118 {transformed_lower_left_x, transformed_lower_left_y}};
119 transformed_rrect.setRectRadii(transformed_clip_rect, corners);
120 return transformed_rrect.contains(platformview_boundingrect);
121 }
122
123 @interface FlutterPlatformViewsController ()
124
125 // The pool of reusable view layers. The pool allows to recycle layer in each frame.
126 @property(nonatomic, readonly) flutter::OverlayLayerPool* layerPool;
127
128 // The platform view's |EmbedderViewSlice| keyed off the view id, which contains any subsequent
129 // operation until the next platform view or the end of the last leaf node in the layer tree.
130 //
131 // The Slices are deleted by the PlatformViewsController.reset().
132 @property(nonatomic, readonly)
133 std::unordered_map<int64_t, std::unique_ptr<flutter::EmbedderViewSlice>>& slices;
134
135 @property(nonatomic, readonly) FlutterClippingMaskViewPool* maskViewPool;
136
137 @property(nonatomic, readonly)
138 std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*>& factories;
139
140 // The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view.
141 @property(nonatomic, readonly)
142 std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>&
143 gestureRecognizersBlockingPolicies;
144
145 /// The size of the current onscreen surface in physical pixels.
146 @property(nonatomic, assign) SkISize frameSize;
147
148 /// The task runner for posting tasks to the platform thread.
149 @property(nonatomic, readonly) const fml::RefPtr<fml::TaskRunner>& platformTaskRunner;
150
151 /// This data must only be accessed on the platform thread.
152 @property(nonatomic, readonly) std::unordered_map<int64_t, PlatformViewData>& platformViews;
153
154 /// The composition parameters for each platform view.
155 ///
156 /// This state is only modified on the raster thread.
157 @property(nonatomic, readonly)
158 std::unordered_map<int64_t, flutter::EmbeddedViewParams>& currentCompositionParams;
159
160 /// Method channel `OnDispose` calls adds the views to be disposed to this set to be disposed on
161 /// the next frame.
162 ///
163 /// This state is modified on both the platform and raster thread.
164 @property(nonatomic, readonly) std::unordered_set<int64_t>& viewsToDispose;
165
166 /// view IDs in composition order.
167 ///
168 /// This state is only modified on the raster thread.
169 @property(nonatomic, readonly) std::vector<int64_t>& compositionOrder;
170
171 /// platform view IDs visited during layer tree composition.
172 ///
173 /// This state is only modified on the raster thread.
174 @property(nonatomic, readonly) std::vector<int64_t>& visitedPlatformViews;
175
176 /// Only composite platform views in this set.
177 ///
178 /// This state is only modified on the raster thread.
179 @property(nonatomic, readonly) std::unordered_set<int64_t>& viewsToRecomposite;
180
181 /// @brief The composition order from the previous thread.
182 ///
183 /// Only accessed from the platform thread.
184 @property(nonatomic, readonly) std::vector<int64_t>& previousCompositionOrder;
185
186 /// Whether the previous frame had any platform views in active composition order.
187 ///
188 /// This state is tracked so that the first frame after removing the last platform view
189 /// runs through the platform view rendering code path, giving us a chance to remove the
190 /// platform view from the UIView hierarchy.
191 ///
192 /// Only accessed from the raster thread.
193 @property(nonatomic, assign) BOOL hadPlatformViews;
194
195 /// Whether blurred backdrop filters can be applied.
196 ///
197 /// Defaults to YES, but becomes NO if blurred backdrop filters cannot be applied.
198 @property(nonatomic, assign) BOOL canApplyBlurBackdrop;
199
200 /// Populate any missing overlay layers.
201 ///
202 /// This requires posting a task to the platform thread and blocking on its completion.
203 - (void)createMissingOverlays:(size_t)requiredOverlayLayers
204 withIosContext:(const std::shared_ptr<flutter::IOSContext>&)iosContext
205 grContext:(GrDirectContext*)grContext;
206
207 /// Update the buffers and mutate the platform views in CATransaction on the platform thread.
208 - (void)performSubmit:(const LayersMap&)platformViewLayers
209 currentCompositionParams:
210 (std::unordered_map<int64_t, flutter::EmbeddedViewParams>&)currentCompositionParams
211 viewsToRecomposite:(const std::unordered_set<int64_t>&)viewsToRecomposite
212 compositionOrder:(const std::vector<int64_t>&)compositionOrder
213 unusedLayers:
214 (const std::vector<std::shared_ptr<flutter::OverlayLayer>>&)unusedLayers
215 surfaceFrames:
216 (const std::vector<std::unique_ptr<flutter::SurfaceFrame>>&)surfaceFrames;
217
218 - (void)onCreate:(FlutterMethodCall*)call result:(FlutterResult)result;
219 - (void)onDispose:(FlutterMethodCall*)call result:(FlutterResult)result;
220 - (void)onAcceptGesture:(FlutterMethodCall*)call result:(FlutterResult)result;
221 - (void)onRejectGesture:(FlutterMethodCall*)call result:(FlutterResult)result;
222
223 - (void)clipViewSetMaskView:(UIView*)clipView;
224
225 // Applies the mutators in the mutatorsStack to the UIView chain that was constructed by
226 // `ReconstructClipViewsChain`
227 //
228 // Clips are applied to the `embeddedView`'s super view(|ChildClippingView|) using a
229 // |FlutterClippingMaskView|. Transforms are applied to `embeddedView`
230 //
231 // The `boundingRect` is the final bounding rect of the PlatformView
232 // (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding
233 // rect of the PlatformView, the clip mutator is not applied for performance optimization.
234 //
235 // This method is only called when the `embeddedView` needs to be re-composited at the current
236 // frame. See: `compositeView:withParams:` for details.
237 - (void)applyMutators:(const flutter::MutatorsStack&)mutatorsStack
238 embeddedView:(UIView*)embeddedView
239 boundingRect:(const SkRect&)boundingRect;
240
241 // Appends the overlay views and platform view and sets their z index based on the composition
242 // order.
243 - (void)bringLayersIntoView:(const LayersMap&)layerMap
244 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder;
245
246 - (std::shared_ptr<flutter::OverlayLayer>)nextLayerInPool;
247
248 /// Runs on the platform thread.
249 - (void)createLayerWithIosContext:(const std::shared_ptr<flutter::IOSContext>&)iosContext
250 grContext:(GrDirectContext*)grContext
251 pixelFormat:(MTLPixelFormat)pixelFormat;
252
253 /// Removes overlay views and platform views that aren't needed in the current frame.
254 /// Must run on the platform thread.
255 - (void)removeUnusedLayers:(const std::vector<std::shared_ptr<flutter::OverlayLayer>>&)unusedLayers
256 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder;
257
258 /// Computes and returns all views to be disposed on the platform thread, removes them from
259 /// self.platformViews, self.viewsToRecomposite, and self.currentCompositionParams. Any views that
260 /// still require compositing are not returned, but instead added to `viewsToDelayDispose` for
261 /// disposal on the next call.
262 - (std::vector<UIView*>)computeViewsToDispose;
263
264 /// Resets the state of the frame.
265 - (void)resetFrameState;
266 @end
267
268 @implementation FlutterPlatformViewsController {
269 // TODO(cbracken): Replace with Obj-C types and use @property declarations to automatically
270 // synthesize the ivars.
271 //
272 // These ivars are required because we're transitioning the previous C++ implementation to Obj-C.
273 // We require ivars to declare the concrete types and then wrap with @property declarations that
274 // return a reference to the ivar, allowing for use like `self.layerPool` and
275 // `self.slices[viewId] = x`.
276 std::unique_ptr<flutter::OverlayLayerPool> _layerPool;
277 std::unordered_map<int64_t, std::unique_ptr<flutter::EmbedderViewSlice>> _slices;
278 std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*> _factories;
279 std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
280 _gestureRecognizersBlockingPolicies;
281 fml::RefPtr<fml::TaskRunner> _platformTaskRunner;
282 std::unordered_map<int64_t, PlatformViewData> _platformViews;
283 std::unordered_map<int64_t, flutter::EmbeddedViewParams> _currentCompositionParams;
284 std::unordered_set<int64_t> _viewsToDispose;
285 std::vector<int64_t> _compositionOrder;
286 std::vector<int64_t> _visitedPlatformViews;
287 std::unordered_set<int64_t> _viewsToRecomposite;
288 std::vector<int64_t> _previousCompositionOrder;
289 }
290
291 - (id)init {
292 if (self = [super init]) {
293 _layerPool = std::make_unique<flutter::OverlayLayerPool>();
294 _maskViewPool =
295 [[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity];
296 _hadPlatformViews = NO;
297 _canApplyBlurBackdrop = YES;
298 }
299 return self;
300 }
301
302 - (const fml::RefPtr<fml::TaskRunner>&)taskRunner {
303 return _platformTaskRunner;
304 }
305
306 - (void)setTaskRunner:(const fml::RefPtr<fml::TaskRunner>&)platformTaskRunner {
307 _platformTaskRunner = platformTaskRunner;
308 }
309
310 - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
311 if ([[call method] isEqualToString:@"create"]) {
312 [self onCreate:call result:result];
313 } else if ([[call method] isEqualToString:@"dispose"]) {
314 [self onDispose:call result:result];
315 } else if ([[call method] isEqualToString:@"acceptGesture"]) {
316 [self onAcceptGesture:call result:result];
317 } else if ([[call method] isEqualToString:@"rejectGesture"]) {
318 [self onRejectGesture:call result:result];
319 } else {
320 result(FlutterMethodNotImplemented);
321 }
322 }
323
324 - (void)onCreate:(FlutterMethodCall*)call result:(FlutterResult)result {
325 NSDictionary<NSString*, id>* args = [call arguments];
326
327 int64_t viewId = [args[@"id"] longLongValue];
328 NSString* viewTypeString = args[@"viewType"];
329 std::string viewType(viewTypeString.UTF8String);
330
331 if (self.platformViews.count(viewId) != 0) {
332 result([FlutterError errorWithCode:@"recreating_view"
333 message:@"trying to create an already created view"
334 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
335 return;
336 }
337
338 NSObject<FlutterPlatformViewFactory>* factory = self.factories[viewType];
339 if (factory == nil) {
340 result([FlutterError
341 errorWithCode:@"unregistered_view_type"
342 message:[NSString stringWithFormat:@"A UIKitView widget is trying to create a "
343 @"PlatformView with an unregistered type: < %@ >",
344 viewTypeString]
345 details:@"If you are the author of the PlatformView, make sure `registerViewFactory` "
346 @"is invoked.\n"
347 @"See: "
348 @"https://docs.flutter.dev/development/platform-integration/"
349 @"platform-views#on-the-platform-side-1 for more details.\n"
350 @"If you are not the author of the PlatformView, make sure to call "
351 @"`GeneratedPluginRegistrant.register`."]);
352 return;
353 }
354
355 id params = nil;
356 if ([factory respondsToSelector:@selector(createArgsCodec)]) {
357 NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
358 if (codec != nil && args[@"params"] != nil) {
359 FlutterStandardTypedData* paramsData = args[@"params"];
360 params = [codec decode:paramsData.data];
361 }
362 }
363
364 NSObject<FlutterPlatformView>* embeddedView = [factory createWithFrame:CGRectZero
365 viewIdentifier:viewId
366 arguments:params];
367 UIView* platformView = [embeddedView view];
368 // Set a unique view identifier, so the platform view can be identified in unit tests.
369 platformView.accessibilityIdentifier = [NSString stringWithFormat:@"platform_view[%lld]", viewId];
370
371 FlutterTouchInterceptingView* touchInterceptor = [[FlutterTouchInterceptingView alloc]
372 initWithEmbeddedView:platformView
373 platformViewsController:self
374 gestureRecognizersBlockingPolicy:self.gestureRecognizersBlockingPolicies[viewType]];
375
376 ChildClippingView* clippingView = [[ChildClippingView alloc] initWithFrame:CGRectZero];
377 [clippingView addSubview:touchInterceptor];
378
379 self.platformViews.emplace(viewId, PlatformViewData{
380 .view = embeddedView, //
381 .touch_interceptor = touchInterceptor, //
382 .root_view = clippingView //
383 });
384
385 result(nil);
386 }
387
388 - (void)onDispose:(FlutterMethodCall*)call result:(FlutterResult)result {
389 NSNumber* arg = [call arguments];
390 int64_t viewId = [arg longLongValue];
391
392 if (self.platformViews.count(viewId) == 0) {
393 result([FlutterError errorWithCode:@"unknown_view"
394 message:@"trying to dispose an unknown"
395 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
396 return;
397 }
398 // We wait for next submitFrame to dispose views.
399 self.viewsToDispose.insert(viewId);
400 result(nil);
401 }
402
403 - (void)onAcceptGesture:(FlutterMethodCall*)call result:(FlutterResult)result {
404 NSDictionary<NSString*, id>* args = [call arguments];
405 int64_t viewId = [args[@"id"] longLongValue];
406
407 if (self.platformViews.count(viewId) == 0) {
408 result([FlutterError errorWithCode:@"unknown_view"
409 message:@"trying to set gesture state for an unknown view"
410 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
411 return;
412 }
413
414 FlutterTouchInterceptingView* view = self.platformViews[viewId].touch_interceptor;
415 [view releaseGesture];
416
417 result(nil);
418 }
419
420 - (void)onRejectGesture:(FlutterMethodCall*)call result:(FlutterResult)result {
421 NSDictionary<NSString*, id>* args = [call arguments];
422 int64_t viewId = [args[@"id"] longLongValue];
423
424 if (self.platformViews.count(viewId) == 0) {
425 result([FlutterError errorWithCode:@"unknown_view"
426 message:@"trying to set gesture state for an unknown view"
427 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
428 return;
429 }
430
431 FlutterTouchInterceptingView* view = self.platformViews[viewId].touch_interceptor;
432 [view blockGesture];
433
434 result(nil);
435 }
436
437 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
438 withId:(NSString*)factoryId
439 gestureRecognizersBlockingPolicy:
440 (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizerBlockingPolicy {
441 std::string idString([factoryId UTF8String]);
442 FML_CHECK(self.factories.count(idString) == 0);
443 self.factories[idString] = factory;
444 self.gestureRecognizersBlockingPolicies[idString] = gestureRecognizerBlockingPolicy;
445 }
446
447 - (void)beginFrameWithSize:(SkISize)frameSize {
448 [self resetFrameState];
449 self.frameSize = frameSize;
450 }
451
452 - (void)cancelFrame {
453 [self resetFrameState];
454 }
455
456 - (flutter::PostPrerollResult)postPrerollActionWithThreadMerger:
457 (const fml::RefPtr<fml::RasterThreadMerger>&)rasterThreadMerger
458 impellerEnabled:(BOOL)impellerEnabled {
459 // TODO(jonahwilliams): remove this once Software backend is removed for iOS Sim.
460 #ifdef FML_OS_IOS_SIMULATOR
461 const bool mergeThreads = true;
462 #else
463 const bool mergeThreads = !impellerEnabled;
464 #endif // FML_OS_IOS_SIMULATOR
465
466 if (mergeThreads) {
467 if (self.compositionOrder.empty()) {
468 return flutter::PostPrerollResult::kSuccess;
469 }
470 if (!rasterThreadMerger->IsMerged()) {
471 // The raster thread merger may be disabled if the rasterizer is being
472 // created or teared down.
473 //
474 // In such cases, the current frame is dropped, and a new frame is attempted
475 // with the same layer tree.
476 //
477 // Eventually, the frame is submitted once this method returns `kSuccess`.
478 // At that point, the raster tasks are handled on the platform thread.
479 [self cancelFrame];
480 return flutter::PostPrerollResult::kSkipAndRetryFrame;
481 }
482 // If the post preroll action is successful, we will display platform views in the current
483 // frame. In order to sync the rendering of the platform views (quartz) with skia's rendering,
484 // We need to begin an explicit CATransaction. This transaction needs to be submitted
485 // after the current frame is submitted.
486 rasterThreadMerger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
487 }
488 return flutter::PostPrerollResult::kSuccess;
489 }
490
491 - (void)endFrameWithResubmit:(BOOL)shouldResubmitFrame
492 threadMerger:(const fml::RefPtr<fml::RasterThreadMerger>&)rasterThreadMerger
493 impellerEnabled:(BOOL)impellerEnabled {
494 #if FML_OS_IOS_SIMULATOR
495 BOOL runCheck = YES;
496 #else
497 BOOL runCheck = !impellerEnabled;
498 #endif // FML_OS_IOS_SIMULATOR
499 if (runCheck && shouldResubmitFrame) {
500 rasterThreadMerger->MergeWithLease(kDefaultMergedLeaseDuration);
501 }
502 }
503
504 - (void)pushFilterToVisitedPlatformViews:(const std::shared_ptr<flutter::DlImageFilter>&)filter
505 withRect:(const SkRect&)filterRect {
506 for (int64_t id : self.visitedPlatformViews) {
507 flutter::EmbeddedViewParams params = self.currentCompositionParams[id];
508 params.PushImageFilter(filter, filterRect);
509 self.currentCompositionParams[id] = params;
510 }
511 }
512
513 - (void)prerollCompositeEmbeddedView:(int64_t)viewId
514 withParams:(std::unique_ptr<flutter::EmbeddedViewParams>)params {
515 SkRect viewBounds = SkRect::Make(self.frameSize);
516 std::unique_ptr<flutter::EmbedderViewSlice> view;
517 view = std::make_unique<flutter::DisplayListEmbedderViewSlice>(viewBounds);
518 self.slices.insert_or_assign(viewId, std::move(view));
519
520 self.compositionOrder.push_back(viewId);
521
522 if (self.currentCompositionParams.count(viewId) == 1 &&
523 self.currentCompositionParams[viewId] == *params.get()) {
524 // Do nothing if the params didn't change.
525 return;
526 }
527 self.currentCompositionParams[viewId] = flutter::EmbeddedViewParams(*params.get());
528 self.viewsToRecomposite.insert(viewId);
529 }
530
531 - (size_t)embeddedViewCount {
532 return self.compositionOrder.size();
533 }
534
535 - (UIView*)platformViewForId:(int64_t)viewId {
536 return [self flutterTouchInterceptingViewForId:viewId].embeddedView;
537 }
538
539 - (FlutterTouchInterceptingView*)flutterTouchInterceptingViewForId:(int64_t)viewId {
540 if (self.platformViews.empty()) {
541 return nil;
542 }
543 return self.platformViews[viewId].touch_interceptor;
544 }
545
546 - (long)firstResponderPlatformViewId {
547 for (auto const& [id, platformViewData] : self.platformViews) {
548 UIView* rootView = platformViewData.root_view;
549 if (rootView.flt_hasFirstResponderInViewHierarchySubtree) {
550 return id;
551 }
552 }
553 return -1;
554 }
555
556 - (void)clipViewSetMaskView:(UIView*)clipView {
557 FML_DCHECK([[NSThread currentThread] isMainThread]);
558 if (clipView.maskView) {
559 return;
560 }
561 CGRect frame =
562 CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y,
563 CGRectGetWidth(self.flutterView.bounds), CGRectGetHeight(self.flutterView.bounds));
564 clipView.maskView = [self.maskViewPool getMaskViewWithFrame:frame];
565 }
566
567 - (void)applyMutators:(const flutter::MutatorsStack&)mutatorsStack
568 embeddedView:(UIView*)embeddedView
569 boundingRect:(const SkRect&)boundingRect {
570 if (self.flutterView == nil) {
571 return;
572 }
573
574 ResetAnchor(embeddedView.layer);
575 ChildClippingView* clipView = (ChildClippingView*)embeddedView.superview;
576
577 SkMatrix transformMatrix;
578 NSMutableArray* blurFilters = [[NSMutableArray alloc] init];
579 FML_DCHECK(!clipView.maskView ||
580 [clipView.maskView isKindOfClass:[FlutterClippingMaskView class]]);
581 if (clipView.maskView) {
582 [self.maskViewPool insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
583 clipView.maskView = nil;
584 }
585 CGFloat screenScale = [UIScreen mainScreen].scale;
586 auto iter = mutatorsStack.Begin();
587 while (iter != mutatorsStack.End()) {
588 switch ((*iter)->GetType()) {
589 case flutter::kTransform: {
590 transformMatrix.preConcat((*iter)->GetMatrix());
591 break;
592 }
593 case flutter::kClipRect: {
594 if (ClipRectContainsPlatformViewBoundingRect((*iter)->GetRect(), boundingRect,
595 transformMatrix)) {
596 break;
597 }
598 [self clipViewSetMaskView:clipView];
599 [(FlutterClippingMaskView*)clipView.maskView clipRect:(*iter)->GetRect()
600 matrix:transformMatrix];
601 break;
602 }
603 case flutter::kClipRRect: {
604 if (ClipRRectContainsPlatformViewBoundingRect((*iter)->GetRRect(), boundingRect,
605 transformMatrix)) {
606 break;
607 }
608 [self clipViewSetMaskView:clipView];
609 [(FlutterClippingMaskView*)clipView.maskView clipRRect:(*iter)->GetRRect()
610 matrix:transformMatrix];
611 break;
612 }
613 case flutter::kClipPath: {
614 // TODO(cyanglaz): Find a way to pre-determine if path contains the PlatformView boudning
615 // rect. See `ClipRRectContainsPlatformViewBoundingRect`.
616 // https://github.com/flutter/flutter/issues/118650
617 [self clipViewSetMaskView:clipView];
618 [(FlutterClippingMaskView*)clipView.maskView clipPath:(*iter)->GetPath()
619 matrix:transformMatrix];
620 break;
621 }
622 case flutter::kOpacity:
623 embeddedView.alpha = (*iter)->GetAlphaFloat() * embeddedView.alpha;
624 break;
625 case flutter::kBackdropFilter: {
626 // Only support DlBlurImageFilter for BackdropFilter.
627 if (!self.canApplyBlurBackdrop || !(*iter)->GetFilterMutation().GetFilter().asBlur()) {
628 break;
629 }
630 CGRect filterRect = GetCGRectFromSkRect((*iter)->GetFilterMutation().GetFilterRect());
631 // `filterRect` is in global coordinates. We need to convert to local space.
632 filterRect = CGRectApplyAffineTransform(
633 filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale));
634 // `filterRect` reprents the rect that should be filtered inside the `_flutterView`.
635 // The `PlatformViewFilter` needs the frame inside the `clipView` that needs to be
636 // filtered.
637 if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) {
638 break;
639 }
640 CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
641 CGRect frameInClipView = [self.flutterView convertRect:intersection toView:clipView];
642 // sigma_x is arbitrarily chosen as the radius value because Quartz sets
643 // sigma_x and sigma_y equal to each other. DlBlurImageFilter's Tile Mode
644 // is not supported in Quartz's gaussianBlur CAFilter, so it is not used
645 // to blur the PlatformView.
646 CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
647 UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
648 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
649 PlatformViewFilter* filter = [[PlatformViewFilter alloc] initWithFrame:frameInClipView
650 blurRadius:blurRadius
651 visualEffectView:visualEffectView];
652 if (!filter) {
653 self.canApplyBlurBackdrop = NO;
654 } else {
655 [blurFilters addObject:filter];
656 }
657 break;
658 }
659 }
660 ++iter;
661 }
662
663 if (self.canApplyBlurBackdrop) {
664 [clipView applyBlurBackdropFilters:blurFilters];
665 }
666
667 // The UIKit frame is set based on the logical resolution (points) instead of physical.
668 // (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html).
669 // However, flow is based on the physical resolution. For example, 1000 pixels in flow equals
670 // 500 points in UIKit for devices that has screenScale of 2. We need to scale the transformMatrix
671 // down to the logical resoltion before applying it to the layer of PlatformView.
672 transformMatrix.postScale(1 / screenScale, 1 / screenScale);
673
674 // Reverse the offset of the clipView.
675 // The clipView's frame includes the final translate of the final transform matrix.
676 // Thus, this translate needs to be reversed so the platform view can layout at the correct
677 // offset.
678 //
679 // Note that the transforms are not applied to the clipping paths because clipping paths happen on
680 // the mask view, whose origin is always (0,0) to the _flutterView.
681 transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y);
682
683 embeddedView.layer.transform = GetCATransform3DFromSkMatrix(transformMatrix);
684 }
685
686 - (void)compositeView:(int64_t)viewId withParams:(const flutter::EmbeddedViewParams&)params {
687 // TODO(https://github.com/flutter/flutter/issues/109700)
688 CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());
689 FlutterTouchInterceptingView* touchInterceptor = self.platformViews[viewId].touch_interceptor;
690 touchInterceptor.layer.transform = CATransform3DIdentity;
691 touchInterceptor.frame = frame;
692 touchInterceptor.alpha = 1;
693
694 const flutter::MutatorsStack& mutatorStack = params.mutatorsStack();
695 UIView* clippingView = self.platformViews[viewId].root_view;
696 // The frame of the clipping view should be the final bounding rect.
697 // Because the translate matrix in the Mutator Stack also includes the offset,
698 // when we apply the transforms matrix in |applyMutators:embeddedView:boundingRect|, we need
699 // to remember to do a reverse translate.
700 const SkRect& rect = params.finalBoundingRect();
701 CGFloat screenScale = [UIScreen mainScreen].scale;
702 clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
703 rect.width() / screenScale, rect.height() / screenScale);
704 [self applyMutators:mutatorStack embeddedView:touchInterceptor boundingRect:rect];
705 }
706
707 - (flutter::DlCanvas*)compositeEmbeddedViewWithId:(int64_t)viewId {
708 FML_DCHECK(self.slices.find(viewId) != self.slices.end());
709 return self.slices[viewId]->canvas();
710 }
711
712 - (void)reset {
713 // Reset will only be called from the raster thread or a merged raster/platform thread.
714 // _platformViews must only be modified on the platform thread, and any operations that
715 // read or modify platform views should occur there.
716 fml::TaskRunner::RunNowOrPostTask(self.platformTaskRunner, [self]() {
717 for (int64_t viewId : self.compositionOrder) {
718 [self.platformViews[viewId].root_view removeFromSuperview];
719 }
720 self.platformViews.clear();
721 });
722
723 self.compositionOrder.clear();
724 self.slices.clear();
725 self.currentCompositionParams.clear();
726 self.viewsToRecomposite.clear();
727 self.layerPool->RecycleLayers();
728 self.visitedPlatformViews.clear();
729 }
730
731 - (BOOL)submitFrame:(std::unique_ptr<flutter::SurfaceFrame>)background_frame
732 withIosContext:(const std::shared_ptr<flutter::IOSContext>&)iosContext
733 grContext:(GrDirectContext*)grContext {
734 TRACE_EVENT0("flutter", "PlatformViewsController::SubmitFrame");
735
736 // No platform views to render; we're done.
737 if (self.flutterView == nil || (self.compositionOrder.empty() && !self.hadPlatformViews)) {
738 self.hadPlatformViews = NO;
739 return background_frame->Submit();
740 }
741 self.hadPlatformViews = !self.compositionOrder.empty();
742
743 bool didEncode = true;
744 LayersMap platformViewLayers;
745 std::vector<std::unique_ptr<flutter::SurfaceFrame>> surfaceFrames;
746 surfaceFrames.reserve(self.compositionOrder.size());
747 std::unordered_map<int64_t, SkRect> viewRects;
748
749 for (int64_t viewId : self.compositionOrder) {
750 viewRects[viewId] = self.currentCompositionParams[viewId].finalBoundingRect();
751 }
752
753 std::unordered_map<int64_t, SkRect> overlayLayers =
754 SliceViews(background_frame->Canvas(), self.compositionOrder, self.slices, viewRects);
755
756 size_t requiredOverlayLayers = 0;
757 for (int64_t viewId : self.compositionOrder) {
758 std::unordered_map<int64_t, SkRect>::const_iterator overlay = overlayLayers.find(viewId);
759 if (overlay == overlayLayers.end()) {
760 continue;
761 }
762 requiredOverlayLayers++;
763 }
764
765 // If there are not sufficient overlay layers, we must construct them on the platform
766 // thread, at least until we've refactored iOS surface creation to use IOSurfaces
767 // instead of CALayers.
768 [self createMissingOverlays:requiredOverlayLayers withIosContext:iosContext grContext:grContext];
769
770 int64_t overlayId = 0;
771 for (int64_t viewId : self.compositionOrder) {
772 std::unordered_map<int64_t, SkRect>::const_iterator overlay = overlayLayers.find(viewId);
773 if (overlay == overlayLayers.end()) {
774 continue;
775 }
776 std::shared_ptr<flutter::OverlayLayer> layer = self.nextLayerInPool;
777 if (!layer) {
778 continue;
779 }
780
781 std::unique_ptr<flutter::SurfaceFrame> frame = layer->surface->AcquireFrame(self.frameSize);
782 // If frame is null, AcquireFrame already printed out an error message.
783 if (!frame) {
784 continue;
785 }
786 flutter::DlCanvas* overlayCanvas = frame->Canvas();
787 int restoreCount = overlayCanvas->GetSaveCount();
788 overlayCanvas->Save();
789 overlayCanvas->ClipRect(overlay->second);
790 overlayCanvas->Clear(flutter::DlColor::kTransparent());
791 self.slices[viewId]->render_into(overlayCanvas);
792 overlayCanvas->RestoreToCount(restoreCount);
793
794 // This flutter view is never the last in a frame, since we always submit the
795 // underlay view last.
796 frame->set_submit_info({.frame_boundary = false, .present_with_transaction = true});
797 layer->did_submit_last_frame = frame->Encode();
798
799 didEncode &= layer->did_submit_last_frame;
800 platformViewLayers[viewId] = LayerData{
801 .rect = overlay->second, //
802 .view_id = viewId, //
803 .overlay_id = overlayId, //
804 .layer = layer //
805 };
806 surfaceFrames.push_back(std::move(frame));
807 overlayId++;
808 }
809
810 auto previousSubmitInfo = background_frame->submit_info();
811 background_frame->set_submit_info({
812 .frame_damage = previousSubmitInfo.frame_damage,
813 .buffer_damage = previousSubmitInfo.buffer_damage,
814 .present_with_transaction = true,
815 });
816 background_frame->Encode();
817 surfaceFrames.push_back(std::move(background_frame));
818
819 // Mark all layers as available, so they can be used in the next frame.
820 std::vector<std::shared_ptr<flutter::OverlayLayer>> unusedLayers =
821 self.layerPool->RemoveUnusedLayers();
822 self.layerPool->RecycleLayers();
823
824 auto task = [self, //
825 platformViewLayers = std::move(platformViewLayers), //
826 currentCompositionParams = self.currentCompositionParams, //
827 viewsToRecomposite = self.viewsToRecomposite, //
828 compositionOrder = self.compositionOrder, //
829 unusedLayers = std::move(unusedLayers), //
830 surfaceFrames = std::move(surfaceFrames) //
831 ]() mutable {
832 [self performSubmit:platformViewLayers
833 currentCompositionParams:currentCompositionParams
834 viewsToRecomposite:viewsToRecomposite
835 compositionOrder:compositionOrder
836 unusedLayers:unusedLayers
837 surfaceFrames:surfaceFrames];
838 };
839
840 fml::TaskRunner::RunNowOrPostTask(self.platformTaskRunner, fml::MakeCopyable(std::move(task)));
841
842 return didEncode;
843 }
844
845 - (void)createMissingOverlays:(size_t)requiredOverlayLayers
846 withIosContext:(const std::shared_ptr<flutter::IOSContext>&)iosContext
847 grContext:(GrDirectContext*)grContext {
848 TRACE_EVENT0("flutter", "PlatformViewsController::CreateMissingLayers");
849
850 if (requiredOverlayLayers <= self.layerPool->size()) {
851 return;
852 }
853 auto missingLayerCount = requiredOverlayLayers - self.layerPool->size();
854
855 // If the raster thread isn't merged, create layers on the platform thread and block until
856 // complete.
857 auto latch = std::make_shared<fml::CountDownLatch>(1u);
858 fml::TaskRunner::RunNowOrPostTask(
859 self.platformTaskRunner, [self, missingLayerCount, iosContext, grContext, latch]() {
860 for (auto i = 0u; i < missingLayerCount; i++) {
861 [self createLayerWithIosContext:iosContext
862 grContext:grContext
863 pixelFormat:((FlutterView*)self.flutterView).pixelFormat];
864 }
865 latch->CountDown();
866 });
867 if (![[NSThread currentThread] isMainThread]) {
868 latch->Wait();
869 }
870 }
871
872 - (void)performSubmit:(const LayersMap&)platformViewLayers
873 currentCompositionParams:
874 (std::unordered_map<int64_t, flutter::EmbeddedViewParams>&)currentCompositionParams
875 viewsToRecomposite:(const std::unordered_set<int64_t>&)viewsToRecomposite
876 compositionOrder:(const std::vector<int64_t>&)compositionOrder
877 unusedLayers:
878 (const std::vector<std::shared_ptr<flutter::OverlayLayer>>&)unusedLayers
879 surfaceFrames:
880 (const std::vector<std::unique_ptr<flutter::SurfaceFrame>>&)surfaceFrames {
881 TRACE_EVENT0("flutter", "PlatformViewsController::PerformSubmit");
882 FML_DCHECK([[NSThread currentThread] isMainThread]);
883
884 [CATransaction begin];
885
886 // Configure Flutter overlay views.
887 for (const auto& [viewId, layerData] : platformViewLayers) {
888 layerData.layer->UpdateViewState(self.flutterView, //
889 layerData.rect, //
890 layerData.view_id, //
891 layerData.overlay_id //
892 );
893 }
894
895 // Dispose unused Flutter Views.
896 for (auto& view : [self computeViewsToDispose]) {
897 [view removeFromSuperview];
898 }
899
900 // Composite Platform Views.
901 for (int64_t viewId : viewsToRecomposite) {
902 [self compositeView:viewId withParams:currentCompositionParams[viewId]];
903 }
904
905 // Present callbacks.
906 for (const auto& frame : surfaceFrames) {
907 frame->Submit();
908 }
909
910 // If a layer was allocated in the previous frame, but it's not used in the current frame,
911 // then it can be removed from the scene.
912 [self removeUnusedLayers:unusedLayers withCompositionOrder:compositionOrder];
913
914 // Organize the layers by their z indexes.
915 [self bringLayersIntoView:platformViewLayers withCompositionOrder:compositionOrder];
916
917 [CATransaction commit];
918 }
919
920 - (void)bringLayersIntoView:(const LayersMap&)layerMap
921 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder {
922 FML_DCHECK(self.flutterView);
923 UIView* flutterView = self.flutterView;
924
925 self.previousCompositionOrder.clear();
926 NSMutableArray* desiredPlatformSubviews = [NSMutableArray array];
927 for (int64_t platformViewId : compositionOrder) {
928 self.previousCompositionOrder.push_back(platformViewId);
929 UIView* platformViewRoot = self.platformViews[platformViewId].root_view;
930 if (platformViewRoot != nil) {
931 [desiredPlatformSubviews addObject:platformViewRoot];
932 }
933
934 auto maybeLayerData = layerMap.find(platformViewId);
935 if (maybeLayerData != layerMap.end()) {
936 auto view = maybeLayerData->second.layer->overlay_view_wrapper;
937 if (view != nil) {
938 [desiredPlatformSubviews addObject:view];
939 }
940 }
941 }
942
943 NSSet* desiredPlatformSubviewsSet = [NSSet setWithArray:desiredPlatformSubviews];
944 NSArray* existingPlatformSubviews = [flutterView.subviews
945 filteredArrayUsingPredicate:[NSPredicate
946 predicateWithBlock:^BOOL(id object, NSDictionary* bindings) {
947 return [desiredPlatformSubviewsSet containsObject:object];
948 }]];
949
950 // Manipulate view hierarchy only if needed, to address a performance issue where
951 // this method is called even when view hierarchy stays the same.
952 // See: https://github.com/flutter/flutter/issues/121833
953 // TODO(hellohuanlin): investigate if it is possible to skip unnecessary bringLayersIntoView.
954 if (![desiredPlatformSubviews isEqualToArray:existingPlatformSubviews]) {
955 for (UIView* subview in desiredPlatformSubviews) {
956 // `addSubview` will automatically reorder subview if it is already added.
957 [flutterView addSubview:subview];
958 }
959 }
960 }
961
962 - (std::shared_ptr<flutter::OverlayLayer>)nextLayerInPool {
963 return self.layerPool->GetNextLayer();
964 }
965
966 - (void)createLayerWithIosContext:(const std::shared_ptr<flutter::IOSContext>&)iosContext
967 grContext:(GrDirectContext*)grContext
968 pixelFormat:(MTLPixelFormat)pixelFormat {
969 self.layerPool->CreateLayer(grContext, iosContext, pixelFormat);
970 }
971
972 - (void)removeUnusedLayers:(const std::vector<std::shared_ptr<flutter::OverlayLayer>>&)unusedLayers
973 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder {
974 for (const std::shared_ptr<flutter::OverlayLayer>& layer : unusedLayers) {
975 [layer->overlay_view_wrapper removeFromSuperview];
976 }
977
978 std::unordered_set<int64_t> compositionOrderSet;
979 for (int64_t viewId : compositionOrder) {
980 compositionOrderSet.insert(viewId);
981 }
982 // Remove unused platform views.
983 for (int64_t viewId : self.previousCompositionOrder) {
984 if (compositionOrderSet.find(viewId) == compositionOrderSet.end()) {
985 UIView* platformViewRoot = self.platformViews[viewId].root_view;
986 [platformViewRoot removeFromSuperview];
987 }
988 }
989 }
990
991 - (std::vector<UIView*>)computeViewsToDispose {
992 std::vector<UIView*> views;
993 if (self.viewsToDispose.empty()) {
994 return views;
995 }
996
997 std::unordered_set<int64_t> viewsToComposite(self.compositionOrder.begin(),
998 self.compositionOrder.end());
999 std::unordered_set<int64_t> viewsToDelayDispose;
1000 for (int64_t viewId : self.viewsToDispose) {
1001 if (viewsToComposite.count(viewId)) {
1002 viewsToDelayDispose.insert(viewId);
1003 continue;
1004 }
1005 UIView* rootView = self.platformViews[viewId].root_view;
1006 views.push_back(rootView);
1007 self.currentCompositionParams.erase(viewId);
1008 self.viewsToRecomposite.erase(viewId);
1009 self.platformViews.erase(viewId);
1010 }
1011 self.viewsToDispose = std::move(viewsToDelayDispose);
1012 return views;
1013 }
1014
1015 - (void)resetFrameState {
1016 self.slices.clear();
1017 self.compositionOrder.clear();
1018 self.visitedPlatformViews.clear();
1019 }
1020
1021 - (void)pushVisitedPlatformViewId:(int64_t)viewId {
1022 self.visitedPlatformViews.push_back(viewId);
1023 }
1024
1025 - (const flutter::EmbeddedViewParams&)compositionParamsForView:(int64_t)viewId {
1026 return self.currentCompositionParams.find(viewId)->second;
1027 }
1028
1029 #pragma mark - Properties
1030
1031 - (flutter::OverlayLayerPool*)layerPool {
1032 return _layerPool.get();
1033 }
1034
1035 - (std::unordered_map<int64_t, std::unique_ptr<flutter::EmbedderViewSlice>>&)slices {
1036 return _slices;
1037 }
1038
1039 - (std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*>&)factories {
1040 return _factories;
1041 }
1042 - (std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>&)
1043 gestureRecognizersBlockingPolicies {
1044 return _gestureRecognizersBlockingPolicies;
1045 }
1046
1047 - (std::unordered_map<int64_t, PlatformViewData>&)platformViews {
1048 return _platformViews;
1049 }
1050
1051 - (std::unordered_map<int64_t, flutter::EmbeddedViewParams>&)currentCompositionParams {
1052 return _currentCompositionParams;
1053 }
1054
1055 - (std::unordered_set<int64_t>&)viewsToDispose {
1056 return _viewsToDispose;
1057 }
1058
1059 - (std::vector<int64_t>&)compositionOrder {
1060 return _compositionOrder;
1061 }
1062
1063 - (std::vector<int64_t>&)visitedPlatformViews {
1064 return _visitedPlatformViews;
1065 }
1066
1067 - (std::unordered_set<int64_t>&)viewsToRecomposite {
1068 return _viewsToRecomposite;
1069 }
1070
1071 - (std::vector<int64_t>&)previousCompositionOrder {
1072 return _previousCompositionOrder;
1073 }
1074
1075 @end
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
FlutterOverlayView.h
FlutterPlatformViewsController.h
GetCGRectFromSkRect
static CGRect GetCGRectFromSkRect(const SkRect &clipSkRect)
Definition: FlutterPlatformViewsController.mm:70
_gestureRecognizersBlockingPolicies
std::unordered_map< std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy > _gestureRecognizersBlockingPolicies
Definition: FlutterPlatformViewsController.mm:280
LayersMap
std::unordered_map< int64_t, LayerData > LayersMap
Definition: FlutterPlatformViewsController.mm:31
ClipRectContainsPlatformViewBoundingRect
static bool ClipRectContainsPlatformViewBoundingRect(const SkRect &clip_rect, const SkRect &platformview_boundingrect, const SkMatrix &transform_matrix)
Definition: FlutterPlatformViewsController.mm:83
_compositionOrder
std::vector< int64_t > _compositionOrder
Definition: FlutterPlatformViewsController.mm:285
_viewsToRecomposite
std::unordered_set< int64_t > _viewsToRecomposite
Definition: FlutterPlatformViewsController.mm:287
_factories
std::unordered_map< std::string, NSObject< FlutterPlatformViewFactory > * > _factories
Definition: FlutterPlatformViewsController.mm:278
_previousCompositionOrder
std::vector< int64_t > _previousCompositionOrder
Definition: FlutterPlatformViewsController.mm:288
kFlutterClippingMaskViewPoolCapacity
static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity
Definition: FlutterPlatformViewsController.mm:23
_platformViews
std::unordered_map< int64_t, PlatformViewData > _platformViews
Definition: FlutterPlatformViewsController.mm:282
_slices
std::unordered_map< int64_t, std::unique_ptr< flutter::EmbedderViewSlice > > _slices
Definition: FlutterPlatformViewsController.mm:268
kDefaultMergedLeaseDuration
static constexpr int kDefaultMergedLeaseDuration
Definition: FlutterPlatformViewsController.mm:21
_visitedPlatformViews
std::vector< int64_t > _visitedPlatformViews
Definition: FlutterPlatformViewsController.mm:286
GetCATransform3DFromSkMatrix
static CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix &matrix)
Definition: FlutterPlatformViewsController.mm:46
ClipRRectContainsPlatformViewBoundingRect
static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect &clip_rrect, const SkRect &platformview_boundingrect, const SkMatrix &transform_matrix)
Definition: FlutterPlatformViewsController.mm:98
_platformTaskRunner
fml::RefPtr< fml::TaskRunner > _platformTaskRunner
Definition: FlutterPlatformViewsController.mm:281
_currentCompositionParams
std::unordered_map< int64_t, flutter::EmbeddedViewParams > _currentCompositionParams
Definition: FlutterPlatformViewsController.mm:283
ResetAnchor
static void ResetAnchor(CALayer *layer)
Definition: FlutterPlatformViewsController.mm:64
_viewsToDispose
std::unordered_set< int64_t > _viewsToDispose
Definition: FlutterPlatformViewsController.mm:284
FlutterPlatformViewGestureRecognizersBlockingPolicy
FlutterPlatformViewGestureRecognizersBlockingPolicy
Definition: FlutterPlugin.h:252
self
return self
Definition: FlutterTextureRegistryRelay.mm:19
FlutterView.h
ChildClippingView
Definition: FlutterPlatformViews.mm:143
-[ChildClippingView applyBlurBackdropFilters:]
void applyBlurBackdropFilters:(NSArray< PlatformViewFilter * > *filters)
Definition: FlutterPlatformViews.mm:157
FlutterClippingMaskView
Definition: FlutterPlatformViews.mm:206
FlutterClippingMaskViewPool
Definition: FlutterPlatformViews.mm:464
FlutterTouchInterceptingView
Definition: FlutterPlatformViews.mm:521
-[FlutterTouchInterceptingView releaseGesture]
void releaseGesture()
Definition: FlutterPlatformViews.mm:565
-[FlutterTouchInterceptingView blockGesture]
void blockGesture()
Definition: FlutterPlatformViews.mm:584
PlatformViewFilter
Definition: FlutterPlatformViews.mm:51
flutter::OverlayLayerPool
Storage for Overlay layers across frames.
Definition: overlay_layer_pool.h:52
FlutterError
Definition: FlutterCodecs.h:247
FlutterMethodCall
Definition: FlutterCodecs.h:221
FlutterMethodCall::arguments
id arguments
Definition: FlutterCodecs.h:238
FlutterPlatformViewsController
Definition: FlutterPlatformViewsController.h:32
FlutterStandardTypedData
Definition: FlutterCodecs.h:301
ios_surface.h
flutter
Definition: accessibility_bridge.h:27
fml
Definition: profiler_metrics_ios.mm:41
overlay_layer_pool.h
FlutterPlatformViewFactory-p
Definition: FlutterPlatformViews.h:26
LayerData
Definition: FlutterPlatformViewsController.mm:25
LayerData::view_id
int64_t view_id
Definition: FlutterPlatformViewsController.mm:27
LayerData::layer
std::shared_ptr< flutter::OverlayLayer > layer
Definition: FlutterPlatformViewsController.mm:29
LayerData::overlay_id
int64_t overlay_id
Definition: FlutterPlatformViewsController.mm:28
LayerData::rect
SkRect rect
Definition: FlutterPlatformViewsController.mm:26
PlatformViewData
Definition: FlutterPlatformViewsController.mm:37
PlatformViewData::root_view
UIView * root_view
Definition: FlutterPlatformViewsController.mm:40
PlatformViewData::touch_interceptor
FlutterTouchInterceptingView * touch_interceptor
Definition: FlutterPlatformViewsController.mm:39
PlatformViewData::view
NSObject< FlutterPlatformView > * view
Definition: FlutterPlatformViewsController.mm:38