Flutter Engine
checkerboard_layertree_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/clip_path_layer.h"
6 #include "flutter/flow/layers/clip_rect_layer.h"
7 #include "flutter/flow/layers/clip_rrect_layer.h"
8 #include "flutter/flow/layers/physical_shape_layer.h"
9 
10 #include "flutter/flow/testing/layer_test.h"
11 #include "flutter/flow/testing/mock_layer.h"
12 #include "flutter/fml/macros.h"
13 #include "flutter/testing/mock_canvas.h"
14 
15 namespace flutter {
16 namespace testing {
17 
19 
20 #ifndef NDEBUG
21 TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerNotCheckBoard) {
22  const SkMatrix initial_matrix = SkMatrix::MakeTrans(0.5f, 1.0f);
23  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
24  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
25  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
26  const SkPath child_path = SkPath().addRect(child_bounds);
27  const SkPaint child_paint = SkPaint(SkColors::kYellow);
28  const SkPaint clip_paint;
29 
30  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
31  auto layer = std::make_shared<ClipRectLayer>(layer_bounds,
33  layer->Add(mock_layer);
34 
35  SkRect intersect_bounds = layer_bounds;
36  SkRect child_intersect_bounds = layer_bounds;
37  intersect_bounds.intersect(cull_bounds);
38  child_intersect_bounds.intersect(child_bounds);
39  preroll_context()->cull_rect = cull_bounds; // Cull child
40 
41  layer->Preroll(preroll_context(), initial_matrix);
42  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
43  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
44  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
45  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
46  EXPECT_TRUE(mock_layer->needs_painting());
47  EXPECT_TRUE(layer->needs_painting());
48  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
49  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
50  EXPECT_EQ(mock_layer->parent_mutators(),
51  std::vector({Mutator(layer_bounds)}));
52 
53  layer->Paint(paint_context());
54 
55  EXPECT_EQ(
56  mock_canvas().draw_calls(),
57  std::vector(
60  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
61  MockCanvas::kSoft_ClipEdgeStyle}},
63  1,
64  MockCanvas::SaveLayerData{layer_bounds, clip_paint, nullptr, 2}},
66  2, MockCanvas::DrawPathData{child_path, child_paint}},
69 }
70 
71 TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) {
72  const SkMatrix initial_matrix = SkMatrix::MakeTrans(0.5f, 1.0f);
73  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
74  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
75  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
76  const SkPath child_path = SkPath().addRect(child_bounds);
77  const SkPaint child_paint = SkPaint(SkColors::kYellow);
78  const SkPaint clip_paint;
79 
80  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
81  auto layer = std::make_shared<ClipRectLayer>(layer_bounds,
83  layer->Add(mock_layer);
84 
85  SkRect intersect_bounds = layer_bounds;
86  SkRect child_intersect_bounds = layer_bounds;
87  intersect_bounds.intersect(cull_bounds);
88  child_intersect_bounds.intersect(child_bounds);
89  preroll_context()->cull_rect = cull_bounds; // Cull child
90 
91  layer->Preroll(preroll_context(), initial_matrix);
92  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
93  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
94  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
95  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
96  EXPECT_TRUE(mock_layer->needs_painting());
97  EXPECT_TRUE(layer->needs_painting());
98  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
99  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
100  EXPECT_EQ(mock_layer->parent_mutators(),
101  std::vector({Mutator(layer_bounds)}));
102 
103  layer->Paint(check_board_context());
104 
105  EXPECT_NE(
106  mock_canvas().draw_calls(),
107  std::vector(
110  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
111  MockCanvas::kSoft_ClipEdgeStyle}},
113  1,
114  MockCanvas::SaveLayerData{layer_bounds, clip_paint, nullptr, 2}},
116  2, MockCanvas::DrawPathData{child_path, child_paint}},
119 }
120 
121 TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerNotCheckBoard) {
122  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
123  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
124  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
125  const SkPath child_path = SkPath().addRect(child_bounds);
126  const SkPath layer_path = SkPath().addRect(layer_bounds);
127  const SkPaint child_paint = SkPaint(SkColors::kYellow);
128  const SkPaint clip_paint;
129  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
130  auto layer =
131  std::make_shared<ClipPathLayer>(layer_path, Clip::antiAliasWithSaveLayer);
132  layer->Add(mock_layer);
133 
134  layer->Preroll(preroll_context(), initial_matrix);
135  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
136  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
137  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
138  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
139  EXPECT_TRUE(mock_layer->needs_painting());
140  EXPECT_TRUE(layer->needs_painting());
141  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
142  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
143  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
144 
145  layer->Paint(paint_context());
146  EXPECT_EQ(
147  mock_canvas().draw_calls(),
148  std::vector(
151  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
152  MockCanvas::kSoft_ClipEdgeStyle}},
154  1,
155  MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
157  2, MockCanvas::DrawPathData{child_path, child_paint}},
160 }
161 
162 TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckBoard) {
163  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
164  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
165  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
166  const SkPath child_path = SkPath().addRect(child_bounds);
167  const SkPath layer_path = SkPath().addRect(layer_bounds);
168  const SkPaint child_paint = SkPaint(SkColors::kYellow);
169  const SkPaint clip_paint;
170  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
171  auto layer =
172  std::make_shared<ClipPathLayer>(layer_path, Clip::antiAliasWithSaveLayer);
173  layer->Add(mock_layer);
174 
175  layer->Preroll(preroll_context(), initial_matrix);
176  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
177  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
178  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
179  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
180  EXPECT_TRUE(mock_layer->needs_painting());
181  EXPECT_TRUE(layer->needs_painting());
182  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
183  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
184  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
185 
186  layer->Paint(check_board_context());
187  EXPECT_NE(
188  mock_canvas().draw_calls(),
189  std::vector(
192  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
193  MockCanvas::kSoft_ClipEdgeStyle}},
195  1,
196  MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
198  2, MockCanvas::DrawPathData{child_path, child_paint}},
201 }
202 
203 TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerNotCheckBoard) {
204  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
205  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
206  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
207  const SkPath child_path = SkPath().addRect(child_bounds);
208  const SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
209  const SkPaint child_paint = SkPaint(SkColors::kYellow);
210  const SkPaint clip_paint;
211  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
212  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect,
214  layer->Add(mock_layer);
215 
216  layer->Preroll(preroll_context(), initial_matrix);
217  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
218  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
219  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
220  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
221  EXPECT_TRUE(mock_layer->needs_painting());
222  EXPECT_TRUE(layer->needs_painting());
223  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
224  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
225  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
226 
227  layer->Paint(paint_context());
228  EXPECT_EQ(
229  mock_canvas().draw_calls(),
230  std::vector(
233  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
234  MockCanvas::kSoft_ClipEdgeStyle}},
236  1,
237  MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
239  2, MockCanvas::DrawPathData{child_path, child_paint}},
242 }
243 
244 TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckBoard) {
245  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
246  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
247  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
248  const SkPath child_path = SkPath().addRect(child_bounds);
249  const SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
250  const SkPaint child_paint = SkPaint(SkColors::kYellow);
251  const SkPaint clip_paint;
252  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
253  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect,
255  layer->Add(mock_layer);
256 
257  layer->Preroll(preroll_context(), initial_matrix);
258  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
259  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
260  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
261  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
262  EXPECT_TRUE(mock_layer->needs_painting());
263  EXPECT_TRUE(layer->needs_painting());
264  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
265  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
266  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
267 
268  layer->Paint(check_board_context());
269  EXPECT_NE(
270  mock_canvas().draw_calls(),
271  std::vector(
274  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
275  MockCanvas::kSoft_ClipEdgeStyle}},
277  1,
278  MockCanvas::SaveLayerData{child_bounds, clip_paint, nullptr, 2}},
280  2, MockCanvas::DrawPathData{child_path, child_paint}},
283 }
284 
285 TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerNotCheckBoard) {
286  constexpr float initial_elevation = 20.0f;
287  SkPath layer_path;
288  layer_path.addRect(0, 0, 8, 8).close();
289  auto layer = std::make_shared<PhysicalShapeLayer>(
290  SK_ColorGREEN, SK_ColorBLACK, initial_elevation, layer_path,
292 
293  layer->Preroll(preroll_context(), SkMatrix());
294  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
295  // their shadows , so we do not do any painting there.
296  EXPECT_EQ(layer->paint_bounds(),
297  PhysicalShapeLayer::ComputeShadowBounds(layer_path.getBounds(),
298  initial_elevation, 1.0f));
299  EXPECT_TRUE(layer->needs_painting());
300  EXPECT_FALSE(layer->needs_system_composite());
301  EXPECT_EQ(layer->elevation(), initial_elevation);
302 
303  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
304  // their shadows , so we do not use the direct |Paint()| path there.
305 #if !defined(LEGACY_FUCHSIA_EMBEDDER)
306  const SkRect paint_bounds = SkRect::MakeXYWH(0, 0, 8, 8);
307  const SkPaint clip_paint;
308  SkPaint layer_paint;
309  layer_paint.setColor(SK_ColorGREEN);
310  layer_paint.setAntiAlias(true);
311  layer->Paint(paint_context());
312  EXPECT_EQ(
313  mock_canvas().draw_calls(),
314  std::vector(
318  1, MockCanvas::ClipRectData{paint_bounds, SkClipOp::kIntersect,
319  MockCanvas::kSoft_ClipEdgeStyle}},
321  1, MockCanvas::SaveLayerData{layer->paint_bounds(), clip_paint,
322  nullptr, 2}},
326 #endif
327 }
328 
329 TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerCheckBoard) {
330  constexpr float initial_elevation = 20.0f;
331  SkPath layer_path;
332  layer_path.addRect(0, 0, 8, 8).close();
333  auto layer = std::make_shared<PhysicalShapeLayer>(
334  SK_ColorGREEN, SK_ColorBLACK, initial_elevation, layer_path,
336 
337  layer->Preroll(preroll_context(), SkMatrix());
338  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
339  // their shadows , so we do not do any painting there.
340  EXPECT_EQ(layer->paint_bounds(),
341  PhysicalShapeLayer::ComputeShadowBounds(layer_path.getBounds(),
342  initial_elevation, 1.0f));
343  EXPECT_TRUE(layer->needs_painting());
344  EXPECT_FALSE(layer->needs_system_composite());
345  EXPECT_EQ(layer->elevation(), initial_elevation);
346 
347  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
348  // their shadows , so we do not use the direct |Paint()| path there.
349 #if !defined(LEGACY_FUCHSIA_EMBEDDER)
350  const SkRect paint_bounds = SkRect::MakeXYWH(0, 0, 8, 8);
351  const SkPaint clip_paint;
352  SkPaint layer_paint;
353  layer_paint.setColor(SK_ColorGREEN);
354  layer_paint.setAntiAlias(true);
355  layer->Paint(check_board_context());
356  EXPECT_NE(
357  mock_canvas().draw_calls(),
358  std::vector(
362  1, MockCanvas::ClipRectData{paint_bounds, SkClipOp::kIntersect,
363  MockCanvas::kSoft_ClipEdgeStyle}},
365  1, MockCanvas::SaveLayerData{layer->paint_bounds(), clip_paint,
366  nullptr, 2}},
370 #endif
371 }
372 
373 #endif
374 } // namespace testing
375 } // namespace flutter
static SkRect ComputeShadowBounds(const SkRect &bounds, float elevation, float pixel_ratio)
static constexpr SkRect kGiantRect
Definition: layer.h:38
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:151
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)