From b25d3561d6827ad7aa7db85d75428dc37bc0c03a Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Mon, 11 May 2026 18:15:04 +0200 Subject: [PATCH] LibGfx+LibWeb: Use Gfx gradient interpolation in display lists Prep for moving display-list rasterization out of LibWeb. Display-list gradient commands should not expose CSS enum types to the playback side, so add the matching interpolation method types to LibGfx and convert CSS values while recording. --- Libraries/LibGfx/GradientInterpolation.h | 54 +++++++++++++ .../LibWeb/Painting/DisplayListCommand.h | 20 +---- .../LibWeb/Painting/DisplayListPlayerSkia.cpp | 44 +++++------ .../LibWeb/Painting/DisplayListRecorder.cpp | 75 +++++++++++++++++-- 4 files changed, 148 insertions(+), 45 deletions(-) create mode 100644 Libraries/LibGfx/GradientInterpolation.h diff --git a/Libraries/LibGfx/GradientInterpolation.h b/Libraries/LibGfx/GradientInterpolation.h new file mode 100644 index 0000000000..bd084819ab --- /dev/null +++ b/Libraries/LibGfx/GradientInterpolation.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Gfx { + +enum class RectangularColorSpace : u8 { + Srgb, + SrgbLinear, + DisplayP3, + DisplayP3Linear, + A98Rgb, + ProphotoRgb, + Rec2020, + Lab, + Oklab, + Xyz, + XyzD50, + XyzD65, +}; + +enum class PolarColorSpace : u8 { + Hsl, + Hwb, + Lch, + Oklch, +}; + +enum class HueInterpolationMethod : u8 { + Shorter, + Longer, + Increasing, + Decreasing, +}; + +struct GradientInterpolationMethod { + enum class Type : u8 { + Rectangular, + Polar, + }; + + Type type { Type::Rectangular }; + RectangularColorSpace rectangular_color_space { RectangularColorSpace::Oklab }; + PolarColorSpace polar_color_space { PolarColorSpace::Oklch }; + HueInterpolationMethod hue_interpolation_method { HueInterpolationMethod::Shorter }; +}; + +} diff --git a/Libraries/LibWeb/Painting/DisplayListCommand.h b/Libraries/LibWeb/Painting/DisplayListCommand.h index 2513058d0c..f9491db8f5 100644 --- a/Libraries/LibWeb/Painting/DisplayListCommand.h +++ b/Libraries/LibWeb/Painting/DisplayListCommand.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -78,18 +78,6 @@ struct DisplayListDataSpan { [[nodiscard]] bool is_empty() const { return size == 0; } }; -struct DisplayListColorInterpolationMethod { - enum class Type : u8 { - Rectangular, - Polar, - }; - - Type type { Type::Rectangular }; - CSS::RectangularColorSpace rectangular_color_space { CSS::RectangularColorSpace::Oklab }; - CSS::PolarColorSpace polar_color_space { CSS::PolarColorSpace::Oklch }; - CSS::HueInterpolationMethod hue_interpolation_method { CSS::HueInterpolationMethod::Shorter }; -}; - struct DisplayListGradientColorStops { DisplayListDataSpan colors; DisplayListDataSpan positions; @@ -242,7 +230,7 @@ struct PaintLinearGradient { DisplayListGradientColorStops color_stops; float first_stop_position { 0.0f }; float repeat_length { 1.0f }; - DisplayListColorInterpolationMethod interpolation_method; + Gfx::GradientInterpolationMethod interpolation_method; [[nodiscard]] Gfx::IntRect bounding_rect() const { return gradient_rect; } @@ -462,7 +450,7 @@ struct PaintRadialGradient { Gfx::IntRect rect; DisplayListGradientColorStops color_stops; - DisplayListColorInterpolationMethod interpolation_method; + Gfx::GradientInterpolationMethod interpolation_method; Gfx::IntPoint center; Gfx::IntSize size; @@ -478,7 +466,7 @@ struct PaintConicGradient { Gfx::IntRect rect; float start_angle { 0.0f }; DisplayListGradientColorStops color_stops; - DisplayListColorInterpolationMethod interpolation_method; + Gfx::GradientInterpolationMethod interpolation_method; Gfx::IntPoint position; [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index 2c90c1a78d..88e5f625f7 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -299,72 +299,72 @@ void DisplayListPlayerSkia::translate(Translate const& command) canvas.translate(command.delta.x(), command.delta.y()); } -static SkGradientShader::Interpolation to_skia_interpolation(DisplayListColorInterpolationMethod interpolation_method) +static SkGradientShader::Interpolation to_skia_interpolation(Gfx::GradientInterpolationMethod interpolation_method) { SkGradientShader::Interpolation interpolation; - if (interpolation_method.type == DisplayListColorInterpolationMethod::Type::Rectangular) { + if (interpolation_method.type == Gfx::GradientInterpolationMethod::Type::Rectangular) { switch (interpolation_method.rectangular_color_space) { - case CSS::RectangularColorSpace::Srgb: + case Gfx::RectangularColorSpace::Srgb: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB; break; - case CSS::RectangularColorSpace::SrgbLinear: + case Gfx::RectangularColorSpace::SrgbLinear: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGBLinear; break; - case CSS::RectangularColorSpace::Lab: + case Gfx::RectangularColorSpace::Lab: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kLab; break; - case CSS::RectangularColorSpace::Oklab: + case Gfx::RectangularColorSpace::Oklab: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLab; break; - case CSS::RectangularColorSpace::DisplayP3: + case Gfx::RectangularColorSpace::DisplayP3: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kDisplayP3; break; - case CSS::RectangularColorSpace::A98Rgb: + case Gfx::RectangularColorSpace::A98Rgb: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kA98RGB; break; - case CSS::RectangularColorSpace::ProphotoRgb: + case Gfx::RectangularColorSpace::ProphotoRgb: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kProphotoRGB; break; - case CSS::RectangularColorSpace::Rec2020: + case Gfx::RectangularColorSpace::Rec2020: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kRec2020; break; - case CSS::RectangularColorSpace::DisplayP3Linear: - case CSS::RectangularColorSpace::XyzD50: - case CSS::RectangularColorSpace::XyzD65: + case Gfx::RectangularColorSpace::DisplayP3Linear: + case Gfx::RectangularColorSpace::XyzD50: + case Gfx::RectangularColorSpace::XyzD65: dbgln("FIXME: Unsupported gradient color space"); interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLab; break; - case CSS::RectangularColorSpace::Xyz: + case Gfx::RectangularColorSpace::Xyz: VERIFY_NOT_REACHED(); } } else { switch (interpolation_method.polar_color_space) { - case CSS::PolarColorSpace::Hsl: + case Gfx::PolarColorSpace::Hsl: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kHSL; break; - case CSS::PolarColorSpace::Hwb: + case Gfx::PolarColorSpace::Hwb: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kHWB; break; - case CSS::PolarColorSpace::Lch: + case Gfx::PolarColorSpace::Lch: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kLCH; break; - case CSS::PolarColorSpace::Oklch: + case Gfx::PolarColorSpace::Oklch: interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLCH; break; } switch (interpolation_method.hue_interpolation_method) { - case CSS::HueInterpolationMethod::Shorter: + case Gfx::HueInterpolationMethod::Shorter: interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kShorter; break; - case CSS::HueInterpolationMethod::Longer: + case Gfx::HueInterpolationMethod::Longer: interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kLonger; break; - case CSS::HueInterpolationMethod::Increasing: + case Gfx::HueInterpolationMethod::Increasing: interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kIncreasing; break; - case CSS::HueInterpolationMethod::Decreasing: + case Gfx::HueInterpolationMethod::Decreasing: interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kDecreasing; break; } diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index a3ac2a3dbd..affe9ca25f 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -94,19 +94,80 @@ private: Vector m_inline_payload; }; -static DisplayListColorInterpolationMethod to_display_list_color_interpolation_method( +static Gfx::RectangularColorSpace to_gfx_rectangular_color_space(CSS::RectangularColorSpace color_space) +{ + switch (color_space) { + case CSS::RectangularColorSpace::Srgb: + return Gfx::RectangularColorSpace::Srgb; + case CSS::RectangularColorSpace::SrgbLinear: + return Gfx::RectangularColorSpace::SrgbLinear; + case CSS::RectangularColorSpace::DisplayP3: + return Gfx::RectangularColorSpace::DisplayP3; + case CSS::RectangularColorSpace::DisplayP3Linear: + return Gfx::RectangularColorSpace::DisplayP3Linear; + case CSS::RectangularColorSpace::A98Rgb: + return Gfx::RectangularColorSpace::A98Rgb; + case CSS::RectangularColorSpace::ProphotoRgb: + return Gfx::RectangularColorSpace::ProphotoRgb; + case CSS::RectangularColorSpace::Rec2020: + return Gfx::RectangularColorSpace::Rec2020; + case CSS::RectangularColorSpace::Lab: + return Gfx::RectangularColorSpace::Lab; + case CSS::RectangularColorSpace::Oklab: + return Gfx::RectangularColorSpace::Oklab; + case CSS::RectangularColorSpace::Xyz: + return Gfx::RectangularColorSpace::Xyz; + case CSS::RectangularColorSpace::XyzD50: + return Gfx::RectangularColorSpace::XyzD50; + case CSS::RectangularColorSpace::XyzD65: + return Gfx::RectangularColorSpace::XyzD65; + } + VERIFY_NOT_REACHED(); +} + +static Gfx::PolarColorSpace to_gfx_polar_color_space(CSS::PolarColorSpace color_space) +{ + switch (color_space) { + case CSS::PolarColorSpace::Hsl: + return Gfx::PolarColorSpace::Hsl; + case CSS::PolarColorSpace::Hwb: + return Gfx::PolarColorSpace::Hwb; + case CSS::PolarColorSpace::Lch: + return Gfx::PolarColorSpace::Lch; + case CSS::PolarColorSpace::Oklch: + return Gfx::PolarColorSpace::Oklch; + } + VERIFY_NOT_REACHED(); +} + +static Gfx::HueInterpolationMethod to_gfx_hue_interpolation_method(CSS::HueInterpolationMethod hue_interpolation_method) +{ + switch (hue_interpolation_method) { + case CSS::HueInterpolationMethod::Shorter: + return Gfx::HueInterpolationMethod::Shorter; + case CSS::HueInterpolationMethod::Longer: + return Gfx::HueInterpolationMethod::Longer; + case CSS::HueInterpolationMethod::Increasing: + return Gfx::HueInterpolationMethod::Increasing; + case CSS::HueInterpolationMethod::Decreasing: + return Gfx::HueInterpolationMethod::Decreasing; + } + VERIFY_NOT_REACHED(); +} + +static Gfx::GradientInterpolationMethod to_display_list_color_interpolation_method( CSS::ColorInterpolationMethodStyleValue::ColorInterpolationMethod const& interpolation_method) { - DisplayListColorInterpolationMethod result; + Gfx::GradientInterpolationMethod result; interpolation_method.visit( [&](CSS::RectangularColorSpace color_space) { - result.type = DisplayListColorInterpolationMethod::Type::Rectangular; - result.rectangular_color_space = color_space; + result.type = Gfx::GradientInterpolationMethod::Type::Rectangular; + result.rectangular_color_space = to_gfx_rectangular_color_space(color_space); }, [&](CSS::ColorInterpolationMethodStyleValue::PolarColorInterpolationMethod const& color_space) { - result.type = DisplayListColorInterpolationMethod::Type::Polar; - result.polar_color_space = color_space.color_space; - result.hue_interpolation_method = color_space.hue_interpolation_method; + result.type = Gfx::GradientInterpolationMethod::Type::Polar; + result.polar_color_space = to_gfx_polar_color_space(color_space.color_space); + result.hue_interpolation_method = to_gfx_hue_interpolation_method(color_space.hue_interpolation_method); }); return result; }