Flutter Impeller
aiks_dl_gradient_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 "display_list/display_list.h"
6 #include "display_list/dl_blend_mode.h"
7 #include "display_list/dl_tile_mode.h"
8 #include "display_list/effects/dl_color_filter.h"
9 #include "display_list/effects/dl_color_source.h"
10 #include "display_list/effects/dl_mask_filter.h"
12 
13 #include "flutter/display_list/dl_builder.h"
14 #include "flutter/display_list/dl_color.h"
15 #include "flutter/display_list/dl_paint.h"
16 #include "flutter/testing/testing.h"
18 #include "include/core/SkPath.h"
19 #include "include/core/SkRRect.h"
20 #include "include/core/SkRect.h"
21 
22 using namespace flutter;
23 ////////////////////////////////////////////////////////////////////////////////
24 // This is for tests of Canvas that are interested the results of rendering
25 // gradients.
26 ////////////////////////////////////////////////////////////////////////////////
27 
28 namespace impeller {
29 namespace testing {
30 
31 namespace {
32 
33 /// Test body for linear gradient tile mode tests (ex.
34 /// CanRenderLinearGradientClamp).
35 void CanRenderLinearGradient(AiksTest* aiks_test, DlTileMode tile_mode) {
36  DisplayListBuilder builder;
37  Point scale = aiks_test->GetContentScale();
38  builder.Scale(scale.x, scale.y);
39  DlPaint paint;
40  builder.Translate(100.0f, 0);
41 
42  std::vector<DlColor> colors = {
43  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
44  DlColor(Color{0.1294, 0.5882, 0.9529, 0.0}.ToARGB())};
45  std::vector<Scalar> stops = {0.0, 1.0};
46 
47  auto gradient = DlColorSource::MakeLinear(
48  {0, 0}, {200, 200}, 2, colors.data(), stops.data(), tile_mode);
49  paint.setColorSource(gradient);
50  paint.setColor(DlColor::kWhite());
51  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
52  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
53 }
54 
55 Matrix ToMatrix(const SkMatrix& m) {
56  return Matrix{
57  // clang-format off
58  m[0], m[3], 0, m[6],
59  m[1], m[4], 0, m[7],
60  0, 0, 1, 0,
61  m[2], m[5], 0, m[8],
62  // clang-format on
63  };
64 }
65 } // namespace
66 
67 TEST_P(AiksTest, CanRenderLinearGradientClamp) {
68  CanRenderLinearGradient(this, DlTileMode::kClamp);
69 }
70 TEST_P(AiksTest, CanRenderLinearGradientRepeat) {
71  CanRenderLinearGradient(this, DlTileMode::kRepeat);
72 }
73 TEST_P(AiksTest, CanRenderLinearGradientMirror) {
74  CanRenderLinearGradient(this, DlTileMode::kMirror);
75 }
76 TEST_P(AiksTest, CanRenderLinearGradientDecal) {
77  CanRenderLinearGradient(this, DlTileMode::kDecal);
78 }
79 
80 TEST_P(AiksTest, CanRenderLinearGradientDecalWithColorFilter) {
81  DisplayListBuilder builder;
82  Point scale = GetContentScale();
83  builder.Scale(scale.x, scale.y);
84  DlPaint paint;
85  builder.Translate(100.0f, 0);
86 
87  std::vector<DlColor> colors = {
88  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
89  DlColor(Color{0.1294, 0.5882, 0.9529, 0.0}.ToARGB())};
90  std::vector<Scalar> stops = {0.0, 1.0};
91 
92  paint.setColorSource(DlColorSource::MakeLinear(
93  {0, 0}, {200, 200}, 2, colors.data(), stops.data(), DlTileMode::kDecal));
94  // Overlay the gradient with 25% green. This should appear as the entire
95  // rectangle being drawn with 25% green, including the border area outside the
96  // decal gradient.
97  paint.setColorFilter(DlBlendColorFilter::Make(DlColor::kGreen().withAlpha(64),
98  DlBlendMode::kSrcOver));
99  paint.setColor(DlColor::kWhite());
100  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
101  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
102 }
103 
105  DisplayListBuilder builder;
106  DlPaint paint;
107  builder.Translate(100.0, 100.0);
108 
109  // 0xffcccccc --> 0xff333333, taken from
110  // https://github.com/flutter/flutter/issues/118073#issue-1521699748
111  std::vector<DlColor> colors = {DlColor(0xFFCCCCCC), DlColor(0xFF333333)};
112  std::vector<Scalar> stops = {0.0, 1.0};
113 
114  paint.setColorSource(DlColorSource::MakeLinear(
115  {0, 0}, {800, 500}, 2, colors.data(), stops.data(), DlTileMode::kClamp));
116  builder.DrawRect(SkRect::MakeXYWH(0, 0, 800, 500), paint);
117  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
118 }
119 
120 TEST_P(AiksTest, CanRenderLinearGradientWithDitheringEnabled) {
122 }
123 
125  DisplayListBuilder builder;
126  DlPaint paint;
127  builder.Translate(100.0, 100.0);
128 
129  // #FFF -> #000
130  std::vector<DlColor> colors = {DlColor(Color{1.0, 1.0, 1.0, 1.0}.ToARGB()),
131  DlColor(Color{0.0, 0.0, 0.0, 1.0}.ToARGB())};
132  std::vector<Scalar> stops = {0.0, 1.0};
133 
134  paint.setColorSource(DlColorSource::MakeRadial(
135  {600, 600}, 600, 2, colors.data(), stops.data(), DlTileMode::kClamp));
136  builder.DrawRect(SkRect::MakeXYWH(0, 0, 1200, 1200), paint);
137  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
138 }
139 
140 TEST_P(AiksTest, CanRenderRadialGradientWithDitheringEnabled) {
142 }
143 
145  DisplayListBuilder builder;
146  builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
147  DlPaint paint;
148  builder.Translate(100.0, 100.0);
149 
150  // #FFF -> #000
151  std::vector<DlColor> colors = {DlColor(Color{1.0, 1.0, 1.0, 1.0}.ToARGB()),
152  DlColor(Color{0.0, 0.0, 0.0, 1.0}.ToARGB())};
153  std::vector<Scalar> stops = {0.0, 1.0};
154 
155  paint.setColorSource(DlColorSource::MakeSweep(
156  {100, 100}, /*start=*/45, /*end=*/135, 2, colors.data(), stops.data(),
157  DlTileMode::kMirror));
158 
159  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
160  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
161 }
162 
163 TEST_P(AiksTest, CanRenderSweepGradientWithDitheringEnabled) {
165 }
166 
168  DisplayListBuilder builder;
169  builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
170  DlPaint paint;
171  builder.Translate(100.0, 100.0);
172 
173  // #FFF -> #000
174  std::vector<DlColor> colors = {DlColor(Color{1.0, 1.0, 1.0, 1.0}.ToARGB()),
175  DlColor(Color{0.0, 0.0, 0.0, 1.0}.ToARGB())};
176  std::vector<Scalar> stops = {0.0, 1.0};
177 
178  paint.setColorSource(DlColorSource::MakeConical({0, 1}, 0, {100, 100}, 100, 2,
179  colors.data(), stops.data(),
180  DlTileMode::kMirror));
181 
182  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
183  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
184 }
185 
186 TEST_P(AiksTest, CanRenderConicalGradientWithDitheringEnabled) {
188 }
189 
190 namespace {
191 void CanRenderLinearGradientWithOverlappingStops(AiksTest* aiks_test,
192  DlTileMode tile_mode) {
193  DisplayListBuilder builder;
194  DlPaint paint;
195  builder.Translate(100.0, 100.0);
196 
197  std::vector<DlColor> colors = {
198  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
199  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
200  DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB()),
201  DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
202  std::vector<Scalar> stops = {0.0, 0.5, 0.5, 1.0};
203 
204  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {500, 500},
205  stops.size(), colors.data(),
206  stops.data(), tile_mode));
207 
208  paint.setColor(DlColor::kWhite());
209  builder.DrawRect(SkRect::MakeXYWH(0, 0, 500, 500), paint);
210  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
211 }
212 } // namespace
213 
214 // Only clamp is necessary. All tile modes are the same output.
215 TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) {
216  CanRenderLinearGradientWithOverlappingStops(this, DlTileMode::kClamp);
217 }
218 
219 namespace {
220 void CanRenderLinearGradientManyColors(AiksTest* aiks_test,
221  DlTileMode tile_mode) {
222  DisplayListBuilder builder;
223  builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
224  DlPaint paint;
225  builder.Translate(100, 100);
226 
227  std::vector<DlColor> colors = {
228  DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
229  DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
230  DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
231  DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
232  DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
233  DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
234  DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
235  std::vector<Scalar> stops = {
236  0.0,
237  (1.0 / 6.0) * 1,
238  (1.0 / 6.0) * 2,
239  (1.0 / 6.0) * 3,
240  (1.0 / 6.0) * 4,
241  (1.0 / 6.0) * 5,
242  1.0,
243  };
244 
245  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {200, 200},
246  stops.size(), colors.data(),
247  stops.data(), tile_mode));
248 
249  paint.setColor(DlColor::kWhite());
250  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
251  builder.Restore();
252  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
253 }
254 } // namespace
255 
256 TEST_P(AiksTest, CanRenderLinearGradientManyColorsClamp) {
257  CanRenderLinearGradientManyColors(this, DlTileMode::kClamp);
258 }
259 TEST_P(AiksTest, CanRenderLinearGradientManyColorsRepeat) {
260  CanRenderLinearGradientManyColors(this, DlTileMode::kRepeat);
261 }
262 TEST_P(AiksTest, CanRenderLinearGradientManyColorsMirror) {
263  CanRenderLinearGradientManyColors(this, DlTileMode::kMirror);
264 }
265 TEST_P(AiksTest, CanRenderLinearGradientManyColorsDecal) {
266  CanRenderLinearGradientManyColors(this, DlTileMode::kDecal);
267 }
268 
269 namespace {
270 void CanRenderLinearGradientWayManyColors(AiksTest* aiks_test,
271  DlTileMode tile_mode) {
272  DisplayListBuilder builder;
273  DlPaint paint;
274  builder.Translate(100.0, 100.0);
275  auto color = DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB());
276  std::vector<DlColor> colors;
277  std::vector<Scalar> stops;
278  auto current_stop = 0.0;
279  for (int i = 0; i < 2000; i++) {
280  colors.push_back(color);
281  stops.push_back(current_stop);
282  current_stop += 1 / 2000.0;
283  }
284  stops[2000 - 1] = 1.0;
285 
286  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {200, 200},
287  stops.size(), colors.data(),
288  stops.data(), tile_mode));
289 
290  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
291  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
292 }
293 } // namespace
294 
295 // Only test clamp on purpose since they all look the same.
296 TEST_P(AiksTest, CanRenderLinearGradientWayManyColorsClamp) {
297  CanRenderLinearGradientWayManyColors(this, DlTileMode::kClamp);
298 }
299 
300 TEST_P(AiksTest, CanRenderLinearGradientManyColorsUnevenStops) {
301  auto callback = [&]() -> sk_sp<DisplayList> {
302  const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
303  const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
304  DlTileMode::kMirror, DlTileMode::kDecal};
305 
306  static int selected_tile_mode = 0;
307  static Matrix matrix;
308  if (AiksTest::ImGuiBegin("Controls", nullptr,
309  ImGuiWindowFlags_AlwaysAutoResize)) {
310  ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
311  sizeof(tile_mode_names) / sizeof(char*));
312  std::string label = "##1";
313  for (int i = 0; i < 4; i++) {
314  ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
315  &(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
316  label[2]++;
317  }
318  ImGui::End();
319  }
320 
321  DisplayListBuilder builder;
322  DlPaint paint;
323  builder.Translate(100.0, 100.0);
324  auto tile_mode = tile_modes[selected_tile_mode];
325 
326  std::vector<DlColor> colors = {
327  DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
328  DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
329  DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
330  DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
331  DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
332  DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
333  DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
334  std::vector<Scalar> stops = {
335  0.0, 2.0 / 62.0, 4.0 / 62.0, 8.0 / 62.0, 16.0 / 62.0, 32.0 / 62.0, 1.0,
336  };
337 
338  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {200, 200},
339  stops.size(), colors.data(),
340  stops.data(), tile_mode));
341 
342  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
343  return builder.Build();
344  };
345  ASSERT_TRUE(OpenPlaygroundHere(callback));
346 }
347 
348 TEST_P(AiksTest, CanRenderLinearGradientMaskBlur) {
349  DisplayListBuilder builder;
350 
351  std::vector<DlColor> colors = {
352  DlColor::kRed(), DlColor::kWhite(), DlColor::kRed(), DlColor::kWhite(),
353  DlColor::kRed(), DlColor::kWhite(), DlColor::kRed(), DlColor::kWhite(),
354  DlColor::kRed(), DlColor::kWhite(), DlColor::kRed()};
355  std::vector<Scalar> stops = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
356  0.6, 0.7, 0.8, 0.9, 1.0};
357 
358  DlPaint paint;
359  paint.setColor(DlColor::kWhite());
360  paint.setColorSource(DlColorSource::MakeLinear(
361  {200, 200}, {400, 400}, stops.size(), colors.data(), stops.data(),
362  DlTileMode::kClamp));
363  paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 20));
364 
365  builder.DrawCircle({300, 300}, 200, paint);
366  builder.DrawRect(SkRect::MakeLTRB(100, 300, 500, 600), paint);
367 
368  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
369 }
370 
371 TEST_P(AiksTest, CanRenderRadialGradient) {
372  auto callback = [&]() -> sk_sp<DisplayList> {
373  const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
374  const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
375  DlTileMode::kMirror, DlTileMode::kDecal};
376 
377  static int selected_tile_mode = 0;
378  static Matrix matrix;
379  if (AiksTest::ImGuiBegin("Controls", nullptr,
380  ImGuiWindowFlags_AlwaysAutoResize)) {
381  ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
382  sizeof(tile_mode_names) / sizeof(char*));
383  std::string label = "##1";
384  for (int i = 0; i < 4; i++) {
385  ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
386  &(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
387  label[2]++;
388  }
389  ImGui::End();
390  }
391 
392  DisplayListBuilder builder;
393  DlPaint paint;
394  builder.Translate(100.0, 100.0);
395  auto tile_mode = tile_modes[selected_tile_mode];
396 
397  std::vector<DlColor> colors = {
398  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
399  DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
400  std::vector<Scalar> stops = {0.0, 1.0};
401 
402  paint.setColorSource(DlColorSource::MakeRadial(
403  {100, 100}, 100, 2, colors.data(), stops.data(), tile_mode));
404 
405  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
406  return builder.Build();
407  };
408  ASSERT_TRUE(OpenPlaygroundHere(callback));
409 }
410 
411 TEST_P(AiksTest, CanRenderRadialGradientManyColors) {
412  auto callback = [&]() -> sk_sp<DisplayList> {
413  const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
414  const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
415  DlTileMode::kMirror, DlTileMode::kDecal};
416 
417  static int selected_tile_mode = 0;
418  static Matrix matrix = {
419  1, 0, 0, 0, //
420  0, 1, 0, 0, //
421  0, 0, 1, 0, //
422  0, 0, 0, 1 //
423  };
424  if (AiksTest::ImGuiBegin("Controls", nullptr,
425  ImGuiWindowFlags_AlwaysAutoResize)) {
426  ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
427  sizeof(tile_mode_names) / sizeof(char*));
428  std::string label = "##1";
429  for (int i = 0; i < 4; i++) {
430  ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
431  &(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
432  label[2]++;
433  }
434  ImGui::End();
435  }
436 
437  DisplayListBuilder builder;
438  DlPaint paint;
439  builder.Translate(100.0, 100.0);
440  auto tile_mode = tile_modes[selected_tile_mode];
441 
442  std::vector<DlColor> colors = {
443  DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
444  DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
445  DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
446  DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
447  DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
448  DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
449  DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
450  std::vector<Scalar> stops = {
451  0.0,
452  (1.0 / 6.0) * 1,
453  (1.0 / 6.0) * 2,
454  (1.0 / 6.0) * 3,
455  (1.0 / 6.0) * 4,
456  (1.0 / 6.0) * 5,
457  1.0,
458  };
459 
460  paint.setColorSource(DlColorSource::MakeRadial(
461  {100, 100}, 100, stops.size(), colors.data(), stops.data(), tile_mode));
462 
463  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
464  return builder.Build();
465  };
466  ASSERT_TRUE(OpenPlaygroundHere(callback));
467 }
468 
469 namespace {
470 void CanRenderSweepGradient(AiksTest* aiks_test, DlTileMode tile_mode) {
471  DisplayListBuilder builder;
472  builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
473  DlPaint paint;
474  builder.Translate(100, 100);
475 
476  std::vector<DlColor> colors = {
477  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
478  DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
479  std::vector<Scalar> stops = {0.0, 1.0};
480 
481  paint.setColorSource(DlColorSource::MakeSweep(
482  {100, 100}, /*start=*/45, /*end=*/135, /*stop_count=*/2, colors.data(),
483  stops.data(), tile_mode));
484 
485  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
486  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
487 }
488 } // namespace
489 
490 TEST_P(AiksTest, CanRenderSweepGradientClamp) {
491  CanRenderSweepGradient(this, DlTileMode::kClamp);
492 }
493 TEST_P(AiksTest, CanRenderSweepGradientRepeat) {
494  CanRenderSweepGradient(this, DlTileMode::kRepeat);
495 }
496 TEST_P(AiksTest, CanRenderSweepGradientMirror) {
497  CanRenderSweepGradient(this, DlTileMode::kMirror);
498 }
499 TEST_P(AiksTest, CanRenderSweepGradientDecal) {
500  CanRenderSweepGradient(this, DlTileMode::kDecal);
501 }
502 
503 namespace {
504 void CanRenderSweepGradientManyColors(AiksTest* aiks_test,
505  DlTileMode tile_mode) {
506  DisplayListBuilder builder;
507  DlPaint paint;
508  builder.Translate(100.0, 100.0);
509 
510  std::vector<DlColor> colors = {
511  DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
512  DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
513  DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
514  DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
515  DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
516  DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
517  DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
518  std::vector<Scalar> stops = {
519  0.0,
520  (1.0 / 6.0) * 1,
521  (1.0 / 6.0) * 2,
522  (1.0 / 6.0) * 3,
523  (1.0 / 6.0) * 4,
524  (1.0 / 6.0) * 5,
525  1.0,
526  };
527 
528  paint.setColorSource(DlColorSource::MakeSweep({100, 100}, 45, 135,
529  stops.size(), colors.data(),
530  stops.data(), tile_mode));
531 
532  builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
533  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
534 }
535 } // namespace
536 
537 TEST_P(AiksTest, CanRenderSweepGradientManyColorsClamp) {
538  CanRenderSweepGradientManyColors(this, DlTileMode::kClamp);
539 }
540 TEST_P(AiksTest, CanRenderSweepGradientManyColorsRepeat) {
541  CanRenderSweepGradientManyColors(this, DlTileMode::kRepeat);
542 }
543 TEST_P(AiksTest, CanRenderSweepGradientManyColorsMirror) {
544  CanRenderSweepGradientManyColors(this, DlTileMode::kMirror);
545 }
546 TEST_P(AiksTest, CanRenderSweepGradientManyColorsDecal) {
547  CanRenderSweepGradientManyColors(this, DlTileMode::kDecal);
548 }
549 
550 TEST_P(AiksTest, CanRenderConicalGradient) {
551  Scalar size = 256;
552  DisplayListBuilder builder;
553  DlPaint paint;
554  paint.setColor(DlColor::kWhite());
555  builder.DrawRect(SkRect::MakeXYWH(0, 0, size * 3, size * 3), paint);
556  std::vector<DlColor> colors = {
557  DlColor(Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF).ToARGB()),
558  DlColor(Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF).ToARGB()),
559  DlColor(Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF).ToARGB()),
560  DlColor(Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF).ToARGB())};
561  std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
562  std::array<std::tuple<SkPoint, float, SkPoint, float>, 8> array{
563  std::make_tuple(SkPoint::Make(size / 2.f, size / 2.f), 0.f,
564  SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
565  std::make_tuple(SkPoint::Make(size / 2.f, size / 2.f), size / 4.f,
566  SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
567  std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), 0.f,
568  SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
569  std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 2.f,
570  SkPoint::Make(size / 2.f, size / 2.f), 0),
571  std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 4.f,
572  SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
573  std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 16.f,
574  SkPoint::Make(size / 2.f, size / 2.f), size / 8.f),
575  std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 8.f,
576  SkPoint::Make(size / 2.f, size / 2.f), size / 16.f),
577  std::make_tuple(SkPoint::Make(size / 8.f, size / 8.f), size / 8.f,
578  SkPoint::Make(size / 2.f, size / 2.f), size / 8.f),
579  };
580  for (int i = 0; i < 8; i++) {
581  builder.Save();
582  builder.Translate((i % 3) * size, i / 3 * size);
583  paint.setColorSource(DlColorSource::MakeConical(
584  std::get<2>(array[i]), std::get<3>(array[i]), std::get<0>(array[i]),
585  std::get<1>(array[i]), stops.size(), colors.data(), stops.data(),
586  DlTileMode::kClamp));
587  builder.DrawRect(SkRect::MakeXYWH(0, 0, size, size), paint);
588  builder.Restore();
589  }
590  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
591 }
592 
593 TEST_P(AiksTest, CanRenderGradientDecalWithBackground) {
594  std::vector<DlColor> colors = {
595  DlColor(Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF).ToARGB()),
596  DlColor(Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF).ToARGB()),
597  DlColor(Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF).ToARGB()),
598  DlColor(Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF).ToARGB())};
599  std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
600 
601  std::array<std::shared_ptr<DlColorSource>, 3> color_sources = {
602  DlColorSource::MakeLinear({0, 0}, {100, 100}, stops.size(), colors.data(),
603  stops.data(), DlTileMode::kDecal),
604  DlColorSource::MakeRadial({100, 100}, 100, stops.size(), colors.data(),
605  stops.data(), DlTileMode::kDecal),
606  DlColorSource::MakeSweep({100, 100}, 45, 135, stops.size(), colors.data(),
607  stops.data(), DlTileMode::kDecal),
608  };
609 
610  DisplayListBuilder builder;
611  DlPaint paint;
612  paint.setColor(DlColor::kWhite());
613  builder.DrawRect(SkRect::MakeLTRB(0, 0, 605, 205), paint);
614  for (int i = 0; i < 3; i++) {
615  builder.Save();
616  builder.Translate(i * 200.0f, 0);
617  paint.setColorSource(color_sources[i]);
618  builder.DrawRect(SkRect::MakeLTRB(0, 0, 200, 200), paint);
619  builder.Restore();
620  }
621  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
622 }
623 
624 TEST_P(AiksTest, GradientStrokesRenderCorrectly) {
625  // Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
626  auto callback = [&]() -> sk_sp<DisplayList> {
627  static float scale = 3;
628  static bool add_circle_clip = true;
629  const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
630  const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
631  DlTileMode::kMirror, DlTileMode::kDecal};
632  static int selected_tile_mode = 0;
633  static float alpha = 1;
634 
635  if (AiksTest::ImGuiBegin("Controls", nullptr,
636  ImGuiWindowFlags_AlwaysAutoResize)) {
637  ImGui::SliderFloat("Scale", &scale, 0, 6);
638  ImGui::Checkbox("Circle clip", &add_circle_clip);
639  ImGui::SliderFloat("Alpha", &alpha, 0, 1);
640  ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
641  sizeof(tile_mode_names) / sizeof(char*));
642  ImGui::End();
643  }
644 
645  DisplayListBuilder builder;
646  builder.Scale(GetContentScale().x, GetContentScale().y);
647  DlPaint paint;
648  paint.setColor(DlColor::kWhite());
649  builder.DrawPaint(paint);
650 
651  paint.setDrawStyle(DlDrawStyle::kStroke);
652  paint.setColor(DlColor::kWhite().withAlpha(alpha * 255));
653  paint.setStrokeWidth(10);
654  auto tile_mode = tile_modes[selected_tile_mode];
655 
656  std::vector<DlColor> colors = {
657  DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
658  DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
659  std::vector<Scalar> stops = {0.0, 1.0};
660 
661  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {50, 50},
662  stops.size(), colors.data(),
663  stops.data(), tile_mode));
664 
665  SkPath path;
666  path.moveTo(20, 20);
667  path.quadTo({60, 20}, {60, 60});
668  path.close();
669  path.moveTo(60, 20);
670  path.quadTo({60, 60}, {20, 60});
671 
672  builder.Scale(scale, scale);
673 
674  if (add_circle_clip) {
675  static PlaygroundPoint circle_clip_point_a(Point(60, 300), 20,
676  Color::Red());
677  static PlaygroundPoint circle_clip_point_b(Point(600, 300), 20,
678  Color::Red());
679  auto [handle_a, handle_b] =
680  DrawPlaygroundLine(circle_clip_point_a, circle_clip_point_b);
681 
682  SkMatrix screen_to_canvas;
683  if (!builder.GetTransform().invert(&screen_to_canvas)) {
684  return nullptr;
685  }
686  Matrix ip_matrix = ToMatrix(screen_to_canvas);
687  Point point_a = ip_matrix * handle_a * GetContentScale();
688  Point point_b = ip_matrix * handle_b * GetContentScale();
689 
690  Point middle = (point_a + point_b) / 2;
691  auto radius = point_a.GetDistance(middle);
692  SkPath circle;
693  circle.addCircle(middle.x, middle.y, radius);
694  builder.ClipPath(circle);
695  }
696 
697  for (auto join :
698  {DlStrokeJoin::kBevel, DlStrokeJoin::kRound, DlStrokeJoin::kMiter}) {
699  paint.setStrokeJoin(join);
700  for (auto cap :
701  {DlStrokeCap::kButt, DlStrokeCap::kSquare, DlStrokeCap::kRound}) {
702  paint.setStrokeCap(cap);
703  builder.DrawPath(path, paint);
704  builder.Translate(80, 0);
705  }
706  builder.Translate(-240, 60);
707  }
708 
709  return builder.Build();
710  };
711 
712  ASSERT_TRUE(OpenPlaygroundHere(callback));
713 }
714 
715 // Draws two gradients that should look identical (except that one is an RRECT).
716 TEST_P(AiksTest, FastGradientTestHorizontal) {
717  DisplayListBuilder builder;
718  DlPaint paint;
719  builder.Translate(100.0f, 0);
720 
721  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
722  DlColor::kGreen()};
723  std::vector<Scalar> stops = {0.0, 0.1, 1.0};
724 
725  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {300, 0}, stops.size(),
726  colors.data(), stops.data(),
727  DlTileMode::kClamp));
728 
729  paint.setColor(DlColor::kWhite());
730  builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
731  builder.Translate(400, 0);
732  builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
733  paint);
734 
735  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
736 }
737 
738 // Draws two gradients that should look identical (except that one is an RRECT).
739 TEST_P(AiksTest, FastGradientTestVertical) {
740  DisplayListBuilder builder;
741  DlPaint paint;
742  builder.Translate(100.0f, 0);
743 
744  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
745  DlColor::kGreen()};
746  std::vector<Scalar> stops = {0.0, 0.1, 1.0};
747 
748  paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {0, 300}, stops.size(),
749  colors.data(), stops.data(),
750  DlTileMode::kClamp));
751 
752  paint.setColor(DlColor::kWhite());
753  builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
754  builder.Translate(400, 0);
755  builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
756  paint);
757 
758  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
759 }
760 
761 // Draws two gradients that should look identical (except that one is an RRECT).
762 TEST_P(AiksTest, FastGradientTestHorizontalReversed) {
763  DisplayListBuilder builder;
764  DlPaint paint;
765  builder.Translate(100.0f, 0);
766 
767  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
768  DlColor::kGreen()};
769  std::vector<Scalar> stops = {0.0, 0.1, 1.0};
770 
771  paint.setColorSource(DlColorSource::MakeLinear({300, 0}, {0, 0}, stops.size(),
772  colors.data(), stops.data(),
773  DlTileMode::kClamp));
774 
775  paint.setColor(DlColor::kWhite());
776  builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
777  builder.Translate(400, 0);
778  builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
779  paint);
780 
781  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
782 }
783 
784 // Draws two gradients that should look identical (except that one is an RRECT).
785 TEST_P(AiksTest, FastGradientTestVerticalReversed) {
786  DisplayListBuilder builder;
787  DlPaint paint;
788  builder.Translate(100.0f, 0);
789 
790  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
791  DlColor::kGreen()};
792  std::vector<Scalar> stops = {0.0, 0.1, 1.0};
793 
794  paint.setColorSource(DlColorSource::MakeLinear({0, 300}, {0, 0}, stops.size(),
795  colors.data(), stops.data(),
796  DlTileMode::kClamp));
797 
798  paint.setColor(DlColor::kWhite());
799  builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
800  builder.Translate(400, 0);
801  builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
802  paint);
803 
804  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
805 }
806 
807 TEST_P(AiksTest, VerifyNonOptimizedGradient) {
808  DisplayListBuilder builder;
809  DlPaint paint;
810  builder.Translate(100.0f, 0);
811 
812  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
813  DlColor::kGreen()};
814  std::vector<Scalar> stops = {0.0, 0.1, 1.0};
815 
816  // Inset the start and end point to verify that we do not apply
817  // the fast gradient condition.
818  paint.setColorSource(
819  DlColorSource::MakeLinear({0, 150}, {0, 100}, stops.size(), colors.data(),
820  stops.data(), DlTileMode::kRepeat));
821 
822  paint.setColor(DlColor::kWhite());
823  builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
824  builder.Translate(400, 0);
825  builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
826  paint);
827 
828  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
829 }
830 
831 } // namespace testing
832 } // namespace impeller
impeller::AiksPlayground
Definition: aiks_playground.h:17
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
aiks_unittests.h
impeller::testing::AiksTest
AiksPlayground AiksTest
Definition: aiks_unittests.h:17
impeller::Color
Definition: color.h:124
impeller::testing::CanRenderRadialGradientWithDithering
static void CanRenderRadialGradientWithDithering(AiksTest *aiks_test)
Definition: aiks_dl_gradient_unittests.cc:124
impeller::Color::ToARGB
constexpr uint32_t ToARGB() const
Convert to ARGB 32 bit color.
Definition: color.h:261
impeller::testing::TEST_P
TEST_P(AiksTest, VerifyNonOptimizedGradient)
Definition: aiks_dl_gradient_unittests.cc:807
impeller::Matrix::vec
Vector4 vec[4]
Definition: matrix.h:41
impeller::ToMatrix
static Matrix ToMatrix(const SkMatrix &m)
Definition: dl_dispatcher.cc:161
impeller::Point
TPoint< Scalar > Point
Definition: point.h:322
widgets.h
flutter
Definition: dl_golden_blur_unittests.cc:14
impeller::testing::CanRenderConicalGradientWithDithering
static void CanRenderConicalGradientWithDithering(AiksTest *aiks_test)
Definition: aiks_dl_gradient_unittests.cc:167
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::AiksPlayground::OpenPlaygroundHere
bool OpenPlaygroundHere(Picture picture)
Definition: aiks_playground.cc:31
impeller::Playground::GetContentScale
Point GetContentScale() const
Definition: playground.cc:192
impeller::PlaygroundPoint
Definition: widgets.h:17
impeller::testing::CanRenderLinearGradientWithDithering
static void CanRenderLinearGradientWithDithering(AiksTest *aiks_test)
Definition: aiks_dl_gradient_unittests.cc:104
impeller::TPoint< Scalar >
scale
const Scalar scale
Definition: stroke_path_geometry.cc:308
paint
const Paint & paint
Definition: color_source.cc:38
color
DlColor color
Definition: dl_golden_blur_unittests.cc:23
impeller::TPoint::GetDistance
constexpr Type GetDistance(const TPoint &p) const
Definition: point.h:200
impeller
Definition: aiks_blend_unittests.cc:18
impeller::testing::CanRenderSweepGradientWithDithering
static void CanRenderSweepGradientWithDithering(AiksTest *aiks_test)
Definition: aiks_dl_gradient_unittests.cc:144
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::DrawPlaygroundLine
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition: widgets.cc:50