diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc index d958822b45b7a..5fbd10e5c038f 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc @@ -47,10 +47,18 @@ Contents::StencilCoverage ClipContents::GetStencilCoverage( return {.type = StencilCoverage::Type::kAppend, .coverage = current_stencil_coverage}; case Entity::ClipOperation::kIntersect: + if (!geometry_) { + return {.type = StencilCoverage::Type::kAppend, + .coverage = std::nullopt}; + } + auto coverage = geometry_->GetCoverage(entity.GetTransformation()); + if (!coverage.has_value() || !current_stencil_coverage.has_value()) { + return {.type = StencilCoverage::Type::kAppend, + .coverage = std::nullopt}; + } return { .type = StencilCoverage::Type::kAppend, - .coverage = current_stencil_coverage->Intersection( - geometry_->GetCoverage(entity.GetTransformation()).value()), + .coverage = current_stencil_coverage->Intersection(coverage.value()), }; } FML_UNREACHABLE(); diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 4114c8ada5652..0dde60a9246a0 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1463,6 +1463,66 @@ TEST_P(EntityTest, ClipContentsShouldRenderIsCorrect) { } } +TEST_P(EntityTest, ClipContentsGetStencilCoverageIsCorrect) { + // Intersection: No stencil coverage, no geometry. + { + auto clip = std::make_shared(); + clip->SetClipOperation(Entity::ClipOperation::kIntersect); + auto result = clip->GetStencilCoverage(Entity{}, Rect{}); + + ASSERT_FALSE(result.coverage.has_value()); + } + + // Intersection: No stencil coverage, with geometry. + { + auto clip = std::make_shared(); + clip->SetClipOperation(Entity::ClipOperation::kIntersect); + clip->SetGeometry(Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 100, 100)).TakePath())); + auto result = clip->GetStencilCoverage(Entity{}, Rect{}); + + ASSERT_FALSE(result.coverage.has_value()); + } + + // Intersection: With stencil coverage, no geometry. + { + auto clip = std::make_shared(); + clip->SetClipOperation(Entity::ClipOperation::kIntersect); + auto result = + clip->GetStencilCoverage(Entity{}, Rect::MakeLTRB(0, 0, 100, 100)); + + ASSERT_FALSE(result.coverage.has_value()); + } + + // Intersection: With stencil coverage, with geometry. + { + auto clip = std::make_shared(); + clip->SetClipOperation(Entity::ClipOperation::kIntersect); + clip->SetGeometry(Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 50, 50)).TakePath())); + auto result = + clip->GetStencilCoverage(Entity{}, Rect::MakeLTRB(0, 0, 100, 100)); + + ASSERT_TRUE(result.coverage.has_value()); + ASSERT_RECT_NEAR(result.coverage.value(), Rect::MakeLTRB(0, 0, 50, 50)); + ASSERT_EQ(result.type, Contents::StencilCoverage::Type::kAppend); + } + + // Difference: With stencil coverage, with geometry. + { + auto clip = std::make_shared(); + clip->SetClipOperation(Entity::ClipOperation::kDifference); + clip->SetGeometry(Geometry::MakeFillPath( + PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 50, 50)).TakePath())); + auto result = + clip->GetStencilCoverage(Entity{}, Rect::MakeLTRB(0, 0, 100, 100)); + + ASSERT_TRUE(result.coverage.has_value()); + ASSERT_RECT_NEAR(result.coverage.value(), Rect::MakeLTRB(0, 0, 100, 100)); + ASSERT_EQ(result.type, Contents::StencilCoverage::Type::kAppend); + } +} + TEST_P(EntityTest, RRectShadowTest) { auto callback = [&](ContentContext& context, RenderPass& pass) { static Color color = Color::Red();