diff --git a/engine/src/flutter/impeller/aiks/aiks_unittests.cc b/engine/src/flutter/impeller/aiks/aiks_unittests.cc index 1339bba871..628b6df102 100644 --- a/engine/src/flutter/impeller/aiks/aiks_unittests.cc +++ b/engine/src/flutter/impeller/aiks/aiks_unittests.cc @@ -3781,5 +3781,55 @@ TEST_P(AiksTest, EmptySaveLayerRendersWithClear) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, BlurredRectangleWithShader) { + Canvas canvas; + canvas.Scale(GetContentScale()); + + auto paint_lines = [&canvas](Scalar dx, Scalar dy, Paint paint) { + auto draw_line = [&canvas, &paint](Point a, Point b) { + canvas.DrawPath(PathBuilder{}.AddLine(a, b).TakePath(), paint); + }; + paint.stroke_width = 5; + paint.style = Paint::Style::kStroke; + draw_line(Point(dx + 100, dy + 100), Point(dx + 200, dy + 200)); + draw_line(Point(dx + 100, dy + 200), Point(dx + 200, dy + 100)); + draw_line(Point(dx + 150, dy + 100), Point(dx + 200, dy + 150)); + draw_line(Point(dx + 100, dy + 150), Point(dx + 150, dy + 200)); + }; + + AiksContext renderer(GetContext(), nullptr); + Canvas recorder_canvas; + for (int x = 0; x < 5; ++x) { + for (int y = 0; y < 5; ++y) { + Rect rect = Rect::MakeXYWH(x * 20, y * 20, 20, 20); + Paint paint{.color = + ((x + y) & 1) == 0 ? Color::Yellow() : Color::Blue()}; + recorder_canvas.DrawRect(rect, paint); + } + } + Picture picture = recorder_canvas.EndRecordingAsPicture(); + std::shared_ptr texture = + picture.ToImage(renderer, ISize{100, 100})->GetTexture(); + + ColorSource image_source = ColorSource::MakeImage( + texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {}, {}); + std::shared_ptr blur_filter = ImageFilter::MakeBlur( + Sigma(5), Sigma(5), FilterContents::BlurStyle::kNormal, + Entity::TileMode::kDecal); + canvas.DrawRect(Rect::MakeLTRB(0, 0, 300, 600), + Paint{.color = Color::DarkGreen()}); + canvas.DrawRect(Rect::MakeLTRB(100, 100, 200, 200), + Paint{.color_source = image_source}); + canvas.DrawRect(Rect::MakeLTRB(300, 0, 600, 600), + Paint{.color = Color::Red()}); + canvas.DrawRect( + Rect::MakeLTRB(400, 100, 500, 200), + Paint{.color_source = image_source, .image_filter = blur_filter}); + paint_lines(0, 300, Paint{.color_source = image_source}); + paint_lines(300, 300, + Paint{.color_source = image_source, .image_filter = blur_filter}); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc index 0b54d4ba01..22984b478f 100644 --- a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.cc @@ -202,10 +202,18 @@ std::optional TiledTextureContents::RenderToSnapshot( const std::optional& sampler_descriptor, bool msaa_enabled, const std::string& label) const { - if (GetInverseEffectTransform().IsIdentity()) { + if (GetInverseEffectTransform().IsIdentity() && + GetGeometry()->IsAxisAlignedRect()) { + auto coverage = GetCoverage(entity); + if (!coverage.has_value()) { + return std::nullopt; + } + auto scale = Vector2(coverage->size / Size(texture_->GetSize())); + return Snapshot{ .texture = texture_, - .transform = entity.GetTransformation(), + .transform = Matrix::MakeTranslation(coverage->origin) * + Matrix::MakeScale(scale), .sampler_descriptor = sampler_descriptor.value_or(sampler_descriptor_), .opacity = GetOpacityFactor(), }; diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.cc b/engine/src/flutter/impeller/entity/geometry/geometry.cc index 36267c51c2..cff1770f13 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry.cc @@ -147,4 +147,8 @@ bool Geometry::CoversArea(const Matrix& transform, const Rect& rect) const { return false; } +bool Geometry::IsAxisAlignedRect() const { + return false; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.h b/engine/src/flutter/impeller/entity/geometry/geometry.h index 6a8861d120..c074362695 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/geometry.h @@ -101,6 +101,8 @@ class Geometry { /// given `rect`. May return `false` in many undetected cases where /// the transformed geometry does in fact cover the `rect`. virtual bool CoversArea(const Matrix& transform, const Rect& rect) const; + + virtual bool IsAxisAlignedRect() const; }; } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc b/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc index 6328b40768..7ea0476699 100644 --- a/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/rect_geometry.cc @@ -55,4 +55,8 @@ bool RectGeometry::CoversArea(const Matrix& transform, const Rect& rect) const { return coverage.Contains(rect); } +bool RectGeometry::IsAxisAlignedRect() const { + return true; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/rect_geometry.h b/engine/src/flutter/impeller/entity/geometry/rect_geometry.h index d0c058cf12..37364981a7 100644 --- a/engine/src/flutter/impeller/entity/geometry/rect_geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/rect_geometry.h @@ -17,6 +17,9 @@ class RectGeometry : public Geometry { // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; + // |Geometry| + bool IsAxisAlignedRect() const override; + private: // |Geometry| GeometryResult GetPositionBuffer(const ContentContext& renderer,