| 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"
11 #include "flutter/impeller/display_list/aiks_unittests.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"
17 #include "impeller/playground/widgets.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
104 static void CanRenderLinearGradientWithDithering(AiksTest* aiks_test) {
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) {
121 CanRenderLinearGradientWithDithering(this);
122 }
123
124 static void CanRenderRadialGradientWithDithering(AiksTest* aiks_test) {
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) {
141 CanRenderRadialGradientWithDithering(this);
142 }
143
144 static void CanRenderSweepGradientWithDithering(AiksTest* aiks_test) {
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) {
164 CanRenderSweepGradientWithDithering(this);
165 }
166
167 static void CanRenderConicalGradientWithDithering(AiksTest* aiks_test) {
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) {
187 CanRenderConicalGradientWithDithering(this);
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:16
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:123
impeller::AiksPlayground::OpenPlaygroundHere
bool OpenPlaygroundHere(const AiksDlPlaygroundCallback &callback)
Definition: aiks_playground.cc:42
impeller::skia_conversions::ToMatrix
Matrix ToMatrix(const SkMatrix &m)
Definition: skia_conversions.cc:193
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:258
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::Point
TPoint< Scalar > Point
Definition: point.h:327
widgets.h
flutter
Definition: dl_golden_blur_unittests.cc:15
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::Playground::GetContentScale
Point GetContentScale() const
Definition: playground.cc:185
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:301
color
DlColor color
Definition: dl_golden_blur_unittests.cc:24
impeller::TPoint::GetDistance
constexpr Type GetDistance(const TPoint &p) const
Definition: point.h:200
impeller
Definition: allocation.cc:12
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