From 3284e309ea47109e6593d888a59f7af98e611e93 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 15 Sep 2022 13:32:15 -0700 Subject: [PATCH] Ensure pre-rolled opacity children see snapped matrix (#36173) --- flow/layers/opacity_layer.cc | 5 +++- flow/layers/opacity_layer_unittests.cc | 39 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index eba8bf828e2c7..155c20e8733cf 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -42,6 +42,9 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { SkMatrix child_matrix = matrix; child_matrix.preTranslate(offset_.fX, offset_.fY); + if (context->raster_cache) { + child_matrix = RasterCacheUtil::GetIntegralTransCTM(child_matrix); + } // Similar to what's done in TransformLayer::Preroll, we have to apply the // reverse transformation to the cull rect to properly cull child layers. @@ -52,7 +55,7 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { context->mutators_stack.PushOpacity(alpha_); AutoCache auto_cache = - AutoCache(layer_raster_cache_item_.get(), context, matrix); + AutoCache(layer_raster_cache_item_.get(), context, child_matrix); Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index cf7fe4715f343..84a8ef29cd5a5 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -8,6 +8,7 @@ #include "flutter/flow/layers/image_filter_layer.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/layers/transform_layer.h" +#include "flutter/flow/raster_cache_util.h" #include "flutter/flow/testing/diff_context_test.h" #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" @@ -662,5 +663,43 @@ TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) { EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(11, 11, 61, 61)); } +TEST_F(OpacityLayerTest, FullyOpaqueWithFractionalValues) { + use_mock_raster_cache(); // Ensure non-fractional alignment. + + const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); + const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f); + const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f); + const SkMatrix layer_transform = + SkMatrix::Translate(layer_offset.fX, layer_offset.fY); + const SkPaint child_paint = SkPaint(SkColors::kGreen); + const SkRect expected_layer_bounds = + layer_transform.mapRect(child_path.getBounds()); + auto mock_layer = std::make_shared(child_path, child_paint); + auto layer = std::make_shared(SK_AlphaOPAQUE, layer_offset); + layer->Add(mock_layer); + layer->Preroll(preroll_context(), initial_transform); + + const SkPaint opacity_paint = SkPaint(SkColors::kBlack); // A = 1.0f + SkRect opacity_bounds; + expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY) + .roundOut(&opacity_bounds); + auto expected_draw_calls = std::vector( + {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, + MockCanvas::DrawCall{ + 1, MockCanvas::ConcatMatrixData{SkM44(layer_transform)}}, + MockCanvas::DrawCall{ + 1, MockCanvas::SetMatrixData{SkM44( + RasterCacheUtil::GetIntegralTransCTM(layer_transform))}}, + MockCanvas::DrawCall{ + 1, MockCanvas::SaveLayerData{opacity_bounds, opacity_paint, nullptr, + 2}}, + MockCanvas::DrawCall{2, + MockCanvas::DrawPathData{child_path, child_paint}}, + MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, + MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); + layer->Paint(paint_context()); + EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); +} + } // namespace testing } // namespace flutter