Flutter Engine
physical_shape_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/physical_shape_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(PhysicalShapeLayerTest, PaintingEmptyLayerDies) {
19  auto layer =
20  std::make_shared<PhysicalShapeLayer>(SK_ColorBLACK, SK_ColorBLACK,
21  0.0f, // elevation
22  SkPath(), Clip::none);
23 
24  layer->Preroll(preroll_context(), SkMatrix());
25  EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
26  EXPECT_FALSE(layer->needs_painting());
27  EXPECT_FALSE(layer->needs_system_composite());
28 
29  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
30  "needs_painting\\(\\)");
31 }
32 
33 TEST_F(PhysicalShapeLayerTest, PaintBeforePreollDies) {
34  SkPath child_path;
35  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
36  auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
37  auto layer =
38  std::make_shared<PhysicalShapeLayer>(SK_ColorBLACK, SK_ColorBLACK,
39  0.0f, // elevation
40  SkPath(), Clip::none);
41  layer->Add(mock_layer);
42 
43  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
44  "needs_painting\\(\\)");
45 }
46 #endif
47 
48 TEST_F(PhysicalShapeLayerTest, NonEmptyLayer) {
49  SkPath layer_path;
50  layer_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
51  auto layer =
52  std::make_shared<PhysicalShapeLayer>(SK_ColorGREEN, SK_ColorBLACK,
53  0.0f, // elevation
54  layer_path, Clip::none);
55  layer->Preroll(preroll_context(), SkMatrix());
56  EXPECT_EQ(layer->paint_bounds(), layer_path.getBounds());
57  EXPECT_TRUE(layer->needs_painting());
58  EXPECT_FALSE(layer->needs_system_composite());
59 
60  SkPaint layer_paint;
61  layer_paint.setColor(SK_ColorGREEN);
62  layer_paint.setAntiAlias(true);
63  layer->Paint(paint_context());
64  EXPECT_EQ(mock_canvas().draw_calls(),
65  std::vector({MockCanvas::DrawCall{
66  0, MockCanvas::DrawPathData{layer_path, layer_paint}}}));
67 }
68 
69 TEST_F(PhysicalShapeLayerTest, ChildrenLargerThanPath) {
70  SkPath layer_path;
71  layer_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
72  SkPath child1_path;
73  child1_path.addRect(4, 0, 12, 12).close();
74  SkPath child2_path;
75  child2_path.addRect(3, 2, 5, 15).close();
76  auto child1 = std::make_shared<PhysicalShapeLayer>(SK_ColorRED, SK_ColorBLACK,
77  0.0f, // elevation
78  child1_path, Clip::none);
79  auto child2 =
80  std::make_shared<PhysicalShapeLayer>(SK_ColorBLUE, SK_ColorBLACK,
81  0.0f, // elevation
82  child2_path, Clip::none);
83  auto layer =
84  std::make_shared<PhysicalShapeLayer>(SK_ColorGREEN, SK_ColorBLACK,
85  0.0f, // elevation
86  layer_path, Clip::none);
87  layer->Add(child1);
88  layer->Add(child2);
89 
90  SkRect child_paint_bounds;
91  layer->Preroll(preroll_context(), SkMatrix());
92  child_paint_bounds.join(child1->paint_bounds());
93  child_paint_bounds.join(child2->paint_bounds());
94  EXPECT_EQ(layer->paint_bounds(), layer_path.getBounds());
95  EXPECT_NE(layer->paint_bounds(), child_paint_bounds);
96  EXPECT_TRUE(layer->needs_painting());
97  EXPECT_FALSE(layer->needs_system_composite());
98 
99  SkPaint layer_paint;
100  layer_paint.setColor(SK_ColorGREEN);
101  layer_paint.setAntiAlias(true);
102  SkPaint child1_paint;
103  child1_paint.setColor(SK_ColorRED);
104  child1_paint.setAntiAlias(true);
105  SkPaint child2_paint;
106  child2_paint.setColor(SK_ColorBLUE);
107  child2_paint.setAntiAlias(true);
108  layer->Paint(paint_context());
109  EXPECT_EQ(
110  mock_canvas().draw_calls(),
111  std::vector({MockCanvas::DrawCall{
112  0, MockCanvas::DrawPathData{layer_path, layer_paint}},
114  0, MockCanvas::DrawPathData{child1_path, child1_paint}},
116  child2_path, child2_paint}}}));
117 }
118 
119 TEST_F(PhysicalShapeLayerTest, ElevationSimple) {
120  constexpr float initial_elevation = 20.0f;
121  SkPath layer_path;
122  layer_path.addRect(0, 0, 8, 8).close();
123  auto layer = std::make_shared<PhysicalShapeLayer>(
124  SK_ColorGREEN, SK_ColorBLACK, initial_elevation, layer_path, Clip::none);
125 
126  layer->Preroll(preroll_context(), SkMatrix());
127  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
128  // their shadows , so we do not do any painting there.
129  EXPECT_EQ(layer->paint_bounds(),
130  PhysicalShapeLayer::ComputeShadowBounds(layer_path.getBounds(),
131  initial_elevation, 1.0f));
132  EXPECT_TRUE(layer->needs_painting());
133  EXPECT_FALSE(layer->needs_system_composite());
134  EXPECT_EQ(layer->elevation(), initial_elevation);
135 
136  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
137  // their shadows , so we do not use the direct |Paint()| path there.
138 #if !defined(LEGACY_FUCHSIA_EMBEDDER)
139  SkPaint layer_paint;
140  layer_paint.setColor(SK_ColorGREEN);
141  layer_paint.setAntiAlias(true);
142  layer->Paint(paint_context());
143  EXPECT_EQ(
144  mock_canvas().draw_calls(),
145  std::vector(
148  0, MockCanvas::DrawPathData{layer_path, layer_paint}}}));
149 #endif
150 }
151 
152 TEST_F(PhysicalShapeLayerTest, ElevationComplex) {
153  // The layer tree should look like this:
154  // layers[0] +1.0f = 1.0f
155  // | \
156  // | \
157  // | \
158  // | layers[2] +3.0f = 4.0f
159  // | |
160  // | layers[3] +4.0f = 8.0f
161  // |
162  // |
163  // layers[1] + 2.0f = 3.0f
164  constexpr float initial_elevations[4] = {1.0f, 2.0f, 3.0f, 4.0f};
165  SkPath layer_path;
166  layer_path.addRect(0, 0, 80, 80).close();
167 
168  std::shared_ptr<PhysicalShapeLayer> layers[4];
169  for (int i = 0; i < 4; i += 1) {
170  layers[i] = std::make_shared<PhysicalShapeLayer>(
171  SK_ColorBLACK, SK_ColorBLACK, initial_elevations[i], layer_path,
172  Clip::none);
173  }
174  layers[0]->Add(layers[1]);
175  layers[0]->Add(layers[2]);
176  layers[2]->Add(layers[3]);
177 
178  layers[0]->Preroll(preroll_context(), SkMatrix());
179  for (int i = 0; i < 4; i += 1) {
180  // On Fuchsia, the system compositor handles all elevated
181  // PhysicalShapeLayers and their shadows , so we do not do any painting
182  // there.
183  EXPECT_EQ(layers[i]->paint_bounds(),
185  layer_path.getBounds(), initial_elevations[i],
186  1.0f /* pixel_ratio */)));
187  EXPECT_TRUE(layers[i]->needs_painting());
188  EXPECT_FALSE(layers[i]->needs_system_composite());
189  }
190 
191  // The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
192  // their shadows , so we do not use the direct |Paint()| path there.
193 #if !defined(LEGACY_FUCHSIA_EMBEDDER)
194  SkPaint layer_paint;
195  layer_paint.setColor(SK_ColorBLACK);
196  layer_paint.setAntiAlias(true);
197  layers[0]->Paint(paint_context());
198  EXPECT_EQ(
199  mock_canvas().draw_calls(),
200  std::vector(
203  0, MockCanvas::DrawPathData{layer_path, layer_paint}},
206  0, MockCanvas::DrawPathData{layer_path, layer_paint}},
209  0, MockCanvas::DrawPathData{layer_path, layer_paint}},
212  0, MockCanvas::DrawPathData{layer_path, layer_paint}}}));
213 #endif
214 }
215 
216 static bool ReadbackResult(PrerollContext* context,
217  Clip clip_behavior,
218  std::shared_ptr<Layer> child,
219  bool before) {
220  const SkMatrix initial_matrix = SkMatrix();
221  const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
222  const SkPath layer_path = SkPath().addRect(layer_bounds);
223  auto layer =
224  std::make_shared<PhysicalShapeLayer>(SK_ColorGREEN, SK_ColorBLACK,
225  0.0f, // elevation
226  layer_path, clip_behavior);
227  if (child != nullptr) {
228  layer->Add(child);
229  }
230  context->surface_needs_readback = before;
231  layer->Preroll(context, initial_matrix);
232  return context->surface_needs_readback;
233 }
234 
235 TEST_F(PhysicalShapeLayerTest, Readback) {
236  PrerollContext* context = preroll_context();
237  SkPath path;
238  SkPaint paint;
239 
240  const Clip hard = Clip::hardEdge;
241  const Clip soft = Clip::antiAlias;
242  const Clip save_layer = Clip::antiAliasWithSaveLayer;
243 
244  std::shared_ptr<MockLayer> nochild;
245  auto reader = std::make_shared<MockLayer>(path, paint, false, false, true);
246  auto nonreader = std::make_shared<MockLayer>(path, paint);
247 
248  // No children, no prior readback -> no readback after
249  EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
250  EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
251  EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
252 
253  // No children, prior readback -> readback after
254  EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
255  EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
256  EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
257 
258  // Non readback child, no prior readback -> no readback after
259  EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
260  EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
261  EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
262 
263  // Non readback child, prior readback -> readback after
264  EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
265  EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
266  EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
267 
268  // Readback child, no prior readback -> readback after unless SaveLayer
269  EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
270  EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
271  EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
272 
273  // Readback child, prior readback -> readback after
274  EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
275  EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
276  EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
277 }
278 
279 } // namespace testing
280 } // namespace flutter
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
static SkRect ComputeShadowBounds(const SkRect &bounds, float elevation, float pixel_ratio)
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
bool surface_needs_readback
Definition: layer.h:50