Flutter Engine
shader_mask_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/shader_mask_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/SkShader.h"
12 #include "third_party/skia/include/effects/SkPerlinNoiseShader.h"
13 
14 namespace flutter {
15 namespace testing {
16 
18 
19 #ifndef NDEBUG
20 TEST_F(ShaderMaskLayerTest, PaintingEmptyLayerDies) {
21  auto layer =
22  std::make_shared<ShaderMaskLayer>(nullptr, kEmptyRect, SkBlendMode::kSrc);
23 
24  layer->Preroll(preroll_context(), SkMatrix());
25  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
26  EXPECT_FALSE(layer->needs_painting());
27 
28  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
29  "needs_painting\\(\\)");
30 }
31 
32 TEST_F(ShaderMaskLayerTest, PaintBeforePreollDies) {
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 =
37  std::make_shared<ShaderMaskLayer>(nullptr, kEmptyRect, SkBlendMode::kSrc);
38  layer->Add(mock_layer);
39 
40  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
41  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
42  "needs_painting\\(\\)");
43 }
44 #endif
45 
46 TEST_F(ShaderMaskLayerTest, EmptyFilter) {
47  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
48  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
49  const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 6.5f, 6.5f);
50  const SkPath child_path = SkPath().addRect(child_bounds);
51  const SkPaint child_paint = SkPaint(SkColors::kYellow);
52  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
53  auto layer = std::make_shared<ShaderMaskLayer>(nullptr, layer_bounds,
54  SkBlendMode::kSrc);
55  layer->Add(mock_layer);
56 
57  layer->Preroll(preroll_context(), initial_transform);
58  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
59  EXPECT_EQ(layer->paint_bounds(), child_bounds);
60  EXPECT_TRUE(mock_layer->needs_painting());
61  EXPECT_TRUE(layer->needs_painting());
62  EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
63 
64  SkPaint filter_paint;
65  filter_paint.setBlendMode(SkBlendMode::kSrc);
66  filter_paint.setShader(nullptr);
67  layer->Paint(paint_context());
68  EXPECT_EQ(
69  mock_canvas().draw_calls(),
70  std::vector({MockCanvas::DrawCall{
71  0, MockCanvas::SaveLayerData{child_bounds, SkPaint(),
72  nullptr, 1}},
74  1, MockCanvas::DrawPathData{child_path, child_paint}},
76  1, MockCanvas::ConcatMatrixData{SkMatrix::Translate(
77  layer_bounds.fLeft, layer_bounds.fTop)}},
79  1, MockCanvas::DrawRectData{SkRect::MakeWH(
80  layer_bounds.width(),
81  layer_bounds.height()),
82  filter_paint}},
84 }
85 
86 TEST_F(ShaderMaskLayerTest, SimpleFilter) {
87  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
88  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
89  const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 6.5f, 6.5f);
90  const SkPath child_path = SkPath().addRect(child_bounds);
91  const SkPaint child_paint = SkPaint(SkColors::kYellow);
92  auto layer_filter =
93  SkPerlinNoiseShader::MakeImprovedNoise(1.0f, 1.0f, 1, 1.0f);
94  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
95  auto layer = std::make_shared<ShaderMaskLayer>(layer_filter, layer_bounds,
96  SkBlendMode::kSrc);
97  layer->Add(mock_layer);
98 
99  layer->Preroll(preroll_context(), initial_transform);
100  EXPECT_EQ(layer->paint_bounds(), child_bounds);
101  EXPECT_TRUE(layer->needs_painting());
102  EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
103 
104  SkPaint filter_paint;
105  filter_paint.setBlendMode(SkBlendMode::kSrc);
106  filter_paint.setShader(layer_filter);
107  layer->Paint(paint_context());
108  EXPECT_EQ(
109  mock_canvas().draw_calls(),
110  std::vector({MockCanvas::DrawCall{
111  0, MockCanvas::SaveLayerData{child_bounds, SkPaint(),
112  nullptr, 1}},
114  1, MockCanvas::DrawPathData{child_path, child_paint}},
116  1, MockCanvas::ConcatMatrixData{SkMatrix::Translate(
117  layer_bounds.fLeft, layer_bounds.fTop)}},
119  1, MockCanvas::DrawRectData{SkRect::MakeWH(
120  layer_bounds.width(),
121  layer_bounds.height()),
122  filter_paint}},
124 }
125 
126 TEST_F(ShaderMaskLayerTest, MultipleChildren) {
127  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
128  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
129  const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 6.5f, 6.5f);
130  const SkPath child_path1 = SkPath().addRect(child_bounds);
131  const SkPath child_path2 =
132  SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
133  const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
134  const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
135  auto layer_filter =
136  SkPerlinNoiseShader::MakeImprovedNoise(1.0f, 1.0f, 1, 1.0f);
137  auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
138  auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
139  auto layer = std::make_shared<ShaderMaskLayer>(layer_filter, layer_bounds,
140  SkBlendMode::kSrc);
141  layer->Add(mock_layer1);
142  layer->Add(mock_layer2);
143 
144  SkRect children_bounds = child_path1.getBounds();
145  children_bounds.join(child_path2.getBounds());
146  layer->Preroll(preroll_context(), initial_transform);
147  EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
148  EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
149  EXPECT_EQ(layer->paint_bounds(), children_bounds);
150  EXPECT_TRUE(mock_layer1->needs_painting());
151  EXPECT_TRUE(mock_layer2->needs_painting());
152  EXPECT_TRUE(layer->needs_painting());
153  EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
154  EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
155 
156  SkPaint filter_paint;
157  filter_paint.setBlendMode(SkBlendMode::kSrc);
158  filter_paint.setShader(layer_filter);
159  layer->Paint(paint_context());
160  EXPECT_EQ(
161  mock_canvas().draw_calls(),
162  std::vector({MockCanvas::DrawCall{
163  0, MockCanvas::SaveLayerData{children_bounds, SkPaint(),
164  nullptr, 1}},
166  1, MockCanvas::DrawPathData{child_path1, child_paint1}},
168  1, MockCanvas::DrawPathData{child_path2, child_paint2}},
170  1, MockCanvas::ConcatMatrixData{SkMatrix::Translate(
171  layer_bounds.fLeft, layer_bounds.fTop)}},
173  1, MockCanvas::DrawRectData{SkRect::MakeWH(
174  layer_bounds.width(),
175  layer_bounds.height()),
176  filter_paint}},
178 }
179 
180 TEST_F(ShaderMaskLayerTest, Nested) {
181  const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
182  const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 7.5f, 8.5f);
183  const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 20.5f, 20.5f);
184  const SkPath child_path1 = SkPath().addRect(child_bounds);
185  const SkPath child_path2 =
186  SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
187  const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
188  const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
189  auto layer_filter1 =
190  SkPerlinNoiseShader::MakeImprovedNoise(1.0f, 1.0f, 1, 1.0f);
191  auto layer_filter2 =
192  SkPerlinNoiseShader::MakeImprovedNoise(2.0f, 2.0f, 2, 2.0f);
193  auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
194  auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
195  auto layer1 = std::make_shared<ShaderMaskLayer>(layer_filter1, layer_bounds,
196  SkBlendMode::kSrc);
197  auto layer2 = std::make_shared<ShaderMaskLayer>(layer_filter2, layer_bounds,
198  SkBlendMode::kSrc);
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(child_path2.getBounds());
205  layer1->Preroll(preroll_context(), initial_transform);
206  EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
207  EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
208  EXPECT_EQ(layer1->paint_bounds(), children_bounds);
209  EXPECT_EQ(layer2->paint_bounds(), mock_layer2->paint_bounds());
210  EXPECT_TRUE(mock_layer1->needs_painting());
211  EXPECT_TRUE(mock_layer2->needs_painting());
212  EXPECT_TRUE(layer1->needs_painting());
213  EXPECT_TRUE(layer2->needs_painting());
214  EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
215  EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
216 
217  SkPaint filter_paint1, filter_paint2;
218  filter_paint1.setBlendMode(SkBlendMode::kSrc);
219  filter_paint2.setBlendMode(SkBlendMode::kSrc);
220  filter_paint1.setShader(layer_filter1);
221  filter_paint2.setShader(layer_filter2);
222  layer1->Paint(paint_context());
223  EXPECT_EQ(
224  mock_canvas().draw_calls(),
225  std::vector(
227  0, MockCanvas::SaveLayerData{children_bounds, SkPaint(), nullptr,
228  1}},
230  1, MockCanvas::DrawPathData{child_path1, child_paint1}},
232  1, MockCanvas::SaveLayerData{child_path2.getBounds(), SkPaint(),
233  nullptr, 2}},
235  2, MockCanvas::DrawPathData{child_path2, child_paint2}},
237  2, MockCanvas::ConcatMatrixData{SkMatrix::Translate(
238  layer_bounds.fLeft, layer_bounds.fTop)}},
240  2,
242  SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()),
243  filter_paint2}},
246  1, MockCanvas::ConcatMatrixData{SkMatrix::Translate(
247  layer_bounds.fLeft, layer_bounds.fTop)}},
249  1,
251  SkRect::MakeWH(layer_bounds.width(), layer_bounds.height()),
252  filter_paint1}},
254 }
255 
256 TEST_F(ShaderMaskLayerTest, Readback) {
257  auto initial_transform = SkMatrix();
258  const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 20.5f, 20.5f);
259  auto layer_filter =
260  SkPerlinNoiseShader::MakeImprovedNoise(1.0f, 1.0f, 1, 1.0f);
261  auto layer = std::make_shared<ShaderMaskLayer>(layer_filter, layer_bounds,
262  SkBlendMode::kSrc);
263 
264  // ShaderMaskLayer does not read from surface
265  preroll_context()->surface_needs_readback = false;
266  layer->Preroll(preroll_context(), initial_transform);
267  EXPECT_FALSE(preroll_context()->surface_needs_readback);
268 
269  // ShaderMaskLayer blocks child with readback
270  auto mock_layer =
271  std::make_shared<MockLayer>(SkPath(), SkPaint(), false, false, true);
272  layer->Add(mock_layer);
273  preroll_context()->surface_needs_readback = false;
274  layer->Preroll(preroll_context(), initial_transform);
275  EXPECT_FALSE(preroll_context()->surface_needs_readback);
276 }
277 
278 } // namespace testing
279 } // namespace flutter
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:151
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
static constexpr SkRect kEmptyRect
Definition: mock_canvas.h:28