mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-18 07:22:22 +00:00
LibWeb: Implement css gradient-interpolation-method
This commit is contained in:
parent
02a642b87b
commit
31853c13d3
Notes:
github-actions[bot]
2025-03-06 11:34:14 +00:00
Author: https://github.com/Gingeh
Commit: 31853c13d3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3638
Reviewed-by: https://github.com/AtkinsSJ ✅
Reviewed-by: https://github.com/LucasChollet
35 changed files with 499 additions and 101 deletions
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/CSS/Enums.h>
|
||||
#include <LibWeb/CSS/PercentageOr.h>
|
||||
#include <LibWeb/CSS/Serialize.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSColorValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
|
@ -48,6 +49,112 @@ enum class GradientRepeating {
|
|||
No
|
||||
};
|
||||
|
||||
enum class GradientSpace : u8 {
|
||||
sRGB,
|
||||
sRGBLinear,
|
||||
DisplayP3,
|
||||
A98RGB,
|
||||
ProPhotoRGB,
|
||||
Rec2020,
|
||||
Lab,
|
||||
OKLab,
|
||||
XYZD50,
|
||||
XYZD65,
|
||||
HSL,
|
||||
HWB,
|
||||
LCH,
|
||||
OKLCH,
|
||||
};
|
||||
|
||||
enum class HueMethod : u8 {
|
||||
Shorter,
|
||||
Longer,
|
||||
Increasing,
|
||||
Decreasing,
|
||||
};
|
||||
|
||||
struct InterpolationMethod {
|
||||
GradientSpace color_space;
|
||||
HueMethod hue_method = HueMethod::Shorter;
|
||||
|
||||
String to_string() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
|
||||
switch (color_space) {
|
||||
case GradientSpace::OKLab:
|
||||
builder.append("in oklab"sv);
|
||||
break;
|
||||
case GradientSpace::sRGB:
|
||||
builder.append("in srgb"sv);
|
||||
break;
|
||||
case GradientSpace::sRGBLinear:
|
||||
builder.append("in srgb-linear"sv);
|
||||
break;
|
||||
case GradientSpace::DisplayP3:
|
||||
builder.append("in display-p3"sv);
|
||||
break;
|
||||
case GradientSpace::A98RGB:
|
||||
builder.append("in a98-rgb"sv);
|
||||
break;
|
||||
case GradientSpace::ProPhotoRGB:
|
||||
builder.append("in prophoto-rgb"sv);
|
||||
break;
|
||||
case GradientSpace::Rec2020:
|
||||
builder.append("in rec2020"sv);
|
||||
break;
|
||||
case GradientSpace::Lab:
|
||||
builder.append("in lab"sv);
|
||||
break;
|
||||
case GradientSpace::XYZD50:
|
||||
builder.append("in xyz-d50"sv);
|
||||
break;
|
||||
case GradientSpace::XYZD65:
|
||||
builder.append("in xyz-d65"sv);
|
||||
break;
|
||||
case GradientSpace::HSL:
|
||||
builder.append("in hsl"sv);
|
||||
break;
|
||||
case GradientSpace::HWB:
|
||||
builder.append("in hwb"sv);
|
||||
break;
|
||||
case GradientSpace::LCH:
|
||||
builder.append("in lch"sv);
|
||||
break;
|
||||
case GradientSpace::OKLCH:
|
||||
builder.append("in oklch"sv);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (hue_method) {
|
||||
case HueMethod::Shorter:
|
||||
// "shorter" is the default value and isn't serialized
|
||||
break;
|
||||
case HueMethod::Longer:
|
||||
builder.append(" longer hue"sv);
|
||||
break;
|
||||
case HueMethod::Increasing:
|
||||
builder.append(" increasing hue"sv);
|
||||
break;
|
||||
case HueMethod::Decreasing:
|
||||
builder.append(" decreasing hue"sv);
|
||||
break;
|
||||
}
|
||||
|
||||
return MUST(builder.to_string());
|
||||
}
|
||||
|
||||
static GradientSpace default_color_space(ColorSyntax color_syntax)
|
||||
{
|
||||
if (color_syntax == ColorSyntax::Legacy)
|
||||
return GradientSpace::sRGB;
|
||||
|
||||
return GradientSpace::OKLab;
|
||||
}
|
||||
|
||||
bool operator==(InterpolationMethod const&) const = default;
|
||||
};
|
||||
|
||||
template<typename TPosition>
|
||||
struct ColorStopListElement {
|
||||
using PositionType = TPosition;
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
|
||||
private:
|
||||
CSSColor(ColorType color_type, ValueComparingNonnullRefPtr<CSSStyleValue> c1, ValueComparingNonnullRefPtr<CSSStyleValue> c2, ValueComparingNonnullRefPtr<CSSStyleValue> c3, ValueComparingNonnullRefPtr<CSSStyleValue> alpha)
|
||||
: CSSColorValue(color_type)
|
||||
: CSSColorValue(color_type, ColorSyntax::Modern)
|
||||
, m_properties { .channels = { move(c1), move(c2), move(c3) }, .alpha = move(alpha) }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
ValueComparingNonnullRefPtr<CSSColorValue> CSSColorValue::create_from_color(Color color, Optional<FlyString> name)
|
||||
ValueComparingNonnullRefPtr<CSSColorValue> CSSColorValue::create_from_color(Color color, ColorSyntax color_syntax, Optional<FlyString> name)
|
||||
{
|
||||
return CSSRGB::create(
|
||||
NumberStyleValue::create(color.red()),
|
||||
NumberStyleValue::create(color.green()),
|
||||
NumberStyleValue::create(color.blue()),
|
||||
NumberStyleValue::create(color.alpha() / 255.0),
|
||||
color_syntax,
|
||||
name);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,15 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
enum class ColorSyntax : u8 {
|
||||
Legacy,
|
||||
Modern,
|
||||
};
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#csscolorvalue
|
||||
class CSSColorValue : public CSSStyleValue {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<CSSColorValue> create_from_color(Color color, Optional<FlyString> name = {});
|
||||
static ValueComparingNonnullRefPtr<CSSColorValue> create_from_color(Color color, ColorSyntax color_syntax, Optional<FlyString> name = {});
|
||||
virtual ~CSSColorValue() override = default;
|
||||
|
||||
virtual bool has_color() const override { return true; }
|
||||
|
@ -42,11 +47,13 @@ public:
|
|||
LightDark, // This is used by CSSLightDark for light-dark(..., ...).
|
||||
};
|
||||
ColorType color_type() const { return m_color_type; }
|
||||
ColorSyntax color_syntax() const { return m_color_syntax; }
|
||||
|
||||
protected:
|
||||
explicit CSSColorValue(ColorType color_type)
|
||||
explicit CSSColorValue(ColorType color_type, ColorSyntax color_syntax)
|
||||
: CSSStyleValue(Type::Color)
|
||||
, m_color_type(color_type)
|
||||
, m_color_syntax(color_syntax)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +62,7 @@ protected:
|
|||
static Optional<double> resolve_alpha(CSSStyleValue const&);
|
||||
|
||||
ColorType m_color_type;
|
||||
ColorSyntax m_color_syntax;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@ namespace Web::CSS {
|
|||
// https://drafts.css-houdini.org/css-typed-om-1/#csshsl
|
||||
class CSSHSL final : public CSSColorValue {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<CSSHSL> create(ValueComparingNonnullRefPtr<CSSStyleValue> h, ValueComparingNonnullRefPtr<CSSStyleValue> s, ValueComparingNonnullRefPtr<CSSStyleValue> l, ValueComparingRefPtr<CSSStyleValue> alpha = {})
|
||||
static ValueComparingNonnullRefPtr<CSSHSL> create(ValueComparingNonnullRefPtr<CSSStyleValue> h, ValueComparingNonnullRefPtr<CSSStyleValue> s, ValueComparingNonnullRefPtr<CSSStyleValue> l, ValueComparingRefPtr<CSSStyleValue> alpha, ColorSyntax color_syntax)
|
||||
{
|
||||
// alpha defaults to 1
|
||||
if (!alpha)
|
||||
return adopt_ref(*new (nothrow) CSSHSL(move(h), move(s), move(l), NumberStyleValue::create(1)));
|
||||
return adopt_ref(*new (nothrow) CSSHSL(move(h), move(s), move(l), NumberStyleValue::create(1), color_syntax));
|
||||
|
||||
return adopt_ref(*new (nothrow) CSSHSL(move(h), move(s), move(l), alpha.release_nonnull()));
|
||||
return adopt_ref(*new (nothrow) CSSHSL(move(h), move(s), move(l), alpha.release_nonnull(), color_syntax));
|
||||
}
|
||||
virtual ~CSSHSL() override = default;
|
||||
|
||||
|
@ -36,8 +36,8 @@ public:
|
|||
virtual bool equals(CSSStyleValue const& other) const override;
|
||||
|
||||
private:
|
||||
CSSHSL(ValueComparingNonnullRefPtr<CSSStyleValue> h, ValueComparingNonnullRefPtr<CSSStyleValue> s, ValueComparingNonnullRefPtr<CSSStyleValue> l, ValueComparingNonnullRefPtr<CSSStyleValue> alpha)
|
||||
: CSSColorValue(ColorType::HSL)
|
||||
CSSHSL(ValueComparingNonnullRefPtr<CSSStyleValue> h, ValueComparingNonnullRefPtr<CSSStyleValue> s, ValueComparingNonnullRefPtr<CSSStyleValue> l, ValueComparingNonnullRefPtr<CSSStyleValue> alpha, ColorSyntax color_syntax)
|
||||
: CSSColorValue(ColorType::HSL, color_syntax)
|
||||
, m_properties { .h = move(h), .s = move(s), .l = move(l), .alpha = move(alpha) }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
|
||||
private:
|
||||
CSSHWB(ValueComparingNonnullRefPtr<CSSStyleValue> h, ValueComparingNonnullRefPtr<CSSStyleValue> w, ValueComparingNonnullRefPtr<CSSStyleValue> b, ValueComparingNonnullRefPtr<CSSStyleValue> alpha)
|
||||
: CSSColorValue(ColorType::HWB)
|
||||
: CSSColorValue(ColorType::HWB, ColorSyntax::Modern)
|
||||
, m_properties { .h = move(h), .w = move(w), .b = move(b), .alpha = move(alpha) }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
protected:
|
||||
CSSLCHLike(ColorType color_type, ValueComparingNonnullRefPtr<CSSStyleValue> l, ValueComparingNonnullRefPtr<CSSStyleValue> c, ValueComparingNonnullRefPtr<CSSStyleValue> h, ValueComparingNonnullRefPtr<CSSStyleValue> alpha)
|
||||
: CSSColorValue(color_type)
|
||||
: CSSColorValue(color_type, ColorSyntax::Modern)
|
||||
, m_properties { .l = move(l), .c = move(c), .h = move(h), .alpha = move(alpha) }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
|
||||
protected:
|
||||
CSSLabLike(ColorType color_type, ValueComparingNonnullRefPtr<CSSStyleValue> l, ValueComparingNonnullRefPtr<CSSStyleValue> a, ValueComparingNonnullRefPtr<CSSStyleValue> b, ValueComparingNonnullRefPtr<CSSStyleValue> alpha)
|
||||
: CSSColorValue(color_type)
|
||||
: CSSColorValue(color_type, ColorSyntax::Modern)
|
||||
, m_properties { .l = move(l), .a = move(a), .b = move(b), .alpha = move(alpha) }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
private:
|
||||
CSSLightDark(ValueComparingNonnullRefPtr<CSSStyleValue> light, ValueComparingNonnullRefPtr<CSSStyleValue> dark)
|
||||
: CSSColorValue(CSSColorValue::ColorType::LightDark)
|
||||
: CSSColorValue(CSSColorValue::ColorType::LightDark, ColorSyntax::Modern)
|
||||
, m_properties { .light = move(light), .dark = move(dark) }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@ namespace Web::CSS {
|
|||
// https://drafts.css-houdini.org/css-typed-om-1/#cssrgb
|
||||
class CSSRGB final : public CSSColorValue {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<CSSRGB> create(ValueComparingNonnullRefPtr<CSSStyleValue> r, ValueComparingNonnullRefPtr<CSSStyleValue> g, ValueComparingNonnullRefPtr<CSSStyleValue> b, ValueComparingRefPtr<CSSStyleValue> alpha = {}, Optional<FlyString> name = {})
|
||||
static ValueComparingNonnullRefPtr<CSSRGB> create(ValueComparingNonnullRefPtr<CSSStyleValue> r, ValueComparingNonnullRefPtr<CSSStyleValue> g, ValueComparingNonnullRefPtr<CSSStyleValue> b, ValueComparingRefPtr<CSSStyleValue> alpha, ColorSyntax color_syntax, Optional<FlyString> name = {})
|
||||
{
|
||||
// alpha defaults to 1
|
||||
if (!alpha)
|
||||
return adopt_ref(*new (nothrow) CSSRGB(move(r), move(g), move(b), NumberStyleValue::create(1), name));
|
||||
return adopt_ref(*new (nothrow) CSSRGB(move(r), move(g), move(b), NumberStyleValue::create(1), color_syntax, name));
|
||||
|
||||
return adopt_ref(*new (nothrow) CSSRGB(move(r), move(g), move(b), alpha.release_nonnull(), name));
|
||||
return adopt_ref(*new (nothrow) CSSRGB(move(r), move(g), move(b), alpha.release_nonnull(), color_syntax, name));
|
||||
}
|
||||
virtual ~CSSRGB() override = default;
|
||||
|
||||
|
@ -36,8 +36,8 @@ public:
|
|||
virtual bool equals(CSSStyleValue const& other) const override;
|
||||
|
||||
private:
|
||||
CSSRGB(ValueComparingNonnullRefPtr<CSSStyleValue> r, ValueComparingNonnullRefPtr<CSSStyleValue> g, ValueComparingNonnullRefPtr<CSSStyleValue> b, ValueComparingNonnullRefPtr<CSSStyleValue> alpha, Optional<FlyString> name = {})
|
||||
: CSSColorValue(ColorType::RGB)
|
||||
CSSRGB(ValueComparingNonnullRefPtr<CSSStyleValue> r, ValueComparingNonnullRefPtr<CSSStyleValue> g, ValueComparingNonnullRefPtr<CSSStyleValue> b, ValueComparingNonnullRefPtr<CSSStyleValue> alpha, ColorSyntax color_syntax, Optional<FlyString> name = {})
|
||||
: CSSColorValue(ColorType::RGB, color_syntax)
|
||||
, m_properties { .r = move(r), .g = move(g), .b = move(b), .alpha = move(alpha), .name = name }
|
||||
{
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ String ConicGradientStyleValue::to_string(SerializationMode mode) const
|
|||
builder.append("conic-gradient("sv);
|
||||
bool has_from_angle = m_properties.from_angle.to_degrees() != 0;
|
||||
bool has_at_position = !m_properties.position->is_center();
|
||||
bool has_color_space = m_properties.interpolation_method.has_value() && m_properties.interpolation_method.value().color_space != InterpolationMethod::default_color_space(m_properties.color_syntax);
|
||||
|
||||
if (has_from_angle)
|
||||
builder.appendff("from {}", m_properties.from_angle.to_string());
|
||||
if (has_at_position) {
|
||||
|
@ -29,7 +31,12 @@ String ConicGradientStyleValue::to_string(SerializationMode mode) const
|
|||
builder.append(' ');
|
||||
builder.appendff("at {}"sv, m_properties.position->to_string(mode));
|
||||
}
|
||||
if (has_from_angle || has_at_position)
|
||||
if (has_color_space) {
|
||||
if (has_from_angle || has_at_position)
|
||||
builder.append(' ');
|
||||
builder.append(m_properties.interpolation_method.value().to_string());
|
||||
}
|
||||
if (has_from_angle || has_at_position || has_color_space)
|
||||
builder.append(", "sv);
|
||||
serialize_color_stop_list(builder, m_properties.color_stop_list, mode);
|
||||
builder.append(')');
|
||||
|
|
|
@ -17,10 +17,11 @@ namespace Web::CSS {
|
|||
|
||||
class ConicGradientStyleValue final : public AbstractImageStyleValue {
|
||||
public:
|
||||
static ValueComparingNonnullRefPtr<ConicGradientStyleValue> create(Angle from_angle, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<AngularColorStopListElement> color_stop_list, GradientRepeating repeating)
|
||||
static ValueComparingNonnullRefPtr<ConicGradientStyleValue> create(Angle from_angle, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<AngularColorStopListElement> color_stop_list, GradientRepeating repeating, Optional<InterpolationMethod> interpolation_method)
|
||||
{
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
return adopt_ref(*new (nothrow) ConicGradientStyleValue(from_angle, move(position), move(color_stop_list), repeating));
|
||||
bool any_non_legacy = color_stop_list.find_first_index_if([](auto const& stop) { return !stop.color_stop.color->is_keyword() && stop.color_stop.color->as_color().color_syntax() == ColorSyntax::Modern; }).has_value();
|
||||
return adopt_ref(*new (nothrow) ConicGradientStyleValue(from_angle, move(position), move(color_stop_list), repeating, interpolation_method, any_non_legacy ? ColorSyntax::Modern : ColorSyntax::Legacy));
|
||||
}
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
@ -34,6 +35,14 @@ public:
|
|||
return m_properties.color_stop_list;
|
||||
}
|
||||
|
||||
InterpolationMethod interpolation_method() const
|
||||
{
|
||||
if (m_properties.interpolation_method.has_value())
|
||||
return m_properties.interpolation_method.value();
|
||||
|
||||
return InterpolationMethod { .color_space = InterpolationMethod::default_color_space(m_properties.color_syntax) };
|
||||
}
|
||||
|
||||
float angle_degrees() const;
|
||||
|
||||
bool is_paintable() const override { return true; }
|
||||
|
@ -45,18 +54,19 @@ public:
|
|||
bool is_repeating() const { return m_properties.repeating == GradientRepeating::Yes; }
|
||||
|
||||
private:
|
||||
ConicGradientStyleValue(Angle from_angle, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<AngularColorStopListElement> color_stop_list, GradientRepeating repeating)
|
||||
ConicGradientStyleValue(Angle from_angle, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<AngularColorStopListElement> color_stop_list, GradientRepeating repeating, Optional<InterpolationMethod> interpolation_method, ColorSyntax color_syntax)
|
||||
: AbstractImageStyleValue(Type::ConicGradient)
|
||||
, m_properties { .from_angle = from_angle, .position = move(position), .color_stop_list = move(color_stop_list), .repeating = repeating }
|
||||
, m_properties { .from_angle = from_angle, .position = move(position), .color_stop_list = move(color_stop_list), .repeating = repeating, .interpolation_method = interpolation_method, .color_syntax = color_syntax }
|
||||
{
|
||||
}
|
||||
|
||||
struct Properties {
|
||||
// FIXME: Support <color-interpolation-method>
|
||||
Angle from_angle;
|
||||
ValueComparingNonnullRefPtr<PositionStyleValue> position;
|
||||
Vector<AngularColorStopListElement> color_stop_list;
|
||||
GradientRepeating repeating;
|
||||
Optional<InterpolationMethod> interpolation_method;
|
||||
ColorSyntax color_syntax;
|
||||
bool operator==(Properties const&) const = default;
|
||||
} m_properties;
|
||||
|
||||
|
|
|
@ -27,30 +27,45 @@ String LinearGradientStyleValue::to_string(SerializationMode mode) const
|
|||
case SideOrCorner::Right:
|
||||
return "right"sv;
|
||||
case SideOrCorner::TopLeft:
|
||||
return "top left"sv;
|
||||
return "left top"sv;
|
||||
case SideOrCorner::TopRight:
|
||||
return "top right"sv;
|
||||
return "right top"sv;
|
||||
case SideOrCorner::BottomLeft:
|
||||
return "bottom left"sv;
|
||||
return "left bottom"sv;
|
||||
case SideOrCorner::BottomRight:
|
||||
return "bottom right"sv;
|
||||
return "right bottom"sv;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
};
|
||||
|
||||
auto default_direction = m_properties.gradient_type == GradientType::WebKit ? SideOrCorner::Top : SideOrCorner::Bottom;
|
||||
bool has_direction = m_properties.direction != default_direction;
|
||||
bool has_color_space = m_properties.interpolation_method.has_value() && m_properties.interpolation_method.value().color_space != InterpolationMethod::default_color_space(m_properties.color_syntax);
|
||||
|
||||
if (m_properties.gradient_type == GradientType::WebKit)
|
||||
builder.append("-webkit-"sv);
|
||||
if (is_repeating())
|
||||
builder.append("repeating-"sv);
|
||||
builder.append("linear-gradient("sv);
|
||||
m_properties.direction.visit(
|
||||
[&](SideOrCorner side_or_corner) {
|
||||
return builder.appendff("{}{}, "sv, m_properties.gradient_type == GradientType::Standard ? "to "sv : ""sv, side_or_corner_to_string(side_or_corner));
|
||||
},
|
||||
[&](Angle const& angle) {
|
||||
return builder.appendff("{}, "sv, angle.to_string());
|
||||
});
|
||||
if (has_direction) {
|
||||
m_properties.direction.visit(
|
||||
[&](SideOrCorner side_or_corner) {
|
||||
builder.appendff("{}{}"sv, m_properties.gradient_type == GradientType::Standard ? "to "sv : ""sv, side_or_corner_to_string(side_or_corner));
|
||||
},
|
||||
[&](Angle const& angle) {
|
||||
builder.append(angle.to_string());
|
||||
});
|
||||
|
||||
if (has_color_space)
|
||||
builder.append(' ');
|
||||
}
|
||||
|
||||
if (has_color_space)
|
||||
builder.append(m_properties.interpolation_method.value().to_string());
|
||||
|
||||
if (has_direction || has_color_space)
|
||||
builder.append(", "sv);
|
||||
|
||||
serialize_color_stop_list(builder, m_properties.color_stop_list, mode);
|
||||
builder.append(")"sv);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/CSS/Angle.h>
|
||||
#include <LibWeb/CSS/Percentage.h>
|
||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CSSColorValue.h>
|
||||
#include <LibWeb/Painting/GradientPainting.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
@ -38,10 +39,11 @@ public:
|
|||
WebKit
|
||||
};
|
||||
|
||||
static ValueComparingNonnullRefPtr<LinearGradientStyleValue> create(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating)
|
||||
static ValueComparingNonnullRefPtr<LinearGradientStyleValue> create(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating, Optional<InterpolationMethod> interpolation_method)
|
||||
{
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
return adopt_ref(*new (nothrow) LinearGradientStyleValue(direction, move(color_stop_list), type, repeating));
|
||||
bool any_non_legacy = color_stop_list.find_first_index_if([](auto const& stop) { return !stop.color_stop.color->is_keyword() && stop.color_stop.color->as_color().color_syntax() == ColorSyntax::Modern; }).has_value();
|
||||
return adopt_ref(*new (nothrow) LinearGradientStyleValue(direction, move(color_stop_list), type, repeating, interpolation_method, any_non_legacy ? ColorSyntax::Modern : ColorSyntax::Legacy));
|
||||
}
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
@ -53,6 +55,17 @@ public:
|
|||
return m_properties.color_stop_list;
|
||||
}
|
||||
|
||||
// FIXME: This (and the any_non_legacy code in the constructor) is duplicated in the separate gradient classes,
|
||||
// should this logic be pulled into some kind of GradientStyleValue superclass?
|
||||
// It could also contain the "gradient related things" currently in AbstractImageStyleValue.h
|
||||
InterpolationMethod interpolation_method() const
|
||||
{
|
||||
if (m_properties.interpolation_method.has_value())
|
||||
return m_properties.interpolation_method.value();
|
||||
|
||||
return InterpolationMethod { .color_space = InterpolationMethod::default_color_space(m_properties.color_syntax) };
|
||||
}
|
||||
|
||||
bool is_repeating() const { return m_properties.repeating == GradientRepeating::Yes; }
|
||||
|
||||
float angle_degrees(CSSPixelSize gradient_size) const;
|
||||
|
@ -63,9 +76,9 @@ public:
|
|||
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
|
||||
|
||||
private:
|
||||
LinearGradientStyleValue(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating)
|
||||
LinearGradientStyleValue(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating, Optional<InterpolationMethod> interpolation_method, ColorSyntax color_syntax)
|
||||
: AbstractImageStyleValue(Type::LinearGradient)
|
||||
, m_properties { .direction = direction, .color_stop_list = move(color_stop_list), .gradient_type = type, .repeating = repeating }
|
||||
, m_properties { .direction = direction, .color_stop_list = move(color_stop_list), .gradient_type = type, .repeating = repeating, .interpolation_method = interpolation_method, .color_syntax = color_syntax }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -74,6 +87,8 @@ private:
|
|||
Vector<LinearColorStopListElement> color_stop_list;
|
||||
GradientType gradient_type;
|
||||
GradientRepeating repeating;
|
||||
Optional<InterpolationMethod> interpolation_method;
|
||||
ColorSyntax color_syntax;
|
||||
bool operator==(Properties const&) const = default;
|
||||
} m_properties;
|
||||
|
||||
|
|
|
@ -19,8 +19,11 @@ String RadialGradientStyleValue::to_string(SerializationMode mode) const
|
|||
StringBuilder builder;
|
||||
if (is_repeating())
|
||||
builder.append("repeating-"sv);
|
||||
builder.appendff("radial-gradient({} "sv,
|
||||
m_properties.ending_shape == EndingShape::Circle ? "circle"sv : "ellipse"sv);
|
||||
builder.appendff("radial-gradient("sv);
|
||||
|
||||
bool has_size = !m_properties.size.has<Extent>() || m_properties.size.get<Extent>() != Extent::FarthestCorner;
|
||||
bool has_position = !m_properties.position->is_center();
|
||||
bool has_color_space = m_properties.interpolation_method.has_value() && m_properties.interpolation_method.value().color_space != InterpolationMethod::default_color_space(m_properties.color_syntax);
|
||||
|
||||
m_properties.size.visit(
|
||||
[&](Extent extent) {
|
||||
|
@ -31,7 +34,8 @@ String RadialGradientStyleValue::to_string(SerializationMode mode) const
|
|||
case Extent::ClosestSide:
|
||||
return "closest-side"sv;
|
||||
case Extent::FarthestCorner:
|
||||
return "farthest-corner"sv;
|
||||
// "farthest-corner" is the default value and isn't serialized
|
||||
return ""sv;
|
||||
case Extent::FarthestSide:
|
||||
return "farthest-side"sv;
|
||||
default:
|
||||
|
@ -46,10 +50,23 @@ String RadialGradientStyleValue::to_string(SerializationMode mode) const
|
|||
builder.appendff("{} {}", ellipse_size.radius_a.to_string(), ellipse_size.radius_b.to_string());
|
||||
});
|
||||
|
||||
if (!m_properties.position->is_center())
|
||||
builder.appendff(" at {}"sv, m_properties.position->to_string(mode));
|
||||
if (has_position) {
|
||||
if (has_size)
|
||||
builder.append(' ');
|
||||
|
||||
builder.appendff("at {}"sv, m_properties.position->to_string(mode));
|
||||
}
|
||||
|
||||
if (has_color_space) {
|
||||
if (has_size || has_position)
|
||||
builder.append(' ');
|
||||
|
||||
builder.append(m_properties.interpolation_method.value().to_string());
|
||||
}
|
||||
|
||||
if (has_size || has_position || has_color_space)
|
||||
builder.append(", "sv);
|
||||
|
||||
builder.append(", "sv);
|
||||
serialize_color_stop_list(builder, m_properties.color_stop_list, mode);
|
||||
builder.append(')');
|
||||
return MUST(builder.to_string());
|
||||
|
|
|
@ -43,10 +43,11 @@ public:
|
|||
|
||||
using Size = Variant<Extent, CircleSize, EllipseSize>;
|
||||
|
||||
static ValueComparingNonnullRefPtr<RadialGradientStyleValue> create(EndingShape ending_shape, Size size, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<LinearColorStopListElement> color_stop_list, GradientRepeating repeating)
|
||||
static ValueComparingNonnullRefPtr<RadialGradientStyleValue> create(EndingShape ending_shape, Size size, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<LinearColorStopListElement> color_stop_list, GradientRepeating repeating, Optional<InterpolationMethod> interpolation_method)
|
||||
{
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
return adopt_ref(*new (nothrow) RadialGradientStyleValue(ending_shape, size, move(position), move(color_stop_list), repeating));
|
||||
bool any_non_legacy = color_stop_list.find_first_index_if([](auto const& stop) { return !stop.color_stop.color->is_keyword() && stop.color_stop.color->as_color().color_syntax() == ColorSyntax::Modern; }).has_value();
|
||||
return adopt_ref(*new (nothrow) RadialGradientStyleValue(ending_shape, size, move(position), move(color_stop_list), repeating, interpolation_method, any_non_legacy ? ColorSyntax::Modern : ColorSyntax::Legacy));
|
||||
}
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
@ -60,6 +61,14 @@ public:
|
|||
return m_properties.color_stop_list;
|
||||
}
|
||||
|
||||
InterpolationMethod interpolation_method() const
|
||||
{
|
||||
if (m_properties.interpolation_method.has_value())
|
||||
return m_properties.interpolation_method.value();
|
||||
|
||||
return InterpolationMethod { .color_space = InterpolationMethod::default_color_space(m_properties.color_syntax) };
|
||||
}
|
||||
|
||||
bool is_paintable() const override { return true; }
|
||||
|
||||
void resolve_for_size(Layout::NodeWithStyle const&, CSSPixelSize) const override;
|
||||
|
@ -71,9 +80,9 @@ public:
|
|||
virtual ~RadialGradientStyleValue() override = default;
|
||||
|
||||
private:
|
||||
RadialGradientStyleValue(EndingShape ending_shape, Size size, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<LinearColorStopListElement> color_stop_list, GradientRepeating repeating)
|
||||
RadialGradientStyleValue(EndingShape ending_shape, Size size, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<LinearColorStopListElement> color_stop_list, GradientRepeating repeating, Optional<InterpolationMethod> interpolation_method, ColorSyntax color_syntax)
|
||||
: AbstractImageStyleValue(Type::RadialGradient)
|
||||
, m_properties { .ending_shape = ending_shape, .size = size, .position = move(position), .color_stop_list = move(color_stop_list), .repeating = repeating }
|
||||
, m_properties { .ending_shape = ending_shape, .size = size, .position = move(position), .color_stop_list = move(color_stop_list), .repeating = repeating, .interpolation_method = interpolation_method, .color_syntax = color_syntax }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -83,6 +92,8 @@ private:
|
|||
ValueComparingNonnullRefPtr<PositionStyleValue> position;
|
||||
Vector<LinearColorStopListElement> color_stop_list;
|
||||
GradientRepeating repeating;
|
||||
Optional<InterpolationMethod> interpolation_method;
|
||||
ColorSyntax color_syntax;
|
||||
bool operator==(Properties const&) const = default;
|
||||
} m_properties;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue