| Flutter Impeller |

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
5 #include "flutter/display_list/display_list.h"
6 #include "flutter/display_list/dl_blend_mode.h"
7 #include "flutter/display_list/dl_builder.h"
8 #include "flutter/display_list/dl_color.h"
9 #include "flutter/display_list/dl_paint.h"
10 #include "flutter/display_list/dl_sampling_options.h"
11 #include "flutter/display_list/dl_tile_mode.h"
12 #include "flutter/display_list/effects/dl_color_filter.h"
13 #include "flutter/display_list/effects/dl_color_source.h"
14 #include "flutter/display_list/effects/dl_image_filter.h"
15 #include "flutter/display_list/effects/dl_mask_filter.h"
16 #include "flutter/display_list/geometry/dl_path_builder.h"
17 #include "flutter/impeller/display_list/aiks_unittests.h"
18
19 #include "gmock/gmock.h"
20 #include "impeller/display_list/dl_dispatcher.h"
21 #include "impeller/display_list/dl_image_impeller.h"
22 #include "impeller/playground/widgets.h"
23 #include "impeller/renderer/testing/mocks.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
31 namespace impeller {
32 namespace testing {
33
34 using namespace flutter;
35
36 // The shapes of these ovals should appear equal. They are demonstrating the
37 // difference between the fast pass and not.
38 TEST_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(),
44 DlColor::kRed()};
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
62 sk_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);
80 paint.setColor(DlColor::kWhite());
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
103 TEST_P(AiksTest, GradientOvalStrokeMaskBlur) {
104 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
105 GetContentScale(), /*sigma=*/10, DlBlurStyle::kNormal)));
106 }
107
108 TEST_P(AiksTest, GradientOvalStrokeMaskBlurSigmaZero) {
109 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
110 GetContentScale(), /*sigma=*/0, DlBlurStyle::kNormal)));
111 }
112
113 TEST_P(AiksTest, GradientOvalStrokeMaskBlurOuter) {
114 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
115 GetContentScale(), /*sigma=*/10, DlBlurStyle::kOuter)));
116 }
117
118 TEST_P(AiksTest, GradientOvalStrokeMaskBlurInner) {
119 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
120 GetContentScale(), /*sigma=*/10, DlBlurStyle::kInner)));
121 }
122
123 TEST_P(AiksTest, GradientOvalStrokeMaskBlurSolid) {
124 ASSERT_TRUE(OpenPlaygroundHere(DoGradientOvalStrokeMaskBlur(
125 GetContentScale(), /*sigma=*/10, DlBlurStyle::kSolid)));
126 }
127
128 TEST_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);
143 DlRoundRect rrect = DlRoundRect::MakeRectXY(
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
152 TEST_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
164 TEST_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
183 TEST_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
204 TEST_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;
212 paint.setColor(DlColor::kCornflowerBlue());
213 builder.DrawCircle(DlPoint(100, 100), 50, paint);
214
215 paint.setColor(DlColor::kGreenYellow());
216 builder.DrawCircle(DlPoint(300, 200), 100, paint);
217
218 paint.setColor(DlColor::kDarkMagenta());
219 builder.DrawCircle(DlPoint(140, 170), 75, paint);
220
221 paint.setColor(DlColor::kOrangeRed());
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
241 TEST_P(AiksTest, CanRenderBackdropBlur) {
242 DisplayListBuilder builder;
243
244 DlPaint paint;
245 paint.setColor(DlColor::kCornflowerBlue());
246 builder.DrawCircle(DlPoint(100, 100), 50, paint);
247
248 paint.setColor(DlColor::kGreenYellow());
249 builder.DrawCircle(DlPoint(300, 200), 100, paint);
250
251 paint.setColor(DlColor::kDarkMagenta());
252 builder.DrawCircle(DlPoint(140, 170), 75, paint);
253
254 paint.setColor(DlColor::kOrangeRed());
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
270 TEST_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
295 TEST_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++) {
305 DlRoundRect rrect = DlRoundRect::MakeRectXY(
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
322 TEST_P(AiksTest,
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++) {
333 DlRoundRect rrect = DlRoundRect::MakeRectXY(
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
351 TEST_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
369 TEST_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
382 TEST_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 =
398 DlImageFilter::MakeColorFilter(DlColorFilter::MakeMatrix(matrix));
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
407 TEST_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 =
423 DlImageFilter::MakeColorFilter(DlColorFilter::MakeMatrix(matrix));
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
432 TEST_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
456 TEST_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
473 TEST_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
488 TEST_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
511 TEST_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
524 TEST_P(AiksTest, MaskBlurOnZeroDimensionIsSkippedWideGamut) {
525 // Making sure this test is run on a wide gamut enabled backend
526 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
527 PixelFormat::kB10G10R10A10XR);
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
546 struct MaskBlurTestConfig {
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
555 static 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(
566 DlColor::RGBA(Color::AntiqueWhite().red, Color::AntiqueWhite().green,
567 Color::AntiqueWhite().blue, Color::AntiqueWhite().alpha));
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));
599 DlRoundRect rrect = DlRoundRect::MakeRectXY(
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
636 static 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
685 MASK_BLUR_VARIANT_TEST(NormalTranslucentZeroSigma)
686 MASK_BLUR_VARIANT_TEST(NormalTranslucent)
687 MASK_BLUR_VARIANT_TEST(SolidTranslucent)
688 MASK_BLUR_VARIANT_TEST(SolidOpaque)
689 MASK_BLUR_VARIANT_TEST(SolidTranslucentWithFilters)
690 MASK_BLUR_VARIANT_TEST(SolidTranslucentExclusionBlend)
691 MASK_BLUR_VARIANT_TEST(InnerTranslucent)
692 MASK_BLUR_VARIANT_TEST(InnerTranslucentWithBlurImageFilter)
693 MASK_BLUR_VARIANT_TEST(OuterTranslucent)
694 MASK_BLUR_VARIANT_TEST(OuterOpaqueWithBlurImageFilter)
695
696 #undef MASK_BLUR_VARIANT_TEST
697
698 TEST_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
725 TEST_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
752 TEST_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
779 TEST_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
808 TEST_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
829 paint.setColorSource(DlColorSource::MakeImage(
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
843 TEST_P(AiksTest, GaussianBlurAtPeripheryVertical) {
844 DisplayListBuilder builder;
845
846 DlPaint paint;
847 builder.Scale(GetContentScale().x, GetContentScale().y);
848
849 paint.setColor(DlColor::kLimeGreen());
850 DlRoundRect rrect = DlRoundRect::MakeRectXY(
851 DlRect::MakeLTRB(0, 0, GetWindowSize().width, 100), 10, 10);
852 builder.DrawRoundRect(rrect, paint);
853
854 paint.setColor(DlColor::kMagenta());
855 rrect = DlRoundRect::MakeRectXY(
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
871 TEST_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;
883 paint.setColor(DlColor::kMagenta());
884
885 DlRoundRect rrect = DlRoundRect::MakeRectXY(
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
900 TEST_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
948 TEST_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{};
962 paint.setColorSource(DlColorSource::MakeLinear(
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
986 TEST_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{};
999 paint.setColorSource(DlColorSource::MakeLinear(
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
1022 TEST_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{};
1035 paint.setColorSource(DlColorSource::MakeLinear(
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
1058 TEST_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
1091 TEST_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
1146 TEST_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.
1168 TEST_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
1205 TEST_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
1246 TEST_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;
1283 paint.setColor(DlColor::kDarkGreen());
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
1309 TEST_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;
1320 paint.setColor(DlColor::kChartreuse());
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
1334 TEST_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
1357 TEST_P(AiksTest,
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 }
1373 DlRoundRect rrect = DlRoundRect::MakeRectXY(
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
1393 TEST_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
1421 TEST_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;
1432 paint.setColor(DlColor::kCornflowerBlue());
1433 builder.DrawCircle(DlPoint(100 + offset, 100), 50, paint);
1434 paint.setColor(DlColor::kGreenYellow());
1435 builder.DrawCircle(DlPoint(300, 200 + offset), 100, paint);
1436 paint.setColor(DlColor::kDarkMagenta());
1437 builder.DrawCircle(DlPoint(140, 170), 75, paint);
1438 paint.setColor(DlColor::kOrangeRed());
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
MASK_BLUR_VARIANT_TEST
#define MASK_BLUR_VARIANT_TEST(config)
Definition: aiks_dl_blur_unittests.cc:679
aiks_unittests.h
impeller::AiksContext
Definition: aiks_context.h:20
impeller::AiksPlayground
Definition: aiks_playground.h:16
impeller::AiksPlayground::ImGuiBegin
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
Definition: aiks_playground.cc:30
impeller::DlImageImpeller::Make
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
Definition: dl_image_impeller.cc:23
impeller::Playground::GetContentScale
Point GetContentScale() const
Definition: playground.cc:189
dl_dispatcher.h
x
int32_t x
Definition: dl_golden_unittests.cc:458
dl_image_impeller.h
flutter
Definition: dl_golden_blur_unittests.cc:16
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller::testing::DoGradientOvalStrokeMaskBlur
sk_sp< flutter::DisplayList > DoGradientOvalStrokeMaskBlur(Vector2 content_Scale, Scalar sigma, DlBlurStyle style)
Definition: aiks_dl_blur_unittests.cc:62
impeller::testing::MaskBlurVariantTest
static sk_sp< DisplayList > MaskBlurVariantTest(const AiksTest &test_context, const MaskBlurTestConfig &config)
Definition: aiks_dl_blur_unittests.cc:555
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:59
impeller::testing::kPaintVariations
static const std::map< std::string, MaskBlurTestConfig > kPaintVariations
Definition: aiks_dl_blur_unittests.cc:636
impeller
Definition: allocation.cc:12
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::DlRect
flutter::DlRect DlRect
Definition: dl_dispatcher.h:25
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::DrawPlaygroundPoint
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition: widgets.cc:11
impeller::DrawPlaygroundLine
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition: widgets.cc:51
impeller::DisplayListToTexture
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips, std::optional< PixelFormat > target_pixel_format)
Render the provided display list to a texture with the given size.
Definition: dl_dispatcher.cc:1220
impeller::DlRoundRect
flutter::DlRoundRect DlRoundRect
Definition: dl_dispatcher.h:27
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::PixelFormat::kB10G10R10A10XR
@ kB10G10R10A10XR
impeller::DlPoint
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
impeller::DlPath
flutter::DlPath DlPath
Definition: dl_dispatcher.h:29
impeller::ISize
ISize64 ISize
Definition: size.h:162
impeller::Color::White
static constexpr Color White()
Definition: color.h:264
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:272
impeller::Color::AntiqueWhite
static constexpr Color AntiqueWhite()
Definition: color.h:286
impeller::Color::Green
static constexpr Color Green()
Definition: color.h:274
impeller::Degrees
Definition: scalar.h:66
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::PlaygroundPoint
Definition: widgets.h:21
impeller::Radius
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition: sigma.h:48
impeller::Sigma
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition: sigma.h:32
impeller::Sigma::sigma
Scalar sigma
Definition: sigma.h:33
impeller::TPoint< Scalar >
impeller::TPoint::Rotate
constexpr TPoint Rotate(const Radians &angle) const
Definition: point.h:226
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TRect< Scalar >
impeller::TRect::Expand
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
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:357
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:353
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:351
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:327
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:355
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::TRect::Shift
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition: rect.h:602
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TSize
Definition: size.h:25
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TSize::width
Type width
Definition: size.h:28
impeller::testing::MaskBlurTestConfig
Definition: aiks_dl_blur_unittests.cc:546
impeller::testing::MaskBlurTestConfig::blend_mode
DlBlendMode blend_mode
Definition: aiks_dl_blur_unittests.cc:552
impeller::testing::MaskBlurTestConfig::invert_colors
bool invert_colors
Definition: aiks_dl_blur_unittests.cc:551
impeller::testing::MaskBlurTestConfig::alpha
Scalar alpha
Definition: aiks_dl_blur_unittests.cc:549
impeller::testing::MaskBlurTestConfig::style
DlBlurStyle style
Definition: aiks_dl_blur_unittests.cc:547
impeller::testing::MaskBlurTestConfig::image_filter
std::shared_ptr< DlImageFilter > image_filter
Definition: aiks_dl_blur_unittests.cc:550
impeller::testing::MaskBlurTestConfig::sigma
Scalar sigma
Definition: aiks_dl_blur_unittests.cc:548
widgets.h