diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index 92827288925..9a9bba545aa 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -1008,7 +1008,9 @@ TextTransform ComputedProperties::text_transform() const ListStyleType ComputedProperties::list_style_type() const { auto const& value = property(PropertyID::ListStyleType); - return keyword_to_list_style_type(value.to_keyword()).release_value(); + if (value.is_string()) + return value.as_string().string_value().to_string(); + return keyword_to_counter_style_name_keyword(value.to_keyword()).release_value(); } ListStylePosition ComputedProperties::list_style_position() const diff --git a/Libraries/LibWeb/CSS/ComputedValues.h b/Libraries/LibWeb/CSS/ComputedValues.h index 2027d6e5411..4cdad61c9d6 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Libraries/LibWeb/CSS/ComputedValues.h @@ -78,6 +78,8 @@ struct Containment { bool is_empty() const { return !(size_containment || inline_size_containment || layout_containment || style_containment || paint_containment); } }; +using ListStyleType = Variant; + class InitialValues { public: static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; } @@ -112,7 +114,7 @@ public: static Vector backdrop_filter() { return {}; } static Vector filter() { return {}; } static Color background_color() { return Color::Transparent; } - static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::Disc; } + static CSS::ListStyleType list_style_type() { return CSS::CounterStyleNameKeyword::Disc; } static CSS::ListStylePosition list_style_position() { return CSS::ListStylePosition::Outside; } static CSS::Visibility visibility() { return CSS::Visibility::Visible; } static CSS::FlexDirection flex_direction() { return CSS::FlexDirection::Row; } diff --git a/Libraries/LibWeb/CSS/Enums.json b/Libraries/LibWeb/CSS/Enums.json index 1343df0aa9a..6b03f3f473c 100644 --- a/Libraries/LibWeb/CSS/Enums.json +++ b/Libraries/LibWeb/CSS/Enums.json @@ -122,6 +122,22 @@ "auto", "hidden" ], + "counter-style-name-keyword": [ + "circle", + "decimal", + "decimal-leading-zero", + "disc", + "disclosure-closed", + "disclosure-open", + "lower-alpha", + "lower-latin", + "lower-roman", + "none", + "square", + "upper-alpha", + "upper-latin", + "upper-roman" + ], "cursor": [ "auto", "default", @@ -386,22 +402,6 @@ "inset", "outset" ], - "list-style-type": [ - "circle", - "decimal", - "decimal-leading-zero", - "disc", - "disclosure-closed", - "disclosure-open", - "lower-alpha", - "lower-latin", - "lower-roman", - "none", - "square", - "upper-alpha", - "upper-latin", - "upper-roman" - ], "list-style-position": [ "inside", "outside" @@ -419,10 +419,10 @@ "compact" ], "mix-blend-mode": [ - "normal", - "multiply", - "screen", - "overlay", + "normal", + "multiply", + "screen", + "overlay", "darken", "lighten", "color-dodge", @@ -434,8 +434,8 @@ "hue", "saturation", "color", - "luminosity", - "plus-darker", + "luminosity", + "plus-darker", "plus-lighter" ], "object-fit": [ diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index f9f5612e6bf..030cadf185f 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -1815,8 +1815,8 @@ "inherited": true, "initial": "disc", "valid-types": [ - "string", - "list-style-type" + "counter-style-name-keyword", + "string" ] }, "margin": { diff --git a/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp index 99be372fc74..bc361ca828f 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp @@ -53,35 +53,34 @@ static String generate_a_counter_representation(CSSStyleValue const& counter_sty auto counter_style_name = counter_style.as_custom_ident().custom_ident(); auto keyword = keyword_from_string(counter_style_name); if (keyword.has_value()) { - auto list_style_type = keyword_to_list_style_type(*keyword); - if (list_style_type.has_value()) { + if (auto list_style_type = keyword_to_counter_style_name_keyword(*keyword); list_style_type.has_value()) { switch (*list_style_type) { - case ListStyleType::Square: + case CounterStyleNameKeyword::Square: return "▪"_string; - case ListStyleType::Circle: + case CounterStyleNameKeyword::Circle: return "◦"_string; - case ListStyleType::Disc: + case CounterStyleNameKeyword::Disc: return "•"_string; - case ListStyleType::DisclosureClosed: + case CounterStyleNameKeyword::DisclosureClosed: return "▸"_string; - case ListStyleType::DisclosureOpen: + case CounterStyleNameKeyword::DisclosureOpen: return "▾"_string; - case ListStyleType::Decimal: + case CounterStyleNameKeyword::Decimal: return MUST(String::formatted("{}", value)); - case ListStyleType::DecimalLeadingZero: + case CounterStyleNameKeyword::DecimalLeadingZero: // This is weird, but in accordance to spec. if (value < 10) return MUST(String::formatted("0{}", value)); return MUST(String::formatted("{}", value)); - case ListStyleType::LowerAlpha: - case ListStyleType::LowerLatin: + case CounterStyleNameKeyword::LowerAlpha: + case CounterStyleNameKeyword::LowerLatin: return String::bijective_base_from(value - 1, String::Case::Lower); - case ListStyleType::UpperAlpha: - case ListStyleType::UpperLatin: + case CounterStyleNameKeyword::UpperAlpha: + case CounterStyleNameKeyword::UpperLatin: return String::bijective_base_from(value - 1, String::Case::Upper); - case ListStyleType::LowerRoman: + case CounterStyleNameKeyword::LowerRoman: return String::roman_number_from(value, String::Case::Lower); - case ListStyleType::UpperRoman: + case CounterStyleNameKeyword::UpperRoman: return String::roman_number_from(value, String::Case::Upper); default: break; diff --git a/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp b/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp index e722b3bd049..d87657fa34e 100644 --- a/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp +++ b/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp @@ -18,40 +18,43 @@ ListItemMarkerBox::ListItemMarkerBox(DOM::Document& document, CSS::ListStyleType , m_list_style_position(style_position) , m_index(index) { - switch (m_list_style_type) { - case CSS::ListStyleType::Square: - case CSS::ListStyleType::Circle: - case CSS::ListStyleType::Disc: - case CSS::ListStyleType::DisclosureClosed: - case CSS::ListStyleType::DisclosureOpen: - break; - case CSS::ListStyleType::Decimal: - m_text = MUST(String::formatted("{}.", m_index)); - break; - case CSS::ListStyleType::DecimalLeadingZero: - // This is weird, but in accordance to spec. - m_text = m_index < 10 ? MUST(String::formatted("0{}.", m_index)) : MUST(String::formatted("{}.", m_index)); - break; - case CSS::ListStyleType::LowerAlpha: - case CSS::ListStyleType::LowerLatin: - m_text = String::bijective_base_from(m_index - 1, String::Case::Lower); - break; - case CSS::ListStyleType::UpperAlpha: - case CSS::ListStyleType::UpperLatin: - m_text = String::bijective_base_from(m_index - 1, String::Case::Upper); - break; - case CSS::ListStyleType::LowerRoman: - m_text = String::roman_number_from(m_index, String::Case::Lower); - break; - case CSS::ListStyleType::UpperRoman: - m_text = String::roman_number_from(m_index, String::Case::Upper); - break; - case CSS::ListStyleType::None: - break; - - default: - VERIFY_NOT_REACHED(); - } + m_list_style_type.visit( + [this](CSS::CounterStyleNameKeyword keyword) { + switch (keyword) { + case CSS::CounterStyleNameKeyword::Square: + case CSS::CounterStyleNameKeyword::Circle: + case CSS::CounterStyleNameKeyword::Disc: + case CSS::CounterStyleNameKeyword::DisclosureClosed: + case CSS::CounterStyleNameKeyword::DisclosureOpen: + break; + case CSS::CounterStyleNameKeyword::Decimal: + m_text = MUST(String::formatted("{}.", m_index)); + break; + case CSS::CounterStyleNameKeyword::DecimalLeadingZero: + // This is weird, but in accordance to spec. + m_text = m_index < 10 ? MUST(String::formatted("0{}.", m_index)) : MUST(String::formatted("{}.", m_index)); + break; + case CSS::CounterStyleNameKeyword::LowerAlpha: + case CSS::CounterStyleNameKeyword::LowerLatin: + m_text = String::bijective_base_from(m_index - 1, String::Case::Lower); + break; + case CSS::CounterStyleNameKeyword::UpperAlpha: + case CSS::CounterStyleNameKeyword::UpperLatin: + m_text = String::bijective_base_from(m_index - 1, String::Case::Upper); + break; + case CSS::CounterStyleNameKeyword::LowerRoman: + m_text = String::roman_number_from(m_index, String::Case::Lower); + break; + case CSS::CounterStyleNameKeyword::UpperRoman: + m_text = String::roman_number_from(m_index, String::Case::Upper); + break; + case CSS::CounterStyleNameKeyword::None: + break; + } + }, + [this](String const& string) { + m_text = string; + }); } ListItemMarkerBox::~ListItemMarkerBox() = default; diff --git a/Libraries/LibWeb/Layout/ListItemMarkerBox.h b/Libraries/LibWeb/Layout/ListItemMarkerBox.h index 92ed3f9c8db..2ae9527c54a 100644 --- a/Libraries/LibWeb/Layout/ListItemMarkerBox.h +++ b/Libraries/LibWeb/Layout/ListItemMarkerBox.h @@ -24,14 +24,14 @@ public: virtual GC::Ptr create_paintable() const override; - CSS::ListStyleType list_style_type() const { return m_list_style_type; } + CSS::ListStyleType const& list_style_type() const { return m_list_style_type; } CSS::ListStylePosition list_style_position() const { return m_list_style_position; } private: virtual bool is_list_item_marker_box() const final { return true; } virtual bool can_have_children() const override { return false; } - CSS::ListStyleType m_list_style_type { CSS::ListStyleType::None }; + CSS::ListStyleType m_list_style_type { CSS::CounterStyleNameKeyword::None }; CSS::ListStylePosition m_list_style_position { CSS::ListStylePosition::Outside }; size_t m_index; diff --git a/Libraries/LibWeb/Painting/MarkerPaintable.cpp b/Libraries/LibWeb/Painting/MarkerPaintable.cpp index 39408210df4..b84441183f4 100644 --- a/Libraries/LibWeb/Painting/MarkerPaintable.cpp +++ b/Libraries/LibWeb/Painting/MarkerPaintable.cpp @@ -66,65 +66,63 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const auto color = computed_values().color(); - switch (layout_box().list_style_type()) { - case CSS::ListStyleType::Square: - context.display_list_recorder().fill_rect(device_marker_rect.to_type(), color); - break; - case CSS::ListStyleType::Circle: - context.display_list_recorder().draw_ellipse(device_marker_rect.to_type(), color, 1); - break; - case CSS::ListStyleType::Disc: - context.display_list_recorder().fill_ellipse(device_marker_rect.to_type(), color); - break; - case CSS::ListStyleType::DisclosureClosed: { - // https://drafts.csswg.org/css-counter-styles-3/#disclosure-closed - // For the disclosure-open and disclosure-closed counter styles, the marker must be an image or character suitable for indicating the open and closed states of a disclosure widget, such as HTML’s details element. - // FIXME: If the image is directional, it must respond to the writing mode of the element, similar to the bidi-sensitive images feature of the Images 4 module. - - // Draw an equilateral triangle pointing right. - auto path = Gfx::Path(); - path.move_to({ left, top }); - path.line_to({ left + sin_60_deg * (right - left), (top + bottom) / 2 }); - path.line_to({ left, bottom }); - path.close(); - context.display_list_recorder().fill_path({ .path = path, .color = color, .winding_rule = Gfx::WindingRule::EvenOdd }); - break; - } - case CSS::ListStyleType::DisclosureOpen: { - // https://drafts.csswg.org/css-counter-styles-3/#disclosure-open - // For the disclosure-open and disclosure-closed counter styles, the marker must be an image or character suitable for indicating the open and closed states of a disclosure widget, such as HTML’s details element. - // FIXME: If the image is directional, it must respond to the writing mode of the element, similar to the bidi-sensitive images feature of the Images 4 module. - - // Draw an equilateral triangle pointing down. - auto path = Gfx::Path(); - path.move_to({ left, top }); - path.line_to({ right, top }); - path.line_to({ (left + right) / 2, top + sin_60_deg * (bottom - top) }); - path.close(); - context.display_list_recorder().fill_path({ .path = path, .color = color, .winding_rule = Gfx::WindingRule::EvenOdd }); - break; - } - case CSS::ListStyleType::Decimal: - case CSS::ListStyleType::DecimalLeadingZero: - case CSS::ListStyleType::LowerAlpha: - case CSS::ListStyleType::LowerLatin: - case CSS::ListStyleType::LowerRoman: - case CSS::ListStyleType::UpperAlpha: - case CSS::ListStyleType::UpperLatin: - case CSS::ListStyleType::UpperRoman: { - auto text = layout_box().text(); - if (!text.has_value()) - break; + if (auto& text = layout_box().text(); text.has_value()) { // FIXME: This should use proper text layout logic! // This does not line up with the text in the
  • element which looks very sad :( context.display_list_recorder().draw_text(device_enclosing.to_type(), *text, layout_box().scaled_font(context), Gfx::TextAlignment::Center, color); - break; - } - case CSS::ListStyleType::None: - return; + } else if (auto const* counter_style = layout_box().list_style_type().get_pointer()) { + switch (*counter_style) { + case CSS::CounterStyleNameKeyword::Square: + context.display_list_recorder().fill_rect(device_marker_rect.to_type(), color); + break; + case CSS::CounterStyleNameKeyword::Circle: + context.display_list_recorder().draw_ellipse(device_marker_rect.to_type(), color, 1); + break; + case CSS::CounterStyleNameKeyword::Disc: + context.display_list_recorder().fill_ellipse(device_marker_rect.to_type(), color); + break; + case CSS::CounterStyleNameKeyword::DisclosureClosed: { + // https://drafts.csswg.org/css-counter-styles-3/#disclosure-closed + // For the disclosure-open and disclosure-closed counter styles, the marker must be an image or character suitable for indicating the open and closed states of a disclosure widget, such as HTML’s details element. + // FIXME: If the image is directional, it must respond to the writing mode of the element, similar to the bidi-sensitive images feature of the Images 4 module. - default: - VERIFY_NOT_REACHED(); + // Draw an equilateral triangle pointing right. + auto path = Gfx::Path(); + path.move_to({ left, top }); + path.line_to({ left + sin_60_deg * (right - left), (top + bottom) / 2 }); + path.line_to({ left, bottom }); + path.close(); + context.display_list_recorder().fill_path({ .path = path, .color = color, .winding_rule = Gfx::WindingRule::EvenOdd }); + break; + } + case CSS::CounterStyleNameKeyword::DisclosureOpen: { + // https://drafts.csswg.org/css-counter-styles-3/#disclosure-open + // For the disclosure-open and disclosure-closed counter styles, the marker must be an image or character suitable for indicating the open and closed states of a disclosure widget, such as HTML’s details element. + // FIXME: If the image is directional, it must respond to the writing mode of the element, similar to the bidi-sensitive images feature of the Images 4 module. + + // Draw an equilateral triangle pointing down. + auto path = Gfx::Path(); + path.move_to({ left, top }); + path.line_to({ right, top }); + path.line_to({ (left + right) / 2, top + sin_60_deg * (bottom - top) }); + path.close(); + context.display_list_recorder().fill_path({ .path = path, .color = color, .winding_rule = Gfx::WindingRule::EvenOdd }); + break; + } + case CSS::CounterStyleNameKeyword::None: + return; + case CSS::CounterStyleNameKeyword::Decimal: + case CSS::CounterStyleNameKeyword::DecimalLeadingZero: + case CSS::CounterStyleNameKeyword::LowerAlpha: + case CSS::CounterStyleNameKeyword::LowerLatin: + case CSS::CounterStyleNameKeyword::LowerRoman: + case CSS::CounterStyleNameKeyword::UpperAlpha: + case CSS::CounterStyleNameKeyword::UpperLatin: + case CSS::CounterStyleNameKeyword::UpperRoman: + // These are handled by text() already. + default: + VERIFY_NOT_REACHED(); + } } } diff --git a/Tests/LibWeb/Ref/expected/wpt-import/css/css-lists/list-style-type-string-004-ref.html b/Tests/LibWeb/Ref/expected/wpt-import/css/css-lists/list-style-type-string-004-ref.html new file mode 100644 index 00000000000..3a828b28893 --- /dev/null +++ b/Tests/LibWeb/Ref/expected/wpt-import/css/css-lists/list-style-type-string-004-ref.html @@ -0,0 +1,25 @@ + + + + + CSS Test: String value of list-style-type changing dynamically + + + + +
      +
    1. item 1
    2. +
    3. item 2
    4. +
    5. item 3
    6. +
    7. item 4
    8. +
    +
      +
    • item 1
    • +
    • item 2
    • +
    • item 3
    • +
    • item 4
    • +
    + + diff --git a/Tests/LibWeb/Ref/input/wpt-import/css/css-lists/list-style-type-string-004.html b/Tests/LibWeb/Ref/input/wpt-import/css/css-lists/list-style-type-string-004.html new file mode 100644 index 00000000000..51906ae02b6 --- /dev/null +++ b/Tests/LibWeb/Ref/input/wpt-import/css/css-lists/list-style-type-string-004.html @@ -0,0 +1,40 @@ + + + + + CSS Test: String value of list-style-type changing dynamically + + + + + + + +
      +
    1. item 1
    2. +
    3. item 2
    4. +
    5. item 3
    6. +
    7. item 4
    8. +
    +
      +
    • item 1
    • +
    • item 2
    • +
    • item 3
    • +
    • item 4
    • +
    + + + +