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/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
12namespace flutter {
13namespace testing {
14
15using TransformLayerTest = LayerTest;
16
17#ifndef NDEBUG
18TEST_F(TransformLayerTest, PaintingEmptyLayerDies) {
19 auto layer = std::make_shared<TransformLayer>(SkMatrix()); // identity
20
21 layer->Preroll(preroll_context(), SkMatrix());
22 EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
23 EXPECT_FALSE(layer->needs_painting());
24
25 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
26 "needs_painting\\(\\)");
27}
28
29TEST_F(TransformLayerTest, PaintBeforePreollDies) {
30 SkPath child_path;
31 child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
32 auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
33 auto layer = std::make_shared<TransformLayer>(SkMatrix()); // identity
34 layer->Add(mock_layer);
35
36 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
37 "needs_painting\\(\\)");
38}
39#endif
40
41TEST_F(TransformLayerTest, Identity) {
42 SkPath child_path;
43 child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
44 SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
45 auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
46 auto layer = std::make_shared<TransformLayer>(SkMatrix()); // identity
47 layer->Add(mock_layer);
48
49 preroll_context()->cull_rect = cull_rect;
50 layer->Preroll(preroll_context(), SkMatrix());
51 EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
52 EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
53 EXPECT_TRUE(mock_layer->needs_painting());
54 EXPECT_TRUE(layer->needs_painting());
55 EXPECT_EQ(mock_layer->parent_matrix(), SkMatrix()); // identity
56 EXPECT_EQ(mock_layer->parent_cull_rect(), cull_rect);
57 EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(SkMatrix())}));
58
59 layer->Paint(paint_context());
60 EXPECT_EQ(mock_canvas().draw_calls(),
61 std::vector({MockCanvas::DrawCall{
62 0, MockCanvas::DrawPathData{child_path, SkPaint()}}}));
63}
64
65TEST_F(TransformLayerTest, Simple) {
66 SkPath child_path;
67 child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
68 SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
69 SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f);
70 SkMatrix layer_transform = SkMatrix::Translate(2.5f, 2.5f);
71 SkMatrix inverse_layer_transform;
72 EXPECT_TRUE(layer_transform.invert(&inverse_layer_transform));
73
74 auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
75 auto layer = std::make_shared<TransformLayer>(layer_transform);
76 layer->Add(mock_layer);
77
78 preroll_context()->cull_rect = cull_rect;
79 layer->Preroll(preroll_context(), initial_transform);
80 EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
81 EXPECT_EQ(layer->paint_bounds(),
82 layer_transform.mapRect(mock_layer->paint_bounds()));
83 EXPECT_TRUE(mock_layer->needs_painting());
84 EXPECT_TRUE(layer->needs_painting());
85 EXPECT_EQ(mock_layer->parent_matrix(),
86 SkMatrix::Concat(initial_transform, layer_transform));
87 EXPECT_EQ(mock_layer->parent_cull_rect(),
88 inverse_layer_transform.mapRect(cull_rect));
89 EXPECT_EQ(mock_layer->parent_mutators(),
90 std::vector({Mutator(layer_transform)}));
91
92 layer->Paint(paint_context());
93 EXPECT_EQ(
94 mock_canvas().draw_calls(),
95 std::vector({MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
96 MockCanvas::DrawCall{
97 1, MockCanvas::ConcatMatrixData{layer_transform}},
98 MockCanvas::DrawCall{
99 1, MockCanvas::DrawPathData{child_path, SkPaint()}},
100 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
101}
102
103TEST_F(TransformLayerTest, Nested) {
104 SkPath child_path;
105 child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
106 SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
107 SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f);
108 SkMatrix layer1_transform = SkMatrix::Translate(2.5f, 2.5f);
109 SkMatrix layer2_transform = SkMatrix::Translate(2.5f, 2.5f);
110 SkMatrix inverse_layer1_transform, inverse_layer2_transform;
111 EXPECT_TRUE(layer1_transform.invert(&inverse_layer1_transform));
112 EXPECT_TRUE(layer2_transform.invert(&inverse_layer2_transform));
113
114 auto mock_layer = std::make_shared<MockLayer>(child_path, SkPaint());
115 auto layer1 = std::make_shared<TransformLayer>(layer1_transform);
116 auto layer2 = std::make_shared<TransformLayer>(layer2_transform);
117 layer1->Add(layer2);
118 layer2->Add(mock_layer);
119
120 preroll_context()->cull_rect = cull_rect;
121 layer1->Preroll(preroll_context(), initial_transform);
122 EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
123 EXPECT_EQ(layer2->paint_bounds(),
124 layer2_transform.mapRect(mock_layer->paint_bounds()));
125 EXPECT_EQ(layer1->paint_bounds(),
126 layer1_transform.mapRect(layer2->paint_bounds()));
127 EXPECT_TRUE(mock_layer->needs_painting());
128 EXPECT_TRUE(layer2->needs_painting());
129 EXPECT_TRUE(layer1->needs_painting());
130 EXPECT_EQ(
131 mock_layer->parent_matrix(),
132 SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
133 layer2_transform));
134 EXPECT_EQ(mock_layer->parent_cull_rect(),
135 inverse_layer2_transform.mapRect(
136 inverse_layer1_transform.mapRect(cull_rect)));
137 EXPECT_EQ(
138 mock_layer->parent_mutators(),
139 std::vector({Mutator(layer2_transform), Mutator(layer1_transform)}));
140
141 layer1->Paint(paint_context());
142 EXPECT_EQ(
143 mock_canvas().draw_calls(),
144 std::vector({MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
145 MockCanvas::DrawCall{
146 1, MockCanvas::ConcatMatrixData{layer1_transform}},
147 MockCanvas::DrawCall{1, MockCanvas::SaveData{2}},
148 MockCanvas::DrawCall{
149 2, MockCanvas::ConcatMatrixData{layer2_transform}},
150 MockCanvas::DrawCall{
151 2, MockCanvas::DrawPathData{child_path, SkPaint()}},
152 MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
153 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
154}
155
156TEST_F(TransformLayerTest, NestedSeparated) {
157 SkPath child_path;
158 child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
159 SkRect cull_rect = SkRect::MakeXYWH(2.0f, 2.0f, 14.0f, 14.0f);
160 SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f);
161 SkMatrix layer1_transform = SkMatrix::Translate(2.5f, 2.5f);
162 SkMatrix layer2_transform = SkMatrix::Translate(2.5f, 2.5f);
163 SkMatrix inverse_layer1_transform, inverse_layer2_transform;
164 EXPECT_TRUE(layer1_transform.invert(&inverse_layer1_transform));
165 EXPECT_TRUE(layer2_transform.invert(&inverse_layer2_transform));
166
167 auto mock_layer1 =
168 std::make_shared<MockLayer>(child_path, SkPaint(SkColors::kBlue));
169 auto mock_layer2 =
170 std::make_shared<MockLayer>(child_path, SkPaint(SkColors::kGreen));
171 auto layer1 = std::make_shared<TransformLayer>(layer1_transform);
172 auto layer2 = std::make_shared<TransformLayer>(layer2_transform);
173 layer1->Add(mock_layer1);
174 layer1->Add(layer2);
175 layer2->Add(mock_layer2);
176
177 preroll_context()->cull_rect = cull_rect;
178 layer1->Preroll(preroll_context(), initial_transform);
179 SkRect expected_layer1_bounds = layer2->paint_bounds();
180 expected_layer1_bounds.join(mock_layer1->paint_bounds());
181 layer1_transform.mapRect(&expected_layer1_bounds);
182 EXPECT_EQ(mock_layer2->paint_bounds(), child_path.getBounds());
183 EXPECT_EQ(layer2->paint_bounds(),
184 layer2_transform.mapRect(mock_layer2->paint_bounds()));
185 EXPECT_EQ(mock_layer1->paint_bounds(), child_path.getBounds());
186 EXPECT_EQ(layer1->paint_bounds(), expected_layer1_bounds);
187 EXPECT_TRUE(mock_layer2->needs_painting());
188 EXPECT_TRUE(layer2->needs_painting());
189 EXPECT_TRUE(mock_layer1->needs_painting());
190 EXPECT_TRUE(layer1->needs_painting());
191 EXPECT_EQ(mock_layer1->parent_matrix(),
192 SkMatrix::Concat(initial_transform, layer1_transform));
193 EXPECT_EQ(
194 mock_layer2->parent_matrix(),
195 SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
196 layer2_transform));
197 EXPECT_EQ(mock_layer1->parent_cull_rect(),
198 inverse_layer1_transform.mapRect(cull_rect));
199 EXPECT_EQ(mock_layer2->parent_cull_rect(),
200 inverse_layer2_transform.mapRect(
201 inverse_layer1_transform.mapRect(cull_rect)));
202 EXPECT_EQ(mock_layer1->parent_mutators(),
203 std::vector({Mutator(layer1_transform)}));
204 EXPECT_EQ(
205 mock_layer2->parent_mutators(),
206 std::vector({Mutator(layer2_transform), Mutator(layer1_transform)}));
207
208 layer1->Paint(paint_context());
209 EXPECT_EQ(
210 mock_canvas().draw_calls(),
211 std::vector({MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
212 MockCanvas::DrawCall{
213 1, MockCanvas::ConcatMatrixData{layer1_transform}},
214 MockCanvas::DrawCall{
215 1, MockCanvas::DrawPathData{child_path,
216 SkPaint(SkColors::kBlue)}},
217 MockCanvas::DrawCall{1, MockCanvas::SaveData{2}},
218 MockCanvas::DrawCall{
219 2, MockCanvas::ConcatMatrixData{layer2_transform}},
220 MockCanvas::DrawCall{
221 2, MockCanvas::DrawPathData{child_path,
222 SkPaint(SkColors::kGreen)}},
223 MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
224 MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
225}
226
227} // namespace testing
228} // namespace flutter
229