diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-08-04 12:34:14 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-14 12:45:01 +0200 |
commit | 44a082391be71d3f4a44de7e502cd9b9dc8863f1 (patch) | |
tree | 20b3f4d2e246c9709c749afb2bbcf8b8146dbc4e | |
parent | 0e15561df08a5fe0d080cbd3a2dcb1b0c750a24b (diff) | |
download | serenity-44a082391be71d3f4a44de7e502cd9b9dc8863f1.zip |
LibWeb: Implement and use TextDecorationStyleValue
Modified text-decoration.html to better test that the values can be in
any order, and that it adopts the color from the `color` property if no
decoration color is specified. Right now, it always does because we do
not support a different decoration color. Later, we need to support the
`currentcolor` special CSS value for this purpose.
-rw-r--r-- | Base/res/html/misc/text-decoration.html | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 78 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleResolver.cpp | 92 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleValue.h | 39 |
5 files changed, 129 insertions, 87 deletions
diff --git a/Base/res/html/misc/text-decoration.html b/Base/res/html/misc/text-decoration.html index 3406e82c76..562fb4b772 100644 --- a/Base/res/html/misc/text-decoration.html +++ b/Base/res/html/misc/text-decoration.html @@ -4,9 +4,10 @@ <title>text-decoration test</title> <style> .overline { text-decoration: wavy blue overline; } -.underline { text-decoration: double red underline; } -.strikethrough { text-decoration: dotted green line-through; } +.underline { text-decoration: red underline double; } +.strikethrough { text-decoration: line-through dotted green; } .blink { text-decoration: blink; } +.current-color { color: #8B4513; text-decoration: underline; } </style> </head> <body> @@ -14,5 +15,6 @@ <p class="underline">Underline</p> <p class="strikethrough">Wombling</p> <p class="blink">FREE!</p> + <p class="current-color">This underline should match the text color</p> </body> </html> diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index d933b8bcc5..06a3135178 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -2173,6 +2173,80 @@ RefPtr<StyleValue> Parser::parse_list_style_value(ParsingContext const& context, return ListStyleStyleValue::create(list_position.release_nonnull(), list_image.release_nonnull(), list_type.release_nonnull()); } +RefPtr<StyleValue> Parser::parse_text_decoration_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values) +{ + auto is_text_decoration_line = [](StyleValue const& value) -> bool { + switch (value.to_identifier()) { + case ValueID::None: + case ValueID::Underline: + case ValueID::Overline: + case ValueID::LineThrough: + case ValueID::Blink: + return true; + default: + return false; + } + }; + + auto is_text_decoration_style = [](StyleValue const& value) -> bool { + switch (value.to_identifier()) { + case ValueID::Solid: + case ValueID::Double: + case ValueID::Dotted: + case ValueID::Dashed: + case ValueID::Wavy: + return true; + default: + return false; + } + }; + + if (component_values.size() > 3) + return nullptr; + + RefPtr<StyleValue> decoration_line; + RefPtr<StyleValue> decoration_style; + RefPtr<StyleValue> decoration_color; + // FIXME: Implement 'text-decoration-thickness' parameter. https://www.w3.org/TR/css-text-decor-4/#text-decoration-width-property + + for (auto& part : component_values) { + auto value = parse_css_value(context, PropertyID::TextDecoration, part); + if (!value) + return nullptr; + + if (value->is_color()) { + if (decoration_color) + return nullptr; + decoration_color = value.release_nonnull(); + continue; + } + if (is_text_decoration_line(*value)) { + if (decoration_line) + return nullptr; + decoration_line = value.release_nonnull(); + continue; + } + if (is_text_decoration_style(*value)) { + if (decoration_style) + return nullptr; + decoration_style = value.release_nonnull(); + continue; + } + + return nullptr; + } + + if (!decoration_line) + decoration_line = IdentifierStyleValue::create(ValueID::None); + if (!decoration_style) + decoration_style = IdentifierStyleValue::create(ValueID::Solid); + // FIXME: Should default to 'currentcolor' special value: https://www.w3.org/TR/css-color-3/#currentcolor + if (!decoration_color) + decoration_color = InitialStyleValue::create(); + + return TextDecorationStyleValue::create(decoration_line.release_nonnull(), decoration_style.release_nonnull(), decoration_color.release_nonnull()); +} + RefPtr<StyleValue> Parser::parse_as_css_value(PropertyID property_id) { auto component_values = parse_as_list_of_component_values(); @@ -2219,6 +2293,10 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S if (auto parsed_value = parse_list_style_value(m_context, component_values)) return parsed_value; break; + case PropertyID::TextDecoration: + if (auto parsed_value = parse_text_decoration_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 5e666be8ca..f620e2fde1 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -179,6 +179,7 @@ private: 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&); + static RefPtr<StyleValue> parse_text_decoration_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 0e759ade69..387b0308e9 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp @@ -336,40 +336,6 @@ static inline bool is_line_width(StyleValue const& value) } } -static inline bool is_text_decoration_line(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - - switch (value.to_identifier()) { - case ValueID::None: - case ValueID::Underline: - case ValueID::Overline: - case ValueID::LineThrough: - case ValueID::Blink: - return true; - default: - return false; - } -} - -static inline bool is_text_decoration_style(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - - switch (value.to_identifier()) { - case ValueID::Solid: - case ValueID::Double: - case ValueID::Dotted: - case ValueID::Dashed: - case ValueID::Wavy: - return true; - default: - return false; - } -} - static void set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, StyleValue const& value, DOM::Document& document, bool is_internally_generated_pseudo_property = false) { CSS::ParsingContext context(document); @@ -404,63 +370,19 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope }; if (property_id == CSS::PropertyID::TextDecoration) { - if (value.is_color()) { - style.set_property(CSS::PropertyID::TextDecorationColor, value); + if (value.is_text_decoration()) { + auto& text_decoration = static_cast<TextDecorationStyleValue const&>(value); + style.set_property(CSS::PropertyID::TextDecorationLine, text_decoration.line()); + style.set_property(CSS::PropertyID::TextDecorationStyle, text_decoration.style()); + style.set_property(CSS::PropertyID::TextDecorationColor, text_decoration.color()); return; } - if (is_text_decoration_line(value)) { + if (value.is_builtin()) { style.set_property(CSS::PropertyID::TextDecorationLine, value); - return; - } - if (is_text_decoration_style(value)) { style.set_property(CSS::PropertyID::TextDecorationStyle, value); + style.set_property(CSS::PropertyID::TextDecorationColor, value); return; } - - if (value.is_component_value_list()) { - auto& parts = static_cast<CSS::ValueListStyleValue const&>(value).values(); - if (!parts.is_empty() && parts.size() <= 3) { - RefPtr<StyleValue> color_value; - RefPtr<StyleValue> line_value; - RefPtr<StyleValue> style_value; - - for (auto& part : parts) { - auto value = Parser::parse_css_value(context, property_id, part); - if (!value) - return; - - if (value->is_color()) { - if (color_value) - return; - color_value = move(value); - continue; - } - if (is_text_decoration_line(*value)) { - if (line_value) - return; - line_value = move(value); - continue; - } - if (is_text_decoration_style(*value)) { - if (style_value) - return; - style_value = move(value); - continue; - } - - return; - } - - if (color_value) - style.set_property(CSS::PropertyID::TextDecorationColor, *color_value); - if (line_value) - style.set_property(CSS::PropertyID::TextDecorationLine, *line_value); - if (style_value) - style.set_property(CSS::PropertyID::TextDecorationStyle, *style_value); - } - return; - } - return; } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 4a19bf8a6b..bcbde3f97f 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -233,6 +233,7 @@ public: BoxShadow, Font, ListStyle, + TextDecoration, }; Type type() const { return m_type; } @@ -253,6 +254,7 @@ public: 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_text_decoration() const { return type() == Type::TextDecoration; } bool is_builtin() const { return is_inherit() || is_initial(); } @@ -756,6 +758,43 @@ private: NonnullRefPtr<StyleValue> m_style_type; }; +class TextDecorationStyleValue final : public StyleValue { +public: + static NonnullRefPtr<TextDecorationStyleValue> create( + NonnullRefPtr<StyleValue> line, + NonnullRefPtr<StyleValue> style, + NonnullRefPtr<StyleValue> color) + { + return adopt_ref(*new TextDecorationStyleValue(line, style, color)); + } + virtual ~TextDecorationStyleValue() override { } + + NonnullRefPtr<StyleValue> line() const { return m_line; } + NonnullRefPtr<StyleValue> style() const { return m_style; } + NonnullRefPtr<StyleValue> color() const { return m_color; } + + virtual String to_string() const override + { + return String::formatted("TextDecoration line: {}, style: {}, color: {}", m_line->to_string(), m_style->to_string(), m_color->to_string()); + } + +private: + TextDecorationStyleValue( + NonnullRefPtr<StyleValue> line, + NonnullRefPtr<StyleValue> style, + NonnullRefPtr<StyleValue> color) + : StyleValue(Type::TextDecoration) + , m_line(line) + , m_style(style) + , m_color(color) + { + } + + NonnullRefPtr<StyleValue> m_line; + NonnullRefPtr<StyleValue> m_style; + NonnullRefPtr<StyleValue> m_color; +}; + class StyleValueList final : public StyleValue { public: static NonnullRefPtr<StyleValueList> create(NonnullRefPtrVector<StyleValue>&& values) { return adopt_ref(*new StyleValueList(move(values))); } |