summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-08-05 21:11:38 +0100
committerAndreas Kling <kling@serenityos.org>2021-08-14 12:45:01 +0200
commitcb3e09766387c08e2be6d55d2b6b3499fb132910 (patch)
tree74641e829243e82919596776f0978e56f95ea896
parentc27f99fc1d541f995673653961414a87ac81aee0 (diff)
downloadserenity-cb3e09766387c08e2be6d55d2b6b3499fb132910.zip
LibWeb: Implement and use BorderStyleValue
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp88
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h1
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleResolver.cpp189
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValue.h39
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(