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/opacity_layer.h" |
6 | |
7 | #include "flutter/flow/layers/clip_rect_layer.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 | |
16 | using OpacityLayerTest = LayerTest; |
17 | |
18 | #ifndef NDEBUG |
19 | TEST_F(OpacityLayerTest, LeafLayer) { |
20 | auto layer = |
21 | std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f)); |
22 | |
23 | EXPECT_DEATH_IF_SUPPORTED(layer->Preroll(preroll_context(), SkMatrix()), |
24 | "\\!container->layers\\(\\)\\.empty\\(\\)" ); |
25 | } |
26 | |
27 | TEST_F(OpacityLayerTest, PaintingEmptyLayerDies) { |
28 | auto mock_layer = std::make_shared<MockLayer>(SkPath()); |
29 | auto layer = |
30 | std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f)); |
31 | layer->Add(mock_layer); |
32 | |
33 | layer->Preroll(preroll_context(), SkMatrix()); |
34 | EXPECT_EQ(mock_layer->paint_bounds(), SkPath().getBounds()); |
35 | EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds()); |
36 | EXPECT_FALSE(mock_layer->needs_painting()); |
37 | EXPECT_FALSE(layer->needs_painting()); |
38 | |
39 | EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), |
40 | "needs_painting\\(\\)" ); |
41 | } |
42 | |
43 | TEST_F(OpacityLayerTest, PaintBeforePreollDies) { |
44 | SkPath child_path; |
45 | child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f); |
46 | auto mock_layer = std::make_shared<MockLayer>(child_path); |
47 | auto layer = |
48 | std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f)); |
49 | layer->Add(mock_layer); |
50 | |
51 | EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), |
52 | "needs_painting\\(\\)" ); |
53 | } |
54 | #endif |
55 | |
56 | TEST_F(OpacityLayerTest, ChildIsCached) { |
57 | const SkAlpha alpha_half = 255 / 2; |
58 | auto initial_transform = SkMatrix::Translate(50.0, 25.5); |
59 | auto other_transform = SkMatrix::Scale(1.0, 2.0); |
60 | const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); |
61 | auto mock_layer = std::make_shared<MockLayer>(child_path); |
62 | auto layer = |
63 | std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f)); |
64 | layer->Add(mock_layer); |
65 | |
66 | SkMatrix cache_ctm = initial_transform; |
67 | SkCanvas cache_canvas; |
68 | cache_canvas.setMatrix(cache_ctm); |
69 | SkCanvas other_canvas; |
70 | other_canvas.setMatrix(other_transform); |
71 | |
72 | use_mock_raster_cache(); |
73 | |
74 | EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); |
75 | EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas)); |
76 | EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), cache_canvas)); |
77 | |
78 | layer->Preroll(preroll_context(), initial_transform); |
79 | |
80 | EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1); |
81 | EXPECT_FALSE(raster_cache()->Draw(mock_layer.get(), other_canvas)); |
82 | EXPECT_TRUE(raster_cache()->Draw(mock_layer.get(), cache_canvas)); |
83 | } |
84 | |
85 | TEST_F(OpacityLayerTest, ChildrenNotCached) { |
86 | const SkAlpha alpha_half = 255 / 2; |
87 | auto initial_transform = SkMatrix::Translate(50.0, 25.5); |
88 | auto other_transform = SkMatrix::Scale(1.0, 2.0); |
89 | const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); |
90 | const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); |
91 | auto mock_layer1 = std::make_shared<MockLayer>(child_path1); |
92 | auto mock_layer2 = std::make_shared<MockLayer>(child_path2); |
93 | auto layer = |
94 | std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f)); |
95 | layer->Add(mock_layer1); |
96 | layer->Add(mock_layer2); |
97 | |
98 | SkMatrix cache_ctm = initial_transform; |
99 | SkCanvas cache_canvas; |
100 | cache_canvas.setMatrix(cache_ctm); |
101 | SkCanvas other_canvas; |
102 | other_canvas.setMatrix(other_transform); |
103 | |
104 | use_mock_raster_cache(); |
105 | |
106 | EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); |
107 | EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas)); |
108 | EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas)); |
109 | EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas)); |
110 | EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas)); |
111 | |
112 | layer->Preroll(preroll_context(), initial_transform); |
113 | |
114 | EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1); |
115 | EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), other_canvas)); |
116 | EXPECT_FALSE(raster_cache()->Draw(mock_layer1.get(), cache_canvas)); |
117 | EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), other_canvas)); |
118 | EXPECT_FALSE(raster_cache()->Draw(mock_layer2.get(), cache_canvas)); |
119 | } |
120 | |
121 | TEST_F(OpacityLayerTest, FullyOpaque) { |
122 | const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); |
123 | const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f); |
124 | const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f); |
125 | const SkMatrix layer_transform = |
126 | SkMatrix::Translate(layer_offset.fX, layer_offset.fY); |
127 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
128 | const SkMatrix integral_layer_transform = RasterCache::GetIntegralTransCTM( |
129 | SkMatrix::Concat(initial_transform, layer_transform)); |
130 | #endif |
131 | const SkPaint child_paint = SkPaint(SkColors::kGreen); |
132 | const SkRect expected_layer_bounds = |
133 | layer_transform.mapRect(child_path.getBounds()); |
134 | auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
135 | auto layer = std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, layer_offset); |
136 | layer->Add(mock_layer); |
137 | |
138 | layer->Preroll(preroll_context(), initial_transform); |
139 | EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds()); |
140 | EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds); |
141 | EXPECT_TRUE(mock_layer->needs_painting()); |
142 | EXPECT_TRUE(layer->needs_painting()); |
143 | EXPECT_EQ(mock_layer->parent_matrix(), |
144 | SkMatrix::Concat(initial_transform, layer_transform)); |
145 | EXPECT_EQ(mock_layer->parent_mutators(), |
146 | std::vector({Mutator(layer_transform), Mutator(SK_AlphaOPAQUE)})); |
147 | |
148 | const SkPaint opacity_paint = SkPaint(SkColors::kBlack); // A = 1.0f |
149 | SkRect opacity_bounds; |
150 | expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY) |
151 | .roundOut(&opacity_bounds); |
152 | auto expected_draw_calls = std::vector( |
153 | {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, |
154 | MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer_transform}}, |
155 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
156 | MockCanvas::DrawCall{ |
157 | 1, MockCanvas::SetMatrixData{integral_layer_transform}}, |
158 | #endif |
159 | MockCanvas::DrawCall{ |
160 | 1, MockCanvas::SaveLayerData{opacity_bounds, opacity_paint, nullptr, |
161 | 2}}, |
162 | MockCanvas::DrawCall{2, |
163 | MockCanvas::DrawPathData{child_path, child_paint}}, |
164 | MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, |
165 | MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); |
166 | layer->Paint(paint_context()); |
167 | EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); |
168 | } |
169 | |
170 | TEST_F(OpacityLayerTest, FullyTransparent) { |
171 | const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); |
172 | const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f); |
173 | const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f); |
174 | const SkMatrix layer_transform = |
175 | SkMatrix::Translate(layer_offset.fX, layer_offset.fY); |
176 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
177 | const SkMatrix integral_layer_transform = RasterCache::GetIntegralTransCTM( |
178 | SkMatrix::Concat(initial_transform, layer_transform)); |
179 | #endif |
180 | const SkPaint child_paint = SkPaint(SkColors::kGreen); |
181 | const SkRect expected_layer_bounds = |
182 | layer_transform.mapRect(child_path.getBounds()); |
183 | auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
184 | auto layer = |
185 | std::make_shared<OpacityLayer>(SK_AlphaTRANSPARENT, layer_offset); |
186 | layer->Add(mock_layer); |
187 | |
188 | layer->Preroll(preroll_context(), initial_transform); |
189 | EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds()); |
190 | EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds); |
191 | EXPECT_TRUE(mock_layer->needs_painting()); |
192 | EXPECT_TRUE(layer->needs_painting()); |
193 | EXPECT_EQ(mock_layer->parent_matrix(), |
194 | SkMatrix::Concat(initial_transform, layer_transform)); |
195 | EXPECT_EQ( |
196 | mock_layer->parent_mutators(), |
197 | std::vector({Mutator(layer_transform), Mutator(SK_AlphaTRANSPARENT)})); |
198 | |
199 | auto expected_draw_calls = std::vector( |
200 | {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, |
201 | MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer_transform}}, |
202 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
203 | MockCanvas::DrawCall{ |
204 | 1, MockCanvas::SetMatrixData{integral_layer_transform}}, |
205 | #endif |
206 | MockCanvas::DrawCall{1, MockCanvas::SaveData{2}}, |
207 | MockCanvas::DrawCall{ |
208 | 2, MockCanvas::ClipRectData{kEmptyRect, SkClipOp::kIntersect, |
209 | MockCanvas::kHard_ClipEdgeStyle}}, |
210 | MockCanvas::DrawCall{2, |
211 | MockCanvas::DrawPathData{child_path, child_paint}}, |
212 | MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, |
213 | MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); |
214 | layer->Paint(paint_context()); |
215 | EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); |
216 | } |
217 | |
218 | TEST_F(OpacityLayerTest, HalfTransparent) { |
219 | const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); |
220 | const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f); |
221 | const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f); |
222 | const SkMatrix layer_transform = |
223 | SkMatrix::Translate(layer_offset.fX, layer_offset.fY); |
224 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
225 | const SkMatrix integral_layer_transform = RasterCache::GetIntegralTransCTM( |
226 | SkMatrix::Concat(initial_transform, layer_transform)); |
227 | #endif |
228 | const SkPaint child_paint = SkPaint(SkColors::kGreen); |
229 | const SkRect expected_layer_bounds = |
230 | layer_transform.mapRect(child_path.getBounds()); |
231 | const SkAlpha alpha_half = 255 / 2; |
232 | auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
233 | auto layer = std::make_shared<OpacityLayer>(alpha_half, layer_offset); |
234 | layer->Add(mock_layer); |
235 | |
236 | layer->Preroll(preroll_context(), initial_transform); |
237 | EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds()); |
238 | EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds); |
239 | EXPECT_TRUE(mock_layer->needs_painting()); |
240 | EXPECT_TRUE(layer->needs_painting()); |
241 | EXPECT_EQ(mock_layer->parent_matrix(), |
242 | SkMatrix::Concat(initial_transform, layer_transform)); |
243 | EXPECT_EQ(mock_layer->parent_mutators(), |
244 | std::vector({Mutator(layer_transform), Mutator(alpha_half)})); |
245 | |
246 | const SkPaint opacity_paint = |
247 | SkPaint(SkColor4f::FromColor(SkColorSetA(SK_ColorBLACK, alpha_half))); |
248 | SkRect opacity_bounds; |
249 | expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY) |
250 | .roundOut(&opacity_bounds); |
251 | auto expected_draw_calls = std::vector( |
252 | {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, |
253 | MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer_transform}}, |
254 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
255 | MockCanvas::DrawCall{ |
256 | 1, MockCanvas::SetMatrixData{integral_layer_transform}}, |
257 | #endif |
258 | MockCanvas::DrawCall{ |
259 | 1, MockCanvas::SaveLayerData{opacity_bounds, opacity_paint, nullptr, |
260 | 2}}, |
261 | MockCanvas::DrawCall{2, |
262 | MockCanvas::DrawPathData{child_path, child_paint}}, |
263 | MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, |
264 | MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); |
265 | layer->Paint(paint_context()); |
266 | EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); |
267 | } |
268 | |
269 | TEST_F(OpacityLayerTest, Nested) { |
270 | const SkPath child1_path = SkPath().addRect(SkRect::MakeWH(5.0f, 6.0f)); |
271 | const SkPath child2_path = SkPath().addRect(SkRect::MakeWH(2.0f, 7.0f)); |
272 | const SkPath child3_path = SkPath().addRect(SkRect::MakeWH(6.0f, 6.0f)); |
273 | const SkPoint layer1_offset = SkPoint::Make(0.5f, 1.5f); |
274 | const SkPoint layer2_offset = SkPoint::Make(2.5f, 0.5f); |
275 | const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f); |
276 | const SkMatrix layer1_transform = |
277 | SkMatrix::Translate(layer1_offset.fX, layer1_offset.fY); |
278 | const SkMatrix layer2_transform = |
279 | SkMatrix::Translate(layer2_offset.fX, layer2_offset.fY); |
280 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
281 | const SkMatrix integral_layer1_transform = RasterCache::GetIntegralTransCTM( |
282 | SkMatrix::Concat(initial_transform, layer1_transform)); |
283 | const SkMatrix integral_layer2_transform = RasterCache::GetIntegralTransCTM( |
284 | SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform), |
285 | layer2_transform)); |
286 | #endif |
287 | const SkPaint child1_paint = SkPaint(SkColors::kRed); |
288 | const SkPaint child2_paint = SkPaint(SkColors::kBlue); |
289 | const SkPaint child3_paint = SkPaint(SkColors::kGreen); |
290 | const SkAlpha alpha1 = 155; |
291 | const SkAlpha alpha2 = 224; |
292 | auto mock_layer1 = std::make_shared<MockLayer>(child1_path, child1_paint); |
293 | auto mock_layer2 = std::make_shared<MockLayer>(child2_path, child2_paint); |
294 | auto mock_layer3 = std::make_shared<MockLayer>(child3_path, child3_paint); |
295 | auto layer1 = std::make_shared<OpacityLayer>(alpha1, layer1_offset); |
296 | auto layer2 = std::make_shared<OpacityLayer>(alpha2, layer2_offset); |
297 | layer2->Add(mock_layer2); |
298 | layer1->Add(mock_layer1); |
299 | layer1->Add(layer2); |
300 | layer1->Add(mock_layer3); // Ensure something is processed after recursion |
301 | |
302 | const SkRect expected_layer2_bounds = |
303 | layer2_transform.mapRect(child2_path.getBounds()); |
304 | SkRect expected_layer1_bounds = expected_layer2_bounds; |
305 | expected_layer1_bounds.join(child1_path.getBounds()); |
306 | expected_layer1_bounds.join(child3_path.getBounds()); |
307 | expected_layer1_bounds = layer1_transform.mapRect(expected_layer1_bounds); |
308 | layer1->Preroll(preroll_context(), initial_transform); |
309 | EXPECT_EQ(mock_layer1->paint_bounds(), child1_path.getBounds()); |
310 | EXPECT_EQ(mock_layer2->paint_bounds(), child2_path.getBounds()); |
311 | EXPECT_EQ(mock_layer3->paint_bounds(), child3_path.getBounds()); |
312 | EXPECT_EQ(layer1->paint_bounds(), expected_layer1_bounds); |
313 | EXPECT_EQ(layer2->paint_bounds(), expected_layer2_bounds); |
314 | EXPECT_TRUE(mock_layer1->needs_painting()); |
315 | EXPECT_TRUE(mock_layer2->needs_painting()); |
316 | EXPECT_TRUE(mock_layer3->needs_painting()); |
317 | EXPECT_TRUE(layer1->needs_painting()); |
318 | EXPECT_TRUE(layer2->needs_painting()); |
319 | EXPECT_EQ(mock_layer1->parent_matrix(), |
320 | SkMatrix::Concat(initial_transform, layer1_transform)); |
321 | // EXPECT_EQ(mock_layer1->parent_mutators(), |
322 | // std::vector({Mutator(layer1_transform), Mutator(alpha1)})); |
323 | EXPECT_EQ( |
324 | mock_layer2->parent_matrix(), |
325 | SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform), |
326 | layer2_transform)); |
327 | // EXPECT_EQ(mock_layer2->parent_mutators(), |
328 | // std::vector({Mutator(layer1_transform), Mutator(alpha1), |
329 | // Mutator(layer2_transform), Mutator(alpha2)})); |
330 | EXPECT_EQ(mock_layer3->parent_matrix(), |
331 | SkMatrix::Concat(initial_transform, layer1_transform)); |
332 | // EXPECT_EQ(mock_layer3->parent_mutators(), |
333 | // std::vector({Mutator(layer1_transform), Mutator(alpha1)})); |
334 | |
335 | const SkPaint opacity1_paint = |
336 | SkPaint(SkColor4f::FromColor(SkColorSetA(SK_ColorBLACK, alpha1))); |
337 | const SkPaint opacity2_paint = |
338 | SkPaint(SkColor4f::FromColor(SkColorSetA(SK_ColorBLACK, alpha2))); |
339 | SkRect opacity1_bounds, opacity2_bounds; |
340 | expected_layer1_bounds.makeOffset(-layer1_offset.fX, -layer1_offset.fY) |
341 | .roundOut(&opacity1_bounds); |
342 | expected_layer2_bounds.makeOffset(-layer2_offset.fX, -layer2_offset.fY) |
343 | .roundOut(&opacity2_bounds); |
344 | auto expected_draw_calls = std::vector( |
345 | {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, |
346 | MockCanvas::DrawCall{1, MockCanvas::ConcatMatrixData{layer1_transform}}, |
347 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
348 | MockCanvas::DrawCall{ |
349 | 1, MockCanvas::SetMatrixData{integral_layer1_transform}}, |
350 | #endif |
351 | MockCanvas::DrawCall{ |
352 | 1, MockCanvas::SaveLayerData{opacity1_bounds, opacity1_paint, |
353 | nullptr, 2}}, |
354 | MockCanvas::DrawCall{ |
355 | 2, MockCanvas::DrawPathData{child1_path, child1_paint}}, |
356 | MockCanvas::DrawCall{2, MockCanvas::SaveData{3}}, |
357 | MockCanvas::DrawCall{3, MockCanvas::ConcatMatrixData{layer2_transform}}, |
358 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
359 | MockCanvas::DrawCall{ |
360 | 3, MockCanvas::SetMatrixData{integral_layer2_transform}}, |
361 | #endif |
362 | MockCanvas::DrawCall{ |
363 | 3, MockCanvas::SaveLayerData{opacity2_bounds, opacity2_paint, |
364 | nullptr, 4}}, |
365 | MockCanvas::DrawCall{ |
366 | 4, MockCanvas::DrawPathData{child2_path, child2_paint}}, |
367 | MockCanvas::DrawCall{4, MockCanvas::RestoreData{3}}, |
368 | MockCanvas::DrawCall{3, MockCanvas::RestoreData{2}}, |
369 | MockCanvas::DrawCall{ |
370 | 2, MockCanvas::DrawPathData{child3_path, child3_paint}}, |
371 | MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, |
372 | MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); |
373 | layer1->Paint(paint_context()); |
374 | EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); |
375 | } |
376 | |
377 | TEST_F(OpacityLayerTest, Readback) { |
378 | auto initial_transform = SkMatrix(); |
379 | auto layer = std::make_shared<OpacityLayer>(kOpaque_SkAlphaType, SkPoint()); |
380 | layer->Add(std::make_shared<MockLayer>(SkPath())); |
381 | |
382 | // OpacityLayer does not read from surface |
383 | preroll_context()->surface_needs_readback = false; |
384 | layer->Preroll(preroll_context(), initial_transform); |
385 | EXPECT_FALSE(preroll_context()->surface_needs_readback); |
386 | |
387 | // OpacityLayer blocks child with readback |
388 | auto mock_layer = |
389 | std::make_shared<MockLayer>(SkPath(), SkPaint(), false, false, true); |
390 | layer->Add(mock_layer); |
391 | preroll_context()->surface_needs_readback = false; |
392 | layer->Preroll(preroll_context(), initial_transform); |
393 | EXPECT_FALSE(preroll_context()->surface_needs_readback); |
394 | } |
395 | |
396 | TEST_F(OpacityLayerTest, CullRectIsTransformed) { |
397 | auto clipRectLayer = std::make_shared<ClipRectLayer>( |
398 | SkRect::MakeLTRB(0, 0, 10, 10), flutter::hardEdge); |
399 | auto opacityLayer = |
400 | std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20)); |
401 | auto mockLayer = std::make_shared<MockLayer>(SkPath()); |
402 | clipRectLayer->Add(opacityLayer); |
403 | opacityLayer->Add(mockLayer); |
404 | clipRectLayer->Preroll(preroll_context(), SkMatrix::I()); |
405 | EXPECT_EQ(mockLayer->parent_cull_rect().fLeft, -20); |
406 | EXPECT_EQ(mockLayer->parent_cull_rect().fTop, -20); |
407 | } |
408 | |
409 | } // namespace testing |
410 | } // namespace flutter |
411 | |