diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 2edc73ecbd..eebb270642 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -46,6 +46,7 @@ public: static CSS::BackdropFilter backdrop_filter() { return BackdropFilter::make_none(); } static Color background_color() { return Color::Transparent; } static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::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; } static CSS::FlexWrap flex_wrap() { return CSS::FlexWrap::Nowrap; } @@ -288,6 +289,7 @@ public: Vector const& background_layers() const { return m_noninherited.background_layers; } CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; } + CSS::ListStylePosition list_style_position() const { return m_inherited.list_style_position; } Optional const& fill() const { return m_inherited.fill; } Optional const& stroke() const { return m_inherited.stroke; } @@ -327,6 +329,7 @@ protected: CSS::LengthPercentage text_indent { InitialValues::text_indent() }; CSS::WhiteSpace white_space { InitialValues::white_space() }; CSS::ListStyleType list_style_type { InitialValues::list_style_type() }; + CSS::ListStylePosition list_style_position { InitialValues::list_style_position() }; CSS::Visibility visibility { InitialValues::visibility() }; Optional fill; @@ -448,6 +451,7 @@ public: void set_overflow_x(CSS::Overflow value) { m_noninherited.overflow_x = value; } void set_overflow_y(CSS::Overflow value) { m_noninherited.overflow_y = value; } void set_list_style_type(CSS::ListStyleType value) { m_inherited.list_style_type = value; } + void set_list_style_position(CSS::ListStylePosition value) { m_inherited.list_style_position = value; } void set_display(CSS::Display value) { m_noninherited.display = value; } void set_backdrop_filter(CSS::BackdropFilter backdrop_filter) { m_noninherited.backdrop_filter = move(backdrop_filter); } void set_border_bottom_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_bottom_left_radius = move(value); } diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json index b82058ec74..19376e0d63 100644 --- a/Userland/Libraries/LibWeb/CSS/Enums.json +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -190,6 +190,10 @@ "upper-latin", "upper-roman" ], + "list-style-position": [ + "inside", + "outside" + ], "overflow": [ "auto", "clip", diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 8f1981223b..4ca89f0a2d 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -1232,9 +1232,8 @@ "list-style-position": { "inherited": true, "initial": "outside", - "valid-identifiers": [ - "inside", - "outside" + "valid-types": [ + "list-style-position" ] }, "list-style-type": { diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 53ab1e0afd..dcdbfba6af 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -711,6 +711,12 @@ Optional StyleProperties::list_style_type() const return value_id_to_list_style_type(value->to_identifier()); } +Optional StyleProperties::list_style_position() const +{ + auto value = property(CSS::PropertyID::ListStylePosition); + return value_id_to_list_style_position(value->to_identifier()); +} + Optional StyleProperties::overflow_x() const { return overflow(CSS::PropertyID::OverflowX); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 84ef77c749..4181c8e0fd 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -63,6 +63,7 @@ public: Optional text_transform() const; Vector text_shadow() const; Optional list_style_type() const; + Optional list_style_position() const; Optional flex_direction() const; Optional flex_wrap() const; Optional flex_basis() const; diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 48b2cc3f7a..2213eb1b16 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -999,8 +999,14 @@ void BlockFormattingContext::layout_list_item_marker(ListItemBox const& list_ite marker_state.set_content_height(max(image_height, marker.font().pixel_size_rounded_up() + 1).value()); - marker_state.set_content_offset({ -(marker_state.content_width() + default_marker_width), - max(CSSPixels(0), (CSSPixels(marker.line_height()) - marker_state.content_height()) / 2) }); + auto final_marker_width = marker_state.content_width() + default_marker_width; + + if (marker.list_style_position() == CSS::ListStylePosition::Inside) { + list_item_state.set_content_offset({ final_marker_width, list_item_state.offset.y() }); + list_item_state.set_content_width(list_item_state.content_width() - final_marker_width); + } + + marker_state.set_content_offset({ -final_marker_width, max(CSSPixels(0), (CSSPixels(marker.line_height()) - marker_state.content_height()) / 2) }); if (marker_state.content_height() > list_item_state.content_height()) list_item_state.set_content_height(marker_state.content_height()); diff --git a/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp b/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp index 94be21c5d3..a2db7cc229 100644 --- a/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp @@ -10,9 +10,10 @@ namespace Web::Layout { -ListItemMarkerBox::ListItemMarkerBox(DOM::Document& document, CSS::ListStyleType style_type, size_t index, NonnullRefPtr style) +ListItemMarkerBox::ListItemMarkerBox(DOM::Document& document, CSS::ListStyleType style_type, CSS::ListStylePosition style_position, size_t index, NonnullRefPtr style) : Box(document, nullptr, move(style)) , m_list_style_type(style_type) + , m_list_style_position(style_position) , m_index(index) { switch (m_list_style_type) { diff --git a/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h b/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h index 152c000c50..10c54c5a0c 100644 --- a/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h +++ b/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h @@ -15,7 +15,7 @@ class ListItemMarkerBox final : public Box { JS_CELL(ListItemMarkerBox, Box); public: - explicit ListItemMarkerBox(DOM::Document&, CSS::ListStyleType, size_t index, NonnullRefPtr); + explicit ListItemMarkerBox(DOM::Document&, CSS::ListStyleType, CSS::ListStylePosition, size_t index, NonnullRefPtr); virtual ~ListItemMarkerBox() override; DeprecatedString const& text() const { return m_text; } @@ -23,12 +23,14 @@ public: virtual JS::GCPtr create_paintable() const override; CSS::ListStyleType 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::ListStylePosition m_list_style_position { CSS::ListStylePosition::Outside }; size_t m_index; DeprecatedString m_text {}; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index bb87ac1882..69398f9ed7 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -572,6 +572,9 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) const_cast(*m_list_style_image).load_any_resources(document()); } + if (auto list_style_position = computed_style.list_style_position(); list_style_position.has_value()) + computed_values.set_list_style_position(list_style_position.value()); + // FIXME: The default text decoration color value is `currentcolor`, but since we can't resolve that easily, // we just manually grab the value from `color`. This makes it dependent on `color` being // specified first, so it's far from ideal. diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index 1844889ffc..268a33f72d 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -291,7 +291,7 @@ ErrorOr TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder:: auto& element = static_cast(dom_node); int child_index = layout_node->parent()->index_of_child(*layout_node).value(); auto marker_style = TRY(style_computer.compute_style(element, CSS::Selector::PseudoElement::Marker)); - auto list_item_marker = document.heap().allocate_without_realm(document, layout_node->computed_values().list_style_type(), child_index + 1, *marker_style); + auto list_item_marker = document.heap().allocate_without_realm(document, layout_node->computed_values().list_style_type(), layout_node->computed_values().list_style_position(), child_index + 1, *marker_style); static_cast(*layout_node).set_marker(list_item_marker); element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::Marker, list_item_marker); layout_node->append_child(*list_item_marker);