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 | |
12 | namespace flutter { |
13 | namespace testing { |
14 | |
15 | using TransformLayerTest = LayerTest; |
16 | |
17 | #ifndef NDEBUG |
18 | TEST_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 | |
29 | TEST_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 | |
41 | TEST_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 | |
65 | TEST_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 | |
103 | TEST_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 | |
156 | TEST_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 | |