mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Reland ImageFiltered bounds fix (flutter/engine#17077)
Fix for https://github.com/flutter/flutter/issues/51978 to use the bounds of the filtered result as the layer's paint bounds.
This commit is contained in:
parent
983d7b41e6
commit
61cfe07919
@ -11,9 +11,22 @@ ImageFilterLayer::ImageFilterLayer(sk_sp<SkImageFilter> 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);
|
||||
|
||||
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);
|
||||
set_paint_bounds(SkRect::Make(filter_output_bounds));
|
||||
} else {
|
||||
set_paint_bounds(child_paint_bounds_);
|
||||
}
|
||||
|
||||
if (!context->has_platform_view && context->raster_cache &&
|
||||
SkRect::Intersects(context->cull_rect, paint_bounds())) {
|
||||
@ -48,8 +61,12 @@ void ImageFilterLayer::Paint(PaintContext& context) const {
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(filter_);
|
||||
|
||||
// Normally a save_layer is sized to the current layer bounds, but in this
|
||||
// case the bounds of the child may not be the same as the filtered version
|
||||
// so we use the child_paint_bounds_ which were snapshotted from the
|
||||
// Preroll on the children before we adjusted them based on the filter.
|
||||
Layer::AutoSaveLayer save_layer =
|
||||
Layer::AutoSaveLayer::Create(context, paint_bounds(), &paint);
|
||||
Layer::AutoSaveLayer::Create(context, child_paint_bounds_, &paint);
|
||||
PaintChildren(context);
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ class ImageFilterLayer : public ContainerLayer {
|
||||
|
||||
private:
|
||||
sk_sp<SkImageFilter> filter_;
|
||||
SkRect child_paint_bounds_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ImageFilterLayer);
|
||||
};
|
||||
|
||||
@ -83,8 +83,47 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) {
|
||||
auto layer = std::make_shared<ImageFilterLayer>(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);
|
||||
|
||||
SkPaint filter_paint;
|
||||
filter_paint.setImageFilter(layer_filter);
|
||||
layer->Paint(paint_context());
|
||||
EXPECT_EQ(mock_canvas().draw_calls(),
|
||||
std::vector({
|
||||
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}},
|
||||
MockCanvas::DrawCall{
|
||||
1, MockCanvas::SaveLayerData{child_bounds, filter_paint,
|
||||
nullptr, 2}},
|
||||
MockCanvas::DrawCall{
|
||||
2, MockCanvas::DrawPathData{child_path, child_paint}},
|
||||
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
|
||||
}));
|
||||
}
|
||||
|
||||
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<MockLayer>(child_path, child_paint);
|
||||
auto layer = std::make_shared<ImageFilterLayer>(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);
|
||||
|
||||
@ -123,10 +162,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());
|
||||
@ -172,12 +213,17 @@ TEST_F(ImageFilterLayerTest, Nested) {
|
||||
layer1->Add(layer2);
|
||||
|
||||
SkRect children_bounds = child_path1.getBounds();
|
||||
children_bounds.join(child_path2.getBounds());
|
||||
children_bounds.join(SkRect::Make(child_path2.getBounds().roundOut()));
|
||||
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());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user