diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index 5a93f57eb525e..78e7d8ade81cf 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -199,6 +199,7 @@ class DisplayListBuilder final : public virtual DlCanvas, DlImageSampling sampling, const DlPaint* paint = nullptr, SrcRectConstraint constraint = SrcRectConstraint::kFast) override; + using DlCanvas::DrawImageRect; // |DlCanvas| void DrawImageNine(const sk_sp& image, const SkIRect& center, diff --git a/flow/layers/texture_layer_unittests.cc b/flow/layers/texture_layer_unittests.cc index b1a96002821e2..01da461eb77c4 100644 --- a/flow/layers/texture_layer_unittests.cc +++ b/flow/layers/texture_layer_unittests.cc @@ -9,7 +9,7 @@ #include "flutter/flow/testing/mock_layer.h" #include "flutter/flow/testing/mock_texture.h" #include "flutter/fml/macros.h" -#include "flutter/testing/mock_canvas.h" +#include "flutter/testing/display_list_testing.h" namespace flutter { namespace testing { @@ -28,8 +28,8 @@ TEST_F(TextureLayerTest, InvalidTexture) { .makeOffset(layer_offset.fX, layer_offset.fY))); EXPECT_TRUE(layer->needs_painting(paint_context())); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), std::vector()); + layer->Paint(display_list_paint_context()); + EXPECT_TRUE(display_list()->Equals(DisplayList())); } #ifndef NDEBUG @@ -72,8 +72,11 @@ TEST_F(TextureLayerTest, PaintBeforePrerollDies) { TEST_F(TextureLayerTest, PaintingWithLinearSampling) { const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f); const SkSize layer_size = SkSize::Make(8.0f, 8.0f); + const SkRect layer_bounds = + SkRect::MakeSize(layer_size).makeOffset(layer_offset.fX, layer_offset.fY); const int64_t texture_id = 0; - auto mock_texture = std::make_shared(texture_id); + const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5); + auto mock_texture = std::make_shared(texture_id, texture_image); auto layer = std::make_shared( layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); @@ -81,17 +84,16 @@ TEST_F(TextureLayerTest, PaintingWithLinearSampling) { preroll_context()->texture_registry->RegisterTexture(mock_texture); layer->Preroll(preroll_context()); - EXPECT_EQ(layer->paint_bounds(), - (SkRect::MakeSize(layer_size) - .makeOffset(layer_offset.fX, layer_offset.fY))); + EXPECT_EQ(layer->paint_bounds(), layer_bounds); EXPECT_TRUE(layer->needs_painting(paint_context())); - layer->Paint(paint_context()); - EXPECT_EQ(mock_texture->paint_calls(), - std::vector({MockTexture::PaintCall{ - mock_canvas(), layer->paint_bounds(), false, nullptr, - DlImageSampling::kLinear}})); - EXPECT_EQ(mock_canvas().draw_calls(), std::vector()); + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Texture)layer::Paint */ { + expected_builder.DrawImageRect(texture_image, layer_bounds, + DlImageSampling::kLinear); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } using TextureLayerDiffTest = DiffContextTest; @@ -118,24 +120,50 @@ TEST_F(TextureLayerDiffTest, TextureInRetainedLayer) { TEST_F(TextureLayerTest, OpacityInheritance) { const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f); const SkSize layer_size = SkSize::Make(8.0f, 8.0f); + const SkRect layer_bounds = + SkRect::MakeSize(layer_size).makeOffset(layer_offset.fX, layer_offset.fY); const int64_t texture_id = 0; - auto mock_texture = std::make_shared(texture_id); - auto layer = std::make_shared( + const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5); + auto mock_texture = std::make_shared(texture_id, texture_image); + SkAlpha alpha = 0x7f; + auto texture_layer = std::make_shared( layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); + auto layer = std::make_shared(alpha, SkPoint::Make(0.0f, 0.0f)); + layer->Add(texture_layer); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry->RegisterTexture(mock_texture); - - // The texture layer always reports opacity compatibility. PrerollContext* context = preroll_context(); context->texture_registry->RegisterTexture(mock_texture); + + // The texture layer always reports opacity compatibility. + texture_layer->Preroll(context); + EXPECT_EQ(context->renderable_state_flags, + LayerStateStack::kCallerCanApplyOpacity); + + // Reset has_texture_layer since it is not supposed to be sent as we + // descend a tree in Preroll, but it was set by the previous test. + context->has_texture_layer = false; layer->Preroll(context); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::kCallerCanApplyOpacity); - // MockTexture has no actual textur to render into the - // PaintContext canvas so we have no way to verify its - // rendering. + DlPaint texture_paint; + texture_paint.setAlpha(alpha); + + layer->Paint(display_list_paint_context()); + DisplayListBuilder expected_builder; + /* (Opacity)layer::Paint */ { + expected_builder.Save(); + { + /* texture_layer::Paint */ { + expected_builder.DrawImageRect(texture_image, layer_bounds, + DlImageSampling::kLinear, + &texture_paint); + } + } + expected_builder.Restore(); + } + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } } // namespace testing diff --git a/flow/testing/mock_texture.cc b/flow/testing/mock_texture.cc index 7414c660b8df8..96c25b9c81758 100644 --- a/flow/testing/mock_texture.cc +++ b/flow/testing/mock_texture.cc @@ -9,27 +9,41 @@ namespace flutter { namespace testing { -MockTexture::MockTexture(int64_t textureId) : Texture(textureId) {} +sk_sp MockTexture::MakeTestTexture(int w, int h, int checker_size) { + sk_sp surface = SkSurface::MakeRasterN32Premul(w, h); + SkCanvas* canvas = surface->getCanvas(); + SkPaint p0, p1; + p0.setStyle(SkPaint::kFill_Style); + p0.setColor(SK_ColorGREEN); + p1.setStyle(SkPaint::kFill_Style); + p1.setColor(SK_ColorBLUE); + p1.setAlpha(128); + for (int y = 0; y < w; y += checker_size) { + for (int x = 0; x < h; x += checker_size) { + SkPaint& cellp = ((x + y) & 1) == 0 ? p0 : p1; + canvas->drawRect(SkRect::MakeXYWH(x, y, checker_size, checker_size), + cellp); + } + } + return DlImage::Make(surface->makeImageSnapshot()); +} + +MockTexture::MockTexture(int64_t textureId, const sk_sp& texture) + : Texture(textureId), texture_(texture) {} void MockTexture::Paint(PaintContext& context, const SkRect& bounds, bool freeze, const DlImageSampling sampling) { - paint_calls_.emplace_back(PaintCall{*(context.canvas), bounds, freeze, - context.gr_context, sampling, - context.paint}); -} - -bool operator==(const MockTexture::PaintCall& a, - const MockTexture::PaintCall& b) { - return &a.canvas == &b.canvas && a.bounds == b.bounds && - a.context == b.context && a.freeze == b.freeze && - a.sampling == b.sampling && a.paint == b.paint; -} - -std::ostream& operator<<(std::ostream& os, const MockTexture::PaintCall& data) { - return os << &data.canvas << " " << data.bounds << " " << data.context << " " - << data.freeze << " " << data.sampling << " " << data.paint; + // MockTexture objects that are not painted are allowed to have a null + // texture, but when we get to this method we must have a non-null texture. + FML_DCHECK(texture_ != nullptr); + SkRect src = SkRect::Make(texture_->bounds()); + if (freeze) { + FML_DCHECK(src.width() > 2.0f && src.height() > 2.0f); + src = src.makeInset(1.0f, 1.0f); + } + context.canvas->DrawImageRect(texture_, src, bounds, sampling, context.paint); } } // namespace testing diff --git a/flow/testing/mock_texture.h b/flow/testing/mock_texture.h index c1b786eab8cd1..70f0991192dec 100644 --- a/flow/testing/mock_texture.h +++ b/flow/testing/mock_texture.h @@ -19,16 +19,10 @@ namespace testing { // later verify them against expected data. class MockTexture : public Texture { public: - struct PaintCall { - DlCanvas& canvas; - SkRect bounds; - bool freeze; - GrDirectContext* context; - DlImageSampling sampling; - const DlPaint* paint; - }; + static sk_sp MakeTestTexture(int w, int h, int checker_size); - explicit MockTexture(int64_t textureId); + explicit MockTexture(int64_t textureId, + const sk_sp& texture = nullptr); // Called from raster thread. void Paint(PaintContext& context, @@ -41,23 +35,17 @@ class MockTexture : public Texture { void MarkNewFrameAvailable() override {} void OnTextureUnregistered() override { unregistered_ = true; } - const std::vector& paint_calls() { return paint_calls_; } bool gr_context_created() { return gr_context_created_; } bool gr_context_destroyed() { return gr_context_destroyed_; } bool unregistered() { return unregistered_; } private: - std::vector paint_calls_; + sk_sp texture_; bool gr_context_created_ = false; bool gr_context_destroyed_ = false; bool unregistered_ = false; }; -extern bool operator==(const MockTexture::PaintCall& a, - const MockTexture::PaintCall& b); -extern std::ostream& operator<<(std::ostream& os, - const MockTexture::PaintCall& data); - } // namespace testing } // namespace flutter diff --git a/flow/testing/mock_texture_unittests.cc b/flow/testing/mock_texture_unittests.cc index 3413f2855d18d..5f5bab254dd6e 100644 --- a/flow/testing/mock_texture_unittests.cc +++ b/flow/testing/mock_texture_unittests.cc @@ -4,7 +4,8 @@ #include "flutter/flow/testing/mock_texture.h" -#include "flutter/testing/mock_canvas.h" +#include "flutter/display_list/dl_builder.h" +#include "flutter/testing/display_list_testing.h" #include "gtest/gtest.h" namespace flutter { @@ -27,37 +28,51 @@ TEST(MockTextureTest, Callbacks) { } TEST(MockTextureTest, PaintCalls) { - MockCanvas canvas; + DisplayListBuilder builder; const SkRect paint_bounds1 = SkRect::MakeWH(1.0f, 1.0f); const SkRect paint_bounds2 = SkRect::MakeWH(2.0f, 2.0f); const DlImageSampling sampling = DlImageSampling::kNearestNeighbor; - const auto expected_paint_calls = std::vector{ - MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr, sampling}, - MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr, sampling}}; - auto texture = std::make_shared(0); + const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5); + auto texture = std::make_shared(0, texture_image); + Texture::PaintContext context{ - .canvas = &canvas, + .canvas = &builder, }; texture->Paint(context, paint_bounds1, false, sampling); texture->Paint(context, paint_bounds2, true, sampling); - EXPECT_EQ(texture->paint_calls(), expected_paint_calls); + + SkRect src1 = SkRect::Make(texture_image->bounds()); + SkRect src2 = src1.makeInset(1.0, 1.0f); + + DisplayListBuilder expected_builder; + expected_builder.DrawImageRect(texture_image, src1, paint_bounds1, sampling); + expected_builder.DrawImageRect(texture_image, src2, paint_bounds2, sampling); + EXPECT_TRUE( + DisplayListsEQ_Verbose(builder.Build(), expected_builder.Build())); } TEST(MockTextureTest, PaintCallsWithLinearSampling) { - MockCanvas canvas; + DisplayListBuilder builder; const SkRect paint_bounds1 = SkRect::MakeWH(1.0f, 1.0f); const SkRect paint_bounds2 = SkRect::MakeWH(2.0f, 2.0f); const auto sampling = DlImageSampling::kLinear; - const auto expected_paint_calls = std::vector{ - MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr, sampling}, - MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr, sampling}}; - auto texture = std::make_shared(0); + const auto texture_image = MockTexture::MakeTestTexture(20, 20, 5); + auto texture = std::make_shared(0, texture_image); + Texture::PaintContext context{ - .canvas = &canvas, + .canvas = &builder, }; texture->Paint(context, paint_bounds1, false, sampling); texture->Paint(context, paint_bounds2, true, sampling); - EXPECT_EQ(texture->paint_calls(), expected_paint_calls); + + SkRect src1 = SkRect::Make(texture_image->bounds()); + SkRect src2 = src1.makeInset(1.0, 1.0f); + + DisplayListBuilder expected_builder; + expected_builder.DrawImageRect(texture_image, src1, paint_bounds1, sampling); + expected_builder.DrawImageRect(texture_image, src2, paint_bounds2, sampling); + EXPECT_TRUE( + DisplayListsEQ_Verbose(builder.Build(), expected_builder.Build())); } } // namespace testing