diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-08-05 21:11:38 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-14 12:45:01 +0200 |
commit | cb3e09766387c08e2be6d55d2b6b3499fb132910 (patch) | |
tree | 74641e829243e82919596776f0978e56f95ea896 | |
parent | c27f99fc1d541f995673653961414a87ac81aee0 (diff) | |
download | serenity-cb3e09766387c08e2be6d55d2b6b3499fb132910.zip |
LibWeb: Implement and use BorderStyleValue
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 88 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleResolver.cpp | 189 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleValue.h | 39 |
4 files changed, 148 insertions, 169 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index df4a7d04d5..7b28958d19 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1848,6 +1848,84 @@ RefPtr<StyleValue> 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<StyleValue> Parser::parse_border_value(ParsingContext const& context, PropertyID property_id, Vector<StyleComponentValueRule> const& component_values) +{ + auto is_line_style = [](StyleValue const& value) -> bool { + switch (value.to_identifier()) { + case ValueID::Dotted: + case ValueID::Dashed: + case ValueID::Solid: + case ValueID::Double: + case ValueID::Groove: + case ValueID::Ridge: + case ValueID::None: + case ValueID::Hidden: + case ValueID::Inset: + case ValueID::Outset: + return true; + default: + return false; + } + }; + + auto is_line_width = [](StyleValue const& value) -> bool { + if (value.is_length()) + return true; + + // FIXME: Implement thin/medium/thick + switch (value.to_identifier()) { + case ValueID::None: + return true; + default: + return false; + } + }; + + if (component_values.size() > 3) + return nullptr; + + RefPtr<StyleValue> border_width; + RefPtr<StyleValue> border_color; + RefPtr<StyleValue> border_style; + + for (auto& part : component_values) { + auto value = parse_css_value(context, property_id, part); + if (!value) + return nullptr; + + if (is_line_width(*value)) { + if (border_width) + return nullptr; + border_width = value.release_nonnull(); + continue; + } + if (value->is_color()) { + if (border_color) + return nullptr; + border_color = value.release_nonnull(); + continue; + } + if (is_line_style(*value)) { + if (border_style) + return nullptr; + border_style = value.release_nonnull(); + continue; + } + + return nullptr; + } + + if (!border_width) + border_width = IdentifierStyleValue::create(ValueID::Medium); + if (!border_style) + border_style = IdentifierStyleValue::create(ValueID::None); + // FIXME: Default should be `currentcolor` special value. https://www.w3.org/TR/css-color-4/#currentcolor-color + if (!border_color) + border_color = ColorStyleValue::create(Gfx::Color::Black); + + return BorderStyleValue::create(border_width.release_nonnull(), border_style.release_nonnull(), border_color.release_nonnull()); +} + RefPtr<StyleValue> Parser::parse_box_shadow_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values) { // FIXME: Also support inset, spread-radius and multiple comma-seperated box-shadows @@ -2013,7 +2091,7 @@ RefPtr<StyleValue> Parser::parse_flex_flow_value(ParsingContext const& context, RefPtr<StyleValue> flex_wrap; for (auto& part : component_values) { - auto value = Parser::parse_css_value(context, PropertyID::FlexFlow, part); + auto value = parse_css_value(context, PropertyID::FlexFlow, part); if (!value) return nullptr; if (is_flex_direction(*value)) { @@ -2430,6 +2508,14 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S if (auto parsed_value = parse_background_value(m_context, component_values)) return parsed_value; break; + case PropertyID::Border: + case PropertyID::BorderBottom: + case PropertyID::BorderLeft: + case PropertyID::BorderRight: + case PropertyID::BorderTop: + if (auto parsed_value = parse_border_value(m_context, property_id, component_values)) + return parsed_value; + break; case PropertyID::BoxShadow: if (auto parsed_box_shadow = parse_box_shadow_value(m_context, component_values)) return parsed_box_shadow; diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index d24553e8e0..b71dd6b49b 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -176,6 +176,7 @@ private: static RefPtr<StyleValue> parse_string_value(ParsingContext const&, StyleComponentValueRule const&); static RefPtr<StyleValue> parse_image_value(ParsingContext const&, StyleComponentValueRule const&); static RefPtr<StyleValue> parse_background_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); + static RefPtr<StyleValue> parse_border_value(ParsingContext const&, PropertyID, Vector<StyleComponentValueRule> const&); static RefPtr<StyleValue> parse_box_shadow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); static RefPtr<StyleValue> parse_flex_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); static RefPtr<StyleValue> parse_flex_flow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp index bec66219a7..c58cc4ee0d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp @@ -134,28 +134,6 @@ bool StyleResolver::is_inherited_property(CSS::PropertyID property_id) return inherited_properties.contains(property_id); } -static Vector<String> split_on_whitespace(StringView const& string) -{ - if (string.is_empty()) - return {}; - - Vector<String> v; - size_t substart = 0; - for (size_t i = 0; i < string.length(); ++i) { - char ch = string.characters_without_null_termination()[i]; - if (isspace(ch)) { - size_t sublen = i - substart; - if (sublen != 0) - v.append(string.substring_view(substart, sublen)); - substart = i + 1; - } - } - size_t taillen = string.length() - substart; - if (taillen != 0) - v.append(string.substring_view(substart, taillen)); - return v; -} - enum class Edge { Top, Right, @@ -169,56 +147,6 @@ static bool contains(Edge a, Edge b) return a == b || b == Edge::All; } -static inline void set_property_border_width(StyleProperties& style, StyleValue const& value, Edge edge) -{ - VERIFY(value.is_length()); - if (contains(Edge::Top, edge)) - style.set_property(CSS::PropertyID::BorderTopWidth, value); - if (contains(Edge::Right, edge)) - style.set_property(CSS::PropertyID::BorderRightWidth, value); - if (contains(Edge::Bottom, edge)) - style.set_property(CSS::PropertyID::BorderBottomWidth, value); - if (contains(Edge::Left, edge)) - style.set_property(CSS::PropertyID::BorderLeftWidth, value); -} - -static inline void set_property_border_color(StyleProperties& style, StyleValue const& value, Edge edge) -{ - VERIFY(value.is_color()); - if (contains(Edge::Top, edge)) - style.set_property(CSS::PropertyID::BorderTopColor, value); - if (contains(Edge::Right, edge)) - style.set_property(CSS::PropertyID::BorderRightColor, value); - if (contains(Edge::Bottom, edge)) - style.set_property(CSS::PropertyID::BorderBottomColor, value); - if (contains(Edge::Left, edge)) - style.set_property(CSS::PropertyID::BorderLeftColor, value); -} - -static inline void set_property_border_style(StyleProperties& style, StyleValue const& value, Edge edge) -{ - VERIFY(value.type() == CSS::StyleValue::Type::Identifier); - if (contains(Edge::Top, edge)) - style.set_property(CSS::PropertyID::BorderTopStyle, value); - if (contains(Edge::Right, edge)) - style.set_property(CSS::PropertyID::BorderRightStyle, value); - if (contains(Edge::Bottom, edge)) - style.set_property(CSS::PropertyID::BorderBottomStyle, value); - if (contains(Edge::Left, edge)) - style.set_property(CSS::PropertyID::BorderLeftStyle, value); -} - -static inline bool is_color(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - - if (value.is_color()) - return true; - - return false; -} - static inline bool is_font_family(StyleValue const& value) { if (value.is_builtin_or_dynamic()) @@ -241,45 +169,6 @@ static inline bool is_font_family(StyleValue const& value) } } -static inline bool is_line_style(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - - switch (value.to_identifier()) { - case ValueID::Dotted: - case ValueID::Dashed: - case ValueID::Solid: - case ValueID::Double: - case ValueID::Groove: - case ValueID::Ridge: - case ValueID::None: - case ValueID::Hidden: - case ValueID::Inset: - case ValueID::Outset: - return true; - default: - return false; - } -} - -static inline bool is_line_width(StyleValue const& value) -{ - if (value.is_builtin_or_dynamic()) - return true; - - if (value.is_length()) - return true; - - // FIXME: Implement thin/medium/thick - switch (value.to_identifier()) { - case ValueID::None: - 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); @@ -341,6 +230,7 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope set_property_expanding_shorthands(style, CSS::PropertyID::BorderRight, value, document); set_property_expanding_shorthands(style, CSS::PropertyID::BorderBottom, value, document); set_property_expanding_shorthands(style, CSS::PropertyID::BorderLeft, value, document); + // FIXME: Also reset border-image, in line with the spec: https://www.w3.org/TR/css-backgrounds-3/#border-shorthands return; } @@ -422,65 +312,28 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope break; } - auto parts = split_on_whitespace(value.to_string()); - if (value.is_length()) { - set_property_border_width(style, value, edge); - return; - } - if (value.is_color()) { - set_property_border_color(style, value, edge); - return; - } - - if (value.is_component_value_list()) { - auto& parts = static_cast<CSS::ValueListStyleValue const&>(value).values(); - - if (parts.size() == 1) { - auto value = Parser::parse_css_value(context, property_id, parts[0]); - if (value && is_line_style(*value)) { - set_property_border_style(style, value.release_nonnull(), edge); - set_property_border_color(style, ColorStyleValue::create(Gfx::Color::Black), edge); - set_property_border_width(style, LengthStyleValue::create(Length(3, Length::Type::Px)), edge); - return; - } + if (value.is_border()) { + auto& border = static_cast<BorderStyleValue const&>(value); + if (contains(Edge::Top, edge)) { + style.set_property(PropertyID::BorderTopWidth, border.border_width()); + style.set_property(PropertyID::BorderTopStyle, border.border_style()); + style.set_property(PropertyID::BorderTopColor, border.border_color()); } - - RefPtr<StyleValue> line_width_value; - RefPtr<StyleValue> color_value; - RefPtr<StyleValue> line_style_value; - - for (auto& part : parts) { - auto value = Parser::parse_css_value(context, property_id, part); - if (!value) - return; - - if (is_line_width(*value)) { - if (line_width_value) - return; - line_width_value = move(value); - continue; - } - if (is_color(*value)) { - if (color_value) - return; - color_value = move(value); - continue; - } - if (is_line_style(*value)) { - if (line_style_value) - return; - line_style_value = move(value); - continue; - } + if (contains(Edge::Right, edge)) { + style.set_property(PropertyID::BorderRightWidth, border.border_width()); + style.set_property(PropertyID::BorderRightStyle, border.border_style()); + style.set_property(PropertyID::BorderRightColor, border.border_color()); + } + if (contains(Edge::Bottom, edge)) { + style.set_property(PropertyID::BorderBottomWidth, border.border_width()); + style.set_property(PropertyID::BorderBottomStyle, border.border_style()); + style.set_property(PropertyID::BorderBottomColor, border.border_color()); + } + if (contains(Edge::Left, edge)) { + style.set_property(PropertyID::BorderLeftWidth, border.border_width()); + style.set_property(PropertyID::BorderLeftStyle, border.border_style()); + style.set_property(PropertyID::BorderLeftColor, border.border_color()); } - - if (line_width_value) - set_property_border_width(style, line_width_value.release_nonnull(), edge); - if (color_value) - set_property_border_color(style, color_value.release_nonnull(), edge); - if (line_style_value) - set_property_border_style(style, line_style_value.release_nonnull(), edge); - return; } return; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 8fbe2dd7b8..a08860bfd2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -230,6 +230,7 @@ public: ComponentValueList, Calculated, Background, + Border, BoxShadow, Flex, FlexFlow, @@ -253,6 +254,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_border() const { return type() == Type::Border; } bool is_box_shadow() const { return type() == Type::BoxShadow; } bool is_flex() const { return type() == Type::Flex; } bool is_flex_flow() const { return type() == Type::FlexFlow; } @@ -681,6 +683,43 @@ private: // FIXME: background-origin }; +class BorderStyleValue final : public StyleValue { +public: + static NonnullRefPtr<BorderStyleValue> create( + NonnullRefPtr<StyleValue> border_width, + NonnullRefPtr<StyleValue> border_style, + NonnullRefPtr<StyleValue> border_color) + { + return adopt_ref(*new BorderStyleValue(border_width, border_style, border_color)); + } + virtual ~BorderStyleValue() override { } + + NonnullRefPtr<StyleValue> border_width() const { return m_border_width; } + NonnullRefPtr<StyleValue> border_style() const { return m_border_style; } + NonnullRefPtr<StyleValue> border_color() const { return m_border_color; } + + virtual String to_string() const override + { + return String::formatted("Border border_width: {}, border_style: {}, border_color: {}", m_border_width->to_string(), m_border_style->to_string(), m_border_color->to_string()); + } + +private: + BorderStyleValue( + NonnullRefPtr<StyleValue> border_width, + NonnullRefPtr<StyleValue> border_style, + NonnullRefPtr<StyleValue> border_color) + : StyleValue(Type::Border) + , m_border_width(border_width) + , m_border_style(border_style) + , m_border_color(border_color) + { + } + + NonnullRefPtr<StyleValue> m_border_width; + NonnullRefPtr<StyleValue> m_border_style; + NonnullRefPtr<StyleValue> m_border_color; +}; + class FlexStyleValue final : public StyleValue { public: static NonnullRefPtr<FlexStyleValue> create( |