From 4d7ce818354a7d2131b77107488f971aeca6a04f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 15 Dec 2020 13:36:27 +0100 Subject: [PATCH] LibWeb: Use IdentifierStyleValue for CSS 'text-decoration-line' Also 'text-decoration' is actually a shorthand, so treat it that way. --- Libraries/LibWeb/CSS/Parser/CSSParser.cpp | 8 ++++++++ Libraries/LibWeb/CSS/Properties.json | 22 ++++++++++++++++++++++ Libraries/LibWeb/CSS/StyleProperties.cpp | 21 +++++++++++++++++++++ Libraries/LibWeb/CSS/StyleProperties.h | 1 + Libraries/LibWeb/CSS/StyleResolver.cpp | 14 ++++++++++++++ Libraries/LibWeb/CSS/StyleValue.h | 21 +++++++++++++++++++++ Libraries/LibWeb/Layout/LayoutStyle.h | 4 ++++ Libraries/LibWeb/Layout/Node.cpp | 4 ++++ Libraries/LibWeb/Layout/TextNode.cpp | 4 +--- 9 files changed, 96 insertions(+), 3 deletions(-) diff --git a/Libraries/LibWeb/CSS/Parser/CSSParser.cpp b/Libraries/LibWeb/CSS/Parser/CSSParser.cpp index 0d3b6c2d39..991a9858ad 100644 --- a/Libraries/LibWeb/CSS/Parser/CSSParser.cpp +++ b/Libraries/LibWeb/CSS/Parser/CSSParser.cpp @@ -446,6 +446,14 @@ static Optional value_id_from_string(const String& string) return CSS::ValueID::TableHeaderGroup; if (string.equals_ignoring_case("table-footer-group")) return CSS::ValueID::TableFooterGroup; + if (string.equals_ignoring_case("underline")) + return CSS::ValueID::Underline; + if (string.equals_ignoring_case("overline")) + return CSS::ValueID::Overline; + if (string.equals_ignoring_case("line-through")) + return CSS::ValueID::LineThrough; + if (string.equals_ignoring_case("blink")) + return CSS::ValueID::Blink; if (string.starts_with("-libweb-palette-", CaseSensitivity::CaseInsensitive)) return value_id_for_palette_string(string.substring_view(16, string.length() - 16)); return {}; diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index d902e74087..86c4009834 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -304,6 +304,28 @@ "initial": "left" }, "text-decoration": { + "inherited": false, + "initial": "none", + "longhands": [ + "text-decoration-color", + "text-decoration-line", + "text-decoration-style", + "text-decoration-thickness" + ] + }, + "text-decoration-color": { + "inherited": false, + "initial": "none" + }, + "text-decoration-line": { + "inherited": false, + "initial": "none" + }, + "text-decoration-style": { + "inherited": false, + "initial": "none" + }, + "text-decoration-thickness": { "inherited": false, "initial": "none" }, diff --git a/Libraries/LibWeb/CSS/StyleProperties.cpp b/Libraries/LibWeb/CSS/StyleProperties.cpp index f374f29ec1..6af5ef0084 100644 --- a/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -409,4 +409,25 @@ CSS::Display StyleProperties::display() const } } +Optional StyleProperties::text_decoration_line() const +{ + auto value = property(CSS::PropertyID::TextDecorationLine); + if (!value.has_value() || !value.value()->is_identifier()) + return {}; + switch (static_cast(*value.value()).id()) { + case CSS::ValueID::None: + return CSS::TextDecorationLine::None; + case CSS::ValueID::Underline: + return CSS::TextDecorationLine::Underline; + case CSS::ValueID::Overline: + return CSS::TextDecorationLine::Overline; + case CSS::ValueID::LineThrough: + return CSS::TextDecorationLine::LineThrough; + case CSS::ValueID::Blink: + return CSS::TextDecorationLine::Blink; + default: + return {}; + } +} + } diff --git a/Libraries/LibWeb/CSS/StyleProperties.h b/Libraries/LibWeb/CSS/StyleProperties.h index f23dbef7dd..78330438ba 100644 --- a/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Libraries/LibWeb/CSS/StyleProperties.h @@ -66,6 +66,7 @@ public: Optional clear() const; Optional white_space() const; Optional line_style(CSS::PropertyID) const; + Optional text_decoration_line() const; const Gfx::Font& font() const { diff --git a/Libraries/LibWeb/CSS/StyleResolver.cpp b/Libraries/LibWeb/CSS/StyleResolver.cpp index 5eb4091e2f..42c56ba2c9 100644 --- a/Libraries/LibWeb/CSS/StyleResolver.cpp +++ b/Libraries/LibWeb/CSS/StyleResolver.cpp @@ -229,6 +229,20 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope { CSS::ParsingContext context(document); + if (property_id == CSS::PropertyID::TextDecoration) { + switch (value.to_identifier()) { + case CSS::ValueID::None: + case CSS::ValueID::Underline: + case CSS::ValueID::Overline: + case CSS::ValueID::LineThrough: + case CSS::ValueID::Blink: + set_property_expanding_shorthands(style, CSS::PropertyID::TextDecorationLine, value, document); + default: + break; + } + return; + } + if (property_id == CSS::PropertyID::Border) { set_property_expanding_shorthands(style, CSS::PropertyID::BorderTop, value, document); set_property_expanding_shorthands(style, CSS::PropertyID::BorderRight, value, document); diff --git a/Libraries/LibWeb/CSS/StyleValue.h b/Libraries/LibWeb/CSS/StyleValue.h index db3dc1aaf2..8cf2dd47de 100644 --- a/Libraries/LibWeb/CSS/StyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValue.h @@ -147,6 +147,10 @@ enum class ValueID { TableHeaderGroup, TableRowGroup, TableFooterGroup, + Underline, + Overline, + LineThrough, + Blink, }; enum class Position { @@ -165,6 +169,14 @@ enum class TextAlign { VendorSpecificCenter, }; +enum class TextDecorationLine { + None, + Underline, + Overline, + LineThrough, + Blink, +}; + enum class Display { None, Block, @@ -244,6 +256,8 @@ public: virtual Length to_length() const { return Length::make_auto(); } virtual Color to_color(const DOM::Document&) const { return {}; } + CSS::ValueID to_identifier() const; + virtual bool is_auto() const { return false; } bool operator==(const StyleValue& other) const { return equals(other); } @@ -410,4 +424,11 @@ private: RefPtr m_bitmap; }; +inline CSS::ValueID StyleValue::to_identifier() const +{ + if (is_identifier()) + return static_cast(*this).id(); + return CSS::ValueID::Invalid; +} + } diff --git a/Libraries/LibWeb/Layout/LayoutStyle.h b/Libraries/LibWeb/Layout/LayoutStyle.h index f8f9ee8b6c..2c0b077ede 100644 --- a/Libraries/LibWeb/Layout/LayoutStyle.h +++ b/Libraries/LibWeb/Layout/LayoutStyle.h @@ -39,6 +39,7 @@ public: static CSS::WhiteSpace white_space() { return CSS::WhiteSpace::Normal; } static CSS::TextAlign text_align() { return CSS::TextAlign::Left; } static CSS::Position position() { return CSS::Position::Static; } + static CSS::TextDecorationLine text_decoration_line() { return CSS::TextDecorationLine::None; } }; struct BorderData { @@ -54,6 +55,7 @@ public: CSS::Clear clear() const { return m_clear; } Optional z_index() const { return m_z_index; } CSS::TextAlign text_align() const { return m_text_align; } + CSS::TextDecorationLine text_decoration_line() const { return m_text_decoration_line; } CSS::Position position() const { return m_position; } CSS::WhiteSpace white_space() const { return m_white_space; } const CSS::Length& width() const { return m_width; } @@ -77,6 +79,7 @@ protected: CSS::Clear m_clear { InitialValues::clear() }; Optional m_z_index; CSS::TextAlign m_text_align { InitialValues::text_align() }; + CSS::TextDecorationLine m_text_decoration_line { InitialValues::text_decoration_line() }; CSS::Position m_position { InitialValues::position() }; CSS::WhiteSpace m_white_space { InitialValues::white_space() }; CSS::Length m_width; @@ -103,6 +106,7 @@ public: void set_clear(CSS::Clear value) { m_clear = value; } void set_z_index(Optional value) { m_z_index = value; } void set_text_align(CSS::TextAlign text_align) { m_text_align = text_align; } + void set_text_decoration_line(CSS::TextDecorationLine value) { m_text_decoration_line = value; } void set_position(CSS::Position position) { m_position = position; } void set_white_space(CSS::WhiteSpace value) { m_white_space = value; } void set_width(const CSS::Length& width) { m_width = width; } diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index ff7105a742..adf13069a6 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -239,6 +239,10 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) if (clear.has_value()) style.set_clear(clear.value()); + auto text_decoration_line = specified_style.text_decoration_line(); + if (text_decoration_line.has_value()) + style.set_text_decoration_line(text_decoration_line.value()); + style.set_z_index(specified_style.z_index()); style.set_width(specified_style.length_or_fallback(CSS::PropertyID::Width, {})); style.set_min_width(specified_style.length_or_fallback(CSS::PropertyID::MinWidth, {})); diff --git a/Libraries/LibWeb/Layout/TextNode.cpp b/Libraries/LibWeb/Layout/TextNode.cpp index 0ae4546cbb..8b241022b8 100644 --- a/Libraries/LibWeb/Layout/TextNode.cpp +++ b/Libraries/LibWeb/Layout/TextNode.cpp @@ -80,13 +80,11 @@ void TextNode::paint_fragment(PaintContext& context, const LineBoxFragment& frag if (phase == PaintPhase::Foreground) { painter.set_font(specified_style().font()); auto color = specified_style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text()); - auto text_decoration = specified_style().string_or_fallback(CSS::PropertyID::TextDecoration, "none"); if (document().inspected_node() == &dom_node()) context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Magenta); - bool is_underline = text_decoration == "underline"; - if (is_underline) + if (style().text_decoration_line() == CSS::TextDecorationLine::Underline) painter.draw_line(enclosing_int_rect(fragment.absolute_rect()).bottom_left().translated(0, 1), enclosing_int_rect(fragment.absolute_rect()).bottom_right().translated(0, 1), color); // FIXME: text-transform should be done already in layout, since uppercase glyphs may be wider than lowercase, etc.