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(paint_context()));
32 
33  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
34  "needs_painting\\(context\\)");
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(paint_context()));
43 
44  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
45  "needs_painting\\(context\\)");
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 SkRect distant_bounds = SkRect::MakeXYWH(100.0, 100.0, 10.0, 10.0);
53  const SkPath child_path = SkPath().addRect(child_bounds);
54  const SkPath layer_path = SkPath().addRect(layer_bounds);
55  auto mock_layer = std::make_shared<MockLayer>(child_path);
56  auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::hardEdge);
57  layer->Add(mock_layer);
58 
59  preroll_context()->cull_rect = distant_bounds; // Cull these children
60 
61  layer->Preroll(preroll_context(), initial_matrix);
62  EXPECT_EQ(preroll_context()->cull_rect, distant_bounds); // Untouched
63  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
64  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
65  EXPECT_EQ(layer->paint_bounds(), child_bounds);
66  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
67  EXPECT_TRUE(layer->needs_painting(paint_context()));
68  EXPECT_EQ(mock_layer->parent_cull_rect(), kEmptyRect);
69  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
70  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
71 
72  paint_context().internal_nodes_canvas->clipRect(distant_bounds, false);
73  EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
74  EXPECT_FALSE(layer->needs_painting(paint_context()));
75  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
76  "needs_painting\\(context\\)");
77 }
78 #endif
79 
80 TEST_F(ClipPathLayerTest, ChildOutsideBounds) {
81  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
82  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
83  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
84  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
85  const SkPath child_path = SkPath().addRect(child_bounds);
86  const SkPath layer_path = SkPath().addRect(layer_bounds);
87  const SkPaint child_paint = SkPaint(SkColors::kYellow);
88  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
89  auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::hardEdge);
90  layer->Add(mock_layer);
91 
92  SkRect intersect_bounds = layer_bounds;
93  SkRect child_intersect_bounds = layer_bounds;
94  intersect_bounds.intersect(cull_bounds);
95  child_intersect_bounds.intersect(child_bounds);
96  preroll_context()->cull_rect = cull_bounds; // Cull child
97 
98  layer->Preroll(preroll_context(), initial_matrix);
99  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
100  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
101  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
102  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
103  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
104  EXPECT_TRUE(layer->needs_painting(paint_context()));
105  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
106  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
107  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
108 
109  layer->Paint(paint_context());
110  EXPECT_EQ(
111  mock_canvas().draw_calls(),
112  std::vector(
115  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
116  MockCanvas::kHard_ClipEdgeStyle}},
118  1, MockCanvas::DrawPathData{child_path, child_paint}},
120 }
121 
122 TEST_F(ClipPathLayerTest, FullyContainedChild) {
123  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
124  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
125  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
126  const SkPath child_path = SkPath().addRect(child_bounds);
127  const SkPath layer_path = SkPath().addRect(layer_bounds);
128  const SkPaint child_paint = SkPaint(SkColors::kYellow);
129  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
130  auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::hardEdge);
131  layer->Add(mock_layer);
132 
133  layer->Preroll(preroll_context(), initial_matrix);
134  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
135  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
136  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
137  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
138  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
139  EXPECT_TRUE(layer->needs_painting(paint_context()));
140  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
141  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
142  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
143 
144  layer->Paint(paint_context());
145  EXPECT_EQ(
146  mock_canvas().draw_calls(),
147  std::vector(
150  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
151  MockCanvas::kHard_ClipEdgeStyle}},
153  1, MockCanvas::DrawPathData{child_path, child_paint}},
155 }
156 
157 TEST_F(ClipPathLayerTest, PartiallyContainedChild) {
158  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
159  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 4.0, 5.5);
160  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
161  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
162  const SkPath child_path = SkPath().addRect(child_bounds);
163  const SkPath layer_path = SkPath().addRect(layer_bounds);
164  const SkPaint child_paint = SkPaint(SkColors::kYellow);
165  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
166  auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::hardEdge);
167  layer->Add(mock_layer);
168 
169  SkRect intersect_bounds = layer_bounds;
170  SkRect child_intersect_bounds = layer_bounds;
171  intersect_bounds.intersect(cull_bounds);
172  child_intersect_bounds.intersect(child_bounds);
173  preroll_context()->cull_rect = cull_bounds; // Cull child
174 
175  layer->Preroll(preroll_context(), initial_matrix);
176  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // 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(), child_intersect_bounds);
180  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
181  EXPECT_TRUE(layer->needs_painting(paint_context()));
182  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_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(paint_context());
187  EXPECT_EQ(
188  mock_canvas().draw_calls(),
189  std::vector(
192  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
193  MockCanvas::kHard_ClipEdgeStyle}},
195  1, MockCanvas::DrawPathData{child_path, child_paint}},
197 }
198 
199 static bool ReadbackResult(PrerollContext* context,
200  Clip clip_behavior,
201  std::shared_ptr<Layer> child,
202  bool before) {
203  const SkMatrix initial_matrix = SkMatrix();
204  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
205  const SkPath layer_path = SkPath().addRect(layer_bounds);
206  auto layer = std::make_shared<ClipPathLayer>(layer_path, clip_behavior);
207  if (child != nullptr) {
208  layer->Add(child);
209  }
210  context->surface_needs_readback = before;
211  layer->Preroll(context, initial_matrix);
212  return context->surface_needs_readback;
213 }
214 
215 TEST_F(ClipPathLayerTest, Readback) {
216  PrerollContext* context = preroll_context();
217  SkPath path;
218  SkPaint paint;
219 
220  const Clip hard = Clip::hardEdge;
221  const Clip soft = Clip::antiAlias;
222  const Clip save_layer = Clip::antiAliasWithSaveLayer;
223 
224  std::shared_ptr<MockLayer> nochild;
225  auto reader = std::make_shared<MockLayer>(path, paint, false, true);
226  auto nonreader = std::make_shared<MockLayer>(path, paint);
227 
228  // No children, no prior readback -> no readback after
229  EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
230  EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
231  EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
232 
233  // No children, prior readback -> readback after
234  EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
235  EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
236  EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
237 
238  // Non readback child, no prior readback -> no readback after
239  EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
240  EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
241  EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
242 
243  // Non readback child, prior readback -> readback after
244  EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
245  EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
246  EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
247 
248  // Readback child, no prior readback -> readback after unless SaveLayer
249  EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
250  EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
251  EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
252 
253  // Readback child, prior readback -> readback after
254  EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
255  EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
256  EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
257 }
258 
259 } // namespace testing
260 } // namespace flutter
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)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
Clip
Definition: layer.h:40
static constexpr SkRect kEmptyRect
Definition: mock_canvas.h:28
bool surface_needs_readback
Definition: layer.h:49