diff --git a/impeller/aiks/aiks_blur_unittests.cc b/impeller/aiks/aiks_blur_unittests.cc index 34a7b7c112d10..9ade5689524c9 100644 --- a/impeller/aiks/aiks_blur_unittests.cc +++ b/impeller/aiks/aiks_blur_unittests.cc @@ -755,6 +755,105 @@ TEST_P(AiksTest, GaussianBlurAnimatedBackdrop) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(AiksTest, GaussianBlurStyleInnerGradient) { + Canvas canvas; + canvas.Scale(GetContentScale()); + + canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.7568, 0.2627, 0.2118, 1.0}}; + std::vector stops = {0.0, 1.0}; + + Paint paint; + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), + Entity::TileMode::kMirror, {}); + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kInner, + .sigma = Sigma(30), + }; + canvas.DrawPath(PathBuilder() + .MoveTo({200, 200}) + .LineTo({300, 400}) + .LineTo({100, 400}) + .Close() + .TakePath(), + paint); + + // Draw another thing to make sure the clip area is reset. + Paint red; + red.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, GaussianBlurStyleSolidGradient) { + Canvas canvas; + canvas.Scale(GetContentScale()); + + canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.7568, 0.2627, 0.2118, 1.0}}; + std::vector stops = {0.0, 1.0}; + + Paint paint; + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), + Entity::TileMode::kMirror, {}); + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kSolid, + .sigma = Sigma(30), + }; + canvas.DrawPath(PathBuilder() + .MoveTo({200, 200}) + .LineTo({300, 400}) + .LineTo({100, 400}) + .Close() + .TakePath(), + paint); + + // Draw another thing to make sure the clip area is reset. + Paint red; + red.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, GaussianBlurStyleOuterGradient) { + Canvas canvas; + canvas.Scale(GetContentScale()); + + canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); + + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.7568, 0.2627, 0.2118, 1.0}}; + std::vector stops = {0.0, 1.0}; + + Paint paint; + paint.color_source = ColorSource::MakeLinearGradient( + {0, 0}, {200, 200}, std::move(colors), std::move(stops), + Entity::TileMode::kMirror, {}); + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kOuter, + .sigma = Sigma(30), + }; + canvas.DrawPath(PathBuilder() + .MoveTo({200, 200}) + .LineTo({300, 400}) + .LineTo({100, 400}) + .Close() + .TakePath(), + paint); + + // Draw another thing to make sure the clip area is reset. + Paint red; + red.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + TEST_P(AiksTest, GaussianBlurStyleInner) { Canvas canvas; canvas.Scale(GetContentScale()); diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 31043a148550c..dc2c3e9be2807 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -170,7 +170,8 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( /// 2. Blur the mask. auto blurred_mask = FilterContents::MakeGaussianBlur( - FilterInput::Make(mask), sigma, sigma, Entity::TileMode::kDecal, style); + FilterInput::Make(mask), sigma, sigma, Entity::TileMode::kDecal, style, + color_source_contents->GetGeometry()); /// 3. Replace the geometry of the original color source with a rectangle that /// covers the full region of the blurred mask. Note that geometry is in diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 46513f3b4bf85..c116b3d517cdc 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -210,30 +210,39 @@ Entity ApplyClippedBlurStyle(Entity::ClipOperation clip_operation, const Snapshot& input_snapshot, Entity blur_entity, const std::shared_ptr& geometry) { - auto shared_blur_entity = std::make_shared(std::move(blur_entity)); - shared_blur_entity->SetNewClipDepth(entity.GetNewClipDepth()); - auto clipper = std::make_unique(); - clipper->SetClipOperation(clip_operation); - clipper->SetGeometry(geometry); + auto clip_contents = std::make_shared(); + clip_contents->SetClipOperation(clip_operation); + clip_contents->SetGeometry(geometry); + Entity clipper; + clipper.SetContents(clip_contents); auto restore = std::make_unique(); - Entity result; - result.SetTransform(entity.GetTransform()); - result.SetContents(Contents::MakeAnonymous( - fml::MakeCopyable([shared_blur_entity, clipper = std::move(clipper), - restore = std::move(restore)]( - const ContentContext& renderer, - const Entity& entity, RenderPass& pass) mutable { + Matrix entity_transform = entity.GetTransform(); + Matrix blur_transform = blur_entity.GetTransform(); + auto renderer = fml::MakeCopyable( + [blur_entity = blur_entity.Clone(), clipper = std::move(clipper), + restore = std::move(restore), entity_transform, + blur_transform](const ContentContext& renderer, const Entity& entity, + RenderPass& pass) mutable { bool result = true; - result = clipper->Render(renderer, entity, pass) && result; - result = shared_blur_entity->Render(renderer, pass) && result; + clipper.SetNewClipDepth(entity.GetNewClipDepth()); + clipper.SetTransform(entity.GetTransform() * entity_transform); + result = clipper.Render(renderer, pass) && result; + blur_entity.SetNewClipDepth(entity.GetNewClipDepth()); + blur_entity.SetTransform(entity.GetTransform() * blur_transform); + result = blur_entity.Render(renderer, pass) && result; if constexpr (!ContentContext::kEnableStencilThenCover) { result = restore->Render(renderer, entity, pass) && result; } return result; - }), - [shared_blur_entity](const Entity& entity) { - return shared_blur_entity->GetCoverage(); - })); + }); + auto coverage = + fml::MakeCopyable([blur_entity = std::move(blur_entity), + blur_transform](const Entity& entity) mutable { + blur_entity.SetTransform(entity.GetTransform() * blur_transform); + return blur_entity.GetCoverage(); + }); + Entity result; + result.SetContents(Contents::MakeAnonymous(renderer, coverage)); return result; } @@ -256,24 +265,33 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style, input, input_snapshot, std::move(blur_entity), geometry); case FilterContents::BlurStyle::kSolid: { - Entity blurred = ApplyClippedBlurStyle(Entity::ClipOperation::kIntersect, - entity, input, input_snapshot, - std::move(blur_entity), geometry); Entity snapshot_entity = Entity::FromSnapshot( input_snapshot, entity.GetBlendMode(), entity.GetClipDepth()); Entity result; - std::optional coverage = blurred.GetCoverage(); + Matrix blurred_transform = blur_entity.GetTransform(); + Matrix snapshot_transform = snapshot_entity.GetTransform(); result.SetContents(Contents::MakeAnonymous( - fml::MakeCopyable([blurred = std::move(blurred), + fml::MakeCopyable([blur_entity = blur_entity.Clone(), + blurred_transform, snapshot_transform, snapshot_entity = std::move(snapshot_entity)]( const ContentContext& renderer, const Entity& entity, RenderPass& pass) mutable { - return blurred.Render(renderer, pass) && - snapshot_entity.Render(renderer, pass); + bool result = true; + blur_entity.SetNewClipDepth(entity.GetNewClipDepth()); + blur_entity.SetTransform(entity.GetTransform() * blurred_transform); + result = result && blur_entity.Render(renderer, pass); + snapshot_entity.SetTransform(entity.GetTransform() * + snapshot_transform); + snapshot_entity.SetNewClipDepth(entity.GetNewClipDepth()); + result = result && snapshot_entity.Render(renderer, pass); + return result; }), - fml::MakeCopyable( - [coverage](const Entity& entity) { return coverage; }))); + fml::MakeCopyable([blur_entity = blur_entity.Clone(), + blurred_transform](const Entity& entity) mutable { + blur_entity.SetTransform(entity.GetTransform() * blurred_transform); + return blur_entity.GetCoverage(); + }))); return result; } } diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 7da59594a013d..f48cecd4b7be6 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -488,12 +488,21 @@ impeller_Play_AiksTest_GaussianBlurRotatedAndClipped_Vulkan.png impeller_Play_AiksTest_GaussianBlurScaledAndClipped_Metal.png impeller_Play_AiksTest_GaussianBlurScaledAndClipped_OpenGLES.png impeller_Play_AiksTest_GaussianBlurScaledAndClipped_Vulkan.png +impeller_Play_AiksTest_GaussianBlurStyleInnerGradient_Metal.png +impeller_Play_AiksTest_GaussianBlurStyleInnerGradient_OpenGLES.png +impeller_Play_AiksTest_GaussianBlurStyleInnerGradient_Vulkan.png impeller_Play_AiksTest_GaussianBlurStyleInner_Metal.png impeller_Play_AiksTest_GaussianBlurStyleInner_OpenGLES.png impeller_Play_AiksTest_GaussianBlurStyleInner_Vulkan.png +impeller_Play_AiksTest_GaussianBlurStyleOuterGradient_Metal.png +impeller_Play_AiksTest_GaussianBlurStyleOuterGradient_OpenGLES.png +impeller_Play_AiksTest_GaussianBlurStyleOuterGradient_Vulkan.png impeller_Play_AiksTest_GaussianBlurStyleOuter_Metal.png impeller_Play_AiksTest_GaussianBlurStyleOuter_OpenGLES.png impeller_Play_AiksTest_GaussianBlurStyleOuter_Vulkan.png +impeller_Play_AiksTest_GaussianBlurStyleSolidGradient_Metal.png +impeller_Play_AiksTest_GaussianBlurStyleSolidGradient_OpenGLES.png +impeller_Play_AiksTest_GaussianBlurStyleSolidGradient_Vulkan.png impeller_Play_AiksTest_GaussianBlurStyleSolid_Metal.png impeller_Play_AiksTest_GaussianBlurStyleSolid_OpenGLES.png impeller_Play_AiksTest_GaussianBlurStyleSolid_Vulkan.png