Flutter Engine
The Flutter Engine
clip_path_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/clip_path_layer.h"
6
7#include "flutter/flow/layers/layer_tree.h"
8#include "flutter/flow/layers/opacity_layer.h"
9#include "flutter/flow/layers/platform_view_layer.h"
10#include "flutter/flow/raster_cache_item.h"
11#include "flutter/flow/testing/layer_test.h"
12#include "flutter/flow/testing/mock_embedder.h"
13#include "flutter/flow/testing/mock_layer.h"
14#include "gtest/gtest.h"
15
16// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
17// NOLINTBEGIN(bugprone-unchecked-optional-access)
18
19namespace flutter {
20namespace testing {
21
23
25
26#ifndef NDEBUG
27TEST_F(ClipPathLayerTest, ClipNoneBehaviorDies) {
28 EXPECT_DEATH_IF_SUPPORTED(
29 auto clip = std::make_shared<ClipPathLayer>(SkPath(), Clip::kNone),
30 "clip_behavior != Clip::kNone");
31}
32
33TEST_F(ClipPathLayerTest, PaintingEmptyLayerDies) {
34 auto layer = std::make_shared<ClipPathLayer>(SkPath(), Clip::kHardEdge);
35
36 layer->Preroll(preroll_context());
37
38 // Untouched
39 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), kGiantRect);
40 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
41
42 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
43 EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect);
44 EXPECT_FALSE(layer->needs_painting(paint_context()));
45
46 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
47 "needs_painting\\(context\\)");
48}
49
50TEST_F(ClipPathLayerTest, PaintBeforePrerollDies) {
51 const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
52 const SkPath layer_path = SkPath().addRect(layer_bounds);
53 auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::kHardEdge);
54 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
55 EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect);
56 EXPECT_FALSE(layer->needs_painting(paint_context()));
57
58 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
59 "needs_painting\\(context\\)");
60}
61
62TEST_F(ClipPathLayerTest, PaintingCulledLayerDies) {
63 const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
64 const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
65 const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
66 const SkRect distant_bounds = SkRect::MakeXYWH(100.0, 100.0, 10.0, 10.0);
67 const SkPath child_path = SkPath().addRect(child_bounds);
68 const SkPath layer_path = SkPath().addRect(layer_bounds);
69 auto mock_layer = std::make_shared<MockLayer>(child_path);
70 auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::kHardEdge);
71 layer->Add(mock_layer);
72
73 // Cull these children
74 preroll_context()->state_stack.set_preroll_delegate(distant_bounds,
75 initial_matrix);
76 layer->Preroll(preroll_context());
77
78 // Untouched
79 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), distant_bounds);
80 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
81
82 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
83 EXPECT_EQ(layer->paint_bounds(), child_bounds);
84 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
85 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
86 EXPECT_TRUE(layer->needs_painting(paint_context()));
87 EXPECT_EQ(mock_layer->parent_cull_rect(), kEmptyRect);
88 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
89 EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
90
91 auto mutator = paint_context().state_stack.save();
92 mutator.clipRect(distant_bounds, false);
93 EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
94 EXPECT_FALSE(layer->needs_painting(paint_context()));
95 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
96 "needs_painting\\(context\\)");
97}
98#endif
99
100TEST_F(ClipPathLayerTest, ChildOutsideBounds) {
101 const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
102 const SkRect local_cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0);
103 const SkRect device_cull_bounds = initial_matrix.mapRect(local_cull_bounds);
104 const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
105 const SkRect clip_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
106 const SkPath child_path = SkPath().addRect(child_bounds);
107 const SkPath clip_path = SkPath().addRect(clip_bounds);
108 const DlPaint child_paint = DlPaint(DlColor::kYellow());
109 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
110 auto layer = std::make_shared<ClipPathLayer>(clip_path, Clip::kHardEdge);
111 layer->Add(mock_layer);
112
113 SkRect clip_cull_rect = local_cull_bounds;
114 ASSERT_TRUE(clip_cull_rect.intersect(clip_bounds));
115 SkRect clip_layer_bounds = child_bounds;
116 ASSERT_TRUE(clip_layer_bounds.intersect(clip_bounds));
117
118 // Set up both contexts to cull clipped child
119 preroll_context()->state_stack.set_preroll_delegate(device_cull_bounds,
120 initial_matrix);
121 paint_context().canvas->ClipRect(device_cull_bounds);
122 paint_context().canvas->Transform(initial_matrix);
123
124 layer->Preroll(preroll_context());
125 // Untouched
126 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(),
127 device_cull_bounds);
128 EXPECT_EQ(preroll_context()->state_stack.local_cull_rect(),
129 local_cull_bounds);
130 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
131
132 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
133 EXPECT_EQ(layer->paint_bounds(), clip_layer_bounds);
134 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
135 EXPECT_EQ(mock_layer->parent_cull_rect(), clip_cull_rect);
136 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
137 EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(clip_path)}));
138
139 EXPECT_FALSE(layer->needs_painting(paint_context()));
140 EXPECT_FALSE(mock_layer->needs_painting(paint_context()));
141 // Top level layer not visible so calling layer->Paint()
142 // would trip an FML_DCHECK
143}
144
145TEST_F(ClipPathLayerTest, FullyContainedChild) {
146 const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
147 const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0);
148 const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
149 const SkPath child_path =
150 SkPath().addRect(child_bounds).addOval(child_bounds.makeInset(0.1, 0.1));
151 const SkPath layer_path =
152 SkPath().addRect(layer_bounds).addOval(layer_bounds.makeInset(0.1, 0.1));
153 const DlPaint child_paint = DlPaint(DlColor::kYellow());
154 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
155 auto layer = std::make_shared<ClipPathLayer>(layer_path, Clip::kHardEdge);
156 layer->Add(mock_layer);
157
158 preroll_context()->state_stack.set_preroll_delegate(initial_matrix);
159 layer->Preroll(preroll_context());
160
161 // Untouched
162 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(), kGiantRect);
163 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
164
165 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
166 EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
167 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
168 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
169 EXPECT_TRUE(layer->needs_painting(paint_context()));
170 EXPECT_EQ(mock_layer->parent_cull_rect(), layer_bounds);
171 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
172 EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)}));
173
174 layer->Paint(display_list_paint_context());
175 DisplayListBuilder expected_builder;
176 /* (ClipPath)layer::Paint */ {
177 expected_builder.Save();
178 {
179 expected_builder.ClipPath(layer_path);
180 /* mock_layer::Paint */ {
181 expected_builder.DrawPath(child_path, child_paint);
182 }
183 }
184 expected_builder.Restore();
185 }
186 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
187}
188
189TEST_F(ClipPathLayerTest, PartiallyContainedChild) {
190 const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f);
191 const SkRect local_cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 4.0, 5.5);
192 const SkRect device_cull_bounds = initial_matrix.mapRect(local_cull_bounds);
193 const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0);
194 const SkRect clip_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
195 const SkPath child_path =
196 SkPath().addRect(child_bounds).addOval(child_bounds.makeInset(0.1, 0.1));
197 const SkPath clip_path =
198 SkPath().addRect(clip_bounds).addOval(clip_bounds.makeInset(0.1, 0.1));
199 const DlPaint child_paint = DlPaint(DlColor::kYellow());
200 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
201 auto layer = std::make_shared<ClipPathLayer>(clip_path, Clip::kHardEdge);
202 layer->Add(mock_layer);
203
204 SkRect clip_cull_rect = local_cull_bounds;
205 ASSERT_TRUE(clip_cull_rect.intersect(clip_bounds));
206 SkRect clip_layer_bounds = child_bounds;
207 ASSERT_TRUE(clip_layer_bounds.intersect(clip_bounds));
208
209 // Cull child
210 preroll_context()->state_stack.set_preroll_delegate(device_cull_bounds,
211 initial_matrix);
212 layer->Preroll(preroll_context());
213
214 // Untouched
215 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(),
216 device_cull_bounds);
217 EXPECT_EQ(preroll_context()->state_stack.local_cull_rect(),
218 local_cull_bounds);
219 EXPECT_TRUE(preroll_context()->state_stack.is_empty());
220
221 EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
222 EXPECT_EQ(layer->paint_bounds(), clip_layer_bounds);
223 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
224 EXPECT_TRUE(mock_layer->needs_painting(paint_context()));
225 EXPECT_TRUE(layer->needs_painting(paint_context()));
226 EXPECT_EQ(mock_layer->parent_cull_rect(), clip_cull_rect);
227 EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix);
228 EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(clip_path)}));
229
230 layer->Paint(display_list_paint_context());
231 DisplayListBuilder expected_builder;
232 /* (ClipPath)layer::Paint */ {
233 expected_builder.Save();
234 {
235 expected_builder.ClipPath(clip_path);
236 /* mock_layer::Paint */ {
237 expected_builder.DrawPath(child_path, child_paint);
238 }
239 }
240 expected_builder.Restore();
241 }
242 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
243}
244
245static bool ReadbackResult(PrerollContext* context,
246 Clip clip_behavior,
247 const std::shared_ptr<Layer>& child,
248 bool before) {
249 const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0);
250 const SkPath layer_path = SkPath().addRect(layer_bounds);
251 auto layer = std::make_shared<ClipPathLayer>(layer_path, clip_behavior);
252 if (child != nullptr) {
253 layer->Add(child);
254 }
255 context->surface_needs_readback = before;
256 layer->Preroll(context);
257 return context->surface_needs_readback;
258}
259
260TEST_F(ClipPathLayerTest, Readback) {
261 PrerollContext* context = preroll_context();
262 SkPath path;
264
265 const Clip hard = Clip::kHardEdge;
266 const Clip soft = Clip::kAntiAlias;
267 const Clip save_layer = Clip::kAntiAliasWithSaveLayer;
268
269 std::shared_ptr<MockLayer> nochild;
270 auto reader = std::make_shared<MockLayer>(path, paint);
271 reader->set_fake_reads_surface(true);
272 auto nonreader = std::make_shared<MockLayer>(path, paint);
273
274 // No children, no prior readback -> no readback after
275 EXPECT_FALSE(ReadbackResult(context, hard, nochild, false));
276 EXPECT_FALSE(ReadbackResult(context, soft, nochild, false));
277 EXPECT_FALSE(ReadbackResult(context, save_layer, nochild, false));
278
279 // No children, prior readback -> readback after
280 EXPECT_TRUE(ReadbackResult(context, hard, nochild, true));
281 EXPECT_TRUE(ReadbackResult(context, soft, nochild, true));
282 EXPECT_TRUE(ReadbackResult(context, save_layer, nochild, true));
283
284 // Non readback child, no prior readback -> no readback after
285 EXPECT_FALSE(ReadbackResult(context, hard, nonreader, false));
286 EXPECT_FALSE(ReadbackResult(context, soft, nonreader, false));
287 EXPECT_FALSE(ReadbackResult(context, save_layer, nonreader, false));
288
289 // Non readback child, prior readback -> readback after
290 EXPECT_TRUE(ReadbackResult(context, hard, nonreader, true));
291 EXPECT_TRUE(ReadbackResult(context, soft, nonreader, true));
292 EXPECT_TRUE(ReadbackResult(context, save_layer, nonreader, true));
293
294 // Readback child, no prior readback -> readback after unless SaveLayer
295 EXPECT_TRUE(ReadbackResult(context, hard, reader, false));
296 EXPECT_TRUE(ReadbackResult(context, soft, reader, false));
297 EXPECT_FALSE(ReadbackResult(context, save_layer, reader, false));
298
299 // Readback child, prior readback -> readback after
300 EXPECT_TRUE(ReadbackResult(context, hard, reader, true));
301 EXPECT_TRUE(ReadbackResult(context, soft, reader, true));
302 EXPECT_TRUE(ReadbackResult(context, save_layer, reader, true));
303}
304
305TEST_F(ClipPathLayerTest, OpacityInheritance) {
306 auto path1 = SkPath().addRect({10, 10, 30, 30});
308 auto layer_clip = SkPath()
309 .addRect(SkRect::MakeLTRB(5, 5, 25, 25))
310 .addOval(SkRect::MakeLTRB(20, 20, 40, 50));
311 auto clip_path_layer =
312 std::make_shared<ClipPathLayer>(layer_clip, Clip::kHardEdge);
313 clip_path_layer->Add(mock1);
314
315 // ClipRectLayer will pass through compatibility from a compatible child
316 PrerollContext* context = preroll_context();
317 clip_path_layer->Preroll(context);
318 EXPECT_EQ(context->renderable_state_flags,
320
321 auto path2 = SkPath().addRect({40, 40, 50, 50});
323 clip_path_layer->Add(mock2);
324
325 // ClipRectLayer will pass through compatibility from multiple
326 // non-overlapping compatible children
327 clip_path_layer->Preroll(context);
328 EXPECT_EQ(context->renderable_state_flags,
330
331 auto path3 = SkPath().addRect({20, 20, 40, 40});
333 clip_path_layer->Add(mock3);
334
335 // ClipRectLayer will not pass through compatibility from multiple
336 // overlapping children even if they are individually compatible
337 clip_path_layer->Preroll(context);
338 EXPECT_EQ(context->renderable_state_flags, 0);
339
340 {
341 // ClipRectLayer(aa with saveLayer) will always be compatible
342 auto clip_path_savelayer = std::make_shared<ClipPathLayer>(
344 clip_path_savelayer->Add(mock1);
345 clip_path_savelayer->Add(mock2);
346
347 // Double check first two children are compatible and non-overlapping
348 clip_path_savelayer->Preroll(context);
349 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
350
351 // Now add the overlapping child and test again, should still be compatible
352 clip_path_savelayer->Add(mock3);
353 clip_path_savelayer->Preroll(context);
354 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
355 }
356
357 // An incompatible, but non-overlapping child for the following tests
358 auto path4 = SkPath().addRect({60, 60, 70, 70});
359 auto mock4 = MockLayer::Make(path4);
360
361 {
362 // ClipRectLayer with incompatible child will not be compatible
363 auto clip_path_bad_child =
364 std::make_shared<ClipPathLayer>(layer_clip, Clip::kHardEdge);
365 clip_path_bad_child->Add(mock1);
366 clip_path_bad_child->Add(mock2);
367
368 // Double check first two children are compatible and non-overlapping
369 clip_path_bad_child->Preroll(context);
370 EXPECT_EQ(context->renderable_state_flags,
372
373 clip_path_bad_child->Add(mock4);
374
375 // The third child is non-overlapping, but not compatible so the
376 // TransformLayer should end up incompatible
377 clip_path_bad_child->Preroll(context);
378 EXPECT_EQ(context->renderable_state_flags, 0);
379 }
380
381 {
382 // ClipRectLayer(aa with saveLayer) will always be compatible
383 auto clip_path_savelayer_bad_child = std::make_shared<ClipPathLayer>(
385 clip_path_savelayer_bad_child->Add(mock1);
386 clip_path_savelayer_bad_child->Add(mock2);
387
388 // Double check first two children are compatible and non-overlapping
389 clip_path_savelayer_bad_child->Preroll(context);
390 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
391
392 // Now add the incompatible child and test again, should still be compatible
393 clip_path_savelayer_bad_child->Add(mock4);
394 clip_path_savelayer_bad_child->Preroll(context);
395 EXPECT_EQ(context->renderable_state_flags, Layer::kSaveLayerRenderFlags);
396 }
397}
398
399TEST_F(ClipPathLayerTest, OpacityInheritancePainting) {
400 auto path1 = SkPath().addRect({10, 10, 30, 30});
402 auto path2 = SkPath().addRect({40, 40, 50, 50});
404 auto layer_clip = SkPath()
405 .addRect(SkRect::MakeLTRB(5, 5, 25, 25))
406 .addOval(SkRect::MakeLTRB(45, 45, 55, 55));
407 auto clip_path_layer =
408 std::make_shared<ClipPathLayer>(layer_clip, Clip::kAntiAlias);
409 clip_path_layer->Add(mock1);
410 clip_path_layer->Add(mock2);
411
412 // ClipRectLayer will pass through compatibility from multiple
413 // non-overlapping compatible children
414 PrerollContext* context = preroll_context();
415 clip_path_layer->Preroll(context);
416 EXPECT_EQ(context->renderable_state_flags,
418
419 int opacity_alpha = 0x7F;
420 SkPoint offset = SkPoint::Make(10, 10);
421 auto opacity_layer = std::make_shared<OpacityLayer>(opacity_alpha, offset);
422 opacity_layer->Add(clip_path_layer);
423 opacity_layer->Preroll(context);
424 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
425
426 DisplayListBuilder expected_builder;
427 /* OpacityLayer::Paint() */ {
428 expected_builder.Save();
429 {
430 expected_builder.Translate(offset.fX, offset.fY);
431 /* ClipRectLayer::Paint() */ {
432 expected_builder.Save();
433 expected_builder.ClipPath(layer_clip, ClipOp::kIntersect, true);
434 /* child layer1 paint */ {
435 expected_builder.DrawPath(path1, DlPaint().setAlpha(opacity_alpha));
436 }
437 /* child layer2 paint */ {
438 expected_builder.DrawPath(path2, DlPaint().setAlpha(opacity_alpha));
439 }
440 expected_builder.Restore();
441 }
442 }
443 expected_builder.Restore();
444 }
445
446 opacity_layer->Paint(display_list_paint_context());
447 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
448}
449
450TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) {
451 auto path1 = SkPath().addRect({10, 10, 30, 30});
453 auto path2 = SkPath().addRect({20, 20, 40, 40});
455 auto children_bounds = path1.getBounds();
456 children_bounds.join(path2.getBounds());
457 auto layer_clip = SkPath()
458 .addRect(SkRect::MakeLTRB(5, 5, 25, 25))
459 .addOval(SkRect::MakeLTRB(20, 20, 40, 50));
460 auto clip_path_layer = std::make_shared<ClipPathLayer>(
462 clip_path_layer->Add(mock1);
463 clip_path_layer->Add(mock2);
464
465 // ClipRectLayer will pass through compatibility from multiple
466 // non-overlapping compatible children
467 PrerollContext* context = preroll_context();
468 clip_path_layer->Preroll(context);
470
471 int opacity_alpha = 0x7F;
472 SkPoint offset = SkPoint::Make(10, 10);
473 auto opacity_layer = std::make_shared<OpacityLayer>(opacity_alpha, offset);
474 opacity_layer->Add(clip_path_layer);
475 opacity_layer->Preroll(context);
476 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
477
478 DisplayListBuilder expected_builder;
479 /* OpacityLayer::Paint() */ {
480 expected_builder.Save();
481 {
482 expected_builder.Translate(offset.fX, offset.fY);
483 /* ClipRectLayer::Paint() */ {
484 expected_builder.Save();
485 expected_builder.ClipPath(layer_clip, ClipOp::kIntersect, true);
486 expected_builder.SaveLayer(&children_bounds,
487 &DlPaint().setAlpha(opacity_alpha));
488 /* child layer1 paint */ {
489 expected_builder.DrawPath(path1, DlPaint());
490 }
491 /* child layer2 paint */ { //
492 expected_builder.DrawPath(path2, DlPaint());
493 }
494 expected_builder.Restore();
495 }
496 }
497 expected_builder.Restore();
498 }
499
500 opacity_layer->Paint(display_list_paint_context());
501 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
502}
503
505 auto path1 = SkPath().addRect({10, 10, 30, 30});
507 auto layer_clip = SkPath()
508 .addRect(SkRect::MakeLTRB(5, 5, 25, 25))
509 .addOval(SkRect::MakeLTRB(20, 20, 40, 50));
510 auto layer = std::make_shared<ClipPathLayer>(layer_clip,
512 layer->Add(mock1);
513
514 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
515 SkMatrix cache_ctm = initial_transform;
516 DisplayListBuilder cache_canvas;
517 cache_canvas.Transform(cache_ctm);
518
519 use_mock_raster_cache();
520 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
521
522 const auto* clip_cache_item = layer->raster_cache_item();
523
524 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
525
526 layer->Preroll(preroll_context());
527 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
528
529 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
530 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
531
532 layer->Preroll(preroll_context());
533 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
534 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
535 EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
536
537 layer->Preroll(preroll_context());
538 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
539 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
540 EXPECT_EQ(clip_cache_item->cache_state(),
541 RasterCacheItem::CacheState::kCurrent);
543 EXPECT_TRUE(raster_cache()->Draw(clip_cache_item->GetId().value(),
544 cache_canvas, &paint));
545}
546
547TEST_F(ClipPathLayerTest, EmptyClipDoesNotCullPlatformView) {
548 const SkPoint view_offset = SkPoint::Make(0.0f, 0.0f);
549 const SkSize view_size = SkSize::Make(8.0f, 8.0f);
550 const int64_t view_id = 42;
551 auto platform_view =
552 std::make_shared<PlatformViewLayer>(view_offset, view_size, view_id);
553
554 auto layer_clip = SkPath().addRect(kEmptyRect);
555 auto clip = std::make_shared<ClipPathLayer>(layer_clip,
557 clip->Add(platform_view);
558
559 auto embedder = MockViewEmbedder();
560 DisplayListBuilder fake_overlay_builder;
561 embedder.AddCanvas(&fake_overlay_builder);
562 preroll_context()->view_embedder = &embedder;
563 paint_context().view_embedder = &embedder;
564
565 clip->Preroll(preroll_context());
566 EXPECT_EQ(embedder.prerolled_views(), std::vector<int64_t>({view_id}));
567
568 clip->Paint(paint_context());
569 EXPECT_EQ(embedder.painted_views(), std::vector<int64_t>({view_id}));
570}
571
572} // namespace testing
573} // namespace flutter
574
575// NOLINTEND(bugprone-unchecked-optional-access)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
static SkPath path1()
static SkPath path4()
static SkPath path3()
static SkPath path2()
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
Definition: SkPath.h:59
const SkRect & getBounds() const
Definition: SkPath.cpp:430
SkPath & addOval(const SkRect &oval, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1106
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition: SkPath.cpp:864
void Transform(const SkMatrix *matrix) override
Definition: dl_builder.cc:919
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 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
void ClipPath(const SkPath &path, ClipOp clip_op=ClipOp::kIntersect, bool is_aa=false) override
Definition: dl_builder.cc:999
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 constexpr int kSaveLayerRenderFlags
Definition: layer.h:132
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
TEST_F(DisplayListTest, Defaults)
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:210
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
static constexpr SkRect kEmptyRect
Definition: mock_canvas.h:30
static bool ReadbackResult(PrerollContext *context, Clip clip_behavior, const std::shared_ptr< Layer > &child, bool before)
Clip
Definition: layer.h:53
@ kAntiAlias
Definition: layer.h:53
@ kAntiAliasWithSaveLayer
Definition: layer.h:53
@ kNone
Definition: layer.h:53
@ kHardEdge
Definition: layer.h:53
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: switches.h:57
static constexpr SkRect kGiantRect
Definition: layer.h:50
flutter::DlPaint DlPaint
SeparatedVector2 offset
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
bool intersect(const SkRect &r)
Definition: SkRect.cpp:114
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
SkRect makeInset(float dx, float dy) const
Definition: SkRect.h:987
void join(const SkRect &r)
Definition: SkRect.cpp:126
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 kYellow()
Definition: dl_color.h:29
bool surface_needs_readback
Definition: layer.h:61
int renderable_state_flags
Definition: layer.h:83
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678