[Impeller] Move Gradient tests to display list. (flutter/engine#53345)

Migrate almost all of the gradient unittests to display list. Removes tests for disabled dithering and the dithering flag, as it has not been possible to disable dithering on gradients for months and months.

Part of https://github.com/flutter/flutter/issues/142054
This commit is contained in:
Jonah Williams 2024-06-12 18:49:57 -07:00 committed by GitHub
parent 72373a1c04
commit 673ff9c03b
11 changed files with 886 additions and 813 deletions

View File

@ -141,6 +141,7 @@
../../../flutter/impeller/compiler/switches_unittests.cc
../../../flutter/impeller/core/allocator_unittests.cc
../../../flutter/impeller/display_list/aiks_dl_clip_unittests.cc
../../../flutter/impeller/display_list/aiks_dl_gradient_unittests.cc
../../../flutter/impeller/display_list/aiks_dl_opacity_unittests.cc
../../../flutter/impeller/display_list/aiks_dl_path_unittests.cc
../../../flutter/impeller/display_list/dl_golden_unittests.cc

View File

@ -22,616 +22,6 @@
namespace impeller {
namespace testing {
namespace {
void CanRenderLinearGradient(AiksTest* aiks_test, Entity::TileMode tile_mode) {
Canvas canvas;
canvas.Scale(aiks_test->GetContentScale());
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
Color{0.1294, 0.5882, 0.9529, 0.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace
TEST_P(AiksTest, CanRenderLinearGradientClamp) {
CanRenderLinearGradient(this, Entity::TileMode::kClamp);
}
TEST_P(AiksTest, CanRenderLinearGradientRepeat) {
CanRenderLinearGradient(this, Entity::TileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderLinearGradientMirror) {
CanRenderLinearGradient(this, Entity::TileMode::kMirror);
}
TEST_P(AiksTest, CanRenderLinearGradientDecal) {
CanRenderLinearGradient(this, Entity::TileMode::kDecal);
}
TEST_P(AiksTest, CanRenderLinearGradientDecalWithColorFilter) {
Canvas canvas;
canvas.Scale(GetContentScale());
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
Color{0.1294, 0.5882, 0.9529, 0.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {200, 200}, std::move(colors), std::move(stops),
Entity::TileMode::kDecal, {});
// Overlay the gradient with 25% green. This should appear as the entire
// rectangle being drawn with 25% green, including the border area outside the
// decal gradient.
paint.color_filter = ColorFilter::MakeBlend(BlendMode::kSourceOver,
Color::Green().WithAlpha(0.25));
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
static void CanRenderLinearGradientWithDithering(AiksTest* aiks_test,
bool use_dithering) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
// 0xffcccccc --> 0xff333333, taken from
// https://github.com/flutter/flutter/issues/118073#issue-1521699748
std::vector<Color> colors = {Color{0.8, 0.8, 0.8, 1.0},
Color{0.2, 0.2, 0.2, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {800, 500}, std::move(colors), std::move(stops),
Entity::TileMode::kClamp, {});
paint.dither = use_dithering;
canvas.DrawRect(Rect::MakeXYWH(0, 0, 800, 500), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderLinearGradientWithDitheringDisabled) {
CanRenderLinearGradientWithDithering(this, false);
}
TEST_P(AiksTest, CanRenderLinearGradientWithDitheringEnabled) {
CanRenderLinearGradientWithDithering(this, true);
} // namespace
static void CanRenderRadialGradientWithDithering(AiksTest* aiks_test,
bool use_dithering) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
// #FFF -> #000
std::vector<Color> colors = {Color{1.0, 1.0, 1.0, 1.0},
Color{0.0, 0.0, 0.0, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeRadialGradient(
{600, 600}, 600, std::move(colors), std::move(stops),
Entity::TileMode::kClamp, {});
paint.dither = use_dithering;
canvas.DrawRect(Rect::MakeXYWH(0, 0, 1200, 1200), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderRadialGradientWithDitheringDisabled) {
CanRenderRadialGradientWithDithering(this, false);
}
TEST_P(AiksTest, CanRenderRadialGradientWithDitheringEnabled) {
CanRenderRadialGradientWithDithering(this, true);
}
static void CanRenderSweepGradientWithDithering(AiksTest* aiks_test,
bool use_dithering) {
Canvas canvas;
canvas.Scale(aiks_test->GetContentScale());
Paint paint;
canvas.Translate({100.0, 100.0, 0});
// #FFF -> #000
std::vector<Color> colors = {Color{1.0, 1.0, 1.0, 1.0},
Color{0.0, 0.0, 0.0, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeSweepGradient(
{100, 100}, Degrees(45), Degrees(135), std::move(colors),
std::move(stops), Entity::TileMode::kMirror, {});
paint.dither = use_dithering;
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderSweepGradientWithDitheringDisabled) {
CanRenderSweepGradientWithDithering(this, false);
}
TEST_P(AiksTest, CanRenderSweepGradientWithDitheringEnabled) {
CanRenderSweepGradientWithDithering(this, true);
}
static void CanRenderConicalGradientWithDithering(AiksTest* aiks_test,
bool use_dithering) {
Canvas canvas;
canvas.Scale(aiks_test->GetContentScale());
Paint paint;
canvas.Translate({100.0, 100.0, 0});
// #FFF -> #000
std::vector<Color> colors = {Color{1.0, 1.0, 1.0, 1.0},
Color{0.0, 0.0, 0.0, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeConicalGradient(
{100, 100}, 100, std::move(colors), std::move(stops), {0, 1}, 0,
Entity::TileMode::kMirror, {});
paint.dither = use_dithering;
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderConicalGradientWithDitheringDisabled) {
CanRenderConicalGradientWithDithering(this, false);
}
TEST_P(AiksTest, CanRenderConicalGradientWithDitheringEnabled) {
CanRenderConicalGradientWithDithering(this, true);
}
namespace {
void CanRenderLinearGradientWithOverlappingStops(AiksTest* aiks_test,
Entity::TileMode tile_mode) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
std::vector<Color> colors = {
Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.9568, 0.2627, 0.2118, 1.0},
Color{0.1294, 0.5882, 0.9529, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}};
std::vector<Scalar> stops = {0.0, 0.5, 0.5, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {500, 500}, std::move(colors), std::move(stops), tile_mode, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 500, 500), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace
// Only clamp is necessary. All tile modes are the same output.
TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) {
CanRenderLinearGradientWithOverlappingStops(this, Entity::TileMode::kClamp);
}
namespace {
void CanRenderLinearGradientManyColors(AiksTest* aiks_test,
Entity::TileMode tile_mode) {
Canvas canvas;
canvas.Scale(aiks_test->GetContentScale());
Paint paint;
canvas.Translate({100, 100, 0});
std::vector<Color> colors = {
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
std::vector<Scalar> stops = {
0.0,
(1.0 / 6.0) * 1,
(1.0 / 6.0) * 2,
(1.0 / 6.0) * 3,
(1.0 / 6.0) * 4,
(1.0 / 6.0) * 5,
1.0,
};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
canvas.Restore();
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace
TEST_P(AiksTest, CanRenderLinearGradientManyColorsClamp) {
CanRenderLinearGradientManyColors(this, Entity::TileMode::kClamp);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsRepeat) {
CanRenderLinearGradientManyColors(this, Entity::TileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsMirror) {
CanRenderLinearGradientManyColors(this, Entity::TileMode::kMirror);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsDecal) {
CanRenderLinearGradientManyColors(this, Entity::TileMode::kDecal);
}
namespace {
void CanRenderLinearGradientWayManyColors(AiksTest* aiks_test,
Entity::TileMode tile_mode) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
auto color = Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0};
std::vector<Color> colors;
std::vector<Scalar> stops;
auto current_stop = 0.0;
for (int i = 0; i < 2000; i++) {
colors.push_back(color);
stops.push_back(current_stop);
current_stop += 1 / 2000.0;
}
stops[2000 - 1] = 1.0;
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace
// Only test clamp on purpose since they all look the same.
TEST_P(AiksTest, CanRenderLinearGradientWayManyColorsClamp) {
CanRenderLinearGradientWayManyColors(this, Entity::TileMode::kClamp);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsUnevenStops) {
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const Entity::TileMode tile_modes[] = {
Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
Entity::TileMode::kMirror, Entity::TileMode::kDecal};
static int selected_tile_mode = 0;
static Matrix matrix = {
1, 0, 0, 0, //
0, 1, 0, 0, //
0, 0, 1, 0, //
0, 0, 0, 1 //
};
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 4; i++) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
label[2]++;
}
ImGui::End();
}
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<Color> colors = {
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
std::vector<Scalar> stops = {
0.0, 2.0 / 62.0, 4.0 / 62.0, 8.0 / 62.0, 16.0 / 62.0, 32.0 / 62.0, 1.0,
};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {200, 200}, std::move(colors), std::move(stops), tile_mode, {});
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
return canvas.EndRecordingAsPicture();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
TEST_P(AiksTest, CanRenderLinearGradientMaskBlur) {
Canvas canvas;
Paint paint = {
.color = Color::White(),
.color_source = ColorSource::MakeLinearGradient(
{200, 200}, {400, 400},
{Color::Red(), Color::White(), Color::Red(), Color::White(),
Color::Red(), Color::White(), Color::Red(), Color::White(),
Color::Red(), Color::White(), Color::Red()},
{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0},
Entity::TileMode::kClamp, {}),
.mask_blur_descriptor =
Paint::MaskBlurDescriptor{
.style = FilterContents::BlurStyle::kNormal,
.sigma = Sigma(20),
},
};
canvas.DrawCircle({300, 300}, 200, paint);
canvas.DrawRect(Rect::MakeLTRB(100, 300, 500, 600), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderRadialGradient) {
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const Entity::TileMode tile_modes[] = {
Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
Entity::TileMode::kMirror, Entity::TileMode::kDecal};
static int selected_tile_mode = 0;
static Matrix matrix = {
1, 0, 0, 0, //
0, 1, 0, 0, //
0, 0, 1, 0, //
0, 0, 0, 1 //
};
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 4; i++) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
label[2]++;
}
ImGui::End();
}
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
Color{0.1294, 0.5882, 0.9529, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeRadialGradient(
{100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {});
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
return canvas.EndRecordingAsPicture();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
TEST_P(AiksTest, CanRenderRadialGradientManyColors) {
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const Entity::TileMode tile_modes[] = {
Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
Entity::TileMode::kMirror, Entity::TileMode::kDecal};
static int selected_tile_mode = 0;
static Matrix matrix = {
1, 0, 0, 0, //
0, 1, 0, 0, //
0, 0, 1, 0, //
0, 0, 0, 1 //
};
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 4; i++) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
label[2]++;
}
ImGui::End();
}
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<Color> colors = {
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
std::vector<Scalar> stops = {
0.0,
(1.0 / 6.0) * 1,
(1.0 / 6.0) * 2,
(1.0 / 6.0) * 3,
(1.0 / 6.0) * 4,
(1.0 / 6.0) * 5,
1.0,
};
paint.color_source = ColorSource::MakeRadialGradient(
{100, 100}, 100, std::move(colors), std::move(stops), tile_mode, {});
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
return canvas.EndRecordingAsPicture();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
namespace {
void CanRenderSweepGradient(AiksTest* aiks_test, Entity::TileMode tile_mode) {
Canvas canvas;
canvas.Scale(aiks_test->GetContentScale());
Paint paint;
canvas.Translate({100, 100, 0});
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
Color{0.1294, 0.5882, 0.9529, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeSweepGradient(
{100, 100}, Degrees(45), Degrees(135), std::move(colors),
std::move(stops), tile_mode, {});
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace
TEST_P(AiksTest, CanRenderSweepGradientClamp) {
CanRenderSweepGradient(this, Entity::TileMode::kClamp);
}
TEST_P(AiksTest, CanRenderSweepGradientRepeat) {
CanRenderSweepGradient(this, Entity::TileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderSweepGradientMirror) {
CanRenderSweepGradient(this, Entity::TileMode::kMirror);
}
TEST_P(AiksTest, CanRenderSweepGradientDecal) {
CanRenderSweepGradient(this, Entity::TileMode::kDecal);
}
namespace {
void CanRenderSweepGradientManyColors(AiksTest* aiks_test,
Entity::TileMode tile_mode) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0, 100.0, 0});
std::vector<Color> colors = {
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
std::vector<Scalar> stops = {
0.0,
(1.0 / 6.0) * 1,
(1.0 / 6.0) * 2,
(1.0 / 6.0) * 3,
(1.0 / 6.0) * 4,
(1.0 / 6.0) * 5,
1.0,
};
paint.color_source = ColorSource::MakeSweepGradient(
{100, 100}, Degrees(45), Degrees(135), std::move(colors),
std::move(stops), tile_mode, {});
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace
TEST_P(AiksTest, CanRenderSweepGradientManyColorsClamp) {
CanRenderSweepGradientManyColors(this, Entity::TileMode::kClamp);
}
TEST_P(AiksTest, CanRenderSweepGradientManyColorsRepeat) {
CanRenderSweepGradientManyColors(this, Entity::TileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderSweepGradientManyColorsMirror) {
CanRenderSweepGradientManyColors(this, Entity::TileMode::kMirror);
}
TEST_P(AiksTest, CanRenderSweepGradientManyColorsDecal) {
CanRenderSweepGradientManyColors(this, Entity::TileMode::kDecal);
}
TEST_P(AiksTest, CanRenderConicalGradient) {
Scalar size = 256;
Canvas canvas;
Paint paint;
paint.color = Color::White();
canvas.DrawRect(Rect::MakeXYWH(0, 0, size * 3, size * 3), paint);
std::vector<Color> colors = {Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF),
Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF),
Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF),
Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF)};
std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
std::array<std::tuple<Point, float, Point, float>, 8> array{
std::make_tuple(Point{size / 2.f, size / 2.f}, 0.f,
Point{size / 2.f, size / 2.f}, size / 2.f),
std::make_tuple(Point{size / 2.f, size / 2.f}, size / 4.f,
Point{size / 2.f, size / 2.f}, size / 2.f),
std::make_tuple(Point{size / 4.f, size / 4.f}, 0.f,
Point{size / 2.f, size / 2.f}, size / 2.f),
std::make_tuple(Point{size / 4.f, size / 4.f}, size / 2.f,
Point{size / 2.f, size / 2.f}, 0),
std::make_tuple(Point{size / 4.f, size / 4.f}, size / 4.f,
Point{size / 2.f, size / 2.f}, size / 2.f),
std::make_tuple(Point{size / 4.f, size / 4.f}, size / 16.f,
Point{size / 2.f, size / 2.f}, size / 8.f),
std::make_tuple(Point{size / 4.f, size / 4.f}, size / 8.f,
Point{size / 2.f, size / 2.f}, size / 16.f),
std::make_tuple(Point{size / 8.f, size / 8.f}, size / 8.f,
Point{size / 2.f, size / 2.f}, size / 8.f),
};
for (int i = 0; i < 8; i++) {
canvas.Save();
canvas.Translate({(i % 3) * size, i / 3 * size, 0});
paint.color_source = ColorSource::MakeConicalGradient(
std::get<0>(array[i]), std::get<1>(array[i]), colors, stops,
std::get<2>(array[i]), std::get<3>(array[i]), Entity::TileMode::kClamp,
{});
canvas.DrawRect(Rect::MakeXYWH(0, 0, size, size), paint);
canvas.Restore();
}
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderGradientDecalWithBackground) {
std::vector<Color> colors = {Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF),
Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF),
Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF),
Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF)};
std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
std::array<ColorSource, 3> color_sources = {
ColorSource::MakeLinearGradient({0, 0}, {100, 100}, colors, stops,
Entity::TileMode::kDecal, {}),
ColorSource::MakeRadialGradient({100, 100}, 100, colors, stops,
Entity::TileMode::kDecal, {}),
ColorSource::MakeSweepGradient({100, 100}, Degrees(45), Degrees(135),
colors, stops, Entity::TileMode::kDecal,
{}),
};
Canvas canvas;
Paint paint;
paint.color = Color::White();
canvas.DrawRect(Rect::MakeLTRB(0, 0, 605, 205), paint);
for (int i = 0; i < 3; i++) {
canvas.Save();
canvas.Translate({i * 200.0f, 0, 0});
paint.color_source = color_sources[i];
canvas.DrawRect(Rect::MakeLTRB(0, 0, 200, 200), paint);
canvas.Restore();
}
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
#define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \
TEST_P(AiksTest, name##GradientApplyColorFilter) { \
auto contents = name##GradientContents(); \
@ -651,194 +41,5 @@ APPLY_COLOR_FILTER_GRADIENT_TEST(Radial);
APPLY_COLOR_FILTER_GRADIENT_TEST(Conical);
APPLY_COLOR_FILTER_GRADIENT_TEST(Sweep);
TEST_P(AiksTest, GradientStrokesRenderCorrectly) {
// Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
static float scale = 3;
static bool add_circle_clip = true;
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const Entity::TileMode tile_modes[] = {
Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
Entity::TileMode::kMirror, Entity::TileMode::kDecal};
static int selected_tile_mode = 0;
static float alpha = 1;
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::SliderFloat("Scale", &scale, 0, 6);
ImGui::Checkbox("Circle clip", &add_circle_clip);
ImGui::SliderFloat("Alpha", &alpha, 0, 1);
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
ImGui::End();
}
Canvas canvas;
canvas.Scale(GetContentScale());
Paint paint;
paint.color = Color::White();
canvas.DrawPaint(paint);
paint.style = Paint::Style::kStroke;
paint.color = Color(1.0, 1.0, 1.0, alpha);
paint.stroke_width = 10;
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
Color{0.1294, 0.5882, 0.9529, 1.0}};
std::vector<Scalar> stops = {0.0, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {50, 50}, std::move(colors), std::move(stops), tile_mode, {});
Path path = PathBuilder{}
.MoveTo({20, 20})
.QuadraticCurveTo({60, 20}, {60, 60})
.Close()
.MoveTo({60, 20})
.QuadraticCurveTo({60, 60}, {20, 60})
.TakePath();
canvas.Scale(Vector2(scale, scale));
if (add_circle_clip) {
static PlaygroundPoint circle_clip_point_a(Point(60, 300), 20,
Color::Red());
static PlaygroundPoint circle_clip_point_b(Point(600, 300), 20,
Color::Red());
auto [handle_a, handle_b] =
DrawPlaygroundLine(circle_clip_point_a, circle_clip_point_b);
auto screen_to_canvas = canvas.GetCurrentTransform().Invert();
Point point_a = screen_to_canvas * handle_a * GetContentScale();
Point point_b = screen_to_canvas * handle_b * GetContentScale();
Point middle = (point_a + point_b) / 2;
auto radius = point_a.GetDistance(middle);
canvas.ClipPath(PathBuilder{}.AddCircle(middle, radius).TakePath());
}
for (auto join : {Join::kBevel, Join::kRound, Join::kMiter}) {
paint.stroke_join = join;
for (auto cap : {Cap::kButt, Cap::kSquare, Cap::kRound}) {
paint.stroke_cap = cap;
canvas.DrawPath(path, paint);
canvas.Translate({80, 0});
}
canvas.Translate({-240, 60});
}
return canvas.EndRecordingAsPicture();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestHorizontal) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {300, 0}, std::move(colors), std::move(stops),
Entity::TileMode::kClamp, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), paint);
canvas.Translate({400, 0, 0});
canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), Size(4, 4), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestVertical) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 0}, {0, 300}, std::move(colors), std::move(stops),
Entity::TileMode::kClamp, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), paint);
canvas.Translate({400, 0, 0});
canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), Size(4, 4), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestHorizontalReversed) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{300, 0}, {0, 0}, std::move(colors), std::move(stops),
Entity::TileMode::kClamp, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), paint);
canvas.Translate({400, 0, 0});
canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), Size(4, 4), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestVerticalReversed) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.color_source = ColorSource::MakeLinearGradient(
{0, 300}, {0, 0}, std::move(colors), std::move(stops),
Entity::TileMode::kClamp, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), paint);
canvas.Translate({400, 0, 0});
canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), Size(4, 4), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, VerifyNonOptimizedGradient) {
Canvas canvas;
Paint paint;
canvas.Translate({100.0f, 0, 0});
std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
// Inset the start and end point to verify that we do not apply
// the fast gradient condition.
paint.color_source = ColorSource::MakeLinearGradient(
{0, 150}, {0, 100}, std::move(colors), std::move(stops),
Entity::TileMode::kRepeat, {});
paint.color = Color(1.0, 1.0, 1.0, 1.0);
canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), paint);
canvas.Translate({400, 0, 0});
canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), Size(4, 4), paint);
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace testing
} // namespace impeller
} // namespace impeller

View File

@ -81,4 +81,23 @@ bool AiksPlayground::OpenPlaygroundHere(
return OpenPlaygroundHere(std::move(picture));
}
bool AiksPlayground::OpenPlaygroundHere(
const AiksDlPlaygroundCallback& callback) {
AiksContext renderer(GetContext(), typographer_context_);
if (!renderer.IsValid()) {
return false;
}
return Playground::OpenPlaygroundHere(
[&renderer, &callback](RenderTarget& render_target) -> bool {
auto display_list = callback();
DlDispatcher dispatcher;
display_list->Dispatch(dispatcher);
Picture picture = dispatcher.EndRecordingAsPicture();
return renderer.Render(picture, render_target, true);
});
}
} // namespace impeller

View File

@ -19,6 +19,8 @@ class AiksPlayground : public PlaygroundTest {
using AiksPlaygroundCallback =
std::function<std::optional<Picture>(AiksContext& renderer)>;
using AiksDlPlaygroundCallback = std::function<sk_sp<flutter::DisplayList>()>;
AiksPlayground();
~AiksPlayground();
@ -32,6 +34,8 @@ class AiksPlayground : public PlaygroundTest {
bool OpenPlaygroundHere(AiksPlaygroundCallback callback);
bool OpenPlaygroundHere(const AiksDlPlaygroundCallback& callback);
bool OpenPlaygroundHere(const sk_sp<flutter::DisplayList>& list);
static bool ImGuiBegin(const char* name,

View File

@ -63,7 +63,6 @@ struct Paint {
Color color = Color::Black();
ColorSource color_source;
bool dither = false;
Scalar stroke_width = 0.0;
Cap stroke_cap = Cap::kButt;

View File

@ -53,6 +53,7 @@ template("display_list_unittests_component") {
target_name = invoker.target_name
predefined_sources = [
"aiks_dl_clip_unittests.cc",
"aiks_dl_gradient_unittests.cc",
"aiks_dl_opacity_unittests.cc",
"aiks_dl_path_unittests.cc",
"dl_golden_unittests.cc",

View File

@ -0,0 +1,832 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "display_list/display_list.h"
#include "display_list/dl_blend_mode.h"
#include "display_list/dl_tile_mode.h"
#include "display_list/effects/dl_color_filter.h"
#include "display_list/effects/dl_color_source.h"
#include "display_list/effects/dl_mask_filter.h"
#include "flutter/impeller/aiks/aiks_unittests.h"
#include "flutter/display_list/dl_builder.h"
#include "flutter/display_list/dl_color.h"
#include "flutter/display_list/dl_paint.h"
#include "flutter/testing/testing.h"
#include "impeller/playground/widgets.h"
#include "include/core/SkPath.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
using namespace flutter;
////////////////////////////////////////////////////////////////////////////////
// This is for tests of Canvas that are interested the results of rendering
// gradients.
////////////////////////////////////////////////////////////////////////////////
namespace impeller {
namespace testing {
namespace {
/// Test body for linear gradient tile mode tests (ex.
/// CanRenderLinearGradientClamp).
void CanRenderLinearGradient(AiksTest* aiks_test, DlTileMode tile_mode) {
DisplayListBuilder builder;
Point scale = aiks_test->GetContentScale();
builder.Scale(scale.x, scale.y);
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 0.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
auto gradient = DlColorSource::MakeLinear(
{0, 0}, {200, 200}, 2, colors.data(), stops.data(), tile_mode);
paint.setColorSource(gradient);
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
Matrix ToMatrix(const SkMatrix& m) {
return Matrix{
// clang-format off
m[0], m[3], 0, m[6],
m[1], m[4], 0, m[7],
0, 0, 1, 0,
m[2], m[5], 0, m[8],
// clang-format on
};
}
} // namespace
TEST_P(AiksTest, CanRenderLinearGradientClamp) {
CanRenderLinearGradient(this, DlTileMode::kClamp);
}
TEST_P(AiksTest, CanRenderLinearGradientRepeat) {
CanRenderLinearGradient(this, DlTileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderLinearGradientMirror) {
CanRenderLinearGradient(this, DlTileMode::kMirror);
}
TEST_P(AiksTest, CanRenderLinearGradientDecal) {
CanRenderLinearGradient(this, DlTileMode::kDecal);
}
TEST_P(AiksTest, CanRenderLinearGradientDecalWithColorFilter) {
DisplayListBuilder builder;
Point scale = GetContentScale();
builder.Scale(scale.x, scale.y);
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 0.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeLinear(
{0, 0}, {200, 200}, 2, colors.data(), stops.data(), DlTileMode::kDecal));
// Overlay the gradient with 25% green. This should appear as the entire
// rectangle being drawn with 25% green, including the border area outside the
// decal gradient.
paint.setColorFilter(DlBlendColorFilter::Make(DlColor::kGreen().withAlpha(64),
DlBlendMode::kSrcOver));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
static void CanRenderLinearGradientWithDithering(AiksTest* aiks_test) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
// 0xffcccccc --> 0xff333333, taken from
// https://github.com/flutter/flutter/issues/118073#issue-1521699748
std::vector<DlColor> colors = {DlColor(0xFFCCCCCC), DlColor(0xFF333333)};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeLinear(
{0, 0}, {800, 500}, 2, colors.data(), stops.data(), DlTileMode::kClamp));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 800, 500), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, CanRenderLinearGradientWithDitheringEnabled) {
CanRenderLinearGradientWithDithering(this);
}
static void CanRenderRadialGradientWithDithering(AiksTest* aiks_test) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
// #FFF -> #000
std::vector<DlColor> colors = {DlColor(Color{1.0, 1.0, 1.0, 1.0}.ToARGB()),
DlColor(Color{0.0, 0.0, 0.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeRadial(
{600, 600}, 600, 2, colors.data(), stops.data(), DlTileMode::kClamp));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 1200, 1200), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, CanRenderRadialGradientWithDitheringEnabled) {
CanRenderRadialGradientWithDithering(this);
}
static void CanRenderSweepGradientWithDithering(AiksTest* aiks_test) {
DisplayListBuilder builder;
builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
DlPaint paint;
builder.Translate(100.0, 100.0);
// #FFF -> #000
std::vector<DlColor> colors = {DlColor(Color{1.0, 1.0, 1.0, 1.0}.ToARGB()),
DlColor(Color{0.0, 0.0, 0.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeSweep(
{100, 100}, /*start=*/45, /*end=*/135, 2, colors.data(), stops.data(),
DlTileMode::kMirror));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, CanRenderSweepGradientWithDitheringEnabled) {
CanRenderSweepGradientWithDithering(this);
}
static void CanRenderConicalGradientWithDithering(AiksTest* aiks_test) {
DisplayListBuilder builder;
builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
DlPaint paint;
builder.Translate(100.0, 100.0);
// #FFF -> #000
std::vector<DlColor> colors = {DlColor(Color{1.0, 1.0, 1.0, 1.0}.ToARGB()),
DlColor(Color{0.0, 0.0, 0.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeConical({0, 1}, 0, {100, 100}, 100, 2,
colors.data(), stops.data(),
DlTileMode::kMirror));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, CanRenderConicalGradientWithDitheringEnabled) {
CanRenderConicalGradientWithDithering(this);
}
namespace {
void CanRenderLinearGradientWithOverlappingStops(AiksTest* aiks_test,
DlTileMode tile_mode) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
std::vector<DlColor> colors = {
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 0.5, 0.5, 1.0};
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {500, 500},
stops.size(), colors.data(),
stops.data(), tile_mode));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 500, 500), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
} // namespace
// Only clamp is necessary. All tile modes are the same output.
TEST_P(AiksTest, CanRenderLinearGradientWithOverlappingStopsClamp) {
CanRenderLinearGradientWithOverlappingStops(this, DlTileMode::kClamp);
}
namespace {
void CanRenderLinearGradientManyColors(AiksTest* aiks_test,
DlTileMode tile_mode) {
DisplayListBuilder builder;
builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
DlPaint paint;
builder.Translate(100, 100);
std::vector<DlColor> colors = {
DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {
0.0,
(1.0 / 6.0) * 1,
(1.0 / 6.0) * 2,
(1.0 / 6.0) * 3,
(1.0 / 6.0) * 4,
(1.0 / 6.0) * 5,
1.0,
};
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {200, 200},
stops.size(), colors.data(),
stops.data(), tile_mode));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
builder.Restore();
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
} // namespace
TEST_P(AiksTest, CanRenderLinearGradientManyColorsClamp) {
CanRenderLinearGradientManyColors(this, DlTileMode::kClamp);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsRepeat) {
CanRenderLinearGradientManyColors(this, DlTileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsMirror) {
CanRenderLinearGradientManyColors(this, DlTileMode::kMirror);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsDecal) {
CanRenderLinearGradientManyColors(this, DlTileMode::kDecal);
}
namespace {
void CanRenderLinearGradientWayManyColors(AiksTest* aiks_test,
DlTileMode tile_mode) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
auto color = DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB());
std::vector<DlColor> colors;
std::vector<Scalar> stops;
auto current_stop = 0.0;
for (int i = 0; i < 2000; i++) {
colors.push_back(color);
stops.push_back(current_stop);
current_stop += 1 / 2000.0;
}
stops[2000 - 1] = 1.0;
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {200, 200},
stops.size(), colors.data(),
stops.data(), tile_mode));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
} // namespace
// Only test clamp on purpose since they all look the same.
TEST_P(AiksTest, CanRenderLinearGradientWayManyColorsClamp) {
CanRenderLinearGradientWayManyColors(this, DlTileMode::kClamp);
}
TEST_P(AiksTest, CanRenderLinearGradientManyColorsUnevenStops) {
auto callback = [&]() -> sk_sp<DisplayList> {
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
DlTileMode::kMirror, DlTileMode::kDecal};
static int selected_tile_mode = 0;
static Matrix matrix;
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 4; i++) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
label[2]++;
}
ImGui::End();
}
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<DlColor> colors = {
DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {
0.0, 2.0 / 62.0, 4.0 / 62.0, 8.0 / 62.0, 16.0 / 62.0, 32.0 / 62.0, 1.0,
};
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {200, 200},
stops.size(), colors.data(),
stops.data(), tile_mode));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
return builder.Build();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
TEST_P(AiksTest, CanRenderLinearGradientMaskBlur) {
DisplayListBuilder builder;
std::vector<DlColor> colors = {
DlColor::kRed(), DlColor::kWhite(), DlColor::kRed(), DlColor::kWhite(),
DlColor::kRed(), DlColor::kWhite(), DlColor::kRed(), DlColor::kWhite(),
DlColor::kRed(), DlColor::kWhite(), DlColor::kRed()};
std::vector<Scalar> stops = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5,
0.6, 0.7, 0.8, 0.9, 1.0};
DlPaint paint;
paint.setColor(DlColor::kWhite());
paint.setColorSource(DlColorSource::MakeLinear(
{200, 200}, {400, 400}, stops.size(), colors.data(), stops.data(),
DlTileMode::kClamp));
paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 20));
builder.DrawCircle({300, 300}, 200, paint);
builder.DrawRect(SkRect::MakeLTRB(100, 300, 500, 600), paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, CanRenderRadialGradient) {
auto callback = [&]() -> sk_sp<DisplayList> {
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
DlTileMode::kMirror, DlTileMode::kDecal};
static int selected_tile_mode = 0;
static Matrix matrix;
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 4; i++) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
label[2]++;
}
ImGui::End();
}
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<DlColor> colors = {
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeRadial(
{100, 100}, 100, 2, colors.data(), stops.data(), tile_mode));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
return builder.Build();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
TEST_P(AiksTest, CanRenderRadialGradientManyColors) {
auto callback = [&]() -> sk_sp<DisplayList> {
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
DlTileMode::kMirror, DlTileMode::kDecal};
static int selected_tile_mode = 0;
static Matrix matrix = {
1, 0, 0, 0, //
0, 1, 0, 0, //
0, 0, 1, 0, //
0, 0, 0, 1 //
};
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 4; i++) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(matrix.vec[i]), 4, NULL, NULL, "%.2f", 0);
label[2]++;
}
ImGui::End();
}
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<DlColor> colors = {
DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {
0.0,
(1.0 / 6.0) * 1,
(1.0 / 6.0) * 2,
(1.0 / 6.0) * 3,
(1.0 / 6.0) * 4,
(1.0 / 6.0) * 5,
1.0,
};
paint.setColorSource(DlColorSource::MakeRadial(
{100, 100}, 100, stops.size(), colors.data(), stops.data(), tile_mode));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
return builder.Build();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
namespace {
void CanRenderSweepGradient(AiksTest* aiks_test, DlTileMode tile_mode) {
DisplayListBuilder builder;
builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
DlPaint paint;
builder.Translate(100, 100);
std::vector<DlColor> colors = {
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeSweep(
{100, 100}, /*start=*/45, /*end=*/135, /*stop_count=*/2, colors.data(),
stops.data(), tile_mode));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
} // namespace
TEST_P(AiksTest, CanRenderSweepGradientClamp) {
CanRenderSweepGradient(this, DlTileMode::kClamp);
}
TEST_P(AiksTest, CanRenderSweepGradientRepeat) {
CanRenderSweepGradient(this, DlTileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderSweepGradientMirror) {
CanRenderSweepGradient(this, DlTileMode::kMirror);
}
TEST_P(AiksTest, CanRenderSweepGradientDecal) {
CanRenderSweepGradient(this, DlTileMode::kDecal);
}
namespace {
void CanRenderSweepGradientManyColors(AiksTest* aiks_test,
DlTileMode tile_mode) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0, 100.0);
std::vector<DlColor> colors = {
DlColor(Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0}.ToARGB()),
DlColor(Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}.ToARGB())};
std::vector<Scalar> stops = {
0.0,
(1.0 / 6.0) * 1,
(1.0 / 6.0) * 2,
(1.0 / 6.0) * 3,
(1.0 / 6.0) * 4,
(1.0 / 6.0) * 5,
1.0,
};
paint.setColorSource(DlColorSource::MakeSweep({100, 100}, 45, 135,
stops.size(), colors.data(),
stops.data(), tile_mode));
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
}
} // namespace
TEST_P(AiksTest, CanRenderSweepGradientManyColorsClamp) {
CanRenderSweepGradientManyColors(this, DlTileMode::kClamp);
}
TEST_P(AiksTest, CanRenderSweepGradientManyColorsRepeat) {
CanRenderSweepGradientManyColors(this, DlTileMode::kRepeat);
}
TEST_P(AiksTest, CanRenderSweepGradientManyColorsMirror) {
CanRenderSweepGradientManyColors(this, DlTileMode::kMirror);
}
TEST_P(AiksTest, CanRenderSweepGradientManyColorsDecal) {
CanRenderSweepGradientManyColors(this, DlTileMode::kDecal);
}
TEST_P(AiksTest, CanRenderConicalGradient) {
Scalar size = 256;
DisplayListBuilder builder;
DlPaint paint;
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, size * 3, size * 3), paint);
std::vector<DlColor> colors = {
DlColor(Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF).ToARGB()),
DlColor(Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF).ToARGB()),
DlColor(Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF).ToARGB()),
DlColor(Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF).ToARGB())};
std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
std::array<std::tuple<SkPoint, float, SkPoint, float>, 8> array{
std::make_tuple(SkPoint::Make(size / 2.f, size / 2.f), 0.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
std::make_tuple(SkPoint::Make(size / 2.f, size / 2.f), size / 4.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), 0.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 2.f,
SkPoint::Make(size / 2.f, size / 2.f), 0),
std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 4.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 2.f),
std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 16.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 8.f),
std::make_tuple(SkPoint::Make(size / 4.f, size / 4.f), size / 8.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 16.f),
std::make_tuple(SkPoint::Make(size / 8.f, size / 8.f), size / 8.f,
SkPoint::Make(size / 2.f, size / 2.f), size / 8.f),
};
for (int i = 0; i < 8; i++) {
builder.Save();
builder.Translate((i % 3) * size, i / 3 * size);
paint.setColorSource(DlColorSource::MakeConical(
std::get<2>(array[i]), std::get<3>(array[i]), std::get<0>(array[i]),
std::get<1>(array[i]), stops.size(), colors.data(), stops.data(),
DlTileMode::kClamp));
builder.DrawRect(SkRect::MakeXYWH(0, 0, size, size), paint);
builder.Restore();
}
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, CanRenderGradientDecalWithBackground) {
std::vector<DlColor> colors = {
DlColor(Color::MakeRGBA8(0xF4, 0x43, 0x36, 0xFF).ToARGB()),
DlColor(Color::MakeRGBA8(0xFF, 0xEB, 0x3B, 0xFF).ToARGB()),
DlColor(Color::MakeRGBA8(0x4c, 0xAF, 0x50, 0xFF).ToARGB()),
DlColor(Color::MakeRGBA8(0x21, 0x96, 0xF3, 0xFF).ToARGB())};
std::vector<Scalar> stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0};
std::array<std::shared_ptr<DlColorSource>, 3> color_sources = {
DlColorSource::MakeLinear({0, 0}, {100, 100}, stops.size(), colors.data(),
stops.data(), DlTileMode::kDecal),
DlColorSource::MakeRadial({100, 100}, 100, stops.size(), colors.data(),
stops.data(), DlTileMode::kDecal),
DlColorSource::MakeSweep({100, 100}, 45, 135, stops.size(), colors.data(),
stops.data(), DlTileMode::kDecal),
};
DisplayListBuilder builder;
DlPaint paint;
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeLTRB(0, 0, 605, 205), paint);
for (int i = 0; i < 3; i++) {
builder.Save();
builder.Translate(i * 200.0f, 0);
paint.setColorSource(color_sources[i]);
builder.DrawRect(SkRect::MakeLTRB(0, 0, 200, 200), paint);
builder.Restore();
}
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, GradientStrokesRenderCorrectly) {
// Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
auto callback = [&]() -> sk_sp<DisplayList> {
static float scale = 3;
static bool add_circle_clip = true;
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
const DlTileMode tile_modes[] = {DlTileMode::kClamp, DlTileMode::kRepeat,
DlTileMode::kMirror, DlTileMode::kDecal};
static int selected_tile_mode = 0;
static float alpha = 1;
if (AiksTest::ImGuiBegin("Controls", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::SliderFloat("Scale", &scale, 0, 6);
ImGui::Checkbox("Circle clip", &add_circle_clip);
ImGui::SliderFloat("Alpha", &alpha, 0, 1);
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
sizeof(tile_mode_names) / sizeof(char*));
ImGui::End();
}
DisplayListBuilder builder;
builder.Scale(GetContentScale().x, GetContentScale().y);
DlPaint paint;
paint.setColor(DlColor::kWhite());
builder.DrawPaint(paint);
paint.setDrawStyle(DlDrawStyle::kStroke);
paint.setColor(DlColor::kWhite().withAlpha(alpha * 255));
paint.setStrokeWidth(10);
auto tile_mode = tile_modes[selected_tile_mode];
std::vector<DlColor> colors = {
DlColor(Color{0.9568, 0.2627, 0.2118, 1.0}.ToARGB()),
DlColor(Color{0.1294, 0.5882, 0.9529, 1.0}.ToARGB())};
std::vector<Scalar> stops = {0.0, 1.0};
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {50, 50},
stops.size(), colors.data(),
stops.data(), tile_mode));
SkPath path;
path.moveTo(20, 20);
path.quadTo({60, 20}, {60, 60});
path.close();
path.moveTo(60, 20);
path.quadTo({60, 60}, {20, 60});
builder.Scale(scale, scale);
if (add_circle_clip) {
static PlaygroundPoint circle_clip_point_a(Point(60, 300), 20,
Color::Red());
static PlaygroundPoint circle_clip_point_b(Point(600, 300), 20,
Color::Red());
auto [handle_a, handle_b] =
DrawPlaygroundLine(circle_clip_point_a, circle_clip_point_b);
SkMatrix screen_to_canvas;
if (!builder.GetTransform().invert(&screen_to_canvas)) {
return nullptr;
}
Matrix ip_matrix = ToMatrix(screen_to_canvas);
Point point_a = ip_matrix * handle_a * GetContentScale();
Point point_b = ip_matrix * handle_b * GetContentScale();
Point middle = (point_a + point_b) / 2;
auto radius = point_a.GetDistance(middle);
SkPath circle;
circle.addCircle(middle.x, middle.y, radius);
builder.ClipPath(circle);
}
for (auto join :
{DlStrokeJoin::kBevel, DlStrokeJoin::kRound, DlStrokeJoin::kMiter}) {
paint.setStrokeJoin(join);
for (auto cap :
{DlStrokeCap::kButt, DlStrokeCap::kSquare, DlStrokeCap::kRound}) {
paint.setStrokeCap(cap);
builder.DrawPath(path, paint);
builder.Translate(80, 0);
}
builder.Translate(-240, 60);
}
return builder.Build();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestHorizontal) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
DlColor::kGreen()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {300, 0}, stops.size(),
colors.data(), stops.data(),
DlTileMode::kClamp));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
builder.Translate(400, 0);
builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestVertical) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
DlColor::kGreen()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {0, 300}, stops.size(),
colors.data(), stops.data(),
DlTileMode::kClamp));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
builder.Translate(400, 0);
builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestHorizontalReversed) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
DlColor::kGreen()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.setColorSource(DlColorSource::MakeLinear({300, 0}, {0, 0}, stops.size(),
colors.data(), stops.data(),
DlTileMode::kClamp));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
builder.Translate(400, 0);
builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
// Draws two gradients that should look identical (except that one is an RRECT).
TEST_P(AiksTest, FastGradientTestVerticalReversed) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
DlColor::kGreen()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
paint.setColorSource(DlColorSource::MakeLinear({0, 300}, {0, 0}, stops.size(),
colors.data(), stops.data(),
DlTileMode::kClamp));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
builder.Translate(400, 0);
builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, VerifyNonOptimizedGradient) {
DisplayListBuilder builder;
DlPaint paint;
builder.Translate(100.0f, 0);
std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue(),
DlColor::kGreen()};
std::vector<Scalar> stops = {0.0, 0.1, 1.0};
// Inset the start and end point to verify that we do not apply
// the fast gradient condition.
paint.setColorSource(
DlColorSource::MakeLinear({0, 150}, {0, 100}, stops.size(), colors.data(),
stops.data(), DlTileMode::kRepeat));
paint.setColor(DlColor::kWhite());
builder.DrawRect(SkRect::MakeXYWH(0, 0, 300, 300), paint);
builder.Translate(400, 0);
builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 300, 300), 4, 4),
paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
} // namespace testing
} // namespace impeller

View File

@ -28,6 +28,8 @@ class GoldenPlaygroundTest
using AiksPlaygroundCallback =
std::function<std::optional<Picture>(AiksContext& renderer)>;
using AiksDlPlaygroundCallback = std::function<sk_sp<flutter::DisplayList>()>;
GoldenPlaygroundTest();
~GoldenPlaygroundTest() override;
@ -45,6 +47,8 @@ class GoldenPlaygroundTest
bool OpenPlaygroundHere(AiksPlaygroundCallback callback);
bool OpenPlaygroundHere(const AiksDlPlaygroundCallback& callback);
bool OpenPlaygroundHere(const sk_sp<flutter::DisplayList>& list);
static bool ImGuiBegin(const char* name,

View File

@ -210,6 +210,25 @@ bool GoldenPlaygroundTest::OpenPlaygroundHere(Picture picture) {
return SaveScreenshot(std::move(screenshot));
}
bool GoldenPlaygroundTest::OpenPlaygroundHere(
const AiksDlPlaygroundCallback& callback) {
AiksContext renderer(GetContext(), typographer_context_);
std::optional<Picture> picture;
std::unique_ptr<testing::Screenshot> screenshot;
for (int i = 0; i < 2; ++i) {
auto display_list = callback();
DlDispatcher dispatcher;
display_list->Dispatch(dispatcher);
Picture picture = dispatcher.EndRecordingAsPicture();
screenshot = pimpl_->screenshotter->MakeScreenshot(renderer, picture,
pimpl_->window_size);
}
return SaveScreenshot(std::move(screenshot));
}
bool GoldenPlaygroundTest::OpenPlaygroundHere(
AiksPlaygroundCallback
callback) { // NOLINT(performance-unnecessary-value-param)

View File

@ -37,6 +37,11 @@ bool GoldenPlaygroundTest::OpenPlaygroundHere(
return false;
}
bool GoldenPlaygroundTest::OpenPlaygroundHere(
const AiksDlPlaygroundCallback& callback) {
return false;
}
bool GoldenPlaygroundTest::OpenPlaygroundHere(
const sk_sp<flutter::DisplayList>& list) {
return false;

View File

@ -268,9 +268,6 @@ impeller_Play_AiksTest_CanRenderColorFilterWithInvertColors_Vulkan.png
impeller_Play_AiksTest_CanRenderColoredRect_Metal.png
impeller_Play_AiksTest_CanRenderColoredRect_OpenGLES.png
impeller_Play_AiksTest_CanRenderColoredRect_Vulkan.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringDisabled_Metal.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringDisabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringDisabled_Vulkan.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderConicalGradientWithDitheringEnabled_Vulkan.png
@ -364,9 +361,6 @@ impeller_Play_AiksTest_CanRenderLinearGradientRepeat_Vulkan.png
impeller_Play_AiksTest_CanRenderLinearGradientWayManyColorsClamp_Metal.png
impeller_Play_AiksTest_CanRenderLinearGradientWayManyColorsClamp_OpenGLES.png
impeller_Play_AiksTest_CanRenderLinearGradientWayManyColorsClamp_Vulkan.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringDisabled_Metal.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringDisabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringDisabled_Vulkan.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderLinearGradientWithDitheringEnabled_Vulkan.png
@ -388,9 +382,6 @@ impeller_Play_AiksTest_CanRenderQuadraticStrokeWithInstantTurn_Vulkan.png
impeller_Play_AiksTest_CanRenderRadialGradientManyColors_Metal.png
impeller_Play_AiksTest_CanRenderRadialGradientManyColors_OpenGLES.png
impeller_Play_AiksTest_CanRenderRadialGradientManyColors_Vulkan.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringDisabled_Metal.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringDisabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringDisabled_Vulkan.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderRadialGradientWithDitheringEnabled_Vulkan.png
@ -439,9 +430,6 @@ impeller_Play_AiksTest_CanRenderSweepGradientMirror_Vulkan.png
impeller_Play_AiksTest_CanRenderSweepGradientRepeat_Metal.png
impeller_Play_AiksTest_CanRenderSweepGradientRepeat_OpenGLES.png
impeller_Play_AiksTest_CanRenderSweepGradientRepeat_Vulkan.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringDisabled_Metal.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringDisabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringDisabled_Vulkan.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_Metal.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_OpenGLES.png
impeller_Play_AiksTest_CanRenderSweepGradientWithDitheringEnabled_Vulkan.png