[Impeller] Fix back-to-back clip restoration (#38964)
diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index c4913e5..2485772 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc
@@ -270,6 +270,29 @@ ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, CanRenderWithContiguousClipRestores) { + Canvas canvas; + + // Cover the whole canvas with red. + canvas.DrawPaint({.color = Color::Red()}); + + canvas.Save(); + + // Append two clips. First with empty coverage. + canvas.ClipPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(100, 100, 100, 100)).TakePath()); + canvas.ClipPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(100, 100, 100, 100)).TakePath()); + + // Restore to no clips. + canvas.Restore(); + + // Replace the whole canvas with green. + canvas.DrawPaint({.color = Color::Green()}); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + TEST_P(AiksTest, ClipsUseCurrentTransform) { std::array<Color, 5> colors = {Color::White(), Color::Black(), Color::SkyBlue(), Color::Red(),
diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index b83c848..5819740 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc
@@ -456,11 +456,14 @@ return true; } - FML_DCHECK(stencil_stack.size() > 1); + auto restoration_depth = + element_entity.GetStencilDepth() - stencil_depth_floor; + FML_DCHECK(restoration_depth < stencil_stack.size()); - stencil_stack.pop_back(); + auto restored_coverage = stencil_stack.back().coverage; + stencil_stack.resize(restoration_depth + 1); - if (!stencil_stack.back().coverage.has_value()) { + if (!restored_coverage.has_value()) { // Running this restore op won't make anything renderable, so skip it. return true; }