Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit db0c0b7

Browse files
authored
fixes mask blurs on stoked gradient geometry (#55717)
fixes flutter/flutter#155930 This starts taking into account the translation of the entity that is snapshotted when performing the gaussian blur. I'm uncertain under what conditions, but sometimes the snapshot logic would need this offset. The linked issue and added tests demonstrate those cases. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent 88e2ac9 commit db0c0b7

File tree

4 files changed

+106
-9
lines changed

4 files changed

+106
-9
lines changed

impeller/display_list/aiks_dl_blur_unittests.cc

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,72 @@ TEST_P(AiksTest, SolidColorOvalsMaskBlurTinySigma) {
6060
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
6161
}
6262

63+
sk_sp<flutter::DisplayList> DoGradientOvalStrokeMaskBlur(Vector2 content_Scale,
64+
Scalar sigma,
65+
DlBlurStyle style) {
66+
DisplayListBuilder builder;
67+
builder.Scale(content_Scale.x, content_Scale.y);
68+
69+
DlPaint background_paint;
70+
background_paint.setColor(DlColor(1, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
71+
builder.DrawPaint(background_paint);
72+
73+
std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue()};
74+
std::vector<Scalar> stops = {0.0, 1.0};
75+
76+
DlPaint paint;
77+
paint.setMaskFilter(DlBlurMaskFilter::Make(style, sigma));
78+
auto gradient = DlColorSource::MakeLinear(
79+
{0, 0}, {200, 200}, 2, colors.data(), stops.data(), DlTileMode::kClamp);
80+
paint.setColorSource(gradient);
81+
paint.setColor(DlColor::kWhite());
82+
paint.setDrawStyle(DlDrawStyle::kStroke);
83+
paint.setStrokeWidth(20);
84+
85+
builder.Save();
86+
builder.Translate(100, 100);
87+
88+
{
89+
DlPaint line_paint;
90+
line_paint.setColor(DlColor::kWhite());
91+
builder.DrawLine({100, 0}, {100, 60}, line_paint);
92+
builder.DrawLine({0, 30}, {200, 30}, line_paint);
93+
}
94+
95+
SkRRect rrect =
96+
SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 200.0f, 60.0f), 50, 100);
97+
builder.DrawRRect(rrect, paint);
98+
builder.Restore();
99+
100+
return builder.Build();
101+
}
102+
103+
// https://github.com/flutter/flutter/issues/155930
104+
TEST_P(AiksTest, GradientOvalStrokeMaskBlur) {
105+
ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
106+
GetContentScale(), /*sigma=*/10, DlBlurStyle::kNormal)));
107+
}
108+
109+
TEST_P(AiksTest, GradientOvalStrokeMaskBlurSigmaZero) {
110+
ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
111+
GetContentScale(), /*sigma=*/0, DlBlurStyle::kNormal)));
112+
}
113+
114+
TEST_P(AiksTest, GradientOvalStrokeMaskBlurOuter) {
115+
ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
116+
GetContentScale(), /*sigma=*/10, DlBlurStyle::kOuter)));
117+
}
118+
119+
TEST_P(AiksTest, GradientOvalStrokeMaskBlurInner) {
120+
ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
121+
GetContentScale(), /*sigma=*/10, DlBlurStyle::kInner)));
122+
}
123+
124+
TEST_P(AiksTest, GradientOvalStrokeMaskBlurSolid) {
125+
ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
126+
GetContentScale(), /*sigma=*/10, DlBlurStyle::kSolid)));
127+
}
128+
63129
TEST_P(AiksTest, SolidColorCircleMaskBlurTinySigma) {
64130
DisplayListBuilder builder;
65131
builder.Scale(GetContentScale().x, GetContentScale().y);

impeller/display_list/aiks_dl_text_unittests.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ TEST_P(AiksTest, CanRenderEmojiTextFrame) {
300300
TEST_P(AiksTest, CanRenderEmojiTextFrameWithBlur) {
301301
DisplayListBuilder builder;
302302

303+
builder.Scale(GetContentScale().x, GetContentScale().y);
303304
DlPaint paint;
304305
paint.setColor(DlColor::ARGB(1, 0.1, 0.1, 0.1));
305306
builder.DrawPaint(paint);

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ Vector2 ExtractScale(const Matrix& matrix) {
7474
struct BlurInfo {
7575
/// The scalar that is used to get from source space to unrotated local space.
7676
Vector2 source_space_scalar;
77+
/// The translation that is used to get from source space to unrotated local
78+
/// space.
79+
Vector2 source_space_offset;
7780
/// Sigma when considering an entity's scale and the effect transform.
7881
Vector2 scaled_sigma;
7982
/// Blur radius in source pixels based on scaled_sigma.
@@ -95,6 +98,8 @@ BlurInfo CalculateBlurInfo(const Entity& entity,
9598
// applied to the result of the blur as part of the result's transform.
9699
const Vector2 source_space_scalar =
97100
ExtractScale(entity.GetTransform().Basis());
101+
const Vector2 source_space_offset =
102+
Vector2(entity.GetTransform().m[12], entity.GetTransform().m[13]);
98103

99104
Vector2 scaled_sigma =
100105
(effect_transform.Basis() * Matrix::MakeScale(source_space_scalar) * //
@@ -110,6 +115,7 @@ BlurInfo CalculateBlurInfo(const Entity& entity,
110115
(Matrix::MakeScale(source_space_scalar) * padding).Abs();
111116
return {
112117
.source_space_scalar = source_space_scalar,
118+
.source_space_offset = source_space_offset,
113119
.scaled_sigma = scaled_sigma,
114120
.blur_radius = blur_radius,
115121
.padding = padding,
@@ -545,7 +551,8 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style,
545551
const Snapshot& input_snapshot,
546552
Entity blur_entity,
547553
const Geometry* geometry,
548-
Vector2 source_space_scalar) {
554+
Vector2 source_space_scalar,
555+
Vector2 source_space_offset) {
549556
switch (blur_style) {
550557
case FilterContents::BlurStyle::kNormal:
551558
return blur_entity;
@@ -563,9 +570,11 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style,
563570
Entity::FromSnapshot(input_snapshot, entity.GetBlendMode());
564571
Entity result;
565572
Matrix blurred_transform = blur_entity.GetTransform();
566-
Matrix snapshot_transform = entity.GetTransform() * //
567-
Matrix::MakeScale(1.f / source_space_scalar) *
568-
input_snapshot.transform;
573+
Matrix snapshot_transform =
574+
entity.GetTransform() * //
575+
Matrix::MakeScale(1.f / source_space_scalar) *
576+
Matrix::MakeTranslation(-1 * source_space_offset) *
577+
input_snapshot.transform;
569578
result.SetContents(Contents::MakeAnonymous(
570579
fml::MakeCopyable([blur_entity = blur_entity.Clone(),
571580
blurred_transform, snapshot_transform,
@@ -697,11 +706,13 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
697706

698707
Entity snapshot_entity = entity.Clone();
699708
snapshot_entity.SetTransform(
709+
Matrix::MakeTranslation(blur_info.source_space_offset) *
700710
Matrix::MakeScale(blur_info.source_space_scalar));
701711

702712
std::optional<Rect> source_expanded_coverage_hint;
703713
if (expanded_coverage_hint.has_value()) {
704714
source_expanded_coverage_hint = expanded_coverage_hint->TransformBounds(
715+
Matrix::MakeTranslation(blur_info.source_space_offset) *
705716
Matrix::MakeScale(blur_info.source_space_scalar) *
706717
entity.GetTransform().Invert());
707718
}
@@ -717,9 +728,11 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
717728
Entity result =
718729
Entity::FromSnapshot(input_snapshot.value(),
719730
entity.GetBlendMode()); // No blur to render.
720-
result.SetTransform(entity.GetTransform() *
721-
Matrix::MakeScale(1.f / blur_info.source_space_scalar) *
722-
input_snapshot->transform);
731+
result.SetTransform(
732+
entity.GetTransform() *
733+
Matrix::MakeScale(1.f / blur_info.source_space_scalar) *
734+
Matrix::MakeTranslation(-1 * blur_info.source_space_offset) *
735+
input_snapshot->transform);
723736
return result;
724737
}
725738

@@ -827,15 +840,17 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
827840
.transform =
828841
entity.GetTransform() * //
829842
Matrix::MakeScale(1.f / blur_info.source_space_scalar) * //
830-
downsample_pass_args.transform * //
843+
Matrix::MakeTranslation(-1 * blur_info.source_space_offset) *
844+
downsample_pass_args.transform * //
831845
Matrix::MakeScale(1 / downsample_pass_args.effective_scalar),
832846
.sampler_descriptor = sampler_desc,
833847
.opacity = input_snapshot->opacity},
834848
entity.GetBlendMode());
835849

836850
return ApplyBlurStyle(mask_blur_style_, entity, inputs[0],
837851
input_snapshot.value(), std::move(blur_output_entity),
838-
mask_geometry_, blur_info.source_space_scalar);
852+
mask_geometry_, blur_info.source_space_scalar,
853+
blur_info.source_space_offset);
839854
}
840855

841856
Scalar GaussianBlurFilterContents::CalculateBlurRadius(Scalar sigma) {

testing/impeller_golden_tests_output.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,21 @@ impeller_Play_AiksTest_GaussianBlurStyleSolid_Metal.png
718718
impeller_Play_AiksTest_GaussianBlurStyleSolid_OpenGLES.png
719719
impeller_Play_AiksTest_GaussianBlurStyleSolid_Vulkan.png
720720
impeller_Play_AiksTest_GaussianBlurWithoutDecalSupport_Metal.png
721+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurInner_Metal.png
722+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurInner_OpenGLES.png
723+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurInner_Vulkan.png
724+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurOuter_Metal.png
725+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurOuter_OpenGLES.png
726+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurOuter_Vulkan.png
727+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurSigmaZero_Metal.png
728+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurSigmaZero_OpenGLES.png
729+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurSigmaZero_Vulkan.png
730+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurSolid_Metal.png
731+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurSolid_OpenGLES.png
732+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlurSolid_Vulkan.png
733+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlur_Metal.png
734+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlur_OpenGLES.png
735+
impeller_Play_AiksTest_GradientOvalStrokeMaskBlur_Vulkan.png
721736
impeller_Play_AiksTest_GradientStrokesRenderCorrectly_Metal.png
722737
impeller_Play_AiksTest_GradientStrokesRenderCorrectly_OpenGLES.png
723738
impeller_Play_AiksTest_GradientStrokesRenderCorrectly_Vulkan.png

0 commit comments

Comments
 (0)