diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-08-03 15:56:51 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-14 12:45:01 +0200 |
commit | 0e15561df08a5fe0d080cbd3a2dcb1b0c750a24b (patch) | |
tree | b5324674ba0a4e1bec888b166859d0478e32b895 /Userland | |
parent | dcbfb618169858dcea1a654505c55f72b6e277b7 (diff) | |
download | serenity-0e15561df08a5fe0d080cbd3a2dcb1b0c750a24b.zip |
LibWeb: Implement and use ListStyleStyleValue
Yes, the name is silly, but it's a StyleValue for list-style, so...
yeah. :^)
Since `list-style-type` and `list-style-image` can both have `none` as a
value, and can appear in any order, we have to handle it separately, and
then assign either or both of those to `none` depending on how many
`none`s there are, and whether those sub-properties already have values.
Added some extra test cases to lists.html to cover list-style-image and
list-style-position parts of the list-style shorthand, and the `none`
values.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 114 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleResolver.cpp | 106 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleValue.h | 39 |
4 files changed, 162 insertions, 98 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index b222f02453..d933b8bcc5 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -2063,6 +2063,116 @@ RefPtr<StyleValue> Parser::parse_font_value(ParsingContext const& context, Vecto return FontStyleValue::create(font_style.release_nonnull(), font_weight.release_nonnull(), font_size.release_nonnull(), line_height.release_nonnull(), move(font_families)); } +RefPtr<StyleValue> Parser::parse_list_style_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values) +{ + auto is_list_style_image = [](StyleValue const& value) -> bool { + if (value.is_image()) + return true; + if (value.is_identifier() && value.to_identifier() == ValueID::None) + return true; + + return false; + }; + + auto is_list_style_position = [](StyleValue const& value) -> bool { + switch (value.to_identifier()) { + case ValueID::Inside: + case ValueID::Outside: + return true; + default: + return false; + } + }; + + auto is_list_style_type = [](StyleValue const& value) -> bool { + // FIXME: Handle strings and symbols("...") syntax + switch (value.to_identifier()) { + case CSS::ValueID::None: + case CSS::ValueID::Disc: + case CSS::ValueID::Circle: + case CSS::ValueID::Square: + case CSS::ValueID::Decimal: + case CSS::ValueID::DecimalLeadingZero: + case CSS::ValueID::LowerAlpha: + case CSS::ValueID::LowerLatin: + case CSS::ValueID::UpperAlpha: + case CSS::ValueID::UpperLatin: + case CSS::ValueID::UpperRoman: + case CSS::ValueID::LowerRoman: + return true; + default: + return false; + } + }; + + if (component_values.size() > 3) + return nullptr; + + RefPtr<StyleValue> list_position; + RefPtr<StyleValue> list_image; + RefPtr<StyleValue> list_type; + int found_nones = 0; + + for (auto& part : component_values) { + auto value = parse_css_value(context, PropertyID::ListStyle, part); + if (!value) + return nullptr; + + if (value->to_identifier() == ValueID::None) { + found_nones++; + continue; + } + + if (is_list_style_position(*value)) { + if (list_position) + return nullptr; + list_position = value.release_nonnull(); + continue; + } + if (is_list_style_image(*value)) { + if (list_image) + return nullptr; + list_image = value.release_nonnull(); + continue; + } + if (is_list_style_type(*value)) { + if (list_type) + return nullptr; + list_type = value.release_nonnull(); + continue; + } + } + + if (found_nones > 2) + return nullptr; + + if (found_nones == 2) { + if (list_image || list_type) + return nullptr; + auto none = IdentifierStyleValue::create(ValueID::None); + list_image = none; + list_type = none; + + } else if (found_nones == 1) { + if (list_image && list_type) + return nullptr; + auto none = IdentifierStyleValue::create(ValueID::None); + if (!list_image) + list_image = none; + if (!list_type) + list_type = none; + } + + if (!list_position) + list_position = IdentifierStyleValue::create(ValueID::Outside); + if (!list_image) + list_image = IdentifierStyleValue::create(ValueID::None); + if (!list_type) + list_type = IdentifierStyleValue::create(ValueID::Disc); + + return ListStyleStyleValue::create(list_position.release_nonnull(), list_image.release_nonnull(), list_type.release_nonnull()); +} + RefPtr<StyleValue> Parser::parse_as_css_value(PropertyID property_id) { auto component_values = parse_as_list_of_component_values(); @@ -2105,6 +2215,10 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S if (auto parsed_value = parse_font_value(m_context, component_values)) return parsed_value; break; + case PropertyID::ListStyle: + if (auto parsed_value = parse_list_style_value(m_context, component_values)) + return parsed_value; + break; default: break; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 2a4c4d51d9..5e666be8ca 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -178,6 +178,7 @@ private: static RefPtr<StyleValue> parse_background_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); static RefPtr<StyleValue> parse_box_shadow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); static RefPtr<StyleValue> parse_font_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); + static RefPtr<StyleValue> parse_list_style_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); // calc() parsing, according to https://www.w3.org/TR/css-values-3/#calc-syntax static OwnPtr<CalculatedStyleValue::CalcSum> parse_calc_sum(ParsingContext const&, TokenStream<StyleComponentValueRule>&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp index 89ae825ddb..0e759ade69 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp @@ -336,56 +336,6 @@ static inline bool is_line_width(StyleValue const& value) } } -static inline bool is_list_style_image(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - if (value.is_image()) - return true; - if (value.is_identifier() && value.to_identifier() == ValueID::None) - return true; - - return false; -} - -static inline bool is_list_style_position(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - - switch (value.to_identifier()) { - case ValueID::Inside: - case ValueID::Outside: - return true; - default: - return false; - } -} - -static inline bool is_list_style_type(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - // FIXME: Handle strings and symbols("...") syntax - switch (value.to_identifier()) { - case CSS::ValueID::None: - case CSS::ValueID::Disc: - case CSS::ValueID::Circle: - case CSS::ValueID::Square: - case CSS::ValueID::Decimal: - case CSS::ValueID::DecimalLeadingZero: - case CSS::ValueID::LowerAlpha: - case CSS::ValueID::LowerLatin: - case CSS::ValueID::UpperAlpha: - case CSS::ValueID::UpperLatin: - case CSS::ValueID::UpperRoman: - case CSS::ValueID::LowerRoman: - return true; - default: - return true; - } -} - static inline bool is_text_decoration_line(StyleValue const& value) { if (value.is_builtin_or_dynamic()) @@ -868,59 +818,19 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope } if (property_id == CSS::PropertyID::ListStyle) { - if (value.is_component_value_list()) { - auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values(); - - if (!parts.is_empty() && parts.size() <= 3) { - RefPtr<StyleValue> position_value; - RefPtr<StyleValue> image_value; - RefPtr<StyleValue> type_value; - - // FIXME: `none` is ambiguous as it is a valid value for ListStyleImage and ListStyleType, - // so requires special handling. https://www.w3.org/TR/css-lists-3/#propdef-list-style - - for (auto& part : parts) { - auto value = Parser::parse_css_value(context, property_id, part); - if (!value) - return; - - if (is_list_style_position(*value)) { - if (position_value) - return; - position_value = move(value); - continue; - } - if (is_list_style_image(*value)) { - if (image_value) - return; - image_value = move(value); - continue; - } - if (is_list_style_type(*value)) { - if (type_value) - return; - type_value = move(value); - continue; - } - } - - if (position_value) - style.set_property(CSS::PropertyID::ListStylePosition, *position_value); - if (image_value) - style.set_property(CSS::PropertyID::ListStyleImage, *image_value); - if (type_value) - style.set_property(CSS::PropertyID::ListStyleType, *type_value); - } + if (value.is_list_style()) { + auto& list_style = static_cast<CSS::ListStyleStyleValue const&>(value); + style.set_property(CSS::PropertyID::ListStylePosition, list_style.position()); + style.set_property(CSS::PropertyID::ListStyleImage, list_style.image()); + style.set_property(CSS::PropertyID::ListStyleType, list_style.style_type()); return; } - - if (is_list_style_position(value)) + if (value.is_builtin()) { style.set_property(CSS::PropertyID::ListStylePosition, value); - else if (is_list_style_image(value)) style.set_property(CSS::PropertyID::ListStyleImage, value); - else if (is_list_style_type(value)) style.set_property(CSS::PropertyID::ListStyleType, value); - + return; + } return; } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index fa0d859b86..4a19bf8a6b 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -232,6 +232,7 @@ public: Background, BoxShadow, Font, + ListStyle, }; Type type() const { return m_type; } @@ -251,6 +252,7 @@ public: bool is_background() const { return type() == Type::Background; } bool is_box_shadow() const { return type() == Type::BoxShadow; } bool is_font() const { return type() == Type::Font; } + bool is_list_style() const { return type() == Type::ListStyle; } bool is_builtin() const { return is_inherit() || is_initial(); } @@ -717,6 +719,43 @@ private: // FIXME: Implement font-stretch and font-variant. }; +class ListStyleStyleValue final : public StyleValue { +public: + static NonnullRefPtr<ListStyleStyleValue> create( + NonnullRefPtr<StyleValue> position, + NonnullRefPtr<StyleValue> image, + NonnullRefPtr<StyleValue> style_type) + { + return adopt_ref(*new ListStyleStyleValue(position, image, style_type)); + } + virtual ~ListStyleStyleValue() override { } + + NonnullRefPtr<StyleValue> position() const { return m_position; } + NonnullRefPtr<StyleValue> image() const { return m_image; } + NonnullRefPtr<StyleValue> style_type() const { return m_style_type; } + + virtual String to_string() const override + { + return String::formatted("ListStyle position: {}, image: {}, style_type: {}", m_position->to_string(), m_image->to_string(), m_style_type->to_string()); + } + +private: + ListStyleStyleValue( + NonnullRefPtr<StyleValue> position, + NonnullRefPtr<StyleValue> image, + NonnullRefPtr<StyleValue> style_type) + : StyleValue(Type::ListStyle) + , m_position(position) + , m_image(image) + , m_style_type(style_type) + { + } + + NonnullRefPtr<StyleValue> m_position; + NonnullRefPtr<StyleValue> m_image; + NonnullRefPtr<StyleValue> m_style_type; +}; + class StyleValueList final : public StyleValue { public: static NonnullRefPtr<StyleValueList> create(NonnullRefPtrVector<StyleValue>&& values) { return adopt_ref(*new StyleValueList(move(values))); } |