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