diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 119fddc181fb8..c44303a43f7d5 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -11,9 +11,21 @@ ImageFilterLayer::ImageFilterLayer(sk_sp filter) void ImageFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "ImageFilterLayer::Preroll"); + Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - ContainerLayer::Preroll(context, matrix); + + SkRect child_paint_bounds = SkRect::MakeEmpty(); + PrerollChildren(context, matrix, &child_paint_bounds); + if (filter_) { + const SkIRect filter_input_bounds = child_paint_bounds.roundOut(); + SkIRect filter_output_bounds = + filter_->filterBounds(filter_input_bounds, SkMatrix::I(), + SkImageFilter::kForward_MapDirection); + child_paint_bounds = SkRect::Make(filter_output_bounds); + } + set_paint_bounds(child_paint_bounds); if (!context->has_platform_view && context->raster_cache && SkRect::Intersects(context->cull_rect, paint_bounds())) { diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 63357fbd89ce8..94f9f902a3107 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -83,8 +83,11 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { auto layer = std::make_shared(layer_filter); layer->Add(mock_layer); + const SkRect child_rounded_bounds = + SkRect::MakeLTRB(5.0f, 6.0f, 21.0f, 22.0f); + layer->Preroll(preroll_context(), initial_transform); - EXPECT_EQ(layer->paint_bounds(), child_bounds); + EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds); EXPECT_TRUE(layer->needs_painting()); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); @@ -96,8 +99,8 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}}, MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{child_bounds, filter_paint, - nullptr, 2}}, + 1, MockCanvas::SaveLayerData{child_rounded_bounds, + filter_paint, nullptr, 2}}, MockCanvas::DrawCall{ 2, MockCanvas::DrawPathData{child_path, child_paint}}, MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, @@ -105,6 +108,26 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { })); } +TEST_F(ImageFilterLayerTest, SimpleFilterBounds) { + const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f); + const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); + const SkPath child_path = SkPath().addRect(child_bounds); + const SkPaint child_paint = SkPaint(SkColors::kYellow); + const SkMatrix filter_transform = SkMatrix::MakeScale(2.0, 2.0); + auto layer_filter = SkImageFilter::MakeMatrixFilter( + filter_transform, SkFilterQuality::kMedium_SkFilterQuality, nullptr); + auto mock_layer = std::make_shared(child_path, child_paint); + auto layer = std::make_shared(layer_filter); + layer->Add(mock_layer); + + const SkRect filter_bounds = SkRect::MakeLTRB(10.0f, 12.0f, 42.0f, 44.0f); + + layer->Preroll(preroll_context(), initial_transform); + EXPECT_EQ(layer->paint_bounds(), filter_bounds); + EXPECT_TRUE(layer->needs_painting()); + EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); +} + TEST_F(ImageFilterLayerTest, MultipleChildren) { const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f); const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f); @@ -123,10 +146,12 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { SkRect children_bounds = child_path1.getBounds(); children_bounds.join(child_path2.getBounds()); + SkRect children_rounded_bounds = SkRect::Make(children_bounds.roundOut()); + layer->Preroll(preroll_context(), initial_transform); EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); - EXPECT_EQ(layer->paint_bounds(), children_bounds); + EXPECT_EQ(layer->paint_bounds(), children_rounded_bounds); EXPECT_TRUE(mock_layer1->needs_painting()); EXPECT_TRUE(mock_layer2->needs_painting()); EXPECT_TRUE(layer->needs_painting()); @@ -141,8 +166,8 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}}, MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{children_bounds, filter_paint, - nullptr, 2}}, + 1, MockCanvas::SaveLayerData{children_rounded_bounds, + filter_paint, nullptr, 2}}, MockCanvas::DrawCall{ 2, MockCanvas::DrawPathData{child_path1, child_paint1}}, MockCanvas::DrawCall{ @@ -173,11 +198,16 @@ TEST_F(ImageFilterLayerTest, Nested) { SkRect children_bounds = child_path1.getBounds(); children_bounds.join(child_path2.getBounds()); + const SkRect children_rounded_bounds = + SkRect::Make(children_bounds.roundOut()); + const SkRect mock_layer2_rounded_bounds = + SkRect::Make(child_path2.getBounds().roundOut()); + layer1->Preroll(preroll_context(), initial_transform); EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); - EXPECT_EQ(layer1->paint_bounds(), children_bounds); - EXPECT_EQ(layer2->paint_bounds(), mock_layer2->paint_bounds()); + EXPECT_EQ(layer1->paint_bounds(), children_rounded_bounds); + EXPECT_EQ(layer2->paint_bounds(), mock_layer2_rounded_bounds); EXPECT_TRUE(mock_layer1->needs_painting()); EXPECT_TRUE(mock_layer2->needs_painting()); EXPECT_TRUE(layer1->needs_painting()); @@ -194,14 +224,14 @@ TEST_F(ImageFilterLayerTest, Nested) { MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}}, MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{children_bounds, filter_paint1, - nullptr, 2}}, + 1, MockCanvas::SaveLayerData{children_rounded_bounds, + filter_paint1, nullptr, 2}}, MockCanvas::DrawCall{ 2, MockCanvas::DrawPathData{child_path1, child_paint1}}, MockCanvas::DrawCall{2, MockCanvas::SaveData{3}}, MockCanvas::DrawCall{3, MockCanvas::SetMatrixData{SkMatrix()}}, MockCanvas::DrawCall{ - 3, MockCanvas::SaveLayerData{child_path2.getBounds(), + 3, MockCanvas::SaveLayerData{mock_layer2_rounded_bounds, filter_paint2, nullptr, 4}}, MockCanvas::DrawCall{ 4, MockCanvas::DrawPathData{child_path2, child_paint2}},