From 259217c7aa672406ce22360c844407b92cd809aa Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 16 May 2023 09:24:05 -0700 Subject: [PATCH] [ios_platform_view] only recycle maskView when the view is applying mutators (flutter/engine#41573) A mistake was introduced in https://github.com/flutter/engine/pull/39498 where the maskViews are already recycles each frame. Sometimes a PlatformView does not need to be re-composite: (https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm#L398-L401), so the mask view for such PlatformView should not be recycled. This PR changed the `recycleMaskViews` API to allow individual maskviews to be recycled. `ApplyMutator` then only recycle the maskView for that particular PlatformView. The MaskViewPool is also reworked to be simpler. - The pool now contains a single set of mask views, there is no index counter needed. - When a maskView is needed, try to get it from the pool. - If pool is empty, create a new view. - If pool has an available maskview, remove it from the pool. - When a PlatformView starts to `applyMutator`, it removes current the maskView, insert the maskView to the pool. - When the above PlatformView needs to a maskView, it grabs one from the pool. fixes: https://github.com/flutter/flutter/issues/125620 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../framework/Source/FlutterPlatformViews.mm | 20 +- .../Source/FlutterPlatformViewsTest.mm | 82 +++++++- .../Source/FlutterPlatformViews_Internal.h | 21 +- .../Source/FlutterPlatformViews_Internal.mm | 53 +++-- .../Scenarios.xcodeproj/project.pbxproj | 12 ++ .../ios/Scenarios/Scenarios/AppDelegate.m | 5 +- .../ScenariosUITests/GoldenTestManager.m | 3 + .../ScenariosUITests/PlatformViewUITests.m | 54 +++++ ...one SE (3rd generation)_16.2_simulator.png | Bin 0 -> 24014 bytes ...one SE (3rd generation)_16.2_simulator.png | Bin 0 -> 18548 bytes ...one SE (3rd generation)_16.2_simulator.png | Bin 0 -> 35060 bytes .../scenario_app/lib/src/platform_view.dart | 199 +++++++++++++++++- .../scenario_app/lib/src/scenarios.dart | 3 + 13 files changed, 387 insertions(+), 65 deletions(-) create mode 100644 engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png create mode 100644 engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png create mode 100644 engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 51349cb70e..70fdf7936b 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -18,8 +18,6 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" -static const NSUInteger kFlutterClippingMaskViewPoolCapacity = 5; - @implementation UIView (FirstResponder) - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { if (self.isFirstResponder) { @@ -447,6 +445,8 @@ void FlutterPlatformViewsController::ClipViewSetMaskView(UIView* clipView) { clipView.maskView = [mask_view_pool_.get() getMaskViewWithFrame:frame]; } +// This method is only called when the `embedded_view` needs to be re-composited at the current +// frame. See: `CompositeWithParams` for details. void FlutterPlatformViewsController::ApplyMutators(const MutatorsStack& mutators_stack, UIView* embedded_view, const SkRect& bounding_rect) { @@ -461,12 +461,10 @@ void FlutterPlatformViewsController::ApplyMutators(const MutatorsStack& mutators NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease]; FML_DCHECK(!clipView.maskView || [clipView.maskView isKindOfClass:[FlutterClippingMaskView class]]); - if (mask_view_pool_.get() == nil) { - mask_view_pool_.reset([[FlutterClippingMaskViewPool alloc] - initWithCapacity:kFlutterClippingMaskViewPoolCapacity]); + if (clipView.maskView) { + [mask_view_pool_.get() insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)]; + clipView.maskView = nil; } - [mask_view_pool_.get() recycleMaskViews]; - clipView.maskView = nil; CGFloat screenScale = [UIScreen mainScreen].scale; auto iter = mutators_stack.Begin(); while (iter != mutators_stack.End()) { @@ -570,6 +568,14 @@ void FlutterPlatformViewsController::ApplyMutators(const MutatorsStack& mutators embedded_view.layer.transform = flutter::GetCATransform3DFromSkMatrix(transformMatrix); } +// Composite the PlatformView with `view_id`. +// +// Every frame, during the paint traversal of the layer tree, this method is called for all +// the PlatformViews in `views_to_recomposite_`. +// +// Note that `views_to_recomposite_` does not represent all the views in the view hierarchy, +// if a PlatformView does not change its composition parameter from last frame, it is not +// included in the `views_to_recomposite_`. void FlutterPlatformViewsController::CompositeWithParams(int64_t view_id, const EmbeddedViewParams& params) { CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height()); diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 670206331b..6f205b88c5 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -2649,7 +2649,8 @@ fml::RefPtr CreateNewThread(std::string name) { [[[FlutterClippingMaskViewPool alloc] initWithCapacity:2] autorelease]; FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame:CGRectZero]; FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame:CGRectZero]; - [pool recycleMaskViews]; + [pool insertViewToPoolIfNeeded:view1]; + [pool insertViewToPoolIfNeeded:view2]; CGRect newRect = CGRectMake(0, 0, 10, 10); FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame:newRect]; FlutterClippingMaskView* view4 = [pool getMaskViewWithFrame:newRect]; @@ -2727,10 +2728,6 @@ fml::RefPtr CreateNewThread(std::string name) { auto embeddedViewParams1 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack1); - flutter::MutatorsStack stack2; - auto embeddedViewParams2 = std::make_unique( - screenScaleMatrix, SkSize::Make(10, 10), stack2); - flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); flutterPlatformViewsController->CompositeEmbeddedView(1); UIView* childClippingView1 = gMockPlatformView.superview.superview; @@ -2738,6 +2735,10 @@ fml::RefPtr CreateNewThread(std::string name) { XCTAssertNotNil(maskView1); // Composite a new frame. + flutterPlatformViewsController->BeginFrame(SkISize::Make(100, 100)); + flutter::MutatorsStack stack2; + auto embeddedViewParams2 = std::make_unique( + screenScaleMatrix, SkSize::Make(10, 10), stack2); auto embeddedViewParams3 = std::make_unique( screenScaleMatrix, SkSize::Make(10, 10), stack2); flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams3)); @@ -2763,6 +2764,77 @@ fml::RefPtr CreateNewThread(std::string name) { XCTAssertNil(childClippingView1.maskView); } +- (void)testDifferentClipMaskViewIsUsedForEachView { + flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate; + auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest"); + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/thread_task_runner, + /*raster=*/thread_task_runner, + /*ui=*/thread_task_runner, + /*io=*/thread_task_runner); + auto flutterPlatformViewsController = std::make_shared(); + auto platform_view = std::make_unique( + /*delegate=*/mock_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kSoftware, + /*platform_views_controller=*/flutterPlatformViewsController, + /*task_runners=*/runners); + + FlutterPlatformViewsTestMockFlutterPlatformFactory* factory = + [[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease]; + flutterPlatformViewsController->RegisterViewFactory( + factory, @"MockFlutterPlatformView", + FlutterPlatformViewGestureRecognizersBlockingPolicyEager); + FlutterResult result = ^(id result) { + }; + + flutterPlatformViewsController->OnMethodCall( + [FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}], + result); + UIView* view1 = gMockPlatformView; + + // This overwrites `gMockPlatformView` to another view. + flutterPlatformViewsController->OnMethodCall( + [FlutterMethodCall + methodCallWithMethodName:@"create" + arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}], + result); + UIView* view2 = gMockPlatformView; + + XCTAssertNotNil(gMockPlatformView); + UIView* mockFlutterView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)] autorelease]; + flutterPlatformViewsController->SetFlutterView(mockFlutterView); + // Create embedded view params + flutter::MutatorsStack stack1; + // Layer tree always pushes a screen scale factor to the stack + SkMatrix screenScaleMatrix = + SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale); + stack1.PushTransform(screenScaleMatrix); + // Push a clip rect + SkRect rect = SkRect::MakeXYWH(2, 2, 3, 3); + stack1.PushClipRect(rect); + + auto embeddedViewParams1 = std::make_unique( + screenScaleMatrix, SkSize::Make(10, 10), stack1); + + flutter::MutatorsStack stack2; + stack2.PushClipRect(rect); + auto embeddedViewParams2 = std::make_unique( + screenScaleMatrix, SkSize::Make(10, 10), stack2); + + flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1)); + flutterPlatformViewsController->CompositeEmbeddedView(1); + UIView* childClippingView1 = view1.superview.superview; + + flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams2)); + flutterPlatformViewsController->CompositeEmbeddedView(2); + UIView* childClippingView2 = view2.superview.superview; + UIView* maskView1 = childClippingView1.maskView; + UIView* maskView2 = childClippingView2.maskView; + XCTAssertNotEqual(maskView1, maskView2); +} + // Return true if a correct visual effect view is found. It also implies all the validation in this // method passes. // diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 8447d19ca2..55e9d5a8fc 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -56,7 +56,7 @@ // in the pool. If there are none available, a new FlutterClippingMaskView is constructed. If the // capacity is reached, the newly constructed FlutterClippingMaskView is not added to the pool. // -// Call |recycleMaskViews| to mark all the FlutterClippingMaskViews in the pool available. +// Call |insertViewToPoolIfNeeded:| to return a maskView to the pool. @interface FlutterClippingMaskViewPool : NSObject // Initialize the pool with `capacity`. When the `capacity` is reached, a FlutterClippingMaskView is @@ -66,8 +66,8 @@ // Reuse a maskView from the pool, or allocate a new one. - (FlutterClippingMaskView*)getMaskViewWithFrame:(CGRect)frame; -// Mark all the maskViews available. -- (void)recycleMaskViews; +// Insert the `maskView` into the pool. +- (void)insertViewToPoolIfNeeded:(FlutterClippingMaskView*)maskView; @end @@ -291,20 +291,12 @@ class FlutterPlatformViewsController { int CountClips(const MutatorsStack& mutators_stack); void ClipViewSetMaskView(UIView* clipView); + // Applies the mutators in the mutators_stack to the UIView chain that was constructed by // `ReconstructClipViewsChain` // - // Clips are applied to the super view with a CALayer mask. Transforms are applied to the - // current view that's at the head of the chain. For example the following mutators stack [T_1, - // C_2, T_3, T_4, C_5, T_6] where T denotes a transform and C denotes a clip, will result in the - // following UIView tree: - // - // C_2 -> C_5 -> PLATFORM_VIEW - // (PLATFORM_VIEW is a subview of C_5 which is a subview of C_2) - // - // T_1 is applied to C_2, T_3 and T_4 are applied to C_5, and T_6 is applied to PLATFORM_VIEW. - // - // After each clip operation, we update the head to the super view of the current head. + // Clips are applied to the `embedded_view`'s super view(|ChildClippingView|) using a + // |FlutterClippingMaskView|. Transforms are applied to `embedded_view` // // The `bounding_rect` is the final bounding rect of the PlatformView // (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding @@ -312,6 +304,7 @@ class FlutterPlatformViewsController { void ApplyMutators(const MutatorsStack& mutators_stack, UIView* embedded_view, const SkRect& bounding_rect); + void CompositeWithParams(int64_t view_id, const EmbeddedViewParams& params); // Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index 89e1687795..ebcfcad0dd 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm @@ -9,6 +9,7 @@ #import "flutter/shell/platform/darwin/ios/ios_surface.h" static int kMaxPointsInVerb = 4; +static const NSUInteger kFlutterClippingMaskViewPoolCapacity = 5; namespace flutter { @@ -26,7 +27,10 @@ FlutterPlatformViewLayer::~FlutterPlatformViewLayer() = default; FlutterPlatformViewsController::FlutterPlatformViewsController() : layer_pool_(std::make_unique()), - weak_factory_(std::make_unique>(this)){}; + weak_factory_(std::make_unique>(this)) { + mask_view_pool_.reset( + [[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity]); +}; FlutterPlatformViewsController::~FlutterPlatformViewsController() = default; @@ -458,9 +462,10 @@ static BOOL _preparedOnce = NO; // The maximum number of `FlutterClippingMaskView` the pool can contain. // This prevents the pool to grow infinately and limits the maximum memory a pool can use. @property(assign, nonatomic) NSUInteger capacity; -@property(retain, nonatomic) NSMutableArray* pool; -// The index points to the first available FlutterClippingMaskView in the `pool`. -@property(assign, nonatomic) NSUInteger availableIndex; + +// The pool contains the views that are available to use. +// The number of items in the pool must not excceds `capacity`. +@property(retain, nonatomic) NSMutableSet* pool; @end @@ -468,48 +473,42 @@ static BOOL _preparedOnce = NO; - (instancetype)initWithCapacity:(NSInteger)capacity { if (self = [super init]) { - _pool = [[NSMutableArray alloc] initWithCapacity:capacity]; + // Most of cases, there are only one PlatformView in the scene. + // Thus init with the capacity of 1. + _pool = [[NSMutableSet alloc] initWithCapacity:1]; _capacity = capacity; - _availableIndex = 0; } return self; } - (FlutterClippingMaskView*)getMaskViewWithFrame:(CGRect)frame { - FML_DCHECK(self.availableIndex <= self.capacity); + FML_DCHECK(self.pool.count <= self.capacity); FlutterClippingMaskView* maskView; - if (self.availableIndex == self.capacity) { - // The pool is full, alloc a new one. + if (self.pool.count == 0) { + // The pool is empty, alloc a new one. maskView = [[[FlutterClippingMaskView alloc] initWithFrame:frame screenScale:[UIScreen mainScreen].scale] autorelease]; return maskView; } - - if (self.availableIndex >= self.pool.count) { - // The pool doesn't have enough maskViews, alloc a new one and add to the pool. - maskView = - [[[FlutterClippingMaskView alloc] initWithFrame:frame - screenScale:[UIScreen mainScreen].scale] autorelease]; - [self.pool addObject:maskView]; - FML_DCHECK(self.pool.count <= self.capacity); - } else { - // Reuse a maskView from the pool. - maskView = [self.pool objectAtIndex:self.availableIndex]; - maskView.frame = frame; - [maskView reset]; - } - self.availableIndex++; + maskView = [self.pool anyObject]; + maskView.frame = frame; + [maskView reset]; + [self.pool removeObject:maskView]; return maskView; } -- (void)recycleMaskViews { - self.availableIndex = 0; +- (void)insertViewToPoolIfNeeded:(FlutterClippingMaskView*)maskView { + FML_DCHECK(![self.pool containsObject:maskView]); + FML_DCHECK(self.pool.count <= self.capacity); + if (self.pool.count == self.capacity) { + return; + } + [self.pool addObject:maskView]; } - (void)dealloc { [_pool release]; - _pool = nil; [super dealloc]; } diff --git a/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj b/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj index 0fcb3c83f3..4e69202318 100644 --- a/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj +++ b/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj @@ -57,6 +57,9 @@ 684FFF8D29F9C10700281002 /* golden_platform_view_large_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 684FFF7929F9C10600281002 /* golden_platform_view_large_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png */; }; 684FFF8E29F9C10700281002 /* golden_spawn_engine_works_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 684FFF7A29F9C10700281002 /* golden_spawn_engine_works_iPhone SE (3rd generation)_16.2_simulator.png */; }; 684FFF8F29F9C10700281002 /* golden_platform_view_with_other_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 684FFF7B29F9C10700281002 /* golden_platform_view_with_other_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png */; }; + 6860CE252A01B2FF00B68EC5 /* golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6860CE222A01B2FF00B68EC5 /* golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png */; }; + 6860CE262A01B2FF00B68EC5 /* golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6860CE232A01B2FF00B68EC5 /* golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png */; }; + 6860CE272A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6860CE242A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png */; }; 68A5B63423EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */; }; 68D4017D2564859300ECD91A /* ContinuousTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 68D4017C2564859300ECD91A /* ContinuousTexture.m */; }; F26F15B8268B6B5600EC54D3 /* iPadGestureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F26F15B7268B6B5500EC54D3 /* iPadGestureTests.m */; }; @@ -174,6 +177,9 @@ 684FFF7929F9C10600281002 /* golden_platform_view_large_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_large_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = ""; }; 684FFF7A29F9C10700281002 /* golden_spawn_engine_works_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_spawn_engine_works_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = ""; }; 684FFF7B29F9C10700281002 /* golden_platform_view_with_other_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_with_other_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = ""; }; + 6860CE222A01B2FF00B68EC5 /* golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = ""; }; + 6860CE232A01B2FF00B68EC5 /* golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = ""; }; + 6860CE242A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png"; sourceTree = ""; }; 68A5B63323EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformViewGestureRecognizerTests.m; sourceTree = ""; }; 68D4017B2564859300ECD91A /* ContinuousTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContinuousTexture.h; sourceTree = ""; }; 68D4017C2564859300ECD91A /* ContinuousTexture.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContinuousTexture.m; sourceTree = ""; }; @@ -302,6 +308,9 @@ F7B464DC2759D02B00079189 /* Goldens */ = { isa = PBXGroup; children = ( + 6860CE242A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png */, + 6860CE232A01B2FF00B68EC5 /* golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png */, + 6860CE222A01B2FF00B68EC5 /* golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png */, 684FFF7229F9C10500281002 /* golden_bogus_font_text_iPhone SE (3rd generation)_16.2_simulator.png */, 684FFF7029F9C10500281002 /* golden_non_full_screen_flutter_view_platform_view_iPhone SE (3rd generation)_16.2_simulator.png */, 684FFF7729F9C10600281002 /* golden_platform_view_clippath_iPhone SE (3rd generation)_16.2_simulator.png */, @@ -456,7 +465,9 @@ 684FFF7D29F9C10700281002 /* golden_platform_view_cliprect_with_transform_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8829F9C10700281002 /* golden_platform_view_cliprect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8529F9C10700281002 /* golden_platform_view_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, + 6860CE252A01B2FF00B68EC5 /* golden_two_platform_view_clip_rrect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8F29F9C10700281002 /* golden_platform_view_with_other_backdrop_filter_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, + 6860CE262A01B2FF00B68EC5 /* golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8A29F9C10700281002 /* golden_platform_view_clippath_with_transform_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8429F9C10700281002 /* golden_non_full_screen_flutter_view_platform_view_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF7C29F9C10700281002 /* golden_platform_view_cliprrect_with_transform_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, @@ -469,6 +480,7 @@ 684FFF8D29F9C10700281002 /* golden_platform_view_large_cliprrect_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8329F9C10700281002 /* golden_platform_view_transform_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8B29F9C10700281002 /* golden_platform_view_clippath_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, + 6860CE272A01B2FF00B68EC5 /* golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, 684FFF8129F9C10700281002 /* golden_platform_view_large_cliprrect_with_transform_iPhone SE (3rd generation)_16.2_simulator.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m b/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m index 28c84f8e68..4dca96551a 100644 --- a/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m +++ b/engine/src/flutter/testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m @@ -69,7 +69,10 @@ @"--spawn-engine-works" : @"spawn_engine_works", @"--pointer-events" : @"pointer_events", @"--platform-view-scrolling-under-widget" : @"platform_view_scrolling_under_widget", - @"--platform-view-cliprect-after-moved" : @"platform_view_cliprect_after_moved" + @"--platform-view-cliprect-after-moved" : @"platform_view_cliprect_after_moved", + @"--two-platform-view-clip-rect" : @"two_platform_view_clip_rect", + @"--two-platform-view-clip-rrect" : @"two_platform_view_clip_rrect", + @"--two-platform-view-clip-path" : @"two_platform_view_clip_path", }; __block NSString* flutterViewControllerTestName = nil; [launchArgsMap diff --git a/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m b/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m index 6ecb07a7c7..3bcff69684 100644 --- a/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m +++ b/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/GoldenTestManager.m @@ -47,6 +47,9 @@ NSDictionary* launchArgsMap; @"--bogus-font-text" : @"bogus_font_text", @"--spawn-engine-works" : @"spawn_engine_works", @"--platform-view-cliprect-after-moved" : @"platform_view_cliprect_after_moved", + @"--two-platform-view-clip-rect" : @"two_platform_view_clip_rect", + @"--two-platform-view-clip-rrect" : @"two_platform_view_clip_rrect", + @"--two-platform-view-clip-path" : @"two_platform_view_clip_path", }; }); _identifier = launchArgsMap[launchArg]; diff --git a/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m b/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m index 47d49f3c77..cd28f98781 100644 --- a/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m +++ b/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewUITests.m @@ -254,6 +254,60 @@ static const NSInteger kSecondsToWaitForPlatformView = 30; @end +@interface TwoPlatformViewClipRectTests : GoldenPlatformViewTests + +@end + +@implementation TwoPlatformViewClipRectTests + +- (instancetype)initWithInvocation:(NSInvocation*)invocation { + GoldenTestManager* manager = + [[GoldenTestManager alloc] initWithLaunchArg:@"--two-platform-view-clip-rect"]; + return [super initWithManager:manager invocation:invocation]; +} + +- (void)testPlatformView { + [self checkPlatformViewGolden]; +} + +@end + +@interface TwoPlatformViewClipRRectTests : GoldenPlatformViewTests + +@end + +@implementation TwoPlatformViewClipRRectTests + +- (instancetype)initWithInvocation:(NSInvocation*)invocation { + GoldenTestManager* manager = + [[GoldenTestManager alloc] initWithLaunchArg:@"--two-platform-view-clip-rrect"]; + return [super initWithManager:manager invocation:invocation]; +} + +- (void)testPlatformView { + [self checkPlatformViewGolden]; +} + +@end + +@interface TwoPlatformViewClipPathTests : GoldenPlatformViewTests + +@end + +@implementation TwoPlatformViewClipPathTests + +- (instancetype)initWithInvocation:(NSInvocation*)invocation { + GoldenTestManager* manager = + [[GoldenTestManager alloc] initWithLaunchArg:@"--two-platform-view-clip-path"]; + return [super initWithManager:manager invocation:invocation]; +} + +- (void)testPlatformView { + [self checkPlatformViewGolden]; +} + +@end + @interface PlatformViewMutationTransformTests : GoldenPlatformViewTests @end diff --git a/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png b/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_path_iPhone SE (3rd generation)_16.2_simulator.png new file mode 100644 index 0000000000000000000000000000000000000000..71caaac361f030626718202b07cf5fcb82de0428 GIT binary patch literal 24014 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 R=zY*x>YlECF6*2UngAt-4UPZ+ literal 0 HcmV?d00001 diff --git a/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png b/engine/src/flutter/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_view_clip_rect_iPhone SE (3rd generation)_16.2_simulator.png new file mode 100644 index 0000000000000000000000000000000000000000..d90daed50411ab590f9c985790875d7dcaf04215 GIT binary patch literal 18548 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≫&P)FwSuKFHgjVhC%;MkyKc{?yEF11c>NTT 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 literal 0 HcmV?d00001 diff --git a/engine/src/flutter/testing/scenario_app/lib/src/platform_view.dart b/engine/src/flutter/testing/scenario_app/lib/src/platform_view.dart index 75ccd39520..741ed0c854 100644 --- a/engine/src/flutter/testing/scenario_app/lib/src/platform_view.dart +++ b/engine/src/flutter/testing/scenario_app/lib/src/platform_view.dart @@ -112,7 +112,6 @@ class PlatformViewNoOverlayIntersectionScenario extends Scenario } } - /// A platform view that is larger than the display size. /// This is only applicable on Android while using virtual displays. /// Related issue: https://github.com/flutter/flutter/issues/28978. @@ -576,7 +575,7 @@ class PlatformViewClipRectAfterMovedScenario extends Scenario with _BasePlatform ..pushClipRect(const Rect.fromLTRB(100, 100, 400, 400)); addPlatformView( - _numberOfFrames == 10? 10000:id, + _numberOfFrames == 10? 10000: id, dispatcher: view.platformDispatcher, sceneBuilder: builder, ); @@ -639,7 +638,6 @@ class PlatformViewClipRRectScenario extends PlatformViewScenario { } } - /// Platform view with clip rrect. /// The bounding rect of the rrect is the same as PlatformView and only the corner radii clips the PlatformView. class PlatformViewLargeClipRRectScenario extends PlatformViewScenario { @@ -878,6 +876,187 @@ class PlatformViewClipPathWithTransformScenario extends PlatformViewScenario { } } +/// Two platform views, both have clip rects +class TwoPlatformViewClipRect extends Scenario + with _BasePlatformViewScenarioMixin { + /// Creates the PlatformView scenario. + TwoPlatformViewClipRect( + super.view, { + required this.firstId, + required this.secondId, + }); + + /// The platform view identifier to use for the first platform view. + final int firstId; + + /// The platform view identifier to use for the second platform view. + final int secondId; + + @override + void onBeginFrame(Duration duration) { + final SceneBuilder builder = SceneBuilder(); + builder.pushOffset(0, 600); + builder.pushClipRect(const Rect.fromLTRB(100, 100, 400, 400)); + + addPlatformView( + firstId, + dispatcher: view.platformDispatcher, + sceneBuilder: builder, + text: 'platform view 1', + ); + + builder.pop(); + builder.pop(); + + // Use a different rect to differentiate from the 1st clip rect. + builder.pushClipRect(const Rect.fromLTRB(100, 100, 300, 300)); + + addPlatformView( + secondId, + dispatcher: view.platformDispatcher, + sceneBuilder: builder, + text: 'platform view 2', + ); + + builder.pop(); + final Scene scene = builder.build(); + view.render(scene); + scene.dispose(); + } +} + +/// Two platform views, both have clip rrects +class TwoPlatformViewClipRRect extends Scenario + with _BasePlatformViewScenarioMixin { + /// Creates the PlatformView scenario. + TwoPlatformViewClipRRect( + super.view, { + required this.firstId, + required this.secondId, + }); + + /// The platform view identifier to use for the first platform view. + final int firstId; + + /// The platform view identifier to use for the second platform view. + final int secondId; + + @override + void onBeginFrame(Duration duration) { + final SceneBuilder builder = SceneBuilder(); + builder.pushOffset(0, 600); + builder.pushClipRRect( + RRect.fromLTRBAndCorners( + 0, + 0, + 500, + 500, + topLeft: const Radius.circular(15), + topRight: const Radius.circular(50), + bottomLeft: const Radius.circular(50), + ), + ); + + addPlatformView( + firstId, + dispatcher: view.platformDispatcher, + sceneBuilder: builder, + text: 'platform view 1', + ); + + builder.pop(); + builder.pop(); + + // Use a different rrect to differentiate from the 1st clip rrect. + builder.pushClipRRect( + RRect.fromLTRBAndCorners( + 0, + 0, + 500, + 500, + topLeft: const Radius.circular(100), + topRight: const Radius.circular(50), + bottomLeft: const Radius.circular(50), + ), + ); + + addPlatformView( + secondId, + dispatcher: view.platformDispatcher, + sceneBuilder: builder, + text: 'platform view 2', + ); + + builder.pop(); + final Scene scene = builder.build(); + view.render(scene); + scene.dispose(); + } +} + +/// Two platform views, both have clip path +class TwoPlatformViewClipPath extends Scenario + with _BasePlatformViewScenarioMixin { + /// Creates the PlatformView scenario. + TwoPlatformViewClipPath( + super.view, { + required this.firstId, + required this.secondId, + }); + + /// The platform view identifier to use for the first platform view. + final int firstId; + + /// The platform view identifier to use for the second platform view. + final int secondId; + + @override + void onBeginFrame(Duration duration) { + final SceneBuilder builder = SceneBuilder(); + builder.pushOffset(0, 600); + final Path path = Path() + ..moveTo(100, 100) + ..quadraticBezierTo(50, 250, 100, 400) + ..lineTo(350, 400) + ..cubicTo(400, 300, 300, 200, 350, 100) + ..close(); + + builder.pushClipPath(path); + + addPlatformView( + firstId, + dispatcher: view.platformDispatcher, + sceneBuilder: builder, + text: 'platform view 1', + ); + + builder.pop(); + builder.pop(); + + // Use a different path to differentiate from the 1st clip path. + final Path path2 = Path() + ..moveTo(100, 100) + ..quadraticBezierTo(100, 150, 100, 400) + ..lineTo(350, 350) + ..cubicTo(400, 300, 300, 200, 350, 200) + ..close(); + + builder.pushClipPath(path2); + + addPlatformView( + secondId, + dispatcher: view.platformDispatcher, + sceneBuilder: builder, + text: 'platform view 2', + ); + + builder.pop(); + final Scene scene = builder.build(); + view.render(scene); + scene.dispose(); + } +} + /// Platform view with transform. class PlatformViewTransformScenario extends PlatformViewScenario { /// Constructs a platform view with transform scenario. @@ -1044,10 +1223,10 @@ class PlatformViewForOverlappingPlatformViewsScenario extends Scenario /// Creates the PlatformViewForOverlappingPlatformViewsScenario. PlatformViewForOverlappingPlatformViewsScenario( - super.view, { - required this.foregroundId, - required this.backgroundId, - }) { + super.view, { + required this.foregroundId, + required this.backgroundId, + }) { _nextFrame = _firstFrame; } @@ -1151,7 +1330,7 @@ class PlatformViewForOverlappingPlatformViewsScenario extends Scenario view.platformDispatcher.sendPlatformMessage( 'flutter/platform_views', message.buffer.asByteData(), - (ByteData? response) {}, + (ByteData? response) {}, ); } } @@ -1360,7 +1539,7 @@ class PlatformViewScrollingUnderWidget extends Scenario super.view, { required int firstPlatformViewId, required int lastPlatformViewId, - }) : _firstPlatformViewId = firstPlatformViewId, + }) : _firstPlatformViewId = firstPlatformViewId, _lastPlatformViewId = lastPlatformViewId; final int _firstPlatformViewId; @@ -1450,7 +1629,6 @@ void addPlatformView( } final String platformViewKey = '$viewType-$id'; - if (_createdPlatformViews.containsKey(platformViewKey)) { addPlatformViewToSceneBuilder( id, @@ -1473,7 +1651,6 @@ void addPlatformView( const int valueString = 7; const int valueUint8List = 8; const int valueMap = 13; - final Uint8List message = Uint8List.fromList([ valueString, ..._encodeString('create'), diff --git a/engine/src/flutter/testing/scenario_app/lib/src/scenarios.dart b/engine/src/flutter/testing/scenario_app/lib/src/scenarios.dart index ff71e609e0..e18f3a8009 100644 --- a/engine/src/flutter/testing/scenario_app/lib/src/scenarios.dart +++ b/engine/src/flutter/testing/scenario_app/lib/src/scenarios.dart @@ -53,6 +53,9 @@ Map _scenarios = { 'platform_view_gesture_reject_after_touches_ended': (FlutterView view) => PlatformViewForTouchIOSScenario(view, id: _viewId++, accept: false, rejectUntilTouchesEnded: true), 'platform_view_gesture_accept_with_overlapping_platform_views': (FlutterView view) => PlatformViewForOverlappingPlatformViewsScenario(view, foregroundId: _viewId++, backgroundId: _viewId++), 'platform_view_scrolling_under_widget':(FlutterView view) => PlatformViewScrollingUnderWidget(view, firstPlatformViewId: _viewId++, lastPlatformViewId: _viewId+=16), + 'two_platform_view_clip_rect': (FlutterView view) => TwoPlatformViewClipRect(view, firstId: _viewId++, secondId: _viewId++), + 'two_platform_view_clip_rrect': (FlutterView view) => TwoPlatformViewClipRRect(view, firstId: _viewId++, secondId: _viewId++), + 'two_platform_view_clip_path': (FlutterView view) => TwoPlatformViewClipPath(view, firstId: _viewId++, secondId: _viewId++), 'tap_status_bar': (FlutterView view) => TouchesScenario(view), 'initial_route_reply': (FlutterView view) => InitialRouteReply(view), 'platform_view_with_continuous_texture': (FlutterView view) => PlatformViewWithContinuousTexture(view, id: _viewId++),