Handle nested display list clips in Impeller dispatcher (#43442) (#43469)
CP issue: https://github.com/flutter/flutter/issues/130149
Fixes https://github.com/flutter/flutter/issues/130084
If a display list is drawn into another display list and the child display list establishes a small clip, subsequent drawing operations are discarded when really they should not be.
The test is expected to render both a blue and a red square; before the fix it renders only the blue square since the red square is incorrectly clipped out.
See also https://github.com/dnfield/flutter_svg/issues/938
diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc
index 88f9bc5..95558f3 100644
--- a/impeller/display_list/display_list_dispatcher.cc
+++ b/impeller/display_list/display_list_dispatcher.cc
@@ -1252,6 +1252,10 @@
Matrix saved_initial_matrix = initial_matrix_;
int restore_count = canvas_.GetSaveCount();
+ // The display list may alter the clip, which must be restored to the current
+ // clip at the end of playback.
+ canvas_.Save();
+
// Establish a new baseline for interpreting the new DL.
// Matrix and clip are left untouched, the current
// transform is saved as the new base matrix, and paint
diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc
index 5164897..9364279 100644
--- a/impeller/display_list/display_list_unittests.cc
+++ b/impeller/display_list/display_list_unittests.cc
@@ -45,6 +45,21 @@
using DisplayListTest = DisplayListPlayground;
INSTANTIATE_PLAYGROUND_SUITE(DisplayListTest);
+TEST_P(DisplayListTest, DrawPictureWithAClip) {
+ flutter::DisplayListBuilder sub_builder;
+ sub_builder.ClipRect(SkRect::MakeXYWH(0, 0, 24, 24),
+ flutter::DlCanvas::ClipOp::kIntersect,
+ /*is_aa=*/false);
+ sub_builder.DrawPaint(flutter::DlPaint(flutter::DlColor::kBlue()));
+
+ auto display_list = sub_builder.Build();
+ flutter::DisplayListBuilder builder;
+ builder.DrawDisplayList(display_list);
+ builder.DrawRect(SkRect::MakeXYWH(30, 30, 24, 24),
+ flutter::DlPaint(flutter::DlColor::kRed()));
+ ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
TEST_P(DisplayListTest, CanDrawRect) {
flutter::DisplayListBuilder builder;
builder.DrawRect(SkRect::MakeXYWH(10, 10, 100, 100),