Flutter Engine
The Flutter Engine
opacity_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/opacity_layer.h"
6
7#include "flutter/flow/layers/clip_rect_layer.h"
8#include "flutter/flow/layers/image_filter_layer.h"
9#include "flutter/flow/layers/layer_tree.h"
10#include "flutter/flow/layers/platform_view_layer.h"
11#include "flutter/flow/layers/transform_layer.h"
12#include "flutter/flow/raster_cache_util.h"
13#include "flutter/flow/testing/diff_context_test.h"
14#include "flutter/flow/testing/layer_test.h"
15#include "flutter/flow/testing/mock_embedder.h"
16#include "flutter/flow/testing/mock_layer.h"
17#include "flutter/fml/macros.h"
18#include "flutter/testing/display_list_testing.h"
19#include "gtest/gtest.h"
20
21// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
22// NOLINTBEGIN(bugprone-unchecked-optional-access)
23
24namespace flutter {
25namespace testing {
26
28
29#ifndef NDEBUG
30TEST_F(OpacityLayerTest, PaintingEmptyLayerDies) {
31 auto mock_layer = std::make_shared<MockLayer>(SkPath());
32 auto layer =
33 std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f));
34 layer->Add(mock_layer);
35
36 layer->Preroll(preroll_context());
37 EXPECT_EQ(mock_layer->paint_bounds(), SkPath().getBounds());
38 EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
39 EXPECT_EQ(layer->child_paint_bounds(), mock_layer->paint_bounds());
40 EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
41 EXPECT_FALSE(layer->needs_painting(paint_context()));
42
43 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
44 "needs_painting\\(context\\)");
45}
46
47TEST_F(OpacityLayerTest, PaintBeforePrerollDies) {
48 SkPath child_path;
49 child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f);
50 auto mock_layer = std::make_shared<MockLayer>(child_path);
51 auto layer =
52 std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, SkPoint::Make(0.0f, 0.0f));
53 layer->Add(mock_layer);
54
55 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
56 "needs_painting\\(context\\)");
57}
58#endif
59
60TEST_F(OpacityLayerTest, TranslateChildren) {
61 SkPath child_path1;
62 child_path1.addRect(10.0f, 10.0f, 20.0f, 20.f);
63 DlPaint child_paint1 = DlPaint(DlColor::kMidGrey());
64 auto layer = std::make_shared<OpacityLayer>(0.5, SkPoint::Make(10, 10));
65 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
66 layer->Add(mock_layer1);
67
68 auto initial_transform = SkMatrix::Scale(2.0, 2.0);
69 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
70 layer->Preroll(preroll_context());
71
72 SkRect layer_bounds = mock_layer1->paint_bounds();
73 mock_layer1->parent_matrix().mapRect(&layer_bounds);
74
75 EXPECT_EQ(layer_bounds, SkRect::MakeXYWH(40, 40, 20, 20));
76}
77
78TEST_F(OpacityLayerTest, CacheChild) {
79 const SkAlpha alpha_half = 255 / 2;
80 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
81 auto other_transform = SkMatrix::Scale(1.0, 2.0);
82 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
83 auto mock_layer = std::make_shared<MockLayer>(child_path);
84 auto layer =
85 std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
86 layer->Add(mock_layer);
88
89 SkMatrix cache_ctm = initial_transform;
90 DisplayListBuilder cache_canvas;
91 cache_canvas.Transform(cache_ctm);
92 DisplayListBuilder other_canvas;
93 other_canvas.Transform(other_transform);
94
95 use_mock_raster_cache();
96
97 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
98
99 const auto* cacheable_opacity_item = layer->raster_cache_item();
100
101 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
102 EXPECT_EQ(cacheable_opacity_item->cache_state(),
104 EXPECT_FALSE(cacheable_opacity_item->GetId().has_value());
105
106 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
107 layer->Preroll(preroll_context());
108 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
109
110 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
111
112 EXPECT_EQ(cacheable_opacity_item->cache_state(),
113 RasterCacheItem::CacheState::kChildren);
114 EXPECT_EQ(
115 cacheable_opacity_item->GetId().value(),
118 EXPECT_FALSE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
119 other_canvas, &paint));
120 EXPECT_TRUE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
121 cache_canvas, &paint));
122}
123
124TEST_F(OpacityLayerTest, CacheChildren) {
125 const SkAlpha alpha_half = 255 / 2;
126 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
127 auto other_transform = SkMatrix::Scale(1.0, 2.0);
128 const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
129 const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
131 auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
132 auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
133 auto layer =
134 std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
135 layer->Add(mock_layer1);
136 layer->Add(mock_layer2);
137
138 SkMatrix cache_ctm = initial_transform;
139 DisplayListBuilder cache_canvas;
140 cache_canvas.Transform(cache_ctm);
141 DisplayListBuilder other_canvas;
142 other_canvas.Transform(other_transform);
143
144 use_mock_raster_cache();
145
146 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
147
148 const auto* cacheable_opacity_item = layer->raster_cache_item();
149
150 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
151 EXPECT_EQ(cacheable_opacity_item->cache_state(),
153 EXPECT_FALSE(cacheable_opacity_item->GetId().has_value());
154
155 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
156 layer->Preroll(preroll_context());
157 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
158
159 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
160
161 EXPECT_EQ(cacheable_opacity_item->cache_state(),
162 RasterCacheItem::CacheState::kChildren);
163 EXPECT_EQ(
164 cacheable_opacity_item->GetId().value(),
165 RasterCacheKeyID(RasterCacheKeyID::LayerChildrenIds(layer.get()).value(),
167 EXPECT_FALSE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
168 other_canvas, &paint));
169 EXPECT_TRUE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
170 cache_canvas, &paint));
171}
172
173TEST_F(OpacityLayerTest, ShouldNotCacheChildren) {
175 auto opacity_layer =
176 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
177 auto mock_layer = MockLayer::MakeOpacityCompatible(SkPath());
178 opacity_layer->Add(mock_layer);
179
180 PrerollContext* context = preroll_context();
181
182 use_mock_raster_cache();
183
184 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
185
186 const auto* cacheable_opacity_item = opacity_layer->raster_cache_item();
187
188 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
189 EXPECT_EQ(cacheable_opacity_item->cache_state(),
191 EXPECT_FALSE(cacheable_opacity_item->GetId().has_value());
192
193 opacity_layer->Preroll(preroll_context());
194
195 EXPECT_EQ(context->renderable_state_flags,
197 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
198 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
199 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
200 EXPECT_EQ(cacheable_opacity_item->cache_state(),
202 EXPECT_FALSE(cacheable_opacity_item->Draw(paint_context(), &paint));
203}
204
206 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
207 const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
208 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
209 const SkMatrix layer_transform =
210 SkMatrix::Translate(layer_offset.fX, layer_offset.fY);
211 const DlPaint child_paint = DlPaint(DlColor::kGreen());
212 const SkRect expected_layer_bounds =
213 layer_transform.mapRect(child_path.getBounds());
214 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
215 auto layer = std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, layer_offset);
216 layer->Add(mock_layer);
217
218 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
219 layer->Preroll(preroll_context());
220 EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
221 EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds);
222 EXPECT_EQ(layer->child_paint_bounds(), child_path.getBounds());
223 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
224 EXPECT_TRUE(layer->needs_painting(paint_context()));
225 EXPECT_EQ(mock_layer->parent_matrix(),
226 SkMatrix::Concat(initial_transform, layer_transform));
227 EXPECT_EQ(mock_layer->parent_mutators(),
228 std::vector({Mutator(layer_transform)}));
229
230 DisplayListBuilder expected_builder;
231 /* (Opacity)layer::Paint */ {
232 expected_builder.Save();
233 {
234 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
235 // Opaque alpha needs no SaveLayer, just recurse into painting mock_layer
236 /* mock_layer::Paint */ {
237 expected_builder.DrawPath(child_path, child_paint);
238 }
239 }
240 expected_builder.Restore();
241 }
242 layer->Paint(display_list_paint_context());
243 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
244}
245
246TEST_F(OpacityLayerTest, FullyTransparent) {
247 const SkRect child_bounds = SkRect::MakeWH(5.0f, 5.0f);
248 const SkPath child_path = SkPath().addRect(child_bounds);
249 const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
250 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
251 const SkMatrix layer_transform =
252 SkMatrix::Translate(layer_offset.fX, layer_offset.fY);
253 const DlPaint child_paint = DlPaint(DlColor::kGreen());
254 const SkRect expected_layer_bounds =
255 layer_transform.mapRect(child_path.getBounds());
256 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
257 auto layer =
258 std::make_shared<OpacityLayer>(SK_AlphaTRANSPARENT, layer_offset);
259 layer->Add(mock_layer);
260
261 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
262 layer->Preroll(preroll_context());
263 EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
264 EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds);
265 EXPECT_EQ(layer->child_paint_bounds(), child_path.getBounds());
266 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
267 EXPECT_TRUE(layer->needs_painting(paint_context()));
268 EXPECT_EQ(mock_layer->parent_matrix(),
269 SkMatrix::Concat(initial_transform, layer_transform));
270 EXPECT_EQ(
271 mock_layer->parent_mutators(),
272 std::vector({Mutator(layer_transform), Mutator(SK_AlphaTRANSPARENT)}));
273
274 DisplayListBuilder expected_builder;
275 /* (Opacity)layer::Paint */ {
276 expected_builder.Save();
277 {
278 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
279 /* (Opacity)layer::PaintChildren */ {
280 DlPaint save_paint(DlPaint().setOpacity(layer->opacity()));
281 expected_builder.SaveLayer(&child_bounds, &save_paint);
282 /* mock_layer::Paint */ {
283 expected_builder.DrawPath(child_path, child_paint);
284 }
285 expected_builder.Restore();
286 }
287 }
288 expected_builder.Restore();
289 }
290 layer->Paint(display_list_paint_context());
291 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
292}
293
294TEST_F(OpacityLayerTest, HalfTransparent) {
295 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
296 const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
297 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
298 const SkMatrix layer_transform =
299 SkMatrix::Translate(layer_offset.fX, layer_offset.fY);
300 const DlPaint child_paint = DlPaint(DlColor::kGreen());
301 const SkRect expected_layer_bounds =
302 layer_transform.mapRect(child_path.getBounds());
303 const SkAlpha alpha_half = 255 / 2;
304 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
305 auto layer = std::make_shared<OpacityLayer>(alpha_half, layer_offset);
306 layer->Add(mock_layer);
307
308 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
309 layer->Preroll(preroll_context());
310 EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds());
311 EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds);
312 EXPECT_EQ(layer->child_paint_bounds(), child_path.getBounds());
313 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
314 EXPECT_TRUE(layer->needs_painting(paint_context()));
315 EXPECT_EQ(mock_layer->parent_matrix(),
316 SkMatrix::Concat(initial_transform, layer_transform));
317 EXPECT_EQ(mock_layer->parent_mutators(),
318 std::vector({Mutator(layer_transform), Mutator(alpha_half)}));
319
320 SkRect opacity_bounds;
321 expected_layer_bounds.makeOffset(-layer_offset.fX, -layer_offset.fY)
322 .roundOut(&opacity_bounds);
323 DlPaint save_paint = DlPaint().setAlpha(alpha_half);
324 DlPaint child_dl_paint = DlPaint(DlColor::kGreen());
325
326 auto expected_builder = DisplayListBuilder();
327 /* (Opacity)layer::Paint */ {
328 expected_builder.Save();
329 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
330 /* (Opacity)layer::PaintChildren */ {
331 expected_builder.SaveLayer(&opacity_bounds, &save_paint);
332 /* mock_layer::Paint */ {
333 expected_builder.DrawPath(child_path, child_dl_paint);
334 }
335 expected_builder.Restore();
336 }
337 expected_builder.Restore();
338 }
339 sk_sp<DisplayList> expected_display_list = expected_builder.Build();
340
341 layer->Paint(display_list_paint_context());
342 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
343}
344
345TEST_F(OpacityLayerTest, Nested) {
346 const SkPath child1_path = SkPath().addRect(SkRect::MakeWH(5.0f, 6.0f));
347 const SkPath child2_path = SkPath().addRect(SkRect::MakeWH(2.0f, 7.0f));
348 const SkPath child3_path = SkPath().addRect(SkRect::MakeWH(6.0f, 6.0f));
349 const SkPoint layer1_offset = SkPoint::Make(0.5f, 1.5f);
350 const SkPoint layer2_offset = SkPoint::Make(2.5f, 0.5f);
351 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
352 const SkMatrix layer1_transform =
353 SkMatrix::Translate(layer1_offset.fX, layer1_offset.fY);
354 const SkMatrix layer2_transform =
355 SkMatrix::Translate(layer2_offset.fX, layer2_offset.fY);
356 const DlPaint child1_paint = DlPaint(DlColor::kRed());
357 const DlPaint child2_paint = DlPaint(DlColor::kBlue());
358 const DlPaint child3_paint = DlPaint(DlColor::kGreen());
359 const SkAlpha alpha1 = 155;
360 const SkAlpha alpha2 = 224;
361 auto mock_layer1 = std::make_shared<MockLayer>(child1_path, child1_paint);
362 auto mock_layer2 = std::make_shared<MockLayer>(child2_path, child2_paint);
363 auto mock_layer3 = std::make_shared<MockLayer>(child3_path, child3_paint);
364 auto layer1 = std::make_shared<OpacityLayer>(alpha1, layer1_offset);
365 auto layer2 = std::make_shared<OpacityLayer>(alpha2, layer2_offset);
366 layer2->Add(mock_layer2);
367 layer1->Add(mock_layer1);
368 layer1->Add(layer2);
369 layer1->Add(mock_layer3); // Ensure something is processed after recursion
370
371 const SkRect expected_layer2_bounds =
372 layer2_transform.mapRect(child2_path.getBounds());
373 SkRect layer1_child_bounds = expected_layer2_bounds;
374 layer1_child_bounds.join(child1_path.getBounds());
375 layer1_child_bounds.join(child3_path.getBounds());
376 SkRect expected_layer1_bounds = layer1_transform.mapRect(layer1_child_bounds);
377 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
378 layer1->Preroll(preroll_context());
379 EXPECT_EQ(mock_layer1->paint_bounds(), child1_path.getBounds());
380 EXPECT_EQ(mock_layer2->paint_bounds(), child2_path.getBounds());
381 EXPECT_EQ(mock_layer3->paint_bounds(), child3_path.getBounds());
382 EXPECT_EQ(layer1->paint_bounds(), expected_layer1_bounds);
383 EXPECT_EQ(layer1->child_paint_bounds(), layer1_child_bounds);
384 EXPECT_EQ(layer2->paint_bounds(), expected_layer2_bounds);
385 EXPECT_EQ(layer2->child_paint_bounds(), child2_path.getBounds());
386 EXPECT_TRUE(mock_layer1->needs_painting(paint_context()));
387 EXPECT_TRUE(mock_layer2->needs_painting(paint_context()));
388 EXPECT_TRUE(mock_layer3->needs_painting(paint_context()));
389 EXPECT_TRUE(layer1->needs_painting(paint_context()));
390 EXPECT_TRUE(layer2->needs_painting(paint_context()));
391 EXPECT_EQ(mock_layer1->parent_matrix(),
392 SkMatrix::Concat(initial_transform, layer1_transform));
393 EXPECT_EQ(mock_layer1->parent_mutators(),
394 std::vector({Mutator(layer1_transform), Mutator(alpha1)}));
395 EXPECT_EQ(
396 mock_layer2->parent_matrix(),
397 SkMatrix::Concat(SkMatrix::Concat(initial_transform, layer1_transform),
398 layer2_transform));
399 EXPECT_EQ(mock_layer2->parent_mutators(),
400 std::vector({Mutator(layer1_transform), Mutator(alpha1),
401 Mutator(layer2_transform), Mutator(alpha2)}));
402 EXPECT_EQ(mock_layer3->parent_matrix(),
403 SkMatrix::Concat(initial_transform, layer1_transform));
404 EXPECT_EQ(mock_layer3->parent_mutators(),
405 std::vector({Mutator(layer1_transform), Mutator(alpha1)}));
406
407 SkRect opacity1_bounds =
408 expected_layer1_bounds.makeOffset(-layer1_offset.fX, -layer1_offset.fY);
409 SkRect opacity2_bounds =
410 expected_layer2_bounds.makeOffset(-layer2_offset.fX, -layer2_offset.fY);
411 DlPaint opacity1_paint;
412 opacity1_paint.setOpacity(alpha1 * (1.0 / SK_AlphaOPAQUE));
413 DlPaint opacity2_paint;
414 opacity2_paint.setOpacity(alpha2 * (1.0 / SK_AlphaOPAQUE));
415
416 DisplayListBuilder expected_builder;
417 /* (Opacity)layer1::Paint */ {
418 expected_builder.Save();
419 {
420 expected_builder.Translate(layer1_offset.fX, layer1_offset.fY);
421 /* (Opacity)layer1::PaintChildren */ {
422 expected_builder.SaveLayer(&opacity1_bounds, &opacity1_paint);
423 /* mock_layer1::Paint */ {
424 expected_builder.DrawPath(child1_path, child1_paint);
425 }
426 /* (Opacity)layer2::Paint */ {
427 expected_builder.Save();
428 {
429 expected_builder.Translate(layer2_offset.fX, layer2_offset.fY);
430 /* (Opacity)layer2::PaintChidren */ {
431 expected_builder.SaveLayer(&opacity2_bounds, &opacity2_paint);
432 {
433 /* mock_layer2::Paint */ {
434 expected_builder.DrawPath(child2_path, child2_paint);
435 }
436 }
437 expected_builder.Restore();
438 }
439 }
440 expected_builder.Restore();
441 }
442 /* mock_layer3::Paint */ {
443 expected_builder.DrawPath(child3_path, child3_paint);
444 }
445 expected_builder.Restore();
446 }
447 }
448 expected_builder.Restore();
449 }
450 layer1->Paint(display_list_paint_context());
451 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
452}
453
454TEST_F(OpacityLayerTest, Readback) {
455 auto layer = std::make_shared<OpacityLayer>(kOpaque_SkAlphaType, SkPoint());
456 layer->Add(std::make_shared<MockLayer>(SkPath()));
457
458 // OpacityLayer does not read from surface
459 preroll_context()->surface_needs_readback = false;
460 layer->Preroll(preroll_context());
461 EXPECT_FALSE(preroll_context()->surface_needs_readback);
462
463 // OpacityLayer blocks child with readback
464 auto mock_layer = std::make_shared<MockLayer>(SkPath(), DlPaint());
465 mock_layer->set_fake_reads_surface(true);
466 layer->Add(mock_layer);
467 preroll_context()->surface_needs_readback = false;
468 layer->Preroll(preroll_context());
469 EXPECT_FALSE(preroll_context()->surface_needs_readback);
470}
471
472TEST_F(OpacityLayerTest, CullRectIsTransformed) {
473 auto clip_rect_layer = std::make_shared<ClipRectLayer>(
474 SkRect::MakeLTRB(0, 0, 10, 10), Clip::kHardEdge);
475 auto opacity_layer =
476 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
477 auto mock_layer = std::make_shared<MockLayer>(SkPath());
478 clip_rect_layer->Add(opacity_layer);
479 opacity_layer->Add(mock_layer);
480 clip_rect_layer->Preroll(preroll_context());
481 EXPECT_EQ(mock_layer->parent_cull_rect().fLeft, -20);
482 EXPECT_EQ(mock_layer->parent_cull_rect().fTop, -20);
483}
484
485TEST_F(OpacityLayerTest, OpacityInheritanceCompatibleChild) {
486 auto opacity_layer =
487 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
488 auto mock_layer = MockLayer::MakeOpacityCompatible(SkPath());
489 opacity_layer->Add(mock_layer);
490
491 PrerollContext* context = preroll_context();
492 opacity_layer->Preroll(context);
493 EXPECT_EQ(context->renderable_state_flags,
495 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
496}
497
498TEST_F(OpacityLayerTest, OpacityInheritanceIncompatibleChild) {
499 auto opacity_layer =
500 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
501 auto mock_layer = MockLayer::Make(SkPath());
502 opacity_layer->Add(mock_layer);
503
504 PrerollContext* context = preroll_context();
505 opacity_layer->Preroll(context);
506 EXPECT_EQ(context->renderable_state_flags,
508 EXPECT_FALSE(opacity_layer->children_can_accept_opacity());
509}
510
511TEST_F(OpacityLayerTest, OpacityInheritanceThroughContainer) {
512 auto opacity_layer =
513 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
514 auto container_layer = std::make_shared<ContainerLayer>();
515 auto mock_layer = MockLayer::MakeOpacityCompatible(SkPath());
516 container_layer->Add(mock_layer);
517 opacity_layer->Add(container_layer);
518
519 PrerollContext* context = preroll_context();
520 opacity_layer->Preroll(context);
521 EXPECT_EQ(context->renderable_state_flags,
523 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
524}
525
526TEST_F(OpacityLayerTest, OpacityInheritanceThroughTransform) {
527 auto opacity_layer =
528 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
529 auto transformLayer = std::make_shared<TransformLayer>(SkMatrix::Scale(2, 2));
530 auto mock_layer = MockLayer::MakeOpacityCompatible(SkPath());
531 transformLayer->Add(mock_layer);
532 opacity_layer->Add(transformLayer);
533
534 PrerollContext* context = preroll_context();
535 opacity_layer->Preroll(context);
536 EXPECT_EQ(context->renderable_state_flags,
538 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
539}
540
541TEST_F(OpacityLayerTest, OpacityInheritanceThroughImageFilter) {
542 auto opacity_layer =
543 std::make_shared<OpacityLayer>(128, SkPoint::Make(20, 20));
544 auto filter_layer = std::make_shared<ImageFilterLayer>(
545 std::make_shared<DlBlurImageFilter>(5.0, 5.0, DlTileMode::kClamp));
546 auto mock_layer = MockLayer::MakeOpacityCompatible(SkPath());
547 filter_layer->Add(mock_layer);
548 opacity_layer->Add(filter_layer);
549
550 PrerollContext* context = preroll_context();
551 opacity_layer->Preroll(context);
552 EXPECT_EQ(context->renderable_state_flags,
554 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
555}
556
557TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithCompatibleChild) {
558 SkPoint offset1 = SkPoint::Make(10, 20);
559 SkPoint offset2 = SkPoint::Make(20, 10);
560 SkPath mock_path = SkPath::Rect({10, 10, 20, 20});
561 auto opacity_layer_1 = std::make_shared<OpacityLayer>(128, offset1);
562 auto opacity_layer_2 = std::make_shared<OpacityLayer>(64, offset2);
563 auto mock_layer = MockLayer::MakeOpacityCompatible(mock_path);
564 opacity_layer_2->Add(mock_layer);
565 opacity_layer_1->Add(opacity_layer_2);
566
567 PrerollContext* context = preroll_context();
568 opacity_layer_1->Preroll(context);
569 EXPECT_EQ(context->renderable_state_flags,
571 EXPECT_TRUE(opacity_layer_1->children_can_accept_opacity());
572 EXPECT_TRUE(opacity_layer_2->children_can_accept_opacity());
573
574 DlPaint savelayer_paint;
575 SkScalar inherited_opacity = 128 * 1.0 / SK_AlphaOPAQUE;
576 inherited_opacity *= 64 * 1.0 / SK_AlphaOPAQUE;
577 savelayer_paint.setOpacity(inherited_opacity);
578
579 DisplayListBuilder expected_builder;
580 /* opacity_layer_1::Paint */ {
581 expected_builder.Save();
582 {
583 expected_builder.Translate(offset1.fX, offset1.fY);
584 /* opacity_layer_2::Paint */ {
585 expected_builder.Save();
586 {
587 expected_builder.Translate(offset2.fX, offset2.fY);
588 /* mock_layer::Paint */ {
589 expected_builder.DrawPath(mock_path,
590 DlPaint().setOpacity(inherited_opacity));
591 }
592 }
593 expected_builder.Restore();
594 }
595 }
596 expected_builder.Restore();
597 }
598
599 opacity_layer_1->Paint(display_list_paint_context());
600 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
601}
602
603TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithIncompatibleChild) {
604 SkPoint offset1 = SkPoint::Make(10, 20);
605 SkPoint offset2 = SkPoint::Make(20, 10);
606 SkPath mock_path = SkPath::Rect({10, 10, 20, 20});
607 auto opacity_layer_1 = std::make_shared<OpacityLayer>(128, offset1);
608 auto opacity_layer_2 = std::make_shared<OpacityLayer>(64, offset2);
609 auto mock_layer = MockLayer::Make(mock_path);
610 opacity_layer_2->Add(mock_layer);
611 opacity_layer_1->Add(opacity_layer_2);
612
613 PrerollContext* context = preroll_context();
614 opacity_layer_1->Preroll(context);
615 EXPECT_EQ(context->renderable_state_flags,
617 EXPECT_TRUE(opacity_layer_1->children_can_accept_opacity());
618 EXPECT_FALSE(opacity_layer_2->children_can_accept_opacity());
619
620 DlPaint savelayer_paint;
621 SkScalar inherited_opacity = 128 * 1.0 / SK_AlphaOPAQUE;
622 inherited_opacity *= 64 * 1.0 / SK_AlphaOPAQUE;
623 savelayer_paint.setOpacity(inherited_opacity);
624
625 DisplayListBuilder expected_builder;
626 /* opacity_layer_1::Paint */ {
627 expected_builder.Save();
628 {
629 expected_builder.Translate(offset1.fX, offset1.fY);
630 /* opacity_layer_2::Paint */ {
631 expected_builder.Save();
632 {
633 expected_builder.Translate(offset2.fX, offset2.fY);
634 expected_builder.SaveLayer(&mock_layer->paint_bounds(),
635 &savelayer_paint);
636 /* mock_layer::Paint */ {
637 expected_builder.DrawPath(mock_path, DlPaint());
638 }
639 }
640 expected_builder.Restore();
641 }
642 }
643 expected_builder.Restore();
644 }
645
646 opacity_layer_1->Paint(display_list_paint_context());
647 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
648}
649
651
652TEST_F(OpacityLayerDiffTest, FractionalTranslation) {
653 auto picture = CreateDisplayListLayer(
654 CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)));
655 auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5));
656
657 MockLayerTree tree1;
658 tree1.root()->Add(layer);
659
660 auto damage = DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0,
661 0, /*use_raster_cache=*/false);
662 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 61, 61));
663}
664
665TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) {
666 auto picture = CreateDisplayListLayer(
667 CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)));
668 auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5));
669
670 MockLayerTree tree1;
671 tree1.root()->Add(layer);
672
673 auto damage = DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0,
674 0, /*use_raster_cache=*/true);
675 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(11, 11, 61, 61));
676}
677
678TEST_F(OpacityLayerTest, FullyOpaqueWithFractionalValues) {
679 use_mock_raster_cache(); // Ensure pixel-snapped alignment.
680
681 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
682 const SkPoint layer_offset = SkPoint::Make(0.5f, 1.5f);
683 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 0.5f);
684 const DlPaint child_paint = DlPaint(DlColor::kGreen());
685 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
686 auto layer = std::make_shared<OpacityLayer>(SK_AlphaOPAQUE, layer_offset);
687 layer->Add(mock_layer);
688
689 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
690 layer->Preroll(preroll_context());
691
692 auto expected_builder = DisplayListBuilder();
693 /* (Opacity)layer::Paint */ {
694 expected_builder.Save();
695 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
696 // Opaque alpha needs no SaveLayer, just recurse into painting mock_layer
697 // but since we use the mock raster cache we pixel snap the transform
698 expected_builder.TransformReset();
699 expected_builder.Transform2DAffine(
700 1, 0, SkScalarRoundToScalar(layer_offset.fX), //
701 0, 1, SkScalarRoundToScalar(layer_offset.fY));
702 /* mock_layer::Paint */ {
703 expected_builder.DrawPath(child_path, child_paint);
704 }
705 expected_builder.Restore();
706 }
707 sk_sp<DisplayList> expected_display_list = expected_builder.Build();
708
709 layer->Paint(display_list_paint_context());
710 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
711}
712
713TEST_F(OpacityLayerTest, FullyTransparentDoesNotCullPlatformView) {
714 const SkPoint opacity_offset = SkPoint::Make(0.5f, 1.5f);
715 const SkPoint view_offset = SkPoint::Make(0.0f, 0.0f);
716 const SkSize view_size = SkSize::Make(8.0f, 8.0f);
717 const int64_t view_id = 42;
718 auto platform_view =
719 std::make_shared<PlatformViewLayer>(view_offset, view_size, view_id);
720
721 auto opacity =
722 std::make_shared<OpacityLayer>(SK_AlphaTRANSPARENT, opacity_offset);
723 opacity->Add(platform_view);
724
725 auto embedder = MockViewEmbedder();
726 DisplayListBuilder fake_overlay_builder;
727 embedder.AddCanvas(&fake_overlay_builder);
728 preroll_context()->view_embedder = &embedder;
729 paint_context().view_embedder = &embedder;
730
731 opacity->Preroll(preroll_context());
732 EXPECT_EQ(embedder.prerolled_views(), std::vector<int64_t>({view_id}));
733
734 opacity->Paint(paint_context());
735 EXPECT_EQ(embedder.painted_views(), std::vector<int64_t>({view_id}));
736}
737
738} // namespace testing
739} // namespace flutter
740
741// NOLINTEND(bugprone-unchecked-optional-access)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
uint8_t SkAlpha
Definition: SkColor.h:26
constexpr SkAlpha SK_AlphaOPAQUE
Definition: SkColor.h:94
constexpr SkAlpha SK_AlphaTRANSPARENT
Definition: SkColor.h:89
#define SkScalarRoundToScalar(x)
Definition: SkScalar.h:32
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
Definition: SkPath.h:59
static SkPath Rect(const SkRect &, SkPathDirection=SkPathDirection::kCW, unsigned startIndex=0)
Definition: SkPath.cpp:3586
const SkRect & getBounds() const
Definition: SkPath.cpp:430
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition: SkPath.cpp:864
virtual void Add(std::shared_ptr< Layer > layer)
void Transform(const SkMatrix *matrix) override
Definition: dl_builder.cc:919
void TransformReset() override
Definition: dl_builder.cc:893
void Translate(SkScalar tx, SkScalar ty) override
Definition: dl_builder.cc:799
void DrawPath(const SkPath &path, const DlPaint &paint) override
Definition: dl_builder.cc:1204
void Transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myt) override
Definition: dl_builder.cc:835
void SaveLayer(const SkRect *bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr) override
Definition: dl_builder.cc:549
sk_sp< DisplayList > Build()
Definition: dl_builder.cc:67
DlPaint & setAlpha(uint8_t alpha)
Definition: dl_paint.h:76
DlPaint & setOpacity(SkScalar opacity)
Definition: dl_paint.h:78
static constexpr int kCallerCanApplyOpacity
static void TryToRasterCache(const std::vector< RasterCacheItem * > &raster_cached_entries, const PaintContext *paint_context, bool ignore_raster_cache=false)
Definition: layer_tree.cc:68
static std::optional< std::vector< RasterCacheKeyID > > LayerChildrenIds(const Layer *layer)
static std::shared_ptr< MockLayer > MakeOpacityCompatible(const SkPath &path)
Definition: mock_layer.h:35
static std::shared_ptr< MockLayer > Make(const SkPath &path, DlPaint paint=DlPaint())
Definition: mock_layer.h:30
static void Draw(SkCanvas *canvas, const SkRect &rect)
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
TEST_F(DisplayListTest, Defaults)
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:210
DiffContextTest OpacityLayerDiffTest
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
@ kNone
Definition: layer.h:53
@ kHardEdge
Definition: layer.h:53
flutter::DlPaint DlPaint
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
static constexpr SkIRect MakeEmpty()
Definition: SkRect.h:45
float fX
x-axis value
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
void join(const SkRect &r)
Definition: SkRect.cpp:126
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
Definition: SkSize.h:52
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56
static constexpr DlColor kBlue()
Definition: dl_color.h:26
static constexpr DlColor kMidGrey()
Definition: dl_color.h:31
static constexpr DlColor kRed()
Definition: dl_color.h:24
static constexpr DlColor kGreen()
Definition: dl_color.h:25
int renderable_state_flags
Definition: layer.h:83
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678