summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/CSS
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-08-03 15:56:51 +0100
committerAndreas Kling <kling@serenityos.org>2021-08-14 12:45:01 +0200
commit0e15561df08a5fe0d080cbd3a2dcb1b0c750a24b (patch)
treeb5324674ba0a4e1bec888b166859d0478e32b895 /Userland/Libraries/LibWeb/CSS
parentdcbfb618169858dcea1a654505c55f72b6e277b7 (diff)
downloadserenity-0e15561df08a5fe0d080cbd3a2dcb1b0c750a24b.zip
LibWeb: Implement and use ListStyleStyleValue
Yes, the name is silly, but it's a StyleValue for list-style, so... yeah. :^) Since `list-style-type` and `list-style-image` can both have `none` as a value, and can appear in any order, we have to handle it separately, and then assign either or both of those to `none` depending on how many `none`s there are, and whether those sub-properties already have values. Added some extra test cases to lists.html to cover list-style-image and list-style-position parts of the list-style shorthand, and the `none` values.
Diffstat (limited to 'Userland/Libraries/LibWeb/CSS')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp114
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h1
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleResolver.cpp106
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValue.h39
4 files changed, 162 insertions, 98 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index b222f02453..d933b8bcc5 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -2063,6 +2063,116 @@ RefPtr<StyleValue> Parser::parse_font_value(ParsingContext const& context, Vecto
return FontStyleValue::create(font_style.release_nonnull(), font_weight.release_nonnull(), font_size.release_nonnull(), line_height.release_nonnull(), move(font_families));
}
+RefPtr<StyleValue> Parser::parse_list_style_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
+{
+ auto is_list_style_image = [](StyleValue const& value) -> bool {
+ if (value.is_image())
+ return true;
+ if (value.is_identifier() && value.to_identifier() == ValueID::None)
+ return true;
+
+ return false;
+ };
+
+ auto is_list_style_position = [](StyleValue const& value) -> bool {
+ switch (value.to_identifier()) {
+ case ValueID::Inside:
+ case ValueID::Outside:
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ auto is_list_style_type = [](StyleValue const& value) -> bool {
+ // FIXME: Handle strings and symbols("...") syntax
+ switch (value.to_identifier()) {
+ case CSS::ValueID::None:
+ case CSS::ValueID::Disc:
+ case CSS::ValueID::Circle:
+ case CSS::ValueID::Square:
+ case CSS::ValueID::Decimal:
+ case CSS::ValueID::DecimalLeadingZero:
+ case CSS::ValueID::LowerAlpha:
+ case CSS::ValueID::LowerLatin:
+ case CSS::ValueID::UpperAlpha:
+ case CSS::ValueID::UpperLatin:
+ case CSS::ValueID::UpperRoman:
+ case CSS::ValueID::LowerRoman:
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ if (component_values.size() > 3)
+ return nullptr;
+
+ RefPtr<StyleValue> list_position;
+ RefPtr<StyleValue> list_image;
+ RefPtr<StyleValue> list_type;
+ int found_nones = 0;
+
+ for (auto& part : component_values) {
+ auto value = parse_css_value(context, PropertyID::ListStyle, part);
+ if (!value)
+ return nullptr;
+
+ if (value->to_identifier() == ValueID::None) {
+ found_nones++;
+ continue;
+ }
+
+ if (is_list_style_position(*value)) {
+ if (list_position)
+ return nullptr;
+ list_position = value.release_nonnull();
+ continue;
+ }
+ if (is_list_style_image(*value)) {
+ if (list_image)
+ return nullptr;
+ list_image = value.release_nonnull();
+ continue;
+ }
+ if (is_list_style_type(*value)) {
+ if (list_type)
+ return nullptr;
+ list_type = value.release_nonnull();
+ continue;
+ }
+ }
+
+ if (found_nones > 2)
+ return nullptr;
+
+ if (found_nones == 2) {
+ if (list_image || list_type)
+ return nullptr;
+ auto none = IdentifierStyleValue::create(ValueID::None);
+ list_image = none;
+ list_type = none;
+
+ } else if (found_nones == 1) {
+ if (list_image && list_type)
+ return nullptr;
+ auto none = IdentifierStyleValue::create(ValueID::None);
+ if (!list_image)
+ list_image = none;
+ if (!list_type)
+ list_type = none;
+ }
+
+ if (!list_position)
+ list_position = IdentifierStyleValue::create(ValueID::Outside);
+ if (!list_image)
+ list_image = IdentifierStyleValue::create(ValueID::None);
+ if (!list_type)
+ list_type = IdentifierStyleValue::create(ValueID::Disc);
+
+ return ListStyleStyleValue::create(list_position.release_nonnull(), list_image.release_nonnull(), list_type.release_nonnull());
+}
+
RefPtr<StyleValue> Parser::parse_as_css_value(PropertyID property_id)
{
auto component_values = parse_as_list_of_component_values();
@@ -2105,6 +2215,10 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S
if (auto parsed_value = parse_font_value(m_context, component_values))
return parsed_value;
break;
+ case PropertyID::ListStyle:
+ if (auto parsed_value = parse_list_style_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 2a4c4d51d9..5e666be8ca 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
@@ -178,6 +178,7 @@ private:
static RefPtr<StyleValue> parse_background_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
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&);
// 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 89ae825ddb..0e759ade69 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
@@ -336,56 +336,6 @@ static inline bool is_line_width(StyleValue const& value)
}
}
-static inline bool is_list_style_image(StyleValue const& value)
-{
- if (value.is_builtin_or_dynamic())
- return true;
- if (value.is_image())
- return true;
- if (value.is_identifier() && value.to_identifier() == ValueID::None)
- return true;
-
- return false;
-}
-
-static inline bool is_list_style_position(StyleValue const& value)
-{
- if (value.is_builtin_or_dynamic())
- return true;
-
- switch (value.to_identifier()) {
- case ValueID::Inside:
- case ValueID::Outside:
- return true;
- default:
- return false;
- }
-}
-
-static inline bool is_list_style_type(StyleValue const& value)
-{
- if (value.is_builtin_or_dynamic())
- return true;
- // FIXME: Handle strings and symbols("...") syntax
- switch (value.to_identifier()) {
- case CSS::ValueID::None:
- case CSS::ValueID::Disc:
- case CSS::ValueID::Circle:
- case CSS::ValueID::Square:
- case CSS::ValueID::Decimal:
- case CSS::ValueID::DecimalLeadingZero:
- case CSS::ValueID::LowerAlpha:
- case CSS::ValueID::LowerLatin:
- case CSS::ValueID::UpperAlpha:
- case CSS::ValueID::UpperLatin:
- case CSS::ValueID::UpperRoman:
- case CSS::ValueID::LowerRoman:
- return true;
- default:
- return true;
- }
-}
-
static inline bool is_text_decoration_line(StyleValue const& value)
{
if (value.is_builtin_or_dynamic())
@@ -868,59 +818,19 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
}
if (property_id == CSS::PropertyID::ListStyle) {
- if (value.is_component_value_list()) {
- auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
-
- if (!parts.is_empty() && parts.size() <= 3) {
- RefPtr<StyleValue> position_value;
- RefPtr<StyleValue> image_value;
- RefPtr<StyleValue> type_value;
-
- // FIXME: `none` is ambiguous as it is a valid value for ListStyleImage and ListStyleType,
- // so requires special handling. https://www.w3.org/TR/css-lists-3/#propdef-list-style
-
- for (auto& part : parts) {
- auto value = Parser::parse_css_value(context, property_id, part);
- if (!value)
- return;
-
- if (is_list_style_position(*value)) {
- if (position_value)
- return;
- position_value = move(value);
- continue;
- }
- if (is_list_style_image(*value)) {
- if (image_value)
- return;
- image_value = move(value);
- continue;
- }
- if (is_list_style_type(*value)) {
- if (type_value)
- return;
- type_value = move(value);
- continue;
- }
- }
-
- if (position_value)
- style.set_property(CSS::PropertyID::ListStylePosition, *position_value);
- if (image_value)
- style.set_property(CSS::PropertyID::ListStyleImage, *image_value);
- if (type_value)
- style.set_property(CSS::PropertyID::ListStyleType, *type_value);
- }
+ if (value.is_list_style()) {
+ auto& list_style = static_cast<CSS::ListStyleStyleValue const&>(value);
+ style.set_property(CSS::PropertyID::ListStylePosition, list_style.position());
+ style.set_property(CSS::PropertyID::ListStyleImage, list_style.image());
+ style.set_property(CSS::PropertyID::ListStyleType, list_style.style_type());
return;
}
-
- if (is_list_style_position(value))
+ if (value.is_builtin()) {
style.set_property(CSS::PropertyID::ListStylePosition, value);
- else if (is_list_style_image(value))
style.set_property(CSS::PropertyID::ListStyleImage, value);
- else if (is_list_style_type(value))
style.set_property(CSS::PropertyID::ListStyleType, value);
-
+ return;
+ }
return;
}
diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h
index fa0d859b86..4a19bf8a6b 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleValue.h
+++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h
@@ -232,6 +232,7 @@ public:
Background,
BoxShadow,
Font,
+ ListStyle,
};
Type type() const { return m_type; }
@@ -251,6 +252,7 @@ public:
bool is_background() const { return type() == Type::Background; }
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_builtin() const { return is_inherit() || is_initial(); }
@@ -717,6 +719,43 @@ private:
// FIXME: Implement font-stretch and font-variant.
};
+class ListStyleStyleValue final : public StyleValue {
+public:
+ static NonnullRefPtr<ListStyleStyleValue> create(
+ NonnullRefPtr<StyleValue> position,
+ NonnullRefPtr<StyleValue> image,
+ NonnullRefPtr<StyleValue> style_type)
+ {
+ return adopt_ref(*new ListStyleStyleValue(position, image, style_type));
+ }
+ virtual ~ListStyleStyleValue() override { }
+
+ NonnullRefPtr<StyleValue> position() const { return m_position; }
+ NonnullRefPtr<StyleValue> image() const { return m_image; }
+ NonnullRefPtr<StyleValue> style_type() const { return m_style_type; }
+
+ virtual String to_string() const override
+ {
+ return String::formatted("ListStyle position: {}, image: {}, style_type: {}", m_position->to_string(), m_image->to_string(), m_style_type->to_string());
+ }
+
+private:
+ ListStyleStyleValue(
+ NonnullRefPtr<StyleValue> position,
+ NonnullRefPtr<StyleValue> image,
+ NonnullRefPtr<StyleValue> style_type)
+ : StyleValue(Type::ListStyle)
+ , m_position(position)
+ , m_image(image)
+ , m_style_type(style_type)
+ {
+ }
+
+ NonnullRefPtr<StyleValue> m_position;
+ NonnullRefPtr<StyleValue> m_image;
+ NonnullRefPtr<StyleValue> m_style_type;
+};
+
class StyleValueList final : public StyleValue {
public:
static NonnullRefPtr<StyleValueList> create(NonnullRefPtrVector<StyleValue>&& values) { return adopt_ref(*new StyleValueList(move(values))); }