[Impeller] Do not apply mask filters to a DrawPaint cover geometry (#51670)
The DisplayListBuilder only updates the paint attributes that are relevant to a given operation. DrawPaint does not support mask filters, so DisplayListBuilder::DrawPaint will not modify the mask filter state. So a call to DrawPaint in the display list dispatcher may receive a paint containing a mask filter set by a previous call.
Aiks Canvas::DrawPaint should ignore any mask filter set on the paint (matching the spec for Skia's SkCanvas::drawPaint)
Fixes https://github.com/flutter/flutter/issues/145442
diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc
index 1e3fe38..22a6984 100644
--- a/impeller/aiks/canvas.cc
+++ b/impeller/aiks/canvas.cc
@@ -44,8 +44,10 @@
}
}
+ bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
contents->SetGeometry(std::move(geometry));
- if (paint.mask_blur_descriptor.has_value()) {
+
+ if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) {
// If there's a mask blur and we need to apply the color filter on the GPU,
// we need to be careful to only apply the color filter to the source
// colors. CreateMaskBlur is able to handle this case.
diff --git a/impeller/display_list/dl_unittests.cc b/impeller/display_list/dl_unittests.cc
index 5da4606..b10f554 100644
--- a/impeller/display_list/dl_unittests.cc
+++ b/impeller/display_list/dl_unittests.cc
@@ -1834,5 +1834,28 @@
}
#endif
+TEST_P(DisplayListTest, DrawPaintIgnoresMaskFilter) {
+ flutter::DisplayListBuilder builder;
+ builder.DrawPaint(flutter::DlPaint().setColor(flutter::DlColor::kWhite()));
+
+ auto filter = flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
+ builder.DrawCircle({300, 300}, 200,
+ flutter::DlPaint().setMaskFilter(&filter));
+
+ std::vector<flutter::DlColor> colors = {flutter::DlColor::kGreen(),
+ flutter::DlColor::kGreen()};
+ const float stops[2] = {0.0, 1.0};
+ auto linear = flutter::DlColorSource::MakeLinear(
+ {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
+ flutter::DlTileMode::kRepeat);
+ flutter::DlPaint blend_paint =
+ flutter::DlPaint() //
+ .setColorSource(linear) //
+ .setBlendMode(flutter::DlBlendMode::kScreen);
+ builder.DrawPaint(blend_paint);
+
+ ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
} // namespace testing
} // namespace impeller
diff --git a/impeller/entity/geometry/cover_geometry.cc b/impeller/entity/geometry/cover_geometry.cc
index 62c97c0..488976e 100644
--- a/impeller/entity/geometry/cover_geometry.cc
+++ b/impeller/entity/geometry/cover_geometry.cc
@@ -58,4 +58,8 @@
return true;
}
+bool CoverGeometry::CanApplyMaskFilter() const {
+ return false;
+}
+
} // namespace impeller
diff --git a/impeller/entity/geometry/cover_geometry.h b/impeller/entity/geometry/cover_geometry.h
index 3d76756..e9f5653 100644
--- a/impeller/entity/geometry/cover_geometry.h
+++ b/impeller/entity/geometry/cover_geometry.h
@@ -20,6 +20,8 @@
// |Geometry|
bool CoversArea(const Matrix& transform, const Rect& rect) const override;
+ bool CanApplyMaskFilter() const override;
+
private:
// |Geometry|
GeometryResult GetPositionBuffer(const ContentContext& renderer,
diff --git a/impeller/entity/geometry/geometry.cc b/impeller/entity/geometry/geometry.cc
index 772c0cb..ce4b72d 100644
--- a/impeller/entity/geometry/geometry.cc
+++ b/impeller/entity/geometry/geometry.cc
@@ -240,4 +240,8 @@
return false;
}
+bool Geometry::CanApplyMaskFilter() const {
+ return true;
+}
+
} // namespace impeller
diff --git a/impeller/entity/geometry/geometry.h b/impeller/entity/geometry/geometry.h
index ae30159..5144ead 100644
--- a/impeller/entity/geometry/geometry.h
+++ b/impeller/entity/geometry/geometry.h
@@ -148,6 +148,8 @@
virtual bool IsAxisAlignedRect() const;
+ virtual bool CanApplyMaskFilter() const;
+
protected:
static GeometryResult ComputePositionGeometry(
const ContentContext& renderer,