diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 32a49871ac506..4c4a0ab3f263c 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -540,6 +540,14 @@ void Canvas::SaveLayer(const Paint& paint, const std::shared_ptr& backdrop_filter) { Save(true, paint.blend_mode, backdrop_filter); + // The DisplayList bounds/rtree doesn't account for filters applied to parent + // layers, and so sub-DisplayLists are getting culled as if no filters are + // applied. + // See also: https://github.com/flutter/flutter/issues/139294 + if (paint.image_filter) { + xformation_stack_.back().cull_rect = std::nullopt; + } + auto& new_layer_pass = GetCurrentPass(); new_layer_pass.SetBoundsLimit(bounds); diff --git a/impeller/aiks/canvas_unittests.cc b/impeller/aiks/canvas_unittests.cc index ed83f0500a254..728316cb3c61d 100644 --- a/impeller/aiks/canvas_unittests.cc +++ b/impeller/aiks/canvas_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/testing/testing.h" #include "impeller/aiks/canvas.h" +#include "impeller/aiks/image_filter.h" #include "impeller/geometry/path_builder.h" // TODO(zanderso): https://github.com/flutter/flutter/issues/127701 @@ -336,6 +337,23 @@ TEST(AiksCanvasTest, PathClipDiffAgainstFullyCoveredCullRect) { ASSERT_EQ(canvas.GetCurrentLocalCullingBounds().value(), result_cull); } +TEST(AiksCanvasTest, DisableLocalBoundsRectForFilteredSaveLayers) { + Rect initial_cull = Rect::MakeXYWH(0, 0, 10, 10); + + Canvas canvas(initial_cull); + ASSERT_TRUE(canvas.GetCurrentLocalCullingBounds().has_value()); + + canvas.Save(); + canvas.SaveLayer( + Paint{.image_filter = ImageFilter::MakeBlur( + Sigma(10), Sigma(10), FilterContents::BlurStyle::kNormal, + Entity::TileMode::kDecal)}); + ASSERT_FALSE(canvas.GetCurrentLocalCullingBounds().has_value()); + + canvas.Restore(); + ASSERT_TRUE(canvas.GetCurrentLocalCullingBounds().has_value()); +} + } // namespace testing } // namespace impeller