Flutter Engine
 
Loading...
Searching...
No Matches
aiks_dl_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
18
19#include "gmock/gmock.h"
24#include "third_party/imgui/imgui.h"
25
26////////////////////////////////////////////////////////////////////////////////
27// This is for tests of Canvas that are interested the results of rendering
28// blurs.
29////////////////////////////////////////////////////////////////////////////////
30
31namespace impeller {
32namespace testing {
33
34using namespace flutter;
35
36// The shapes of these ovals should appear equal. They are demonstrating the
37// difference between the fast pass and not.
38TEST_P(AiksTest, SolidColorOvalsMaskBlurTinySigma) {
39 DisplayListBuilder builder;
40 builder.Scale(GetContentScale().x, GetContentScale().y);
41
42 std::vector<float> sigmas = {0.0, 0.01, 1.0};
43 std::vector<DlColor> colors = {DlColor::kGreen(), DlColor::kYellow(),
45 for (uint32_t i = 0; i < sigmas.size(); ++i) {
46 DlPaint paint;
47 paint.setColor(colors[i]);
48 paint.setMaskFilter(
49 DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigmas[i]));
50
51 builder.Save();
52 builder.Translate(100 + (i * 100), 100);
53 DlRoundRect rrect =
54 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(0, 0, 60.0f, 160.0f), 50, 100);
55 builder.DrawRoundRect(rrect, paint);
56 builder.Restore();
57 }
58
59 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
60}
61
62sk_sp<flutter::DisplayList> DoGradientOvalStrokeMaskBlur(Vector2 content_Scale,
63 Scalar sigma,
64 DlBlurStyle style) {
65 DisplayListBuilder builder;
66 builder.Scale(content_Scale.x, content_Scale.y);
67
68 DlPaint background_paint;
69 background_paint.setColor(DlColor(1, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
70 builder.DrawPaint(background_paint);
71
72 std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue()};
73 std::vector<Scalar> stops = {0.0, 1.0};
74
75 DlPaint paint;
76 paint.setMaskFilter(DlBlurMaskFilter::Make(style, sigma));
77 auto gradient = DlColorSource::MakeLinear(
78 {0, 0}, {200, 200}, 2, colors.data(), stops.data(), DlTileMode::kClamp);
79 paint.setColorSource(gradient);
81 paint.setDrawStyle(DlDrawStyle::kStroke);
82 paint.setStrokeWidth(20);
83
84 builder.Save();
85 builder.Translate(100, 100);
86
87 {
88 DlPaint line_paint;
89 line_paint.setColor(DlColor::kWhite());
90 builder.DrawLine(DlPoint(100, 0), DlPoint(100, 60), line_paint);
91 builder.DrawLine(DlPoint(0, 30), DlPoint(200, 30), line_paint);
92 }
93
94 DlRoundRect rrect =
95 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(0, 0, 200.0f, 60.0f), 50, 100);
96 builder.DrawRoundRect(rrect, paint);
97 builder.Restore();
98
99 return builder.Build();
100}
101
102// https://github.com/flutter/flutter/issues/155930
103TEST_P(AiksTest, GradientOvalStrokeMaskBlur) {
104 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
105 GetContentScale(), /*sigma=*/10, DlBlurStyle::kNormal)));
106}
107
108TEST_P(AiksTest, GradientOvalStrokeMaskBlurSigmaZero) {
109 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
110 GetContentScale(), /*sigma=*/0, DlBlurStyle::kNormal)));
111}
112
113TEST_P(AiksTest, GradientOvalStrokeMaskBlurOuter) {
114 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
115 GetContentScale(), /*sigma=*/10, DlBlurStyle::kOuter)));
116}
117
118TEST_P(AiksTest, GradientOvalStrokeMaskBlurInner) {
119 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
120 GetContentScale(), /*sigma=*/10, DlBlurStyle::kInner)));
121}
122
123TEST_P(AiksTest, GradientOvalStrokeMaskBlurSolid) {
124 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
125 GetContentScale(), /*sigma=*/10, DlBlurStyle::kSolid)));
126}
127
128TEST_P(AiksTest, SolidColorCircleMaskBlurTinySigma) {
129 DisplayListBuilder builder;
130 builder.Scale(GetContentScale().x, GetContentScale().y);
131
132 std::vector<float> sigmas = {0.0, 0.01, 1.0};
133 std::vector<DlColor> colors = {DlColor::kGreen(), DlColor::kYellow(),
134 DlColor::kRed()};
135 for (uint32_t i = 0; i < sigmas.size(); ++i) {
136 DlPaint paint;
137 paint.setColor(colors[i]);
138 paint.setMaskFilter(
139 DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigmas[i]));
140
141 builder.Save();
142 builder.Translate(100 + (i * 100), 100);
144 DlRect::MakeXYWH(0, 0, 100.0f, 100.0f), 100, 100);
145 builder.DrawRoundRect(rrect, paint);
146 builder.Restore();
147 }
148
149 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
150}
151
152TEST_P(AiksTest, CanRenderMaskBlurHugeSigma) {
153 DisplayListBuilder builder;
154
155 DlPaint paint;
156 paint.setColor(DlColor::kGreen());
157 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 99999));
158 builder.DrawCircle(DlPoint(400, 400), 300, paint);
159 builder.Restore();
160
161 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
162}
163
164TEST_P(AiksTest, CanRenderForegroundBlendWithMaskBlur) {
165 // This case triggers the ForegroundPorterDuffBlend path. The color filter
166 // should apply to the color only, and respect the alpha mask.
167 DisplayListBuilder builder;
168 builder.ClipRect(DlRect::MakeXYWH(100, 150, 400, 400));
169
170 DlPaint paint;
171 paint.setColor(DlColor::kWhite());
172
173 Sigma sigma = Radius(20);
174 paint.setMaskFilter(
175 DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma.sigma));
176 paint.setColorFilter(
177 DlColorFilter::MakeBlend(DlColor::kGreen(), DlBlendMode::kSrc));
178 builder.DrawCircle(DlPoint(400, 400), 200, paint);
179
180 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
181}
182
183TEST_P(AiksTest, CanRenderForegroundAdvancedBlendWithMaskBlur) {
184 // This case triggers the ForegroundAdvancedBlend path. The color filter
185 // should apply to the color only, and respect the alpha mask.
186 DisplayListBuilder builder;
187 builder.ClipRect(DlRect::MakeXYWH(100, 150, 400, 400));
188
189 DlPaint paint;
190 paint.setColor(
191 DlColor::RGBA(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1.0f));
192
193 Sigma sigma = Radius(20);
194 paint.setMaskFilter(
195 DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma.sigma));
196 paint.setColorFilter(
197 DlColorFilter::MakeBlend(DlColor::kGreen(), DlBlendMode::kColor));
198 builder.DrawCircle(DlPoint(400, 400), 200, paint);
199 builder.Restore();
200
201 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
202}
203
204TEST_P(AiksTest, CanRenderBackdropBlurInteractive) {
205 auto callback = [&]() -> sk_sp<DisplayList> {
206 static PlaygroundPoint point_a(Point(50, 50), 30, Color::White());
207 static PlaygroundPoint point_b(Point(300, 200), 30, Color::White());
208 auto [a, b] = DrawPlaygroundLine(point_a, point_b);
209
210 DisplayListBuilder builder;
211 DlPaint paint;
213 builder.DrawCircle(DlPoint(100, 100), 50, paint);
214
216 builder.DrawCircle(DlPoint(300, 200), 100, paint);
217
219 builder.DrawCircle(DlPoint(140, 170), 75, paint);
220
222 builder.DrawCircle(DlPoint(180, 120), 100, paint);
223
224 DlRoundRect rrect =
225 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(a.x, a.y, b.x, b.y), 20, 20);
226 builder.ClipRoundRect(rrect);
227
228 DlPaint save_paint;
229 save_paint.setBlendMode(DlBlendMode::kSrc);
230
231 auto backdrop_filter = DlImageFilter::MakeBlur(20, 20, DlTileMode::kClamp);
232 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
233 builder.Restore();
234
235 return builder.Build();
236 };
237
238 ASSERT_TRUE(OpenPlaygroundHere(callback));
239}
240
241TEST_P(AiksTest, CanRenderBackdropBlur) {
242 DisplayListBuilder builder;
243
244 DlPaint paint;
246 builder.DrawCircle(DlPoint(100, 100), 50, paint);
247
249 builder.DrawCircle(DlPoint(300, 200), 100, paint);
250
252 builder.DrawCircle(DlPoint(140, 170), 75, paint);
253
255 builder.DrawCircle(DlPoint(180, 120), 100, paint);
256
257 DlRoundRect rrect =
258 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(75, 50, 375, 275), 20, 20);
259 builder.ClipRoundRect(rrect);
260
261 DlPaint save_paint;
262 save_paint.setBlendMode(DlBlendMode::kSrc);
263 auto backdrop_filter = DlImageFilter::MakeBlur(30, 30, DlTileMode::kClamp);
264 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
265 builder.Restore();
266
267 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
268}
269
270TEST_P(AiksTest, CanRenderBackdropBlurWithSingleBackdropId) {
271 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
272
273 DisplayListBuilder builder;
274
275 DlPaint paint;
276 builder.DrawImage(image, DlPoint(50.0, 50.0),
277 DlImageSampling::kNearestNeighbor, &paint);
278
279 DlRoundRect rrect =
280 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(50, 250, 100, 100), 20, 20);
281 builder.Save();
282 builder.ClipRoundRect(rrect);
283
284 DlPaint save_paint;
285 save_paint.setBlendMode(DlBlendMode::kSrc);
286 auto backdrop_filter = DlImageFilter::MakeBlur(30, 30, DlTileMode::kClamp);
287 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get(),
288 /*backdrop_id=*/1);
289 builder.Restore();
290 builder.Restore();
291
292 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
293}
294
295TEST_P(AiksTest, CanRenderMultipleBackdropBlurWithSingleBackdropId) {
296 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
297
298 DisplayListBuilder builder;
299
300 DlPaint paint;
301 builder.DrawImage(image, DlPoint(50.0, 50.0),
302 DlImageSampling::kNearestNeighbor, &paint);
303
304 for (int i = 0; i < 6; i++) {
306 DlRect::MakeXYWH(50 + (i * 100), 250, 100, 100), 20, 20);
307 builder.Save();
308 builder.ClipRoundRect(rrect);
309
310 DlPaint save_paint;
311 save_paint.setBlendMode(DlBlendMode::kSrc);
312 auto backdrop_filter = DlImageFilter::MakeBlur(30, 30, DlTileMode::kClamp);
313 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get(),
314 /*backdrop_id=*/1);
315 builder.Restore();
316 builder.Restore();
317 }
318
319 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
320}
321
323 CanRenderMultipleBackdropBlurWithSingleBackdropIdAndDistinctFilters) {
324 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
325
326 DisplayListBuilder builder;
327
328 DlPaint paint;
329 builder.DrawImage(image, DlPoint(50.0, 50.0),
330 DlImageSampling::kNearestNeighbor, &paint);
331
332 for (int i = 0; i < 6; i++) {
334 DlRect::MakeXYWH(50 + (i * 100), 250, 100, 100), 20, 20);
335 builder.Save();
336 builder.ClipRoundRect(rrect);
337
338 DlPaint save_paint;
339 save_paint.setBlendMode(DlBlendMode::kSrc);
340 auto backdrop_filter =
341 DlImageFilter::MakeBlur(30 + i, 30, DlTileMode::kClamp);
342 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get(),
343 /*backdrop_id=*/1);
344 builder.Restore();
345 builder.Restore();
346 }
347
348 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
349}
350
351TEST_P(AiksTest, CanRenderBackdropBlurHugeSigma) {
352 DisplayListBuilder builder;
353
354 DlPaint paint;
355 paint.setColor(DlColor::kGreen());
356 builder.DrawCircle(DlPoint(400, 400), 300, paint);
357
358 DlPaint save_paint;
359 save_paint.setBlendMode(DlBlendMode::kSrc);
360
361 auto backdrop_filter =
362 DlImageFilter::MakeBlur(999999, 999999, DlTileMode::kClamp);
363 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
364 builder.Restore();
365
366 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
367}
368
369TEST_P(AiksTest, CanRenderClippedBlur) {
370 DisplayListBuilder builder;
371 builder.ClipRect(DlRect::MakeXYWH(100, 150, 400, 400));
372
373 DlPaint paint;
374 paint.setColor(DlColor::kGreen());
375 paint.setImageFilter(DlImageFilter::MakeBlur(20, 20, DlTileMode::kDecal));
376 builder.DrawCircle(DlPoint(400, 400), 200, paint);
377 builder.Restore();
378
379 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
380}
381
382TEST_P(AiksTest, ComposePaintBlurOuter) {
383 DisplayListBuilder builder;
384
385 DlPaint background;
386 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
387 builder.DrawPaint(background);
388
389 DlPaint paint;
390 paint.setColor(DlColor::kGreen());
391 float matrix[] = {
392 0, 1, 0, 0, 0, //
393 1, 0, 0, 0, 0, //
394 0, 0, 1, 0, 0, //
395 0, 0, 0, 1, 0 //
396 };
397 std::shared_ptr<DlImageFilter> color_filter =
399 std::shared_ptr<DlImageFilter> blur =
400 DlImageFilter::MakeBlur(20, 20, DlTileMode::kDecal);
401 paint.setImageFilter(DlImageFilter::MakeCompose(blur, color_filter));
402 builder.DrawCircle(DlPoint(400, 400), 200, paint);
403
404 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
405}
406
407TEST_P(AiksTest, ComposePaintBlurInner) {
408 DisplayListBuilder builder;
409
410 DlPaint background;
411 background.setColor(DlColor(1.0, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
412 builder.DrawPaint(background);
413
414 DlPaint paint;
415 paint.setColor(DlColor::kGreen());
416 float matrix[] = {
417 0, 1, 0, 0, 0, //
418 1, 0, 0, 0, 0, //
419 0, 0, 1, 0, 0, //
420 0, 0, 0, 1, 0 //
421 };
422 std::shared_ptr<DlImageFilter> color_filter =
424 std::shared_ptr<DlImageFilter> blur =
425 DlImageFilter::MakeBlur(20, 20, DlTileMode::kDecal);
426 paint.setImageFilter(DlImageFilter::MakeCompose(color_filter, blur));
427 builder.DrawCircle(DlPoint(400, 400), 200, paint);
428
429 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
430}
431
432TEST_P(AiksTest, ClippedBlurFilterRendersCorrectlyInteractive) {
433 auto callback = [&]() -> sk_sp<DisplayList> {
434 static PlaygroundPoint playground_point(Point(400, 400), 20,
435 Color::Green());
436 auto point = DrawPlaygroundPoint(playground_point);
437
438 DisplayListBuilder builder;
439 auto location = point - Point(400, 400);
440 builder.Translate(location.x, location.y);
441
442 DlPaint paint;
443 Sigma sigma = Radius{120 * 3};
444 paint.setMaskFilter(
445 DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma.sigma));
446 paint.setColor(DlColor::kRed());
447
448 DlPath path = DlPath::MakeRect(DlRect::MakeLTRB(0, 0, 800, 800));
449 path = path + DlPath::MakeCircle(DlPoint(0, 0), 0.5);
450 builder.DrawPath(path, paint);
451 return builder.Build();
452 };
453 ASSERT_TRUE(OpenPlaygroundHere(callback));
454}
455
456TEST_P(AiksTest, ClippedBlurFilterRendersCorrectly) {
457 DisplayListBuilder builder;
458 builder.Translate(0, -400);
459 DlPaint paint;
460
461 Sigma sigma = Radius{120 * 3};
462 paint.setMaskFilter(
463 DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma.sigma));
464 paint.setColor(DlColor::kRed());
465
466 DlPath path = DlPath::MakeRect(DlRect::MakeLTRB(0, 0, 800, 800));
467 path = path + DlPath::MakeCircle(DlPoint(0, 0), 0.5);
468 builder.DrawPath(path, paint);
469
470 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
471}
472
473TEST_P(AiksTest, ClearBlendWithBlur) {
474 DisplayListBuilder builder;
475 DlPaint paint;
476 paint.setColor(DlColor::kBlue());
477 builder.DrawRect(DlRect::MakeXYWH(0, 0, 600.0, 600.0), paint);
478
479 DlPaint clear;
480 clear.setBlendMode(DlBlendMode::kClear);
481 clear.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 20));
482
483 builder.DrawCircle(DlPoint(300.0, 300.0), 200.0, clear);
484
485 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
486}
487
488TEST_P(AiksTest, BlurHasNoEdge) {
489 Scalar sigma = 47.6;
490 auto callback = [&]() -> sk_sp<DisplayList> {
491 if (AiksTest::ImGuiBegin("Controls", nullptr,
492 ImGuiWindowFlags_AlwaysAutoResize)) {
493 ImGui::SliderFloat("Sigma", &sigma, 0, 50);
494 ImGui::End();
495 }
496 DisplayListBuilder builder;
497 builder.Scale(GetContentScale().x, GetContentScale().y);
498 builder.DrawPaint({});
499
500 DlPaint paint;
501 paint.setColor(DlColor::kGreen());
502 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma));
503
504 builder.DrawRect(DlRect::MakeXYWH(300, 300, 200, 200), paint);
505 return builder.Build();
506 };
507
508 ASSERT_TRUE(OpenPlaygroundHere(callback));
509}
510
511TEST_P(AiksTest, MaskBlurWithZeroSigmaIsSkipped) {
512 DisplayListBuilder builder;
513
514 DlPaint paint;
515 paint.setColor(DlColor::kBlue());
516 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 0));
517
518 builder.DrawCircle(DlPoint(300, 300), 200, paint);
519 builder.DrawRect(DlRect::MakeLTRB(100, 300, 500, 600), paint);
520
521 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
522}
523
524TEST_P(AiksTest, MaskBlurOnZeroDimensionIsSkippedWideGamut) {
525 // Making sure this test is run on a wide gamut enabled backend
526 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
528
529 DisplayListBuilder builder;
530 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
531
532 DlPaint paint;
533 paint.setColor(DlColor::kBlue());
534 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 10));
535
536 // Zero height above
537 builder.DrawRect(DlRect::MakeLTRB(100, 250, 500, 250), paint);
538 // Regular rect
539 builder.DrawRect(DlRect::MakeLTRB(100, 300, 500, 600), paint);
540 // Zero width to the right
541 builder.DrawRect(DlRect::MakeLTRB(550, 300, 550, 600), paint);
542
543 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
544}
545
547 DlBlurStyle style = DlBlurStyle::kNormal;
548 Scalar sigma = 1.0f;
549 Scalar alpha = 1.0f;
550 std::shared_ptr<DlImageFilter> image_filter;
551 bool invert_colors = false;
552 DlBlendMode blend_mode = DlBlendMode::kSrcOver;
553};
554
555static sk_sp<DisplayList> MaskBlurVariantTest(
556 const AiksTest& test_context,
557 const MaskBlurTestConfig& config) {
558 DisplayListBuilder builder;
559 builder.Scale(test_context.GetContentScale().x,
560 test_context.GetContentScale().y);
561 builder.Scale(0.8f, 0.8f);
562 builder.Translate(50.f, 50.f);
563
564 DlPaint draw_paint;
565 draw_paint.setColor(
568 builder.DrawPaint(draw_paint);
569
570 DlPaint paint;
571 paint.setMaskFilter(DlBlurMaskFilter::Make(config.style, config.sigma));
572 paint.setInvertColors(config.invert_colors);
573 paint.setImageFilter(config.image_filter);
574 paint.setBlendMode(config.blend_mode);
575
576 const Scalar x = 50;
577 const Scalar radius = 20.0f;
578 const Scalar y_spacing = 100.0f;
579 Scalar alpha = config.alpha * 255;
580
581 Scalar y = 50;
582 paint.setColor(DlColor::kCrimson().withAlpha(alpha));
583 builder.DrawRect(DlRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
584 radius, 60.0f - radius),
585 paint);
586
587 y += y_spacing;
588 paint.setColor(DlColor::kBlue().withAlpha(alpha));
589 builder.DrawCircle(DlPoint{x + 25, y + 25}, radius, paint);
590
591 y += y_spacing;
592 paint.setColor(DlColor::kGreen().withAlpha(alpha));
593 builder.DrawOval(DlRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
594 radius, 60.0f - radius),
595 paint);
596
597 y += y_spacing;
598 paint.setColor(DlColor::kPurple().withAlpha(alpha));
600 DlRect::MakeXYWH(x, y, 60.0f, 60.0f), radius, radius);
601 builder.DrawRoundRect(rrect, paint);
602
603 y += y_spacing;
604 paint.setColor(DlColor::kOrange().withAlpha(alpha));
605
606 rrect = DlRoundRect::MakeRectXY(DlRect::MakeXYWH(x, y, 60.0f, 60.0f), //
607 radius, 5.0);
608 builder.DrawRoundRect(rrect, paint);
609
610 y += y_spacing;
611 paint.setColor(DlColor::kMaroon().withAlpha(alpha));
612
613 {
614 DlPathBuilder path_builder;
615 path_builder.MoveTo(DlPoint(x + 0, y + 60));
616 path_builder.LineTo(DlPoint(x + 30, y + 0));
617 path_builder.LineTo(DlPoint(x + 60, y + 60));
618 path_builder.Close();
619
620 builder.DrawPath(path_builder.TakePath(), paint);
621 }
622
623 y += y_spacing;
624 paint.setColor(DlColor::kMaroon().withAlpha(alpha));
625 {
626 DlPath path = DlPath::MakeArc(Rect::MakeXYWH(x + 5, y, 50, 50), //
627 Degrees(90), Degrees(180), false) +
628 DlPath::MakeArc(Rect::MakeXYWH(x + 25, y, 50, 50), //
629 Degrees(90), Degrees(180), false);
630 builder.DrawPath(path, paint);
631 }
632
633 return builder.Build();
634}
635
636static const std::map<std::string, MaskBlurTestConfig> kPaintVariations = {
637 // 1. Normal style, translucent, zero sigma.
638 {"NormalTranslucentZeroSigma",
639 {.style = DlBlurStyle::kNormal, .sigma = 0.0f, .alpha = 0.5f}},
640 // 2. Normal style, translucent.
641 {"NormalTranslucent",
642 {.style = DlBlurStyle::kNormal, .sigma = 8.0f, .alpha = 0.5f}},
643 // 3. Solid style, translucent.
644 {"SolidTranslucent",
645 {.style = DlBlurStyle::kSolid, .sigma = 8.0f, .alpha = 0.5f}},
646 // 4. Solid style, opaque.
647 {"SolidOpaque", {.style = DlBlurStyle::kSolid, .sigma = 8.0f}},
648 // 5. Solid style, translucent, color & image filtered.
649 {"SolidTranslucentWithFilters",
650 {.style = DlBlurStyle::kSolid,
651 .sigma = 8.0f,
652 .alpha = 0.5f,
653 .image_filter = DlImageFilter::MakeBlur(3, 3, DlTileMode::kClamp),
654 .invert_colors = true}},
655 // 6. Solid style, translucent, exclusion blended.
656 {"SolidTranslucentExclusionBlend",
657 {.style = DlBlurStyle::kSolid,
658 .sigma = 8.0f,
659 .alpha = 0.5f,
660 .blend_mode = DlBlendMode::kExclusion}},
661 // 7. Inner style, translucent.
662 {"InnerTranslucent",
663 {.style = DlBlurStyle::kInner, .sigma = 8.0f, .alpha = 0.5f}},
664 // 8. Inner style, translucent, blurred.
665 {"InnerTranslucentWithBlurImageFilter",
666 {.style = DlBlurStyle::kInner,
667 .sigma = 8.0f,
668 .alpha = 0.5f,
669 .image_filter = DlImageFilter::MakeBlur(3, 3, DlTileMode::kClamp)}},
670 // 9. Outer style, translucent.
671 {"OuterTranslucent",
672 {.style = DlBlurStyle::kOuter, .sigma = 8.0f, .alpha = 0.5f}},
673 // 10. Outer style, opaque, image filtered.
674 {"OuterOpaqueWithBlurImageFilter",
675 {.style = DlBlurStyle::kOuter,
676 .sigma = 8.0f,
677 .image_filter = DlImageFilter::MakeBlur(3, 3, DlTileMode::kClamp)}}};
678
679#define MASK_BLUR_VARIANT_TEST(config) \
680 TEST_P(AiksTest, MaskBlurVariantTest##config) { \
681 ASSERT_TRUE(OpenPlaygroundHere( \
682 MaskBlurVariantTest(*this, kPaintVariations.at(#config)))); \
683 }
684
685MASK_BLUR_VARIANT_TEST(NormalTranslucentZeroSigma)
686MASK_BLUR_VARIANT_TEST(NormalTranslucent)
687MASK_BLUR_VARIANT_TEST(SolidTranslucent)
688MASK_BLUR_VARIANT_TEST(SolidOpaque)
689MASK_BLUR_VARIANT_TEST(SolidTranslucentWithFilters)
690MASK_BLUR_VARIANT_TEST(SolidTranslucentExclusionBlend)
691MASK_BLUR_VARIANT_TEST(InnerTranslucent)
692MASK_BLUR_VARIANT_TEST(InnerTranslucentWithBlurImageFilter)
693MASK_BLUR_VARIANT_TEST(OuterTranslucent)
694MASK_BLUR_VARIANT_TEST(OuterOpaqueWithBlurImageFilter)
695
696#undef MASK_BLUR_VARIANT_TEST
697
698TEST_P(AiksTest, GaussianBlurStyleInner) {
699 DisplayListBuilder builder;
700 builder.Scale(GetContentScale().x, GetContentScale().y);
701
702 DlPaint paint;
703 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1));
704 builder.DrawPaint(paint);
705
706 paint.setColor(DlColor::kGreen());
707 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kInner, 30));
708
709 DlPathBuilder path_builder;
710 path_builder.MoveTo(DlPoint(200, 200));
711 path_builder.LineTo(DlPoint(300, 400));
712 path_builder.LineTo(DlPoint(100, 400));
713 path_builder.Close();
714
715 builder.DrawPath(path_builder.TakePath(), paint);
716
717 // Draw another thing to make sure the clip area is reset.
718 DlPaint red;
719 red.setColor(DlColor::kRed());
720 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
721
722 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
723}
724
725TEST_P(AiksTest, GaussianBlurStyleOuter) {
726 DisplayListBuilder builder;
727 builder.Scale(GetContentScale().x, GetContentScale().y);
728
729 DlPaint paint;
730 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1.0));
731 builder.DrawPaint(paint);
732
733 paint.setColor(DlColor::kGreen());
734 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kOuter, 30));
735
736 DlPathBuilder path_builder;
737 path_builder.MoveTo(DlPoint(200, 200));
738 path_builder.LineTo(DlPoint(300, 400));
739 path_builder.LineTo(DlPoint(100, 400));
740 path_builder.Close();
741
742 builder.DrawPath(path_builder.TakePath(), paint);
743
744 // Draw another thing to make sure the clip area is reset.
745 DlPaint red;
746 red.setColor(DlColor::kRed());
747 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
748
749 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
750}
751
752TEST_P(AiksTest, GaussianBlurStyleSolid) {
753 DisplayListBuilder builder;
754 builder.Scale(GetContentScale().x, GetContentScale().y);
755
756 DlPaint paint;
757 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1.0));
758 builder.DrawPaint(paint);
759
760 paint.setColor(DlColor::kGreen());
761 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kSolid, 30));
762
763 DlPathBuilder path_builder;
764 path_builder.MoveTo(DlPoint(200, 200));
765 path_builder.LineTo(DlPoint(300, 400));
766 path_builder.LineTo(DlPoint(100, 400));
767 path_builder.Close();
768
769 builder.DrawPath(path_builder.TakePath(), paint);
770
771 // Draw another thing to make sure the clip area is reset.
772 DlPaint red;
773 red.setColor(DlColor::kRed());
774 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
775
776 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
777}
778
779TEST_P(AiksTest, MaskBlurTexture) {
780 Scalar sigma = 30;
781 auto callback = [&]() -> sk_sp<DisplayList> {
782 if (AiksTest::ImGuiBegin("Controls", nullptr,
783 ImGuiWindowFlags_AlwaysAutoResize)) {
784 ImGui::SliderFloat("Sigma", &sigma, 0, 500);
785 ImGui::End();
786 }
787
788 DisplayListBuilder builder;
789 builder.Scale(GetContentScale().x, GetContentScale().y);
790
791 DlPaint paint;
792 paint.setColor(DlColor::kGreen());
793 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma));
794
795 builder.DrawImage(
796 DlImageImpeller::Make(CreateTextureForFixture("boston.jpg")),
797 DlPoint(200, 200), DlImageSampling::kNearestNeighbor, &paint);
798
799 DlPaint red;
800 red.setColor(DlColor::kRed());
801 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
802
803 return builder.Build();
804 };
805 ASSERT_TRUE(OpenPlaygroundHere(callback));
806}
807
808TEST_P(AiksTest, MaskBlurDoesntStretchContents) {
809 Scalar sigma = 70;
810 auto callback = [&]() -> sk_sp<DisplayList> {
811 if (AiksTest::ImGuiBegin("Controls", nullptr,
812 ImGuiWindowFlags_AlwaysAutoResize)) {
813 ImGui::SliderFloat("Sigma", &sigma, 0, 500);
814 ImGui::End();
815 }
816
817 DisplayListBuilder builder;
818 builder.Scale(GetContentScale().x, GetContentScale().y);
819
820 DlPaint paint;
821 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1.0));
822 builder.DrawPaint(paint);
823
824 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
825
826 builder.Transform(Matrix::MakeTranslation({100, 100}) *
827 Matrix::MakeScale({0.5, 0.5, 1.0f}));
828
830 DlImageImpeller::Make(boston), DlTileMode::kRepeat, DlTileMode::kRepeat,
831 DlImageSampling::kMipmapLinear));
832 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, sigma));
833
834 builder.DrawRect(DlRect::MakeXYWH(0, 0, boston->GetSize().width,
835 boston->GetSize().height),
836 paint);
837
838 return builder.Build();
839 };
840 ASSERT_TRUE(OpenPlaygroundHere(callback));
841}
842
843TEST_P(AiksTest, GaussianBlurAtPeripheryVertical) {
844 DisplayListBuilder builder;
845
846 DlPaint paint;
847 builder.Scale(GetContentScale().x, GetContentScale().y);
848
851 DlRect::MakeLTRB(0, 0, GetWindowSize().width, 100), 10, 10);
852 builder.DrawRoundRect(rrect, paint);
853
856 DlRect::MakeLTRB(0, 110, GetWindowSize().width, 210), 10, 10);
857 builder.DrawRoundRect(rrect, paint);
858 builder.ClipRect(DlRect::MakeLTRB(100, 0, 200, GetWindowSize().height));
859
860 DlPaint save_paint;
861 save_paint.setBlendMode(DlBlendMode::kSrc);
862
863 auto backdrop_filter = DlImageFilter::MakeBlur(20, 20, DlTileMode::kClamp);
864
865 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
866 builder.Restore();
867
868 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
869}
870
871TEST_P(AiksTest, GaussianBlurAtPeripheryHorizontal) {
872 DisplayListBuilder builder;
873
874 builder.Scale(GetContentScale().x, GetContentScale().y);
875 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
876 builder.DrawImageRect(
877 DlImageImpeller::Make(boston),
878 DlRect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height),
879 DlRect::MakeLTRB(0, 0, GetWindowSize().width, 100),
880 DlImageSampling::kNearestNeighbor);
881
882 DlPaint paint;
884
886 DlRect::MakeLTRB(0, 110, GetWindowSize().width, 210), 10, 10);
887 builder.DrawRoundRect(rrect, paint);
888 builder.ClipRect(DlRect::MakeLTRB(0, 50, GetWindowSize().width, 150));
889
890 DlPaint save_paint;
891 save_paint.setBlendMode(DlBlendMode::kSrc);
892
893 auto backdrop_filter = DlImageFilter::MakeBlur(20, 20, DlTileMode::kClamp);
894 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get());
895
896 builder.Restore();
897 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
898}
899
900TEST_P(AiksTest, GaussianBlurAnimatedBackdrop) {
901 // This test is for checking out how stable rendering is when content is
902 // translated underneath a blur. Animating under a blur can cause
903 // *shimmering* to happen as a result of pixel alignment.
904 // See also: https://github.com/flutter/flutter/issues/140193
905 auto boston =
906 CreateTextureForFixture("boston.jpg", /*enable_mipmapping=*/true);
907 ASSERT_TRUE(boston);
908 int64_t count = 0;
909 Scalar sigma = 20.0;
910 Scalar freq = 0.1;
911 Scalar amp = 50.0;
912 auto callback = [&]() -> sk_sp<DisplayList> {
913 if (AiksTest::ImGuiBegin("Controls", nullptr,
914 ImGuiWindowFlags_AlwaysAutoResize)) {
915 ImGui::SliderFloat("Sigma", &sigma, 0, 200);
916 ImGui::SliderFloat("Frequency", &freq, 0.01, 2.0);
917 ImGui::SliderFloat("Amplitude", &amp, 1, 100);
918 ImGui::End();
919 }
920
921 DisplayListBuilder builder;
922 builder.Scale(GetContentScale().x, GetContentScale().y);
923 Scalar y = amp * sin(freq * 2.0 * M_PI * count / 60);
924 builder.DrawImage(DlImageImpeller::Make(boston),
925 DlPoint(1024 / 2 - boston->GetSize().width / 2,
926 (768 / 2 - boston->GetSize().height / 2) + y),
927 DlImageSampling::kMipmapLinear);
928 static PlaygroundPoint point_a(Point(100, 100), 20, Color::Red());
929 static PlaygroundPoint point_b(Point(900, 700), 20, Color::Red());
930 auto [handle_a, handle_b] = DrawPlaygroundLine(point_a, point_b);
931
932 builder.ClipRect(
933 DlRect::MakeLTRB(handle_a.x, handle_a.y, handle_b.x, handle_b.y));
934 builder.ClipRect(DlRect::MakeLTRB(100, 100, 900, 700));
935
936 DlPaint paint;
937 paint.setBlendMode(DlBlendMode::kSrc);
938
939 auto backdrop_filter =
940 DlImageFilter::MakeBlur(sigma, sigma, DlTileMode::kClamp);
941 builder.SaveLayer(std::nullopt, &paint, backdrop_filter.get());
942 count += 1;
943 return builder.Build();
944 };
945 ASSERT_TRUE(OpenPlaygroundHere(callback));
946}
947
948TEST_P(AiksTest, GaussianBlurStyleInnerGradient) {
949 DisplayListBuilder builder;
950
951 builder.Scale(GetContentScale().x, GetContentScale().y);
952
953 DlPaint paint;
954 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1.0));
955 builder.DrawPaint(paint);
956
957 std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
958 DlColor::RGBA(0.7568, 0.2627, 0.2118, 1.0)};
959 std::vector<Scalar> stops = {0.0, 1.0};
960
961 paint = DlPaint{};
963 /*start_point=*/{0, 0},
964 /*end_point=*/{200, 200},
965 /*stop_count=*/colors.size(),
966 /*colors=*/colors.data(),
967 /*stops=*/stops.data(),
968 /*tile_mode=*/DlTileMode::kMirror));
969 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kInner, 30));
970
971 DlPathBuilder path_builder;
972 path_builder.MoveTo(DlPoint(200, 200));
973 path_builder.LineTo(DlPoint(300, 400));
974 path_builder.LineTo(DlPoint(100, 400));
975 path_builder.Close();
976 builder.DrawPath(path_builder.TakePath(), paint);
977
978 // Draw another thing to make sure the clip area is reset.
979 DlPaint red;
980 red.setColor(DlColor::kRed());
981 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
982
983 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
984}
985
986TEST_P(AiksTest, GaussianBlurStyleSolidGradient) {
987 DisplayListBuilder builder;
988 builder.Scale(GetContentScale().x, GetContentScale().y);
989
990 DlPaint paint;
991 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1.0));
992 builder.DrawPaint(paint);
993
994 std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
995 DlColor::RGBA(0.7568, 0.2627, 0.2118, 1.0)};
996 std::vector<Scalar> stops = {0.0, 1.0};
997
998 paint = DlPaint{};
1000 /*start_point=*/{0, 0},
1001 /*end_point=*/{200, 200},
1002 /*stop_count=*/colors.size(),
1003 /*colors=*/colors.data(),
1004 /*stops=*/stops.data(),
1005 /*tile_mode=*/DlTileMode::kMirror));
1006 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kSolid, 30));
1007
1008 DlPathBuilder path_builder;
1009 path_builder.MoveTo(DlPoint(200, 200));
1010 path_builder.LineTo(DlPoint(300, 400));
1011 path_builder.LineTo(DlPoint(100, 400));
1012 path_builder.Close();
1013 builder.DrawPath(path_builder.TakePath(), paint);
1014
1015 // Draw another thing to make sure the clip area is reset.
1016 DlPaint red;
1017 red.setColor(DlColor::kRed());
1018 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
1019 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1020}
1021
1022TEST_P(AiksTest, GaussianBlurStyleOuterGradient) {
1023 DisplayListBuilder builder;
1024 builder.Scale(GetContentScale().x, GetContentScale().y);
1025
1026 DlPaint paint;
1027 paint.setColor(DlColor::RGBA(0.1, 0.1, 0.1, 1.0));
1028 builder.DrawPaint(paint);
1029
1030 std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
1031 DlColor::RGBA(0.7568, 0.2627, 0.2118, 1.0)};
1032 std::vector<Scalar> stops = {0.0, 1.0};
1033
1034 paint = DlPaint{};
1036 /*start_point=*/{0, 0},
1037 /*end_point=*/{200, 200},
1038 /*stop_count=*/colors.size(),
1039 /*colors=*/colors.data(),
1040 /*stops=*/stops.data(),
1041 /*tile_mode=*/DlTileMode::kMirror));
1042 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kOuter, 30));
1043
1044 DlPathBuilder path_builder;
1045 path_builder.MoveTo(DlPoint(200, 200));
1046 path_builder.LineTo(DlPoint(300, 400));
1047 path_builder.LineTo(DlPoint(100, 400));
1048 path_builder.Close();
1049 builder.DrawPath(path_builder.TakePath(), paint);
1050
1051 // Draw another thing to make sure the clip area is reset.
1052 DlPaint red;
1053 red.setColor(DlColor::kRed());
1054 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), red);
1055 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1056}
1057
1058TEST_P(AiksTest, GaussianBlurScaledAndClipped) {
1059 DisplayListBuilder builder;
1060 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
1061 Rect bounds =
1062 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
1063 Vector2 image_center = Vector2(bounds.GetSize() / 2);
1064
1065 DlPaint paint;
1066 paint.setImageFilter(DlImageFilter::MakeBlur(20, 20, DlTileMode::kDecal));
1067
1068 Vector2 clip_size = {150, 75};
1069 Vector2 center = Vector2(1024, 768) / 2;
1070 builder.Scale(GetContentScale().x, GetContentScale().y);
1071
1072 auto rect =
1073 Rect::MakeLTRB(center.x, center.y, center.x, center.y).Expand(clip_size);
1074 builder.ClipRect(DlRect::MakeLTRB(rect.GetLeft(), rect.GetTop(),
1075 rect.GetRight(), rect.GetBottom()));
1076 builder.Translate(center.x, center.y);
1077 builder.Scale(0.6, 0.6);
1078
1079 DlRect sk_bounds = DlRect::MakeLTRB(bounds.GetLeft(), bounds.GetTop(),
1080 bounds.GetRight(), bounds.GetBottom());
1081 Rect dest = bounds.Shift(-image_center);
1082 DlRect sk_dst = DlRect::MakeLTRB(dest.GetLeft(), dest.GetTop(),
1083 dest.GetRight(), dest.GetBottom());
1084 builder.DrawImageRect(DlImageImpeller::Make(boston), /*src=*/sk_bounds,
1085 /*dst=*/sk_dst, DlImageSampling::kNearestNeighbor,
1086 &paint);
1087
1088 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1089}
1090
1091TEST_P(AiksTest, GaussianBlurRotatedAndClippedInteractive) {
1092 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
1093
1094 auto callback = [&]() -> sk_sp<DisplayList> {
1095 const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
1096 const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
1097 DlTileMode::kMirror, DlTileMode::kDecal};
1098
1099 static float rotation = 0;
1100 static float scale = 0.6;
1101 static int selected_tile_mode = 3;
1102
1103 if (AiksTest::ImGuiBegin("Controls", nullptr,
1104 ImGuiWindowFlags_AlwaysAutoResize)) {
1105 ImGui::SliderFloat("Rotation (degrees)", &rotation, -180, 180);
1106 ImGui::SliderFloat("Scale", &scale, 0, 2.0);
1107 ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
1108 sizeof(tile_mode_names) / sizeof(char*));
1109 ImGui::End();
1110 }
1111
1112 DisplayListBuilder builder;
1113 Rect bounds =
1114 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
1115 Vector2 image_center = Vector2(bounds.GetSize() / 2);
1116 DlPaint paint;
1117 paint.setImageFilter(
1118 DlImageFilter::MakeBlur(20, 20, tile_modes[selected_tile_mode]));
1119
1120 static PlaygroundPoint point_a(Point(362, 309), 20, Color::Red());
1121 static PlaygroundPoint point_b(Point(662, 459), 20, Color::Red());
1122 auto [handle_a, handle_b] = DrawPlaygroundLine(point_a, point_b);
1123 Vector2 center = Vector2(1024, 768) / 2;
1124
1125 builder.Scale(GetContentScale().x, GetContentScale().y);
1126 builder.ClipRect(
1127 DlRect::MakeLTRB(handle_a.x, handle_a.y, handle_b.x, handle_b.y));
1128 builder.Translate(center.x, center.y);
1129 builder.Scale(scale, scale);
1130 builder.Rotate(rotation);
1131
1132 DlRect sk_bounds = DlRect::MakeLTRB(bounds.GetLeft(), bounds.GetTop(),
1133 bounds.GetRight(), bounds.GetBottom());
1134 Rect dest = bounds.Shift(-image_center);
1135 DlRect sk_dst = DlRect::MakeLTRB(dest.GetLeft(), dest.GetTop(),
1136 dest.GetRight(), dest.GetBottom());
1137 builder.DrawImageRect(DlImageImpeller::Make(boston), /*src=*/sk_bounds,
1138 /*dst=*/sk_dst, DlImageSampling::kNearestNeighbor,
1139 &paint);
1140 return builder.Build();
1141 };
1142
1143 ASSERT_TRUE(OpenPlaygroundHere(callback));
1144}
1145
1146TEST_P(AiksTest, GaussianBlurOneDimension) {
1147 DisplayListBuilder builder;
1148
1149 builder.Scale(GetContentScale().x, GetContentScale().y);
1150 builder.Scale(0.5, 0.5);
1151
1152 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
1153 builder.DrawImage(DlImageImpeller::Make(boston), DlPoint(100, 100), {});
1154
1155 DlPaint paint;
1156 paint.setBlendMode(DlBlendMode::kSrc);
1157
1158 auto backdrop_filter = DlImageFilter::MakeBlur(50, 0, DlTileMode::kClamp);
1159 builder.SaveLayer(std::nullopt, &paint, backdrop_filter.get());
1160 builder.Restore();
1161 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1162}
1163
1164// Smoketest to catch issues with the coverage hint.
1165// Draws a rotated blurred image within a rectangle clip. The center of the clip
1166// rectangle is the center of the rotated image. The entire area of the clip
1167// rectangle should be filled with opaque colors output by the blur.
1168TEST_P(AiksTest, GaussianBlurRotatedAndClipped) {
1169 DisplayListBuilder builder;
1170
1171 std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
1172 Rect bounds =
1173 Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height);
1174
1175 DlPaint paint;
1176 paint.setImageFilter(DlImageFilter::MakeBlur(20, 20, DlTileMode::kDecal));
1177
1178 Vector2 image_center = Vector2(bounds.GetSize() / 2);
1179 Vector2 clip_size = {150, 75};
1180 Vector2 center = Vector2(1024, 768) / 2;
1181 builder.Scale(GetContentScale().x, GetContentScale().y);
1182
1183 auto clip_bounds =
1184 Rect::MakeLTRB(center.x, center.y, center.x, center.y).Expand(clip_size);
1185 builder.ClipRect(DlRect::MakeLTRB(clip_bounds.GetLeft(), clip_bounds.GetTop(),
1186 clip_bounds.GetRight(),
1187 clip_bounds.GetBottom()));
1188 builder.Translate(center.x, center.y);
1189 builder.Scale(0.6, 0.6);
1190 builder.Rotate(25);
1191
1192 auto dst_rect = bounds.Shift(-image_center);
1193 builder.DrawImageRect(
1194 DlImageImpeller::Make(boston), /*src=*/
1195 DlRect::MakeLTRB(bounds.GetLeft(), bounds.GetTop(), bounds.GetRight(),
1196 bounds.GetBottom()),
1197 /*dst=*/
1198 DlRect::MakeLTRB(dst_rect.GetLeft(), dst_rect.GetTop(),
1199 dst_rect.GetRight(), dst_rect.GetBottom()),
1200 DlImageSampling::kMipmapLinear, &paint);
1201
1202 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1203}
1204
1205TEST_P(AiksTest, GaussianBlurRotatedNonUniform) {
1206 auto callback = [&]() -> sk_sp<DisplayList> {
1207 const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
1208 const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
1209 DlTileMode::kMirror, DlTileMode::kDecal};
1210
1211 static float rotation = 45;
1212 static float scale = 0.6;
1213 static int selected_tile_mode = 3;
1214
1215 if (AiksTest::ImGuiBegin("Controls", nullptr,
1216 ImGuiWindowFlags_AlwaysAutoResize)) {
1217 ImGui::SliderFloat("Rotation (degrees)", &rotation, -180, 180);
1218 ImGui::SliderFloat("Scale", &scale, 0, 2.0);
1219 ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
1220 sizeof(tile_mode_names) / sizeof(char*));
1221 ImGui::End();
1222 }
1223
1224 DisplayListBuilder builder;
1225
1226 DlPaint paint;
1227 paint.setColor(DlColor::kGreen());
1228 paint.setImageFilter(
1229 DlImageFilter::MakeBlur(50, 0, tile_modes[selected_tile_mode]));
1230
1231 Vector2 center = Vector2(1024, 768) / 2;
1232 builder.Scale(GetContentScale().x, GetContentScale().y);
1233 builder.Translate(center.x, center.y);
1234 builder.Scale(scale, scale);
1235 builder.Rotate(rotation);
1236
1237 DlRoundRect rrect =
1238 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(-100, -100, 200, 200), 10, 10);
1239 builder.DrawRoundRect(rrect, paint);
1240 return builder.Build();
1241 };
1242
1243 ASSERT_TRUE(OpenPlaygroundHere(callback));
1244}
1245
1246TEST_P(AiksTest, BlurredRectangleWithShader) {
1247 DisplayListBuilder builder;
1248 builder.Scale(GetContentScale().x, GetContentScale().y);
1249
1250 auto paint_lines = [&builder](Scalar dx, Scalar dy, DlPaint paint) {
1251 auto draw_line = [&builder, &paint](DlPoint a, DlPoint b) {
1252 DlPath line = DlPath::MakeLine(a, b);
1253 builder.DrawPath(line, paint);
1254 };
1255 paint.setStrokeWidth(5);
1256 paint.setDrawStyle(DlDrawStyle::kStroke);
1257 draw_line(DlPoint(dx + 100, dy + 100), DlPoint(dx + 200, dy + 200));
1258 draw_line(DlPoint(dx + 100, dy + 200), DlPoint(dx + 200, dy + 100));
1259 draw_line(DlPoint(dx + 150, dy + 100), DlPoint(dx + 200, dy + 150));
1260 draw_line(DlPoint(dx + 100, dy + 150), DlPoint(dx + 150, dy + 200));
1261 };
1262
1263 AiksContext renderer(GetContext(), nullptr);
1264 DisplayListBuilder recorder_builder;
1265 for (int x = 0; x < 5; ++x) {
1266 for (int y = 0; y < 5; ++y) {
1267 DlRect rect = DlRect::MakeXYWH(x * 20, y * 20, 20, 20);
1268 DlPaint paint;
1269 paint.setColor(((x + y) & 1) == 0 ? DlColor::kYellow()
1270 : DlColor::kBlue());
1271
1272 recorder_builder.DrawRect(rect, paint);
1273 }
1274 }
1275 auto texture =
1276 DisplayListToTexture(recorder_builder.Build(), {100, 100}, renderer);
1277
1278 auto image_source = DlColorSource::MakeImage(
1279 DlImageImpeller::Make(texture), DlTileMode::kRepeat, DlTileMode::kRepeat);
1280 auto blur_filter = DlImageFilter::MakeBlur(5, 5, DlTileMode::kDecal);
1281
1282 DlPaint paint;
1284 builder.DrawRect(DlRect::MakeLTRB(0, 0, 300, 600), paint);
1285
1286 paint.setColorSource(image_source);
1287 builder.DrawRect(DlRect::MakeLTRB(100, 100, 200, 200), paint);
1288
1289 paint.setColorSource(nullptr);
1290 paint.setColor(DlColor::kRed());
1291 builder.DrawRect(DlRect::MakeLTRB(300, 0, 600, 600), paint);
1292
1293 paint.setColorSource(image_source);
1294 paint.setImageFilter(blur_filter);
1295 builder.DrawRect(DlRect::MakeLTRB(400, 100, 500, 200), paint);
1296
1297 paint.setImageFilter(nullptr);
1298 paint_lines(0, 300, paint);
1299
1300 paint.setImageFilter(blur_filter);
1301 paint_lines(300, 300, paint);
1302
1303 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1304}
1305
1306// This addresses a bug where tiny blurs could result in mip maps that beyond
1307// the limits for the textures used for blurring.
1308// See also: b/323402168
1309TEST_P(AiksTest, GaussianBlurSolidColorTinyMipMap) {
1310 AiksContext renderer(GetContext(), nullptr);
1311
1312 for (int32_t i = 1; i < 5; ++i) {
1313 DisplayListBuilder builder;
1314 Scalar fi = i;
1315 DlPathBuilder path_builder;
1316 path_builder.MoveTo(DlPoint(100, 100));
1317 path_builder.LineTo(DlPoint(100 + fi, 100 + fi));
1318
1319 DlPaint paint;
1321 auto blur_filter = DlImageFilter::MakeBlur(0.1, 0.1, DlTileMode::kClamp);
1322 paint.setImageFilter(blur_filter);
1323
1324 builder.DrawPath(path_builder.TakePath(), paint);
1325
1326 auto image = DisplayListToTexture(builder.Build(), {1024, 768}, renderer);
1327 EXPECT_TRUE(image) << " length " << i;
1328 }
1329}
1330
1331// This addresses a bug where tiny blurs could result in mip maps that beyond
1332// the limits for the textures used for blurring.
1333// See also: b/323402168
1334TEST_P(AiksTest, GaussianBlurBackdropTinyMipMap) {
1335 AiksContext renderer(GetContext(), nullptr);
1336 for (int32_t i = 1; i < 5; ++i) {
1337 DisplayListBuilder builder;
1338
1339 ISize clip_size = ISize(i, i);
1340 builder.Save();
1341 builder.ClipRect(
1342 DlRect::MakeXYWH(400, 400, clip_size.width, clip_size.height));
1343
1344 DlPaint paint;
1345 paint.setColor(DlColor::kGreen());
1346 auto blur_filter = DlImageFilter::MakeBlur(0.1, 0.1, DlTileMode::kDecal);
1347 paint.setImageFilter(blur_filter);
1348
1349 builder.DrawCircle(DlPoint(400, 400), 200, paint);
1350 builder.Restore();
1351
1352 auto image = DisplayListToTexture(builder.Build(), {1024, 768}, renderer);
1353 EXPECT_TRUE(image) << " length " << i;
1354 }
1355}
1356
1358 CanRenderMultipleBackdropBlurWithSingleBackdropIdDifferentLayers) {
1359 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
1360
1361 DisplayListBuilder builder;
1362
1363 DlPaint paint;
1364 builder.DrawImage(image, DlPoint(50.0, 50.0),
1365 DlImageSampling::kNearestNeighbor, &paint);
1366
1367 for (int i = 0; i < 6; i++) {
1368 if (i != 0) {
1369 DlPaint paint;
1370 paint.setColor(DlColor::kWhite().withAlphaF(0.95));
1371 builder.SaveLayer(std::nullopt, &paint);
1372 }
1374 DlRect::MakeXYWH(50 + (i * 100), 250, 100, 100), 20, 20);
1375 builder.Save();
1376 builder.ClipRoundRect(rrect);
1377
1378 DlPaint save_paint;
1379 save_paint.setBlendMode(DlBlendMode::kSrc);
1380 auto backdrop_filter = DlImageFilter::MakeBlur(30, 30, DlTileMode::kClamp);
1381 builder.SaveLayer(std::nullopt, &save_paint, backdrop_filter.get(),
1382 /*backdrop_id=*/1);
1383 builder.Restore();
1384 builder.Restore();
1385 if (i != 0) {
1386 builder.Restore();
1387 }
1388 }
1389
1390 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1391}
1392
1393TEST_P(AiksTest, BlurGradientWithOpacity) {
1394 DisplayListBuilder builder;
1395 builder.Scale(GetContentScale().x, GetContentScale().y);
1396
1397 std::vector<DlColor> colors = {DlColor(0xFFFF0000), DlColor(0xFF00FF00)};
1398 std::vector<Scalar> stops = {0.0, 1.0};
1399
1400 auto gradient = DlColorSource::MakeLinear(
1401 {0, 0}, {400, 400}, 2, colors.data(), stops.data(), DlTileMode::kClamp);
1402
1403 DlPaint save_paint;
1404 save_paint.setOpacity(0.5);
1405 builder.SaveLayer(std::nullopt, &save_paint);
1406
1407 DlPaint paint;
1408 paint.setColorSource(gradient);
1409 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1));
1410 builder.DrawRect(DlRect::MakeXYWH(100, 100, 200, 200), paint);
1411
1412 builder.Restore();
1413
1414 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1415}
1416
1417// The artifacts this test attempts to reproduce don't reproduce on playgrounds.
1418// The test is animated as an attempt to catch any ghosting that may happen
1419// when DontCare is used instead of Clear.
1420// https://github.com/flutter/flutter/issues/171772
1421TEST_P(AiksTest, CanRenderNestedBackdropBlur) {
1422 int64_t count = 0;
1423 auto callback = [&]() -> sk_sp<DisplayList> {
1424 DisplayListBuilder builder;
1425
1426 Scalar freq = 1.0;
1427 Scalar amp = 50.0;
1428 Scalar offset = amp * sin(freq * 2.0 * M_PI * count / 60.0);
1429
1430 // Draw some background content to be blurred.
1431 DlPaint paint;
1433 builder.DrawCircle(DlPoint(100 + offset, 100), 50, paint);
1435 builder.DrawCircle(DlPoint(300, 200 + offset), 100, paint);
1437 builder.DrawCircle(DlPoint(140, 170), 75, paint);
1439 builder.DrawCircle(DlPoint(180 + offset, 120 + offset), 100, paint);
1440
1441 // This is the first backdrop blur, simulating the navigation transition.
1442 auto backdrop_filter1 = DlImageFilter::MakeBlur(15, 15, DlTileMode::kClamp);
1443 builder.SaveLayer(std::nullopt, nullptr, backdrop_filter1.get());
1444
1445 // Draw the semi-transparent container from the second screen.
1446 DlPaint transparent_paint;
1447 transparent_paint.setColor(DlColor::kWhite().withAlpha(0.1 * 255));
1448 builder.DrawPaint(transparent_paint);
1449
1450 {
1451 // This is the second, nested backdrop blur.
1452 auto backdrop_filter2 =
1453 DlImageFilter::MakeBlur(10, 10, DlTileMode::kClamp);
1454 builder.Save();
1455 builder.ClipRect(DlRect::MakeXYWH(150, 150, 300, 300));
1456 builder.SaveLayer(std::nullopt, nullptr, backdrop_filter2.get());
1457 builder.Restore(); // Restore from SaveLayer
1458 builder.Restore(); // Restore from ClipRect
1459 }
1460
1461 builder.Restore(); // Restore from the first SaveLayer
1462
1463 count++;
1464 return builder.Build();
1465 };
1466 ASSERT_TRUE(OpenPlaygroundHere(callback));
1467}
1468
1469} // namespace testing
1470} // namespace impeller
#define MASK_BLUR_VARIANT_TEST(config)
void DrawOval(const DlRect &bounds, const DlPaint &paint) override
void ClipRect(const DlRect &rect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void DrawImageRect(const sk_sp< DlImage > &image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, const DlPaint *paint=nullptr, DlSrcRectConstraint constraint=DlSrcRectConstraint::kFast) override
void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint) override
void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr) override
void DrawColor(DlColor color, DlBlendMode mode) override
void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void DrawLine(const DlPoint &p0, const DlPoint &p1, const DlPaint &paint) override
void ClipRoundRect(const DlRoundRect &rrect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void Rotate(DlScalar degrees) override
void Scale(DlScalar sx, DlScalar sy) override
void Translate(DlScalar tx, DlScalar ty) override
void DrawPaint(const DlPaint &paint) override
sk_sp< DisplayList > Build()
Definition dl_builder.cc:66
void DrawPath(const DlPath &path, const DlPaint &paint) override
void Transform(const DlMatrix &matrix) override
void DrawRect(const DlRect &rect, const DlPaint &paint) override
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
static std::shared_ptr< const DlColorFilter > MakeBlend(DlColor color, DlBlendMode mode)
static std::shared_ptr< const DlColorFilter > MakeMatrix(const float matrix[20])
static std::shared_ptr< DlColorSource > MakeImage(const sk_sp< const DlImage > &image, DlTileMode horizontal_tile_mode, DlTileMode vertical_tile_mode, DlImageSampling sampling=DlImageSampling::kLinear, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlColorSource > MakeLinear(const DlPoint start_point, const DlPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlImageFilter > MakeBlur(DlScalar sigma_x, DlScalar sigma_y, DlTileMode tile_mode)
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
static std::shared_ptr< DlImageFilter > MakeCompose(const std::shared_ptr< DlImageFilter > &outer, const std::shared_ptr< DlImageFilter > &inner)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setInvertColors(bool isInvertColors)
Definition dl_paint.h:64
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:85
DlPaint & setImageFilter(std::nullptr_t filter)
Definition dl_paint.h:167
DlPaint & setMaskFilter(std::nullptr_t filter)
Definition dl_paint.h:185
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPaint & setOpacity(DlScalar opacity)
Definition dl_paint.h:78
DlPaint & setColorFilter(std::nullptr_t filter)
Definition dl_paint.h:149
DlPaint & setColorSource(std::nullptr_t source)
Definition dl_paint.h:131
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
static DlPath MakeLine(const DlPoint a, const DlPoint b)
Definition dl_path.cc:89
static DlPath MakeCircle(const DlPoint center, DlScalar radius)
Definition dl_path.cc:68
static DlPath MakeArc(const DlRect &bounds, DlDegrees start, DlDegrees sweep, bool use_center)
Definition dl_path.cc:101
static DlPath MakeRect(const DlRect &rect)
Definition dl_path.cc:39
double x() const
Definition geometry.h:22
double y() const
Definition geometry.h:23
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
Point GetContentScale() const
int32_t x
FlutterVulkanImage * image
FlutterDesktopBinaryReply callback
FlTexture * texture
double y
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 switch_defs.h:52
impeller::Point DlPoint
TEST_P(AiksTest, DrawAtlasNoColor)
static const std::map< std::string, MaskBlurTestConfig > kPaintVariations
sk_sp< flutter::DisplayList > DoGradientOvalStrokeMaskBlur(Vector2 content_Scale, Scalar sigma, DlBlurStyle style)
static sk_sp< DisplayList > MaskBlurVariantTest(const AiksTest &test_context, const MaskBlurTestConfig &config)
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips)
Render the provided display list to a texture with the given size.
Point Vector2
Definition point.h:331
float Scalar
Definition scalar.h:19
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition widgets.cc:11
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition widgets.cc:51
BlendMode
Definition color.h:58
ISize64 ISize
Definition size.h:162
int32_t height
int32_t width
static constexpr DlColor kMagenta()
Definition dl_color.h:75
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor kDarkMagenta()
Definition dl_color.h:91
static constexpr DlColor RGBA(DlScalar r, DlScalar g, DlScalar b, DlScalar a)
Construct a 32 bit color from floating point R, G, B, and A color channels.
Definition dl_color.h:48
static constexpr DlColor kCrimson()
Definition dl_color.h:85
static constexpr DlColor kMaroon()
Definition dl_color.h:82
static constexpr DlColor kYellow()
Definition dl_color.h:76
static constexpr DlColor kPurple()
Definition dl_color.h:88
static constexpr DlColor kChartreuse()
Definition dl_color.h:94
static constexpr DlColor kCornflowerBlue()
Definition dl_color.h:84
static constexpr DlColor kDarkGreen()
Definition dl_color.h:93
static constexpr DlColor kRed()
Definition dl_color.h:71
static constexpr DlColor kGreen()
Definition dl_color.h:72
static constexpr DlColor kOrange()
Definition dl_color.h:87
static constexpr DlColor kLimeGreen()
Definition dl_color.h:89
static constexpr DlColor kOrangeRed()
Definition dl_color.h:92
static constexpr DlColor kGreenYellow()
Definition dl_color.h:90
static constexpr Color White()
Definition color.h:264
static constexpr Color Red()
Definition color.h:272
static constexpr Color AntiqueWhite()
Definition color.h:286
static constexpr Color Green()
Definition color.h:274
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition sigma.h:48
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition round_rect.h:31
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition sigma.h:32
Scalar sigma
Definition sigma.h:33
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:618
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
Type height
Definition size.h:29
Type width
Definition size.h:28
std::shared_ptr< DlImageFilter > image_filter