@@ -2644,6 +2644,125 @@ - (void)testHasFirstResponderInViewHierarchySubtree_descendantViewBecomesFirstRe
2644
2644
XCTAssertFalse (view.flt_hasFirstResponderInViewHierarchySubtree );
2645
2645
}
2646
2646
2647
+ - (void )testFlutterClippingMaskViewPoolReuseViewsAfterRecycle {
2648
+ FlutterClippingMaskViewPool* pool =
2649
+ [[[FlutterClippingMaskViewPool alloc ] initWithCapacity: 2 ] autorelease ];
2650
+ FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame: CGRectZero ];
2651
+ FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame: CGRectZero ];
2652
+ [pool recycleMaskViews ];
2653
+ CGRect newRect = CGRectMake (0 , 0 , 10 , 10 );
2654
+ FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame: newRect];
2655
+ FlutterClippingMaskView* view4 = [pool getMaskViewWithFrame: newRect];
2656
+ XCTAssertEqual (view1, view3);
2657
+ XCTAssertEqual (view2, view4);
2658
+ XCTAssertTrue (CGRectEqualToRect (view3.frame , newRect));
2659
+ XCTAssertTrue (CGRectEqualToRect (view4.frame , newRect));
2660
+ }
2661
+
2662
+ - (void )testFlutterClippingMaskViewPoolAllocsNewMaskViewsAfterReachingCapacity {
2663
+ FlutterClippingMaskViewPool* pool =
2664
+ [[[FlutterClippingMaskViewPool alloc ] initWithCapacity: 2 ] autorelease ];
2665
+ FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame: CGRectZero ];
2666
+ FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame: CGRectZero ];
2667
+ FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame: CGRectZero ];
2668
+ XCTAssertNotEqual (view1, view3);
2669
+ XCTAssertNotEqual (view2, view3);
2670
+ }
2671
+
2672
+ - (void )testMaskViewsReleasedWhenPoolIsReleased {
2673
+ UIView* retainedView;
2674
+ @autoreleasepool {
2675
+ FlutterClippingMaskViewPool* pool =
2676
+ [[[FlutterClippingMaskViewPool alloc ] initWithCapacity: 2 ] autorelease ];
2677
+ FlutterClippingMaskView* view = [pool getMaskViewWithFrame: CGRectZero ];
2678
+ retainedView = [view retain ];
2679
+ XCTAssertGreaterThan (retainedView.retainCount , 1u );
2680
+ }
2681
+ // The only retain left is our manual retain called inside the autorelease pool, meaning the
2682
+ // maskViews are dealloc'd.
2683
+ XCTAssertEqual (retainedView.retainCount , 1u );
2684
+ }
2685
+
2686
+ - (void )testClipMaskViewIsReused {
2687
+ flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2688
+ auto thread_task_runner = CreateNewThread (" FlutterPlatformViewsTest" );
2689
+ flutter::TaskRunners runners (/* label=*/ self.name .UTF8String ,
2690
+ /* platform=*/ thread_task_runner,
2691
+ /* raster=*/ thread_task_runner,
2692
+ /* ui=*/ thread_task_runner,
2693
+ /* io=*/ thread_task_runner);
2694
+ auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2695
+ auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2696
+ /* delegate=*/ mock_delegate,
2697
+ /* rendering_api=*/ flutter::IOSRenderingAPI::kSoftware ,
2698
+ /* platform_views_controller=*/ flutterPlatformViewsController,
2699
+ /* task_runners=*/ runners);
2700
+
2701
+ FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
2702
+ [[FlutterPlatformViewsTestMockFlutterPlatformFactory new ] autorelease ];
2703
+ flutterPlatformViewsController->RegisterViewFactory (
2704
+ factory, @" MockFlutterPlatformView" ,
2705
+ FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
2706
+ FlutterResult result = ^(id result) {
2707
+ };
2708
+ flutterPlatformViewsController->OnMethodCall (
2709
+ [FlutterMethodCall
2710
+ methodCallWithMethodName: @" create"
2711
+ arguments: @{@" id" : @1 , @" viewType" : @" MockFlutterPlatformView" }],
2712
+ result);
2713
+
2714
+ XCTAssertNotNil (gMockPlatformView );
2715
+ UIView* mockFlutterView = [[[UIView alloc ] initWithFrame: CGRectMake (0 , 0 , 10 , 10 )] autorelease ];
2716
+ flutterPlatformViewsController->SetFlutterView (mockFlutterView);
2717
+ // Create embedded view params
2718
+ flutter::MutatorsStack stack1;
2719
+ // Layer tree always pushes a screen scale factor to the stack
2720
+ SkMatrix screenScaleMatrix =
2721
+ SkMatrix::Scale ([UIScreen mainScreen ].scale , [UIScreen mainScreen ].scale );
2722
+ stack1.PushTransform (screenScaleMatrix);
2723
+ // Push a clip rect
2724
+ SkRect rect = SkRect::MakeXYWH (2 , 2 , 3 , 3 );
2725
+ stack1.PushClipRect (rect);
2726
+
2727
+ auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
2728
+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack1);
2729
+
2730
+ flutter::MutatorsStack stack2;
2731
+ auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
2732
+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack2);
2733
+
2734
+ flutterPlatformViewsController->PrerollCompositeEmbeddedView (1 , std::move (embeddedViewParams1));
2735
+ flutterPlatformViewsController->CompositeEmbeddedView (1 );
2736
+ UIView* childClippingView1 = gMockPlatformView .superview .superview ;
2737
+ UIView* maskView1 = childClippingView1.maskView ;
2738
+ XCTAssertNotNil (maskView1);
2739
+
2740
+ // Composite a new frame.
2741
+ auto embeddedViewParams3 = std::make_unique<flutter::EmbeddedViewParams>(
2742
+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack2);
2743
+ flutterPlatformViewsController->PrerollCompositeEmbeddedView (1 , std::move (embeddedViewParams3));
2744
+ flutterPlatformViewsController->CompositeEmbeddedView (1 );
2745
+ childClippingView1 = gMockPlatformView .superview .superview ;
2746
+
2747
+ // This overrides gMockPlatformView to point to the newly created platform view.
2748
+ flutterPlatformViewsController->OnMethodCall (
2749
+ [FlutterMethodCall
2750
+ methodCallWithMethodName: @" create"
2751
+ arguments: @{@" id" : @2 , @" viewType" : @" MockFlutterPlatformView" }],
2752
+ result);
2753
+
2754
+ auto embeddedViewParams4 = std::make_unique<flutter::EmbeddedViewParams>(
2755
+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack1);
2756
+ flutterPlatformViewsController->PrerollCompositeEmbeddedView (2 , std::move (embeddedViewParams4));
2757
+ flutterPlatformViewsController->CompositeEmbeddedView (2 );
2758
+ UIView* childClippingView2 = gMockPlatformView .superview .superview ;
2759
+
2760
+ UIView* maskView2 = childClippingView2.maskView ;
2761
+ XCTAssertEqual (maskView1, maskView2);
2762
+ XCTAssertNotNil (childClippingView2.maskView );
2763
+ XCTAssertNil (childClippingView1.maskView );
2764
+ }
2765
+
2647
2766
// Return true if a correct visual effect view is found. It also implies all the validation in this
2648
2767
// method passes.
2649
2768
//
0 commit comments