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