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());
32 
33  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
34  "needs_painting\\(\\)");
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());
42 
43  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
44  "needs_painting\\(\\)");
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 SkPath child_path = SkPath().addRect(child_bounds);
52  auto mock_layer = std::make_shared<MockLayer>(child_path);
53  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
54  layer->Add(mock_layer);
55 
56  preroll_context()->cull_rect = kEmptyRect; // Cull everything
57 
58  layer->Preroll(preroll_context(), initial_matrix);
59  EXPECT_EQ(preroll_context()->cull_rect, kEmptyRect); // Untouched
60  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
61  EXPECT_EQ(mock_layer->paint_bounds(), kEmptyRect);
62  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
63  EXPECT_FALSE(mock_layer->needs_painting());
64  EXPECT_FALSE(layer->needs_painting());
65  EXPECT_EQ(mock_layer->parent_cull_rect(), kEmptyRect);
66  EXPECT_EQ(mock_layer->parent_matrix(), SkMatrix());
67  EXPECT_EQ(mock_layer->parent_mutators(), std::vector<Mutator>());
68 
69  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
70  "needs_painting\\(\\)");
71 }
72 #endif
73 
74 TEST_F(ClipRectLayerTest, ChildOutsideBounds) {
75  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
76  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
77  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
78  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
79  const SkPath child_path = SkPath().addRect(child_bounds);
80  const SkPaint child_paint = SkPaint(SkColors::kYellow);
81  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
82  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
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(paint_context());
104  EXPECT_EQ(
105  mock_canvas().draw_calls(),
106  std::vector(
109  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
110  MockCanvas::kHard_ClipEdgeStyle}},
112  1, MockCanvas::DrawPathData{child_path, child_paint}},
114 }
115 
116 TEST_F(ClipRectLayerTest, FullyContainedChild) {
117  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
118  const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
119  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
120  const SkPath child_path = SkPath().addRect(child_bounds);
121  const SkPaint child_paint = SkPaint(SkColors::kYellow);
122  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
123  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
124  layer->Add(mock_layer);
125 
126  layer->Preroll(preroll_context(), initial_matrix);
127  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
128  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
129  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
130  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
131  EXPECT_TRUE(mock_layer->needs_painting());
132  EXPECT_TRUE(layer->needs_painting());
133  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
134  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
135  EXPECT_EQ(mock_layer->parent_mutators(),
136  std::vector({Mutator(layer_bounds)}));
137 
138  layer->Paint(paint_context());
139  EXPECT_EQ(
140  mock_canvas().draw_calls(),
141  std::vector(
144  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
145  MockCanvas::kHard_ClipEdgeStyle}},
147  1, MockCanvas::DrawPathData{child_path, child_paint}},
149 }
150 
151 TEST_F(ClipRectLayerTest, PartiallyContainedChild) {
152  const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
153  const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 4.0, 5.5);
154  const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
155  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
156  const SkPath child_path = SkPath().addRect(child_bounds);
157  const SkPaint child_paint = SkPaint(SkColors::kYellow);
158  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
159  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, Clip::hardEdge);
160  layer->Add(mock_layer);
161 
162  SkRect intersect_bounds = layer_bounds;
163  SkRect child_intersect_bounds = layer_bounds;
164  intersect_bounds.intersect(cull_bounds);
165  child_intersect_bounds.intersect(child_bounds);
166  preroll_context()->cull_rect = cull_bounds; // Cull child
167 
168  layer->Preroll(preroll_context(), initial_matrix);
169  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
170  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
171  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
172  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
173  EXPECT_TRUE(mock_layer->needs_painting());
174  EXPECT_TRUE(layer->needs_painting());
175  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
176  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
177  EXPECT_EQ(mock_layer->parent_mutators(),
178  std::vector({Mutator(layer_bounds)}));
179 
180  layer->Paint(paint_context());
181  EXPECT_EQ(
182  mock_canvas().draw_calls(),
183  std::vector(
186  1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
187  MockCanvas::kHard_ClipEdgeStyle}},
189  1, MockCanvas::DrawPathData{child_path, child_paint}},
191 }
192 
193 static bool ReadbackResult(PrerollContext* context,
194  Clip clip_behavior,
195  std::shared_ptr<Layer> child,
196  bool before) {
197  const SkMatrix initial_matrix = SkMatrix();
198  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
199  auto layer = std::make_shared<ClipRectLayer>(layer_bounds, clip_behavior);
200  if (child != nullptr) {
201  layer->Add(child);
202  }
203  context->surface_needs_readback = before;
204  layer->Preroll(context, initial_matrix);
205  return context->surface_needs_readback;
206 }
207 
208 TEST_F(ClipRectLayerTest, Readback) {
209  PrerollContext* context = preroll_context();
210  SkPath path;
211  SkPaint paint;
212 
213  const Clip hard = Clip::hardEdge;
214  const Clip soft = Clip::antiAlias;
215  const Clip save_layer = Clip::antiAliasWithSaveLayer;
216 
217  std::shared_ptr<MockLayer> nochild;
218  auto reader = std::make_shared<MockLayer>(path, paint, false, false, true);
219  auto nonreader = std::make_shared<MockLayer>(path, paint);
220 
221  // No children, no prior readback -> no readback after
222  EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
223  EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
224  EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
225 
226  // No children, prior readback -> readback after
227  EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
228  EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
229  EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
230 
231  // Non readback child, no prior readback -> no readback after
232  EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
233  EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
234  EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
235 
236  // Non readback child, prior readback -> readback after
237  EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
238  EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
239  EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
240 
241  // Readback child, no prior readback -> readback after unless SaveLayer
242  EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
243  EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
244  EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
245 
246  // Readback child, prior readback -> readback after
247  EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
248  EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
249  EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
250 }
251 
252 } // namespace testing
253 } // 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