mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 14:17:42 +00:00
LibWeb: Parse radial-gradient()
s
This commit is contained in:
parent
040dac558e
commit
22a7611e1c
2 changed files with 151 additions and 3 deletions
|
@ -2579,8 +2579,8 @@ RefPtr<StyleValue> Parser::parse_conic_gradient_function(ComponentValue const& c
|
||||||
bool got_color_interpolation_method = false;
|
bool got_color_interpolation_method = false;
|
||||||
bool got_at_position = false;
|
bool got_at_position = false;
|
||||||
while (token.is(Token::Type::Ident)) {
|
while (token.is(Token::Type::Ident)) {
|
||||||
auto token_string = token.token().ident();
|
|
||||||
auto consume_identifier = [&](auto identifier) {
|
auto consume_identifier = [&](auto identifier) {
|
||||||
|
auto token_string = token.token().ident();
|
||||||
if (token_string.equals_ignoring_case(identifier)) {
|
if (token_string.equals_ignoring_case(identifier)) {
|
||||||
(void)tokens.next_token();
|
(void)tokens.next_token();
|
||||||
tokens.skip_whitespace();
|
tokens.skip_whitespace();
|
||||||
|
@ -2644,6 +2644,151 @@ RefPtr<StyleValue> Parser::parse_conic_gradient_function(ComponentValue const& c
|
||||||
return ConicGradientStyleValue::create(from_angle, at_position, move(*color_stops), repeating_gradient);
|
return ConicGradientStyleValue::create(from_angle, at_position, move(*color_stops), repeating_gradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<StyleValue> Parser::parse_radial_gradient_function(ComponentValue const& component_value)
|
||||||
|
{
|
||||||
|
using EndingShape = RadialGradientStyleValue::EndingShape;
|
||||||
|
using Extent = RadialGradientStyleValue::Extent;
|
||||||
|
using CircleSize = RadialGradientStyleValue::CircleSize;
|
||||||
|
using EllipseSize = RadialGradientStyleValue::EllipseSize;
|
||||||
|
using Size = RadialGradientStyleValue::Size;
|
||||||
|
|
||||||
|
if (!component_value.is_function())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto function_name = component_value.function().name();
|
||||||
|
|
||||||
|
if (!function_name.equals_ignoring_case("radial-gradient"sv))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
TokenStream tokens { component_value.function().values() };
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
if (!tokens.has_next_token())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
bool expect_comma = false;
|
||||||
|
|
||||||
|
auto commit_value = [&]<typename... T>(auto value, T&... transactions) {
|
||||||
|
(transactions.commit(), ...);
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// radial-gradient( [ <ending-shape> || <size> ]? [ at <position> ]? , <color-stop-list> )
|
||||||
|
|
||||||
|
Size size = Extent::FarthestCorner;
|
||||||
|
EndingShape ending_shape = EndingShape::Circle;
|
||||||
|
PositionValue at_position = PositionValue::center();
|
||||||
|
|
||||||
|
auto parse_ending_shape = [&]() -> Optional<EndingShape> {
|
||||||
|
auto transaction = tokens.begin_transaction();
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
auto& token = tokens.next_token();
|
||||||
|
if (!token.is(Token::Type::Ident))
|
||||||
|
return {};
|
||||||
|
auto ident = token.token().ident();
|
||||||
|
if (ident.equals_ignoring_case("circle"sv))
|
||||||
|
return commit_value(EndingShape::Circle, transaction);
|
||||||
|
if (ident.equals_ignoring_case("ellipse"sv))
|
||||||
|
return commit_value(EndingShape::Ellipse, transaction);
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto parse_extent_keyword = [](StringView keyword) -> Optional<Extent> {
|
||||||
|
if (keyword.equals_ignoring_case("closest-corner"sv))
|
||||||
|
return Extent::ClosestCorner;
|
||||||
|
if (keyword.equals_ignoring_case("closest-side"sv))
|
||||||
|
return Extent::ClosestSide;
|
||||||
|
if (keyword.equals_ignoring_case("farthest-corner"sv))
|
||||||
|
return Extent::FarthestCorner;
|
||||||
|
if (keyword.equals_ignoring_case("farthest-side"sv))
|
||||||
|
return Extent::FarthestSide;
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto parse_size = [&]() -> Optional<Size> {
|
||||||
|
// <size> =
|
||||||
|
// <extent-keyword> |
|
||||||
|
// <length [0,∞]> |
|
||||||
|
// <length-percentage [0,∞]>{2}
|
||||||
|
auto transaction_size = tokens.begin_transaction();
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
if (!tokens.has_next_token())
|
||||||
|
return {};
|
||||||
|
auto& token = tokens.next_token();
|
||||||
|
if (token.is(Token::Type::Ident)) {
|
||||||
|
auto extent = parse_extent_keyword(token.token().ident());
|
||||||
|
if (!extent.has_value())
|
||||||
|
return {};
|
||||||
|
return commit_value(*extent, transaction_size);
|
||||||
|
}
|
||||||
|
auto first_dimension = parse_dimension(token);
|
||||||
|
if (!first_dimension.has_value())
|
||||||
|
return {};
|
||||||
|
if (!first_dimension->is_length_percentage())
|
||||||
|
return {};
|
||||||
|
auto transaction_second_dimension = tokens.begin_transaction();
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
if (tokens.has_next_token()) {
|
||||||
|
auto& second_token = tokens.next_token();
|
||||||
|
auto second_dimension = parse_dimension(second_token);
|
||||||
|
if (second_dimension.has_value() && second_dimension->is_length_percentage())
|
||||||
|
return commit_value(EllipseSize { first_dimension->length_percentage(), second_dimension->length_percentage() },
|
||||||
|
transaction_size, transaction_second_dimension);
|
||||||
|
}
|
||||||
|
if (first_dimension->is_length())
|
||||||
|
return commit_value(CircleSize { first_dimension->length() }, transaction_size);
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
// [ <ending-shape> || <size> ]?
|
||||||
|
auto maybe_ending_shape = parse_ending_shape();
|
||||||
|
auto maybe_size = parse_size();
|
||||||
|
if (!maybe_ending_shape.has_value() && maybe_size.has_value())
|
||||||
|
maybe_ending_shape = parse_ending_shape();
|
||||||
|
if (maybe_size.has_value()) {
|
||||||
|
size = *maybe_size;
|
||||||
|
expect_comma = true;
|
||||||
|
}
|
||||||
|
if (maybe_ending_shape.has_value()) {
|
||||||
|
expect_comma = true;
|
||||||
|
ending_shape = *maybe_ending_shape;
|
||||||
|
if (ending_shape == EndingShape::Circle && size.has<EllipseSize>())
|
||||||
|
return {};
|
||||||
|
if (ending_shape == EndingShape::Ellipse && size.has<CircleSize>())
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
ending_shape = size.has<CircleSize>() ? EndingShape::Circle : EndingShape::Ellipse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
if (!tokens.has_next_token())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto& token = tokens.peek_token();
|
||||||
|
if (token.is(Token::Type::Ident) && token.token().ident().equals_ignoring_case("at"sv)) {
|
||||||
|
(void)tokens.next_token();
|
||||||
|
auto position = parse_position(tokens);
|
||||||
|
if (!position.has_value())
|
||||||
|
return {};
|
||||||
|
at_position = *position;
|
||||||
|
expect_comma = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.skip_whitespace();
|
||||||
|
if (!tokens.has_next_token())
|
||||||
|
return {};
|
||||||
|
if (expect_comma && !tokens.next_token().is(Token::Type::Comma))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// <color-stop-list>
|
||||||
|
auto color_stops = parse_linear_color_stop_list(tokens);
|
||||||
|
if (!color_stops.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return RadialGradientStyleValue::create(ending_shape, size, at_position, move(*color_stops));
|
||||||
|
}
|
||||||
|
|
||||||
Optional<PositionValue> Parser::parse_position(TokenStream<ComponentValue>& tokens, PositionValue initial_value)
|
Optional<PositionValue> Parser::parse_position(TokenStream<ComponentValue>& tokens, PositionValue initial_value)
|
||||||
{
|
{
|
||||||
auto transaction = tokens.begin_transaction();
|
auto transaction = tokens.begin_transaction();
|
||||||
|
@ -3825,11 +3970,13 @@ RefPtr<StyleValue> Parser::parse_image_value(ComponentValue const& component_val
|
||||||
auto url = parse_url_function(component_value, AllowedDataUrlType::Image);
|
auto url = parse_url_function(component_value, AllowedDataUrlType::Image);
|
||||||
if (url.has_value())
|
if (url.has_value())
|
||||||
return ImageStyleValue::create(url.value());
|
return ImageStyleValue::create(url.value());
|
||||||
// FIXME: Implement other kinds of gradient
|
|
||||||
auto linear_gradient = parse_linear_gradient_function(component_value);
|
auto linear_gradient = parse_linear_gradient_function(component_value);
|
||||||
if (linear_gradient)
|
if (linear_gradient)
|
||||||
return linear_gradient;
|
return linear_gradient;
|
||||||
return parse_conic_gradient_function(component_value);
|
auto conic_gradient = parse_conic_gradient_function(component_value);
|
||||||
|
if (conic_gradient)
|
||||||
|
return conic_gradient;
|
||||||
|
return parse_radial_gradient_function(component_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ParseFunction>
|
template<typename ParseFunction>
|
||||||
|
|
|
@ -269,6 +269,7 @@ private:
|
||||||
|
|
||||||
RefPtr<StyleValue> parse_linear_gradient_function(ComponentValue const&);
|
RefPtr<StyleValue> parse_linear_gradient_function(ComponentValue const&);
|
||||||
RefPtr<StyleValue> parse_conic_gradient_function(ComponentValue const&);
|
RefPtr<StyleValue> parse_conic_gradient_function(ComponentValue const&);
|
||||||
|
RefPtr<StyleValue> parse_radial_gradient_function(ComponentValue const&);
|
||||||
|
|
||||||
ParseErrorOr<NonnullRefPtr<StyleValue>> parse_css_value(PropertyID, TokenStream<ComponentValue>&);
|
ParseErrorOr<NonnullRefPtr<StyleValue>> parse_css_value(PropertyID, TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue> parse_css_value(ComponentValue const&);
|
RefPtr<StyleValue> parse_css_value(ComponentValue const&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue