From 7fea2b0933ed1ab94cd6f31af71fbb916d0f2c15 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Wed, 10 May 2023 12:00:18 -0700 Subject: [PATCH] switch from MockCanvas to DisplayListBuilder in layer unit tests (flutter/engine#41889) Part of an ongoing set of efforts to address https://github.com/flutter/flutter/issues/106448 The layer unittests have been using a MockCanvas class to record the painting of trees of layers and then testing for the expected output. A while back a similar mechanism was created to compare DisplayList output and to print out a human-friendly version of the differences found, but it was only used in a few tests written at the time it was created and a few since then. This is the first in a series of PRs that will move all the rest of the unit tests onto the new DL comparison mechanism, starting with the layer types that just do basic drawing. Some of the remaining layers will require creating new hooks in, for instance, the Texture registry, the performance overlay TextBlob generation, etc. --- .../display_list/display_list_unittests.cc | 16 ++ engine/src/flutter/display_list/dl_builder.cc | 21 +- engine/src/flutter/display_list/dl_builder.h | 12 +- .../layers/backdrop_filter_layer_unittests.cc | 198 ++++++++++---- .../flow/layers/clip_path_layer_unittests.cc | 49 ++-- .../flow/layers/clip_rect_layer_unittests.cc | 53 ++-- .../flow/layers/clip_rrect_layer_unittests.cc | 55 ++-- .../layers/color_filter_layer_unittests.cc | 43 +-- .../flow/layers/container_layer_unittests.cc | 63 +++-- .../layers/display_list_layer_unittests.cc | 24 +- .../layers/image_filter_layer_unittests.cc | 192 +++++++------- .../layers/layer_state_stack_unittests.cc | 9 +- .../flow/layers/opacity_layer_unittests.cc | 217 +++++++++------- .../layers/shader_mask_layer_unittests.cc | 244 ++++++++++-------- .../flow/layers/transform_layer_unittests.cc | 129 +++++---- engine/src/flutter/flow/testing/layer_test.h | 12 +- engine/src/flutter/testing/mock_canvas.h | 2 - 17 files changed, 779 insertions(+), 560 deletions(-) diff --git a/engine/src/flutter/display_list/display_list_unittests.cc b/engine/src/flutter/display_list/display_list_unittests.cc index f2e12f74d8..f63435acdd 100644 --- a/engine/src/flutter/display_list/display_list_unittests.cc +++ b/engine/src/flutter/display_list/display_list_unittests.cc @@ -92,6 +92,22 @@ class DisplayListTestBase : public BaseT { }; using DisplayListTest = DisplayListTestBase<::testing::Test>; +TEST_F(DisplayListTest, EmptyBuild) { + DisplayListBuilder builder; + auto dl = builder.Build(); + EXPECT_EQ(dl->op_count(), 0u); + EXPECT_EQ(dl->bytes(), sizeof(DisplayList)); +} + +TEST_F(DisplayListTest, EmptyRebuild) { + DisplayListBuilder builder; + auto dl1 = builder.Build(); + auto dl2 = builder.Build(); + auto dl3 = builder.Build(); + ASSERT_TRUE(dl1->Equals(dl2)); + ASSERT_TRUE(dl2->Equals(dl3)); +} + TEST_F(DisplayListTest, BuilderCanBeReused) { DisplayListBuilder builder(kTestBounds); builder.DrawRect(kTestBounds, DlPaint()); diff --git a/engine/src/flutter/display_list/dl_builder.cc b/engine/src/flutter/display_list/dl_builder.cc index d48659426a..731ac6307b 100644 --- a/engine/src/flutter/display_list/dl_builder.cc +++ b/engine/src/flutter/display_list/dl_builder.cc @@ -578,15 +578,18 @@ void DisplayListBuilder::Transform2DAffine( SkScalar myx, SkScalar myy, SkScalar myt) { if (SkScalarsAreFinite(mxx, myx) && SkScalarsAreFinite(mxy, myy) && - SkScalarsAreFinite(mxt, myt) && - !(mxx == 1 && mxy == 0 && mxt == 0 && - myx == 0 && myy == 1 && myt == 0)) { - checkForDeferredSave(); - Push(0, 1, - mxx, mxy, mxt, - myx, myy, myt); - tracker_.transform2DAffine(mxx, mxy, mxt, - myx, myy, myt); + SkScalarsAreFinite(mxt, myt)) { + if (mxx == 1 && mxy == 0 && + myx == 0 && myy == 1) { + Translate(mxt, myt); + } else { + checkForDeferredSave(); + Push(0, 1, + mxx, mxy, mxt, + myx, myy, myt); + tracker_.transform2DAffine(mxx, mxy, mxt, + myx, myy, myt); + } } } // full 4x4 transform in row major order diff --git a/engine/src/flutter/display_list/dl_builder.h b/engine/src/flutter/display_list/dl_builder.h index e35e160e70..5a93f57eb5 100644 --- a/engine/src/flutter/display_list/dl_builder.h +++ b/engine/src/flutter/display_list/dl_builder.h @@ -113,11 +113,17 @@ class DisplayListBuilder final : public virtual DlCanvas, SkMatrix GetTransform() const override { return tracker_.matrix_3x3(); } // |DlCanvas| - void ClipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override; + void ClipRect(const SkRect& rect, + ClipOp clip_op = ClipOp::kIntersect, + bool is_aa = false) override; // |DlCanvas| - void ClipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override; + void ClipRRect(const SkRRect& rrect, + ClipOp clip_op = ClipOp::kIntersect, + bool is_aa = false) override; // |DlCanvas| - void ClipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override; + void ClipPath(const SkPath& path, + ClipOp clip_op = ClipOp::kIntersect, + bool is_aa = false) override; /// Conservative estimate of the bounds of all outstanding clip operations /// measured in the coordinate space within which this DisplayList will diff --git a/engine/src/flutter/flow/layers/backdrop_filter_layer_unittests.cc b/engine/src/flutter/flow/layers/backdrop_filter_layer_unittests.cc index c547a20b1f..e73433889f 100644 --- a/engine/src/flutter/flow/layers/backdrop_filter_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/backdrop_filter_layer_unittests.cc @@ -11,9 +11,6 @@ #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" -#include "third_party/skia/include/core/SkImageFilter.h" -#include "third_party/skia/include/effects/SkImageFilters.h" namespace flutter { namespace testing { @@ -72,15 +69,30 @@ TEST_F(BackdropFilterLayerTest, EmptyFilter) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, DlPaint(), - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + parent->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)parent::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(child_bounds, DlCanvas::ClipOp::kIntersect, + false); + /* (BackdropFilter)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&child_bounds, nullptr, nullptr); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(BackdropFilterLayerTest, SimpleFilter) { @@ -104,15 +116,31 @@ TEST_F(BackdropFilterLayerTest, SimpleFilter) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, DlPaint(), - layer_filter, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + parent->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)parent::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(child_bounds, DlCanvas::ClipOp::kIntersect, + false); + /* (BackdropFilter)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&child_bounds, nullptr, + layer_filter.get()); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(BackdropFilterLayerTest, NonSrcOverBlend) { @@ -139,15 +167,32 @@ TEST_F(BackdropFilterLayerTest, NonSrcOverBlend) { DlPaint filter_paint = DlPaint(); filter_paint.setBlendMode(DlBlendMode::kSrc); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, filter_paint, - layer_filter, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + parent->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)parent::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(child_bounds, DlCanvas::ClipOp::kIntersect, + false); + /* (BackdropFilter)layer::Paint */ { + expected_builder.Save(); + { + DlPaint save_paint = DlPaint().setBlendMode(DlBlendMode::kSrc); + expected_builder.SaveLayer(&child_bounds, &save_paint, + layer_filter.get()); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(BackdropFilterLayerTest, MultipleChildren) { @@ -184,17 +229,34 @@ TEST_F(BackdropFilterLayerTest, MultipleChildren) { EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, DlPaint(), - layer_filter, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + parent->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)parent::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(children_bounds, DlCanvas::ClipOp::kIntersect, + false); + /* (BackdropFilter)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&children_bounds, nullptr, + layer_filter.get()); + { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child_path2, child_paint2); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(BackdropFilterLayerTest, Nested) { @@ -238,21 +300,45 @@ TEST_F(BackdropFilterLayerTest, Nested) { EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); - layer1->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, DlPaint(), - layer_filter1, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{children_bounds, DlPaint(), - layer_filter2, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + parent->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)parent::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(children_bounds, DlCanvas::ClipOp::kIntersect, + false); + /* (BackdropFilter)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&children_bounds, nullptr, + layer_filter1.get()); + { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + /* (BackdropFilter)layer2::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&children_bounds, nullptr, + layer_filter2.get()); + { + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child_path2, child_paint2); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(BackdropFilterLayerTest, Readback) { diff --git a/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc b/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc index 1012a4ca72..4d3489b923 100644 --- a/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/clip_path_layer_unittests.cc @@ -12,7 +12,6 @@ #include "flutter/flow/testing/mock_embedder.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" #include "gtest/gtest.h" namespace flutter { @@ -170,17 +169,19 @@ TEST_F(ClipPathLayerTest, FullyContainedChild) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)})); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ClipPathData{layer_path, ClipOp::kIntersect, - MockCanvas::kHard_ClipEdgeStyle}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipPath)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipPath(layer_path); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipPathLayerTest, PartiallyContainedChild) { @@ -224,17 +225,19 @@ TEST_F(ClipPathLayerTest, PartiallyContainedChild) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(clip_path)})); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ClipPathData{clip_path, ClipOp::kIntersect, - MockCanvas::kHard_ClipEdgeStyle}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipPath)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipPath(clip_path); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } static bool ReadbackResult(PrerollContext* context, diff --git a/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc b/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc index 6ddb9076dd..f92d459936 100644 --- a/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/clip_rect_layer_unittests.cc @@ -11,7 +11,6 @@ #include "flutter/flow/testing/mock_embedder.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" namespace flutter { namespace testing { @@ -164,17 +163,19 @@ TEST_F(ClipRectLayerTest, FullyContainedChild) { EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_bounds)})); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ClipRectData{layer_bounds, ClipOp::kIntersect, - MockCanvas::kHard_ClipEdgeStyle}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(layer_bounds); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipRectLayerTest, PartiallyContainedChild) { @@ -213,17 +214,19 @@ TEST_F(ClipRectLayerTest, PartiallyContainedChild) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(clip_rect)})); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ClipRectData{clip_rect, ClipOp::kIntersect, - MockCanvas::kHard_ClipEdgeStyle}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRect)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRect(clip_rect); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } static bool ReadbackResult(PrerollContext* context, @@ -488,8 +491,8 @@ TEST_F(ClipRectLayerTest, LayerCached) { auto initial_transform = SkMatrix::Translate(50.0, 25.5); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); use_mock_raster_cache(); preroll_context()->state_stack.set_preroll_delegate(initial_transform); diff --git a/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc b/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc index 75ca41c3e4..9bbef5fbb0 100644 --- a/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/clip_rrect_layer_unittests.cc @@ -11,7 +11,6 @@ #include "flutter/flow/testing/mock_embedder.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" namespace flutter { namespace testing { @@ -170,17 +169,19 @@ TEST_F(ClipRRectLayerTest, FullyContainedChild) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)})); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ClipRRectData{layer_rrect, ClipOp::kIntersect, - MockCanvas::kHard_ClipEdgeStyle}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRRect)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRRect(layer_rrect); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipRRectLayerTest, PartiallyContainedChild) { @@ -220,19 +221,19 @@ TEST_F(ClipRRectLayerTest, PartiallyContainedChild) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(clip_rrect)})); - EXPECT_TRUE(mock_layer->needs_painting(paint_context())); - EXPECT_TRUE(layer->needs_painting(paint_context())); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ClipRRectData{clip_rrect, ClipOp::kIntersect, - MockCanvas::kHard_ClipEdgeStyle}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ClipRRect)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.ClipRRect(clip_rrect); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } static bool ReadbackResult(PrerollContext* context, @@ -503,8 +504,8 @@ TEST_F(ClipRRectLayerTest, LayerCached) { auto initial_transform = SkMatrix::Translate(50.0, 25.5); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); use_mock_raster_cache(); preroll_context()->state_stack.set_preroll_delegate(initial_transform); diff --git a/engine/src/flutter/flow/layers/color_filter_layer_unittests.cc b/engine/src/flutter/flow/layers/color_filter_layer_unittests.cc index bba9ddb096..f07f47d73e 100644 --- a/engine/src/flutter/flow/layers/color_filter_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/color_filter_layer_unittests.cc @@ -16,7 +16,6 @@ #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" namespace flutter { namespace testing { @@ -67,12 +66,18 @@ TEST_F(ColorFilterLayerTest, EmptyFilter) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({ - MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path, child_paint}}, - })); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ColorFilter)layer::Paint */ { + expected_builder.Save(); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ColorFilterLayerTest, SimpleFilter) { @@ -257,10 +262,10 @@ TEST_F(ColorFilterLayerTest, CacheChild) { layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); use_mock_raster_cache(); const auto* cacheable_color_filter_item = layer->raster_cache_item(); @@ -301,10 +306,10 @@ TEST_F(ColorFilterLayerTest, CacheChildren) { DlPaint paint = DlPaint(); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); use_mock_raster_cache(); @@ -347,10 +352,10 @@ TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) { DlPaint paint = DlPaint(); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); use_mock_raster_cache(); preroll_context()->state_stack.set_preroll_delegate(initial_transform); diff --git a/engine/src/flutter/flow/layers/container_layer_unittests.cc b/engine/src/flutter/flow/layers/container_layer_unittests.cc index 990bb244cd..a4c671d05f 100644 --- a/engine/src/flutter/flow/layers/container_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/container_layer_unittests.cc @@ -10,9 +10,7 @@ #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" #include "gtest/gtest.h" -#include "include/core/SkCanvas.h" #include "include/core/SkMatrix.h" namespace flutter { @@ -111,10 +109,14 @@ TEST_F(ContainerLayerTest, Simple) { EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer->parent_cull_rect(), kGiantRect); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path, child_paint}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Container)layer::Paint */ { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ContainerLayerTest, Multiple) { @@ -151,13 +153,17 @@ TEST_F(ContainerLayerTest, Multiple) { EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); // Siblings are independent - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ - child_path2, child_paint2}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Container)layer::Paint */ { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child_path2, child_paint2); + } + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ContainerLayerTest, MultipleWithEmpty) { @@ -188,10 +194,15 @@ TEST_F(ContainerLayerTest, MultipleWithEmpty) { EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path1, child_paint1}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Container)layer::Paint */ { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + // mock_layer2 not drawn due to needs_painting() returning false + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ContainerLayerTest, NeedsSystemComposite) { @@ -227,13 +238,17 @@ TEST_F(ContainerLayerTest, NeedsSystemComposite) { EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ - child_path2, child_paint2}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Container)layer::Paint */ { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child_path2, child_paint2); + } + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ContainerLayerTest, RasterCacheTest) { diff --git a/engine/src/flutter/flow/layers/display_list_layer_unittests.cc b/engine/src/flutter/flow/layers/display_list_layer_unittests.cc index eba4be82fb..137b76d247 100644 --- a/engine/src/flutter/flow/layers/display_list_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/display_list_layer_unittests.cc @@ -10,7 +10,6 @@ #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/testing/diff_context_test.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" namespace flutter { namespace testing { @@ -69,8 +68,6 @@ TEST_F(DisplayListLayerTest, InvalidDisplayListDies) { TEST_F(DisplayListLayerTest, SimpleDisplayList) { const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f); - const SkMatrix layer_offset_matrix = - SkMatrix::Translate(layer_offset.fX, layer_offset.fY); const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); DisplayListBuilder builder; builder.DrawRect(picture_bounds, DlPaint()); @@ -84,15 +81,18 @@ TEST_F(DisplayListLayerTest, SimpleDisplayList) { EXPECT_EQ(layer->display_list(), display_list.get()); EXPECT_TRUE(layer->needs_painting(paint_context())); - layer->Paint(paint_context()); - auto expected_draw_calls = std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(layer_offset_matrix)}}, - MockCanvas::DrawCall{1, - MockCanvas::DrawDisplayListData{display_list, 1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); - EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (DisplayList)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.Translate(layer_offset.fX, layer_offset.fY); + expected_builder.DrawDisplayList(display_list); + } + expected_builder.Restore(); + } + EXPECT_TRUE( + DisplayListsEQ_Verbose(this->display_list(), expected_builder.Build())); } TEST_F(DisplayListLayerTest, CachingDoesNotChangeCullRect) { diff --git a/engine/src/flutter/flow/layers/image_filter_layer_unittests.cc b/engine/src/flutter/flow/layers/image_filter_layer_unittests.cc index 63f7222701..3d27ac6af7 100644 --- a/engine/src/flutter/flow/layers/image_filter_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/image_filter_layer_unittests.cc @@ -11,7 +11,6 @@ #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" #include "gtest/gtest.h" #include "include/core/SkPath.h" #include "third_party/skia/include/effects/SkImageFilters.h" @@ -63,12 +62,16 @@ TEST_F(ImageFilterLayerTest, EmptyFilter) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({ - MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path, child_paint}}, - })); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ImageFilter)layer::Paint */ { + expected_builder.Save(); + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ImageFilterLayerTest, SimpleFilter) { @@ -354,10 +357,10 @@ TEST_F(ImageFilterLayerTest, CacheChild) { layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); DlPaint paint; use_mock_raster_cache(); @@ -400,10 +403,10 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { layer->Add(mock_layer2); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); use_mock_raster_cache(); @@ -430,34 +433,36 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { EXPECT_FALSE(raster_cache()->Draw( cacheable_image_filter_item->GetId().value(), other_canvas, &paint)); - mock_canvas().reset_draw_calls(); layer->Preroll(preroll_context()); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls().size(), 8UL); - auto call0 = MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}; - EXPECT_EQ(mock_canvas().draw_calls()[0], call0); - auto call1 = MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(SkMatrix::Translate(offset))}}; - EXPECT_EQ(mock_canvas().draw_calls()[1], call1); - auto call2 = MockCanvas::DrawCall{ - 1, MockCanvas::SetMatrixData{SkM44(SkMatrix::Translate(offset))}}; - EXPECT_EQ(mock_canvas().draw_calls()[2], call2); - auto call3 = MockCanvas::DrawCall{1, MockCanvas::SaveData{2}}; - EXPECT_EQ(mock_canvas().draw_calls()[3], call3); - auto call4 = MockCanvas::DrawCall{ - 2, MockCanvas::SetMatrixData{SkM44(SkMatrix::Translate(0.0, 0.0))}}; - EXPECT_EQ(mock_canvas().draw_calls()[4], call4); - EXPECT_EQ(mock_canvas().draw_calls()[5].layer, 2); - EXPECT_TRUE(std::holds_alternative( - mock_canvas().draw_calls()[5].data)); - auto call5_data = - std::get(mock_canvas().draw_calls()[5].data); - EXPECT_EQ(call5_data.x, offset.fX); - EXPECT_EQ(call5_data.y, offset.fY); - auto call6 = MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}; - EXPECT_EQ(mock_canvas().draw_calls()[6], call6); - auto call7 = MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}; - EXPECT_EQ(mock_canvas().draw_calls()[7], call7); + + SkRect children_bounds = child_path1.getBounds(); + children_bounds.join(child_path2.getBounds()); + SkMatrix snapped_matrix = SkMatrix::MakeAll( // + 1, 0, SkScalarRoundToScalar(offset.fX), // + 0, 1, SkScalarRoundToScalar(offset.fY), // + 0, 0, 1); + SkMatrix cache_matrix = initial_transform; + cache_matrix.preConcat(snapped_matrix); + auto transformed_filter = dl_image_filter->makeWithLocalMatrix(cache_matrix); + + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ImageFilter)layer::Paint() */ { + expected_builder.Save(); + { + expected_builder.Translate(offset.fX, offset.fY); + // snap translation components to pixels due to using raster cache + expected_builder.TransformReset(); + expected_builder.Transform(snapped_matrix); + DlPaint dl_paint; + dl_paint.setImageFilter(transformed_filter.get()); + raster_cache()->Draw(cacheable_image_filter_item->GetId().value(), + expected_builder, &dl_paint); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) { @@ -470,53 +475,58 @@ TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) { const SkPath child_path = SkPath().addRect(child_rect); auto mock_layer = std::make_shared(child_path); auto offset = SkPoint::Make(53.8, 24.4); - auto offset_rounded = - SkPoint::Make(std::round(offset.x()), std::round(offset.y())); - auto offset_rounded_out = - SkPoint::Make(std::floor(offset.x()), std::floor(offset.y())); auto layer = std::make_shared(dl_image_filter, offset); layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); DlPaint paint; + SkMatrix snapped_matrix = SkMatrix::MakeAll( // + 1, 0, SkScalarRoundToScalar(offset.fX), // + 0, 1, SkScalarRoundToScalar(offset.fY), // + 0, 0, 1); + use_mock_raster_cache(); preroll_context()->state_stack.set_preroll_delegate(initial_transform); const auto* cacheable_image_filter_item = layer->raster_cache_item(); // frame 1. layer->Preroll(preroll_context()); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls().size(), 7UL); - auto uncached_call0 = MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}; - EXPECT_EQ(mock_canvas().draw_calls()[0], uncached_call0); - auto uncached_call1 = MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(SkMatrix::Translate(offset))}}; - EXPECT_EQ(mock_canvas().draw_calls()[1], uncached_call1); - auto uncached_call2 = MockCanvas::DrawCall{ - 1, MockCanvas::SetMatrixData{SkM44(SkMatrix::Translate(offset_rounded))}}; - EXPECT_EQ(mock_canvas().draw_calls()[2], uncached_call2); - EXPECT_EQ(mock_canvas().draw_calls()[3].layer, 1); - auto uncached_call3_data = - std::get(mock_canvas().draw_calls()[3].data); - EXPECT_EQ(uncached_call3_data.save_bounds, child_rect); - EXPECT_EQ(uncached_call3_data.save_to_layer, 2); - auto uncached_call4 = - MockCanvas::DrawCall{2, MockCanvas::DrawPathData{child_path, DlPaint()}}; - EXPECT_EQ(mock_canvas().draw_calls()[4], uncached_call4); - auto uncached_call5 = MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}; - EXPECT_EQ(mock_canvas().draw_calls()[5], uncached_call5); - auto uncached_call6 = MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}; - EXPECT_EQ(mock_canvas().draw_calls()[6], uncached_call6); + + layer->Paint(display_list_paint_context()); + { + DisplayListBuilder expected_builder; + /* (ImageFilter)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.Translate(offset.fX, offset.fY); + // Snap to pixel translation due to use of raster cache + expected_builder.TransformReset(); + expected_builder.Transform(snapped_matrix); + DlPaint save_paint = DlPaint().setImageFilter(dl_image_filter); + expected_builder.SaveLayer(&child_rect, &save_paint); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, DlPaint()); + } + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + EXPECT_TRUE( + DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); + } + // frame 2. layer->Preroll(preroll_context()); - layer->Paint(paint_context()); + layer->Paint(display_list_paint_context()); // frame 3. layer->Preroll(preroll_context()); - layer->Paint(paint_context()); + layer->Paint(display_list_paint_context()); LayerTree::TryToRasterCache(cacheable_items(), &paint_context()); // frame1,2 cache the ImageFilter's children layer, frame3 cache the @@ -533,24 +543,24 @@ TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) { EXPECT_FALSE(raster_cache()->Draw( cacheable_image_filter_item->GetId().value(), other_canvas, &paint)); - mock_canvas().reset_draw_calls(); layer->Preroll(preroll_context()); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls().size(), 4UL); - auto cached_call0 = MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}; - EXPECT_EQ(mock_canvas().draw_calls()[0], cached_call0); - auto cached_call1 = MockCanvas::DrawCall{ - 1, MockCanvas::SetMatrixData{SkM44(SkMatrix::Translate(0.0, 0.0))}}; - EXPECT_EQ(mock_canvas().draw_calls()[1], cached_call1); - EXPECT_EQ(mock_canvas().draw_calls()[2].layer, 1); - EXPECT_TRUE(std::holds_alternative( - mock_canvas().draw_calls()[2].data)); - auto cached_call2_data = std::get( - mock_canvas().draw_calls()[2].data); - EXPECT_EQ(cached_call2_data.x, offset_rounded_out.fX); - EXPECT_EQ(cached_call2_data.y, offset_rounded_out.fY); - auto cached_call3 = MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}; - EXPECT_EQ(mock_canvas().draw_calls()[3], cached_call3); + + reset_display_list(); + layer->Paint(display_list_paint_context()); + { + DisplayListBuilder expected_builder; + /* (ImageFilter)layer::Paint */ { + expected_builder.Save(); + { + EXPECT_TRUE( + raster_cache()->Draw(cacheable_image_filter_item->GetId().value(), + expected_builder, nullptr)); + } + expected_builder.Restore(); + } + EXPECT_TRUE( + DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); + } } TEST_F(ImageFilterLayerTest, OpacityInheritance) { diff --git a/engine/src/flutter/flow/layers/layer_state_stack_unittests.cc b/engine/src/flutter/flow/layers/layer_state_stack_unittests.cc index 2a7e0d8313..73ed2d3cc8 100644 --- a/engine/src/flutter/flow/layers/layer_state_stack_unittests.cc +++ b/engine/src/flutter/flow/layers/layer_state_stack_unittests.cc @@ -9,7 +9,6 @@ #include "flutter/flow/layers/layer.h" #include "flutter/flow/layers/layer_state_stack.h" #include "flutter/testing/display_list_testing.h" -#include "flutter/testing/mock_canvas.h" namespace flutter { namespace testing { @@ -63,9 +62,10 @@ TEST(LayerStateStack, SingularDelegate) { LayerStateStack state_stack; ASSERT_EQ(state_stack.canvas_delegate(), nullptr); - // Two kinds of DlCanvas implementation + // Two different DlCanvas implementators DisplayListBuilder builder; - MockCanvas canvas; + DisplayListBuilder builder2; + DlCanvas& canvas = builder2; // no delegate -> builder delegate state_stack.set_delegate(&builder); @@ -92,7 +92,8 @@ TEST(LayerStateStack, SingularDelegate) { TEST(LayerStateStack, OldDelegateIsRolledBack) { LayerStateStack state_stack; DisplayListBuilder builder; - MockCanvas canvas; + DisplayListBuilder builder2; + DlCanvas& canvas = builder2; ASSERT_TRUE(builder.GetTransform().isIdentity()); ASSERT_TRUE(canvas.GetTransform().isIdentity()); diff --git a/engine/src/flutter/flow/layers/opacity_layer_unittests.cc b/engine/src/flutter/flow/layers/opacity_layer_unittests.cc index 1be70be800..a2a119264b 100644 --- a/engine/src/flutter/flow/layers/opacity_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/opacity_layer_unittests.cc @@ -16,7 +16,6 @@ #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" #include "flutter/testing/display_list_testing.h" -#include "flutter/testing/mock_canvas.h" #include "gtest/gtest.h" namespace flutter { @@ -93,10 +92,10 @@ TEST_F(OpacityLayerTest, CacheChild) { DlPaint paint; SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); use_mock_raster_cache(); @@ -142,10 +141,10 @@ TEST_F(OpacityLayerTest, CacheChildren) { layer->Add(mock_layer2); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); - MockCanvas other_canvas; - other_canvas.SetTransform(other_transform); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); + DisplayListBuilder other_canvas; + other_canvas.Transform(other_transform); use_mock_raster_cache(); @@ -233,18 +232,20 @@ TEST_F(OpacityLayerTest, FullyOpaque) { EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_transform)})); - 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::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); + DisplayListBuilder expected_builder; + /* (Opacity)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.Translate(layer_offset.fX, layer_offset.fY); + // Opaque alpha needs no SaveLayer, just recurse into painting mock_layer + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + } + expected_builder.Restore(); + } + layer->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(OpacityLayerTest, FullyTransparent) { @@ -275,20 +276,24 @@ TEST_F(OpacityLayerTest, FullyTransparent) { mock_layer->parent_mutators(), std::vector({Mutator(layer_transform), Mutator(SK_AlphaTRANSPARENT)})); - auto expected_draw_calls = std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(layer_transform)}}, - MockCanvas::DrawCall{ - 1, - MockCanvas::SaveLayerData{ - child_bounds, DlPaint(DlColor::kTransparent()), 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); + DisplayListBuilder expected_builder; + /* (Opacity)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.Translate(layer_offset.fX, layer_offset.fY); + /* (Opacity)layer::PaintChildren */ { + DlPaint save_paint(DlPaint().setOpacity(layer->opacity())); + expected_builder.SaveLayer(&child_bounds, &save_paint); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + layer->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(OpacityLayerTest, HalfTransparent) { @@ -324,12 +329,18 @@ TEST_F(OpacityLayerTest, HalfTransparent) { DlPaint child_dl_paint = DlPaint(DlColor::kGreen()); auto expected_builder = DisplayListBuilder(); - expected_builder.Save(); - expected_builder.Translate(layer_offset.fX, layer_offset.fY); - expected_builder.SaveLayer(&opacity_bounds, &save_paint); - expected_builder.DrawPath(child_path, child_dl_paint); - expected_builder.Restore(); - expected_builder.Restore(); + /* (Opacity)layer::Paint */ { + expected_builder.Save(); + expected_builder.Translate(layer_offset.fX, layer_offset.fY); + /* (Opacity)layer::PaintChildren */ { + expected_builder.SaveLayer(&opacity_bounds, &save_paint); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_dl_paint); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } sk_sp expected_display_list = expected_builder.Build(); layer->Paint(display_list_paint_context()); @@ -384,53 +395,65 @@ TEST_F(OpacityLayerTest, Nested) { EXPECT_TRUE(layer2->needs_painting(paint_context())); EXPECT_EQ(mock_layer1->parent_matrix(), SkMatrix::Concat(initial_transform, layer1_transform)); - // EXPECT_EQ(mock_layer1->parent_mutators(), - // std::vector({Mutator(layer1_transform), Mutator(alpha1)})); + EXPECT_EQ(mock_layer1->parent_mutators(), + std::vector({Mutator(layer1_transform), Mutator(alpha1)})); EXPECT_EQ( mock_layer2->parent_matrix(), SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform), layer2_transform)); - // EXPECT_EQ(mock_layer2->parent_mutators(), - // std::vector({Mutator(layer1_transform), Mutator(alpha1), - // Mutator(layer2_transform), Mutator(alpha2)})); + EXPECT_EQ(mock_layer2->parent_mutators(), + std::vector({Mutator(layer1_transform), Mutator(alpha1), + Mutator(layer2_transform), Mutator(alpha2)})); EXPECT_EQ(mock_layer3->parent_matrix(), SkMatrix::Concat(initial_transform, layer1_transform)); - // EXPECT_EQ(mock_layer3->parent_mutators(), - // std::vector({Mutator(layer1_transform), Mutator(alpha1)})); + EXPECT_EQ(mock_layer3->parent_mutators(), + std::vector({Mutator(layer1_transform), Mutator(alpha1)})); - DlPaint opacity1_paint; - opacity1_paint.setOpacity(alpha1 * (1.0 / SK_AlphaOPAQUE)); - DlPaint opacity2_paint; - opacity2_paint.setOpacity(alpha2 * (1.0 / SK_AlphaOPAQUE)); SkRect opacity1_bounds = expected_layer1_bounds.makeOffset(-layer1_offset.fX, -layer1_offset.fY); SkRect opacity2_bounds = expected_layer2_bounds.makeOffset(-layer2_offset.fX, -layer2_offset.fY); - auto expected_draw_calls = std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(layer1_transform)}}, - MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{opacity1_bounds, opacity1_paint, - nullptr, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child1_path, child1_paint}}, - MockCanvas::DrawCall{2, MockCanvas::SaveData{3}}, - MockCanvas::DrawCall{ - 3, MockCanvas::ConcatMatrixData{SkM44(layer2_transform)}}, - MockCanvas::DrawCall{ - 3, MockCanvas::SaveLayerData{opacity2_bounds, opacity2_paint, - nullptr, 4}}, - MockCanvas::DrawCall{ - 4, MockCanvas::DrawPathData{child2_path, child2_paint}}, - MockCanvas::DrawCall{4, MockCanvas::RestoreData{3}}, - MockCanvas::DrawCall{3, MockCanvas::RestoreData{2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child3_path, child3_paint}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); - layer1->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); + DlPaint opacity1_paint; + opacity1_paint.setOpacity(alpha1 * (1.0 / SK_AlphaOPAQUE)); + DlPaint opacity2_paint; + opacity2_paint.setOpacity(alpha2 * (1.0 / SK_AlphaOPAQUE)); + + DisplayListBuilder expected_builder; + /* (Opacity)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.Translate(layer1_offset.fX, layer1_offset.fY); + /* (Opacity)layer1::PaintChildren */ { + expected_builder.SaveLayer(&opacity1_bounds, &opacity1_paint); + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child1_path, child1_paint); + } + /* (Opacity)layer2::Paint */ { + expected_builder.Save(); + { + expected_builder.Translate(layer2_offset.fX, layer2_offset.fY); + /* (Opacity)layer2::PaintChidren */ { + expected_builder.SaveLayer(&opacity2_bounds, &opacity2_paint); + { + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child2_path, child2_paint); + } + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + /* mock_layer3::Paint */ { + expected_builder.DrawPath(child3_path, child3_paint); + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + layer1->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(OpacityLayerTest, Readback) { @@ -658,16 +681,12 @@ TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) { } TEST_F(OpacityLayerTest, FullyOpaqueWithFractionalValues) { - use_mock_raster_cache(); // Ensure non-fractional alignment. + use_mock_raster_cache(); // Ensure pixel-snapped 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 DlPaint child_paint = DlPaint(DlColor::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); @@ -675,21 +694,25 @@ TEST_F(OpacityLayerTest, FullyOpaqueWithFractionalValues) { preroll_context()->state_stack.set_preroll_delegate(initial_transform); layer->Preroll(preroll_context()); - 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::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); + auto expected_builder = DisplayListBuilder(); + /* (Opacity)layer::Paint */ { + expected_builder.Save(); + expected_builder.Translate(layer_offset.fX, layer_offset.fY); + // Opaque alpha needs no SaveLayer, just recurse into painting mock_layer + // but since we use the mock raster cache we pixel snap the transform + expected_builder.TransformReset(); + expected_builder.Transform2DAffine( + 1, 0, SkScalarRoundToScalar(layer_offset.fX), // + 0, 1, SkScalarRoundToScalar(layer_offset.fY)); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + expected_builder.Restore(); + } + sk_sp expected_display_list = expected_builder.Build(); + + layer->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list)); } TEST_F(OpacityLayerTest, FullyTransparentDoesNotCullPlatformView) { diff --git a/engine/src/flutter/flow/layers/shader_mask_layer_unittests.cc b/engine/src/flutter/flow/layers/shader_mask_layer_unittests.cc index b08d73cf9c..b5361a54eb 100644 --- a/engine/src/flutter/flow/layers/shader_mask_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/shader_mask_layer_unittests.cc @@ -11,10 +11,7 @@ #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" #include "gtest/gtest.h" -#include "third_party/skia/include/core/SkShader.h" -#include "third_party/skia/include/effects/SkPerlinNoiseShader.h" namespace flutter { namespace testing { @@ -86,23 +83,27 @@ TEST_F(ShaderMaskLayerTest, EmptyFilter) { DlPaint filter_paint; filter_paint.setBlendMode(DlBlendMode::kSrc); filter_paint.setColorSource(nullptr); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, DlPaint(), - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44::Translate( - layer_bounds.fLeft, layer_bounds.fTop)}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawRectData{SkRect::MakeWH( - layer_bounds.width(), - layer_bounds.height()), - filter_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ShaderMask)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&child_bounds); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + expected_builder.Translate(layer_bounds.fLeft, layer_bounds.fTop); + expected_builder.DrawRect( + SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), + filter_paint); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ShaderMaskLayerTest, SimpleFilter) { @@ -127,23 +128,27 @@ TEST_F(ShaderMaskLayerTest, SimpleFilter) { DlPaint filter_paint; filter_paint.setBlendMode(DlBlendMode::kSrc); filter_paint.setColorSource(dl_filter); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, DlPaint(), - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44::Translate( - layer_bounds.fLeft, layer_bounds.fTop)}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawRectData{SkRect::MakeWH( - layer_bounds.width(), - layer_bounds.height()), - filter_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ShaderMask)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&child_bounds); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + expected_builder.Translate(layer_bounds.fLeft, layer_bounds.fTop); + expected_builder.DrawRect( + SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), + filter_paint); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ShaderMaskLayerTest, MultipleChildren) { @@ -180,25 +185,30 @@ TEST_F(ShaderMaskLayerTest, MultipleChildren) { DlPaint filter_paint; filter_paint.setBlendMode(DlBlendMode::kSrc); filter_paint.setColorSource(dl_filter); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, DlPaint(), - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44::Translate( - layer_bounds.fLeft, layer_bounds.fTop)}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawRectData{SkRect::MakeWH( - layer_bounds.width(), - layer_bounds.height()), - filter_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ShaderMask)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&children_bounds); + { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child_path2, child_paint2); + } + expected_builder.Translate(layer_bounds.fLeft, layer_bounds.fTop); + expected_builder.DrawRect( + SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), + filter_paint); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ShaderMaskLayerTest, Nested) { @@ -244,38 +254,44 @@ TEST_F(ShaderMaskLayerTest, Nested) { filter_paint2.setBlendMode(DlBlendMode::kSrc); filter_paint1.setColorSource(dl_filter1); filter_paint2.setColorSource(dl_filter2); - layer1->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, DlPaint(), nullptr, - 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{child_path2.getBounds(), DlPaint(), - nullptr, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{2, - MockCanvas::ConcatMatrixData{SkM44::Translate( - layer_bounds.fLeft, layer_bounds.fTop)}}, - MockCanvas::DrawCall{ - 2, - MockCanvas::DrawRectData{ - SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), - filter_paint2}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, - MockCanvas::ConcatMatrixData{SkM44::Translate( - layer_bounds.fLeft, layer_bounds.fTop)}}, - MockCanvas::DrawCall{ - 1, - MockCanvas::DrawRectData{ - SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), - filter_paint1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + + layer1->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ShaderMask)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&children_bounds); + { + /* mock_layer1::Paint */ { + expected_builder.DrawPath(child_path1, child_paint1); + } + /* (ShaderMask)layer2::Paint */ { + expected_builder.Save(); + { + expected_builder.SaveLayer(&child_path2.getBounds()); + { + /* mock_layer2::Paint */ { + expected_builder.DrawPath(child_path2, child_paint2); + } + expected_builder.Translate(layer_bounds.fLeft, layer_bounds.fTop); + expected_builder.DrawRect( + SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), + filter_paint2); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + expected_builder.Translate(layer_bounds.fLeft, layer_bounds.fTop); + expected_builder.DrawRect( + SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), + filter_paint1); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ShaderMaskLayerTest, Readback) { @@ -310,8 +326,8 @@ TEST_F(ShaderMaskLayerTest, LayerCached) { layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; - MockCanvas cache_canvas; - cache_canvas.SetTransform(cache_ctm); + DisplayListBuilder cache_canvas; + cache_canvas.Transform(cache_ctm); use_mock_raster_cache(); preroll_context()->state_stack.set_preroll_delegate(initial_transform); @@ -398,7 +414,7 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); } -TEST_F(ShaderMaskLayerTest, SimpleFilterWithRasterCache) { +TEST_F(ShaderMaskLayerTest, SimpleFilterWithRasterCacheLayerNotCached) { use_mock_raster_cache(); // Ensure non-fractional alignment. const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f); @@ -418,27 +434,31 @@ TEST_F(ShaderMaskLayerTest, SimpleFilterWithRasterCache) { DlPaint filter_paint; filter_paint.setBlendMode(DlBlendMode::kSrc); filter_paint.setColorSource(dl_filter); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkM44( - SkMatrix::Translate(0.0, 0.0))}}, - MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{child_bounds, DlPaint(), - nullptr, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{ - 2, MockCanvas::ConcatMatrixData{SkM44::Translate( - layer_bounds.fLeft, layer_bounds.fTop)}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawRectData{SkRect::MakeWH( - layer_bounds.width(), - layer_bounds.height()), - filter_paint}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (ShaderMask)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.TransformReset(); + // The layer will perform this Identity transform operation by default, + // but it should be ignored both here and in the layer paint + expected_builder.Transform(SkMatrix()); + expected_builder.SaveLayer(&child_bounds); + { + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint); + } + expected_builder.Translate(layer_bounds.fLeft, layer_bounds.fTop); + expected_builder.DrawRect( + SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()), + filter_paint); + } + expected_builder.Restore(); + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } } // namespace testing diff --git a/engine/src/flutter/flow/layers/transform_layer_unittests.cc b/engine/src/flutter/flow/layers/transform_layer_unittests.cc index a0fd2bb046..129edb5772 100644 --- a/engine/src/flutter/flow/layers/transform_layer_unittests.cc +++ b/engine/src/flutter/flow/layers/transform_layer_unittests.cc @@ -8,7 +8,6 @@ #include "flutter/flow/testing/layer_test.h" #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" namespace flutter { namespace testing { @@ -59,10 +58,19 @@ TEST_F(TransformLayerTest, Identity) { EXPECT_EQ(mock_layer->parent_cull_rect(), cull_rect); EXPECT_EQ(mock_layer->parent_mutators(), MutatorsStack()); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::DrawPathData{child_path, DlPaint()}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Transform)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.Transform(SkMatrix()); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, DlPaint()); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(TransformLayerTest, Simple) { @@ -95,15 +103,19 @@ TEST_F(TransformLayerTest, Simple) { EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_transform)})); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(layer_transform)}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, DlPaint()}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Transform)layer::Paint */ { + expected_builder.Save(); + { + expected_builder.Transform(layer_transform); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, DlPaint()); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(TransformLayerTest, Nested) { @@ -113,7 +125,7 @@ TEST_F(TransformLayerTest, Nested) { SkRect local_cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f); SkRect device_cull_rect = initial_transform.mapRect(local_cull_rect); SkMatrix layer1_transform = SkMatrix::Translate(2.5f, 2.5f); - SkMatrix layer2_transform = SkMatrix::Translate(2.5f, 2.5f); + SkMatrix layer2_transform = SkMatrix::Translate(3.5f, 3.5f); SkMatrix inverse_layer1_transform, inverse_layer2_transform; EXPECT_TRUE(layer1_transform.invert(&inverse_layer1_transform)); EXPECT_TRUE(layer2_transform.invert(&inverse_layer2_transform)); @@ -146,21 +158,28 @@ TEST_F(TransformLayerTest, Nested) { inverse_layer1_transform.mapRect(local_cull_rect))); EXPECT_EQ( mock_layer->parent_mutators(), - std::vector({Mutator(layer2_transform), Mutator(layer1_transform)})); + std::vector({Mutator(layer1_transform), Mutator(layer2_transform)})); - layer1->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(layer1_transform)}}, - MockCanvas::DrawCall{1, MockCanvas::SaveData{2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::ConcatMatrixData{SkM44(layer2_transform)}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path, DlPaint()}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer1->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Transform)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.Transform(layer1_transform); + /* (Transform)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.Transform(layer2_transform); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, DlPaint()); + } + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(TransformLayerTest, NestedSeparated) { @@ -170,15 +189,15 @@ TEST_F(TransformLayerTest, NestedSeparated) { SkRect local_cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f); SkRect device_cull_rect = initial_transform.mapRect(local_cull_rect); SkMatrix layer1_transform = SkMatrix::Translate(2.5f, 2.5f); - SkMatrix layer2_transform = SkMatrix::Translate(2.5f, 2.5f); + SkMatrix layer2_transform = SkMatrix::Translate(3.5f, 3.5f); SkMatrix inverse_layer1_transform, inverse_layer2_transform; EXPECT_TRUE(layer1_transform.invert(&inverse_layer1_transform)); EXPECT_TRUE(layer2_transform.invert(&inverse_layer2_transform)); + DlPaint child_paint1(DlColor::kBlue()); + DlPaint child_paint2(DlColor::kGreen()); - auto mock_layer1 = - std::make_shared(child_path, DlPaint(DlColor::kBlue())); - auto mock_layer2 = - std::make_shared(child_path, DlPaint(DlColor::kGreen())); + auto mock_layer1 = std::make_shared(child_path, child_paint1); + auto mock_layer2 = std::make_shared(child_path, child_paint2); auto layer1 = std::make_shared(layer1_transform); auto layer2 = std::make_shared(layer2_transform); layer1->Add(mock_layer1); @@ -219,25 +238,31 @@ TEST_F(TransformLayerTest, NestedSeparated) { std::vector({Mutator(layer1_transform)})); EXPECT_EQ( mock_layer2->parent_mutators(), - std::vector({Mutator(layer2_transform), Mutator(layer1_transform)})); + std::vector({Mutator(layer1_transform), Mutator(layer2_transform)})); - layer1->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector( - {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::ConcatMatrixData{SkM44(layer1_transform)}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, - DlPaint(DlColor::kBlue())}}, - MockCanvas::DrawCall{1, MockCanvas::SaveData{2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::ConcatMatrixData{SkM44(layer2_transform)}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path, - DlPaint(DlColor::kGreen())}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + layer1->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Transform)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.Transform(layer1_transform); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint1); + } + /* (Transform)layer1::Paint */ { + expected_builder.Save(); + { + expected_builder.Transform(layer2_transform); + /* mock_layer::Paint */ { + expected_builder.DrawPath(child_path, child_paint2); + } + } + expected_builder.Restore(); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(TransformLayerTest, OpacityInheritance) { diff --git a/engine/src/flutter/flow/testing/layer_test.h b/engine/src/flutter/flow/testing/layer_test.h index 70e26670a8..f4e3fd88c9 100644 --- a/engine/src/flutter/flow/testing/layer_test.h +++ b/engine/src/flutter/flow/testing/layer_test.h @@ -172,15 +172,19 @@ class LayerTestBase : public CanvasTestBase { sk_sp display_list() { if (display_list_ == nullptr) { - // null out the canvas and recorder fields of the PaintContext - // and the delegate of the state_stack to prevent future use. - display_list_paint_context_.state_stack.clear_delegate(); - display_list_paint_context_.canvas = nullptr; display_list_ = display_list_builder_.Build(); } return display_list_; } + void reset_display_list() { + display_list_ = nullptr; + // Build() will leave the builder in a state to start recording a new DL + display_list_builder_.Build(); + // Make sure we are starting from a fresh state stack + FML_DCHECK(display_list_state_stack_.is_empty()); + } + void enable_leaf_layer_tracing() { paint_context_.enable_leaf_layer_tracing = true; paint_context_.layer_snapshot_store = &snapshot_store_; diff --git a/engine/src/flutter/testing/mock_canvas.h b/engine/src/flutter/testing/mock_canvas.h index b5d8b44cb7..71260d5b87 100644 --- a/engine/src/flutter/testing/mock_canvas.h +++ b/engine/src/flutter/testing/mock_canvas.h @@ -159,8 +159,6 @@ class MockCanvas final : public DlCanvas { MockCanvas(int width, int height); ~MockCanvas(); - // SkNWayCanvas* internal_canvas() { return &internal_canvas_; } - const std::vector& draw_calls() const { return draw_calls_; } void reset_draw_calls() { draw_calls_.clear(); }