mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +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: https://github.com/LadybirdBrowser/ladybird/commit/31853c13d3c 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
|
@ -465,7 +465,7 @@ NonnullRefPtr<CSSStyleValue const> interpolate_box_shadow(DOM::Element& element,
|
|||
values.ensure_capacity(other.size());
|
||||
for (size_t i = values.size(); i < other.size(); i++) {
|
||||
values.unchecked_append(ShadowStyleValue::create(
|
||||
CSSColorValue::create_from_color(Color::Transparent),
|
||||
CSSColorValue::create_from_color(Color::Transparent, ColorSyntax::Legacy),
|
||||
LengthStyleValue::create(Length::make_px(0)),
|
||||
LengthStyleValue::create(Length::make_px(0)),
|
||||
LengthStyleValue::create(Length::make_px(0)),
|
||||
|
@ -488,7 +488,7 @@ NonnullRefPtr<CSSStyleValue const> interpolate_box_shadow(DOM::Element& element,
|
|||
auto const& from_shadow = from_shadows[i]->as_shadow();
|
||||
auto const& to_shadow = to_shadows[i]->as_shadow();
|
||||
auto result_shadow = ShadowStyleValue::create(
|
||||
CSSColorValue::create_from_color(interpolate_color(from_shadow.color()->to_color({}), to_shadow.color()->to_color({}), delta)),
|
||||
CSSColorValue::create_from_color(interpolate_color(from_shadow.color()->to_color({}), to_shadow.color()->to_color({}), delta), ColorSyntax::Modern),
|
||||
interpolate_value(element, calculation_context, from_shadow.offset_x(), to_shadow.offset_x(), delta),
|
||||
interpolate_value(element, calculation_context, from_shadow.offset_y(), to_shadow.offset_y(), delta),
|
||||
interpolate_value(element, calculation_context, from_shadow.blur_radius(), to_shadow.blur_radius(), delta),
|
||||
|
@ -584,7 +584,7 @@ NonnullRefPtr<CSSStyleValue const> interpolate_value(DOM::Element& element, Calc
|
|||
Optional<Layout::NodeWithStyle const&> layout_node;
|
||||
if (auto node = element.layout_node())
|
||||
layout_node = *node;
|
||||
return CSSColorValue::create_from_color(interpolate_color(from.to_color(layout_node), to.to_color(layout_node), delta));
|
||||
return CSSColorValue::create_from_color(interpolate_color(from.to_color(layout_node), to.to_color(layout_node), delta), ColorSyntax::Modern);
|
||||
}
|
||||
case CSSStyleValue::Type::Integer:
|
||||
return IntegerStyleValue::create(interpolate_raw(from.as_integer().integer(), to.as_integer().integer(), delta));
|
||||
|
|
|
@ -128,6 +128,101 @@ Optional<Vector<AngularColorStopListElement>> Parser::parse_angular_color_stop_l
|
|||
[&](auto& it) { return parse_angle_percentage(it); });
|
||||
}
|
||||
|
||||
Optional<InterpolationMethod> Parser::parse_interpolation_method(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// <color-interpolation-method> = in [ <rectangular-color-space> | <polar-color-space> <hue-interpolation-method>? ]
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
if (!tokens.consume_a_token().is_ident("in"sv))
|
||||
return {};
|
||||
|
||||
tokens.discard_whitespace();
|
||||
auto first_value = tokens.consume_a_token();
|
||||
if (!first_value.is(Token::Type::Ident))
|
||||
return {};
|
||||
|
||||
auto color_space_name = first_value.token().ident();
|
||||
GradientSpace color_space;
|
||||
bool polar_space = false;
|
||||
|
||||
if (color_space_name.equals_ignoring_ascii_case("srgb"sv)) {
|
||||
color_space = GradientSpace::sRGB;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("srgb-linear"sv)) {
|
||||
color_space = GradientSpace::sRGBLinear;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("display-p3"sv)) {
|
||||
color_space = GradientSpace::DisplayP3;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("a98-rgb"sv)) {
|
||||
color_space = GradientSpace::A98RGB;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("prophoto-rgb"sv)) {
|
||||
color_space = GradientSpace::ProPhotoRGB;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("rec2020"sv)) {
|
||||
color_space = GradientSpace::Rec2020;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("lab"sv)) {
|
||||
color_space = GradientSpace::Lab;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("oklab"sv)) {
|
||||
color_space = GradientSpace::OKLab;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("xyz-d50"sv)) {
|
||||
color_space = GradientSpace::XYZD50;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("xyz-d65"sv)
|
||||
|| color_space_name.equals_ignoring_ascii_case("xyz"sv)) {
|
||||
color_space = GradientSpace::XYZD65;
|
||||
} else {
|
||||
polar_space = true;
|
||||
if (color_space_name.equals_ignoring_ascii_case("hsl"sv)) {
|
||||
color_space = GradientSpace::HSL;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("hwb"sv)) {
|
||||
color_space = GradientSpace::HWB;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("lch"sv)) {
|
||||
color_space = GradientSpace::LCH;
|
||||
} else if (color_space_name.equals_ignoring_ascii_case("oklch"sv)) {
|
||||
color_space = GradientSpace::OKLCH;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<HueMethod> hue_method;
|
||||
if (polar_space) {
|
||||
[&]() {
|
||||
auto hue_transaction = transaction.create_child();
|
||||
|
||||
tokens.discard_whitespace();
|
||||
auto second_value = tokens.consume_a_token();
|
||||
if (!second_value.is(Token::Type::Ident))
|
||||
return;
|
||||
|
||||
auto hue_method_name = second_value.token().ident();
|
||||
if (hue_method_name.equals_ignoring_ascii_case("shorter"sv)) {
|
||||
hue_method = HueMethod::Shorter;
|
||||
} else if (hue_method_name.equals_ignoring_ascii_case("longer"sv)) {
|
||||
hue_method = HueMethod::Longer;
|
||||
} else if (hue_method_name.equals_ignoring_ascii_case("increasing"sv)) {
|
||||
hue_method = HueMethod::Increasing;
|
||||
} else if (hue_method_name.equals_ignoring_ascii_case("decreasing"sv)) {
|
||||
hue_method = HueMethod::Decreasing;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
tokens.discard_whitespace();
|
||||
if (!tokens.consume_a_token().is_ident("hue"sv))
|
||||
return;
|
||||
|
||||
hue_transaction.commit();
|
||||
}();
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
|
||||
InterpolationMethod interpolation_method;
|
||||
interpolation_method.color_space = color_space;
|
||||
if (hue_method.has_value())
|
||||
interpolation_method.hue_method = hue_method.value();
|
||||
|
||||
return interpolation_method;
|
||||
}
|
||||
|
||||
RefPtr<LinearGradientStyleValue> Parser::parse_linear_gradient_function(TokenStream<ComponentValue>& outer_tokens)
|
||||
{
|
||||
using GradientType = LinearGradientStyleValue::GradientType;
|
||||
|
@ -156,7 +251,7 @@ RefPtr<LinearGradientStyleValue> Parser::parse_linear_gradient_function(TokenStr
|
|||
if (!function_name.equals_ignoring_ascii_case("linear-gradient"sv))
|
||||
return nullptr;
|
||||
|
||||
// linear-gradient() = linear-gradient([ <angle> | to <side-or-corner> ]?, <color-stop-list>)
|
||||
// <linear-gradient-syntax> = [ [ <angle> | to <side-or-corner> ] || <color-interpolation-method> ]? , <color-stop-list>
|
||||
|
||||
TokenStream tokens { component_value.function().value };
|
||||
tokens.discard_whitespace();
|
||||
|
@ -189,6 +284,9 @@ RefPtr<LinearGradientStyleValue> Parser::parse_linear_gradient_function(TokenStr
|
|||
return token.token().ident().equals_ignoring_ascii_case("to"sv);
|
||||
};
|
||||
|
||||
auto maybe_interpolation_method = parse_interpolation_method(tokens);
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto const& first_param = tokens.next_token();
|
||||
if (first_param.is(Token::Type::Dimension)) {
|
||||
// <angle>
|
||||
|
@ -222,11 +320,12 @@ RefPtr<LinearGradientStyleValue> Parser::parse_linear_gradient_function(TokenStr
|
|||
tokens.discard_whitespace();
|
||||
Optional<SideOrCorner> side_b;
|
||||
if (tokens.has_next_token() && tokens.next_token().is(Token::Type::Ident))
|
||||
side_b = to_side(tokens.consume_a_token().token().ident());
|
||||
side_b = to_side(tokens.next_token().token().ident());
|
||||
|
||||
if (side_a.has_value() && !side_b.has_value()) {
|
||||
gradient_direction = *side_a;
|
||||
} else if (side_a.has_value() && side_b.has_value()) {
|
||||
tokens.discard_a_token();
|
||||
// Convert two sides to a corner
|
||||
if (to_underlying(*side_b) < to_underlying(*side_a))
|
||||
swap(side_a, side_b);
|
||||
|
@ -247,11 +346,16 @@ RefPtr<LinearGradientStyleValue> Parser::parse_linear_gradient_function(TokenStr
|
|||
has_direction_param = false;
|
||||
}
|
||||
|
||||
if (!maybe_interpolation_method.has_value()) {
|
||||
tokens.discard_whitespace();
|
||||
maybe_interpolation_method = parse_interpolation_method(tokens);
|
||||
}
|
||||
|
||||
tokens.discard_whitespace();
|
||||
if (!tokens.has_next_token())
|
||||
return nullptr;
|
||||
|
||||
if (has_direction_param && !tokens.consume_a_token().is(Token::Type::Comma))
|
||||
if ((has_direction_param || maybe_interpolation_method.has_value()) && !tokens.consume_a_token().is(Token::Type::Comma))
|
||||
return nullptr;
|
||||
|
||||
auto color_stops = parse_linear_color_stop_list(tokens);
|
||||
|
@ -259,7 +363,7 @@ RefPtr<LinearGradientStyleValue> Parser::parse_linear_gradient_function(TokenStr
|
|||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return LinearGradientStyleValue::create(gradient_direction, move(*color_stops), gradient_type, repeating_gradient);
|
||||
return LinearGradientStyleValue::create(gradient_direction, move(*color_stops), gradient_type, repeating_gradient, maybe_interpolation_method);
|
||||
}
|
||||
|
||||
RefPtr<ConicGradientStyleValue> Parser::parse_conic_gradient_function(TokenStream<ComponentValue>& outer_tokens)
|
||||
|
@ -290,9 +394,9 @@ RefPtr<ConicGradientStyleValue> Parser::parse_conic_gradient_function(TokenStrea
|
|||
|
||||
Angle from_angle(0, Angle::Type::Deg);
|
||||
RefPtr<PositionStyleValue> at_position;
|
||||
Optional<InterpolationMethod> maybe_interpolation_method;
|
||||
|
||||
// conic-gradient( [ [ from <angle> ]? [ at <position> ]? ] ||
|
||||
// <color-interpolation-method> , <angular-color-stop-list> )
|
||||
// conic-gradient( [ [ [ from <angle> ]? [ at <position> ]? ] || <color-interpolation-method> ]? , <angular-color-stop-list> )
|
||||
NonnullRawPtr<ComponentValue const> token = tokens.next_token();
|
||||
bool got_from_angle = false;
|
||||
bool got_color_interpolation_method = false;
|
||||
|
@ -335,12 +439,15 @@ RefPtr<ConicGradientStyleValue> Parser::parse_conic_gradient_function(TokenStrea
|
|||
return nullptr;
|
||||
at_position = position;
|
||||
got_at_position = true;
|
||||
} else if (consume_identifier("in"sv)) {
|
||||
} else if (token->token().ident().equals_ignoring_ascii_case("in"sv)) {
|
||||
// <color-interpolation-method>
|
||||
if (got_color_interpolation_method)
|
||||
return nullptr;
|
||||
dbgln("FIXME: Parse color interpolation method for conic-gradient()");
|
||||
got_color_interpolation_method = true;
|
||||
|
||||
maybe_interpolation_method = parse_interpolation_method(tokens);
|
||||
if (!maybe_interpolation_method.has_value())
|
||||
return nullptr;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -364,7 +471,7 @@ RefPtr<ConicGradientStyleValue> Parser::parse_conic_gradient_function(TokenStrea
|
|||
at_position = PositionStyleValue::create_center();
|
||||
|
||||
transaction.commit();
|
||||
return ConicGradientStyleValue::create(from_angle, at_position.release_nonnull(), move(*color_stops), repeating_gradient);
|
||||
return ConicGradientStyleValue::create(from_angle, at_position.release_nonnull(), move(*color_stops), repeating_gradient, maybe_interpolation_method);
|
||||
}
|
||||
|
||||
RefPtr<RadialGradientStyleValue> Parser::parse_radial_gradient_function(TokenStream<ComponentValue>& outer_tokens)
|
||||
|
@ -405,7 +512,8 @@ RefPtr<RadialGradientStyleValue> Parser::parse_radial_gradient_function(TokenStr
|
|||
return value;
|
||||
};
|
||||
|
||||
// radial-gradient( [ <ending-shape> || <size> ]? [ at <position> ]? , <color-stop-list> )
|
||||
// <radial-gradient-syntax> = [ [ [ <radial-shape> || <radial-size> ]? [ at <position> ]? ] || <color-interpolation-method> ]? , <color-stop-list>
|
||||
// FIXME: Maybe rename ending-shape things to radial-shape
|
||||
|
||||
Size size = Extent::FarthestCorner;
|
||||
EndingShape ending_shape = EndingShape::Circle;
|
||||
|
@ -469,6 +577,9 @@ RefPtr<RadialGradientStyleValue> Parser::parse_radial_gradient_function(TokenStr
|
|||
return {};
|
||||
};
|
||||
|
||||
auto maybe_interpolation_method = parse_interpolation_method(tokens);
|
||||
tokens.discard_whitespace();
|
||||
|
||||
{
|
||||
// [ <ending-shape> || <size> ]?
|
||||
auto maybe_ending_shape = parse_ending_shape();
|
||||
|
@ -506,6 +617,14 @@ RefPtr<RadialGradientStyleValue> Parser::parse_radial_gradient_function(TokenStr
|
|||
}
|
||||
|
||||
tokens.discard_whitespace();
|
||||
if (!maybe_interpolation_method.has_value()) {
|
||||
maybe_interpolation_method = parse_interpolation_method(tokens);
|
||||
tokens.discard_whitespace();
|
||||
}
|
||||
|
||||
if (maybe_interpolation_method.has_value())
|
||||
expect_comma = true;
|
||||
|
||||
if (!tokens.has_next_token())
|
||||
return nullptr;
|
||||
if (expect_comma && !tokens.consume_a_token().is(Token::Type::Comma))
|
||||
|
@ -520,7 +639,7 @@ RefPtr<RadialGradientStyleValue> Parser::parse_radial_gradient_function(TokenStr
|
|||
at_position = PositionStyleValue::create_center();
|
||||
|
||||
transaction.commit();
|
||||
return RadialGradientStyleValue::create(ending_shape, size, at_position.release_nonnull(), move(*color_stops), repeating_gradient);
|
||||
return RadialGradientStyleValue::create(ending_shape, size, at_position.release_nonnull(), move(*color_stops), repeating_gradient, maybe_interpolation_method);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -281,6 +281,7 @@ private:
|
|||
Optional<Vector<TElement>> parse_color_stop_list(TokenStream<ComponentValue>& tokens, auto parse_position);
|
||||
Optional<Vector<LinearColorStopListElement>> parse_linear_color_stop_list(TokenStream<ComponentValue>&);
|
||||
Optional<Vector<AngularColorStopListElement>> parse_angular_color_stop_list(TokenStream<ComponentValue>&);
|
||||
Optional<InterpolationMethod> parse_interpolation_method(TokenStream<ComponentValue>&);
|
||||
|
||||
RefPtr<LinearGradientStyleValue> parse_linear_gradient_function(TokenStream<ComponentValue>&);
|
||||
RefPtr<ConicGradientStyleValue> parse_conic_gradient_function(TokenStream<ComponentValue>&);
|
||||
|
|
|
@ -1198,7 +1198,7 @@ RefPtr<CSSStyleValue> Parser::parse_rgb_color_value(TokenStream<ComponentValue>&
|
|||
alpha = NumberStyleValue::create(1);
|
||||
|
||||
transaction.commit();
|
||||
return CSSRGB::create(red.release_nonnull(), green.release_nonnull(), blue.release_nonnull(), alpha.release_nonnull());
|
||||
return CSSRGB::create(red.release_nonnull(), green.release_nonnull(), blue.release_nonnull(), alpha.release_nonnull(), legacy_syntax ? ColorSyntax::Legacy : ColorSyntax::Modern);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-color-4/#funcdef-hsl
|
||||
|
@ -1310,7 +1310,7 @@ RefPtr<CSSStyleValue> Parser::parse_hsl_color_value(TokenStream<ComponentValue>&
|
|||
alpha = NumberStyleValue::create(1);
|
||||
|
||||
transaction.commit();
|
||||
return CSSHSL::create(h.release_nonnull(), s.release_nonnull(), l.release_nonnull(), alpha.release_nonnull());
|
||||
return CSSHSL::create(h.release_nonnull(), s.release_nonnull(), l.release_nonnull(), alpha.release_nonnull(), legacy_syntax ? ColorSyntax::Legacy : ColorSyntax::Modern);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-color-4/#funcdef-hwb
|
||||
|
@ -1687,7 +1687,7 @@ RefPtr<CSSStyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tok
|
|||
auto color = Color::from_string(ident);
|
||||
if (color.has_value()) {
|
||||
transaction.commit();
|
||||
return CSSColorValue::create_from_color(color.release_value(), ident);
|
||||
return CSSColorValue::create_from_color(color.release_value(), ColorSyntax::Legacy, ident);
|
||||
}
|
||||
// Otherwise, fall through to the hashless-hex-color case
|
||||
}
|
||||
|
@ -1696,7 +1696,7 @@ RefPtr<CSSStyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tok
|
|||
auto color = Color::from_string(MUST(String::formatted("#{}", component_value.token().hash_value())));
|
||||
if (color.has_value()) {
|
||||
transaction.commit();
|
||||
return CSSColorValue::create_from_color(color.release_value());
|
||||
return CSSColorValue::create_from_color(color.release_value(), ColorSyntax::Legacy);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -1782,7 +1782,7 @@ RefPtr<CSSStyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tok
|
|||
auto color = Color::from_string(MUST(String::formatted("#{}", serialization)));
|
||||
if (color.has_value()) {
|
||||
transaction.commit();
|
||||
return CSSColorValue::create_from_color(color.release_value());
|
||||
return CSSColorValue::create_from_color(color.release_value(), ColorSyntax::Legacy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ static RefPtr<CSSStyleValue const> style_value_for_shadow(Vector<ShadowData> con
|
|||
|
||||
auto make_shadow_style_value = [](ShadowData const& shadow) {
|
||||
return ShadowStyleValue::create(
|
||||
CSSColorValue::create_from_color(shadow.color),
|
||||
CSSColorValue::create_from_color(shadow.color, ColorSyntax::Modern),
|
||||
style_value_for_length_percentage(shadow.offset_x),
|
||||
style_value_for_length_percentage(shadow.offset_y),
|
||||
style_value_for_length_percentage(shadow.blur_radius),
|
||||
|
@ -209,23 +209,23 @@ RefPtr<CSSStyleValue const> ResolvedCSSStyleDeclaration::style_value_for_propert
|
|||
// -> A resolved value special case property like color defined in another specification
|
||||
// The resolved value is the used value.
|
||||
case PropertyID::BackgroundColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().background_color());
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().background_color(), ColorSyntax::Modern);
|
||||
case PropertyID::BorderBottomColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_bottom().color);
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_bottom().color, ColorSyntax::Modern);
|
||||
case PropertyID::BorderLeftColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_left().color);
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_left().color, ColorSyntax::Modern);
|
||||
case PropertyID::BorderRightColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_right().color);
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_right().color, ColorSyntax::Modern);
|
||||
case PropertyID::BorderTopColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_top().color);
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().border_top().color, ColorSyntax::Modern);
|
||||
case PropertyID::BoxShadow:
|
||||
return style_value_for_shadow(layout_node.computed_values().box_shadow());
|
||||
case PropertyID::Color:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().color());
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().color(), ColorSyntax::Modern);
|
||||
case PropertyID::OutlineColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().outline_color());
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().outline_color(), ColorSyntax::Modern);
|
||||
case PropertyID::TextDecorationColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().text_decoration_color());
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().text_decoration_color(), ColorSyntax::Modern);
|
||||
// NOTE: text-shadow isn't listed, but is computed the same as box-shadow.
|
||||
case PropertyID::TextShadow:
|
||||
return style_value_for_shadow(layout_node.computed_values().text_shadow());
|
||||
|
@ -456,7 +456,7 @@ RefPtr<CSSStyleValue const> ResolvedCSSStyleDeclaration::style_value_for_propert
|
|||
// The resolved value is the computed value.
|
||||
// NOTE: This is handled inside the `default` case.
|
||||
case PropertyID::WebkitTextFillColor:
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().webkit_text_fill_color());
|
||||
return CSSColorValue::create_from_color(layout_node.computed_values().webkit_text_fill_color(), ColorSyntax::Modern);
|
||||
case PropertyID::Invalid:
|
||||
return CSSKeywordValue::create(Keyword::Invalid);
|
||||
case PropertyID::Custom:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -65,12 +65,12 @@ void HTMLBodyElement::apply_presentational_hints(GC::Ref<CSS::CascadedProperties
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#the-page:rules-for-parsing-a-legacy-colour-value
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
} else if (name.equals_ignoring_ascii_case("text"sv)) {
|
||||
// https://html.spec.whatwg.org/multipage/rendering.html#the-page:rules-for-parsing-a-legacy-colour-value-2
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
} else if (name.equals_ignoring_ascii_case("background"sv)) {
|
||||
VERIFY(m_background_style_value);
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, *m_background_style_value);
|
||||
|
|
|
@ -129,7 +129,7 @@ void HTMLFontElement::apply_presentational_hints(GC::Ref<CSS::CascadedProperties
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3:rules-for-parsing-a-legacy-colour-value
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
} else if (name.equals_ignoring_ascii_case("size"sv)) {
|
||||
// When a font element has a size attribute, the user agent is expected to use the following steps, known as the rules for parsing a legacy font size, to treat the attribute as a presentational hint setting the element's 'font-size' property:
|
||||
auto font_size_or_empty = parse_legacy_font_size(value);
|
||||
|
|
|
@ -68,7 +68,7 @@ void HTMLHRElement::apply_presentational_hints(GC::Ref<CSS::CascadedProperties>
|
|||
// the user agent is expected to treat the attribute as a presentational hint setting the element's 'color' property to the resulting color.
|
||||
if (name == HTML::AttributeNames::color) {
|
||||
if (auto parsed_value = parse_legacy_color_value(value); parsed_value.has_value()) {
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(*parsed_value));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Color, CSS::CSSColorValue::create_from_color(*parsed_value, CSS::ColorSyntax::Legacy));
|
||||
}
|
||||
}
|
||||
// https://html.spec.whatwg.org/multipage/rendering.html#the-hr-element-2:maps-to-the-dimension-property
|
||||
|
|
|
@ -51,7 +51,7 @@ void HTMLMarqueeElement::apply_presentational_hints(GC::Ref<CSS::CascadedPropert
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#the-marquee-element-2:rules-for-parsing-a-legacy-colour-value
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
} else if (name == HTML::AttributeNames::height) {
|
||||
// https://html.spec.whatwg.org/multipage/rendering.html#the-marquee-element-2:maps-to-the-dimension-property
|
||||
if (auto parsed_value = parse_dimension_value(value)) {
|
||||
|
|
|
@ -59,7 +59,7 @@ void HTMLTableCellElement::apply_presentational_hints(GC::Ref<CSS::CascadedPrope
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
return;
|
||||
}
|
||||
if (name == HTML::AttributeNames::valign) {
|
||||
|
|
|
@ -102,7 +102,7 @@ void HTMLTableElement::apply_presentational_hints(GC::Ref<CSS::CascadedPropertie
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
return;
|
||||
}
|
||||
if (name == HTML::AttributeNames::cellspacing) {
|
||||
|
@ -118,7 +118,7 @@ void HTMLTableElement::apply_presentational_hints(GC::Ref<CSS::CascadedPropertie
|
|||
auto legacy_line_style = CSS::CSSKeywordValue::create(CSS::Keyword::Outset);
|
||||
cascaded_properties->set_property_from_presentational_hint(style_property, legacy_line_style);
|
||||
cascaded_properties->set_property_from_presentational_hint(width_property, CSS::LengthStyleValue::create(CSS::Length::make_px(border)));
|
||||
cascaded_properties->set_property_from_presentational_hint(color_property, CSS::CSSColorValue::create_from_color(Color(128, 128, 128)));
|
||||
cascaded_properties->set_property_from_presentational_hint(color_property, CSS::CSSColorValue::create_from_color(Color(128, 128, 128), CSS::ColorSyntax::Legacy));
|
||||
};
|
||||
apply_border_style(CSS::PropertyID::BorderLeftStyle, CSS::PropertyID::BorderLeftWidth, CSS::PropertyID::BorderLeftColor);
|
||||
apply_border_style(CSS::PropertyID::BorderTopStyle, CSS::PropertyID::BorderTopWidth, CSS::PropertyID::BorderTopColor);
|
||||
|
@ -131,7 +131,7 @@ void HTMLTableElement::apply_presentational_hints(GC::Ref<CSS::CascadedPropertie
|
|||
// and if that does not return failure, the user agent is expected to treat the attribute as a presentational hint setting the element's
|
||||
// 'border-top-color', 'border-right-color', 'border-bottom-color', and 'border-left-color' properties to the resulting color.
|
||||
if (auto parsed_color = parse_legacy_color_value(value); parsed_color.has_value()) {
|
||||
auto color_value = CSS::CSSColorValue::create_from_color(parsed_color.value());
|
||||
auto color_value = CSS::CSSColorValue::create_from_color(parsed_color.value(), CSS::ColorSyntax::Legacy);
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BorderTopColor, color_value);
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BorderRightColor, color_value);
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BorderBottomColor, color_value);
|
||||
|
|
|
@ -58,7 +58,7 @@ void HTMLTableRowElement::apply_presentational_hints(GC::Ref<CSS::CascadedProper
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value
|
||||
auto color = parse_legacy_color_value(value);
|
||||
if (color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
} else if (name == HTML::AttributeNames::background) {
|
||||
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:encoding-parsing-and-serializing-a-url
|
||||
if (auto parsed_value = document().encoding_parse_url(value); parsed_value.has_value())
|
||||
|
|
|
@ -122,7 +122,7 @@ void HTMLTableSectionElement::apply_presentational_hints(GC::Ref<CSS::CascadedPr
|
|||
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value
|
||||
else if (name == HTML::AttributeNames::bgcolor) {
|
||||
if (auto color = parse_legacy_color_value(value); color.has_value())
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value()));
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value(), CSS::ColorSyntax::Legacy));
|
||||
} else if (name == HTML::AttributeNames::height) {
|
||||
if (auto parsed_value = parse_dimension_value(value))
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Height, parsed_value.release_nonnull());
|
||||
|
|
|
@ -315,6 +315,66 @@ static ColorStopList expand_repeat_length(ColorStopList const& color_stop_list,
|
|||
return color_stop_list_with_expanded_repeat;
|
||||
}
|
||||
|
||||
static SkGradientShader::Interpolation to_skia_interpolation(CSS::InterpolationMethod interpolation_method)
|
||||
{
|
||||
SkGradientShader::Interpolation interpolation;
|
||||
|
||||
switch (interpolation_method.color_space) {
|
||||
case CSS::GradientSpace::sRGB:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
|
||||
break;
|
||||
case CSS::GradientSpace::sRGBLinear:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGBLinear;
|
||||
break;
|
||||
case CSS::GradientSpace::Lab:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kLab;
|
||||
break;
|
||||
case CSS::GradientSpace::OKLab:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLab;
|
||||
break;
|
||||
case CSS::GradientSpace::HSL:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kHSL;
|
||||
break;
|
||||
case CSS::GradientSpace::HWB:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kHWB;
|
||||
break;
|
||||
case CSS::GradientSpace::LCH:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kLCH;
|
||||
break;
|
||||
case CSS::GradientSpace::OKLCH:
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLCH;
|
||||
break;
|
||||
case CSS::GradientSpace::DisplayP3:
|
||||
case CSS::GradientSpace::A98RGB:
|
||||
case CSS::GradientSpace::ProPhotoRGB:
|
||||
case CSS::GradientSpace::Rec2020:
|
||||
case CSS::GradientSpace::XYZD50:
|
||||
case CSS::GradientSpace::XYZD65:
|
||||
dbgln("FIXME: Unsupported gradient color space");
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kOKLab;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (interpolation_method.hue_method) {
|
||||
case CSS::HueMethod::Shorter:
|
||||
interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kShorter;
|
||||
break;
|
||||
case CSS::HueMethod::Longer:
|
||||
interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kLonger;
|
||||
break;
|
||||
case CSS::HueMethod::Increasing:
|
||||
interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kIncreasing;
|
||||
break;
|
||||
case CSS::HueMethod::Decreasing:
|
||||
interpolation.fHueMethod = SkGradientShader::Interpolation::HueMethod::kDecreasing;
|
||||
break;
|
||||
}
|
||||
|
||||
interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
|
||||
|
||||
return interpolation;
|
||||
}
|
||||
|
||||
void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
|
||||
{
|
||||
auto const& linear_gradient_data = command.linear_gradient_data;
|
||||
|
@ -351,9 +411,7 @@ void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& com
|
|||
matrix.setRotate(linear_gradient_data.gradient_angle, center.x(), center.y());
|
||||
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
SkGradientShader::Interpolation interpolation = {};
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
|
||||
interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
|
||||
auto interpolation = to_skia_interpolation(linear_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kClamp, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
|
@ -766,9 +824,7 @@ void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& com
|
|||
tile_mode = SkTileMode::kRepeat;
|
||||
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
SkGradientShader::Interpolation interpolation = {};
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
|
||||
interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
|
||||
auto interpolation = to_skia_interpolation(radial_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeRadial(center, size.height(), colors.data(), color_space, positions.data(), positions.size(), tile_mode, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
|
@ -805,9 +861,7 @@ void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& comma
|
|||
SkMatrix matrix;
|
||||
matrix.setRotate(-90 + conic_gradient_data.start_angle, center.x(), center.y());
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
SkGradientShader::Interpolation interpolation = {};
|
||||
interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
|
||||
interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
|
||||
auto interpolation = to_skia_interpolation(conic_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeSweep(center.x(), center.y(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kRepeat, 0, 360, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/Vector.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
@ -24,15 +25,18 @@ struct ColorStopData {
|
|||
struct LinearGradientData {
|
||||
float gradient_angle;
|
||||
ColorStopData color_stops;
|
||||
CSS::InterpolationMethod interpolation_method;
|
||||
};
|
||||
|
||||
struct ConicGradientData {
|
||||
float start_angle;
|
||||
ColorStopData color_stops;
|
||||
CSS::InterpolationMethod interpolation_method;
|
||||
};
|
||||
|
||||
struct RadialGradientData {
|
||||
ColorStopData color_stops;
|
||||
CSS::InterpolationMethod interpolation_method;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ LinearGradientData resolve_linear_gradient_data(Layout::NodeWithStyle const& nod
|
|||
},
|
||||
linear_gradient.is_repeating());
|
||||
|
||||
return { gradient_angle, resolved_color_stops };
|
||||
return { gradient_angle, resolved_color_stops, linear_gradient.interpolation_method() };
|
||||
}
|
||||
|
||||
ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyle const& node, CSS::ConicGradientStyleValue const& conic_gradient)
|
||||
|
@ -132,7 +132,7 @@ ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyle const& node,
|
|||
return angle_percentage.resolved(node, one_turn).to_degrees() / one_turn.to_degrees();
|
||||
},
|
||||
conic_gradient.is_repeating());
|
||||
return { conic_gradient.angle_degrees(), resolved_color_stops };
|
||||
return { conic_gradient.angle_degrees(), resolved_color_stops, conic_gradient.interpolation_method() };
|
||||
}
|
||||
|
||||
RadialGradientData resolve_radial_gradient_data(Layout::NodeWithStyle const& node, CSSPixelSize gradient_size, CSS::RadialGradientStyleValue const& radial_gradient)
|
||||
|
@ -143,7 +143,7 @@ RadialGradientData resolve_radial_gradient_data(Layout::NodeWithStyle const& nod
|
|||
return length_percentage.to_px(node, gradient_size.width()).to_float() / gradient_size.width().to_float();
|
||||
},
|
||||
radial_gradient.is_repeating());
|
||||
return { resolved_color_stops };
|
||||
return { resolved_color_stops, radial_gradient.interpolation_method() };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
<img src="../images/gradient-interpolation-method-ref.png">
|
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/gradient-interpolation-method-ref.html" />
|
||||
<style>
|
||||
div {
|
||||
width: 480px;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
<div style="background: linear-gradient(to right in srgb, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in srgb-linear, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in lab, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in oklab, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in hsl, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in hwb, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in lch, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in oklch shorter hue, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in oklch longer hue, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in oklch increasing hue, red, blue)"></div>
|
||||
<div style="background: linear-gradient(to right in oklch decreasing hue, red, blue)"></div>
|
Loading…
Add table
Reference in a new issue