Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
color_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/display_list.h"
6#include "flutter/display_list/dl_color.h"
7#include "flutter/display_list/dl_paint.h"
8#include "flutter/flow/compositor_context.h"
9#include "flutter/flow/layers/color_filter_layer.h"
10
11#include "flutter/display_list/effects/dl_color_filter.h"
12#include "flutter/flow/layers/layer_tree.h"
13#include "flutter/flow/layers/opacity_layer.h"
14#include "flutter/flow/raster_cache.h"
15#include "flutter/flow/raster_cache_key.h"
16#include "flutter/flow/testing/layer_test.h"
17#include "flutter/flow/testing/mock_layer.h"
18#include "flutter/fml/macros.h"
19
20// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
21// NOLINTBEGIN(bugprone-unchecked-optional-access)
22
23namespace flutter {
24namespace testing {
25
27
28#ifndef NDEBUG
29TEST_F(ColorFilterLayerTest, PaintingEmptyLayerDies) {
30 auto layer = std::make_shared<ColorFilterLayer>(nullptr);
31
32 layer->Preroll(preroll_context());
33 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
34 EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect);
35 EXPECT_FALSE(layer->needs_painting(paint_context()));
36
37 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
38 "needs_painting\\(context\\)");
39}
40
41TEST_F(ColorFilterLayerTest, PaintBeforePrerollDies) {
42 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
43 const SkPath child_path = SkPath().addRect(child_bounds);
44 auto mock_layer = std::make_shared<MockLayer>(child_path);
45
46 auto layer = std::make_shared<ColorFilterLayer>(nullptr);
47 layer->Add(mock_layer);
48
49 EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
50 EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect);
51 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
52 "needs_painting\\(context\\)");
53}
54#endif
55
56TEST_F(ColorFilterLayerTest, EmptyFilter) {
57 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
58 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
59 const SkPath child_path = SkPath().addRect(child_bounds);
60 const DlPaint child_paint = DlPaint(DlColor::kYellow());
61 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
62 auto layer = std::make_shared<ColorFilterLayer>(nullptr);
63 layer->Add(mock_layer);
64
65 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
66 layer->Preroll(preroll_context());
67 EXPECT_EQ(layer->paint_bounds(), child_bounds);
68 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
69 EXPECT_TRUE(layer->needs_painting(paint_context()));
70 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
71
72 layer->Paint(display_list_paint_context());
73 DisplayListBuilder expected_builder;
74 /* (ColorFilter)layer::Paint */ {
75 expected_builder.Save();
76 {
77 /* mock_layer::Paint */ {
78 expected_builder.DrawPath(child_path, child_paint);
79 }
80 }
81 expected_builder.Restore();
82 }
83 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
84}
85
86TEST_F(ColorFilterLayerTest, SimpleFilter) {
87 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
88 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
89 const SkPath child_path = SkPath().addRect(child_bounds);
90 const DlPaint child_paint = DlPaint(DlColor::kYellow());
91
92 auto dl_color_filter = DlLinearToSrgbGammaColorFilter::kInstance;
93 auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
94 auto layer = std::make_shared<ColorFilterLayer>(dl_color_filter);
95 layer->Add(mock_layer);
96
97 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
98 layer->Preroll(preroll_context());
99 EXPECT_EQ(layer->paint_bounds(), child_bounds);
100 EXPECT_EQ(layer->child_paint_bounds(), child_bounds);
101 EXPECT_TRUE(layer->needs_painting(paint_context()));
102 EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
103
104 DisplayListBuilder expected_builder;
105 /* ColorFilterLayer::Paint() */ {
106 DlPaint dl_paint;
107 dl_paint.setColorFilter(dl_color_filter.get());
108 expected_builder.SaveLayer(&child_bounds, &dl_paint);
109 {
110 /* MockLayer::Paint() */ {
111 expected_builder.DrawPath(child_path, DlPaint(DlColor::kYellow()));
112 }
113 }
114 }
115 expected_builder.Restore();
116 auto expected_display_list = expected_builder.Build();
117
118 layer->Paint(display_list_paint_context());
119 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
120}
121
122TEST_F(ColorFilterLayerTest, MultipleChildren) {
123 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
124 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
125 const SkPath child_path1 = SkPath().addRect(child_bounds);
126 const SkPath child_path2 =
127 SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
128 const DlPaint child_paint1 = DlPaint(DlColor::kYellow());
129 const DlPaint child_paint2 = DlPaint(DlColor::kCyan());
130 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
131 auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
132 auto dl_color_filter = DlSrgbToLinearGammaColorFilter::kInstance;
133 auto layer = std::make_shared<ColorFilterLayer>(dl_color_filter);
134 layer->Add(mock_layer1);
135 layer->Add(mock_layer2);
136
137 SkRect children_bounds = child_path1.getBounds();
138 children_bounds.join(child_path2.getBounds());
139 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
140 layer->Preroll(preroll_context());
141 EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
142 EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
143 EXPECT_EQ(layer->paint_bounds(), children_bounds);
144 EXPECT_EQ(layer->child_paint_bounds(), children_bounds);
145 EXPECT_TRUE(mock_layer1->needs_painting(paint_context()));
146 EXPECT_TRUE(mock_layer2->needs_painting(paint_context()));
147 EXPECT_TRUE(layer->needs_painting(paint_context()));
148 EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
149 EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
150
151 DisplayListBuilder expected_builder;
152 /* ColorFilterLayer::Paint() */ {
153 DlPaint dl_paint;
154 dl_paint.setColorFilter(dl_color_filter.get());
155 expected_builder.SaveLayer(&children_bounds, &dl_paint);
156 {
157 /* MockLayer::Paint() */ {
158 expected_builder.DrawPath(child_path1, DlPaint(DlColor::kYellow()));
159 }
160 /* MockLayer::Paint() */ {
161 expected_builder.DrawPath(child_path2, DlPaint(DlColor::kCyan()));
162 }
163 }
164 }
165 expected_builder.Restore();
166 auto expected_display_list = expected_builder.Build();
167
168 layer->Paint(display_list_paint_context());
169 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
170}
171
173 const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
174 const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
175 const SkPath child_path1 = SkPath().addRect(child_bounds);
176 const SkPath child_path2 =
177 SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
178 const DlPaint child_paint1 = DlPaint(DlColor::kYellow());
179 const DlPaint child_paint2 = DlPaint(DlColor::kCyan());
180 auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
181 auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
182 auto dl_color_filter = DlSrgbToLinearGammaColorFilter::kInstance;
183 auto layer1 = std::make_shared<ColorFilterLayer>(dl_color_filter);
184
185 auto layer2 = std::make_shared<ColorFilterLayer>(dl_color_filter);
186 layer2->Add(mock_layer2);
187 layer1->Add(mock_layer1);
188 layer1->Add(layer2);
189
190 SkRect children_bounds = child_path1.getBounds();
191 children_bounds.join(child_path2.getBounds());
192 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
193 layer1->Preroll(preroll_context());
194 EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
195 EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
196 EXPECT_EQ(layer1->paint_bounds(), children_bounds);
197 EXPECT_EQ(layer1->child_paint_bounds(), children_bounds);
198 EXPECT_EQ(layer2->paint_bounds(), mock_layer2->paint_bounds());
199 EXPECT_EQ(layer2->child_paint_bounds(), mock_layer2->paint_bounds());
200 EXPECT_TRUE(mock_layer1->needs_painting(paint_context()));
201 EXPECT_TRUE(mock_layer2->needs_painting(paint_context()));
202 EXPECT_TRUE(layer1->needs_painting(paint_context()));
203 EXPECT_TRUE(layer2->needs_painting(paint_context()));
204 EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
205 EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
206
207 DisplayListBuilder expected_builder;
208 /* ColorFilterLayer::Paint() */ {
209 DlPaint dl_paint;
210 dl_paint.setColorFilter(dl_color_filter.get());
211 expected_builder.SaveLayer(&children_bounds, &dl_paint);
212 {
213 /* MockLayer::Paint() */ {
214 expected_builder.DrawPath(child_path1, DlPaint(DlColor::kYellow()));
215 }
216 /* ColorFilter::Paint() */ {
217 DlPaint child_dl_paint;
218 child_dl_paint.setColor(DlColor::kBlack());
219 child_dl_paint.setColorFilter(dl_color_filter.get());
220 expected_builder.SaveLayer(&child_path2.getBounds(), &child_dl_paint);
221
222 /* MockLayer::Paint() */ {
223 expected_builder.DrawPath(child_path2, DlPaint(DlColor::kCyan()));
224 }
225 expected_builder.Restore();
226 }
227 }
228 }
229 expected_builder.Restore();
230
231 auto expected_display_list = expected_builder.Build();
232
233 layer1->Paint(display_list_paint_context());
234 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list));
235}
236
237TEST_F(ColorFilterLayerTest, Readback) {
238 auto initial_transform = SkMatrix();
239
240 // ColorFilterLayer does not read from surface
241 auto layer = std::make_shared<ColorFilterLayer>(
243 preroll_context()->surface_needs_readback = false;
244 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
245 layer->Preroll(preroll_context());
246 EXPECT_FALSE(preroll_context()->surface_needs_readback);
247
248 // ColorFilterLayer blocks child with readback
249 auto mock_layer = std::make_shared<MockLayer>(SkPath(), DlPaint());
250 mock_layer->set_fake_reads_surface(true);
251 layer->Add(mock_layer);
252 preroll_context()->surface_needs_readback = false;
253 layer->Preroll(preroll_context());
254 EXPECT_FALSE(preroll_context()->surface_needs_readback);
255}
256
259 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
260 auto other_transform = SkMatrix::Scale(1.0, 2.0);
261 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
263 auto mock_layer = std::make_shared<MockLayer>(child_path);
264 auto layer = std::make_shared<ColorFilterLayer>(layer_filter);
265 layer->Add(mock_layer);
266
267 SkMatrix cache_ctm = initial_transform;
268 DisplayListBuilder cache_canvas;
269 cache_canvas.Transform(cache_ctm);
270 DisplayListBuilder other_canvas;
271 other_canvas.Transform(other_transform);
272
273 use_mock_raster_cache();
274 const auto* cacheable_color_filter_item = layer->raster_cache_item();
275
276 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
277 EXPECT_EQ(cacheable_color_filter_item->cache_state(),
279 EXPECT_FALSE(cacheable_color_filter_item->GetId().has_value());
280
281 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
282 layer->Preroll(preroll_context());
283 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
284
285 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
286 EXPECT_EQ(cacheable_color_filter_item->cache_state(),
288 EXPECT_EQ(
289 cacheable_color_filter_item->GetId().value(),
292 EXPECT_FALSE(raster_cache()->Draw(
293 cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
294 EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
295 cache_canvas, &paint));
296}
297
300 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
301 auto other_transform = SkMatrix::Scale(1.0, 2.0);
302 const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
303 const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
304 auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
305 auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
306 auto layer = std::make_shared<ColorFilterLayer>(layer_filter);
307 layer->Add(mock_layer1);
308 layer->Add(mock_layer2);
310
311 SkMatrix cache_ctm = initial_transform;
312 DisplayListBuilder cache_canvas;
313 cache_canvas.Transform(cache_ctm);
314 DisplayListBuilder other_canvas;
315 other_canvas.Transform(other_transform);
316
317 use_mock_raster_cache();
318
319 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
320 const auto* cacheable_color_filter_item = layer->raster_cache_item();
321 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
322
323 EXPECT_EQ(cacheable_color_filter_item->cache_state(),
325 EXPECT_FALSE(cacheable_color_filter_item->GetId().has_value());
326
327 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
328 layer->Preroll(preroll_context());
329 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
330
331 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
332 EXPECT_EQ(cacheable_color_filter_item->cache_state(),
334 EXPECT_EQ(
335 cacheable_color_filter_item->GetId().value(),
338 EXPECT_FALSE(raster_cache()->Draw(
339 cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
340 EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
341 cache_canvas, &paint));
342}
343
344TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) {
346 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
347 auto other_transform = SkMatrix::Scale(1.0, 2.0);
348 const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
349 const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
350 auto mock_layer1 = std::make_shared<MockLayer>(child_path1);
351 auto mock_layer2 = std::make_shared<MockLayer>(child_path2);
352 auto layer = std::make_shared<ColorFilterLayer>(layer_filter);
353 layer->Add(mock_layer1);
354 layer->Add(mock_layer2);
356
357 SkMatrix cache_ctm = initial_transform;
358 DisplayListBuilder cache_canvas;
359 cache_canvas.Transform(cache_ctm);
360 DisplayListBuilder other_canvas;
361 other_canvas.Transform(other_transform);
362
363 use_mock_raster_cache();
364 preroll_context()->state_stack.set_preroll_delegate(initial_transform);
365 const auto* cacheable_color_filter_item = layer->raster_cache_item();
366
367 // frame 1.
368 layer->Preroll(preroll_context());
369 layer->Paint(paint_context());
370 // frame 2.
371 layer->Preroll(preroll_context());
372 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
373 // ColorFilterLayer default cache children.
374 EXPECT_EQ(cacheable_color_filter_item->cache_state(),
376 EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
377 cache_canvas, &paint));
378 EXPECT_FALSE(raster_cache()->Draw(
379 cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
380 layer->Paint(paint_context());
381
382 // frame 3.
383 layer->Preroll(preroll_context());
384 layer->Paint(paint_context());
385
386 LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
387 // frame1,2 cache the ColorFilterLayer's children layer, frame3 cache the
388 // ColorFilterLayer
389 EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)2);
390
391 // ColorFilterLayer default cache itself.
392 EXPECT_EQ(cacheable_color_filter_item->cache_state(),
394 EXPECT_EQ(cacheable_color_filter_item->GetId(),
395 RasterCacheKeyID(layer->unique_id(), RasterCacheKeyType::kLayer));
396 EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
397 cache_canvas, &paint));
398 EXPECT_FALSE(raster_cache()->Draw(
399 cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
400}
401
402TEST_F(ColorFilterLayerTest, OpacityInheritance) {
403 // clang-format off
404 float matrix[20] = {
405 0, 1, 0, 0, 0,
406 0, 0, 1, 0, 0,
407 1, 0, 0, 0, 0,
408 0, 0, 0, 1, 0,
409 };
410 // clang-format on
411 auto layer_filter = DlMatrixColorFilter(matrix);
412 auto initial_transform = SkMatrix::Translate(50.0, 25.5);
413 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
414 auto mock_layer = std::make_shared<MockLayer>(child_path);
415 auto color_filter_layer = std::make_shared<ColorFilterLayer>(
416 std::make_shared<DlMatrixColorFilter>(matrix));
417 color_filter_layer->Add(mock_layer);
418
419 PrerollContext* context = preroll_context();
420 context->state_stack.set_preroll_delegate(initial_transform);
421 color_filter_layer->Preroll(preroll_context());
422 // ColorFilterLayer can always inherit opacity whether or not their
423 // children are compatible.
424 EXPECT_EQ(context->renderable_state_flags,
426
427 int opacity_alpha = 0x7F;
428 SkPoint offset = SkPoint::Make(10, 10);
429 auto opacity_layer = std::make_shared<OpacityLayer>(opacity_alpha, offset);
430 opacity_layer->Add(color_filter_layer);
431 preroll_context()->state_stack.set_preroll_delegate(SkMatrix::I());
432 opacity_layer->Preroll(context);
433 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
434
435 DisplayListBuilder expected_builder;
436 /* OpacityLayer::Paint() */ {
437 expected_builder.Save();
438 {
439 expected_builder.Translate(offset.fX, offset.fY);
440 /* ColorFilterLayer::Paint() */ {
441 DlPaint dl_paint;
442 dl_paint.setColor(DlColor(opacity_alpha << 24));
443 dl_paint.setColorFilter(&layer_filter);
444 expected_builder.SaveLayer(&child_path.getBounds(), &dl_paint);
445 /* MockLayer::Paint() */ {
446 expected_builder.DrawPath(child_path, DlPaint(DlColor(0xFF000000)));
447 }
448 expected_builder.Restore();
449 }
450 }
451 expected_builder.Restore();
452 }
453
454 opacity_layer->Paint(display_list_paint_context());
455 EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list()));
456}
457
458} // namespace testing
459} // namespace flutter
460
461// NOLINTEND(bugprone-unchecked-optional-access)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition SkMatrix.h:75
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition SkMatrix.h:91
static const SkMatrix & I()
const SkRect & getBounds() const
Definition SkPath.cpp:420
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition SkPath.cpp:854
void Transform(const SkMatrix *matrix) override
static const std::shared_ptr< DlLinearToSrgbGammaColorFilter > kInstance
static const std::shared_ptr< DlSrgbToLinearGammaColorFilter > kInstance
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::optional< std::vector< RasterCacheKeyID > > LayerChildrenIds(const Layer *layer)
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
Point offset
static constexpr SkPoint Make(float x, float y)
constexpr SkRect makeOffset(float dx, float dy) const
Definition SkRect.h:965
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 kBlack()
Definition dl_color.h:22
static constexpr DlColor kYellow()
Definition dl_color.h:29
static constexpr DlColor kCyan()
Definition dl_color.h:27
#define EXPECT_TRUE(handle)
Definition unit_test.h:685