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.
This commit is contained in:
Aliaksandr Kalenik 2026-05-11 18:15:04 +02:00 committed by Alexander Kalenik
parent b50b7a41d7
commit b25d3561d6
4 changed files with 148 additions and 45 deletions

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
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 };
};
}

View file

@ -14,6 +14,7 @@
#include <LibGfx/AffineTransform.h>
#include <LibGfx/Color.h>
#include <LibGfx/CompositingAndBlendingOperator.h>
#include <LibGfx/GradientInterpolation.h>
#include <LibGfx/InterpolationColorSpace.h>
#include <LibGfx/LineStyle.h>
#include <LibGfx/Path.h>
@ -21,7 +22,6 @@
#include <LibGfx/Rect.h>
#include <LibGfx/ScalingMode.h>
#include <LibGfx/Size.h>
#include <LibWeb/CSS/ComputedValues.h>
#include <LibWeb/Painting/AccumulatedVisualContext.h>
#include <LibWeb/Painting/BorderRadiiData.h>
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
@ -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; }

View file

@ -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;
}

View file

@ -94,19 +94,80 @@ private:
Vector<u8> 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;
}