diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 9a576142b2c72..d76f7158b3718 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -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 diff --git a/impeller/aiks/aiks_gradient_unittests.cc b/impeller/aiks/aiks_gradient_unittests.cc index ce0e8d31a7139..bf6abdad96cd3 100644 --- a/impeller/aiks/aiks_gradient_unittests.cc +++ b/impeller/aiks/aiks_gradient_unittests.cc @@ -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 colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 0.0}}; - std::vector 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 colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 0.0}}; - std::vector 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 colors = {Color{0.8, 0.8, 0.8, 1.0}, - Color{0.2, 0.2, 0.2, 1.0}}; - std::vector 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 colors = {Color{1.0, 1.0, 1.0, 1.0}, - Color{0.0, 0.0, 0.0, 1.0}}; - std::vector 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 colors = {Color{1.0, 1.0, 1.0, 1.0}, - Color{0.0, 0.0, 0.0, 1.0}}; - std::vector 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 colors = {Color{1.0, 1.0, 1.0, 1.0}, - Color{0.0, 0.0, 0.0, 1.0}}; - std::vector 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 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 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 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 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 colors; - std::vector 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 { - 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 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 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 { - 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 colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector 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 { - 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 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 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 colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector 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 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 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 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 stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; - std::array, 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 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 stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; - - std::array 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 { - 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 colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - std::vector 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 colors = {Color::Red(), Color::Blue(), Color::Green()}; - std::vector 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 colors = {Color::Red(), Color::Blue(), Color::Green()}; - std::vector 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 colors = {Color::Red(), Color::Blue(), Color::Green()}; - std::vector 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 colors = {Color::Red(), Color::Blue(), Color::Green()}; - std::vector 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 colors = {Color::Red(), Color::Blue(), Color::Green()}; - std::vector 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 \ No newline at end of file diff --git a/impeller/aiks/aiks_playground.cc b/impeller/aiks/aiks_playground.cc index df533a434aab2..82f76bf3372a4 100644 --- a/impeller/aiks/aiks_playground.cc +++ b/impeller/aiks/aiks_playground.cc @@ -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 diff --git a/impeller/aiks/aiks_playground.h b/impeller/aiks/aiks_playground.h index c2e9532520232..bb0fddfd1b5d9 100644 --- a/impeller/aiks/aiks_playground.h +++ b/impeller/aiks/aiks_playground.h @@ -19,6 +19,8 @@ class AiksPlayground : public PlaygroundTest { using AiksPlaygroundCallback = std::function(AiksContext& renderer)>; + using AiksDlPlaygroundCallback = std::function()>; + AiksPlayground(); ~AiksPlayground(); @@ -32,6 +34,8 @@ class AiksPlayground : public PlaygroundTest { bool OpenPlaygroundHere(AiksPlaygroundCallback callback); + bool OpenPlaygroundHere(const AiksDlPlaygroundCallback& callback); + bool OpenPlaygroundHere(const sk_sp& list); static bool ImGuiBegin(const char* name, diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 66049e1c0acd9..7aa6da5be3200 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -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; diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index 4c34486798443..449128bccfd48 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -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", diff --git a/impeller/display_list/aiks_dl_gradient_unittests.cc b/impeller/display_list/aiks_dl_gradient_unittests.cc new file mode 100644 index 0000000000000..bea1fa77aef10 --- /dev/null +++ b/impeller/display_list/aiks_dl_gradient_unittests.cc @@ -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 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 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 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 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 colors = {DlColor(0xFFCCCCCC), DlColor(0xFF333333)}; + std::vector 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 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 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 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 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 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 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 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 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 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 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 colors; + std::vector 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 { + 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 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 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 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 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 { + 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 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 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 { + 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 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 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 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 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 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 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 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 stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; + std::array, 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 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 stops = {0.0, 1.f / 3.f, 2.f / 3.f, 1.0}; + + std::array, 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 { + 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 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 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 colors = {DlColor::kRed(), DlColor::kBlue(), + DlColor::kGreen()}; + std::vector 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 colors = {DlColor::kRed(), DlColor::kBlue(), + DlColor::kGreen()}; + std::vector 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 colors = {DlColor::kRed(), DlColor::kBlue(), + DlColor::kGreen()}; + std::vector 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 colors = {DlColor::kRed(), DlColor::kBlue(), + DlColor::kGreen()}; + std::vector 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 colors = {DlColor::kRed(), DlColor::kBlue(), + DlColor::kGreen()}; + std::vector 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 diff --git a/impeller/golden_tests/golden_playground_test.h b/impeller/golden_tests/golden_playground_test.h index 5fdf6720db764..8b480b29c6127 100644 --- a/impeller/golden_tests/golden_playground_test.h +++ b/impeller/golden_tests/golden_playground_test.h @@ -28,6 +28,8 @@ class GoldenPlaygroundTest using AiksPlaygroundCallback = std::function(AiksContext& renderer)>; + using AiksDlPlaygroundCallback = std::function()>; + GoldenPlaygroundTest(); ~GoldenPlaygroundTest() override; @@ -45,6 +47,8 @@ class GoldenPlaygroundTest bool OpenPlaygroundHere(AiksPlaygroundCallback callback); + bool OpenPlaygroundHere(const AiksDlPlaygroundCallback& callback); + bool OpenPlaygroundHere(const sk_sp& list); static bool ImGuiBegin(const char* name, diff --git a/impeller/golden_tests/golden_playground_test_mac.cc b/impeller/golden_tests/golden_playground_test_mac.cc index f90aaa91ed6ff..5a85e5d269a6e 100644 --- a/impeller/golden_tests/golden_playground_test_mac.cc +++ b/impeller/golden_tests/golden_playground_test_mac.cc @@ -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; + std::unique_ptr 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) diff --git a/impeller/golden_tests/golden_playground_test_stub.cc b/impeller/golden_tests/golden_playground_test_stub.cc index bfdb0495e36ae..0d6b81747094e 100644 --- a/impeller/golden_tests/golden_playground_test_stub.cc +++ b/impeller/golden_tests/golden_playground_test_stub.cc @@ -37,6 +37,11 @@ bool GoldenPlaygroundTest::OpenPlaygroundHere( return false; } +bool GoldenPlaygroundTest::OpenPlaygroundHere( + const AiksDlPlaygroundCallback& callback) { + return false; +} + bool GoldenPlaygroundTest::OpenPlaygroundHere( const sk_sp& list) { return false; diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 86e979f0a8d3a..79412098cf562 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -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