Flutter Engine
 
Loading...
Searching...
No Matches
clip_rsuperellipse_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
6
13#include "flutter/fml/macros.h"
14
15// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
16// NOLINTBEGIN(bugprone-unchecked-optional-access)
17
18namespace flutter {
19namespace testing {
20
22
23#ifndef NDEBUG
24TEST_F(ClipRSuperellipseLayerTest, ClipNoneBehaviorDies) {
25 const DlRoundSuperellipse layer_rsuperellipse = DlRoundSuperellipse();
26 EXPECT_DEATH_IF_SUPPORTED(
27 auto clip = std::make_shared<ClipRSuperellipseLayer>(layer_rsuperellipse,
29 "clip_behavior != Clip::kNone");
30}
31
32TEST_F(ClipRSuperellipseLayerTest, PaintingEmptyLayerDies) {
33 const DlRoundSuperellipse layer_rsuperellipse = DlRoundSuperellipse();
34 auto layer = std::make_shared<ClipRSuperellipseLayer>(layer_rsuperellipse,
36
37 layer->Preroll(preroll_context());
38
39 // Untouched
40 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), kGiantRect);
41 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
42
43 EXPECT_EQ(layer->paint_bounds(), DlRect());
44 EXPECT_EQ(layer->child_paint_bounds(), DlRect());
45 EXPECT_FALSE(layer->needs_painting(paint_context()));
46
47 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
48 "needs_painting\\(context\\)");
49}
50
51TEST_F(ClipRSuperellipseLayerTest, PaintBeforePrerollDies) {
52 const DlRect layer_bounds = DlRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
53 const DlRoundSuperellipse layer_rsuperellipse =
55 auto layer = std::make_shared<ClipRSuperellipseLayer>(layer_rsuperellipse,
57 EXPECT_EQ(layer->paint_bounds(), DlRect());
58 EXPECT_EQ(layer->child_paint_bounds(), DlRect());
59 EXPECT_FALSE(layer->needs_painting(paint_context()));
60
61 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
62 "needs_painting\\(context\\)");
63}
64
65TEST_F(ClipRSuperellipseLayerTest, PaintingCulledLayerDies) {
66 const DlMatrix initial_matrix = DlMatrix::MakeTranslation({0.5f, 1.0f});
67 const DlRect child_bounds = DlRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
68 const DlRect layer_bounds = DlRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
69 const DlRect distant_bounds = DlRect::MakeXYWH(100.0, 100.0, 10.0, 10.0);
70 const DlPath child_path = DlPath::MakeRect(child_bounds);
71 const DlRoundSuperellipse layer_rsuperellipse =
73 const DlPaint child_paint = DlPaint(DlColor::kYellow());
74 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
75 auto layer = std::make_shared<ClipRSuperellipseLayer>(layer_rsuperellipse,
77 layer->Add(mock_layer);
78
79 // Cull these children
80 preroll_context()->state_stack.set_preroll_delegate(distant_bounds,
81 initial_matrix);
82 layer->Preroll(preroll_context());
83
84 // Untouched
85 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), distant_bounds);
86 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
87
88 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
89 EXPECT_EQ(layer->paint_bounds(), child_bounds);
90 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
91 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
92 EXPECT_TRUE(layer->needs_painting(paint_context()));
93 EXPECT_EQ(mock_layer->parent_cull_rect(), DlRect());
94 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
95 EXPECT_EQ(mock_layer->parent_mutators(),
96 std::vector({Mutator(layer_rsuperellipse)}));
97
98 auto mutator = paint_context().state_stack.save();
99 mutator.clipRect(distant_bounds, false);
100 EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
101 EXPECT_FALSE(layer->needs_painting(paint_context()));
102 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
103 "needs_painting\\(context\\)");
104}
105#endif
106
107TEST_F(ClipRSuperellipseLayerTest, ChildOutsideBounds) {
108 const DlMatrix initial_matrix = DlMatrix::MakeTranslation({0.5f, 1.0f});
109 const DlRect local_cull_bounds = DlRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
110 const DlRect device_cull_bounds =
111 local_cull_bounds.TransformAndClipBounds(initial_matrix);
112 const DlRect child_bounds = DlRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
113 const DlRect clip_bounds = DlRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
114 const DlPath child_path = DlPath::MakeRect(child_bounds);
115 const DlRoundSuperellipse clip_rsuperellipse =
117 const DlPaint child_paint = DlPaint(DlColor::kYellow());
118 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
119 auto layer = std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
121 layer->Add(mock_layer);
122
123 auto clip_cull_rect = clip_bounds.Intersection(local_cull_bounds);
124 ASSERT_TRUE(clip_cull_rect.has_value());
125 auto clip_layer_bounds = child_bounds.Intersection(clip_bounds);
126 ASSERT_TRUE(clip_layer_bounds.has_value());
127
128 // Set up both contexts to cull clipped child
129 preroll_context()->state_stack.set_preroll_delegate(device_cull_bounds,
130 initial_matrix);
131 paint_context().canvas->ClipRect(device_cull_bounds);
132 paint_context().canvas->Transform(initial_matrix);
133
134 layer->Preroll(preroll_context());
135 // Untouched
136 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(),
137 device_cull_bounds);
138 EXPECT_EQ(preroll_context()->state_stack.local_cull_rect(),
139 local_cull_bounds);
140 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
141
142 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
143 EXPECT_EQ(layer->paint_bounds(), clip_layer_bounds.value());
144 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
145 EXPECT_EQ(mock_layer->parent_cull_rect(), clip_cull_rect.value());
146 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
147 EXPECT_EQ(mock_layer->parent_mutators(),
148 std::vector({Mutator(clip_rsuperellipse)}));
149
150 EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
151 ASSERT_FALSE(layer->needs_painting(paint_context()));
152 // Top level layer not visible so calling layer->Paint()
153 // would trip an FML_DCHECK
154}
155
156TEST_F(ClipRSuperellipseLayerTest, FullyContainedChild) {
157 const DlMatrix initial_matrix = DlMatrix::MakeTranslation({0.5f, 1.0f});
158 const DlRect child_bounds = DlRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
159 const DlRect layer_bounds = DlRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
160 const DlPath child_path = DlPath::MakeRect(child_bounds) +
161 DlPath::MakeOval(child_bounds.Expand(-0.1f));
162 const DlRoundSuperellipse layer_rsuperellipse =
163 DlRoundSuperellipse::MakeRectXY(layer_bounds, 0.1, 0.1);
164 const DlPaint child_paint = DlPaint(DlColor::kYellow());
165 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
166 auto layer = std::make_shared<ClipRSuperellipseLayer>(layer_rsuperellipse,
168 layer->Add(mock_layer);
169
170 preroll_context()->state_stack.set_preroll_delegate(initial_matrix);
171 layer->Preroll(preroll_context());
172
173 // Untouched
174 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), kGiantRect);
175 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
176
177 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
178 EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
179 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
180 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
181 EXPECT_TRUE(layer->needs_painting(paint_context()));
182 EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
183 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
184 EXPECT_EQ(mock_layer->parent_mutators(),
185 std::vector({Mutator(layer_rsuperellipse)}));
186
187 layer->Paint(display_list_paint_context());
188 DisplayListBuilder expected_builder;
189 /* (ClipRSuperellipse)layer::Paint */ {
190 expected_builder.Save();
191 {
192 expected_builder.ClipRoundSuperellipse(layer_rsuperellipse);
193 /* mock_layer::Paint */ {
194 expected_builder.DrawPath(child_path, child_paint);
195 }
196 }
197 expected_builder.Restore();
198 }
199 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
200}
201
202TEST_F(ClipRSuperellipseLayerTest, PartiallyContainedChild) {
203 const DlMatrix initial_matrix = DlMatrix::MakeTranslation({0.5f, 1.0f});
204 const DlRect local_cull_bounds = DlRect::MakeXYWH(0.0, 0.0, 4.0, 5.5);
205 const DlRect device_cull_bounds =
206 local_cull_bounds.TransformAndClipBounds(initial_matrix);
207 const DlRect child_bounds = DlRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
208 const DlRect clip_bounds = DlRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
209 const DlPath child_path = DlPath::MakeRect(child_bounds) +
210 DlPath::MakeOval(child_bounds.Expand(-0.1f));
211 const DlRoundSuperellipse clip_rsuperellipse =
212 DlRoundSuperellipse::MakeRectXY(clip_bounds, 0.1, 0.1);
213 const DlPaint child_paint = DlPaint(DlColor::kYellow());
214 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
215 auto layer = std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
217 layer->Add(mock_layer);
218
219 auto clip_cull_rect = clip_bounds.Intersection(local_cull_bounds);
220 ASSERT_TRUE(clip_cull_rect.has_value());
221 auto clip_layer_bounds = child_bounds.Intersection(clip_bounds);
222 ASSERT_TRUE(clip_layer_bounds.has_value());
223
224 preroll_context()->state_stack.set_preroll_delegate(device_cull_bounds,
225 initial_matrix);
226
227 layer->Preroll(preroll_context());
228 // Untouched
229 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(),
230 device_cull_bounds);
231 EXPECT_EQ(preroll_context()->state_stack.local_cull_rect(),
232 local_cull_bounds);
233 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
234
235 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
236 EXPECT_EQ(layer->paint_bounds(), clip_layer_bounds.value());
237 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
238 EXPECT_EQ(mock_layer->parent_cull_rect(), clip_cull_rect.value());
239 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
240 EXPECT_EQ(mock_layer->parent_mutators(),
241 std::vector({Mutator(clip_rsuperellipse)}));
242
243 layer->Paint(display_list_paint_context());
244 DisplayListBuilder expected_builder;
245 /* (ClipRSuperellipse)layer::Paint */ {
246 expected_builder.Save();
247 {
248 expected_builder.ClipRoundSuperellipse(clip_rsuperellipse);
249 /* mock_layer::Paint */ {
250 expected_builder.DrawPath(child_path, child_paint);
251 }
252 }
253 expected_builder.Restore();
254 }
255 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
256}
257
258static bool ReadbackResult(PrerollContext* context,
259 Clip clip_behavior,
260 const std::shared_ptr<Layer>& child,
261 bool before) {
262 const DlRect layer_bounds = DlRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
263 const DlRoundSuperellipse layer_rsuperellipse =
264 DlRoundSuperellipse::MakeRect(layer_bounds);
265 auto layer = std::make_shared<ClipRSuperellipseLayer>(layer_rsuperellipse,
266 clip_behavior);
267 if (child != nullptr) {
268 layer->Add(child);
269 }
270 context->surface_needs_readback = before;
271 layer->Preroll(context);
272 return context->surface_needs_readback;
273}
274
276 PrerollContext* context = preroll_context();
277 DlPath path;
278 DlPaint paint;
279
280 const Clip hard = Clip::kHardEdge;
281 const Clip soft = Clip::kAntiAlias;
282 const Clip save_layer = Clip::kAntiAliasWithSaveLayer;
283
284 std::shared_ptr<MockLayer> nochild;
285 auto reader = std::make_shared<MockLayer>(path, paint);
286 reader->set_fake_reads_surface(true);
287 auto nonreader = std::make_shared<MockLayer>(path, paint);
288
289 // No children, no prior readback -> no readback after
290 EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
291 EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
292 EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
293
294 // No children, prior readback -> readback after
295 EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
296 EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
297 EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
298
299 // Non readback child, no prior readback -> no readback after
300 EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
301 EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
302 EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
303
304 // Non readback child, prior readback -> readback after
305 EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
306 EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
307 EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
308
309 // Readback child, no prior readback -> readback after unless SaveLayer
310 EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
311 EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
312 EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
313
314 // Readback child, prior readback -> readback after
315 EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
316 EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
317 EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
318}
319
320TEST_F(ClipRSuperellipseLayerTest, OpacityInheritance) {
321 auto path1 = DlPath::MakeRectLTRB(10, 10, 30, 30);
322 auto mock1 = MockLayer::MakeOpacityCompatible(path1);
323 DlRect clip_rect = DlRect::MakeWH(500, 500);
324 DlRoundSuperellipse clip_rsuperellipse =
325 DlRoundSuperellipse::MakeRectXY(clip_rect, 20, 20);
326 auto clip_rsuperellipse_layer = std::make_shared<ClipRSuperellipseLayer>(
327 clip_rsuperellipse, Clip::kHardEdge);
328 clip_rsuperellipse_layer->Add(mock1);
329
330 // ClipRectLayer will pass through compatibility from a compatible child
331 PrerollContext* context = preroll_context();
332 clip_rsuperellipse_layer->Preroll(context);
333 EXPECT_EQ(context->renderable_state_flags,
335
336 auto path2 = DlPath::MakeRectLTRB(40, 40, 50, 50);
337 auto mock2 = MockLayer::MakeOpacityCompatible(path2);
338 clip_rsuperellipse_layer->Add(mock2);
339
340 // ClipRectLayer will pass through compatibility from multiple
341 // non-overlapping compatible children
342 clip_rsuperellipse_layer->Preroll(context);
343 EXPECT_EQ(context->renderable_state_flags,
345
346 auto path3 = DlPath::MakeRectLTRB(20, 20, 40, 40);
347 auto mock3 = MockLayer::MakeOpacityCompatible(path3);
348 clip_rsuperellipse_layer->Add(mock3);
349
350 // ClipRectLayer will not pass through compatibility from multiple
351 // overlapping children even if they are individually compatible
352 clip_rsuperellipse_layer->Preroll(context);
353 EXPECT_EQ(context->renderable_state_flags, 0);
354
355 {
356 // ClipRectLayer(aa with saveLayer) will always be compatible
357 auto clip_rsuperellipse_savelayer =
358 std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
360 clip_rsuperellipse_savelayer->Add(mock1);
361 clip_rsuperellipse_savelayer->Add(mock2);
362
363 // Double check first two children are compatible and non-overlapping
364 clip_rsuperellipse_savelayer->Preroll(context);
365 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
366
367 // Now add the overlapping child and test again, should still be compatible
368 clip_rsuperellipse_savelayer->Add(mock3);
369 clip_rsuperellipse_savelayer->Preroll(context);
370 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
371 }
372
373 // An incompatible, but non-overlapping child for the following tests
374 auto path4 = DlPath::MakeRectLTRB(60, 60, 70, 70);
375 auto mock4 = MockLayer::Make(path4);
376
377 {
378 // ClipRectLayer with incompatible child will not be compatible
379 auto clip_rsuperellipse_bad_child =
380 std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
382 clip_rsuperellipse_bad_child->Add(mock1);
383 clip_rsuperellipse_bad_child->Add(mock2);
384
385 // Double check first two children are compatible and non-overlapping
386 clip_rsuperellipse_bad_child->Preroll(context);
387 EXPECT_EQ(context->renderable_state_flags,
389
390 clip_rsuperellipse_bad_child->Add(mock4);
391
392 // The third child is non-overlapping, but not compatible so the
393 // TransformLayer should end up incompatible
394 clip_rsuperellipse_bad_child->Preroll(context);
395 EXPECT_EQ(context->renderable_state_flags, 0);
396 }
397
398 {
399 // ClipRectLayer(aa with saveLayer) will always be compatible
400 auto clip_rsuperellipse_savelayer_bad_child =
401 std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
403 clip_rsuperellipse_savelayer_bad_child->Add(mock1);
404 clip_rsuperellipse_savelayer_bad_child->Add(mock2);
405
406 // Double check first two children are compatible and non-overlapping
407 clip_rsuperellipse_savelayer_bad_child->Preroll(context);
408 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
409
410 // Now add the incompatible child and test again, should still be compatible
411 clip_rsuperellipse_savelayer_bad_child->Add(mock4);
412 clip_rsuperellipse_savelayer_bad_child->Preroll(context);
413 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
414 }
415}
416
417TEST_F(ClipRSuperellipseLayerTest, OpacityInheritancePainting) {
418 auto path1 = DlPath::MakeRectLTRB(10, 10, 30, 30);
419 auto mock1 = MockLayer::MakeOpacityCompatible(path1);
420 auto path2 = DlPath::MakeRectLTRB(40, 40, 50, 50);
421 auto mock2 = MockLayer::MakeOpacityCompatible(path2);
422 DlRect clip_rect = DlRect::MakeWH(500, 500);
423 DlRoundSuperellipse clip_rsuperellipse =
424 DlRoundSuperellipse::MakeRectXY(clip_rect, 20, 20);
425 auto clip_rect_layer = std::make_shared<ClipRSuperellipseLayer>(
426 clip_rsuperellipse, Clip::kAntiAlias);
427 clip_rect_layer->Add(mock1);
428 clip_rect_layer->Add(mock2);
429
430 // ClipRectLayer will pass through compatibility from multiple
431 // non-overlapping compatible children
432 PrerollContext* context = preroll_context();
433 clip_rect_layer->Preroll(context);
434 EXPECT_EQ(context->renderable_state_flags,
436
437 int opacity_alpha = 0x7F;
438 DlPoint offset = DlPoint(10, 10);
439 auto opacity_layer = std::make_shared<OpacityLayer>(opacity_alpha, offset);
440 opacity_layer->Add(clip_rect_layer);
441 opacity_layer->Preroll(context);
442 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
443
444 DisplayListBuilder expected_builder;
445 /* OpacityLayer::Paint() */ {
446 expected_builder.Save();
447 {
448 expected_builder.Translate(offset.x, offset.y);
449 /* ClipRectLayer::Paint() */ {
450 expected_builder.Save();
451 expected_builder.ClipRoundSuperellipse(clip_rsuperellipse,
453 /* child layer1 paint */ {
454 expected_builder.DrawPath(path1, DlPaint().setAlpha(opacity_alpha));
455 }
456 /* child layer2 paint */ {
457 expected_builder.DrawPath(path2, DlPaint().setAlpha(opacity_alpha));
458 }
459 expected_builder.Restore();
460 }
461 }
462 expected_builder.Restore();
463 }
464
465 opacity_layer->Paint(display_list_paint_context());
466 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
467}
468
469TEST_F(ClipRSuperellipseLayerTest, OpacityInheritanceSaveLayerPainting) {
470 auto path1 = DlPath::MakeRectLTRB(10, 10, 30, 30);
471 auto mock1 = MockLayer::MakeOpacityCompatible(path1);
472 auto path2 = DlPath::MakeRectLTRB(20, 20, 40, 40);
473 auto mock2 = MockLayer::MakeOpacityCompatible(path2);
474 auto children_bounds = path1.GetBounds().Union(path2.GetBounds());
475 DlRect clip_rect = DlRect::MakeWH(500, 500);
476 DlRoundSuperellipse clip_rsuperellipse =
477 DlRoundSuperellipse::MakeRectXY(clip_rect, 20, 20);
478 auto clip_rsuperellipse_layer = std::make_shared<ClipRSuperellipseLayer>(
479 clip_rsuperellipse, Clip::kAntiAliasWithSaveLayer);
480 clip_rsuperellipse_layer->Add(mock1);
481 clip_rsuperellipse_layer->Add(mock2);
482
483 // ClipRectLayer will pass through compatibility from multiple
484 // non-overlapping compatible children
485 PrerollContext* context = preroll_context();
486 clip_rsuperellipse_layer->Preroll(context);
487 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
488
489 int opacity_alpha = 0x7F;
490 DlPoint offset = DlPoint(10, 10);
491 auto opacity_layer = std::make_shared<OpacityLayer>(opacity_alpha, offset);
492 opacity_layer->Add(clip_rsuperellipse_layer);
493 opacity_layer->Preroll(context);
494 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
495
496 DisplayListBuilder expected_builder;
497 /* OpacityLayer::Paint() */ {
498 expected_builder.Save();
499 {
500 expected_builder.Translate(offset.x, offset.y);
501 /* ClipRectLayer::Paint() */ {
502 expected_builder.Save();
503 expected_builder.ClipRoundSuperellipse(clip_rsuperellipse,
505 expected_builder.SaveLayer(children_bounds,
506 &DlPaint().setAlpha(opacity_alpha));
507 /* child layer1 paint */ {
508 expected_builder.DrawPath(path1, DlPaint());
509 }
510 /* child layer2 paint */ { //
511 expected_builder.DrawPath(path2, DlPaint());
512 }
513 expected_builder.Restore();
514 }
515 }
516 expected_builder.Restore();
517 }
518
519 opacity_layer->Paint(display_list_paint_context());
520 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
521}
522
524 auto path1 = DlPath::MakeRectLTRB(10, 10, 30, 30);
525 DlPaint paint = DlPaint();
526 auto mock1 = MockLayer::MakeOpacityCompatible(path1);
527 DlRect clip_rect = DlRect::MakeWH(500, 500);
528 DlRoundSuperellipse clip_rsuperellipse =
529 DlRoundSuperellipse::MakeRectXY(clip_rect, 20, 20);
530 auto layer = std::make_shared<ClipRSuperellipseLayer>(
531 clip_rsuperellipse, Clip::kAntiAliasWithSaveLayer);
532 layer->Add(mock1);
533
534 auto initial_transform = DlMatrix::MakeTranslation({50.0, 25.5});
535 DlMatrix cache_ctm = initial_transform;
536 DisplayListBuilder cache_canvas;
537 cache_canvas.Transform(cache_ctm);
538
539 use_mock_raster_cache();
540 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
541
542 const auto* clip_cache_item = layer->raster_cache_item();
543
544 layer->Preroll(preroll_context());
545 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
546
547 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
548 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
549
550 layer->Preroll(preroll_context());
551 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
552 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
553 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
554
555 layer->Preroll(preroll_context());
556 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
557 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
558 EXPECT_EQ(clip_cache_item->cache_state(),
560 EXPECT_TRUE(raster_cache()->Draw(clip_cache_item->GetId().value(),
561 cache_canvas, &paint));
562}
563
564TEST_F(ClipRSuperellipseLayerTest, NoSaveLayerShouldNotCache) {
565 auto path1 = DlPath::MakeRectLTRB(10, 10, 30, 30);
566
567 auto mock1 = MockLayer::MakeOpacityCompatible(path1);
568 DlRect clip_rect = DlRect::MakeWH(500, 500);
569 DlRoundSuperellipse clip_rsuperellipse =
570 DlRoundSuperellipse::MakeRectXY(clip_rect, 20, 20);
571 auto layer = std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
573 layer->Add(mock1);
574
575 auto initial_transform = DlMatrix::MakeTranslation({50.0, 25.5});
576
577 use_mock_raster_cache();
578 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
579
580 const auto* clip_cache_item = layer->raster_cache_item();
581
582 layer->Preroll(preroll_context());
583 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
584
585 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
586 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
587
588 layer->Preroll(preroll_context());
589 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
590 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
591 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
592
593 layer->Preroll(preroll_context());
594 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
595 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
596 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
597}
598
599TEST_F(ClipRSuperellipseLayerTest, EmptyClipDoesNotCullPlatformView) {
600 const DlPoint view_offset = DlPoint(0.0f, 0.0f);
601 const DlSize view_size = DlSize(8.0f, 8.0f);
602 const int64_t view_id = 42;
603 auto platform_view =
604 std::make_shared<PlatformViewLayer>(view_offset, view_size, view_id);
605
606 DlRoundSuperellipse clip_rsuperellipse =
608 auto clip = std::make_shared<ClipRSuperellipseLayer>(clip_rsuperellipse,
610 clip->Add(platform_view);
611
612 auto embedder = MockViewEmbedder();
613 DisplayListBuilder fake_overlay_builder;
614 embedder.AddCanvas(&fake_overlay_builder);
615 preroll_context()->view_embedder = &embedder;
616 paint_context().view_embedder = &embedder;
617
618 clip->Preroll(preroll_context());
619 EXPECT_EQ(embedder.prerolled_views(), std::vector<int64_t>({view_id}));
620
621 clip->Paint(paint_context());
622 EXPECT_EQ(embedder.painted_views(), std::vector<int64_t>({view_id}));
623}
624
625} // namespace testing
626} // namespace flutter
627
628// NOLINTEND(bugprone-unchecked-optional-access)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
static DlPath MakeRectLTRB(DlScalar left, DlScalar top, DlScalar right, DlScalar bottom)
Definition dl_path.cc:43
static DlPath MakeRect(const DlRect &rect)
Definition dl_path.cc:39
static DlPath MakeOval(const DlRect &bounds)
Definition dl_path.cc:57
static constexpr int kSaveLayerRenderFlags
Definition layer.h:118
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:67
static std::shared_ptr< MockLayer > Make(const DlPath &path, DlPaint paint=DlPaint())
Definition mock_layer.h:30
static std::shared_ptr< MockLayer > MakeOpacityCompatible(const DlPath &path)
Definition mock_layer.h:35
G_BEGIN_DECLS FlutterViewId view_id
TEST_F(DisplayListTest, Defaults)
LayerTestBase<::testing::Test > LayerTest
Definition layer_test.h:177
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
static bool ReadbackResult(PrerollContext *context, Clip clip_behavior, const std::shared_ptr< Layer > &child, bool before)
@ kAntiAlias
Definition layer.h:43
@ kAntiAliasWithSaveLayer
Definition layer.h:43
@ kNone
Definition layer.h:43
@ kHardEdge
Definition layer.h:43
impeller::Matrix DlMatrix
impeller::Rect DlRect
impeller::RoundSuperellipse DlRoundSuperellipse
impeller::Size DlSize
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
static constexpr DlRect kGiantRect
Definition layer.h:40
impeller::Point DlPoint
flutter::DlPath DlPath
flutter::DlPaint DlPaint
static constexpr DlColor kYellow()
Definition dl_color.h:76
bool surface_needs_readback
Definition layer.h:51
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
constexpr Quad Transform(const Quad &quad) const
Definition matrix.h:623
static RoundSuperellipse MakeRect(const Rect &rect)
static RoundSuperellipse MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
static constexpr TRect MakeWH(Type width, Type height)
Definition rect.h:140
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition rect.h:438