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