Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
image_filter_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/display_list/dl_tile_mode.h"
6#include "flutter/flow/layers/image_filter_layer.h"
7
8#include "flutter/flow/layers/layer_tree.h"
9#include "flutter/flow/layers/transform_layer.h"
10#include "flutter/flow/testing/diff_context_test.h"
11#include "flutter/flow/testing/layer_test.h"
12#include "flutter/flow/testing/mock_layer.h"
13#include "flutter/fml/macros.h"
14#include "gtest/gtest.h"
15#include "include/core/SkPath.h"
17
18// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
19// NOLINTBEGIN(bugprone-unchecked-optional-access)
20
21namespace flutter {
22namespace testing {
23
25
26#ifndef NDEBUG
27TEST_F(ImageFilterLayerTest, PaintingEmptyLayerDies) {
28 auto layer = std::make_shared<ImageFilterLayer>(nullptr);
29
30 layer->Preroll(preroll_context());
31 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
32 EXPECT_FALSE(layer->needs_painting(paint_context()));
33
34 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
35 "needs_painting\\(context\\)");
36}
37
38TEST_F(ImageFilterLayerTest, PaintBeforePrerollDies) {
39 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
40 const SkPath child_path = SkPath().addRect(child_bounds);
41 auto mock_layer = std::make_shared<MockLayer>(child_path);
42 auto layer = std::make_shared<ImageFilterLayer>(nullptr);
43 layer->Add(mock_layer);
44
45 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
46 EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect);
47 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
48 "needs_painting\\(context\\)");
49}
50#endif
51
52TEST_F(ImageFilterLayerTest, EmptyFilter) {
53 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
54 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
55 const SkPath child_path = SkPath().addRect(child_bounds);
56 const DlPaint child_paint = DlPaint(DlColor::kYellow());
57 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
58 auto layer = std::make_shared<ImageFilterLayer>(nullptr);
59 layer->Add(mock_layer);
60
61 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
62 layer->Preroll(preroll_context());
63 EXPECT_EQ(layer->paint_bounds(), child_bounds);
64 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
65 EXPECT_TRUE(layer->needs_painting(paint_context()));
66 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
67
68 layer->Paint(display_list_paint_context());
69 DisplayListBuilder expected_builder;
70 /* (ImageFilter)layer::Paint */ {
71 expected_builder.Save();
72 /* mock_layer1::Paint */ {
73 expected_builder.DrawPath(child_path, child_paint);
74 }
75 expected_builder.Restore();
76 }
77 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
78}
79
80TEST_F(ImageFilterLayerTest, SimpleFilter) {
81 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
82 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
83 const SkPath child_path = SkPath().addRect(child_bounds);
84 const DlPaint child_paint = DlPaint(DlColor::kYellow());
85 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
87 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
88 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
89 layer->Add(mock_layer);
90
91 const SkRect child_rounded_bounds =
92 SkRect::MakeLTRB(5.0f, 6.0f, 21.0f, 22.0f);
93
94 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
95 layer->Preroll(preroll_context());
96 EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds);
97 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
98 EXPECT_TRUE(layer->needs_painting(paint_context()));
99 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
100
101 DisplayListBuilder expected_builder;
102 /* ImageFilterLayer::Paint() */ {
103 DlPaint dl_paint;
104 dl_paint.setImageFilter(dl_image_filter.get());
105 expected_builder.SaveLayer(&child_bounds, &dl_paint);
106 {
107 /* MockLayer::Paint() */ {
108 expected_builder.DrawPath(child_path, DlPaint(DlColor::kYellow()));
109 }
110 }
111 }
112 expected_builder.Restore();
113 auto expected_display_list = expected_builder.Build();
114
115 layer->Paint(display_list_paint_context());
116 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
117}
118
119TEST_F(ImageFilterLayerTest, SimpleFilterWithOffset) {
120 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
121 const SkRect initial_cull_rect = SkRect::MakeLTRB(0, 0, 100, 100);
122 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
123 const SkPath child_path = SkPath().addRect(child_bounds);
124 const DlPaint child_paint = DlPaint(DlColor::kYellow());
125 const SkPoint layer_offset = SkPoint::Make(5.5, 6.5);
126 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
128 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
129 auto layer =
130 std::make_shared<ImageFilterLayer>(dl_image_filter, layer_offset);
131 layer->Add(mock_layer);
132
133 SkMatrix child_matrix = initial_transform;
134 child_matrix.preTranslate(layer_offset.fX, layer_offset.fY);
135 const SkRect child_rounded_bounds =
136 SkRect::MakeLTRB(10.5f, 12.5f, 26.5f, 28.5f);
137
138 preroll_context()->state_stack.set_preroll_delegate(initial_cull_rect,
139 initial_transform);
140 layer->Preroll(preroll_context());
141 EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds);
142 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
143 EXPECT_TRUE(layer->needs_painting(paint_context()));
144 EXPECT_EQ(mock_layer->parent_matrix(), child_matrix);
145 EXPECT_EQ(preroll_context()->state_stack.device_cull_rect(),
146 initial_cull_rect);
147
148 DisplayListBuilder expected_builder;
149 /* ImageFilterLayer::Paint() */ {
150 expected_builder.Save();
151 {
152 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
153 DlPaint dl_paint;
154 dl_paint.setImageFilter(dl_image_filter.get());
155 expected_builder.SaveLayer(&child_bounds, &dl_paint);
156 {
157 /* MockLayer::Paint() */ {
158 expected_builder.DrawPath(child_path, DlPaint(DlColor::kYellow()));
159 }
160 }
161 expected_builder.Restore();
162 }
163 expected_builder.Restore();
164 }
165 auto expected_display_list = expected_builder.Build();
166
167 layer->Paint(display_list_paint_context());
168 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
169}
170
171TEST_F(ImageFilterLayerTest, SimpleFilterBounds) {
172 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
173 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
174 const SkPath child_path = SkPath().addRect(child_bounds);
175 const DlPaint child_paint = DlPaint(DlColor::kYellow());
176 const SkMatrix filter_transform = SkMatrix::Scale(2.0, 2.0);
177
178 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
179 filter_transform, DlImageSampling::kMipmapLinear);
180 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
181 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
182 layer->Add(mock_layer);
183
184 const SkRect filter_bounds = SkRect::MakeLTRB(10.0f, 12.0f, 42.0f, 44.0f);
185
186 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
187 layer->Preroll(preroll_context());
188 EXPECT_EQ(layer->paint_bounds(), filter_bounds);
189 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
190 EXPECT_TRUE(layer->needs_painting(paint_context()));
191 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
192
193 DisplayListBuilder expected_builder;
194 /* ImageFilterLayer::Paint() */ {
195 DlPaint dl_paint;
196 dl_paint.setImageFilter(dl_image_filter.get());
197 expected_builder.SaveLayer(&child_bounds, &dl_paint);
198 {
199 /* MockLayer::Paint() */ {
200 expected_builder.DrawPath(child_path, DlPaint(DlColor::kYellow()));
201 }
202 }
203 }
204 expected_builder.Restore();
205 auto expected_display_list = expected_builder.Build();
206
207 layer->Paint(display_list_paint_context());
208 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
209}
210
211TEST_F(ImageFilterLayerTest, MultipleChildren) {
212 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
213 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
214 const SkPath child_path1 = SkPath().addRect(child_bounds);
215 const SkPath child_path2 =
216 SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
217 const DlPaint child_paint1 = DlPaint(DlColor::kYellow());
218 const DlPaint child_paint2 = DlPaint(DlColor::kCyan());
219 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
221 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
222 auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
223 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
224 layer->Add(mock_layer1);
225 layer->Add(mock_layer2);
226
227 SkRect children_bounds = child_path1.getBounds();
228 children_bounds.join(child_path2.getBounds());
229 SkRect children_rounded_bounds = SkRect::Make(children_bounds.roundOut());
230
231 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
232 layer->Preroll(preroll_context());
233 EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
234 EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
235 EXPECT_EQ(layer->paint_bounds(), children_rounded_bounds);
236 EXPECT_EQ(layer->child_paint_bounds(), children_bounds);
237 EXPECT_TRUE(mock_layer1->needs_painting(paint_context()));
238 EXPECT_TRUE(mock_layer2->needs_painting(paint_context()));
239 EXPECT_TRUE(layer->needs_painting(paint_context()));
240 EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
241 EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
242
243 DisplayListBuilder expected_builder;
244 /* ImageFilterLayer::Paint() */ {
245 DlPaint dl_paint;
246 dl_paint.setImageFilter(dl_image_filter.get());
247 expected_builder.SaveLayer(&children_bounds, &dl_paint);
248 {
249 /* MockLayer::Paint() */ {
250 expected_builder.DrawPath(child_path1, DlPaint(DlColor::kYellow()));
251 }
252 /* MockLayer::Paint() */ {
253 expected_builder.DrawPath(child_path2, DlPaint(DlColor::kCyan()));
254 }
255 }
256 }
257 expected_builder.Restore();
258 auto expected_display_list = expected_builder.Build();
259
260 layer->Paint(display_list_paint_context());
261 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
262}
263
265 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
266 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
267 const SkPath child_path1 = SkPath().addRect(child_bounds);
268 const SkPath child_path2 =
269 SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
270 const DlPaint child_paint1 = DlPaint(DlColor::kYellow());
271 const DlPaint child_paint2 = DlPaint(DlColor::kCyan());
272 auto dl_image_filter1 = std::make_shared<DlMatrixImageFilter>(
274 auto dl_image_filter2 = std::make_shared<DlMatrixImageFilter>(
276 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
277 auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
278 auto layer1 = std::make_shared<ImageFilterLayer>(dl_image_filter1);
279 auto layer2 = std::make_shared<ImageFilterLayer>(dl_image_filter2);
280 layer2->Add(mock_layer2);
281 layer1->Add(mock_layer1);
282 layer1->Add(layer2);
283
284 SkRect children_bounds = child_path1.getBounds();
285 children_bounds.join(SkRect::Make(child_path2.getBounds().roundOut()));
286 const SkRect children_rounded_bounds =
287 SkRect::Make(children_bounds.roundOut());
288 const SkRect mock_layer2_rounded_bounds =
289 SkRect::Make(child_path2.getBounds().roundOut());
290
291 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
292 layer1->Preroll(preroll_context());
293 EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
294 EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
295 EXPECT_EQ(layer1->paint_bounds(), children_rounded_bounds);
296 EXPECT_EQ(layer1->child_paint_bounds(), children_bounds);
297 EXPECT_EQ(layer2->paint_bounds(), mock_layer2_rounded_bounds);
298 EXPECT_EQ(layer2->child_paint_bounds(), child_path2.getBounds());
299 EXPECT_TRUE(mock_layer1->needs_painting(paint_context()));
300 EXPECT_TRUE(mock_layer2->needs_painting(paint_context()));
301 EXPECT_TRUE(layer1->needs_painting(paint_context()));
302 EXPECT_TRUE(layer2->needs_painting(paint_context()));
303 EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
304 EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
305
306 DisplayListBuilder expected_builder;
307 /* ImageFilterLayer::Paint() */ {
308 DlPaint dl_paint;
309 dl_paint.setImageFilter(dl_image_filter1.get());
310 expected_builder.SaveLayer(&children_bounds, &dl_paint);
311 {
312 /* MockLayer::Paint() */ {
313 expected_builder.DrawPath(child_path1, DlPaint(DlColor::kYellow()));
314 }
315 /* ImageFilterLayer::Paint() */ {
316 DlPaint child_paint;
317 child_paint.setImageFilter(dl_image_filter2.get());
318 expected_builder.SaveLayer(&child_path2.getBounds(), &child_paint);
319 /* MockLayer::Paint() */ {
320 expected_builder.DrawPath(child_path2, DlPaint(DlColor::kCyan()));
321 }
322 expected_builder.Restore();
323 }
324 }
325 }
326 expected_builder.Restore();
327 auto expected_display_list = expected_builder.Build();
328
329 layer1->Paint(display_list_paint_context());
330 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
331}
332
333TEST_F(ImageFilterLayerTest, Readback) {
334 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
336
337 // ImageFilterLayer does not read from surface
338 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
339 preroll_context()->surface_needs_readback = false;
340 layer->Preroll(preroll_context());
341 EXPECT_FALSE(preroll_context()->surface_needs_readback);
342
343 // ImageFilterLayer blocks child with readback
344 auto mock_layer = std::make_shared<MockLayer>(SkPath(), DlPaint());
345 mock_layer->set_fake_reads_surface(true);
346 layer->Add(mock_layer);
347 preroll_context()->surface_needs_readback = false;
348 layer->Preroll(preroll_context());
349 EXPECT_FALSE(preroll_context()->surface_needs_readback);
350}
351
352TEST_F(ImageFilterLayerTest, CacheChild) {
353 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
355 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
356 auto other_transform = SkMatrix::Scale(1.0, 2.0);
357 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
358 auto mock_layer = std::make_shared<MockLayer>(child_path);
359 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
360 layer->Add(mock_layer);
361
362 SkMatrix cache_ctm = initial_transform;
363 DisplayListBuilder cache_canvas;
364 cache_canvas.Transform(cache_ctm);
365 DisplayListBuilder other_canvas;
366 other_canvas.Transform(other_transform);
367 DlPaint paint;
368
369 use_mock_raster_cache();
370 const auto* cacheable_image_filter_item = layer->raster_cache_item();
371
372 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
373 // ImageFilterLayer default cache itself.
374 EXPECT_EQ(cacheable_image_filter_item->cache_state(),
376 EXPECT_FALSE(cacheable_image_filter_item->Draw(paint_context(), &paint));
377
378 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
379 layer->Preroll(preroll_context());
380 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
381
382 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
383 // The layer_cache_item's strategy is Children, mean we will must cache
384 // his children
385 EXPECT_EQ(cacheable_image_filter_item->cache_state(),
387 EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
388 cache_canvas, &paint));
389 EXPECT_FALSE(raster_cache()->Draw(
390 cacheable_image_filter_item->GetId().value(), other_canvas, &paint));
391}
392
393TEST_F(ImageFilterLayerTest, CacheChildren) {
394 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
396 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
397 auto other_transform = SkMatrix::Scale(1.0, 2.0);
398 DlPaint paint;
399 const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
400 const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
401 auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
402 auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
403 auto offset = SkPoint::Make(54, 24);
404 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter, offset);
405 layer->Add(mock_layer1);
406 layer->Add(mock_layer2);
407
408 SkMatrix cache_ctm = initial_transform;
409 DisplayListBuilder cache_canvas;
410 cache_canvas.Transform(cache_ctm);
411 DisplayListBuilder other_canvas;
412 other_canvas.Transform(other_transform);
413
414 use_mock_raster_cache();
415
416 const auto* cacheable_image_filter_item = layer->raster_cache_item();
417 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
418
419 // ImageFilterLayer default cache itself.
420 EXPECT_EQ(cacheable_image_filter_item->cache_state(),
422 EXPECT_FALSE(cacheable_image_filter_item->Draw(paint_context(), &paint));
423
424 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
425 layer->Preroll(preroll_context());
426 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
427
428 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
429
430 // The layer_cache_item's strategy is Children, mean we will must cache his
431 // children
432 EXPECT_EQ(cacheable_image_filter_item->cache_state(),
434 EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
435 cache_canvas, &paint));
436 EXPECT_FALSE(raster_cache()->Draw(
437 cacheable_image_filter_item->GetId().value(), other_canvas, &paint));
438
439 layer->Preroll(preroll_context());
440
441 SkRect children_bounds = child_path1.getBounds();
442 children_bounds.join(child_path2.getBounds());
443 SkMatrix snapped_matrix = SkMatrix::MakeAll( //
444 1, 0, SkScalarRoundToScalar(offset.fX), //
445 0, 1, SkScalarRoundToScalar(offset.fY), //
446 0, 0, 1);
447 SkMatrix cache_matrix = initial_transform;
448 cache_matrix.preConcat(snapped_matrix);
449 auto transformed_filter = dl_image_filter->makeWithLocalMatrix(cache_matrix);
450
451 layer->Paint(display_list_paint_context());
452 DisplayListBuilder expected_builder;
453 /* (ImageFilter)layer::Paint() */ {
454 expected_builder.Save();
455 {
456 expected_builder.Translate(offset.fX, offset.fY);
457 // translation components already snapped to pixels, intent to
458 // use raster cache won't change them
459 DlPaint dl_paint;
460 dl_paint.setImageFilter(transformed_filter.get());
461 raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
462 expected_builder, &dl_paint);
463 }
464 expected_builder.Restore();
465 }
466 expected_builder.Restore();
467 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
468}
469
470TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) {
471 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
473
474 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
475 auto other_transform = SkMatrix::Scale(1.0, 2.0);
476 auto child_rect = SkRect::MakeWH(5.0f, 5.0f);
477 const SkPath child_path = SkPath().addRect(child_rect);
478 auto mock_layer = std::make_shared<MockLayer>(child_path);
479 auto offset = SkPoint::Make(53.8, 24.4);
480 auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter, offset);
481 layer->Add(mock_layer);
482
483 SkMatrix cache_ctm = initial_transform;
484 DisplayListBuilder cache_canvas;
485 cache_canvas.Transform(cache_ctm);
486 DisplayListBuilder other_canvas;
487 other_canvas.Transform(other_transform);
489
490 SkMatrix snapped_matrix = SkMatrix::MakeAll( //
491 1, 0, SkScalarRoundToScalar(offset.fX), //
492 0, 1, SkScalarRoundToScalar(offset.fY), //
493 0, 0, 1);
494
495 use_mock_raster_cache();
496 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
497 const auto* cacheable_image_filter_item = layer->raster_cache_item();
498 // frame 1.
499 layer->Preroll(preroll_context());
500
501 layer->Paint(display_list_paint_context());
502 {
503 DisplayListBuilder expected_builder;
504 /* (ImageFilter)layer::Paint */ {
505 expected_builder.Save();
506 {
507 expected_builder.Translate(offset.fX, offset.fY);
508 // Snap to pixel translation due to use of raster cache
509 expected_builder.TransformReset();
510 expected_builder.Transform(snapped_matrix);
511 DlPaint save_paint = DlPaint().setImageFilter(dl_image_filter);
512 expected_builder.SaveLayer(&child_rect, &save_paint);
513 {
514 /* mock_layer::Paint */ {
515 expected_builder.DrawPath(child_path, DlPaint());
516 }
517 }
518 expected_builder.Restore();
519 }
520 expected_builder.Restore();
521 }
523 DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
524 }
525
526 // frame 2.
527 layer->Preroll(preroll_context());
528 layer->Paint(display_list_paint_context());
529 // frame 3.
530 layer->Preroll(preroll_context());
531 layer->Paint(display_list_paint_context());
532
533 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
534 // frame1,2 cache the ImageFilter's children layer, frame3 cache the
535 // ImageFilterLayer
536 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)2);
537
538 // ImageFilterLayer default cache itself.
539 EXPECT_EQ(cacheable_image_filter_item->cache_state(),
541 EXPECT_EQ(cacheable_image_filter_item->GetId(),
542 RasterCacheKeyID(layer->unique_id(), RasterCacheKeyType::kLayer));
543 EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
544 cache_canvas, &paint));
545 EXPECT_FALSE(raster_cache()->Draw(
546 cacheable_image_filter_item->GetId().value(), other_canvas, &paint));
547
548 layer->Preroll(preroll_context());
549
550 reset_display_list();
551 layer->Paint(display_list_paint_context());
552 {
553 DisplayListBuilder expected_builder;
554 /* (ImageFilter)layer::Paint */ {
555 expected_builder.Save();
556 {
558 raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
559 expected_builder, nullptr));
560 }
561 expected_builder.Restore();
562 }
564 DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
565 }
566}
567
568TEST_F(ImageFilterLayerTest, OpacityInheritance) {
569 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
570 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
571 const SkPath child_path = SkPath().addRect(child_bounds);
572 const DlPaint child_paint = DlPaint(DlColor::kYellow());
573 auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
575
576 // The mock_layer child will not be compatible with opacity
577 auto mock_layer = MockLayer::Make(child_path, child_paint);
578 auto image_filter_layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
579 image_filter_layer->Add(mock_layer);
580
581 PrerollContext* context = preroll_context();
582 context->state_stack.set_preroll_delegate(initial_transform);
583 image_filter_layer->Preroll(preroll_context());
584 // ImageFilterLayers can always inherit opacity whether or not their
585 // children are compatible.
586 EXPECT_EQ(context->renderable_state_flags,
589
590 int opacity_alpha = 0x7F;
591 SkPoint offset = SkPoint::Make(10, 10);
592 auto opacity_layer = std::make_shared<OpacityLayer>(opacity_alpha, offset);
593 opacity_layer->Add(image_filter_layer);
595 opacity_layer->Preroll(context);
596 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
597
598 DisplayListBuilder expected_builder;
599 /* OpacityLayer::Paint() */ {
600 expected_builder.Save();
601 {
602 expected_builder.Translate(offset.fX, offset.fY);
603 /* ImageFilterLayer::Paint() */ {
604 DlPaint image_filter_paint;
605 image_filter_paint.setColor(DlColor(opacity_alpha << 24));
606 image_filter_paint.setImageFilter(dl_image_filter.get());
607 expected_builder.SaveLayer(&child_path.getBounds(),
608 &image_filter_paint);
609 /* MockLayer::Paint() */ {
610 expected_builder.DrawPath(child_path,
611 DlPaint(child_paint.getColor()));
612 }
613 expected_builder.Restore();
614 }
615 }
616 expected_builder.Restore();
617 }
618
619 opacity_layer->Paint(display_list_paint_context());
620 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
621}
622
624
626 auto dl_blur_filter =
627 std::make_shared<DlBlurImageFilter>(10, 10, DlTileMode::kClamp);
628 {
629 // tests later assume 30px paint area, fail early if that's not the case
630 SkIRect input_bounds;
631 dl_blur_filter->get_input_device_bounds(SkIRect::MakeWH(10, 10),
632 SkMatrix::I(), input_bounds);
633 EXPECT_EQ(input_bounds, SkIRect::MakeLTRB(-30, -30, 40, 40));
634 }
635
636 MockLayerTree l1;
637 auto filter_layer = std::make_shared<ImageFilterLayer>(dl_blur_filter);
638 auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110));
639 filter_layer->Add(std::make_shared<MockLayer>(path));
640 l1.root()->Add(filter_layer);
641
642 auto damage = DiffLayerTree(l1, MockLayerTree());
643 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(70, 70, 140, 140));
644
645 MockLayerTree l2;
646 auto scale = std::make_shared<TransformLayer>(SkMatrix::Scale(2.0, 2.0));
647 scale->Add(filter_layer);
648 l2.root()->Add(scale);
649
650 damage = DiffLayerTree(l2, MockLayerTree());
651 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(140, 140, 280, 280));
652
653 MockLayerTree l3;
654 l3.root()->Add(scale);
655
656 // path outside of ImageFilterLayer
657 auto path1 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 140, 140));
658 l3.root()->Add(std::make_shared<MockLayer>(path1));
659 damage = DiffLayerTree(l3, l2);
660 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(130, 130, 140, 140));
661
662 // path intersecting ImageFilterLayer, shouldn't trigger entire
663 // ImageFilterLayer repaint
664 MockLayerTree l4;
665 l4.root()->Add(scale);
666 auto path2 = SkPath().addRect(SkRect::MakeLTRB(130, 130, 141, 141));
667 l4.root()->Add(std::make_shared<MockLayer>(path2));
668 damage = DiffLayerTree(l4, l3);
669 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(130, 130, 141, 141));
670}
671
672TEST_F(ImageFilterLayerDiffTest, ImageFilterLayerInflatestChildSize) {
673 auto dl_blur_filter =
674 std::make_shared<DlBlurImageFilter>(10, 10, DlTileMode::kClamp);
675
676 {
677 // tests later assume 30px paint area, fail early if that's not the case
678 SkIRect input_bounds;
679 dl_blur_filter->get_input_device_bounds(SkIRect::MakeWH(10, 10),
680 SkMatrix::I(), input_bounds);
681 EXPECT_EQ(input_bounds, SkIRect::MakeLTRB(-30, -30, 40, 40));
682 }
683
684 MockLayerTree l1;
685
686 // Use nested filter layers to check if both contribute to child bounds
687 auto filter_layer_1_1 = std::make_shared<ImageFilterLayer>(dl_blur_filter);
688 auto filter_layer_1_2 = std::make_shared<ImageFilterLayer>(dl_blur_filter);
689 filter_layer_1_1->Add(filter_layer_1_2);
690 auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110));
691 filter_layer_1_2->Add(
692 std::make_shared<MockLayer>(path, DlPaint(DlColor::kYellow())));
693 l1.root()->Add(filter_layer_1_1);
694
695 // second layer tree with identical filter layers but different child layer
696 MockLayerTree l2;
697 auto filter_layer2_1 = std::make_shared<ImageFilterLayer>(dl_blur_filter);
698 filter_layer2_1->AssignOldLayer(filter_layer_1_1.get());
699 auto filter_layer2_2 = std::make_shared<ImageFilterLayer>(dl_blur_filter);
700 filter_layer2_2->AssignOldLayer(filter_layer_1_2.get());
701 filter_layer2_1->Add(filter_layer2_2);
702 filter_layer2_2->Add(
703 std::make_shared<MockLayer>(path, DlPaint(DlColor::kRed())));
704 l2.root()->Add(filter_layer2_1);
705
706 DiffLayerTree(l1, MockLayerTree());
707 auto damage = DiffLayerTree(l2, l1);
708
709 // ensure that filter properly inflated child size
710 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(40, 40, 170, 170));
711}
712
713TEST_F(ImageFilterLayerTest, EmptyFilterWithOffset) {
714 const SkRect child_bounds = SkRect::MakeLTRB(10.0f, 11.0f, 19.0f, 20.0f);
715 const SkPath child_path = SkPath().addRect(child_bounds);
716 const DlPaint child_paint = DlPaint(DlColor::kYellow());
717 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
718 const SkPoint offset = SkPoint::Make(5.0f, 6.0f);
719 auto layer = std::make_shared<ImageFilterLayer>(nullptr, offset);
720 layer->Add(mock_layer);
721
722 layer->Preroll(preroll_context());
723 EXPECT_EQ(layer->paint_bounds(), child_bounds.makeOffset(offset));
724}
725
726} // namespace testing
727} // namespace flutter
728
729// NOLINTEND(bugprone-unchecked-optional-access)
static SkPath path1()
static SkPath path2()
#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 MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition SkMatrix.h:179
static const SkMatrix & I()
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:263
SkMatrix & preConcat(const SkMatrix &other)
Definition SkMatrix.cpp:674
const SkRect & getBounds() const
Definition SkPath.cpp:420
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition SkPath.cpp:854
virtual void Add(std::shared_ptr< Layer > layer)
void Transform(const SkMatrix *matrix) override
void TransformReset() override
void Translate(SkScalar tx, SkScalar ty) override
void DrawPath(const SkPath &path, const DlPaint &paint) override
void SaveLayer(const SkRect *bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr) override
sk_sp< DisplayList > Build()
Definition dl_builder.cc:67
DlColor getColor() const
Definition dl_paint.h:70
DlPaint & setColor(DlColor color)
Definition dl_paint.h:71
DlPaint & setImageFilter(const std::shared_ptr< const DlImageFilter > &filter)
Definition dl_paint.h:158
void set_preroll_delegate(const SkRect &cull_rect, const SkMatrix &matrix)
static constexpr int kCallerCanApplyColorFilter
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 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
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
const Scalar scale
Point offset
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition SkRect.h:91
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
float fY
y-axis value
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
constexpr SkRect makeOffset(float dx, float dy) const
Definition SkRect.h:965
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
static constexpr DlColor kYellow()
Definition dl_color.h:29
static constexpr DlColor kRed()
Definition dl_color.h:24
static constexpr DlColor kCyan()
Definition dl_color.h:27
LayerStateStack & state_stack
Definition layer.h:58
#define EXPECT_TRUE(handle)
Definition unit_test.h:685