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