@@ -2644,6 +2644,125 @@ - (void)testHasFirstResponderInViewHierarchySubtree_descendantViewBecomesFirstRe
26442644 XCTAssertFalse (view.flt_hasFirstResponderInViewHierarchySubtree );
26452645}
26462646
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+
26472766// Return true if a correct visual effect view is found. It also implies all the validation in this
26482767// method passes.
26492768//
0 commit comments