Flutter Engine
image_filter_layer_unittests.cc
Go to the documentation of this file.
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/image_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 
13 namespace flutter {
14 namespace testing {
15 
17 
18 #ifndef NDEBUG
19 TEST_F(ImageFilterLayerTest, PaintingEmptyLayerDies) {
20  auto layer = std::make_shared<ImageFilterLayer>(sk_sp<SkImageFilter>());
21 
22  layer->Preroll(preroll_context(), SkMatrix());
23  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
24  EXPECT_FALSE(layer->needs_painting());
25  EXPECT_FALSE(layer->needs_system_composite());
26 
27  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
28  "needs_painting\\(\\)");
29 }
30 
31 TEST_F(ImageFilterLayerTest, PaintBeforePrerollDies) {
32  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
33  const SkPath child_path = SkPath().addRect(child_bounds);
34  auto mock_layer = std::make_shared<MockLayer>(child_path);
35  auto layer = std::make_shared<ImageFilterLayer>(sk_sp<SkImageFilter>());
36  layer->Add(mock_layer);
37 
38  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
39  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
40  "needs_painting\\(\\)");
41 }
42 #endif
43 
44 TEST_F(ImageFilterLayerTest, EmptyFilter) {
45  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
46  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
47  const SkPath child_path = SkPath().addRect(child_bounds);
48  const SkPaint child_paint = SkPaint(SkColors::kYellow);
49  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
50  auto layer = std::make_shared<ImageFilterLayer>(nullptr);
51  layer->Add(mock_layer);
52 
53  layer->Preroll(preroll_context(), initial_transform);
54  EXPECT_EQ(layer->paint_bounds(), child_bounds);
55  EXPECT_TRUE(layer->needs_painting());
56  EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
57 
58  SkPaint filter_paint;
59  filter_paint.setImageFilter(nullptr);
60  layer->Paint(paint_context());
61  EXPECT_EQ(mock_canvas().draw_calls(),
62  std::vector({
64  0, MockCanvas::SaveLayerData{child_bounds, filter_paint,
65  nullptr, 1}},
67  1, MockCanvas::DrawPathData{child_path, child_paint}},
69  }));
70 }
71 
72 TEST_F(ImageFilterLayerTest, SimpleFilter) {
73  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
74  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
75  const SkPath child_path = SkPath().addRect(child_bounds);
76  const SkPaint child_paint = SkPaint(SkColors::kYellow);
77  auto layer_filter = SkImageFilter::MakeMatrixFilter(
78  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
79  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
80  auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
81  layer->Add(mock_layer);
82 
83  const SkRect child_rounded_bounds =
84  SkRect::MakeLTRB(5.0f, 6.0f, 21.0f, 22.0f);
85 
86  layer->Preroll(preroll_context(), initial_transform);
87  EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds);
88  EXPECT_TRUE(layer->needs_painting());
89  EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
90 
91  SkPaint filter_paint;
92  filter_paint.setImageFilter(layer_filter);
93  layer->Paint(paint_context());
94  EXPECT_EQ(mock_canvas().draw_calls(),
95  std::vector({
97  0, MockCanvas::SaveLayerData{child_bounds, filter_paint,
98  nullptr, 1}},
100  1, MockCanvas::DrawPathData{child_path, child_paint}},
102  }));
103 }
104 
105 TEST_F(ImageFilterLayerTest, SimpleFilterBounds) {
106  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
107  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
108  const SkPath child_path = SkPath().addRect(child_bounds);
109  const SkPaint child_paint = SkPaint(SkColors::kYellow);
110  const SkMatrix filter_transform = SkMatrix::Scale(2.0, 2.0);
111  auto layer_filter = SkImageFilter::MakeMatrixFilter(
112  filter_transform, SkFilterQuality::kMedium_SkFilterQuality, nullptr);
113  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
114  auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
115  layer->Add(mock_layer);
116 
117  const SkRect filter_bounds = SkRect::MakeLTRB(10.0f, 12.0f, 42.0f, 44.0f);
118 
119  layer->Preroll(preroll_context(), initial_transform);
120  EXPECT_EQ(layer->paint_bounds(), filter_bounds);
121  EXPECT_TRUE(layer->needs_painting());
122  EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
123 
124  SkPaint filter_paint;
125  filter_paint.setImageFilter(layer_filter);
126  layer->Paint(paint_context());
127  EXPECT_EQ(mock_canvas().draw_calls(),
128  std::vector({
130  0, MockCanvas::SaveLayerData{child_bounds, filter_paint,
131  nullptr, 1}},
133  1, MockCanvas::DrawPathData{child_path, child_paint}},
135  }));
136 }
137 
138 TEST_F(ImageFilterLayerTest, MultipleChildren) {
139  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
140  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
141  const SkPath child_path1 = SkPath().addRect(child_bounds);
142  const SkPath child_path2 =
143  SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
144  const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
145  const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
146  auto layer_filter = SkImageFilter::MakeMatrixFilter(
147  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
148  auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
149  auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
150  auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
151  layer->Add(mock_layer1);
152  layer->Add(mock_layer2);
153 
154  SkRect children_bounds = child_path1.getBounds();
155  children_bounds.join(child_path2.getBounds());
156  SkRect children_rounded_bounds = SkRect::Make(children_bounds.roundOut());
157 
158  layer->Preroll(preroll_context(), initial_transform);
159  EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
160  EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
161  EXPECT_EQ(layer->paint_bounds(), children_rounded_bounds);
162  EXPECT_TRUE(mock_layer1->needs_painting());
163  EXPECT_TRUE(mock_layer2->needs_painting());
164  EXPECT_TRUE(layer->needs_painting());
165  EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
166  EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
167 
168  SkPaint filter_paint;
169  filter_paint.setImageFilter(layer_filter);
170  layer->Paint(paint_context());
171  EXPECT_EQ(
172  mock_canvas().draw_calls(),
173  std::vector({MockCanvas::DrawCall{
174  0, MockCanvas::SaveLayerData{children_bounds,
175  filter_paint, nullptr, 1}},
177  1, MockCanvas::DrawPathData{child_path1, child_paint1}},
179  1, MockCanvas::DrawPathData{child_path2, child_paint2}},
181 }
182 
183 TEST_F(ImageFilterLayerTest, Nested) {
184  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
185  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
186  const SkPath child_path1 = SkPath().addRect(child_bounds);
187  const SkPath child_path2 =
188  SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
189  const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
190  const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
191  auto layer_filter1 = SkImageFilter::MakeMatrixFilter(
192  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
193  auto layer_filter2 = SkImageFilter::MakeMatrixFilter(
194  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
195  auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
196  auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
197  auto layer1 = std::make_shared<ImageFilterLayer>(layer_filter1);
198  auto layer2 = std::make_shared<ImageFilterLayer>(layer_filter2);
199  layer2->Add(mock_layer2);
200  layer1->Add(mock_layer1);
201  layer1->Add(layer2);
202 
203  SkRect children_bounds = child_path1.getBounds();
204  children_bounds.join(SkRect::Make(child_path2.getBounds().roundOut()));
205  const SkRect children_rounded_bounds =
206  SkRect::Make(children_bounds.roundOut());
207  const SkRect mock_layer2_rounded_bounds =
208  SkRect::Make(child_path2.getBounds().roundOut());
209 
210  layer1->Preroll(preroll_context(), initial_transform);
211  EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
212  EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
213  EXPECT_EQ(layer1->paint_bounds(), children_rounded_bounds);
214  EXPECT_EQ(layer2->paint_bounds(), mock_layer2_rounded_bounds);
215  EXPECT_TRUE(mock_layer1->needs_painting());
216  EXPECT_TRUE(mock_layer2->needs_painting());
217  EXPECT_TRUE(layer1->needs_painting());
218  EXPECT_TRUE(layer2->needs_painting());
219  EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
220  EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
221 
222  SkPaint filter_paint1, filter_paint2;
223  filter_paint1.setImageFilter(layer_filter1);
224  filter_paint2.setImageFilter(layer_filter2);
225  layer1->Paint(paint_context());
226  EXPECT_EQ(mock_canvas().draw_calls(),
227  std::vector({
229  0, MockCanvas::SaveLayerData{children_bounds, filter_paint1,
230  nullptr, 1}},
232  1, MockCanvas::DrawPathData{child_path1, child_paint1}},
234  1, MockCanvas::SaveLayerData{child_path2.getBounds(),
235  filter_paint2, nullptr, 2}},
237  2, MockCanvas::DrawPathData{child_path2, child_paint2}},
240  }));
241 }
242 
243 TEST_F(ImageFilterLayerTest, Readback) {
244  auto layer_filter = SkImageFilter::MakeMatrixFilter(
245  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
246  auto initial_transform = SkMatrix();
247 
248  // ImageFilterLayer does not read from surface
249  auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
250  preroll_context()->surface_needs_readback = false;
251  layer->Preroll(preroll_context(), initial_transform);
252  EXPECT_FALSE(preroll_context()->surface_needs_readback);
253 
254  // ImageFilterLayer blocks child with readback
255  auto mock_layer =
256  std::make_shared<MockLayer>(SkPath(), SkPaint(), false, false, true);
257  layer->Add(mock_layer);
258  preroll_context()->surface_needs_readback = false;
259  layer->Preroll(preroll_context(), initial_transform);
260  EXPECT_FALSE(preroll_context()->surface_needs_readback);
261 }
262 
263 TEST_F(ImageFilterLayerTest, ChildIsCached) {
264  auto layer_filter = SkImageFilter::MakeMatrixFilter(
265  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
266  auto initial_transform = SkMatrix::Translate(50.0, 25.5);
267  auto other_transform = SkMatrix::Scale(1.0, 2.0);
268  const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
269  auto mock_layer = std::make_shared<MockLayer>(child_path);
270  auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
271  layer->Add(mock_layer);
272 
273  SkMatrix cache_ctm = initial_transform;
274  SkCanvas cache_canvas;
275  cache_canvas.setMatrix(cache_ctm);
276  SkCanvas other_canvas;
277  other_canvas.setMatrix(other_transform);
278 
279  use_mock_raster_cache();
280 
281  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
282  EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas));
283  EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), cache_canvas));
284 
285  layer->Preroll(preroll_context(), initial_transform);
286 
287  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
288  EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas));
289  EXPECT_TRUE(raster_cache()->Draw(mock_layer.get(), cache_canvas));
290 }
291 
292 TEST_F(ImageFilterLayerTest, ChildrenNotCached) {
293  auto layer_filter = SkImageFilter::MakeMatrixFilter(
294  SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
295  auto initial_transform = SkMatrix::Translate(50.0, 25.5);
296  auto other_transform = SkMatrix::Scale(1.0, 2.0);
297  const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
298  const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
299  auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
300  auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
301  auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
302  layer->Add(mock_layer1);
303  layer->Add(mock_layer2);
304 
305  SkMatrix cache_ctm = initial_transform;
306  SkCanvas cache_canvas;
307  cache_canvas.setMatrix(cache_ctm);
308  SkCanvas other_canvas;
309  other_canvas.setMatrix(other_transform);
310 
311  use_mock_raster_cache();
312 
313  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
314  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas));
315  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas));
316  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas));
317  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas));
318 
319  layer->Preroll(preroll_context(), initial_transform);
320 
321  EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
322  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas));
323  EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas));
324  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas));
325  EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas));
326 }
327 
328 } // namespace testing
329 } // namespace flutter
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:151
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
static constexpr SkRect kEmptyRect
Definition: mock_canvas.h:28