diff options
author | MacDue <macdue@dueutil.tech> | 2023-04-03 00:04:00 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-04-03 07:10:33 +0200 |
commit | bed55ac6696466723d5067b748f05651e5d1521c (patch) | |
tree | cd4a3fe56090b6bb68fe965e559554b04e04da67 /Userland | |
parent | 2a659693bc54e2c473f71c3ac89905bd9384d8b9 (diff) | |
download | serenity-bed55ac6696466723d5067b748f05651e5d1521c.zip |
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.
Diffstat (limited to 'Userland')
7 files changed, 135 insertions, 67 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index afde36f313..d513f66b17 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -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(); diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index c9e27c2efe..f3a45863f2 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -294,6 +294,7 @@ private: RefPtr<StyleValue> parse_filter_value_list_value(Vector<ComponentValue> const&); RefPtr<StyleValue> parse_background_value(Vector<ComponentValue> const&); RefPtr<StyleValue> parse_single_background_position_value(TokenStream<ComponentValue>&); + RefPtr<StyleValue> parse_single_background_position_x_or_y_value(TokenStream<ComponentValue>&, PropertyID); RefPtr<StyleValue> parse_single_background_repeat_value(TokenStream<ComponentValue>&); RefPtr<StyleValue> parse_single_background_size_value(TokenStream<ComponentValue>&); RefPtr<StyleValue> parse_border_value(Vector<ComponentValue> const&); diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp index 87f76868ca..76cef8fcb6 100644 --- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp @@ -19,6 +19,7 @@ #include <LibWeb/CSS/StyleValues/BorderStyleValue.h> #include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h> #include <LibWeb/CSS/StyleValues/ColorStyleValue.h> +#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h> #include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h> #include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h> #include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h> @@ -195,7 +196,7 @@ RefPtr<StyleValue const> ResolvedCSSStyleDeclaration::style_value_for_property(L return BackgroundStyleValue::create( value_or_default(maybe_background_color, InitialStyleValue::the()), value_or_default(maybe_background_image, IdentifierStyleValue::create(CSS::ValueID::None)), - value_or_default(maybe_background_position, PositionStyleValue::create(PositionEdge::Left, Length::make_px(0), PositionEdge::Top, Length::make_px(0))), + value_or_default(maybe_background_position, PositionStyleValue::create(EdgeStyleValue::create(PositionEdge::Left, Length::make_px(0)), EdgeStyleValue::create(PositionEdge::Top, Length::make_px(0)))), value_or_default(maybe_background_size, IdentifierStyleValue::create(CSS::ValueID::Auto)), value_or_default(maybe_background_repeat, BackgroundRepeatStyleValue::create(CSS::Repeat::Repeat, CSS::Repeat::Repeat)), value_or_default(maybe_background_attachment, IdentifierStyleValue::create(CSS::ValueID::Scroll)), diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index da5e080303..335559bceb 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -43,6 +43,7 @@ #include <LibWeb/CSS/StyleValues/NumericStyleValue.h> #include <LibWeb/CSS/StyleValues/OverflowStyleValue.h> #include <LibWeb/CSS/StyleValues/PercentageStyleValue.h> +#include <LibWeb/CSS/StyleValues/PositionStyleValue.h> #include <LibWeb/CSS/StyleValues/StyleValueList.h> #include <LibWeb/CSS/StyleValues/TextDecorationStyleValue.h> #include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h> @@ -454,6 +455,19 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope return; } + if (property_id == CSS::PropertyID::BackgroundPosition) { + if (value.is_position()) { + auto const& position = value.as_position(); + style.set_property(CSS::PropertyID::BackgroundPositionX, position.edge_x()); + style.set_property(CSS::PropertyID::BackgroundPositionY, position.edge_y()); + return; + } + + style.set_property(CSS::PropertyID::BackgroundPositionX, value); + style.set_property(CSS::PropertyID::BackgroundPositionY, value); + return; + } + if (property_id == CSS::PropertyID::Margin) { if (value.is_value_list()) { auto const& values_list = value.as_value_list(); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp index 543c13de31..71cb93bbc0 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp @@ -13,21 +13,7 @@ namespace Web::CSS { ErrorOr<String> PositionStyleValue::to_string() const { - auto to_string = [](PositionEdge edge) { - switch (edge) { - case PositionEdge::Left: - return "left"; - case PositionEdge::Right: - return "right"; - case PositionEdge::Top: - return "top"; - case PositionEdge::Bottom: - return "bottom"; - } - VERIFY_NOT_REACHED(); - }; - - return String::formatted("{} {} {} {}", to_string(m_properties.edge_x), TRY(m_properties.offset_x.to_string()), to_string(m_properties.edge_y), TRY(m_properties.offset_y.to_string())); + return String::formatted("{} {}", TRY(m_properties.edge_x->to_string()), TRY(m_properties.edge_y->to_string())); } } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h index 39efe318ff..028a75d079 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h @@ -17,33 +17,29 @@ namespace Web::CSS { class PositionStyleValue final : public StyleValueWithDefaultOperators<PositionStyleValue> { public: - static ValueComparingNonnullRefPtr<PositionStyleValue> create(PositionEdge edge_x, LengthPercentage const& offset_x, PositionEdge edge_y, LengthPercentage const& offset_y) + static ValueComparingNonnullRefPtr<PositionStyleValue> create(ValueComparingNonnullRefPtr<StyleValue> egde_x, ValueComparingNonnullRefPtr<StyleValue> edge_y) { - return adopt_ref(*new PositionStyleValue(edge_x, offset_x, edge_y, offset_y)); + return adopt_ref(*new PositionStyleValue(move(egde_x), move(edge_y))); } virtual ~PositionStyleValue() override = default; - PositionEdge edge_x() const { return m_properties.edge_x; } - LengthPercentage const& offset_x() const { return m_properties.offset_x; } - PositionEdge edge_y() const { return m_properties.edge_y; } - LengthPercentage const& offset_y() const { return m_properties.offset_y; } + ValueComparingNonnullRefPtr<StyleValue> edge_x() const { return m_properties.edge_x; } + ValueComparingNonnullRefPtr<StyleValue> edge_y() const { return m_properties.edge_y; } virtual ErrorOr<String> to_string() const override; bool properties_equal(PositionStyleValue const& other) const { return m_properties == other.m_properties; } private: - PositionStyleValue(PositionEdge edge_x, LengthPercentage const& offset_x, PositionEdge edge_y, LengthPercentage const& offset_y) + PositionStyleValue(ValueComparingNonnullRefPtr<StyleValue> edge_x, ValueComparingNonnullRefPtr<StyleValue> edge_y) : StyleValueWithDefaultOperators(Type::Position) - , m_properties { .edge_x = edge_x, .offset_x = offset_x, .edge_y = edge_y, .offset_y = offset_y } + , m_properties { .edge_x = edge_x, .edge_y = edge_y } { } struct Properties { - PositionEdge edge_x; - LengthPercentage offset_x; - PositionEdge edge_y; - LengthPercentage offset_y; + ValueComparingNonnullRefPtr<StyleValue> edge_x; + ValueComparingNonnullRefPtr<StyleValue> edge_y; bool operator==(Properties const&) const = default; } m_properties; }; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 5faf73ebde..d40e6656df 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -9,7 +9,7 @@ #include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h> #include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h> #include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h> -#include <LibWeb/CSS/StyleValues/PositionStyleValue.h> +#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h> #include <LibWeb/CSS/StyleValues/StyleValueList.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/Dump.h> @@ -293,7 +293,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) auto clips = computed_style.property(CSS::PropertyID::BackgroundClip); auto images = computed_style.property(CSS::PropertyID::BackgroundImage); auto origins = computed_style.property(CSS::PropertyID::BackgroundOrigin); - auto positions = computed_style.property(CSS::PropertyID::BackgroundPosition); + auto x_positions = computed_style.property(CSS::PropertyID::BackgroundPositionX); + auto y_positions = computed_style.property(CSS::PropertyID::BackgroundPositionY); auto repeats = computed_style.property(CSS::PropertyID::BackgroundRepeat); auto sizes = computed_style.property(CSS::PropertyID::BackgroundSize); @@ -315,7 +316,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) layer_count = max(layer_count, count_layers(clips)); layer_count = max(layer_count, count_layers(images)); layer_count = max(layer_count, count_layers(origins)); - layer_count = max(layer_count, count_layers(positions)); + layer_count = max(layer_count, count_layers(x_positions)); + layer_count = max(layer_count, count_layers(y_positions)); layer_count = max(layer_count, count_layers(repeats)); layer_count = max(layer_count, count_layers(sizes)); @@ -369,14 +371,18 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) layer.clip = as_box(clip_value->to_identifier()); } - if (auto position_value = value_for_layer(positions, layer_index); position_value && position_value->is_position()) { - auto& position = position_value->as_position(); - layer.position_edge_x = position.edge_x(); - layer.position_edge_y = position.edge_y(); - layer.position_offset_x = position.offset_x(); - layer.position_offset_y = position.offset_y(); + if (auto position_value = value_for_layer(x_positions, layer_index); position_value && position_value->is_edge()) { + auto& position = position_value->as_edge(); + layer.position_edge_x = position.edge(); + layer.position_offset_x = position.offset(); } + if (auto position_value = value_for_layer(y_positions, layer_index); position_value && position_value->is_edge()) { + auto& position = position_value->as_edge(); + layer.position_edge_y = position.edge(); + layer.position_offset_y = position.offset(); + }; + if (auto size_value = value_for_layer(sizes, layer_index); size_value) { if (size_value->is_background_size()) { auto& size = size_value->as_background_size(); |