@@ -2445,6 +2445,125 @@ - (void)testHasFirstResponderInViewHierarchySubtree_descendantViewBecomesFirstRe
24452445 XCTAssertFalse (view.flt_hasFirstResponderInViewHierarchySubtree );
24462446}
24472447
2448+ - (void )testFlutterClippingMaskViewPoolReuseViewsAfterRecycle {
2449+ FlutterClippingMaskViewPool* pool =
2450+ [[[FlutterClippingMaskViewPool alloc ] initWithCapacity: 2 ] autorelease ];
2451+ FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame: CGRectZero];
2452+ FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame: CGRectZero];
2453+ [pool recycleMaskViews ];
2454+ CGRect newRect = CGRectMake (0 , 0 , 10 , 10 );
2455+ FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame: newRect];
2456+ FlutterClippingMaskView* view4 = [pool getMaskViewWithFrame: newRect];
2457+ XCTAssertEqual (view1, view3);
2458+ XCTAssertEqual (view2, view4);
2459+ XCTAssertTrue (CGRectEqualToRect (view3.frame , newRect));
2460+ XCTAssertTrue (CGRectEqualToRect (view4.frame , newRect));
2461+ }
2462+
2463+ - (void )testFlutterClippingMaskViewPoolAllocsNewMaskViewsAfterReachingCapacity {
2464+ FlutterClippingMaskViewPool* pool =
2465+ [[[FlutterClippingMaskViewPool alloc ] initWithCapacity: 2 ] autorelease ];
2466+ FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame: CGRectZero];
2467+ FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame: CGRectZero];
2468+ FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame: CGRectZero];
2469+ XCTAssertNotEqual (view1, view3);
2470+ XCTAssertNotEqual (view2, view3);
2471+ }
2472+
2473+ - (void )testMaskViewsReleasedWhenPoolIsReleased {
2474+ UIView* retainedView;
2475+ @autoreleasepool {
2476+ FlutterClippingMaskViewPool* pool =
2477+ [[[FlutterClippingMaskViewPool alloc ] initWithCapacity: 2 ] autorelease ];
2478+ FlutterClippingMaskView* view = [pool getMaskViewWithFrame: CGRectZero];
2479+ retainedView = [view retain ];
2480+ XCTAssertGreaterThan (retainedView.retainCount , 1u );
2481+ }
2482+ // The only retain left is our manual retain called inside the autorelease pool, meaning the
2483+ // maskViews are dealloc'd.
2484+ XCTAssertEqual (retainedView.retainCount , 1u );
2485+ }
2486+
2487+ - (void )testClipMaskViewIsReused {
2488+ flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2489+ auto thread_task_runner = CreateNewThread (" FlutterPlatformViewsTest" );
2490+ flutter::TaskRunners runners (/* label=*/ self.name .UTF8String ,
2491+ /* platform=*/ thread_task_runner,
2492+ /* raster=*/ thread_task_runner,
2493+ /* ui=*/ thread_task_runner,
2494+ /* io=*/ thread_task_runner);
2495+ auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2496+ auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2497+ /* delegate=*/ mock_delegate,
2498+ /* rendering_api=*/ flutter::IOSRenderingAPI::kSoftware ,
2499+ /* platform_views_controller=*/ flutterPlatformViewsController,
2500+ /* task_runners=*/ runners);
2501+
2502+ FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
2503+ [[FlutterPlatformViewsTestMockFlutterPlatformFactory new ] autorelease ];
2504+ flutterPlatformViewsController->RegisterViewFactory (
2505+ factory, @" MockFlutterPlatformView" ,
2506+ FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
2507+ FlutterResult result = ^(id result) {
2508+ };
2509+ flutterPlatformViewsController->OnMethodCall (
2510+ [FlutterMethodCall
2511+ methodCallWithMethodName: @" create"
2512+ arguments: @{@" id" : @1 , @" viewType" : @" MockFlutterPlatformView" }],
2513+ result);
2514+
2515+ XCTAssertNotNil (gMockPlatformView );
2516+ UIView* mockFlutterView = [[[UIView alloc ] initWithFrame: CGRectMake (0 , 0 , 10 , 10 )] autorelease ];
2517+ flutterPlatformViewsController->SetFlutterView (mockFlutterView);
2518+ // Create embedded view params
2519+ flutter::MutatorsStack stack1;
2520+ // Layer tree always pushes a screen scale factor to the stack
2521+ SkMatrix screenScaleMatrix =
2522+ SkMatrix::Scale ([UIScreen mainScreen ].scale , [UIScreen mainScreen ].scale );
2523+ stack1.PushTransform (screenScaleMatrix);
2524+ // Push a clip rect
2525+ SkRect rect = SkRect::MakeXYWH (2 , 2 , 3 , 3 );
2526+ stack1.PushClipRect (rect);
2527+
2528+ auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
2529+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack1);
2530+
2531+ flutter::MutatorsStack stack2;
2532+ auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
2533+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack2);
2534+
2535+ flutterPlatformViewsController->PrerollCompositeEmbeddedView (1 , std::move (embeddedViewParams1));
2536+ flutterPlatformViewsController->CompositeEmbeddedView (1 );
2537+ UIView* childClippingView1 = gMockPlatformView .superview .superview ;
2538+ UIView* maskView1 = childClippingView1.maskView ;
2539+ XCTAssertNotNil (maskView1);
2540+
2541+ // Composite a new frame.
2542+ auto embeddedViewParams3 = std::make_unique<flutter::EmbeddedViewParams>(
2543+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack2);
2544+ flutterPlatformViewsController->PrerollCompositeEmbeddedView (1 , std::move (embeddedViewParams3));
2545+ flutterPlatformViewsController->CompositeEmbeddedView (1 );
2546+ childClippingView1 = gMockPlatformView .superview .superview ;
2547+
2548+ // This overrides gMockPlatformView to point to the newly created platform view.
2549+ flutterPlatformViewsController->OnMethodCall (
2550+ [FlutterMethodCall
2551+ methodCallWithMethodName: @" create"
2552+ arguments: @{@" id" : @2 , @" viewType" : @" MockFlutterPlatformView" }],
2553+ result);
2554+
2555+ auto embeddedViewParams4 = std::make_unique<flutter::EmbeddedViewParams>(
2556+ screenScaleMatrix, SkSize::Make (10 , 10 ), stack1);
2557+ flutterPlatformViewsController->PrerollCompositeEmbeddedView (2 , std::move (embeddedViewParams4));
2558+ flutterPlatformViewsController->CompositeEmbeddedView (2 );
2559+ UIView* childClippingView2 = gMockPlatformView .superview .superview ;
2560+
2561+ UIView* maskView2 = childClippingView2.maskView ;
2562+ XCTAssertEqual (maskView1, maskView2);
2563+ XCTAssertNotNil (childClippingView2.maskView );
2564+ XCTAssertNil (childClippingView1.maskView );
2565+ }
2566+
24482567// Return true if a correct visual effect view is found. It also implies all the validation in this
24492568// method passes.
24502569//
0 commit comments