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/container_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 ContainerLayerTest = LayerTest; |
16 | |
17 | #ifndef NDEBUG |
18 | TEST_F(ContainerLayerTest, LayerWithParentHasPlatformView) { |
19 | auto layer = std::make_shared<ContainerLayer>(); |
20 | |
21 | preroll_context()->has_platform_view = true; |
22 | EXPECT_DEATH_IF_SUPPORTED(layer->Preroll(preroll_context(), SkMatrix()), |
23 | "!context->has_platform_view" ); |
24 | } |
25 | |
26 | TEST_F(ContainerLayerTest, PaintingEmptyLayerDies) { |
27 | auto layer = std::make_shared<ContainerLayer>(); |
28 | |
29 | layer->Preroll(preroll_context(), SkMatrix()); |
30 | EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty()); |
31 | EXPECT_FALSE(layer->needs_painting()); |
32 | EXPECT_FALSE(layer->needs_system_composite()); |
33 | |
34 | EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), |
35 | "needs_painting\\(\\)" ); |
36 | } |
37 | |
38 | TEST_F(ContainerLayerTest, PaintBeforePreollDies) { |
39 | SkPath child_path; |
40 | child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
41 | auto mock_layer = std::make_shared<MockLayer>(child_path); |
42 | auto layer = std::make_shared<ContainerLayer>(); |
43 | layer->Add(mock_layer); |
44 | |
45 | EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty()); |
46 | EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), |
47 | "needs_painting\\(\\)" ); |
48 | } |
49 | #endif |
50 | |
51 | TEST_F(ContainerLayerTest, Simple) { |
52 | SkPath child_path; |
53 | child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
54 | SkPaint child_paint(SkColors::kGreen); |
55 | SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f); |
56 | |
57 | auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
58 | auto layer = std::make_shared<ContainerLayer>(); |
59 | layer->Add(mock_layer); |
60 | |
61 | layer->Preroll(preroll_context(), initial_transform); |
62 | EXPECT_FALSE(preroll_context()->has_platform_view); |
63 | EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds()); |
64 | EXPECT_EQ(layer->paint_bounds(), child_path.getBounds()); |
65 | EXPECT_TRUE(mock_layer->needs_painting()); |
66 | EXPECT_TRUE(layer->needs_painting()); |
67 | EXPECT_FALSE(mock_layer->needs_system_composite()); |
68 | EXPECT_FALSE(layer->needs_system_composite()); |
69 | EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); |
70 | EXPECT_EQ(mock_layer->parent_cull_rect(), kGiantRect); |
71 | |
72 | layer->Paint(paint_context()); |
73 | EXPECT_EQ(mock_canvas().draw_calls(), |
74 | std::vector({MockCanvas::DrawCall{ |
75 | 0, MockCanvas::DrawPathData{child_path, child_paint}}})); |
76 | } |
77 | |
78 | TEST_F(ContainerLayerTest, Multiple) { |
79 | SkPath child_path1; |
80 | child_path1.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
81 | SkPath child_path2; |
82 | child_path2.addRect(8.0f, 2.0f, 16.5f, 14.5f); |
83 | SkPaint child_paint1(SkColors::kGray); |
84 | SkPaint child_paint2(SkColors::kGreen); |
85 | SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f); |
86 | |
87 | auto mock_layer1 = std::make_shared<MockLayer>( |
88 | child_path1, child_paint1, true /* fake_has_platform_view */); |
89 | auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2); |
90 | auto layer = std::make_shared<ContainerLayer>(); |
91 | layer->Add(mock_layer1); |
92 | layer->Add(mock_layer2); |
93 | |
94 | SkRect expected_total_bounds = child_path1.getBounds(); |
95 | expected_total_bounds.join(child_path2.getBounds()); |
96 | layer->Preroll(preroll_context(), initial_transform); |
97 | EXPECT_TRUE(preroll_context()->has_platform_view); |
98 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
99 | EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); |
100 | EXPECT_EQ(layer->paint_bounds(), expected_total_bounds); |
101 | EXPECT_TRUE(mock_layer1->needs_painting()); |
102 | EXPECT_TRUE(mock_layer2->needs_painting()); |
103 | EXPECT_TRUE(layer->needs_painting()); |
104 | EXPECT_FALSE(mock_layer1->needs_system_composite()); |
105 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
106 | EXPECT_FALSE(layer->needs_system_composite()); |
107 | EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); |
108 | EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); |
109 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
110 | EXPECT_EQ(mock_layer2->parent_cull_rect(), |
111 | kGiantRect); // Siblings are independent |
112 | |
113 | layer->Paint(paint_context()); |
114 | EXPECT_EQ( |
115 | mock_canvas().draw_calls(), |
116 | std::vector({MockCanvas::DrawCall{ |
117 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, |
118 | MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ |
119 | child_path2, child_paint2}}})); |
120 | } |
121 | |
122 | TEST_F(ContainerLayerTest, MultipleWithEmpty) { |
123 | SkPath child_path1; |
124 | child_path1.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
125 | SkPaint child_paint1(SkColors::kGray); |
126 | SkPaint child_paint2(SkColors::kGreen); |
127 | SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f); |
128 | |
129 | auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1); |
130 | auto mock_layer2 = std::make_shared<MockLayer>(SkPath(), child_paint2); |
131 | auto layer = std::make_shared<ContainerLayer>(); |
132 | layer->Add(mock_layer1); |
133 | layer->Add(mock_layer2); |
134 | |
135 | layer->Preroll(preroll_context(), initial_transform); |
136 | EXPECT_FALSE(preroll_context()->has_platform_view); |
137 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
138 | EXPECT_EQ(mock_layer2->paint_bounds(), SkPath().getBounds()); |
139 | EXPECT_EQ(layer->paint_bounds(), child_path1.getBounds()); |
140 | EXPECT_TRUE(mock_layer1->needs_painting()); |
141 | EXPECT_FALSE(mock_layer2->needs_painting()); |
142 | EXPECT_TRUE(layer->needs_painting()); |
143 | EXPECT_FALSE(mock_layer1->needs_system_composite()); |
144 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
145 | EXPECT_FALSE(layer->needs_system_composite()); |
146 | EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); |
147 | EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); |
148 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
149 | EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); |
150 | |
151 | layer->Paint(paint_context()); |
152 | EXPECT_EQ(mock_canvas().draw_calls(), |
153 | std::vector({MockCanvas::DrawCall{ |
154 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}})); |
155 | } |
156 | |
157 | TEST_F(ContainerLayerTest, NeedsSystemComposite) { |
158 | SkPath child_path1; |
159 | child_path1.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
160 | SkPath child_path2; |
161 | child_path2.addRect(8.0f, 2.0f, 16.5f, 14.5f); |
162 | SkPaint child_paint1(SkColors::kGray); |
163 | SkPaint child_paint2(SkColors::kGreen); |
164 | SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f); |
165 | |
166 | auto mock_layer1 = std::make_shared<MockLayer>( |
167 | child_path1, child_paint1, false /* fake_has_platform_view */, |
168 | true /* fake_needs_system_composite */); |
169 | auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2); |
170 | auto layer = std::make_shared<ContainerLayer>(); |
171 | layer->Add(mock_layer1); |
172 | layer->Add(mock_layer2); |
173 | |
174 | SkRect expected_total_bounds = child_path1.getBounds(); |
175 | expected_total_bounds.join(child_path2.getBounds()); |
176 | layer->Preroll(preroll_context(), initial_transform); |
177 | EXPECT_FALSE(preroll_context()->has_platform_view); |
178 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
179 | EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); |
180 | EXPECT_EQ(layer->paint_bounds(), expected_total_bounds); |
181 | EXPECT_TRUE(mock_layer1->needs_painting()); |
182 | EXPECT_TRUE(mock_layer2->needs_painting()); |
183 | EXPECT_TRUE(layer->needs_painting()); |
184 | EXPECT_TRUE(mock_layer1->needs_system_composite()); |
185 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
186 | EXPECT_TRUE(layer->needs_system_composite()); |
187 | EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); |
188 | EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); |
189 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
190 | EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); |
191 | |
192 | layer->Paint(paint_context()); |
193 | EXPECT_EQ( |
194 | mock_canvas().draw_calls(), |
195 | std::vector({MockCanvas::DrawCall{ |
196 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, |
197 | MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ |
198 | child_path2, child_paint2}}})); |
199 | } |
200 | |
201 | TEST_F(ContainerLayerTest, MergedOneChild) { |
202 | SkPath child_path; |
203 | child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
204 | SkPaint child_paint(SkColors::kGreen); |
205 | SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f); |
206 | |
207 | auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
208 | auto layer = std::make_shared<MergedContainerLayer>(); |
209 | layer->Add(mock_layer); |
210 | |
211 | layer->Preroll(preroll_context(), initial_transform); |
212 | EXPECT_FALSE(preroll_context()->has_platform_view); |
213 | EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds()); |
214 | EXPECT_EQ(layer->paint_bounds(), child_path.getBounds()); |
215 | EXPECT_TRUE(mock_layer->needs_painting()); |
216 | EXPECT_TRUE(layer->needs_painting()); |
217 | EXPECT_FALSE(mock_layer->needs_system_composite()); |
218 | EXPECT_FALSE(layer->needs_system_composite()); |
219 | EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); |
220 | EXPECT_EQ(mock_layer->parent_cull_rect(), kGiantRect); |
221 | |
222 | layer->Paint(paint_context()); |
223 | EXPECT_EQ(mock_canvas().draw_calls(), |
224 | std::vector({MockCanvas::DrawCall{ |
225 | 0, MockCanvas::DrawPathData{child_path, child_paint}}})); |
226 | } |
227 | |
228 | TEST_F(ContainerLayerTest, MergedMultipleChildren) { |
229 | SkPath child_path1; |
230 | child_path1.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
231 | SkPath child_path2; |
232 | child_path2.addRect(58.0f, 2.0f, 16.5f, 14.5f); |
233 | SkPaint child_paint1(SkColors::kGray); |
234 | SkPaint child_paint2(SkColors::kGreen); |
235 | SkMatrix initial_transform = SkMatrix::Translate(-0.5f, -0.5f); |
236 | |
237 | auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1); |
238 | auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2); |
239 | auto layer = std::make_shared<MergedContainerLayer>(); |
240 | layer->Add(mock_layer1); |
241 | layer->Add(mock_layer2); |
242 | |
243 | SkRect expected_total_bounds = child_path1.getBounds(); |
244 | expected_total_bounds.join(child_path2.getBounds()); |
245 | layer->Preroll(preroll_context(), initial_transform); |
246 | EXPECT_FALSE(preroll_context()->has_platform_view); |
247 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
248 | EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); |
249 | EXPECT_EQ(layer->paint_bounds(), expected_total_bounds); |
250 | EXPECT_TRUE(mock_layer1->needs_painting()); |
251 | EXPECT_TRUE(mock_layer2->needs_painting()); |
252 | EXPECT_TRUE(layer->needs_painting()); |
253 | EXPECT_FALSE(mock_layer1->needs_system_composite()); |
254 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
255 | EXPECT_FALSE(layer->needs_system_composite()); |
256 | EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); |
257 | EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); |
258 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
259 | EXPECT_EQ(mock_layer2->parent_cull_rect(), |
260 | kGiantRect); // Siblings are independent |
261 | |
262 | layer->Paint(paint_context()); |
263 | EXPECT_EQ( |
264 | mock_canvas().draw_calls(), |
265 | std::vector({MockCanvas::DrawCall{ |
266 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, |
267 | MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ |
268 | child_path2, child_paint2}}})); |
269 | } |
270 | |
271 | } // namespace testing |
272 | } // namespace flutter |
273 | |