summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-08-04 12:34:14 +0100
committerAndreas Kling <kling@serenityos.org>2021-08-14 12:45:01 +0200
commit44a082391be71d3f4a44de7e502cd9b9dc8863f1 (patch)
tree20b3f4d2e246c9709c749afb2bbcf8b8146dbc4e
parent0e15561df08a5fe0d080cbd3a2dcb1b0c750a24b (diff)
downloadserenity-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.html6
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp78
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h1
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleResolver.cpp92
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValue.h39
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))); }