Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ group("flutter") {

# Fuchsia currently only supports a subset of our unit tests
if (is_fuchsia) {
public_deps += [ "$flutter_root/fml:fml_tests" ]
public_deps += [
"$flutter_root/flow:flow_tests",
"$flutter_root/fml:fml_tests",
]
}
}

Expand Down
43 changes: 42 additions & 1 deletion flow/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

if (is_fuchsia) {
import("//build/fuchsia/sdk.gni")
import("$flutter_root/tools/fuchsia/fuchsia_archive.gni")
}

import("$flutter_root/testing/testing.gni")

source_set("flow") {
Expand Down Expand Up @@ -102,15 +102,44 @@ test_fixtures("flow_fixtures") {
fixtures = []
}

source_set("flow_testing") {
testonly = true

sources = [
"testing/layer_test.h",
"testing/mock_layer.cc",
"testing/mock_layer.h",
]

public_deps = [
":flow",
"$flutter_root/testing:skia",
"//third_party/googletest:gtest",
]
}

executable("flow_unittests") {
testonly = true

sources = [
"flow_run_all_unittests.cc",
"flow_test_utils.cc",
"flow_test_utils.h",
"layers/backdrop_filter_layer_unittests.cc",
"layers/clip_path_layer_unittests.cc",
"layers/clip_rect_layer_unittests.cc",
"layers/clip_rrect_layer_unittests.cc",
"layers/color_filter_layer_unittests.cc",
"layers/container_layer_unittests.cc",
"layers/layer_tree_unittests.cc",
"layers/opacity_layer_unittests.cc",
"layers/performance_overlay_layer_unittests.cc",
"layers/physical_shape_layer_unittests.cc",
"layers/picture_layer_unittests.cc",
"layers/platform_view_layer_unittests.cc",
"layers/shader_mask_layer_unittests.cc",
"layers/texture_layer_unittests.cc",
"layers/transform_layer_unittests.cc",
"matrix_decomposition_unittests.cc",
"mutators_stack_unittests.cc",
"raster_cache_unittests.cc",
Expand All @@ -121,10 +150,22 @@ executable("flow_unittests") {
deps = [
":flow",
":flow_fixtures",
":flow_testing",
"$flutter_root/fml",
"$flutter_root/testing:skia",
"$flutter_root/testing:testing_lib",
"//third_party/dart/runtime:libdart_jit", # for tracing
"//third_party/googletest:gtest",
"//third_party/skia",
]
}

if (is_fuchsia) {
fuchsia_test_archive("flow_tests") {
deps = [
":flow_unittests",
]

binary = "flow_unittests"
}
}
1 change: 1 addition & 0 deletions flow/embedded_views.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class MutatorsStack {
// Returns an iterator pointing to the bottom of the stack.
const std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator Bottom()
const;
bool empty() const { return vector_.empty(); }

bool operator==(const MutatorsStack& other) const {
if (vector_.size() != other.vector_.size()) {
Expand Down
188 changes: 188 additions & 0 deletions flow/layers/backdrop_filter_layer_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/backdrop_filter_layer.h"

#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 {

static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();

using BackdropFilterLayerDeathTest = LayerTest;
using BackdropFilterLayerTest = LayerTest;

TEST_F(BackdropFilterLayerDeathTest, EmptyLayer) {
auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>());

layer->Preroll(preroll_context(), SkMatrix());
EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
EXPECT_FALSE(layer->needs_painting());
EXPECT_FALSE(layer->needs_system_composite());

EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
"needs_painting\\(\\)");
}

TEST_F(BackdropFilterLayerDeathTest, PaintBeforePreroll) {
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
const SkPath child_path = SkPath().addRect(child_bounds);
auto mock_layer = std::make_shared<MockLayer>(child_path);
auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>());
layer->Add(mock_layer);

EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
"needs_painting\\(\\)");
}

TEST_F(BackdropFilterLayerTest, EmptyFilter) {
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);
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<BackdropFilterLayer>(nullptr);
layer->Add(mock_layer);

layer->Preroll(preroll_context(), initial_transform);
EXPECT_EQ(layer->paint_bounds(), child_bounds);
EXPECT_TRUE(layer->needs_painting());
mock_layer->ExpectParentMatrix(initial_transform);
mock_layer->ExpectMutators({});

layer->Paint(paint_context());
mock_canvas().ExpectDrawCalls(
{MockCanvas::DrawCall{
0, MockCanvas::SaveLayerData{child_bounds, SkPaint(), nullptr, 1}},
MockCanvas::DrawCall{1,
MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
}

TEST_F(BackdropFilterLayerTest, SimpleFilter) {
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);
auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<BackdropFilterLayer>(layer_filter);
layer->Add(mock_layer);

layer->Preroll(preroll_context(), initial_transform);
EXPECT_EQ(layer->paint_bounds(), child_bounds);
EXPECT_TRUE(layer->needs_painting());
mock_layer->ExpectParentMatrix(initial_transform);
mock_layer->ExpectMutators({});

layer->Paint(paint_context());
mock_canvas().ExpectDrawCalls(
{MockCanvas::DrawCall{
0,
MockCanvas::SaveLayerData{child_bounds, SkPaint(), layer_filter, 1}},
MockCanvas::DrawCall{1,
MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
}

TEST_F(BackdropFilterLayerTest, MultipleChildren) {
const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
const SkPath child_path1 = SkPath().addRect(child_bounds);
const SkPath child_path2 =
SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
auto layer = std::make_shared<BackdropFilterLayer>(layer_filter);
layer->Add(mock_layer1);
layer->Add(mock_layer2);

SkRect children_bounds = child_path1.getBounds();
children_bounds.join(child_path2.getBounds());
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_TRUE(mock_layer1->needs_painting());
EXPECT_TRUE(mock_layer2->needs_painting());
EXPECT_TRUE(layer->needs_painting());
mock_layer1->ExpectParentMatrix(initial_transform);
mock_layer1->ExpectMutators({});
mock_layer2->ExpectParentMatrix(initial_transform);
mock_layer2->ExpectMutators({});

layer->Paint(paint_context());
mock_canvas().ExpectDrawCalls(
{MockCanvas::DrawCall{
0, MockCanvas::SaveLayerData{children_bounds, SkPaint(),
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}}});
}

TEST_F(BackdropFilterLayerTest, Nested) {
const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
const SkPath child_path1 = SkPath().addRect(child_bounds);
const SkPath child_path2 =
SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
auto layer_filter1 = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
auto layer_filter2 = SkImageFilters::Paint(SkPaint(SkColors::kDkGray));
auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter1);
auto layer2 = std::make_shared<BackdropFilterLayer>(layer_filter2);
layer2->Add(mock_layer2);
layer1->Add(mock_layer1);
layer1->Add(layer2);

SkRect children_bounds = child_path1.getBounds();
children_bounds.join(child_path2.getBounds());
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_TRUE(mock_layer1->needs_painting());
EXPECT_TRUE(mock_layer2->needs_painting());
EXPECT_TRUE(layer1->needs_painting());
EXPECT_TRUE(layer2->needs_painting());
mock_layer1->ExpectParentMatrix(initial_transform);
mock_layer1->ExpectMutators({});
mock_layer2->ExpectParentMatrix(initial_transform);
mock_layer2->ExpectMutators({});

layer1->Paint(paint_context());
mock_canvas().ExpectDrawCalls(
{MockCanvas::DrawCall{
0, MockCanvas::SaveLayerData{children_bounds, SkPaint(),
layer_filter1, 1}},
MockCanvas::DrawCall{
1, MockCanvas::DrawPathData{child_path1, child_paint1}},
MockCanvas::DrawCall{
1, MockCanvas::SaveLayerData{child_path2.getBounds(), SkPaint(),
layer_filter2, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path2, child_paint2}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
}

} // namespace testing
} // namespace flutter
Loading