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