Flutter Engine
transform_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/transform_layer.h"
6 
7 #include "flutter/flow/testing/diff_context_test.h"
8 #include "flutter/flow/testing/layer_test.h"
9 #include "flutter/flow/testing/mock_layer.h"
10 #include "flutter/fml/macros.h"
11 #include "flutter/testing/mock_canvas.h"
12 
13 namespace flutter {
14 namespace testing {
15 
17 
18 #ifndef NDEBUG
19 TEST_F(TransformLayerTest, PaintingEmptyLayerDies) {
20  auto layer = std::make_shared<TransformLayer>(SkMatrix()); // identity
21 
22  layer->Preroll(preroll_context(), SkMatrix());
23  EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
24  EXPECT_FALSE(layer->needs_painting(paint_context()));
25 
26  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
27  "needs_painting\\(context\\)");
28 }
29 
30 TEST_F(TransformLayerTest, PaintBeforePrerollDies) {
31  SkPath child_path;
32  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
33  auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
34  auto layer = std::make_shared<TransformLayer>(SkMatrix()); // identity
35  layer->Add(mock_layer);
36 
37  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
38  "needs_painting\\(context\\)");
39 }
40 #endif
41 
43  SkPath child_path;
44  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
45  SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
46  auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
47  auto layer = std::make_shared<TransformLayer>(SkMatrix()); // identity
48  layer->Add(mock_layer);
49 
50  preroll_context()->cull_rect = cull_rect;
51  layer->Preroll(preroll_context(), SkMatrix());
52  EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
53  EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
54  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
55  EXPECT_TRUE(layer->needs_painting(paint_context()));
56  EXPECT_EQ(mock_layer->parent_matrix(), SkMatrix()); // identity
57  EXPECT_EQ(mock_layer->parent_cull_rect(), cull_rect);
58  EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(SkMatrix())}));
59 
60  layer->Paint(paint_context());
61  EXPECT_EQ(mock_canvas().draw_calls(),
62  std::vector({MockCanvas::DrawCall{
63  0, MockCanvas::DrawPathData{child_path, SkPaint()}}}));
64 }
65 
66 TEST_F(TransformLayerTest, Simple) {
67  SkPath child_path;
68  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
69  SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
70  SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f);
71  SkMatrix layer_transform = SkMatrix::Translate(2.5f, 2.5f);
72  SkMatrix inverse_layer_transform;
73  EXPECT_TRUE(layer_transform.invert(&inverse_layer_transform));
74 
75  auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
76  auto layer = std::make_shared<TransformLayer>(layer_transform);
77  layer->Add(mock_layer);
78 
79  preroll_context()->cull_rect = cull_rect;
80  layer->Preroll(preroll_context(), initial_transform);
81  EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
82  EXPECT_EQ(layer->paint_bounds(),
83  layer_transform.mapRect(mock_layer->paint_bounds()));
84  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
85  EXPECT_TRUE(layer->needs_painting(paint_context()));
86  EXPECT_EQ(mock_layer->parent_matrix(),
87  SkMatrix::Concat(initial_transform, layer_transform));
88  EXPECT_EQ(mock_layer->parent_cull_rect(),
89  inverse_layer_transform.mapRect(cull_rect));
90  EXPECT_EQ(mock_layer->parent_mutators(),
91  std::vector({Mutator(layer_transform)}));
92 
93  layer->Paint(paint_context());
94  EXPECT_EQ(
95  mock_canvas().draw_calls(),
96  std::vector({MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
98  1, MockCanvas::ConcatMatrixData{SkM44(layer_transform)}},
100  1, MockCanvas::DrawPathData{child_path, SkPaint()}},
102 }
103 
104 TEST_F(TransformLayerTest, Nested) {
105  SkPath child_path;
106  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
107  SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
108  SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f);
109  SkMatrix layer1_transform = SkMatrix::Translate(2.5f, 2.5f);
110  SkMatrix layer2_transform = SkMatrix::Translate(2.5f, 2.5f);
111  SkMatrix inverse_layer1_transform, inverse_layer2_transform;
112  EXPECT_TRUE(layer1_transform.invert(&inverse_layer1_transform));
113  EXPECT_TRUE(layer2_transform.invert(&inverse_layer2_transform));
114 
115  auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
116  auto layer1 = std::make_shared<TransformLayer>(layer1_transform);
117  auto layer2 = std::make_shared<TransformLayer>(layer2_transform);
118  layer1->Add(layer2);
119  layer2->Add(mock_layer);
120 
121  preroll_context()->cull_rect = cull_rect;
122  layer1->Preroll(preroll_context(), initial_transform);
123  EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
124  EXPECT_EQ(layer2->paint_bounds(),
125  layer2_transform.mapRect(mock_layer->paint_bounds()));
126  EXPECT_EQ(layer1->paint_bounds(),
127  layer1_transform.mapRect(layer2->paint_bounds()));
128  EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
129  EXPECT_TRUE(layer2->needs_painting(paint_context()));
130  EXPECT_TRUE(layer1->needs_painting(paint_context()));
131  EXPECT_EQ(
132  mock_layer->parent_matrix(),
133  SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
134  layer2_transform));
135  EXPECT_EQ(mock_layer->parent_cull_rect(),
136  inverse_layer2_transform.mapRect(
137  inverse_layer1_transform.mapRect(cull_rect)));
138  EXPECT_EQ(
139  mock_layer->parent_mutators(),
140  std::vector({Mutator(layer2_transform), Mutator(layer1_transform)}));
141 
142  layer1->Paint(paint_context());
143  EXPECT_EQ(mock_canvas().draw_calls(),
144  std::vector(
147  1, MockCanvas::ConcatMatrixData{SkM44(layer1_transform)}},
150  2, MockCanvas::ConcatMatrixData{SkM44(layer2_transform)}},
152  2, MockCanvas::DrawPathData{child_path, SkPaint()}},
155 }
156 
157 TEST_F(TransformLayerTest, NestedSeparated) {
158  SkPath child_path;
159  child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
160  SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
161  SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f);
162  SkMatrix layer1_transform = SkMatrix::Translate(2.5f, 2.5f);
163  SkMatrix layer2_transform = SkMatrix::Translate(2.5f, 2.5f);
164  SkMatrix inverse_layer1_transform, inverse_layer2_transform;
165  EXPECT_TRUE(layer1_transform.invert(&inverse_layer1_transform));
166  EXPECT_TRUE(layer2_transform.invert(&inverse_layer2_transform));
167 
168  auto mock_layer1 =
169  std::make_shared<MockLayer>(child_path, SkPaint(SkColors::kBlue));
170  auto mock_layer2 =
171  std::make_shared<MockLayer>(child_path, SkPaint(SkColors::kGreen));
172  auto layer1 = std::make_shared<TransformLayer>(layer1_transform);
173  auto layer2 = std::make_shared<TransformLayer>(layer2_transform);
174  layer1->Add(mock_layer1);
175  layer1->Add(layer2);
176  layer2->Add(mock_layer2);
177 
178  preroll_context()->cull_rect = cull_rect;
179  layer1->Preroll(preroll_context(), initial_transform);
180  SkRect expected_layer1_bounds = layer2->paint_bounds();
181  expected_layer1_bounds.join(mock_layer1->paint_bounds());
182  layer1_transform.mapRect(&expected_layer1_bounds);
183  EXPECT_EQ(mock_layer2->paint_bounds(), child_path.getBounds());
184  EXPECT_EQ(layer2->paint_bounds(),
185  layer2_transform.mapRect(mock_layer2->paint_bounds()));
186  EXPECT_EQ(mock_layer1->paint_bounds(), child_path.getBounds());
187  EXPECT_EQ(layer1->paint_bounds(), expected_layer1_bounds);
188  EXPECT_TRUE(mock_layer2->needs_painting(paint_context()));
189  EXPECT_TRUE(layer2->needs_painting(paint_context()));
190  EXPECT_TRUE(mock_layer1->needs_painting(paint_context()));
191  EXPECT_TRUE(layer1->needs_painting(paint_context()));
192  EXPECT_EQ(mock_layer1->parent_matrix(),
193  SkMatrix::Concat(initial_transform, layer1_transform));
194  EXPECT_EQ(
195  mock_layer2->parent_matrix(),
196  SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
197  layer2_transform));
198  EXPECT_EQ(mock_layer1->parent_cull_rect(),
199  inverse_layer1_transform.mapRect(cull_rect));
200  EXPECT_EQ(mock_layer2->parent_cull_rect(),
201  inverse_layer2_transform.mapRect(
202  inverse_layer1_transform.mapRect(cull_rect)));
203  EXPECT_EQ(mock_layer1->parent_mutators(),
204  std::vector({Mutator(layer1_transform)}));
205  EXPECT_EQ(
206  mock_layer2->parent_mutators(),
207  std::vector({Mutator(layer2_transform), Mutator(layer1_transform)}));
208 
209  layer1->Paint(paint_context());
210  EXPECT_EQ(mock_canvas().draw_calls(),
211  std::vector(
214  1, MockCanvas::ConcatMatrixData{SkM44(layer1_transform)}},
216  1, MockCanvas::DrawPathData{child_path,
217  SkPaint(SkColors::kBlue)}},
220  2, MockCanvas::ConcatMatrixData{SkM44(layer2_transform)}},
222  2, MockCanvas::DrawPathData{child_path,
223  SkPaint(SkColors::kGreen)}},
226 }
227 
228 #ifdef FLUTTER_ENABLE_DIFF_CONTEXT
229 
230 using TransformLayerLayerDiffTest = DiffContextTest;
231 
232 TEST_F(TransformLayerLayerDiffTest, Transform) {
233  auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50));
234  auto m1 = std::make_shared<MockLayer>(path1);
235 
236  auto transform1 =
237  std::make_shared<TransformLayer>(SkMatrix::Translate(10, 10));
238  transform1->Add(m1);
239 
240  MockLayerTree t1;
241  t1.root()->Add(transform1);
242 
243  auto damage = DiffLayerTree(t1, MockLayerTree());
244  EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60));
245 
246  auto transform2 =
247  std::make_shared<TransformLayer>(SkMatrix::Translate(20, 20));
248  transform2->Add(m1);
249  transform2->AssignOldLayer(transform1.get());
250 
251  MockLayerTree t2;
252  t2.root()->Add(transform2);
253 
254  damage = DiffLayerTree(t2, t1);
255  EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 70, 70));
256 
257  auto transform3 =
258  std::make_shared<TransformLayer>(SkMatrix::Translate(20, 20));
259  transform3->Add(m1);
260  transform3->AssignOldLayer(transform2.get());
261 
262  MockLayerTree t3;
263  t3.root()->Add(transform3);
264 
265  damage = DiffLayerTree(t3, t2);
266  EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty());
267 }
268 
269 TEST_F(TransformLayerLayerDiffTest, TransformNested) {
270  auto path1 = SkPath().addRect(SkRect::MakeLTRB(0, 0, 50, 50));
271  auto m1 = CreateContainerLayer(std::make_shared<MockLayer>(path1));
272  auto m2 = CreateContainerLayer(std::make_shared<MockLayer>(path1));
273  auto m3 = CreateContainerLayer(std::make_shared<MockLayer>(path1));
274 
275  auto transform1 = std::make_shared<TransformLayer>(SkMatrix::Scale(2.0, 2.0));
276 
277  auto transform1_1 =
278  std::make_shared<TransformLayer>(SkMatrix::Translate(10, 10));
279  transform1_1->Add(m1);
280  transform1->Add(transform1_1);
281 
282  auto transform1_2 =
283  std::make_shared<TransformLayer>(SkMatrix::Translate(100, 100));
284  transform1_2->Add(m2);
285  transform1->Add(transform1_2);
286 
287  auto transform1_3 =
288  std::make_shared<TransformLayer>(SkMatrix::Translate(200, 200));
289  transform1_3->Add(m3);
290  transform1->Add(transform1_3);
291 
292  MockLayerTree l1;
293  l1.root()->Add(transform1);
294 
295  auto damage = DiffLayerTree(l1, MockLayerTree());
296  EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(20, 20, 500, 500));
297 
298  auto transform2 = std::make_shared<TransformLayer>(SkMatrix::Scale(2.0, 2.0));
299 
300  auto transform2_1 =
301  std::make_shared<TransformLayer>(SkMatrix::Translate(10, 10));
302  transform2_1->Add(m1);
303  transform2_1->AssignOldLayer(transform1_1.get());
304  transform2->Add(transform2_1);
305 
306  // Offset 1px from transform1_2 so that they're not the same
307  auto transform2_2 =
308  std::make_shared<TransformLayer>(SkMatrix::Translate(100, 101));
309  transform2_2->Add(m2);
310  transform2_2->AssignOldLayer(transform1_2.get());
311  transform2->Add(transform2_2);
312 
313  auto transform2_3 =
314  std::make_shared<TransformLayer>(SkMatrix::Translate(200, 200));
315  transform2_3->Add(m3);
316  transform2_3->AssignOldLayer(transform1_3.get());
317  transform2->Add(transform2_3);
318 
319  MockLayerTree l2;
320  l2.root()->Add(transform2);
321 
322  damage = DiffLayerTree(l2, l1);
323 
324  // transform2 has not transform1 assigned as old layer, so it should be
325  // invalidated completely
326  EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(20, 20, 500, 500));
327 
328  // now diff the tree properly, the only difference being transform2_2 and
329  // transform_2_1
330  transform2->AssignOldLayer(transform1.get());
331  damage = DiffLayerTree(l2, l1);
332 
333  EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(200, 200, 300, 302));
334 }
335 
336 #endif
337 
338 } // namespace testing
339 } // namespace flutter
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:151
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)