Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
aiks_blur_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/impeller/aiks/aiks_unittests.h"
6
13#include "third_party/imgui/imgui.h"
14
15////////////////////////////////////////////////////////////////////////////////
16// This is for tests of Canvas that are interested the results of rendering
17// blurs.
18////////////////////////////////////////////////////////////////////////////////
19
20namespace impeller {
21namespace testing {
22
23TEST_P(AiksTest, CanRenderMaskBlurHugeSigma) {
24 Canvas canvas;
25 canvas.DrawCircle({400, 400}, 300,
26 {.color = Color::Green(),
27 .mask_blur_descriptor = Paint::MaskBlurDescriptor{
29 .sigma = Sigma(99999),
30 }});
31 canvas.Restore();
32
33 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
34}
35
36TEST_P(AiksTest, CanRenderForegroundBlendWithMaskBlur) {
37 // This case triggers the ForegroundPorterDuffBlend path. The color filter
38 // should apply to the color only, and respect the alpha mask.
39 Canvas canvas;
40 canvas.ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
41 canvas.DrawCircle({400, 400}, 200,
42 {
43 .color = Color::White(),
44 .color_filter = ColorFilter::MakeBlend(
46 .mask_blur_descriptor =
49 .sigma = Radius(20),
50 },
51 });
52 canvas.Restore();
53
54 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
55}
56
57TEST_P(AiksTest, CanRenderForegroundAdvancedBlendWithMaskBlur) {
58 // This case triggers the ForegroundAdvancedBlend path. The color filter
59 // should apply to the color only, and respect the alpha mask.
60 Canvas canvas;
61 canvas.ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
62 canvas.DrawCircle({400, 400}, 200,
63 {
64 .color = Color::Grey(),
65 .color_filter = ColorFilter::MakeBlend(
67 .mask_blur_descriptor =
70 .sigma = Radius(20),
71 },
72 });
73 canvas.Restore();
74
75 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
76}
77
78TEST_P(AiksTest, CanRenderBackdropBlurInteractive) {
79 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
80 static PlaygroundPoint point_a(Point(50, 50), 30, Color::White());
81 static PlaygroundPoint point_b(Point(300, 200), 30, Color::White());
82 auto [a, b] = DrawPlaygroundLine(point_a, point_b);
83
84 Canvas canvas;
85 canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
86 canvas.DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
87 canvas.DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
88 canvas.DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
89 canvas.ClipRRect(Rect::MakeLTRB(a.x, a.y, b.x, b.y), {20, 20});
90 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
94 canvas.Restore();
95
96 return canvas.EndRecordingAsPicture();
97 };
98
99 ASSERT_TRUE(OpenPlaygroundHere(callback));
100}
101
102TEST_P(AiksTest, CanRenderBackdropBlur) {
103 Canvas canvas;
104 canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
105 canvas.DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
106 canvas.DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
107 canvas.DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
108 canvas.ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), {20, 20});
109 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
110 ImageFilter::MakeBlur(Sigma(30.0), Sigma(30.0),
113 canvas.Restore();
114
115 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
116}
117
118TEST_P(AiksTest, CanRenderBackdropBlurHugeSigma) {
119 Canvas canvas;
120 canvas.DrawCircle({400, 400}, 300, {.color = Color::Green()});
121 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
122 ImageFilter::MakeBlur(Sigma(999999), Sigma(999999),
125 canvas.Restore();
126
127 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
128}
129
130TEST_P(AiksTest, CanRenderClippedBlur) {
131 Canvas canvas;
132 canvas.ClipRect(Rect::MakeXYWH(100, 150, 400, 400));
133 canvas.DrawCircle(
134 {400, 400}, 200,
135 {
136 .color = Color::Green(),
137 .image_filter = ImageFilter::MakeBlur(
140 });
141 canvas.Restore();
142
143 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
144}
145
146TEST_P(AiksTest, ClippedBlurFilterRendersCorrectlyInteractive) {
147 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
148 static PlaygroundPoint playground_point(Point(400, 400), 20,
149 Color::Green());
150 auto point = DrawPlaygroundPoint(playground_point);
151
152 Canvas canvas;
153 canvas.Translate(point - Point(400, 400));
154 Paint paint;
155 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
157 .sigma = Radius{120 * 3},
158 };
159 paint.color = Color::Red();
160 PathBuilder builder{};
161 builder.AddRect(Rect::MakeLTRB(0, 0, 800, 800));
162 canvas.DrawPath(builder.TakePath(), paint);
163 return canvas.EndRecordingAsPicture();
164 };
165 ASSERT_TRUE(OpenPlaygroundHere(callback));
166}
167
168TEST_P(AiksTest, ClippedBlurFilterRendersCorrectly) {
169 Canvas canvas;
170 canvas.Translate(Point(0, -400));
171 Paint paint;
172 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
174 .sigma = Radius{120 * 3},
175 };
176 paint.color = Color::Red();
177 PathBuilder builder{};
178 builder.AddRect(Rect::MakeLTRB(0, 0, 800, 800));
179 canvas.DrawPath(builder.TakePath(), paint);
180 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
181}
182
183TEST_P(AiksTest, ClearBlendWithBlur) {
184 Canvas canvas;
185 Paint white;
186 white.color = Color::Blue();
187 canvas.DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white);
188
189 Paint clear;
193 .sigma = Sigma(20),
194 };
195
196 canvas.DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear);
197
198 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
199}
200
201TEST_P(AiksTest, BlurHasNoEdge) {
202 Canvas canvas;
203 canvas.Scale(GetContentScale());
204 canvas.DrawPaint({});
205 Paint blur = {
206 .color = Color::Green(),
207 .mask_blur_descriptor =
210 .sigma = Sigma(47.6),
211 },
212 };
213 canvas.DrawRect(Rect::MakeXYWH(300, 300, 200, 200), blur);
214 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
215}
216
217TEST_P(AiksTest, BlurredRectangleWithShader) {
218 Canvas canvas;
219 canvas.Scale(GetContentScale());
220
221 auto paint_lines = [&canvas](Scalar dx, Scalar dy, Paint paint) {
222 auto draw_line = [&canvas, &paint](Point a, Point b) {
224 };
225 paint.stroke_width = 5;
227 draw_line(Point(dx + 100, dy + 100), Point(dx + 200, dy + 200));
228 draw_line(Point(dx + 100, dy + 200), Point(dx + 200, dy + 100));
229 draw_line(Point(dx + 150, dy + 100), Point(dx + 200, dy + 150));
230 draw_line(Point(dx + 100, dy + 150), Point(dx + 150, dy + 200));
231 };
232
233 AiksContext renderer(GetContext(), nullptr);
234 Canvas recorder_canvas;
235 for (int x = 0; x < 5; ++x) {
236 for (int y = 0; y < 5; ++y) {
237 Rect rect = Rect::MakeXYWH(x * 20, y * 20, 20, 20);
238 Paint paint{.color =
239 ((x + y) & 1) == 0 ? Color::Yellow() : Color::Blue()};
240 recorder_canvas.DrawRect(rect, paint);
241 }
242 }
243 Picture picture = recorder_canvas.EndRecordingAsPicture();
244 std::shared_ptr<Texture> texture =
245 picture.ToImage(renderer, ISize{100, 100})->GetTexture();
246
247 ColorSource image_source = ColorSource::MakeImage(
249 std::shared_ptr<ImageFilter> blur_filter = ImageFilter::MakeBlur(
252 canvas.DrawRect(Rect::MakeLTRB(0, 0, 300, 600),
254 canvas.DrawRect(Rect::MakeLTRB(100, 100, 200, 200),
255 Paint{.color_source = image_source});
256 canvas.DrawRect(Rect::MakeLTRB(300, 0, 600, 600),
257 Paint{.color = Color::Red()});
258 canvas.DrawRect(
259 Rect::MakeLTRB(400, 100, 500, 200),
260 Paint{.color_source = image_source, .image_filter = blur_filter});
261 paint_lines(0, 300, Paint{.color_source = image_source});
262 paint_lines(300, 300,
263 Paint{.color_source = image_source, .image_filter = blur_filter});
264 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
265}
266
267TEST_P(AiksTest, MaskBlurWithZeroSigmaIsSkipped) {
268 Canvas canvas;
269
270 Paint paint = {
271 .color = Color::Blue(),
272 .mask_blur_descriptor =
275 .sigma = Sigma(0),
276 },
277 };
278
279 canvas.DrawCircle({300, 300}, 200, paint);
280 canvas.DrawRect(Rect::MakeLTRB(100, 300, 500, 600), paint);
281
282 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
283}
284
293
294static Picture MaskBlurVariantTest(const AiksTest& test_context,
295 const MaskBlurTestConfig& config) {
296 Canvas canvas;
297 canvas.Scale(test_context.GetContentScale());
298 canvas.Scale(Vector2{0.8f, 0.8f});
299 Paint paint;
300 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
302 .sigma = Sigma{1},
303 };
304
305 canvas.DrawPaint({.color = Color::AntiqueWhite()});
306
307 paint.mask_blur_descriptor->style = config.style;
308 paint.mask_blur_descriptor->sigma = Sigma{config.sigma};
309 paint.image_filter = config.image_filter;
310 paint.invert_colors = config.invert_colors;
311 paint.blend_mode = config.blend_mode;
312
313 const Scalar x = 50;
314 const Scalar radius = 20.0f;
315 const Scalar y_spacing = 100.0f;
316
317 Scalar y = 50;
318 paint.color = Color::Crimson().WithAlpha(config.alpha);
319 canvas.DrawRect(Rect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
320 radius, 60.0f - radius),
321 paint);
322
323 y += y_spacing;
324 paint.color = Color::Blue().WithAlpha(config.alpha);
325 canvas.DrawCircle({x + 25, y + 25}, radius, paint);
326
327 y += y_spacing;
328 paint.color = Color::Green().WithAlpha(config.alpha);
329 canvas.DrawOval(Rect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
330 radius, 60.0f - radius),
331 paint);
332
333 y += y_spacing;
334 paint.color = Color::Purple().WithAlpha(config.alpha);
335 canvas.DrawRRect(Rect::MakeXYWH(x, y, 60.0f, 60.0f), //
336 {radius, radius}, //
337 paint);
338
339 y += y_spacing;
340 paint.color = Color::Orange().WithAlpha(config.alpha);
341 canvas.DrawRRect(Rect::MakeXYWH(x, y, 60.0f, 60.0f), //
342 {radius, 5.0f}, paint);
343
344 y += y_spacing;
345 paint.color = Color::Maroon().WithAlpha(config.alpha);
346 canvas.DrawPath(PathBuilder{}
347 .MoveTo({x + 0, y + 60})
348 .LineTo({x + 30, y + 0})
349 .LineTo({x + 60, y + 60})
350 .Close()
351 .TakePath(),
352 paint);
353
354 y += y_spacing;
355 paint.color = Color::Maroon().WithAlpha(config.alpha);
356 canvas.DrawPath(PathBuilder{}
357 .AddArc(Rect::MakeXYWH(x + 5, y, 50, 50),
358 Radians{kPi / 2}, Radians{kPi})
359 .AddArc(Rect::MakeXYWH(x + 25, y, 50, 50),
360 Radians{kPi / 2}, Radians{kPi})
361 .Close()
362 .TakePath(),
363 paint);
364
365 return canvas.EndRecordingAsPicture();
366}
367
368static const std::map<std::string, MaskBlurTestConfig> kPaintVariations = {
369 // 1. Normal style, translucent, zero sigma.
370 {"NormalTranslucentZeroSigma",
372 .sigma = 0.0f,
373 .alpha = 0.5f}},
374 // 2. Normal style, translucent.
375 {"NormalTranslucent",
377 .sigma = 8.0f,
378 .alpha = 0.5f}},
379 // 3. Solid style, translucent.
380 {"SolidTranslucent",
382 .sigma = 8.0f,
383 .alpha = 0.5f}},
384 // 4. Solid style, opaque.
385 {"SolidOpaque",
386 {.style = FilterContents::BlurStyle::kSolid, .sigma = 8.0f}},
387 // 5. Solid style, translucent, color & image filtered.
388 {"SolidTranslucentWithFilters",
390 .sigma = 8.0f,
391 .alpha = 0.5f,
392 .image_filter = ImageFilter::MakeBlur(Sigma{3},
393 Sigma{3},
396 .invert_colors = true}},
397 // 6. Solid style, translucent, exclusion blended.
398 {"SolidTranslucentExclusionBlend",
400 .sigma = 8.0f,
401 .alpha = 0.5f,
402 .blend_mode = BlendMode::kExclusion}},
403 // 7. Inner style, translucent.
404 {"InnerTranslucent",
406 .sigma = 8.0f,
407 .alpha = 0.5f}},
408 // 8. Inner style, translucent, blurred.
409 {"InnerTranslucentWithBlurImageFilter",
411 .sigma = 8.0f,
412 .alpha = 0.5f,
413 .image_filter = ImageFilter::MakeBlur(Sigma{3},
414 Sigma{3},
417 // 9. Outer style, translucent.
418 {"OuterTranslucent",
420 .sigma = 8.0f,
421 .alpha = 0.5f}},
422 // 10. Outer style, opaque, image filtered.
423 {"OuterOpaqueWithBlurImageFilter",
425 .sigma = 8.0f,
426 .image_filter = ImageFilter::MakeBlur(Sigma{3},
427 Sigma{3},
430};
431
432#define MASK_BLUR_VARIANT_TEST(config) \
433 TEST_P(AiksTest, MaskBlurVariantTest##config) { \
434 ASSERT_TRUE(OpenPlaygroundHere( \
435 MaskBlurVariantTest(*this, kPaintVariations.at(#config)))); \
436 }
437
438MASK_BLUR_VARIANT_TEST(NormalTranslucentZeroSigma)
439MASK_BLUR_VARIANT_TEST(NormalTranslucent)
440MASK_BLUR_VARIANT_TEST(SolidTranslucent)
441MASK_BLUR_VARIANT_TEST(SolidOpaque)
442MASK_BLUR_VARIANT_TEST(SolidTranslucentWithFilters)
443MASK_BLUR_VARIANT_TEST(SolidTranslucentExclusionBlend)
444MASK_BLUR_VARIANT_TEST(InnerTranslucent)
445MASK_BLUR_VARIANT_TEST(InnerTranslucentWithBlurImageFilter)
446MASK_BLUR_VARIANT_TEST(OuterTranslucent)
447MASK_BLUR_VARIANT_TEST(OuterOpaqueWithBlurImageFilter)
448
449#undef MASK_BLUR_VARIANT_TEST
450
451TEST_P(AiksTest, GaussianBlurAtPeripheryVertical) {
452 Canvas canvas;
453
454 canvas.Scale(GetContentScale());
455 canvas.DrawRRect(Rect::MakeLTRB(0, 0, GetWindowSize().width, 100),
456 Size(10, 10), Paint{.color = Color::LimeGreen()});
457 canvas.DrawRRect(Rect::MakeLTRB(0, 110, GetWindowSize().width, 210),
458 Size(10, 10), Paint{.color = Color::Magenta()});
459 canvas.ClipRect(Rect::MakeLTRB(100, 0, 200, GetWindowSize().height));
460 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
461 ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
464 canvas.Restore();
465
466 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
467}
468
469TEST_P(AiksTest, GaussianBlurAtPeripheryHorizontal) {
470 Canvas canvas;
471
472 canvas.Scale(GetContentScale());
473 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
474 canvas.DrawImageRect(
475 std::make_shared<Image>(boston),
476 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height),
477 Rect::MakeLTRB(0, 0, GetWindowSize().width, 100), Paint{});
478 canvas.DrawRRect(Rect::MakeLTRB(0, 110, GetWindowSize().width, 210),
479 Size(10, 10), Paint{.color = Color::Magenta()});
480 canvas.ClipRect(Rect::MakeLTRB(0, 50, GetWindowSize().width, 150));
481 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
482 ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
485 canvas.Restore();
486 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
487}
488
489#define FLT_FORWARD(mock, real, method) \
490 EXPECT_CALL(*mock, method()) \
491 .WillRepeatedly(::testing::Return(real->method()));
492
493TEST_P(AiksTest, GaussianBlurWithoutDecalSupport) {
494 if (GetParam() != PlaygroundBackend::kMetal) {
495 GTEST_SKIP_(
496 "This backend doesn't yet support setting device capabilities.");
497 }
498 if (!WillRenderSomething()) {
499 // Sometimes these tests are run without playgrounds enabled which is
500 // pointless for this test since we are asserting that
501 // `SupportsDecalSamplerAddressMode` is called.
502 GTEST_SKIP_("This test requires playgrounds.");
503 }
504
505 std::shared_ptr<const Capabilities> old_capabilities =
506 GetContext()->GetCapabilities();
507 auto mock_capabilities = std::make_shared<MockCapabilities>();
508 EXPECT_CALL(*mock_capabilities, SupportsDecalSamplerAddressMode())
509 .Times(::testing::AtLeast(1))
510 .WillRepeatedly(::testing::Return(false));
511 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultColorFormat);
512 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultStencilFormat);
513 FLT_FORWARD(mock_capabilities, old_capabilities,
514 GetDefaultDepthStencilFormat);
515 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsOffscreenMSAA);
516 FLT_FORWARD(mock_capabilities, old_capabilities,
517 SupportsImplicitResolvingMSAA);
518 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsReadFromResolve);
519 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsFramebufferFetch);
520 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsSSBO);
521 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsCompute);
522 FLT_FORWARD(mock_capabilities, old_capabilities,
523 SupportsTextureToTextureBlits);
524 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultGlyphAtlasFormat);
525 ASSERT_TRUE(SetCapabilities(mock_capabilities).ok());
526
527 auto texture = std::make_shared<Image>(CreateTextureForFixture("boston.jpg"));
528 Canvas canvas;
529 canvas.Scale(GetContentScale() * 0.5);
530 canvas.DrawPaint({.color = Color::Black()});
531 canvas.DrawImage(
532 texture, Point(200, 200),
533 {
534 .image_filter = ImageFilter::MakeBlur(
537 });
538 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
539}
540
541TEST_P(AiksTest, GaussianBlurOneDimension) {
542 Canvas canvas;
543
544 canvas.Scale(GetContentScale());
545 canvas.Scale({0.5, 0.5, 1.0});
546 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
547 canvas.DrawImage(std::make_shared<Image>(boston), Point(100, 100), Paint{});
548 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
552 canvas.Restore();
553 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
554}
555
556// Smoketest to catch issues with the coverage hint.
557// Draws a rotated blurred image within a rectangle clip. The center of the clip
558// rectangle is the center of the rotated image. The entire area of the clip
559// rectangle should be filled with opaque colors output by the blur.
560TEST_P(AiksTest, GaussianBlurRotatedAndClipped) {
561 Canvas canvas;
562 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
563 Rect bounds =
564 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
565 Vector2 image_center = Vector2(bounds.GetSize() / 2);
566 Paint paint = {.image_filter =
567 ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
570 Vector2 clip_size = {150, 75};
571 Vector2 center = Vector2(1024, 768) / 2;
572 canvas.Scale(GetContentScale());
573 canvas.ClipRect(
574 Rect::MakeLTRB(center.x, center.y, center.x, center.y).Expand(clip_size));
575 canvas.Translate({center.x, center.y, 0});
576 canvas.Scale({0.6, 0.6, 1});
577 canvas.Rotate(Degrees(25));
578
579 canvas.DrawImageRect(std::make_shared<Image>(boston), /*source=*/bounds,
580 /*dest=*/bounds.Shift(-image_center), paint);
581
582 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
583}
584
585TEST_P(AiksTest, GaussianBlurScaledAndClipped) {
586 Canvas canvas;
587 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
588 Rect bounds =
589 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
590 Vector2 image_center = Vector2(bounds.GetSize() / 2);
591 Paint paint = {.image_filter =
592 ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
595 Vector2 clip_size = {150, 75};
596 Vector2 center = Vector2(1024, 768) / 2;
597 canvas.Scale(GetContentScale());
598 canvas.ClipRect(
599 Rect::MakeLTRB(center.x, center.y, center.x, center.y).Expand(clip_size));
600 canvas.Translate({center.x, center.y, 0});
601 canvas.Scale({0.6, 0.6, 1});
602
603 canvas.DrawImageRect(std::make_shared<Image>(boston), /*source=*/bounds,
604 /*dest=*/bounds.Shift(-image_center), paint);
605
606 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
607}
608
609TEST_P(AiksTest, GaussianBlurRotatedAndClippedInteractive) {
610 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
611
612 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
613 const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
614 const Entity::TileMode tile_modes[] = {
617
618 static float rotation = 0;
619 static float scale = 0.6;
620 static int selected_tile_mode = 3;
621
622 if (AiksTest::ImGuiBegin("Controls", nullptr,
623 ImGuiWindowFlags_AlwaysAutoResize)) {
624 ImGui::SliderFloat("Rotation (degrees)", &rotation, -180, 180);
625 ImGui::SliderFloat("Scale", &scale, 0, 2.0);
626 ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
627 sizeof(tile_mode_names) / sizeof(char*));
628 ImGui::End();
629 }
630
631 Canvas canvas;
632 Rect bounds =
633 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
634 Vector2 image_center = Vector2(bounds.GetSize() / 2);
635 Paint paint = {.image_filter =
636 ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
638 tile_modes[selected_tile_mode])};
639 static PlaygroundPoint point_a(Point(362, 309), 20, Color::Red());
640 static PlaygroundPoint point_b(Point(662, 459), 20, Color::Red());
641 auto [handle_a, handle_b] = DrawPlaygroundLine(point_a, point_b);
642 Vector2 center = Vector2(1024, 768) / 2;
643 canvas.Scale(GetContentScale());
644 canvas.ClipRect(
645 Rect::MakeLTRB(handle_a.x, handle_a.y, handle_b.x, handle_b.y));
646 canvas.Translate({center.x, center.y, 0});
647 canvas.Scale({scale, scale, 1});
648 canvas.Rotate(Degrees(rotation));
649
650 canvas.DrawImageRect(std::make_shared<Image>(boston), /*source=*/bounds,
651 /*dest=*/bounds.Shift(-image_center), paint);
652 return canvas.EndRecordingAsPicture();
653 };
654
655 ASSERT_TRUE(OpenPlaygroundHere(callback));
656}
657
658// This addresses a bug where tiny blurs could result in mip maps that beyond
659// the limits for the textures used for blurring.
660// See also: b/323402168
661TEST_P(AiksTest, GaussianBlurSolidColorTinyMipMap) {
662 for (int32_t i = 1; i < 5; ++i) {
663 Canvas canvas;
664 Scalar fi = i;
665 canvas.DrawPath(
667 .MoveTo({100, 100})
668 .LineTo({100.f + fi, 100.f + fi})
669 .TakePath(),
670 {.color = Color::Chartreuse(),
671 .image_filter = ImageFilter::MakeBlur(
674
675 Picture picture = canvas.EndRecordingAsPicture();
676 std::shared_ptr<RenderTargetCache> cache =
677 std::make_shared<RenderTargetCache>(
678 GetContext()->GetResourceAllocator());
679 AiksContext aiks_context(GetContext(), nullptr, cache);
680 std::shared_ptr<Image> image = picture.ToImage(aiks_context, {1024, 768});
681 EXPECT_TRUE(image) << " length " << i;
682 }
683}
684
685// This addresses a bug where tiny blurs could result in mip maps that beyond
686// the limits for the textures used for blurring.
687// See also: b/323402168
688TEST_P(AiksTest, GaussianBlurBackdropTinyMipMap) {
689 for (int32_t i = 0; i < 5; ++i) {
690 Canvas canvas;
691 ISize clip_size = ISize(i, i);
692 canvas.ClipRect(
693 Rect::MakeXYWH(400, 400, clip_size.width, clip_size.height));
694 canvas.DrawCircle(
695 {400, 400}, 200,
696 {
697 .color = Color::Green(),
698 .image_filter = ImageFilter::MakeBlur(
701 });
702 canvas.Restore();
703
704 Picture picture = canvas.EndRecordingAsPicture();
705 std::shared_ptr<RenderTargetCache> cache =
706 std::make_shared<RenderTargetCache>(
707 GetContext()->GetResourceAllocator());
708 AiksContext aiks_context(GetContext(), nullptr, cache);
709 std::shared_ptr<Image> image = picture.ToImage(aiks_context, {1024, 768});
710 EXPECT_TRUE(image) << " clip rect " << i;
711 }
712}
713
714TEST_P(AiksTest, GaussianBlurAnimatedBackdrop) {
715 // This test is for checking out how stable rendering is when content is
716 // translated underneath a blur. Animating under a blur can cause
717 // *shimmering* to happen as a result of pixel alignment.
718 // See also: https://github.com/flutter/flutter/issues/140193
719 auto boston = std::make_shared<Image>(
720 CreateTextureForFixture("boston.jpg", /*enable_mipmapping=*/true));
721 ASSERT_TRUE(boston);
722 int64_t count = 0;
723 Scalar sigma = 20.0;
724 Scalar freq = 0.1;
725 Scalar amp = 50.0;
726 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
727 if (AiksTest::ImGuiBegin("Controls", nullptr,
728 ImGuiWindowFlags_AlwaysAutoResize)) {
729 ImGui::SliderFloat("Sigma", &sigma, 0, 200);
730 ImGui::SliderFloat("Frequency", &freq, 0.01, 2.0);
731 ImGui::SliderFloat("Amplitude", &amp, 1, 100);
732 ImGui::End();
733 }
734
735 Canvas canvas;
736 canvas.Scale(GetContentScale());
737 Scalar y = amp * sin(freq * 2.0 * M_PI * count / 60);
738 canvas.DrawImage(boston,
739 Point(1024 / 2 - boston->GetSize().width / 2,
740 (768 / 2 - boston->GetSize().height / 2) + y),
741 {});
742 static PlaygroundPoint point_a(Point(100, 100), 20, Color::Red());
743 static PlaygroundPoint point_b(Point(900, 700), 20, Color::Red());
744 auto [handle_a, handle_b] = DrawPlaygroundLine(point_a, point_b);
745 canvas.ClipRect(
746 Rect::MakeLTRB(handle_a.x, handle_a.y, handle_b.x, handle_b.y));
747 canvas.ClipRect(Rect::MakeLTRB(100, 100, 900, 700));
748 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
749 ImageFilter::MakeBlur(Sigma(sigma), Sigma(sigma),
752 count += 1;
753 return canvas.EndRecordingAsPicture();
754 };
755 ASSERT_TRUE(OpenPlaygroundHere(callback));
756}
757
758TEST_P(AiksTest, GaussianBlurStyleInnerGradient) {
759 Canvas canvas;
760 canvas.Scale(GetContentScale());
761
762 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
763
764 std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
765 Color{0.7568, 0.2627, 0.2118, 1.0}};
766 std::vector<Scalar> stops = {0.0, 1.0};
767
768 Paint paint;
770 {0, 0}, {200, 200}, std::move(colors), std::move(stops),
772 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
774 .sigma = Sigma(30),
775 };
776 canvas.DrawPath(PathBuilder()
777 .MoveTo({200, 200})
778 .LineTo({300, 400})
779 .LineTo({100, 400})
780 .Close()
781 .TakePath(),
782 paint);
783
784 // Draw another thing to make sure the clip area is reset.
785 Paint red;
786 red.color = Color::Red();
787 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
788 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
789}
790
791TEST_P(AiksTest, GaussianBlurStyleSolidGradient) {
792 Canvas canvas;
793 canvas.Scale(GetContentScale());
794
795 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
796
797 std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
798 Color{0.7568, 0.2627, 0.2118, 1.0}};
799 std::vector<Scalar> stops = {0.0, 1.0};
800
801 Paint paint;
803 {0, 0}, {200, 200}, std::move(colors), std::move(stops),
805 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
807 .sigma = Sigma(30),
808 };
809 canvas.DrawPath(PathBuilder()
810 .MoveTo({200, 200})
811 .LineTo({300, 400})
812 .LineTo({100, 400})
813 .Close()
814 .TakePath(),
815 paint);
816
817 // Draw another thing to make sure the clip area is reset.
818 Paint red;
819 red.color = Color::Red();
820 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
821 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
822}
823
824TEST_P(AiksTest, GaussianBlurStyleOuterGradient) {
825 Canvas canvas;
826 canvas.Scale(GetContentScale());
827
828 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
829
830 std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
831 Color{0.7568, 0.2627, 0.2118, 1.0}};
832 std::vector<Scalar> stops = {0.0, 1.0};
833
834 Paint paint;
836 {0, 0}, {200, 200}, std::move(colors), std::move(stops),
838 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
840 .sigma = Sigma(30),
841 };
842 canvas.DrawPath(PathBuilder()
843 .MoveTo({200, 200})
844 .LineTo({300, 400})
845 .LineTo({100, 400})
846 .Close()
847 .TakePath(),
848 paint);
849
850 // Draw another thing to make sure the clip area is reset.
851 Paint red;
852 red.color = Color::Red();
853 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
854 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
855}
856
857TEST_P(AiksTest, GaussianBlurStyleInner) {
858 Canvas canvas;
859 canvas.Scale(GetContentScale());
860
861 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
862
863 Paint paint;
864 paint.color = Color::Green();
865 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
867 .sigma = Sigma(30),
868 };
869 canvas.DrawPath(PathBuilder()
870 .MoveTo({200, 200})
871 .LineTo({300, 400})
872 .LineTo({100, 400})
873 .Close()
874 .TakePath(),
875 paint);
876
877 // Draw another thing to make sure the clip area is reset.
878 Paint red;
879 red.color = Color::Red();
880 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
881
882 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
883}
884
885TEST_P(AiksTest, GaussianBlurStyleOuter) {
886 Canvas canvas;
887 canvas.Scale(GetContentScale());
888
889 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
890
891 Paint paint;
892 paint.color = Color::Green();
893 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
895 .sigma = Sigma(30),
896 };
897 canvas.DrawPath(PathBuilder()
898 .MoveTo({200, 200})
899 .LineTo({300, 400})
900 .LineTo({100, 400})
901 .Close()
902 .TakePath(),
903 paint);
904
905 // Draw another thing to make sure the clip area is reset.
906 Paint red;
907 red.color = Color::Red();
908 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
909
910 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
911}
912
913TEST_P(AiksTest, GaussianBlurStyleSolid) {
914 Canvas canvas;
915 canvas.Scale(GetContentScale());
916
917 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
918
919 Paint paint;
920 paint.color = Color::Green();
921 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
923 .sigma = Sigma(30),
924 };
925 canvas.DrawPath(PathBuilder()
926 .MoveTo({200, 200})
927 .LineTo({300, 400})
928 .LineTo({100, 400})
929 .Close()
930 .TakePath(),
931 paint);
932
933 // Draw another thing to make sure the clip area is reset.
934 Paint red;
935 red.color = Color::Red();
936 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
937
938 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
939}
940
941TEST_P(AiksTest, MaskBlurTexture) {
942 Scalar sigma = 30;
943 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
944 if (AiksTest::ImGuiBegin("Controls", nullptr,
945 ImGuiWindowFlags_AlwaysAutoResize)) {
946 ImGui::SliderFloat("Sigma", &sigma, 0, 500);
947 ImGui::End();
948 }
949 Canvas canvas;
950 canvas.Scale(GetContentScale());
951 Paint paint;
952 paint.color = Color::Green();
953 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
955 .sigma = Sigma(sigma),
956 };
957 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
958 canvas.DrawImage(std::make_shared<Image>(boston), {200, 200}, paint);
959 Paint red;
960 red.color = Color::Red();
961 canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
962 return canvas.EndRecordingAsPicture();
963 };
964 ASSERT_TRUE(OpenPlaygroundHere(callback));
965}
966
967TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) {
968 // This makes sure if mip maps are recycled across invocations of blurs the
969 // contents get updated each frame correctly. If they aren't updated the color
970 // inside the blur and outside the blur will be different.
971 //
972 // If there is some change to render target caching this could display a false
973 // positive in the future. Also, if the LOD that is rendered is 1 it could
974 // present a false positive.
975 int32_t count = 0;
976 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
977 Canvas canvas;
978 if (count++ == 0) {
979 canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
980 } else {
981 canvas.DrawCircle({100, 100}, 50, {.color = Color::Chartreuse()});
982 }
983 canvas.ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), {20, 20});
984 canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
985 ImageFilter::MakeBlur(Sigma(30.0), Sigma(30.0),
988 canvas.Restore();
989 return canvas.EndRecordingAsPicture();
990 };
991
992 ASSERT_TRUE(OpenPlaygroundHere(callback));
993}
994
995TEST_P(AiksTest, GaussianBlurSetsMipCountOnPass) {
996 Canvas canvas;
997 canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
998 canvas.SaveLayer({}, std::nullopt,
1002 canvas.Restore();
1003
1004 Picture picture = canvas.EndRecordingAsPicture();
1005 EXPECT_EQ(4, picture.pass->GetRequiredMipCount());
1006}
1007
1008TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
1009 size_t blur_required_mip_count =
1010 GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1011
1012 Canvas canvas;
1013 canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
1014 canvas.SaveLayer({}, std::nullopt,
1018 canvas.Restore();
1019
1020 Picture picture = canvas.EndRecordingAsPicture();
1021 std::shared_ptr<RenderTargetCache> cache =
1022 std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1023 AiksContext aiks_context(GetContext(), nullptr, cache);
1024 picture.ToImage(aiks_context, {100, 100});
1025
1026 size_t max_mip_count = 0;
1027 for (auto it = cache->GetRenderTargetDataBegin();
1028 it != cache->GetRenderTargetDataEnd(); ++it) {
1029 max_mip_count = std::max(it->config.mip_count, max_mip_count);
1030 }
1031 EXPECT_EQ(max_mip_count, blur_required_mip_count);
1032}
1033
1034TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
1035 fml::testing::LogCapture log_capture;
1036 size_t blur_required_mip_count =
1037 GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1038
1039 Canvas canvas;
1040 canvas.DrawPaint({.color = Color::Wheat()});
1041 canvas.SaveLayer({.blend_mode = BlendMode::kMultiply});
1042 canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
1043 canvas.SaveLayer({}, std::nullopt,
1047 canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
1048
1049 Picture picture = canvas.EndRecordingAsPicture();
1050 std::shared_ptr<RenderTargetCache> cache =
1051 std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1052 AiksContext aiks_context(GetContext(), nullptr, cache);
1053 picture.ToImage(aiks_context, {100, 100});
1054
1055 size_t max_mip_count = 0;
1056 for (auto it = cache->GetRenderTargetDataBegin();
1057 it != cache->GetRenderTargetDataEnd(); ++it) {
1058 max_mip_count = std::max(it->config.mip_count, max_mip_count);
1059 }
1060 EXPECT_EQ(max_mip_count, blur_required_mip_count);
1061 // The log is FML_DLOG, so only check in debug builds.
1062#ifndef NDEBUG
1063 if (GetParam() != PlaygroundBackend::kOpenGLES) {
1064 EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1065 std::string::npos);
1066 } else {
1067 EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1068 std::string::npos);
1069 }
1070#endif
1071}
1072
1073TEST_P(AiksTest, GaussianBlurMipMapImageFilter) {
1074 size_t blur_required_mip_count =
1075 GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1076 fml::testing::LogCapture log_capture;
1077 Canvas canvas;
1078 canvas.SaveLayer(
1079 {.image_filter = ImageFilter::MakeBlur(Sigma(30), Sigma(30),
1082 canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
1083
1084 Picture picture = canvas.EndRecordingAsPicture();
1085 std::shared_ptr<RenderTargetCache> cache =
1086 std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1087 AiksContext aiks_context(GetContext(), nullptr, cache);
1088 picture.ToImage(aiks_context, {1024, 768});
1089
1090 size_t max_mip_count = 0;
1091 for (auto it = cache->GetRenderTargetDataBegin();
1092 it != cache->GetRenderTargetDataEnd(); ++it) {
1093 max_mip_count = std::max(it->config.mip_count, max_mip_count);
1094 }
1095 EXPECT_EQ(max_mip_count, blur_required_mip_count);
1096 // The log is FML_DLOG, so only check in debug builds.
1097#ifndef NDEBUG
1098 if (GetParam() != PlaygroundBackend::kOpenGLES) {
1099 EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1100 std::string::npos);
1101 } else {
1102 EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1103 std::string::npos);
1104 }
1105#endif
1106}
1107
1108TEST_P(AiksTest, GaussianBlurMipMapSolidColor) {
1109 size_t blur_required_mip_count =
1110 GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1111 fml::testing::LogCapture log_capture;
1112 Canvas canvas;
1113 canvas.DrawPath(PathBuilder{}
1114 .MoveTo({100, 100})
1115 .LineTo({200, 100})
1116 .LineTo({150, 200})
1117 .LineTo({50, 200})
1118 .Close()
1119 .TakePath(),
1120 {.color = Color::Chartreuse(),
1121 .image_filter = ImageFilter::MakeBlur(
1124
1125 Picture picture = canvas.EndRecordingAsPicture();
1126 std::shared_ptr<RenderTargetCache> cache =
1127 std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1128 AiksContext aiks_context(GetContext(), nullptr, cache);
1129 picture.ToImage(aiks_context, {1024, 768});
1130
1131 size_t max_mip_count = 0;
1132 for (auto it = cache->GetRenderTargetDataBegin();
1133 it != cache->GetRenderTargetDataEnd(); ++it) {
1134 max_mip_count = std::max(it->config.mip_count, max_mip_count);
1135 }
1136 EXPECT_EQ(max_mip_count, blur_required_mip_count);
1137 // The log is FML_DLOG, so only check in debug builds.
1138#ifndef NDEBUG
1139 if (GetParam() != PlaygroundBackend::kOpenGLES) {
1140 EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1141 std::string::npos);
1142 } else {
1143 EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1144 std::string::npos);
1145 }
1146#endif
1147}
1148
1149TEST_P(AiksTest, MaskBlurDoesntStretchContents) {
1150 Scalar sigma = 70;
1151 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
1152 if (AiksTest::ImGuiBegin("Controls", nullptr,
1153 ImGuiWindowFlags_AlwaysAutoResize)) {
1154 ImGui::SliderFloat("Sigma", &sigma, 0, 500);
1155 ImGui::End();
1156 }
1157 Canvas canvas;
1158 canvas.Scale(GetContentScale());
1159 canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)});
1160
1161 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
1162 ColorSource image_source = ColorSource::MakeImage(
1164
1165 canvas.Transform(Matrix::MakeTranslation({100, 100, 0}) *
1166 Matrix::MakeScale({0.5, 0.5, 1.0}));
1167 Paint paint = {
1168 .color_source = image_source,
1169 .mask_blur_descriptor =
1172 .sigma = Sigma(sigma),
1173 },
1174 };
1175 canvas.DrawRect(
1176 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height),
1177 paint);
1178
1179 return canvas.EndRecordingAsPicture();
1180 };
1181 ASSERT_TRUE(OpenPlaygroundHere(callback));
1182}
1183
1184} // namespace testing
1185} // namespace impeller
#define M_PI
int count
static bool ok(int result)
static SkScalar center(float pos0, float pos1)
#define FLT_FORWARD(mock, real, method)
#define MASK_BLUR_VARIANT_TEST(config)
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
void DrawImageRect(const std::shared_ptr< Image > &image, Rect source, Rect dest, const Paint &paint, SamplerDescriptor sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
Definition canvas.cc:764
virtual void SaveLayer(const Paint &paint, std::optional< Rect > bounds=std::nullopt, const std::shared_ptr< ImageFilter > &backdrop_filter=nullptr, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown, uint32_t total_content_depth=kMaxDepth)
Definition canvas.cc:839
void DrawOval(const Rect &rect, const Paint &paint)
Definition canvas.cc:512
void ClipRRect(const Rect &rect, const Size &corner_radii, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
Definition canvas.cc:638
virtual bool Restore()
Definition canvas.cc:257
void Transform(const Matrix &transform)
Definition canvas.cc:292
void DrawImage(const std::shared_ptr< Image > &image, Point offset, const Paint &paint, SamplerDescriptor sampler={})
Definition canvas.cc:750
void Rotate(Radians radians)
Definition canvas.cc:325
void DrawPaint(const Paint &paint)
Definition canvas.cc:350
void ClipRect(const Rect &rect, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
Definition canvas.cc:597
void Scale(const Vector2 &scale)
Definition canvas.cc:313
Picture EndRecordingAsPicture()
Definition canvas.cc:802
void DrawPath(const Path &path, const Paint &paint)
Definition canvas.cc:341
void DrawRect(const Rect &rect, const Paint &paint)
Definition canvas.cc:493
void DrawRRect(const Rect &rect, const Size &corner_radii, const Paint &paint)
Definition canvas.cc:538
void Translate(const Vector3 &offset)
Definition canvas.cc:309
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition canvas.cc:564
static std::shared_ptr< ColorFilter > MakeBlend(BlendMode blend_mode, Color color)
static ColorSource MakeLinearGradient(Point start_point, Point end_point, std::vector< Color > colors, std::vector< Scalar > stops, Entity::TileMode tile_mode, Matrix effect_transform)
static ColorSource MakeImage(std::shared_ptr< Texture > texture, Entity::TileMode x_tile_mode, Entity::TileMode y_tile_mode, SamplerDescriptor sampler_descriptor, Matrix effect_transform)
@ kNormal
Blurred inside and outside.
@ kOuter
Nothing inside, blurred outside.
@ kInner
Blurred inside, nothing outside.
@ kSolid
Solid inside, blurred outside.
static std::shared_ptr< ImageFilter > MakeBlur(Sigma sigma_x, Sigma sigma_y, FilterContents::BlurStyle blur_style, Entity::TileMode tile_mode)
Path TakePath(FillType fill=FillType::kNonZero)
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
PathBuilder & MoveTo(Point point, bool relative=false)
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Point GetContentScale() const
const Paint & paint
sk_sp< SkImage > image
Definition examples.cpp:29
static bool b
struct MyStruct a[10]
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static void draw_line(SkCanvas *canvas, SkImage *, const SkRect &r, sk_sp< SkImageFilter > imf)
FlTexture * texture
double y
double x
static const std::map< std::string, MaskBlurTestConfig > kPaintVariations
static Picture MaskBlurVariantTest(const AiksTest &test_context, const MaskBlurTestConfig &config)
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)
Point Vector2
Definition point.h:320
constexpr float kPi
Definition constants.h:26
float Scalar
Definition scalar.h:18
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition widgets.cc:9
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition widgets.cc:50
TPoint< Scalar > Point
Definition point.h:316
TSize< int64_t > ISize
Definition size.h:138
BlendMode
Definition color.h:59
TSize< Scalar > Size
Definition size.h:137
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void Close(PathBuilder *builder)
int32_t height
int32_t width
const Scalar scale
std::string str() const
Definition logging.cc:122
static constexpr Color Crimson()
Definition color.h:342
static constexpr Color Grey()
Definition color.h:486
static constexpr Color LimeGreen()
Definition color.h:594
static constexpr Color GreenYellow()
Definition color.h:482
static constexpr Color Chartreuse()
Definition color.h:322
static constexpr Color Black()
Definition color.h:258
static constexpr Color CornflowerBlue()
Definition color.h:334
static constexpr Color White()
Definition color.h:256
static constexpr Color Magenta()
Definition color.h:602
constexpr Color WithAlpha(Scalar new_alpha) const
Definition color.h:270
static constexpr Color Maroon()
Definition color.h:606
static constexpr Color OrangeRed()
Definition color.h:686
static constexpr Color DarkGreen()
Definition color.h:366
static constexpr Color Orange()
Definition color.h:682
static constexpr Color Purple()
Definition color.h:734
static constexpr Color Wheat()
Definition color.h:826
static constexpr Color Red()
Definition color.h:264
static constexpr Color AntiqueWhite()
Definition color.h:278
static constexpr Color DarkMagenta()
Definition color.h:378
static constexpr Color Yellow()
Definition color.h:834
static constexpr Color Blue()
Definition color.h:268
static constexpr Color Green()
Definition color.h:266
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
FilterContents::BlurStyle style
Definition paint.h:40
ColorSource color_source
Definition paint.h:56
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition paint.h:69
Color color
Definition paint.h:55
BlendMode blend_mode
Definition paint.h:64
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition sigma.h:48
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition sigma.h:32
static constexpr TPoint< Type > MakeXY(Type x, Type y)
Definition point.h:46
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition rect.h:582
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
Type height
Definition size.h:23
Type width
Definition size.h:22
std::shared_ptr< ImageFilter > image_filter
#define EXPECT_TRUE(handle)
Definition unit_test.h:685