Flutter Engine
clip_rect_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/clip_rect_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 
12 namespace flutter {
13 namespace testing {
14 
16 
17 #ifndef NDEBUG
18 TEST_F(ClipRectLayerTest, ClipNoneBehaviorDies) {
19  EXPECT_DEATH_IF_SUPPORTED(
20  auto clip = std::make_shared<ClipRectLayer>(kEmptyRect, Clip::none),
21  "clip_behavior != Clip::none");
22 }
23 
24 TEST_F(ClipRectLayerTest, PaintingEmptyLayerDies) {
25  auto layer = std::make_shared<ClipRectLayer>(kEmptyRect, Clip::hardEdge);
26 
27  layer->Preroll(preroll_context(), SkMatrix());
28  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
29  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
30  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
31  EXPECT_FALSE(layer->needs_painting(paint_context()));
32 
33  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
34  "needs_painting\\(context\\)");
35 }
36 
37 TEST_F(ClipRectLayerTest, PaintBeforePrerollDies) {
38  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
39  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
40  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
41  EXPECT_FALSE(layer->needs_painting(paint_context()));
42 
43  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
44  "needs_painting\\(context\\)");
45 }
46 
47 TEST_F(ClipRectLayerTest, PaintingCulledLayerDies) {
48  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
49  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
50  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
51  const SkRect distant_bounds = SkRect::MakeXYWH(100.0, 100.0, 10.0, 10.0);
52  const SkPath child_path = SkPath().addRect(child_bounds);
53  auto mock_layer = std::make_shared<MockLayer>(child_path);
54  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
55  layer->Add(mock_layer);
56 
57  preroll_context()->cull_rect = distant_bounds; // Cull these children
58 
59  layer->Preroll(preroll_context(), initial_matrix);
60  EXPECT_EQ(preroll_context()->cull_rect, distant_bounds); // Untouched
61  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
62  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
63  EXPECT_EQ(layer->paint_bounds(), child_bounds);
64  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
65  EXPECT_TRUE(layer->needs_painting(paint_context()));
66  EXPECT_EQ(mock_layer->parent_cull_rect(), kEmptyRect);
67  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
68  EXPECT_EQ(mock_layer->parent_mutators(),
69  std::vector({Mutator(layer_bounds)}));
70 
71  paint_context().internal_nodes_canvas->clipRect(distant_bounds, false);
72  EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
73  EXPECT_FALSE(layer->needs_painting(paint_context()));
74  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
75  "needs_painting\\(context\\)");
76 }
77 #endif
78 
79 TEST_F(ClipRectLayerTest, ChildOutsideBounds) {
80  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
81  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
82  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
83  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
84  const SkPath child_path = SkPath().addRect(child_bounds);
85  const SkPaint child_paint = SkPaint(SkColors::kYellow);
86  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
87  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
88  layer->Add(mock_layer);
89 
90  SkRect intersect_bounds = layer_bounds;
91  SkRect child_intersect_bounds = layer_bounds;
92  intersect_bounds.intersect(cull_bounds);
93  child_intersect_bounds.intersect(child_bounds);
94  preroll_context()->cull_rect = cull_bounds; // Cull child
95 
96  layer->Preroll(preroll_context(), initial_matrix);
97  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
98  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
99  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
100  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
101  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
102  EXPECT_TRUE(layer->needs_painting(paint_context()));
103  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
104  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
105  EXPECT_EQ(mock_layer->parent_mutators(),
106  std::vector({Mutator(layer_bounds)}));
107 
108  layer->Paint(paint_context());
109  EXPECT_EQ(
110  mock_canvas().draw_calls(),
111  std::vector(
114  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
115  MockCanvas::kHard_ClipEdgeStyle}},
117  1, MockCanvas::DrawPathData{child_path, child_paint}},
119 }
120 
121 TEST_F(ClipRectLayerTest, FullyContainedChild) {
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 SkPaint child_paint = SkPaint(SkColors::kYellow);
127  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
128  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
129  layer->Add(mock_layer);
130 
131  layer->Preroll(preroll_context(), initial_matrix);
132  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
133  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
134  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
135  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
136  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
137  EXPECT_TRUE(layer->needs_painting(paint_context()));
138  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
139  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
140  EXPECT_EQ(mock_layer->parent_mutators(),
141  std::vector({Mutator(layer_bounds)}));
142 
143  layer->Paint(paint_context());
144  EXPECT_EQ(
145  mock_canvas().draw_calls(),
146  std::vector(
149  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
150  MockCanvas::kHard_ClipEdgeStyle}},
152  1, MockCanvas::DrawPathData{child_path, child_paint}},
154 }
155 
156 TEST_F(ClipRectLayerTest, PartiallyContainedChild) {
157  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
158  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 4.0, 5.5);
159  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
160  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
161  const SkPath child_path = SkPath().addRect(child_bounds);
162  const SkPaint child_paint = SkPaint(SkColors::kYellow);
163  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
164  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
165  layer->Add(mock_layer);
166 
167  SkRect intersect_bounds = layer_bounds;
168  SkRect child_intersect_bounds = layer_bounds;
169  intersect_bounds.intersect(cull_bounds);
170  child_intersect_bounds.intersect(child_bounds);
171  preroll_context()->cull_rect = cull_bounds; // Cull child
172 
173  layer->Preroll(preroll_context(), initial_matrix);
174  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
175  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
176  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
177  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
178  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
179  EXPECT_TRUE(layer->needs_painting(paint_context()));
180  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
181  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
182  EXPECT_EQ(mock_layer->parent_mutators(),
183  std::vector({Mutator(layer_bounds)}));
184 
185  layer->Paint(paint_context());
186  EXPECT_EQ(
187  mock_canvas().draw_calls(),
188  std::vector(
191  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
192  MockCanvas::kHard_ClipEdgeStyle}},
194  1, MockCanvas::DrawPathData{child_path, child_paint}},
196 }
197 
198 static bool ReadbackResult(PrerollContext* context,
199  Clip clip_behavior,
200  std::shared_ptr<Layer> child,
201  bool before) {
202  const SkMatrix initial_matrix = SkMatrix();
203  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
204  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, clip_behavior);
205  if (child != nullptr) {
206  layer->Add(child);
207  }
208  context->surface_needs_readback = before;
209  layer->Preroll(context, initial_matrix);
210  return context->surface_needs_readback;
211 }
212 
213 TEST_F(ClipRectLayerTest, Readback) {
214  PrerollContext* context = preroll_context();
215  SkPath path;
216  SkPaint paint;
217 
218  const Clip hard = Clip::hardEdge;
219  const Clip soft = Clip::antiAlias;
220  const Clip save_layer = Clip::antiAliasWithSaveLayer;
221 
222  std::shared_ptr<MockLayer> nochild;
223  auto reader = std::make_shared<MockLayer>(path, paint, false, true);
224  auto nonreader = std::make_shared<MockLayer>(path, paint);
225 
226  // No children, no prior readback -> no readback after
227  EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
228  EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
229  EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
230 
231  // No children, prior readback -> readback after
232  EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
233  EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
234  EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
235 
236  // Non readback child, no prior readback -> no readback after
237  EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
238  EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
239  EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
240 
241  // Non readback child, prior readback -> readback after
242  EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
243  EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
244  EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
245 
246  // Readback child, no prior readback -> readback after unless SaveLayer
247  EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
248  EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
249  EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
250 
251  // Readback child, prior readback -> readback after
252  EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
253  EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
254  EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
255 }
256 
257 } // namespace testing
258 } // namespace flutter
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
static constexpr SkRect kGiantRect
Definition: layer.h:37
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:151
static bool ReadbackResult(PrerollContext *context, Clip clip_behavior, std::shared_ptr< Layer > child, bool before)
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
Clip
Definition: layer.h:40
static constexpr SkRect kEmptyRect
Definition: mock_canvas.h:28
bool surface_needs_readback
Definition: layer.h:49