mirror of
https://github.com/RGBCube/serenity
synced 2025-05-20 14:55:08 +00:00
LibWeb: Parse and plumb background-position-x/y
This parses the new background-position-x/y longhands and properly hooks up them up. This requires converting PositionStyleValue to just contain two EdgeStyleValues so that it can be easily expanded into the longhands.
This commit is contained in:
parent
2a659693bc
commit
bed55ac669
7 changed files with 135 additions and 67 deletions
|
@ -41,6 +41,7 @@
|
|||
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ConicGradientStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
|
||||
|
@ -4270,6 +4271,33 @@ RefPtr<StyleValue> Parser::parse_background_value(Vector<ComponentValue> const&
|
|||
background_clip.release_nonnull());
|
||||
}
|
||||
|
||||
static Optional<PositionEdge> identifier_to_edge(ValueID identifier)
|
||||
{
|
||||
switch (identifier) {
|
||||
case ValueID::Top:
|
||||
return PositionEdge::Top;
|
||||
case ValueID::Bottom:
|
||||
return PositionEdge::Bottom;
|
||||
case ValueID::Left:
|
||||
return PositionEdge::Left;
|
||||
case ValueID::Right:
|
||||
return PositionEdge::Right;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
static Optional<LengthPercentage> style_value_to_length_percentage(auto value)
|
||||
{
|
||||
if (value->is_percentage())
|
||||
return LengthPercentage { value->as_percentage().percentage() };
|
||||
if (value->has_length())
|
||||
return LengthPercentage { value->to_length() };
|
||||
if (value->is_calculated())
|
||||
return LengthPercentage { value->as_calculated() };
|
||||
return {};
|
||||
};
|
||||
|
||||
RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// NOTE: This *looks* like it parses a <position>, but it doesn't. From the spec:
|
||||
|
@ -4281,20 +4309,6 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
auto to_edge = [](ValueID identifier) -> Optional<PositionEdge> {
|
||||
switch (identifier) {
|
||||
case ValueID::Top:
|
||||
return PositionEdge::Top;
|
||||
case ValueID::Bottom:
|
||||
return PositionEdge::Bottom;
|
||||
case ValueID::Left:
|
||||
return PositionEdge::Left;
|
||||
case ValueID::Right:
|
||||
return PositionEdge::Right;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
auto is_horizontal = [](ValueID identifier) -> bool {
|
||||
switch (identifier) {
|
||||
case ValueID::Left:
|
||||
|
@ -4328,16 +4342,6 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|||
auto const center_offset = Percentage { 50 };
|
||||
auto const zero_offset = Length::make_px(0);
|
||||
|
||||
auto value_to_length_percentage = [&](auto value) -> Optional<LengthPercentage> {
|
||||
if (value->is_percentage())
|
||||
return LengthPercentage { value->as_percentage().percentage() };
|
||||
if (value->has_length())
|
||||
return LengthPercentage { value->to_length() };
|
||||
if (value->is_calculated())
|
||||
return LengthPercentage { value->as_calculated() };
|
||||
return {};
|
||||
};
|
||||
|
||||
while (tokens.has_next_token()) {
|
||||
// Check if we're done
|
||||
auto seen_items = (horizontal.has_value() ? 1 : 0) + (vertical.has_value() ? 1 : 0) + (found_center ? 1 : 0);
|
||||
|
@ -4351,7 +4355,7 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|||
tokens.next_token();
|
||||
auto value = maybe_value.release_nonnull();
|
||||
|
||||
auto offset = value_to_length_percentage(value);
|
||||
auto offset = style_value_to_length_percentage(value);
|
||||
if (offset.has_value()) {
|
||||
if (!horizontal.has_value()) {
|
||||
horizontal = EdgeOffset { PositionEdge::Left, *offset, false, true };
|
||||
|
@ -4369,7 +4373,7 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|||
auto maybe_value = parse_css_value(token);
|
||||
if (!maybe_value)
|
||||
return zero_offset;
|
||||
auto offset = value_to_length_percentage(maybe_value.release_nonnull());
|
||||
auto offset = style_value_to_length_percentage(maybe_value.release_nonnull());
|
||||
if (offset.has_value()) {
|
||||
offset_provided = true;
|
||||
tokens.next_token();
|
||||
|
@ -4384,11 +4388,11 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|||
if (is_horizontal(identifier)) {
|
||||
bool offset_provided = false;
|
||||
auto offset = try_parse_offset(offset_provided);
|
||||
horizontal = EdgeOffset { *to_edge(identifier), offset, true, offset_provided };
|
||||
horizontal = EdgeOffset { *identifier_to_edge(identifier), offset, true, offset_provided };
|
||||
} else if (is_vertical(identifier)) {
|
||||
bool offset_provided = false;
|
||||
auto offset = try_parse_offset(offset_provided);
|
||||
vertical = EdgeOffset { *to_edge(identifier), offset, true, offset_provided };
|
||||
vertical = EdgeOffset { *identifier_to_edge(identifier), offset, true, offset_provided };
|
||||
} else if (identifier == ValueID::Center) {
|
||||
found_center = true;
|
||||
} else {
|
||||
|
@ -4436,8 +4440,63 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|||
|
||||
transaction.commit();
|
||||
return PositionStyleValue::create(
|
||||
horizontal->edge, horizontal->offset,
|
||||
vertical->edge, vertical->offset);
|
||||
EdgeStyleValue::create(horizontal->edge, horizontal->offset),
|
||||
EdgeStyleValue::create(vertical->edge, vertical->offset));
|
||||
}
|
||||
|
||||
RefPtr<StyleValue> Parser::parse_single_background_position_x_or_y_value(TokenStream<ComponentValue>& tokens, PropertyID property)
|
||||
{
|
||||
PositionEdge relative_edge {};
|
||||
if (property == PropertyID::BackgroundPositionX) {
|
||||
// [ center | [ [ left | right | x-start | x-end ]? <length-percentage>? ]! ]#
|
||||
relative_edge = PositionEdge::Left;
|
||||
} else if (property == PropertyID::BackgroundPositionY) {
|
||||
// [ center | [ [ top | bottom | y-start | y-end ]? <length-percentage>? ]! ]#
|
||||
relative_edge = PositionEdge::Top;
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (!tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
auto parse_value = [&](auto& token) -> RefPtr<StyleValue> {
|
||||
auto maybe_value = parse_css_value(token);
|
||||
if (!maybe_value || !property_accepts_value(property, *maybe_value))
|
||||
return {};
|
||||
return maybe_value.release_nonnull();
|
||||
};
|
||||
|
||||
auto value = parse_value(tokens.next_token());
|
||||
if (value->has_identifier()) {
|
||||
auto identifier = value->to_identifier();
|
||||
if (identifier == ValueID::Center) {
|
||||
transaction.commit();
|
||||
return EdgeStyleValue::create(relative_edge, Percentage { 50 });
|
||||
}
|
||||
if (auto edge = identifier_to_edge(identifier); edge.has_value()) {
|
||||
relative_edge = *edge;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
if (tokens.has_next_token()) {
|
||||
value = parse_value(tokens.peek_token());
|
||||
if (!value) {
|
||||
transaction.commit();
|
||||
return EdgeStyleValue::create(relative_edge, Length::make_px(0));
|
||||
}
|
||||
tokens.next_token();
|
||||
}
|
||||
}
|
||||
|
||||
auto offset = style_value_to_length_percentage(value);
|
||||
if (offset.has_value()) {
|
||||
transaction.commit();
|
||||
return EdgeStyleValue::create(relative_edge, *offset);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
RefPtr<StyleValue> Parser::parse_single_background_repeat_value(TokenStream<ComponentValue>& tokens)
|
||||
|
@ -6531,6 +6590,11 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
|
|||
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this](auto& tokens) { return parse_single_background_position_value(tokens); }))
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::BackgroundPositionX:
|
||||
case PropertyID::BackgroundPositionY:
|
||||
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this, property_id](auto& tokens) { return parse_single_background_position_x_or_y_value(tokens, property_id); }))
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::BackgroundRepeat:
|
||||
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this](auto& tokens) { return parse_single_background_repeat_value(tokens); }))
|
||||
return parsed_value.release_nonnull();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue