Apply superellipse clipping to iOS platform views using an approximated round rect (#172033)

Fixes https://github.com/flutter/flutter/issues/171966
This commit is contained in:
Jason Simmons 2025-07-14 11:08:00 -07:00 committed by GitHub
parent c845f06094
commit d18e28d855
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 81 additions and 1 deletions

View File

@ -538,7 +538,7 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) {
break;
}
[self clipViewSetMaskView:clipView];
[(FlutterClippingMaskView*)clipView.maskView clipRRect:(*iter)->GetRRect()
[(FlutterClippingMaskView*)clipView.maskView clipRRect:(*iter)->GetRSEApproximation()
matrix:transformMatrix];
break;
}

View File

@ -4619,4 +4619,84 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
XCTAssertEqual(*submit_info->buffer_damage, SkIRect::MakeWH(400, 600));
}
- (void)testClipSuperellipse {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
[flutterPlatformViewsController
registerViewFactory:factory
withId:@"MockFlutterPlatformView"
gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
arguments:@{
@"id" : @2,
@"viewType" : @"MockFlutterPlatformView"
}]
result:result];
XCTAssertNotNil(gMockPlatformView);
UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
flutterPlatformViewsController.flutterView = flutterView;
// Create embedded view params
flutter::MutatorsStack stack;
// Layer tree always pushes a screen scale factor to the stack
flutter::DlScalar screenScale = [UIScreen mainScreen].scale;
flutter::DlMatrix screenScaleMatrix = flutter::DlMatrix::MakeScale({screenScale, screenScale, 1});
stack.PushTransform(screenScaleMatrix);
// Push a clip superellipse
flutter::DlRect rect = flutter::DlRect::MakeXYWH(3, 3, 5, 5);
stack.PushClipRSE(flutter::DlRoundSuperellipse::MakeOval(rect));
auto embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(
flutter::ToSkMatrix(screenScaleMatrix), SkSize::Make(10, 10), stack);
[flutterPlatformViewsController prerollCompositeEmbeddedView:2
withParams:std::move(embeddedViewParams)];
[flutterPlatformViewsController
compositeView:2
withParams:[flutterPlatformViewsController compositionParamsForView:2]];
gMockPlatformView.backgroundColor = UIColor.redColor;
XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
[flutterView addSubview:childClippingView];
[flutterView setNeedsLayout];
[flutterView layoutIfNeeded];
CGPoint corners[] = {CGPointMake(rect.GetLeft(), rect.GetTop()),
CGPointMake(rect.GetRight(), rect.GetTop()),
CGPointMake(rect.GetLeft(), rect.GetBottom()),
CGPointMake(rect.GetRight(), rect.GetBottom())};
for (auto point : corners) {
int alpha = [self alphaOfPoint:point onView:flutterView];
XCTAssertNotEqual(alpha, 255);
}
CGPoint center =
CGPointMake(rect.GetLeft() + rect.GetWidth() / 2, rect.GetTop() + rect.GetHeight() / 2);
int alpha = [self alphaOfPoint:center onView:flutterView];
XCTAssertEqual(alpha, 255);
}
@end