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

Commit e48761e

Browse files
authored
Reland ImageFiltered bounds fix (#17077)
Fix for flutter/flutter#51978 to use the bounds of the filtered result as the layer's paint bounds.
1 parent 822593c commit e48761e

File tree

3 files changed

+71
-7
lines changed

3 files changed

+71
-7
lines changed

flow/layers/image_filter_layer.cc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,22 @@ ImageFilterLayer::ImageFilterLayer(sk_sp<SkImageFilter> filter)
1111

1212
void ImageFilterLayer::Preroll(PrerollContext* context,
1313
const SkMatrix& matrix) {
14+
TRACE_EVENT0("flutter", "ImageFilterLayer::Preroll");
15+
1416
Layer::AutoPrerollSaveLayerState save =
1517
Layer::AutoPrerollSaveLayerState::Create(context);
16-
ContainerLayer::Preroll(context, matrix);
18+
19+
child_paint_bounds_ = SkRect::MakeEmpty();
20+
PrerollChildren(context, matrix, &child_paint_bounds_);
21+
if (filter_) {
22+
const SkIRect filter_input_bounds = child_paint_bounds_.roundOut();
23+
SkIRect filter_output_bounds =
24+
filter_->filterBounds(filter_input_bounds, SkMatrix::I(),
25+
SkImageFilter::kForward_MapDirection);
26+
set_paint_bounds(SkRect::Make(filter_output_bounds));
27+
} else {
28+
set_paint_bounds(child_paint_bounds_);
29+
}
1730

1831
if (!context->has_platform_view && context->raster_cache &&
1932
SkRect::Intersects(context->cull_rect, paint_bounds())) {
@@ -48,8 +61,12 @@ void ImageFilterLayer::Paint(PaintContext& context) const {
4861
SkPaint paint;
4962
paint.setImageFilter(filter_);
5063

64+
// Normally a save_layer is sized to the current layer bounds, but in this
65+
// case the bounds of the child may not be the same as the filtered version
66+
// so we use the child_paint_bounds_ which were snapshotted from the
67+
// Preroll on the children before we adjusted them based on the filter.
5168
Layer::AutoSaveLayer save_layer =
52-
Layer::AutoSaveLayer::Create(context, paint_bounds(), &paint);
69+
Layer::AutoSaveLayer::Create(context, child_paint_bounds_, &paint);
5370
PaintChildren(context);
5471
}
5572

flow/layers/image_filter_layer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ImageFilterLayer : public ContainerLayer {
2121

2222
private:
2323
sk_sp<SkImageFilter> filter_;
24+
SkRect child_paint_bounds_;
2425

2526
FML_DISALLOW_COPY_AND_ASSIGN(ImageFilterLayer);
2627
};

flow/layers/image_filter_layer_unittests.cc

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,47 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) {
8383
auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
8484
layer->Add(mock_layer);
8585

86+
const SkRect child_rounded_bounds =
87+
SkRect::MakeLTRB(5.0f, 6.0f, 21.0f, 22.0f);
88+
8689
layer->Preroll(preroll_context(), initial_transform);
87-
EXPECT_EQ(layer->paint_bounds(), child_bounds);
90+
EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds);
91+
EXPECT_TRUE(layer->needs_painting());
92+
EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
93+
94+
SkPaint filter_paint;
95+
filter_paint.setImageFilter(layer_filter);
96+
layer->Paint(paint_context());
97+
EXPECT_EQ(mock_canvas().draw_calls(),
98+
std::vector({
99+
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
100+
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}},
101+
MockCanvas::DrawCall{
102+
1, MockCanvas::SaveLayerData{child_bounds, filter_paint,
103+
nullptr, 2}},
104+
MockCanvas::DrawCall{
105+
2, MockCanvas::DrawPathData{child_path, child_paint}},
106+
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
107+
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
108+
}));
109+
}
110+
111+
TEST_F(ImageFilterLayerTest, SimpleFilterBounds) {
112+
const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f);
113+
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
114+
const SkPath child_path = SkPath().addRect(child_bounds);
115+
const SkPaint child_paint = SkPaint(SkColors::kYellow);
116+
const SkMatrix filter_transform = SkMatrix::MakeScale(2.0, 2.0);
117+
auto layer_filter = SkImageFilter::MakeMatrixFilter(
118+
filter_transform, SkFilterQuality::kMedium_SkFilterQuality, nullptr);
119+
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
120+
auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
121+
layer->Add(mock_layer);
122+
123+
const SkRect filter_bounds = SkRect::MakeLTRB(10.0f, 12.0f, 42.0f, 44.0f);
124+
125+
layer->Preroll(preroll_context(), initial_transform);
126+
EXPECT_EQ(layer->paint_bounds(), filter_bounds);
88127
EXPECT_TRUE(layer->needs_painting());
89128
EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
90129

@@ -123,10 +162,12 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) {
123162

124163
SkRect children_bounds = child_path1.getBounds();
125164
children_bounds.join(child_path2.getBounds());
165+
SkRect children_rounded_bounds = SkRect::Make(children_bounds.roundOut());
166+
126167
layer->Preroll(preroll_context(), initial_transform);
127168
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
128169
EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
129-
EXPECT_EQ(layer->paint_bounds(), children_bounds);
170+
EXPECT_EQ(layer->paint_bounds(), children_rounded_bounds);
130171
EXPECT_TRUE(mock_layer1->needs_painting());
131172
EXPECT_TRUE(mock_layer2->needs_painting());
132173
EXPECT_TRUE(layer->needs_painting());
@@ -172,12 +213,17 @@ TEST_F(ImageFilterLayerTest, Nested) {
172213
layer1->Add(layer2);
173214

174215
SkRect children_bounds = child_path1.getBounds();
175-
children_bounds.join(child_path2.getBounds());
216+
children_bounds.join(SkRect::Make(child_path2.getBounds().roundOut()));
217+
const SkRect children_rounded_bounds =
218+
SkRect::Make(children_bounds.roundOut());
219+
const SkRect mock_layer2_rounded_bounds =
220+
SkRect::Make(child_path2.getBounds().roundOut());
221+
176222
layer1->Preroll(preroll_context(), initial_transform);
177223
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
178224
EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
179-
EXPECT_EQ(layer1->paint_bounds(), children_bounds);
180-
EXPECT_EQ(layer2->paint_bounds(), mock_layer2->paint_bounds());
225+
EXPECT_EQ(layer1->paint_bounds(), children_rounded_bounds);
226+
EXPECT_EQ(layer2->paint_bounds(), mock_layer2_rounded_bounds);
181227
EXPECT_TRUE(mock_layer1->needs_painting());
182228
EXPECT_TRUE(mock_layer2->needs_painting());
183229
EXPECT_TRUE(layer1->needs_painting());

0 commit comments

Comments
 (0)