diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index f3388bab4641b..2982cb40824b9 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -100,10 +100,8 @@ void MutatorsStack::PushOpacity(const int& alpha) { }; void MutatorsStack::PushBackdropFilter( - const std::shared_ptr& filter, - const SkRect& filter_rect) { - std::shared_ptr element = - std::make_shared(filter, filter_rect); + const std::shared_ptr& filter) { + std::shared_ptr element = std::make_shared(filter); vector_.push_back(element); }; diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 84ad68f41faa6..4627c7d880a06 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -32,33 +32,6 @@ enum MutatorType { kBackdropFilter }; -// Represents an image filter mutation. -// -// Should be used for image_filter_layer and backdrop_filter_layer. -// TODO(cyanglaz): Refactor this into a ImageFilterMutator class. -// https://github.com/flutter/flutter/issues/108470 -class ImageFilterMutation { - public: - ImageFilterMutation(std::shared_ptr filter, - const SkRect& filter_rect) - : filter_(filter), filter_rect_(filter_rect) {} - - const DlImageFilter& GetFilter() const { return *filter_; } - const SkRect& GetFilterRect() const { return filter_rect_; } - - bool operator==(const ImageFilterMutation& other) const { - return *filter_ == *other.filter_ && filter_rect_ == other.filter_rect_; - } - - bool operator!=(const ImageFilterMutation& other) const { - return !operator==(other); - } - - private: - std::shared_ptr filter_; - const SkRect filter_rect_; -}; - // Stores mutation information like clipping or kTransform. // // The `type` indicates the type of the mutation: kClipRect, kTransform and etc. @@ -86,7 +59,7 @@ class Mutator { alpha_ = other.alpha_; break; case kBackdropFilter: - filter_mutation_ = other.filter_mutation_; + filter_ = other.filter_; break; default: break; @@ -100,20 +73,15 @@ class Mutator { explicit Mutator(const SkMatrix& matrix) : type_(kTransform), matrix_(matrix) {} explicit Mutator(const int& alpha) : type_(kOpacity), alpha_(alpha) {} - explicit Mutator(std::shared_ptr filter, - const SkRect& filter_rect) - : type_(kBackdropFilter), - filter_mutation_( - std::make_shared(filter, filter_rect)) {} + explicit Mutator(std::shared_ptr filter) + : type_(kBackdropFilter), filter_(filter) {} const MutatorType& GetType() const { return type_; } const SkRect& GetRect() const { return rect_; } const SkRRect& GetRRect() const { return rrect_; } const SkPath& GetPath() const { return *path_; } const SkMatrix& GetMatrix() const { return matrix_; } - const ImageFilterMutation& GetFilterMutation() const { - return *filter_mutation_; - } + const DlImageFilter& GetFilter() const { return *filter_; } const int& GetAlpha() const { return alpha_; } float GetAlphaFloat() const { return (alpha_ / 255.0); } @@ -133,7 +101,7 @@ class Mutator { case kOpacity: return alpha_ == other.alpha_; case kBackdropFilter: - return *filter_mutation_ == *other.filter_mutation_; + return *filter_ == *other.filter_; } return false; @@ -164,7 +132,8 @@ class Mutator { int alpha_; }; - std::shared_ptr filter_mutation_; + std::shared_ptr filter_; + }; // Mutator // A stack of mutators that can be applied to an embedded platform view. @@ -185,8 +154,7 @@ class MutatorsStack { void PushClipPath(const SkPath& path); void PushTransform(const SkMatrix& matrix); void PushOpacity(const int& alpha); - void PushBackdropFilter(const std::shared_ptr& filter, - const SkRect& filter_rect); + void PushBackdropFilter(const std::shared_ptr& filter); // Removes the `Mutator` on the top of the stack // and destroys it. @@ -284,9 +252,8 @@ class EmbeddedViewParams { const SkRect& finalBoundingRect() const { return final_bounding_rect_; } // Pushes the stored DlImageFilter object to the mutators stack. - void PushImageFilter(std::shared_ptr filter, - const SkRect& filter_rect) { - mutators_stack_.PushBackdropFilter(filter, filter_rect); + void PushImageFilter(std::shared_ptr filter) { + mutators_stack_.PushBackdropFilter(filter); } // Whether the embedder should construct DisplayList objects to hold the @@ -490,8 +457,7 @@ class ExternalViewEmbedder { // See also: |PushVisitedPlatformView| for pushing platform view ids to the // visited platform views list. virtual void PushFilterToVisitedPlatformViews( - std::shared_ptr filter, - const SkRect& filter_rect) {} + std::shared_ptr filter) {} private: bool used_this_frame_ = false; diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 6fceb859c380b..07a596662d730 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -43,8 +43,7 @@ void BackdropFilterLayer::Preroll(PrerollContext* context) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, true, bool(filter_)); if (context->view_embedder != nullptr) { - context->view_embedder->PushFilterToVisitedPlatformViews( - filter_, context->cull_rect); + context->view_embedder->PushFilterToVisitedPlatformViews(filter_); } SkRect child_paint_bounds = SkRect::MakeEmpty(); PrerollChildren(context, &child_paint_bounds); diff --git a/flow/mutators_stack_unittests.cc b/flow/mutators_stack_unittests.cc index 42ce6363d47ff..54b6b516e4a72 100644 --- a/flow/mutators_stack_unittests.cc +++ b/flow/mutators_stack_unittests.cc @@ -94,19 +94,14 @@ TEST(MutatorsStack, PushBackdropFilter) { const int num_of_mutators = 10; for (int i = 0; i < num_of_mutators; i++) { auto filter = std::make_shared(i, 5, DlTileMode::kClamp); - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(i, i, i, i)); + stack.PushBackdropFilter(filter); } auto iter = stack.Begin(); int i = 0; while (iter != stack.End()) { ASSERT_EQ(iter->get()->GetType(), MutatorType::kBackdropFilter); - ASSERT_EQ(iter->get()->GetFilterMutation().GetFilter().asBlur()->sigma_x(), - i); - ASSERT_EQ(iter->get()->GetFilterMutation().GetFilterRect().x(), i); - ASSERT_EQ(iter->get()->GetFilterMutation().GetFilterRect().x(), i); - ASSERT_EQ(iter->get()->GetFilterMutation().GetFilterRect().width(), i); - ASSERT_EQ(iter->get()->GetFilterMutation().GetFilterRect().height(), i); + ASSERT_EQ(iter->get()->GetFilter().asBlur()->sigma_x(), i); ++iter; ++i; } @@ -169,7 +164,7 @@ TEST(MutatorsStack, Equality) { int alpha = 240; stack.PushOpacity(alpha); auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - stack.PushBackdropFilter(filter, SkRect::MakeEmpty()); + stack.PushBackdropFilter(filter); MutatorsStack stack_other; SkMatrix matrix_other = SkMatrix::Scale(1, 1); @@ -184,7 +179,7 @@ TEST(MutatorsStack, Equality) { stack_other.PushOpacity(other_alpha); auto other_filter = std::make_shared(5, 5, DlTileMode::kClamp); - stack_other.PushBackdropFilter(other_filter, SkRect::MakeEmpty()); + stack_other.PushBackdropFilter(other_filter); ASSERT_TRUE(stack == stack_other); } @@ -216,9 +211,9 @@ TEST(Mutator, Initialization) { ASSERT_TRUE(mutator5.GetType() == MutatorType::kOpacity); auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - Mutator mutator6 = Mutator(filter, SkRect::MakeEmpty()); + Mutator mutator6 = Mutator(filter); ASSERT_TRUE(mutator6.GetType() == MutatorType::kBackdropFilter); - ASSERT_TRUE(mutator6.GetFilterMutation().GetFilter() == *filter); + ASSERT_TRUE(mutator6.GetFilter() == *filter); } TEST(Mutator, CopyConstructor) { @@ -249,7 +244,7 @@ TEST(Mutator, CopyConstructor) { ASSERT_TRUE(mutator5 == copy5); auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - Mutator mutator6 = Mutator(filter, SkRect::MakeEmpty()); + Mutator mutator6 = Mutator(filter); Mutator copy6 = Mutator(mutator6); ASSERT_TRUE(mutator6 == copy6); } @@ -281,10 +276,9 @@ TEST(Mutator, Equality) { Mutator other_mutator5 = Mutator(alpha); ASSERT_TRUE(mutator5 == other_mutator5); - auto filter1 = std::make_shared(5, 5, DlTileMode::kClamp); - auto filter2 = std::make_shared(5, 5, DlTileMode::kClamp); - Mutator mutator6 = Mutator(filter1, SkRect::MakeEmpty()); - Mutator other_mutator6 = Mutator(filter2, SkRect::MakeEmpty()); + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + Mutator mutator6 = Mutator(filter); + Mutator other_mutator6 = Mutator(filter); ASSERT_TRUE(mutator6 == other_mutator6); } @@ -305,8 +299,8 @@ TEST(Mutator, UnEquality) { auto filter = std::make_shared(5, 5, DlTileMode::kClamp); auto filter2 = std::make_shared(10, 10, DlTileMode::kClamp); - Mutator mutator3 = Mutator(filter, SkRect::MakeEmpty()); - Mutator other_mutator3 = Mutator(filter2, SkRect::MakeEmpty()); + Mutator mutator3 = Mutator(filter); + Mutator other_mutator3 = Mutator(filter2); ASSERT_TRUE(mutator3 != other_mutator3); } diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 7d660b724b2f2..789ebc22d72b8 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -89,11 +89,10 @@ void ShellTestExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::PushFilterToVisitedPlatformViews( - std::shared_ptr filter, - const SkRect& filter_rect) { + std::shared_ptr filter) { for (int64_t id : visited_platform_views_) { EmbeddedViewParams params = current_composition_params_[id]; - params.PushImageFilter(filter, filter_rect); + params.PushImageFilter(filter); current_composition_params_[id] = params; mutators_stacks_[id] = params.mutatorsStack(); } diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index 5bff1c97ebdc9..583a09182e5fc 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -76,8 +76,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| void PushFilterToVisitedPlatformViews( - std::shared_ptr filter, - const SkRect& filter_rect) override; + std::shared_ptr filter) override; // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 0c93386c12c64..799aa814a841a 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -845,7 +845,7 @@ TEST_F(ShellTest, PushBackdropFilterToVisitedPlatformViews) { auto filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp); auto mutator = *external_view_embedder->GetStack(50).Begin(); ASSERT_EQ(mutator->GetType(), MutatorType::kBackdropFilter); - ASSERT_EQ(mutator->GetFilterMutation().GetFilter(), filter); + ASSERT_EQ(mutator->GetFilter(), filter); DestroyShell(std::move(shell)); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 8442e1eadd9cb..00d8324d11b55 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -321,11 +321,10 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews( - std::shared_ptr filter, - const SkRect& filter_rect) { + std::shared_ptr filter) { for (int64_t id : visited_platform_views_) { EmbeddedViewParams params = current_composition_params_[id]; - params.PushImageFilter(filter, filter_rect); + params.PushImageFilter(filter); current_composition_params_[id] = params; } } @@ -426,7 +425,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { CGRectGetWidth(flutter_view.bounds), CGRectGetHeight(flutter_view.bounds))] autorelease]; - NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease]; + NSMutableArray* blurRadii = [[[NSMutableArray alloc] init] autorelease]; auto iter = mutators_stack.Begin(); while (iter != mutators_stack.End()) { @@ -449,35 +448,13 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha; break; case kBackdropFilter: { - // Only support DlBlurImageFilter for BackdropFilter. - if (!(*iter)->GetFilterMutation().GetFilter().asBlur() || !canApplyBlurBackdrop) { - break; - } - CGRect filterRect = - flutter::GetCGRectFromSkRect((*iter)->GetFilterMutation().GetFilterRect()); - // `filterRect` reprents the rect that should be filtered inside the `flutter_view_`. - // The `PlatformViewFilter` needs the frame inside the `clipView` that needs to be - // filtered. - if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) { - break; - } - CGRect intersection = CGRectIntersection(filterRect, clipView.frame); - CGRect frameInClipView = [flutter_view_.get() convertRect:intersection toView:clipView]; - // sigma_x is arbitrarily chosen as the radius value because Quartz sets - // sigma_x and sigma_y equal to each other. DlBlurImageFilter's Tile Mode - // is not supported in Quartz's gaussianBlur CAFilter, so it is not used - // to blur the PlatformView. - CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x(); - UIVisualEffectView* visualEffectView = [[[UIVisualEffectView alloc] - initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]] autorelease]; - PlatformViewFilter* filter = - [[[PlatformViewFilter alloc] initWithFrame:frameInClipView - blurRadius:blurRadius - visualEffectView:visualEffectView] autorelease]; - if (!filter) { - canApplyBlurBackdrop = NO; - } else { - [blurFilters addObject:filter]; + // We only support DlBlurImageFilter for BackdropFilter. + if ((*iter)->GetFilter().asBlur() && canApplyBlurBackdrop) { + // sigma_x is arbitrarily chosen as the radius value because Quartz sets + // sigma_x and sigma_y equal to each other. DlBlurImageFilter's Tile Mode + // is not supported in Quartz's gaussianBlur CAFilter, so it is not used + // to blur the PlatformView. + [blurRadii addObject:@((*iter)->GetFilter().asBlur()->sigma_x())]; } break; } @@ -486,16 +463,15 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } if (canApplyBlurBackdrop) { - [clipView applyBlurBackdropFilters:blurFilters]; + canApplyBlurBackdrop = [clipView applyBlurBackdropFilters:blurRadii]; } // Reverse the offset of the clipView. // The clipView's frame includes the final translate of the final transform matrix. - // Thus, this translate needs to be reversed so the platform view can layout at the correct - // offset. + // So we need to revese this translate so the platform view can layout at the correct offset. // - // Note that the transforms are not applied to the clipping paths because clipping paths happen on - // the mask view, whose origin is always (0,0) to the flutter_view. + // Note that we don't apply this transform matrix the clippings because clippings happen on the + // mask view, whose origin is always (0,0) to the flutter_view. CATransform3D reverseTranslate = CATransform3DMakeTranslation(-clipView.frame.origin.x, -clipView.frame.origin.y, 0); embedded_view.layer.transform = CATransform3DConcat(finalTransform, reverseTranslate); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 9e678e5121bd7..b73373760c106 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -283,7 +283,7 @@ - (void)testApplyBackdropFilter { stack.PushTransform(screenScaleMatrix); // Push a backdrop filter auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack.PushBackdropFilter(filter); auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); @@ -297,90 +297,15 @@ - (void)testApplyBackdropFilter { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - // childClippingView has visual effect view with the correct configurations. - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:5]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 1u); -} - -- (void)testApplyBackdropFilterWithCorrectFrame { - 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" : @2, @"viewType" : @"MockFlutterPlatformView"}], - result); - - XCTAssertNotNil(gMockPlatformView); - - UIView* mockFlutterView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)] autorelease]; - flutterPlatformViewsController->SetFlutterView(mockFlutterView); - // Create embedded view params - flutter::MutatorsStack stack; - // Layer tree always pushes a screen scale factor to the stack - SkMatrix screenScaleMatrix = - SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale); - stack.PushTransform(screenScaleMatrix); - // Push a backdrop filter - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 8, 8)); + // childClippingView has the CAFilter, no additional filters were added + XCTAssertEqual(1, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); - auto embeddedViewParams = - std::make_unique(screenScaleMatrix, SkSize::Make(5, 10), stack); - - flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); - flutterPlatformViewsController->CompositeEmbeddedView(2); - XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); - ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; - [mockFlutterView addSubview:childClippingView]; - - [mockFlutterView setNeedsLayout]; - [mockFlutterView layoutIfNeeded]; - - // childClippingView has visual effect view with the correct configurations. - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 5, 8) - inputRadius:5]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 1u); + // sigmaX is chosen for input radius, regardless of sigmaY + NSObject* gaussianFilter = [childClippingView.layer.filters firstObject]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } - (void)testApplyMultipleBackdropFilters { @@ -424,7 +349,7 @@ - (void)testApplyMultipleBackdropFilters { // Push backdrop filters for (int i = 0; i < 50; i++) { auto filter = std::make_shared(i, 2, flutter::DlTileMode::kClamp); - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack.PushBackdropFilter(filter); } auto embeddedViewParams = @@ -439,19 +364,17 @@ - (void)testApplyMultipleBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 50u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)numberOfExpectedVisualEffectView]) { - numberOfExpectedVisualEffectView++; - } + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(50, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // All filters have sigma X radius + for (int i = 0; i < 50; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(i), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, (NSUInteger)numberOfExpectedVisualEffectView); } - (void)testAddBackdropFilters { @@ -494,7 +417,7 @@ - (void)testAddBackdropFilters { stack.PushTransform(screenScaleMatrix); // Push a backdrop filter auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack.PushBackdropFilter(filter); auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); @@ -508,19 +431,10 @@ - (void)testAddBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)5]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 1u); + // childClippingView has the CAFilter, no additional filters were added + XCTAssertEqual(1, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); // // Simulate adding 1 backdrop filter (create a new mutators stack) @@ -530,7 +444,7 @@ - (void)testAddBackdropFilters { stack2.PushTransform(screenScaleMatrix); // Push backdrop filters for (int i = 0; i < 2; i++) { - stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -541,20 +455,17 @@ - (void)testAddBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 2u); + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(2, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)5]) { - numberOfExpectedVisualEffectView++; - } + // All filters have sigma X radius + for (int i = 0; i < 2; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, 2u); } - (void)testRemoveBackdropFilters { @@ -598,7 +509,7 @@ - (void)testRemoveBackdropFilters { // Push backdrop filters auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); for (int i = 0; i < 5; i++) { - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack.PushBackdropFilter(filter); } auto embeddedViewParams = @@ -620,7 +531,7 @@ - (void)testRemoveBackdropFilters { stack2.PushTransform(screenScaleMatrix); // Push backdrop filters for (int i = 0; i < 4; i++) { - stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -631,19 +542,18 @@ - (void)testRemoveBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)5]) { - numberOfExpectedVisualEffectView++; - } + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(4, (int)[childClippingView.layer.filters count]); + + // All filters have sigma X radius + for (int i = 0; i < 4; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, 4u); + + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); // Simulate removing all backdrop filters (replace the mutators stack) // Update embedded view params, delete except screenScaleMatrix @@ -660,13 +570,10 @@ - (void)testRemoveBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if ([subview isKindOfClass:[UIVisualEffectView class]]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 0u); + // childClippingView has no CAFilters because no backdrop filters were added + XCTAssertEqual(0, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); } - (void)testEditBackdropFilters { @@ -710,7 +617,7 @@ - (void)testEditBackdropFilters { // Push backdrop filters auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); for (int i = 0; i < 5; i++) { - stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack.PushBackdropFilter(filter); } auto embeddedViewParams = @@ -736,11 +643,11 @@ - (void)testEditBackdropFilters { auto filter2 = std::make_shared(2, 5, flutter::DlTileMode::kClamp); - stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter2); continue; } - stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -751,23 +658,21 @@ - (void)testEditBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u); - CGFloat expectInputRadius = 5; - if (numberOfExpectedVisualEffectView == 3) { - expectInputRadius = 2; - } - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)expectInputRadius]) { - numberOfExpectedVisualEffectView++; + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(5, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The edited backdrop filter has the new radius value + for (int i = 0; i < 5; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + if (i == 3) { + XCTAssertEqualObjects(@(2), [gaussianFilter valueForKey:@"inputRadius"]); + } else { + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } } - XCTAssertEqual(numberOfExpectedVisualEffectView, 5u); // Simulate editing 1 backdrop filter in the beginning of the stack (replace the mutators stack) // Update embedded view params, delete except screenScaleMatrix @@ -779,11 +684,11 @@ - (void)testEditBackdropFilters { if (i == 0) { auto filter2 = std::make_shared(2, 5, flutter::DlTileMode::kClamp); - stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter2); continue; } - stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -794,23 +699,21 @@ - (void)testEditBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u); - CGFloat expectInputRadius = 5; - if (numberOfExpectedVisualEffectView == 0) { - expectInputRadius = 2; - } - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)expectInputRadius]) { - numberOfExpectedVisualEffectView++; + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(5, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The edited backdrop filter has the new radius value + for (int i = 0; i < 5; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + if (i == 0) { + XCTAssertEqualObjects(@(2), [gaussianFilter valueForKey:@"inputRadius"]); + } else { + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } } - XCTAssertEqual(numberOfExpectedVisualEffectView, 5u); // Simulate editing 1 backdrop filter in the end of the stack (replace the mutators stack) // Update embedded view params, delete except screenScaleMatrix @@ -822,11 +725,11 @@ - (void)testEditBackdropFilters { if (i == 4) { auto filter2 = std::make_shared(2, 5, flutter::DlTileMode::kClamp); - stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter2); continue; } - stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -837,23 +740,21 @@ - (void)testEditBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u); - CGFloat expectInputRadius = 5; - if (numberOfExpectedVisualEffectView == 4) { - expectInputRadius = 2; - } - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)expectInputRadius]) { - numberOfExpectedVisualEffectView++; + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(5, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The edited backdrop filter has the new radius value + for (int i = 0; i < 5; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + if (i == 4) { + XCTAssertEqualObjects(@(2), [gaussianFilter valueForKey:@"inputRadius"]); + } else { + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } } - XCTAssertEqual(numberOfExpectedVisualEffectView, 5u); // Simulate editing all backdrop filters in the stack (replace the mutators stack) // Update embedded view params, delete except screenScaleMatrix @@ -864,7 +765,7 @@ - (void)testEditBackdropFilters { for (int i = 0; i < 5; i++) { auto filter2 = std::make_shared(i, 2, flutter::DlTileMode::kClamp); - stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(filter2); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -875,19 +776,18 @@ - (void)testEditBackdropFilters { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)numberOfExpectedVisualEffectView]) { - numberOfExpectedVisualEffectView++; - } + // childClippingView has CAFilters for the multiple backdrop filters + XCTAssertEqual(5, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The edited backdrop filter has the new radius value + for (int i = 0; i < 5; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + + XCTAssertEqualObjects(@(i), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, 5u); } - (void)testApplyBackdropFilterNotDlBlurImageFilter { @@ -930,7 +830,7 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { stack.PushTransform(screenScaleMatrix); // Push a dilate backdrop filter auto dilateFilter = std::make_shared(5, 2); - stack.PushBackdropFilter(dilateFilter, SkRect::MakeEmpty()); + stack.PushBackdropFilter(dilateFilter); auto embeddedViewParams = std::make_unique(screenScaleMatrix, SkSize::Make(10, 10), stack); @@ -939,19 +839,15 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { flutterPlatformViewsController->CompositeEmbeddedView(2); XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; - [mockFlutterView addSubview:childClippingView]; [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if ([subview isKindOfClass:[UIVisualEffectView class]]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 0u); + // No filters were added + XCTAssertEqual(0, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); // Simulate adding a non-DlBlurImageFilter in the middle of the stack (create a new mutators // stack) Create embedded view params @@ -963,11 +859,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { for (int i = 0; i < 5; i++) { if (i == 2) { - stack2.PushBackdropFilter(dilateFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(dilateFilter); continue; } - stack2.PushBackdropFilter(blurFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(blurFilter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -978,19 +874,17 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)5]) { - numberOfExpectedVisualEffectView++; - } + // Filters were only added for DlBlurImageFilters + XCTAssertEqual(4, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The added filters are all gaussianBlur filters + for (int i = 0; i < 4; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, 4u); // Simulate adding a non-DlBlurImageFilter to the beginning of the stack (replace the mutators // stack) Update embedded view params, delete except screenScaleMatrix @@ -1000,11 +894,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { // Push backdrop filters and dilate filter for (int i = 0; i < 5; i++) { if (i == 0) { - stack2.PushBackdropFilter(dilateFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(dilateFilter); continue; } - stack2.PushBackdropFilter(blurFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(blurFilter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -1015,19 +909,17 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)5]) { - numberOfExpectedVisualEffectView++; - } + // Filters were only added for DlBlurImageFilters + XCTAssertEqual(4, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The added filters are all gaussianBlur filters + for (int i = 0; i < 4; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, 4u); // Simulate adding a non-DlBlurImageFilter to the end of the stack (replace the mutators stack) // Update embedded view params, delete except screenScaleMatrix @@ -1037,11 +929,11 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { // Push backdrop filters and dilate filter for (int i = 0; i < 5; i++) { if (i == 4) { - stack2.PushBackdropFilter(dilateFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(dilateFilter); continue; } - stack2.PushBackdropFilter(blurFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(blurFilter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -1052,19 +944,17 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:(CGFloat)5]) { - numberOfExpectedVisualEffectView++; - } + // Filters were only added for DlBlurImageFilters + XCTAssertEqual(4, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // The added filters are all gaussianBlur filters + for (int i = 0; i < 4; i++) { + NSObject* gaussianFilter = childClippingView.layer.filters[i]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); } - XCTAssertEqual(numberOfExpectedVisualEffectView, 4u); // Simulate adding only non-DlBlurImageFilter to the stack (replace the mutators stack) // Update embedded view params, delete except screenScaleMatrix @@ -1073,7 +963,7 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { } // Push dilate filters for (int i = 0; i < 5; i++) { - stack2.PushBackdropFilter(dilateFilter, SkRect::MakeXYWH(0, 0, 10, 10)); + stack2.PushBackdropFilter(dilateFilter); } embeddedViewParams = std::make_unique(screenScaleMatrix, @@ -1084,45 +974,38 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if ([subview isKindOfClass:[UIVisualEffectView class]]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 0u); + // No filters were added + XCTAssertEqual(0, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); } -- (void)testApplyBackdropFilterCorrectAPI { - [PlatformViewFilter resetPreparation]; - // The gaussianBlur filter is extracted from UIVisualEffectView. - // Each test requires a new PlatformViewFilter +- (void)testApplyBackdropFilterAPIChanged { + NSArray* blurRadii = @[ @(1), @(5), @(10) ]; + + // The gaussianBlur filter is extracted once for each childClippingView. + // Each test requires a new childClippingView // Valid UIVisualEffectView API - UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] + ChildClippingView* childClippingView1 = [[ChildClippingView alloc] init]; + childClippingView1.blurEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - PlatformViewFilter* platformViewFilter = - [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) - blurRadius:5 - visualEffectView:visualEffectView]; - XCTAssertNotNil(platformViewFilter); -} + XCTAssertTrue([childClippingView1 applyBlurBackdropFilters:blurRadii]); -- (void)testApplyBackdropFilterAPIChangedInvalidUIVisualEffectView { - [PlatformViewFilter resetPreparation]; - UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] init]; - PlatformViewFilter* platformViewFilter = - [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) - blurRadius:5 - visualEffectView:visualEffectView]; - XCTAssertNil(platformViewFilter); -} + // Invalid UIVisualEffectView initialization + ChildClippingView* childClippingView2 = [[ChildClippingView alloc] init]; + childClippingView2.blurEffectView = [[UIVisualEffectView alloc] init]; + XCTAssertFalse([childClippingView2 applyBlurBackdropFilters:blurRadii]); + + // Invalid UIView + ChildClippingView* childClippingView3 = [[ChildClippingView alloc] init]; + childClippingView3.blurEffectView = [[UIView alloc] init]; + XCTAssertFalse([childClippingView3 applyBlurBackdropFilters:blurRadii]); -- (void)testApplyBackdropFilterAPIChangedNoGaussianBlurFilter { - [PlatformViewFilter resetPreparation]; - UIVisualEffectView* editedUIVisualEffectView = [[UIVisualEffectView alloc] + // Invalid UIVisualEffectView API for "name" + UIVisualEffectView* editedUIVisualEffectView1 = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - NSArray* subviews = editedUIVisualEffectView.subviews; - for (UIView* view in subviews) { + NSArray* subviews1 = editedUIVisualEffectView1.subviews; + for (UIView* view in subviews1) { if ([view isKindOfClass:NSClassFromString(@"_UIVisualEffectBackdropView")]) { for (CIFilter* filter in view.layer.filters) { if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"]) { @@ -1133,19 +1016,16 @@ - (void)testApplyBackdropFilterAPIChangedNoGaussianBlurFilter { break; } } - PlatformViewFilter* platformViewFilter = - [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) - blurRadius:5 - visualEffectView:editedUIVisualEffectView]; - XCTAssertNil(platformViewFilter); -} -- (void)testApplyBackdropFilterAPIChangedInvalidInputRadius { - [PlatformViewFilter resetPreparation]; - UIVisualEffectView* editedUIVisualEffectView = [[UIVisualEffectView alloc] + ChildClippingView* childClippingView4 = [[ChildClippingView alloc] init]; + childClippingView4.blurEffectView = editedUIVisualEffectView1; + XCTAssertFalse([childClippingView4 applyBlurBackdropFilters:blurRadii]); + + // Invalid UIVisualEffectView API for "inputRadius" + UIVisualEffectView* editedUIVisualEffectView2 = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - NSArray* subviews = editedUIVisualEffectView.subviews; - for (UIView* view in subviews) { + NSArray* subviews2 = editedUIVisualEffectView2.subviews; + for (UIView* view in subviews2) { if ([view isKindOfClass:NSClassFromString(@"_UIVisualEffectBackdropView")]) { for (CIFilter* filter in view.layer.filters) { if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"]) { @@ -1157,28 +1037,9 @@ - (void)testApplyBackdropFilterAPIChangedInvalidInputRadius { } } - PlatformViewFilter* platformViewFilter = - [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) - blurRadius:5 - visualEffectView:editedUIVisualEffectView]; - XCTAssertNil(platformViewFilter); -} - -- (void)testBackdropFilterVisualEffectSubviewBackgroundColor { - UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] - initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - PlatformViewFilter* platformViewFilter = - [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) - blurRadius:5 - visualEffectView:visualEffectView]; - CGColorRef visualEffectSubviewBackgroundColor; - for (UIView* view in [platformViewFilter backdropFilterView].subviews) { - if ([view isKindOfClass:NSClassFromString(@"_UIVisualEffectSubview")]) { - visualEffectSubviewBackgroundColor = view.layer.backgroundColor; - } - } - XCTAssertTrue( - CGColorEqualToColor(visualEffectSubviewBackgroundColor, UIColor.clearColor.CGColor)); + ChildClippingView* childClippingView5 = [[ChildClippingView alloc] init]; + childClippingView5.blurEffectView = editedUIVisualEffectView2; + XCTAssertFalse([childClippingView5 applyBlurBackdropFilters:blurRadii]); } - (void)testCompositePlatformView { @@ -1281,8 +1142,7 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); flutterPlatformViewsController->PushVisitedPlatformView(2); auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); - flutterPlatformViewsController->PushFilterToVisitedPlatformViews(filter, - SkRect::MakeXYWH(0, 0, 10, 10)); + flutterPlatformViewsController->PushFilterToVisitedPlatformViews(filter); flutterPlatformViewsController->CompositeEmbeddedView(2); XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]); ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview; @@ -1291,20 +1151,15 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - // childClippingView has visual effect view with the correct configurations. - NSUInteger numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u); - if ([self validateOneVisualEffectView:subview - expectedFrame:CGRectMake(0, 0, 10, 10) - inputRadius:5]) { - numberOfExpectedVisualEffectView++; - } - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 1u); + // childClippingView has the CAFilter, no additional filters were added + XCTAssertEqual(1, (int)[childClippingView.layer.filters count]); + // No new views were added + XCTAssertEqual(0, (int)[gMockPlatformView.subviews count]); + + // sigmaX is chosen for input radius, regardless of sigmaY + NSObject* gaussianFilter = [childClippingView.layer.filters firstObject]; + XCTAssertEqualObjects(@"gaussianBlur", [gaussianFilter valueForKey:@"name"]); + XCTAssertEqualObjects(@(5), [gaussianFilter valueForKey:@"inputRadius"]); // New frame, with no filter pushed. auto embeddedViewParams2 = @@ -1317,14 +1172,8 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { [mockFlutterView setNeedsLayout]; [mockFlutterView layoutIfNeeded]; - numberOfExpectedVisualEffectView = 0; - for (UIView* subview in childClippingView.subviews) { - if (![subview isKindOfClass:[UIVisualEffectView class]]) { - continue; - } - numberOfExpectedVisualEffectView++; - } - XCTAssertEqual(numberOfExpectedVisualEffectView, 0u); + // No filter in this frame. + XCTAssertEqual(0, (int)[childClippingView.layer.filters count]); } - (void)testChildClippingViewShouldBeTheBoundingRectOfPlatformView { @@ -2234,31 +2083,4 @@ - (void)testHasFirstResponderInViewHierarchySubtree_descendantViewBecomesFirstRe XCTAssertFalse(view.flt_hasFirstResponderInViewHierarchySubtree); } -// Return true if a correct visual effect view is found. It also implies all the validation in this -// method passes. -// -// There are two fail states for this method. 1. One of the XCTAssert method failed; or 2. No -// correct visual effect view found. -- (BOOL)validateOneVisualEffectView:(UIView*)visualEffectView - expectedFrame:(CGRect)frame - inputRadius:(CGFloat)inputRadius { - XCTAssertTrue(CGRectEqualToRect(visualEffectView.frame, frame)); - for (UIView* view in visualEffectView.subviews) { - if (![view isKindOfClass:NSClassFromString(@"_UIVisualEffectBackdropView")]) { - continue; - } - XCTAssertEqual(view.layer.filters.count, 1u); - NSObject* filter = view.layer.filters.firstObject; - - XCTAssertEqualObjects([filter valueForKey:@"name"], @"gaussianBlur"); - - NSObject* inputRadiusInFilter = [filter valueForKey:@"inputRadius"]; - XCTAssertTrue([inputRadiusInFilter isKindOfClass:[NSNumber class]] && - flutter::BlurRadiusEqualToBlurRadius(((NSNumber*)inputRadiusInFilter).floatValue, - inputRadius)); - return YES; - } - return NO; -} - @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 06180a9d04c78..542f39b736f4f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -45,54 +45,18 @@ @end -// An object represents a blur filter. -// -// This object produces a `backdropFilterView`. -// To blur a View, add `backdropFilterView` as a subView of the View. -@interface PlatformViewFilter : NSObject - -// Determines the rect of the blur effect in the coordinate system of `backdropFilterView`'s -// parentView. -@property(assign, nonatomic, readonly) CGRect frame; - -// Determines the blur intensity. -// -// It is set as the value of `inputRadius` of the `gaussianFilter` that is internally used. -@property(assign, nonatomic, readonly) CGFloat blurRadius; - -// This is the view to use to blur the PlatformView. -// -// It is a modified version of UIKit's `UIVisualEffectView`. -// The inputRadius can be customized and it doesn't add any color saturation to the blurred view. -@property(nonatomic, retain, readonly) UIVisualEffectView* backdropFilterView; - -// For testing only. -+ (void)resetPreparation; - -- (instancetype)init NS_UNAVAILABLE; - -// Initialize the filter object. -// -// The `frame` determines the rect of the blur effect in the coordinate system of -// `backdropFilterView`'s parentView. The `blurRadius` determines the blur intensity. It is set as -// the value of `inputRadius` of the `gaussianFilter` that is internally used. The -// `UIVisualEffectView` is the view that is used to add the blur effects. It is modified to become -// `backdropFilterView`, which better supports the need of Flutter. -// -// Note: if the implementation of UIVisualEffectView changes in a way that affects the -// implementation in `PlatformViewFilter`, this method will return nil. -- (instancetype)initWithFrame:(CGRect)frame - blurRadius:(CGFloat)blurRadius - visualEffectView:(UIVisualEffectView*)visualEffectView NS_DESIGNATED_INITIALIZER; - -@end - -// The parent view handles clipping to its subViews. +// The parent view handles clipping to its subviews. @interface ChildClippingView : UIView -// Applies blur backdrop filters to the ChildClippingView with blur values from -// filters. -- (void)applyBlurBackdropFilters:(NSMutableArray*)filters; +// Applies blur backdrop filters to the ChildClippingView with blur radius values from +// blurRadii. Returns NO if Apple's API has changed and blurred backdrop filters cannot +// be applied, otherwise returns YES. +- (BOOL)applyBlurBackdropFilters:(NSArray*)blurRadii; + +// The UIView used to extract the gaussianBlur filter. This must be a UIVisualEffectView +// initalized with UIBlurEffect to extract the correct filter. Made a public property +// for custom unit tests. +@property(nonatomic, retain) UIView* blurEffectView; @end @@ -105,9 +69,6 @@ CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix); // The position of the `layer` should be unchanged after resetting the anchor. void ResetAnchor(CALayer* layer); -CGRect GetCGRectFromSkRect(const SkRect& clipSkRect); -BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2); - class IOSContextGL; class IOSSurface; @@ -236,8 +197,7 @@ class FlutterPlatformViewsController { long FindFirstResponderPlatformViewId(); // Pushes backdrop filter mutation to the mutator stack of each visited platform view. - void PushFilterToVisitedPlatformViews(std::shared_ptr filter, - const SkRect& filter_rect); + void PushFilterToVisitedPlatformViews(std::shared_ptr filter); // Pushes the view id of a visted platform view to the list of visied platform views. void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index 9f46bf854e75d..e3c3389080a7d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm @@ -55,165 +55,124 @@ void ResetAnchor(CALayer* layer) { layer.position = CGPointZero; } -CGRect GetCGRectFromSkRect(const SkRect& clipSkRect) { - return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft, - clipSkRect.fBottom - clipSkRect.fTop); -} +} // namespace flutter -BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2) { - const CGFloat epsilon = 0.01; - return radius1 - radius2 < epsilon; +@implementation ChildClippingView { + // A gaussianFilter from UIVisualEffectView that can be copied for new backdrop filters. + NSObject* _gaussianFilter; } -} // namespace flutter +// Lazy initializes blurEffectView as the expected UIVisualEffectView. The backdropFilter blur +// requires this UIVisualEffectView initialization. The lazy initalization is only used to allow +// custom unit tests. +- (UIView*)blurEffectView { + if (!_blurEffectView) { + // blurEffectView is only needed to extract its gaussianBlur filter. It is released after + // searching its subviews and extracting the filter. + _blurEffectView = [[[UIVisualEffectView alloc] + initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]] retain]; + } + return _blurEffectView; +} -@implementation PlatformViewFilter - -static NSObject* _gaussianBlurFilter = nil; -// The index of "_UIVisualEffectBackdropView" in UIVisualEffectView's subViews. -static NSInteger _indexOfBackdropView = -1; -// The index of "_UIVisualEffectSubview" in UIVisualEffectView's subViews. -static NSInteger _indexOfVisualEffectSubview = -1; -static BOOL _preparedOnce = NO; - -- (instancetype)initWithFrame:(CGRect)frame - blurRadius:(CGFloat)blurRadius - visualEffectView:(UIVisualEffectView*)visualEffectView { - if (self = [super init]) { - _frame = frame; - _blurRadius = blurRadius; - [PlatformViewFilter prepareOnce:visualEffectView]; - if (![PlatformViewFilter isUIVisualEffectViewImplementationValid]) { - FML_DLOG(ERROR) << "Apple's API for UIVisualEffectView changed. Update the implementation to " - "access the gaussianBlur CAFilter."; - [self release]; - return nil; +// The ChildClippingView's frame is the bounding rect of the platform view. we only want touches to +// be hit tested and consumed by this view if they are inside the embedded platform view which could +// be smaller the embedded platform view is rotated. +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { + for (UIView* view in self.subviews) { + if ([view pointInside:[self convertPoint:point toView:view] withEvent:event]) { + return YES; } - NSObject* gaussianBlurFilter = [[_gaussianBlurFilter copy] autorelease]; - FML_DCHECK(gaussianBlurFilter); - UIView* backdropView = visualEffectView.subviews[_indexOfBackdropView]; - [gaussianBlurFilter setValue:@(_blurRadius) forKey:@"inputRadius"]; - backdropView.layer.filters = @[ gaussianBlurFilter ]; - - UIView* visualEffectSubview = visualEffectView.subviews[_indexOfVisualEffectSubview]; - visualEffectSubview.layer.backgroundColor = UIColor.clearColor.CGColor; - - _backdropFilterView = [visualEffectView retain]; - _backdropFilterView.frame = _frame; } - return self; + return NO; } -+ (void)resetPreparation { - _preparedOnce = NO; - [_gaussianBlurFilter release]; - _gaussianBlurFilter = nil; - _indexOfBackdropView = -1; - _indexOfVisualEffectSubview = -1; -} +// Creates and initializes a UIVisualEffectView with a UIBlurEffect. Extracts and returns its +// gaussianFilter. Returns nil if Apple's API has changed and the filter cannot be extracted. +- (NSObject*)extractGaussianFilter { + NSObject* gaussianFilter = nil; -+ (void)prepareOnce:(UIVisualEffectView*)visualEffectView { - if (_preparedOnce) { - return; - } - for (NSUInteger i = 0; i < visualEffectView.subviews.count; i++) { - UIView* view = visualEffectView.subviews[i]; + for (UIView* view in self.blurEffectView.subviews) { if ([view isKindOfClass:NSClassFromString(@"_UIVisualEffectBackdropView")]) { - _indexOfBackdropView = i; - for (NSObject* filter in view.layer.filters) { - if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"] && - [[filter valueForKey:@"inputRadius"] isKindOfClass:[NSNumber class]]) { - _gaussianBlurFilter = [filter retain]; + for (CIFilter* filter in view.layer.filters) { + if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"]) { + if ([[filter valueForKey:@"inputRadius"] isKindOfClass:[NSNumber class]]) { + gaussianFilter = filter; + } + // No need to look at other CIFilters. If the API structure has not changed, the + // gaussianBlur filter was succesfully saved. Otherwise, still exit the loop because the + // filter cannot be extracted. break; } } - } else if ([view isKindOfClass:NSClassFromString(@"_UIVisualEffectSubview")]) { - _indexOfVisualEffectSubview = i; + // No need to look at other UIViews. If the API structure has not changed, the gaussianBlur + // filter was succesfully saved. Otherwise, still exit the loop because the filter cannot + // be extracted. + break; } } - _preparedOnce = YES; -} -+ (BOOL)isUIVisualEffectViewImplementationValid { - return _indexOfBackdropView > -1 && _indexOfVisualEffectSubview > -1 && _gaussianBlurFilter; + return gaussianFilter; } -- (void)dealloc { - [_backdropFilterView release]; - _backdropFilterView = nil; - - [super dealloc]; -} - -@end +- (BOOL)applyBlurBackdropFilters:(NSArray*)blurRadii { + // The outer if-statement checks for the first time this method is called and _gaussianFilter is + // not initialized. The inner if-statement checks if extracting the gaussianBlur was successful. + // If it was not successful, this method will not be called again. Thus the if-statements check + // for different conditions. + if (!_gaussianFilter) { + _gaussianFilter = [self extractGaussianFilter]; -@interface ChildClippingView () - -@property(retain, nonatomic) NSMutableArray* filters; - -@end - -@implementation ChildClippingView - -// The ChildClippingView's frame is the bounding rect of the platform view. we only want touches to -// be hit tested and consumed by this view if they are inside the embedded platform view which could -// be smaller the embedded platform view is rotated. -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { - for (UIView* view in self.subviews) { - if ([view pointInside:[self convertPoint:point toView:view] withEvent:event]) { - return YES; + if (!_gaussianFilter) { + FML_DLOG(ERROR) << "Apple's API for UIVisualEffectView changed. Update the implementation to " + "access the gaussianBlur CAFilter."; + return NO; } } - return NO; -} -- (void)applyBlurBackdropFilters:(NSMutableArray*)filters { - BOOL needUpdateFilterViews = NO; - if (self.filters.count != filters.count) { - needUpdateFilterViews = YES; + BOOL newRadiusValues = NO; + + if ([blurRadii count] != [self.layer.filters count]) { + newRadiusValues = YES; } else { - for (NSUInteger i = 0; i < filters.count; i++) { - if (!CGRectEqualToRect(self.filters[i].frame, filters[i].frame) || - !flutter::BlurRadiusEqualToBlurRadius(self.filters[i].blurRadius, - filters[i].blurRadius)) { - needUpdateFilterViews = YES; + for (NSUInteger i = 0; i < [blurRadii count]; i++) { + if ([self.layer.filters[i] valueForKey:@"inputRadius"] != blurRadii[i]) { + newRadiusValues = YES; + break; } } } - if (needUpdateFilterViews) { - // Clear the old filter views. - for (PlatformViewFilter* filter in self.filters) { - [[filter backdropFilterView] removeFromSuperview]; - } - // Update to the new filters. - self.filters = [filters retain]; - // Add new filter views. - for (PlatformViewFilter* filter in self.filters) { - UIView* backdropFilterView = [filter backdropFilterView]; - [self addSubview:backdropFilterView]; + + if (newRadiusValues) { + NSMutableArray* newGaussianFilters = [[[NSMutableArray alloc] init] autorelease]; + + for (NSUInteger i = 0; i < [blurRadii count]; i++) { + NSObject* newGaussianFilter = [[_gaussianFilter copy] autorelease]; + [newGaussianFilter setValue:blurRadii[i] forKey:@"inputRadius"]; + [newGaussianFilters addObject:newGaussianFilter]; } + + self.layer.filters = newGaussianFilters; } + + return YES; } - (void)dealloc { - [_filters release]; - _filters = nil; + [_blurEffectView release]; + _blurEffectView = nil; + [_gaussianFilter release]; + _gaussianFilter = nil; [super dealloc]; } -- (NSMutableArray*)filters { - if (!_filters) { - _filters = [[[NSMutableArray alloc] init] retain]; - } - return _filters; -} - @end @interface FlutterClippingMaskView () - (fml::CFRef)getTransformedPath:(CGPathRef)path matrix:(CATransform3D)matrix; +- (CGRect)getCGRectFromSkRect:(const SkRect&)clipSkRect; @end @@ -253,7 +212,7 @@ - (void)drawRect:(CGRect)rect { } - (void)clipRect:(const SkRect&)clipSkRect matrix:(const CATransform3D&)matrix { - CGRect clipRect = flutter::GetCGRectFromSkRect(clipSkRect); + CGRect clipRect = [self getCGRectFromSkRect:clipSkRect]; CGPathRef path = CGPathCreateWithRect(clipRect, nil); paths_.push_back([self getTransformedPath:path matrix:matrix]); } @@ -270,7 +229,7 @@ - (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const CATransform3D&)matri } case SkRRect::kOval_Type: case SkRRect::kSimple_Type: { - CGRect clipRect = flutter::GetCGRectFromSkRect(clipSkRRect.rect()); + CGRect clipRect = [self getCGRectFromSkRect:clipSkRRect.rect()]; pathRef = CGPathCreateWithRoundedRect(clipRect, clipSkRRect.getSimpleRadii().x(), clipSkRRect.getSimpleRadii().y(), nil); break; @@ -337,7 +296,7 @@ - (void)clipPath:(const SkPath&)path matrix:(const CATransform3D&)matrix { SkPath::Iter iter(path, true); SkPoint pts[kMaxPointsInVerb]; SkPath::Verb verb = iter.next(pts); - SkPoint last_pt_from_last_verb = SkPoint::Make(0, 0); + SkPoint last_pt_from_last_verb; while (verb != SkPath::kDone_Verb) { if (verb == SkPath::kLine_Verb || verb == SkPath::kQuad_Verb || verb == SkPath::kConic_Verb || verb == SkPath::kCubic_Verb) { @@ -394,4 +353,9 @@ - (void)clipPath:(const SkPath&)path matrix:(const CATransform3D&)matrix { return fml::CFRef(transformedPath); } +- (CGRect)getCGRectFromSkRect:(const SkRect&)clipSkRect { + return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft, + clipSkRect.fBottom - clipSkRect.fTop); +} + @end diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 8779f936db838..03cec910bae39 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -69,8 +69,7 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| void PushFilterToVisitedPlatformViews( - std::shared_ptr filter, - const SkRect& filter_rect) override; + std::shared_ptr filter) override; // |ExternalViewEmbedder| void PushVisitedPlatformView(int64_t view_id) override; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index 3222bf2a096c3..76995be2c56ad 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -100,9 +100,8 @@ // |ExternalViewEmbedder| void IOSExternalViewEmbedder::PushFilterToVisitedPlatformViews( - std::shared_ptr filter, - const SkRect& filter_rect) { - platform_views_controller_->PushFilterToVisitedPlatformViews(filter, filter_rect); + std::shared_ptr filter) { + platform_views_controller_->PushFilterToVisitedPlatformViews(filter); } // |ExternalViewEmbedder| diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png index 8fbee0e9eac2c..307864c09a863 100644 Binary files a/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png and b/testing/scenario_app/ios/Scenarios/ScenariosUITests/golden_two_platform_views_with_other_backdrop_filter_iPhone 8_13.0_simulator.png differ