diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 056efa7472dc7..5afe03acc3df9 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -82,6 +82,16 @@ void ColorFilterLayer::Paint(PaintContext& context) const { } } + // If the color filter modifies transparent black, then when it's applied to + // a saveLayer, that layer will extend beyond the paint bounds provided in the + // SaveLayerRec (which defines the bounds of the content within the layer, not + // the extent of the layer during the restore()). ColorFilterLayer must clip + // before the saveLayer in these cases to ensure it doesn't go beyond its + // reported paint_bounds(). + if (filter_ && filter_->modifies_transparent_black()) { + mutator.clipRect(paint_bounds(), /*is_aa=*/false); + } + // Now apply the color filter and then try rendering children either from // cache or directly. mutator.applyColorFilter(paint_bounds(), filter_); diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index bba9ddb096a35..f43f207ccacbc 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -447,5 +447,48 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); } +TEST_F(ColorFilterLayerTest, ModifiesTransparentBlack) { + // In Skia, saveLayers with a color filter that modifies transparent black + // will fill all pixels within the clip, going beyond the user bounds hint. + // ColorFilterLayer must insert a clipRect before saveLayer to ensure it + // doesn't draw beyond its reported bounds. + // clang-format off + float matrix[20] = { + -1, 0, 0, 0, 1, + 0,-1, 0, 0, 1, + 0, 0,-1, 0, 1, + 0, 0, 0,-1, 1, + }; + // clang-format on + auto layer_filter = DlMatrixColorFilter(matrix); + ASSERT_TRUE(layer_filter.modifies_transparent_black()); + + const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); + auto mock_layer = std::make_shared(child_path); + auto color_filter_layer = std::make_shared( + std::make_shared(matrix)); + color_filter_layer->Add(mock_layer); + + color_filter_layer->Preroll(preroll_context()); + + DisplayListBuilder expected_builder; + /* ColorFilterLayer::Paint() */ { + DlPaint dl_paint; + dl_paint.setColorFilter(&layer_filter); + expected_builder.Save(); + expected_builder.ClipRect(child_path.getBounds(), + DlCanvas::ClipOp::kIntersect, /*is_aa=*/false); + expected_builder.SaveLayer(&child_path.getBounds(), &dl_paint); + /* MockLayer::Paint() */ { + expected_builder.DrawPath(child_path, DlPaint(0xFF000000)); + } + expected_builder.Restore(); + expected_builder.Restore(); + } + + color_filter_layer->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); +} + } // namespace testing } // namespace flutter diff --git a/tools/gn b/tools/gn old mode 100755 new mode 100644 index fc6504b5127b4..4b86f0bdcc67c --- a/tools/gn +++ b/tools/gn @@ -300,8 +300,6 @@ def to_gn_args(args): gn_args['skia_use_wuffs'] = True gn_args['skia_use_expat'] = args.target_os == 'android' gn_args['skia_use_fontconfig'] = args.enable_fontconfig - gn_args['skia_use_legacy_layer_bounds' - ] = True # Temporary: See skbug.com/12083, skbug.com/12303. gn_args['skia_use_legacy_colorfilter_imagefilter'] = True # Temporary staging gn_args['skia_use_icu'] = True gn_args['is_official_build'] = True # Disable Skia test utilities.