diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 6f82f9755b..76e66d0633 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1746,22 +1746,23 @@ RefPtr Parser::parse_image_value(ParsingContext const& context, Styl return {}; } +static inline bool is_background_repeat(StyleValue const& value) +{ + switch (value.to_identifier()) { + case ValueID::NoRepeat: + case ValueID::Repeat: + case ValueID::RepeatX: + case ValueID::RepeatY: + case ValueID::Round: + case ValueID::Space: + return true; + default: + return false; + } +} + RefPtr Parser::parse_background_value(ParsingContext const& context, Vector const& component_values) { - auto is_background_repeat = [](StyleValue const& value) -> bool { - switch (value.to_identifier()) { - case CSS::ValueID::NoRepeat: - case CSS::ValueID::Repeat: - case CSS::ValueID::RepeatX: - case CSS::ValueID::RepeatY: - case CSS::ValueID::Round: - case CSS::ValueID::Space: - return true; - default: - return false; - } - }; - auto is_background_image = [](StyleValue const& value) -> bool { if (value.is_image()) return true; @@ -1848,6 +1849,50 @@ RefPtr Parser::parse_background_value(ParsingContext const& context, return BackgroundStyleValue::create(background_color.release_nonnull(), background_image.release_nonnull(), repeat_x.release_nonnull(), repeat_y.release_nonnull()); } +RefPtr Parser::parse_background_repeat_value(ParsingContext const& context, Vector const& component_values) +{ + auto is_directional_repeat = [](StyleValue const& value) -> bool { + auto value_id = value.to_identifier(); + return value_id == ValueID::RepeatX || value_id == ValueID::RepeatY; + }; + + if (component_values.size() == 1) { + auto maybe_value = parse_css_value(context, PropertyID::BackgroundRepeat, component_values.first()); + if (!maybe_value) + return nullptr; + auto value = maybe_value.release_nonnull(); + if (!is_background_repeat(*value)) + return nullptr; + + if (is_directional_repeat(value)) { + auto value_id = value->to_identifier(); + return BackgroundRepeatStyleValue::create( + IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::Repeat : ValueID::NoRepeat), + IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::NoRepeat : ValueID::Repeat)); + } + return BackgroundRepeatStyleValue::create(value, value); + } + + if (component_values.size() == 2) { + auto maybe_x_value = parse_css_value(context, PropertyID::BackgroundRepeatX, component_values[0]); + auto maybe_y_value = parse_css_value(context, PropertyID::BackgroundRepeatY, component_values[1]); + if (!maybe_x_value || !maybe_y_value) + return nullptr; + + auto x_value = maybe_x_value.release_nonnull(); + auto y_value = maybe_y_value.release_nonnull(); + if (!is_background_repeat(x_value) || !is_background_repeat(y_value)) + return nullptr; + if (is_directional_repeat(x_value) || is_directional_repeat(y_value)) + return nullptr; + return BackgroundRepeatStyleValue::create(x_value, y_value); + } + + // FIXME: Handle multiple sets of comma-separated values. + dbgln("CSS Parser does not yet support multiple comma-separated values for background-repeat."); + return nullptr; +} + RefPtr Parser::parse_border_value(ParsingContext const& context, PropertyID property_id, Vector const& component_values) { auto is_line_style = [](StyleValue const& value) -> bool { @@ -2652,6 +2697,10 @@ RefPtr Parser::parse_css_value(PropertyID property_id, TokenStream parse_string_value(ParsingContext const&, StyleComponentValueRule const&); static RefPtr parse_image_value(ParsingContext const&, StyleComponentValueRule const&); static RefPtr parse_background_value(ParsingContext const&, Vector const&); + static RefPtr parse_background_repeat_value(ParsingContext const&, Vector const&); static RefPtr parse_border_value(ParsingContext const&, PropertyID, Vector const&); static RefPtr parse_border_radius_value(ParsingContext const&, Vector const&); static RefPtr parse_border_radius_shorthand_value(ParsingContext const&, Vector const&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp index 3d6181741f..07d3fd5f11 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp @@ -427,41 +427,30 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope } if (property_id == CSS::PropertyID::BackgroundRepeat) { - auto assign_background_repeat_from_single_value = [&](StyleValue const& value) { - auto value_id = value.to_identifier(); - if (value_id == ValueID::RepeatX || value_id == ValueID::RepeatY) { - auto repeat_x = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::Repeat : ValueID::NoRepeat); - auto repeat_y = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::NoRepeat : ValueID::Repeat); - set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, repeat_x, document, true); - set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, repeat_y, document, true); - } else { - set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, value, document, true); - set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, value, document, true); - } - }; - - if (value.is_component_value_list()) { - auto parts = static_cast(value).values(); - NonnullRefPtrVector repeat_values; - for (auto& part : parts) { - if (part.is(Token::Type::Comma)) { - // FIXME: Handle multiple backgrounds. - break; + if (value.is_value_list()) { + auto& background_repeat_list = static_cast(value).values(); + // FIXME: Handle multiple backgrounds. + if (!background_repeat_list.is_empty()) { + auto& maybe_background_repeat = background_repeat_list.first(); + if (maybe_background_repeat.is_background_repeat()) { + auto& background_repeat = static_cast(maybe_background_repeat); + set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, background_repeat.repeat_x(), document, true); + set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, background_repeat.repeat_y(), document, true); } - auto parsed_value = Parser::parse_css_value(context, property_id, part); - if (parsed_value) - repeat_values.append(parsed_value.release_nonnull()); - } - if (repeat_values.size() == 1) { - assign_background_repeat_from_single_value(repeat_values[0]); - } else if (repeat_values.size() == 2) { - set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, repeat_values[0], document, true); - set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, repeat_values[1], document, true); } return; } - - assign_background_repeat_from_single_value(value); + if (value.is_background_repeat()) { + auto& background_repeat = static_cast(value); + set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, background_repeat.repeat_x(), document, true); + set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, background_repeat.repeat_y(), document, true); + return; + } + if (value.is_builtin()) { + set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, value, document, true); + set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, value, document, true); + return; + } return; } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 4a190f5e76..49d131e125 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -230,6 +230,7 @@ public: ComponentValueList, Calculated, Background, + BackgroundRepeat, Border, BorderRadius, BoxShadow, @@ -256,6 +257,7 @@ public: bool is_component_value_list() const { return type() == Type::ComponentValueList; } bool is_calculated() const { return type() == Type::Calculated; } bool is_background() const { return type() == Type::Background; } + bool is_background_repeat() const { return type() == Type::BackgroundRepeat; } bool is_border() const { return type() == Type::Border; } bool is_border_radius() const { return type() == Type::BorderRadius; } bool is_box_shadow() const { return type() == Type::BoxShadow; } @@ -687,6 +689,34 @@ private: // FIXME: background-origin }; +class BackgroundRepeatStyleValue final : public StyleValue { +public: + static NonnullRefPtr create(NonnullRefPtr repeat_x, NonnullRefPtr repeat_y) + { + return adopt_ref(*new BackgroundRepeatStyleValue(repeat_x, repeat_y)); + } + virtual ~BackgroundRepeatStyleValue() override { } + + NonnullRefPtr repeat_x() const { return m_repeat_x; } + NonnullRefPtr repeat_y() const { return m_repeat_y; } + + virtual String to_string() const override + { + return String::formatted("{} {}", m_repeat_x->to_string(), m_repeat_y->to_string()); + } + +private: + BackgroundRepeatStyleValue(NonnullRefPtr repeat_x, NonnullRefPtr repeat_y) + : StyleValue(Type::BackgroundRepeat) + , m_repeat_x(repeat_x) + , m_repeat_y(repeat_y) + { + } + + NonnullRefPtr m_repeat_x; + NonnullRefPtr m_repeat_y; +}; + class BorderStyleValue final : public StyleValue { public: static NonnullRefPtr create(