1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/flow/layers/backdrop_filter_layer.h"
6
7#include "flutter/flow/testing/layer_test.h"
8#include "flutter/flow/testing/mock_layer.h"
9#include "flutter/fml/macros.h"
10#include "flutter/testing/mock_canvas.h"
11#include "third_party/skia/include/core/SkImageFilter.h"
12#include "third_party/skia/include/effects/SkImageFilters.h"
13
14namespace flutter {
15namespace testing {
16
17using BackdropFilterLayerTest = LayerTest;
18
19#ifndef NDEBUG
20TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies) {
21 auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>());
22
23 layer->Preroll(preroll_context(), SkMatrix());
24 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
25 EXPECT_FALSE(layer->needs_painting());
26 EXPECT_FALSE(layer->needs_system_composite());
27
28 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
29 "needs_painting\\(\\)");
30}
31
32TEST_F(BackdropFilterLayerTest, PaintBeforePrerollDies) {
33 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
34 const SkPath child_path = SkPath().addRect(child_bounds);
35 auto mock_layer = std::make_shared<MockLayer>(child_path);
36 auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>());
37 layer->Add(mock_layer);
38
39 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
40 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
41 "needs_painting\\(\\)");
42}
43#endif
44
45TEST_F(BackdropFilterLayerTest, EmptyFilter) {
46 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
47 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
48 const SkPath child_path = SkPath().addRect(child_bounds);
49 const SkPaint child_paint = SkPaint(SkColors::kYellow);
50 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
51 auto layer = std::make_shared<BackdropFilterLayer>(nullptr);
52 layer->Add(mock_layer);
53
54 layer->Preroll(preroll_context(), initial_transform);
55 EXPECT_EQ(layer->paint_bounds(), child_bounds);
56 EXPECT_TRUE(layer->needs_painting());
57 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
58
59 layer->Paint(paint_context());
60 EXPECT_EQ(
61 mock_canvas().draw_calls(),
62 std::vector({MockCanvas::DrawCall{
63 0, MockCanvas::SaveLayerData{child_bounds, SkPaint(),
64 nullptr, 1}},
65 MockCanvas::DrawCall{
66 1, MockCanvas::DrawPathData{child_path, child_paint}},
67 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
68}
69
70TEST_F(BackdropFilterLayerTest, SimpleFilter) {
71 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
72 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
73 const SkPath child_path = SkPath().addRect(child_bounds);
74 const SkPaint child_paint = SkPaint(SkColors::kYellow);
75 auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
76 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
77 auto layer = std::make_shared<BackdropFilterLayer>(layer_filter);
78 layer->Add(mock_layer);
79
80 layer->Preroll(preroll_context(), initial_transform);
81 EXPECT_EQ(layer->paint_bounds(), child_bounds);
82 EXPECT_TRUE(layer->needs_painting());
83 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
84
85 layer->Paint(paint_context());
86 EXPECT_EQ(
87 mock_canvas().draw_calls(),
88 std::vector({MockCanvas::DrawCall{
89 0, MockCanvas::SaveLayerData{child_bounds, SkPaint(),
90 layer_filter, 1}},
91 MockCanvas::DrawCall{
92 1, MockCanvas::DrawPathData{child_path, child_paint}},
93 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
94}
95
96TEST_F(BackdropFilterLayerTest, MultipleChildren) {
97 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
98 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
99 const SkPath child_path1 = SkPath().addRect(child_bounds);
100 const SkPath child_path2 =
101 SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
102 const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
103 const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
104 auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
105 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
106 auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
107 auto layer = std::make_shared<BackdropFilterLayer>(layer_filter);
108 layer->Add(mock_layer1);
109 layer->Add(mock_layer2);
110
111 SkRect children_bounds = child_path1.getBounds();
112 children_bounds.join(child_path2.getBounds());
113 layer->Preroll(preroll_context(), initial_transform);
114 EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
115 EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
116 EXPECT_EQ(layer->paint_bounds(), children_bounds);
117 EXPECT_TRUE(mock_layer1->needs_painting());
118 EXPECT_TRUE(mock_layer2->needs_painting());
119 EXPECT_TRUE(layer->needs_painting());
120 EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
121 EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
122
123 layer->Paint(paint_context());
124 EXPECT_EQ(
125 mock_canvas().draw_calls(),
126 std::vector({MockCanvas::DrawCall{
127 0, MockCanvas::SaveLayerData{children_bounds, SkPaint(),
128 layer_filter, 1}},
129 MockCanvas::DrawCall{
130 1, MockCanvas::DrawPathData{child_path1, child_paint1}},
131 MockCanvas::DrawCall{
132 1, MockCanvas::DrawPathData{child_path2, child_paint2}},
133 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
134}
135
136TEST_F(BackdropFilterLayerTest, Nested) {
137 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
138 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
139 const SkPath child_path1 = SkPath().addRect(child_bounds);
140 const SkPath child_path2 =
141 SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
142 const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
143 const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
144 auto layer_filter1 = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
145 auto layer_filter2 = SkImageFilters::Paint(SkPaint(SkColors::kDkGray));
146 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
147 auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
148 auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter1);
149 auto layer2 = std::make_shared<BackdropFilterLayer>(layer_filter2);
150 layer2->Add(mock_layer2);
151 layer1->Add(mock_layer1);
152 layer1->Add(layer2);
153
154 SkRect children_bounds = child_path1.getBounds();
155 children_bounds.join(child_path2.getBounds());
156 layer1->Preroll(preroll_context(), initial_transform);
157 EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
158 EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
159 EXPECT_EQ(layer1->paint_bounds(), children_bounds);
160 EXPECT_EQ(layer2->paint_bounds(), mock_layer2->paint_bounds());
161 EXPECT_TRUE(mock_layer1->needs_painting());
162 EXPECT_TRUE(mock_layer2->needs_painting());
163 EXPECT_TRUE(layer1->needs_painting());
164 EXPECT_TRUE(layer2->needs_painting());
165 EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
166 EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
167
168 layer1->Paint(paint_context());
169 EXPECT_EQ(mock_canvas().draw_calls(),
170 std::vector(
171 {MockCanvas::DrawCall{
172 0, MockCanvas::SaveLayerData{children_bounds, SkPaint(),
173 layer_filter1, 1}},
174 MockCanvas::DrawCall{
175 1, MockCanvas::DrawPathData{child_path1, child_paint1}},
176 MockCanvas::DrawCall{
177 1, MockCanvas::SaveLayerData{child_path2.getBounds(),
178 SkPaint(), layer_filter2, 2}},
179 MockCanvas::DrawCall{
180 2, MockCanvas::DrawPathData{child_path2, child_paint2}},
181 MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
182 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
183}
184
185TEST_F(BackdropFilterLayerTest, Readback) {
186 sk_sp<SkImageFilter> no_filter;
187 auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
188 auto initial_transform = SkMatrix();
189
190 // BDF with filter always reads from surface
191 auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter);
192 preroll_context()->surface_needs_readback = false;
193 layer1->Preroll(preroll_context(), initial_transform);
194 EXPECT_TRUE(preroll_context()->surface_needs_readback);
195
196 // BDF with no filter does not read from surface itself
197 auto layer2 = std::make_shared<BackdropFilterLayer>(no_filter);
198 preroll_context()->surface_needs_readback = false;
199 layer2->Preroll(preroll_context(), initial_transform);
200 EXPECT_FALSE(preroll_context()->surface_needs_readback);
201
202 // BDF with no filter does not block prior readback value
203 preroll_context()->surface_needs_readback = true;
204 layer2->Preroll(preroll_context(), initial_transform);
205 EXPECT_TRUE(preroll_context()->surface_needs_readback);
206
207 // BDF with no filter blocks child with readback
208 auto mock_layer =
209 std::make_shared<MockLayer>(SkPath(), SkPaint(), false, false, true);
210 layer2->Add(mock_layer);
211 preroll_context()->surface_needs_readback = false;
212 layer2->Preroll(preroll_context(), initial_transform);
213 EXPECT_FALSE(preroll_context()->surface_needs_readback);
214}
215
216} // namespace testing
217} // namespace flutter
218