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());
34 
35  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
36  "needs_painting\\(\\)");
37 }
38 
39 TEST_F(ClipRRectLayerTest, PaintBeforePreollDies) {
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());
45 
46  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
47  "needs_painting\\(\\)");
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 SkPath child_path = SkPath().addRect(child_bounds);
55  const SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
56  const SkPaint child_paint = SkPaint(SkColors::kYellow);
57  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
58  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect, Clip::hardEdge);
59  layer->Add(mock_layer);
60 
61  preroll_context()->cull_rect = kEmptyRect; // Cull everything
62 
63  layer->Preroll(preroll_context(), initial_matrix);
64  EXPECT_EQ(preroll_context()->cull_rect, kEmptyRect); // Untouched
65  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
66  EXPECT_EQ(mock_layer->paint_bounds(), kEmptyRect);
67  EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
68  EXPECT_FALSE(mock_layer->needs_painting());
69  EXPECT_FALSE(layer->needs_painting());
70  EXPECT_EQ(mock_layer->parent_cull_rect(), kEmptyRect);
71  EXPECT_EQ(mock_layer->parent_matrix(), SkMatrix());
72  EXPECT_EQ(mock_layer->parent_mutators(), std::vector<Mutator>());
73 
74  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
75  "needs_painting\\(\\)");
76 }
77 #endif
78 
79 TEST_F(ClipRRectLayerTest, 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 SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
86  const SkPaint child_paint = SkPaint(SkColors::kYellow);
87  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
88  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect, Clip::hardEdge);
89  layer->Add(mock_layer);
90 
91  SkRect intersect_bounds = layer_bounds;
92  SkRect child_intersect_bounds = layer_bounds;
93  intersect_bounds.intersect(cull_bounds);
94  child_intersect_bounds.intersect(child_bounds);
95  preroll_context()->cull_rect = cull_bounds; // Cull child
96 
97  layer->Preroll(preroll_context(), initial_matrix);
98  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
99  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
100  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
101  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
102  EXPECT_TRUE(mock_layer->needs_painting());
103  EXPECT_TRUE(layer->needs_painting());
104  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
105  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
106  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
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(ClipRRectLayerTest, 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 SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
127  const SkPaint child_paint = SkPaint(SkColors::kYellow);
128  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
129  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect, Clip::hardEdge);
130  layer->Add(mock_layer);
131 
132  layer->Preroll(preroll_context(), initial_matrix);
133  EXPECT_EQ(preroll_context()->cull_rect, kGiantRect); // Untouched
134  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
135  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
136  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
137  EXPECT_TRUE(mock_layer->needs_painting());
138  EXPECT_TRUE(layer->needs_painting());
139  EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
140  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
141  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
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(ClipRRectLayerTest, 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 SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
163  const SkPaint child_paint = SkPaint(SkColors::kYellow);
164  auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
165  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect, Clip::hardEdge);
166  layer->Add(mock_layer);
167 
168  SkRect intersect_bounds = layer_bounds;
169  SkRect child_intersect_bounds = layer_bounds;
170  intersect_bounds.intersect(cull_bounds);
171  child_intersect_bounds.intersect(child_bounds);
172  preroll_context()->cull_rect = cull_bounds; // Cull child
173 
174  layer->Preroll(preroll_context(), initial_matrix);
175  EXPECT_EQ(preroll_context()->cull_rect, cull_bounds); // Untouched
176  EXPECT_TRUE(preroll_context()->mutators_stack.is_empty()); // Untouched
177  EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
178  EXPECT_EQ(layer->paint_bounds(), child_intersect_bounds);
179  EXPECT_TRUE(mock_layer->needs_painting());
180  EXPECT_TRUE(layer->needs_painting());
181  EXPECT_EQ(mock_layer->parent_cull_rect(), intersect_bounds);
182  EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
183  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)}));
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  const SkRRect layer_rrect = SkRRect::MakeRect(layer_bounds);
205  auto layer = std::make_shared<ClipRRectLayer>(layer_rrect, clip_behavior);
206  if (child != nullptr) {
207  layer->Add(child);
208  }
209  context->surface_needs_readback = before;
210  layer->Preroll(context, initial_matrix);
211  return context->surface_needs_readback;
212 }
213 
214 TEST_F(ClipRRectLayerTest, Readback) {
215  PrerollContext* context = preroll_context();
216  SkPath path;
217  SkPaint paint;
218 
219  const Clip hard = Clip::hardEdge;
220  const Clip soft = Clip::antiAlias;
221  const Clip save_layer = Clip::antiAliasWithSaveLayer;
222 
223  std::shared_ptr<MockLayer> nochild;
224  auto reader = std::make_shared<MockLayer>(path, paint, false, false, true);
225  auto nonreader = std::make_shared<MockLayer>(path, paint);
226 
227  // No children, no prior readback -> no readback after
228  EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
229  EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
230  EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
231 
232  // No children, prior readback -> readback after
233  EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
234  EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
235  EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
236 
237  // Non readback child, no prior readback -> no readback after
238  EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
239  EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
240  EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
241 
242  // Non readback child, prior readback -> readback after
243  EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
244  EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
245  EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
246 
247  // Readback child, no prior readback -> readback after unless SaveLayer
248  EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
249  EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
250  EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
251 
252  // Readback child, prior readback -> readback after
253  EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
254  EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
255  EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
256 }
257 
258 } // namespace testing
259 } // 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