6 #include "display_list/geometry/dl_geometry_types.h"
7 #include "impeller/geometry/rounding_radii.h"
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"
20 using flutter::DlISize;
21 using flutter::DlMatrix;
22 using flutter::DlRect;
23 using flutter::DlRoundRect;
31 std::shared_ptr<flutter::OverlayLayer>
layer;
33 using LayersMap = std::unordered_map<int64_t, LayerData>;
40 NSObject<FlutterPlatformView>*
view;
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];
53 transform.m21 = matrix.m[4];
54 transform.m22 = matrix.m[5];
55 transform.m23 = matrix.m[6];
56 transform.m24 = matrix.m[7];
58 transform.m31 = matrix.m[8];
59 transform.m32 = matrix.m[9];
60 transform.m33 = matrix.m[10];
61 transform.m34 = matrix.m[11];
63 transform.m41 = matrix.m[12];
64 transform.m42 = matrix.m[13];
65 transform.m43 = matrix.m[14];
66 transform.m44 = matrix.m[15];
75 layer.anchorPoint = CGPointZero;
76 layer.position = CGPointZero;
80 return CGRectMake(clipDlRect.GetLeft(),
82 clipDlRect.GetWidth(),
83 clipDlRect.GetHeight());
95 @property(nonatomic, readonly)
96 std::unordered_map<int64_t, std::unique_ptr<flutter::EmbedderViewSlice>>& slices;
100 @property(nonatomic, readonly)
101 std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*>& factories;
104 @property(nonatomic, readonly)
105 std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>&
106 gestureRecognizersBlockingPolicies;
109 @property(nonatomic, assign) DlISize frameSize;
112 @property(nonatomic, readonly)
const fml::RefPtr<fml::TaskRunner>& platformTaskRunner;
115 @property(nonatomic, readonly) std::unordered_map<int64_t, PlatformViewData>& platformViews;
120 @property(nonatomic, readonly)
121 std::unordered_map<int64_t, flutter::EmbeddedViewParams>& currentCompositionParams;
127 @property(nonatomic, readonly) std::unordered_set<int64_t>& viewsToDispose;
132 @property(nonatomic, readonly) std::vector<int64_t>& compositionOrder;
137 @property(nonatomic, readonly) std::vector<int64_t>& visitedPlatformViews;
142 @property(nonatomic, readonly) std::unordered_set<int64_t>& viewsToRecomposite;
156 @property(nonatomic, assign) BOOL hadPlatformViews;
161 @property(nonatomic, assign) BOOL canApplyBlurBackdrop;
166 - (void)createMissingOverlays:(
size_t)requiredOverlayLayers
167 withIosContext:(const std::shared_ptr<
flutter::IOSContext>&)iosContext;
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
176 (const std::vector<std::shared_ptr<
flutter::OverlayLayer>>&)unusedLayers
178 (const std::vector<std::unique_ptr<
flutter::SurfaceFrame>>&)surfaceFrames;
185 - (void)clipViewSetMaskView:(UIView*)clipView;
199 - (void)applyMutators:(const
flutter::MutatorsStack&)mutatorsStack
200 embeddedView:(UIView*)embeddedView
201 boundingRect:(const DlRect&)boundingRect;
205 - (void)bringLayersIntoView:(const
LayersMap&)layerMap
206 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder;
208 - (std::shared_ptr<flutter::OverlayLayer>)nextLayerInPool;
211 - (void)createLayerWithIosContext:(const std::shared_ptr<
flutter::IOSContext>&)iosContext
212 pixelFormat:(MTLPixelFormat)pixelFormat;
216 - (void)removeUnusedLayers:(const std::vector<std::shared_ptr<
flutter::OverlayLayer>>&)unusedLayers
217 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder;
223 - (std::vector<UIView*>)computeViewsToDispose;
226 - (void)resetFrameState;
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>
253 if (
self = [super init]) {
254 _layerPool = std::make_unique<flutter::OverlayLayerPool>();
257 _hadPlatformViews = NO;
258 _canApplyBlurBackdrop = YES;
263 - (const
fml::RefPtr<fml::TaskRunner>&)taskRunner {
267 - (void)setTaskRunner:(const
fml::RefPtr<
fml::TaskRunner>&)platformTaskRunner {
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];
286 NSDictionary<NSString*, id>* args = [call
arguments];
288 int64_t viewId = [args[@"id"] longLongValue];
289 NSString* viewTypeString = args[@"viewType"];
290 std::string viewType(viewTypeString.UTF8String);
292 if (
self.platformViews.count(viewId) != 0) {
294 message:
@"trying to create an already created view"
295 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
299 NSObject<FlutterPlatformViewFactory>* factory =
self.factories[viewType];
300 if (factory == nil) {
302 errorWithCode:
@"unregistered_view_type"
303 message:[NSString stringWithFormat:
@"A UIKitView widget is trying to create a "
304 @"PlatformView with an unregistered type: < %@ >",
306 details:
@"If you are the author of the PlatformView, make sure `registerViewFactory` "
309 @"https://docs.flutter.cn/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`."]);
317 if ([factory respondsToSelector:
@selector(createArgsCodec)]) {
318 NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
319 if (codec != nil && args[
@"params"] != nil) {
321 params = [codec decode:paramsData.data];
325 NSObject<FlutterPlatformView>* embeddedView = [factory createWithFrame:CGRectZero
326 viewIdentifier:viewId
328 UIView* platformView = [embeddedView view];
330 platformView.accessibilityIdentifier = [NSString stringWithFormat:@"platform_view[%lld]", viewId];
333 initWithEmbeddedView:platformView
334 platformViewsController:self
335 gestureRecognizersBlockingPolicy:self.gestureRecognizersBlockingPolicies[viewType]];
338 [clippingView addSubview:touchInterceptor];
341 .
view = embeddedView,
342 .touch_interceptor = touchInterceptor,
343 .root_view = clippingView
351 int64_t viewId = [arg longLongValue];
353 if (
self.platformViews.count(viewId) == 0) {
355 message:
@"trying to dispose an unknown"
356 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
360 self.viewsToDispose.insert(viewId);
365 NSDictionary<NSString*, id>* args = [call
arguments];
366 int64_t viewId = [args[@"id"] longLongValue];
368 if (
self.platformViews.count(viewId) == 0) {
370 message:
@"trying to set gesture state for an unknown view"
371 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
382 NSDictionary<NSString*, id>* args = [call
arguments];
383 int64_t viewId = [args[@"id"] longLongValue];
385 if (
self.platformViews.count(viewId) == 0) {
387 message:
@"trying to set gesture state for an unknown view"
388 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
399 withId:(NSString*)factoryId
400 gestureRecognizersBlockingPolicy:
402 std::string idString([factoryId UTF8String]);
403 FML_CHECK(
self.factories.count(idString) == 0);
404 self.factories[idString] = factory;
405 self.gestureRecognizersBlockingPolicies[idString] = gestureRecognizerBlockingPolicy;
408 - (void)beginFrameWithSize:(DlISize)frameSize {
409 [
self resetFrameState];
410 self.frameSize = frameSize;
413 - (void)cancelFrame {
414 [
self resetFrameState];
417 - (
flutter::PostPrerollResult)postPrerollActionWithThreadMerger:
418 (const
fml::RefPtr<
fml::RasterThreadMerger>&)rasterThreadMerger {
419 return flutter::PostPrerollResult::kSuccess;
422 - (void)endFrameWithResubmit:(BOOL)shouldResubmitFrame
423 threadMerger:(const
fml::RefPtr<
fml::RasterThreadMerger>&)rasterThreadMerger {
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;
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));
442 self.compositionOrder.push_back(viewId);
444 if (
self.currentCompositionParams.count(viewId) == 1 &&
445 self.currentCompositionParams[viewId] == *params.get()) {
449 self.currentCompositionParams[viewId] = flutter::EmbeddedViewParams(*params.get());
450 self.viewsToRecomposite.insert(viewId);
453 - (size_t)embeddedViewCount {
454 return self.compositionOrder.size();
457 - (UIView*)platformViewForId:(int64_t)viewId {
458 return [
self flutterTouchInterceptingViewForId:viewId].embeddedView;
462 if (
self.platformViews.empty()) {
465 return self.platformViews[viewId].touch_interceptor;
468 - (long)firstResponderPlatformViewId {
469 for (
auto const& [
id, platformViewData] :
self.platformViews) {
470 UIView* rootView = platformViewData.root_view;
471 if (rootView.flt_hasFirstResponderInViewHierarchySubtree) {
478 - (void)clipViewSetMaskView:(UIView*)clipView {
479 FML_DCHECK([[NSThread currentThread] isMainThread]);
480 if (clipView.maskView) {
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];
489 - (void)applyMutators:(const
flutter::MutatorsStack&)mutatorsStack
490 embeddedView:(UIView*)embeddedView
491 boundingRect:(const DlRect&)boundingRect {
492 if (
self.flutterView == nil) {
499 DlMatrix transformMatrix;
500 NSMutableArray* blurFilters = [[NSMutableArray alloc] init];
501 NSMutableArray<PendingRRectClip*>* pendingClipRRects = [[NSMutableArray alloc] init];
503 FML_DCHECK(!clipView.maskView ||
505 if (clipView.maskView) {
506 [
self.maskViewPool insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
507 clipView.maskView = nil;
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();
517 case flutter::MutatorType::kClipRect: {
518 if (flutter::DisplayListMatrixClipState::TransformedRectCoversBounds(
519 (*iter)->GetRect(), transformMatrix, boundingRect)) {
522 [
self clipViewSetMaskView:clipView];
524 matrix:transformMatrix];
527 case flutter::MutatorType::kClipRRect: {
528 if (flutter::DisplayListMatrixClipState::TransformedRRectCoversBounds(
529 (*iter)->GetRRect(), transformMatrix, boundingRect)) {
532 [
self clipViewSetMaskView:clipView];
534 matrix:transformMatrix];
537 case flutter::MutatorType::kClipRSE: {
538 if (flutter::DisplayListMatrixClipState::TransformedRoundSuperellipseCoversBounds(
539 (*iter)->GetRSE(), transformMatrix, boundingRect)) {
542 [
self clipViewSetMaskView:clipView];
544 matrix:transformMatrix];
547 case flutter::MutatorType::kClipPath: {
551 [
self clipViewSetMaskView:clipView];
553 matrix:transformMatrix];
556 case flutter::MutatorType::kOpacity:
557 embeddedView.alpha = (*iter)->GetAlphaFloat() * embeddedView.alpha;
559 case flutter::MutatorType::kBackdropFilter: {
561 if (!
self.canApplyBlurBackdrop || !(*iter)->GetFilterMutation().GetFilter().asBlur()) {
566 filterRect = CGRectApplyAffineTransform(
567 filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale));
571 if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) {
574 CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
575 CGRect frameInClipView = [
self.flutterView convertRect:intersection toView:clipView];
580 CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
581 UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
582 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
585 CGFloat cornerRadius = 0.0;
586 BOOL isRoundedSuperellipse = NO;
589 if ([pendingClipRRects count] > 0) {
590 cornerRadius = pendingClipRRects.lastObject.topLeftRadius;
591 isRoundedSuperellipse = pendingClipRRects.lastObject.isRoundedSuperellipse;
592 [pendingClipRRects removeAllObjects];
594 visualEffectView.layer.cornerRadius = cornerRadius;
595 if (@available(iOS 13.0, *)) {
596 visualEffectView.layer.cornerCurve =
597 isRoundedSuperellipse ? kCACornerCurveContinuous : kCACornerCurveCircular;
599 visualEffectView.clipsToBounds = YES;
602 blurRadius:blurRadius
603 cornerRadius:cornerRadius
604 isRoundedSuperellipse:isRoundedSuperellipse
605 visualEffectView:visualEffectView];
607 self.canApplyBlurBackdrop = NO;
609 [blurFilters addObject:filter];
613 case flutter::MutatorType::kBackdropClipRect: {
618 case flutter::MutatorType::kBackdropClipRRect: {
620 DlRoundRect rrect = (*iter)->GetBackdropClipRRect().rrect;
622 clip.
rect = boundingRect;
623 impeller::RoundingRadii radii = rrect.GetRadii();
628 [pendingClipRRects addObject:clip];
631 case flutter::MutatorType::kBackdropClipRSuperellipse: {
633 flutter::DlRoundSuperellipse rse = (*iter)->GetBackdropClipRSuperellipse().rse;
635 clip.
rect = boundingRect;
636 impeller::RoundingRadii radii = rse.GetRadii();
642 [pendingClipRRects addObject:clip];
645 case flutter::MutatorType::kBackdropClipPath: {
653 if (
self.canApplyBlurBackdrop) {
662 flutter::DlScalar pointScale = 1.0 / screenScale;
663 transformMatrix = DlMatrix::MakeScale({pointScale, pointScale, 1}) * transformMatrix;
672 impeller::Vector3 origin = impeller::Vector3(clipView.frame.origin.x, clipView.frame.origin.y);
673 transformMatrix = DlMatrix::MakeTranslation(-origin) * transformMatrix;
678 - (void)compositeView:(int64_t)viewId withParams:(const
flutter::EmbeddedViewParams&)params {
680 CGRect frame = CGRectMake(0, 0, params.sizePoints().width, params.sizePoints().height);
682 touchInterceptor.layer.transform = CATransform3DIdentity;
683 touchInterceptor.frame = frame;
684 touchInterceptor.alpha = 1;
686 const flutter::MutatorsStack& mutatorStack = params.mutatorsStack();
687 UIView* clippingView =
self.platformViews[viewId].root_view;
692 const DlRect& rect = params.finalBoundingRect();
693 CGFloat screenScale = [UIScreen mainScreen].scale;
694 clippingView.frame = CGRectMake(rect.GetX() / screenScale, rect.GetY() / screenScale,
695 rect.GetWidth() / screenScale, rect.GetHeight() / screenScale);
696 [
self applyMutators:mutatorStack embeddedView:touchInterceptor boundingRect:rect];
699 - (
flutter::DlCanvas*)compositeEmbeddedViewWithId:(int64_t)viewId {
700 FML_DCHECK(
self.slices.find(viewId) !=
self.slices.end());
701 return self.slices[viewId]->canvas();
708 fml::TaskRunner::RunNowOrPostTask(
self.platformTaskRunner, [
self]() {
709 for (int64_t viewId :
self.compositionOrder) {
710 [
self.platformViews[viewId].root_view removeFromSuperview];
712 self.platformViews.clear();
713 self.previousCompositionOrder.clear();
716 self.compositionOrder.clear();
718 self.currentCompositionParams.clear();
719 self.viewsToRecomposite.clear();
720 self.layerPool->RecycleLayers();
721 self.visitedPlatformViews.clear();
724 - (BOOL)submitFrame:(std::unique_ptr<
flutter::SurfaceFrame>)background_frame
725 withIosContext:(const std::shared_ptr<
flutter::IOSContext>&)iosContext {
726 TRACE_EVENT0(
"flutter",
"PlatformViewsController::SubmitFrame");
729 if (
self.flutterView == nil || (
self.compositionOrder.empty() && !
self.hadPlatformViews)) {
732 if (
self.flutterView != nil) {
733 fml::TaskRunner::RunNowOrPostTask(
734 weakSelf.platformTaskRunner,
735 fml::MakeCopyable([weakSelf, frameSize = weakSelf.frameSize]() {
736 FlutterPlatformViewsController* strongSelf = weakSelf;
740 [strongSelf performResize:frameSize];
744 self.hadPlatformViews = NO;
745 return background_frame->Submit();
747 self.hadPlatformViews = !
self.compositionOrder.empty();
749 bool didEncode =
true;
751 std::vector<std::unique_ptr<flutter::SurfaceFrame>> surfaceFrames;
752 surfaceFrames.reserve(
self.compositionOrder.size());
753 std::unordered_map<int64_t, DlRect> viewRects;
755 for (int64_t viewId :
self.compositionOrder) {
756 viewRects[viewId] =
self.currentCompositionParams[viewId].finalBoundingRect();
759 std::unordered_map<int64_t, DlRect> overlayLayers =
760 SliceViews(background_frame->Canvas(),
self.compositionOrder,
self.slices, viewRects);
762 size_t requiredOverlayLayers = 0;
763 for (int64_t viewId :
self.compositionOrder) {
764 std::unordered_map<int64_t, DlRect>::const_iterator overlay = overlayLayers.find(viewId);
765 if (overlay == overlayLayers.end()) {
768 requiredOverlayLayers++;
774 [
self createMissingOverlays:requiredOverlayLayers withIosContext:iosContext];
776 int64_t overlayId = 0;
777 for (int64_t viewId :
self.compositionOrder) {
778 std::unordered_map<int64_t, DlRect>::const_iterator overlay = overlayLayers.find(viewId);
779 if (overlay == overlayLayers.end()) {
782 std::shared_ptr<flutter::OverlayLayer> layer =
self.nextLayerInPool;
787 std::unique_ptr<flutter::SurfaceFrame> frame = layer->surface->AcquireFrame(
self.frameSize);
792 flutter::DlCanvas* overlayCanvas = frame->Canvas();
793 int restoreCount = overlayCanvas->GetSaveCount();
794 overlayCanvas->Save();
795 overlayCanvas->ClipRect(overlay->second);
796 overlayCanvas->Clear(flutter::DlColor::kTransparent());
797 self.slices[viewId]->render_into(overlayCanvas);
798 overlayCanvas->RestoreToCount(restoreCount);
802 frame->set_submit_info({.frame_boundary =
false, .present_with_transaction =
true});
803 layer->did_submit_last_frame = frame->Encode();
805 didEncode &= layer->did_submit_last_frame;
807 .
rect = overlay->second,
809 .overlay_id = overlayId,
812 surfaceFrames.push_back(std::move(frame));
816 auto previousSubmitInfo = background_frame->submit_info();
817 background_frame->set_submit_info({
818 .frame_damage = previousSubmitInfo.frame_damage,
819 .buffer_damage = previousSubmitInfo.buffer_damage,
820 .present_with_transaction =
true,
822 background_frame->Encode();
823 surfaceFrames.push_back(std::move(background_frame));
826 std::vector<std::shared_ptr<flutter::OverlayLayer>> unusedLayers =
827 self.layerPool->RemoveUnusedLayers();
828 self.layerPool->RecycleLayers();
830 platformViewLayers = std::move(platformViewLayers),
831 currentCompositionParams = self.currentCompositionParams,
832 viewsToRecomposite = self.viewsToRecomposite,
833 compositionOrder = self.compositionOrder,
834 unusedLayers = std::move(unusedLayers),
835 surfaceFrames = std::move(surfaceFrames)]()
mutable {
836 [
self performSubmit:platformViewLayers
837 currentCompositionParams:currentCompositionParams
838 viewsToRecomposite:viewsToRecomposite
839 compositionOrder:compositionOrder
840 unusedLayers:unusedLayers
841 surfaceFrames:surfaceFrames];
844 fml::TaskRunner::RunNowOrPostTask(
self.platformTaskRunner, fml::MakeCopyable(std::move(task)));
848 - (void)createMissingOverlays:(
size_t)requiredOverlayLayers
849 withIosContext:(const std::shared_ptr<
flutter::IOSContext>&)iosContext {
850 TRACE_EVENT0(
"flutter",
"PlatformViewsController::CreateMissingLayers");
852 if (requiredOverlayLayers <= self.layerPool->size()) {
855 auto missingLayerCount = requiredOverlayLayers -
self.layerPool->size();
859 auto latch = std::make_shared<fml::CountDownLatch>(1u);
860 fml::TaskRunner::RunNowOrPostTask(
861 self.platformTaskRunner, [
self, missingLayerCount, iosContext, latch]() {
862 for (
auto i = 0u; i < missingLayerCount; i++) {
863 [
self createLayerWithIosContext:iosContext
864 pixelFormat:((FlutterView*)self.flutterView).pixelFormat];
868 if (![[NSThread currentThread] isMainThread]) {
873 - (void)performResize:(const
flutter::DlISize&)frameSize {
874 TRACE_EVENT0(
"flutter",
"PlatformViewsController::PerformResize");
875 FML_DCHECK([[NSThread currentThread] isMainThread]);
877 if (
self.flutterView != nil) {
879 setIntrinsicContentSize:CGSizeMake(frameSize.width, frameSize.height)];
883 - (void)performSubmit:(const
LayersMap&)platformViewLayers
884 currentCompositionParams:
885 (std::unordered_map<int64_t,
flutter::EmbeddedViewParams>&)currentCompositionParams
886 viewsToRecomposite:(const std::unordered_set<int64_t>&)viewsToRecomposite
887 compositionOrder:(const std::vector<int64_t>&)compositionOrder
889 (const std::vector<std::shared_ptr<
flutter::OverlayLayer>>&)unusedLayers
891 (const std::vector<std::unique_ptr<
flutter::SurfaceFrame>>&)surfaceFrames {
892 TRACE_EVENT0(
"flutter",
"PlatformViewsController::PerformSubmit");
893 FML_DCHECK([[NSThread currentThread] isMainThread]);
895 [CATransaction begin];
898 for (
const auto& [viewId, layerData] : platformViewLayers) {
899 layerData.layer->UpdateViewState(
self.flutterView,
907 for (
auto& view : [
self computeViewsToDispose]) {
908 [view removeFromSuperview];
912 for (int64_t viewId : viewsToRecomposite) {
913 [
self compositeView:viewId withParams:currentCompositionParams[viewId]];
917 for (
const auto& frame : surfaceFrames) {
923 [
self removeUnusedLayers:unusedLayers withCompositionOrder:compositionOrder];
926 [
self bringLayersIntoView:platformViewLayers withCompositionOrder:compositionOrder];
928 [CATransaction commit];
931 - (void)bringLayersIntoView:(const
LayersMap&)layerMap
932 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder {
933 FML_DCHECK(
self.flutterView);
934 UIView* flutterView =
self.flutterView;
936 self.previousCompositionOrder.clear();
937 NSMutableArray* desiredPlatformSubviews = [NSMutableArray array];
938 for (int64_t platformViewId : compositionOrder) {
939 self.previousCompositionOrder.push_back(platformViewId);
940 UIView* platformViewRoot =
self.platformViews[platformViewId].root_view;
941 if (platformViewRoot != nil) {
942 [desiredPlatformSubviews addObject:platformViewRoot];
945 auto maybeLayerData = layerMap.find(platformViewId);
946 if (maybeLayerData != layerMap.end()) {
947 auto view = maybeLayerData->second.layer->overlay_view_wrapper;
949 [desiredPlatformSubviews addObject:view];
954 NSSet* desiredPlatformSubviewsSet = [NSSet setWithArray:desiredPlatformSubviews];
955 NSArray* existingPlatformSubviews = [flutterView.subviews
956 filteredArrayUsingPredicate:[NSPredicate
957 predicateWithBlock:^BOOL(id object, NSDictionary* bindings) {
958 return [desiredPlatformSubviewsSet containsObject:object];
965 if (![desiredPlatformSubviews isEqualToArray:existingPlatformSubviews]) {
966 for (UIView* subview in desiredPlatformSubviews) {
968 [flutterView addSubview:subview];
973 - (std::shared_ptr<flutter::OverlayLayer>)nextLayerInPool {
974 return self.layerPool->GetNextLayer();
977 - (void)createLayerWithIosContext:(const std::shared_ptr<
flutter::IOSContext>&)iosContext
978 pixelFormat:(MTLPixelFormat)pixelFormat {
979 self.layerPool->CreateLayer(iosContext, pixelFormat);
982 - (void)removeUnusedLayers:(const std::vector<std::shared_ptr<
flutter::OverlayLayer>>&)unusedLayers
983 withCompositionOrder:(const std::vector<int64_t>&)compositionOrder {
984 for (
const std::shared_ptr<flutter::OverlayLayer>& layer : unusedLayers) {
985 [layer->overlay_view_wrapper removeFromSuperview];
988 std::unordered_set<int64_t> compositionOrderSet;
989 for (int64_t viewId : compositionOrder) {
990 compositionOrderSet.insert(viewId);
993 for (int64_t viewId :
self.previousCompositionOrder) {
994 if (compositionOrderSet.find(viewId) == compositionOrderSet.end()) {
995 UIView* platformViewRoot =
self.platformViews[viewId].root_view;
996 [platformViewRoot removeFromSuperview];
1001 - (std::vector<UIView*>)computeViewsToDispose {
1002 std::vector<UIView*> views;
1003 if (
self.viewsToDispose.empty()) {
1007 std::unordered_set<int64_t> viewsToComposite(
self.compositionOrder.begin(),
1008 self.compositionOrder.end());
1009 std::unordered_set<int64_t> viewsToDelayDispose;
1010 for (int64_t viewId :
self.viewsToDispose) {
1011 if (viewsToComposite.count(viewId)) {
1012 viewsToDelayDispose.insert(viewId);
1015 UIView* rootView =
self.platformViews[viewId].root_view;
1016 views.push_back(rootView);
1017 self.currentCompositionParams.erase(viewId);
1018 self.viewsToRecomposite.erase(viewId);
1019 self.platformViews.erase(viewId);
1021 self.viewsToDispose = std::move(viewsToDelayDispose);
1025 - (void)resetFrameState {
1026 self.slices.clear();
1027 self.compositionOrder.clear();
1028 self.visitedPlatformViews.clear();
1031 - (void)pushVisitedPlatformViewId:(int64_t)viewId {
1032 self.visitedPlatformViews.push_back(viewId);
1035 - (void)pushClipRectToVisitedPlatformViews:(const
flutter::DlRect&)clipRect {
1036 for (int64_t
id :
self.visitedPlatformViews) {
1037 flutter::EmbeddedViewParams params =
self.currentCompositionParams[id];
1038 params.PushPlatformViewClipRect(clipRect);
1039 self.currentCompositionParams[id] = params;
1043 - (void)pushClipRRectToVisitedPlatformViews:(const
flutter::DlRoundRect&)clipRRect {
1044 for (int64_t
id :
self.visitedPlatformViews) {
1045 flutter::EmbeddedViewParams params =
self.currentCompositionParams[id];
1046 params.PushPlatformViewClipRRect(clipRRect);
1047 self.currentCompositionParams[id] = params;
1051 - (void)pushClipRSuperellipseToVisitedPlatformViews:(const
flutter::DlRoundSuperellipse&)clipRse {
1052 for (int64_t
id :
self.visitedPlatformViews) {
1053 flutter::EmbeddedViewParams params =
self.currentCompositionParams[id];
1054 params.PushPlatformViewClipRSuperellipse(clipRse);
1055 self.currentCompositionParams[id] = params;
1059 - (void)pushClipPathToVisitedPlatformViews:(const
flutter::DlPath&)clipPath {
1060 for (int64_t
id :
self.visitedPlatformViews) {
1061 flutter::EmbeddedViewParams params =
self.currentCompositionParams[id];
1062 params.PushPlatformViewClipPath(clipPath);
1063 self.currentCompositionParams[id] = params;
1067 - (const
flutter::EmbeddedViewParams&)compositionParamsForView:(int64_t)viewId {
1068 return self.currentCompositionParams.find(viewId)->second;
1071 #pragma mark - Properties
1073 - (
flutter::OverlayLayerPool*)layerPool {
1074 return _layerPool.get();
1077 - (std::unordered_map<int64_t, std::unique_ptr<flutter::EmbedderViewSlice>>&)slices {
1081 - (std::unordered_map<std::string, NSObject<FlutterPlatformViewFactory>*>&)factories {
1084 - (std::unordered_map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>&)
1085 gestureRecognizersBlockingPolicies {
1089 - (std::unordered_map<int64_t, PlatformViewData>&)platformViews {
1093 - (std::unordered_map<int64_t, flutter::EmbeddedViewParams>&)currentCompositionParams {
1097 - (std::unordered_set<int64_t>&)viewsToDispose {
1101 - (std::vector<int64_t>&)compositionOrder {
1105 - (std::vector<int64_t>&)visitedPlatformViews {
1109 - (std::unordered_set<int64_t>&)viewsToRecomposite {
1113 - (std::vector<int64_t>&)previousCompositionOrder {
void(^ FlutterResult)(id _Nullable result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
FlutterPlatformViewGestureRecognizersBlockingPolicy
void applyBlurBackdropFilters:(NSArray< PlatformViewFilter * > *filters)
CGFloat bottomRightRadius
BOOL isRoundedSuperellipse
Storage for Overlay layers across frames.
std::shared_ptr< flutter::OverlayLayer > layer