@@ -2445,6 +2445,125 @@ - (void)testHasFirstResponderInViewHierarchySubtree_descendantViewBecomesFirstRe
2445
2445
XCTAssertFalse (view.flt_hasFirstResponderInViewHierarchySubtree );
2446
2446
}
2447
2447
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
+
2448
2567
// Return true if a correct visual effect view is found. It also implies all the validation in this
2449
2568
// method passes.
2450
2569
//
0 commit comments