Generate and lay out list markers with counters and real text - #10995
Conversation
Implements the css-lists-3 counter machinery that list markers are defined in terms of: - Elements with display:list-item now automatically increment the list-item counter (decrementing it inside reversed scopes), unless counter-increment mentions list-item explicitly. counter(list-item) previously rendered 0 everywhere. - counter-reset: reversed(<name>) now parses (the grammar was already implemented but force-disabled), and unvalued reversed counters compute their start value with the spec's scope-walk algorithm. Also makes reversed(none) invalid, per the <counter-name> grammar. The imported lists-styles-quirks expectations temporarily record five newly-failing counter-reset subtests: with reversed() parsing, the test's reference styles take effect and expose that <ol reversed> is not yet mapped onto the list-item counter. The next commit adds that mapping.
📝 WalkthroughWalkthroughThe PR implements CSS ChangesCSS list counters and HTML integration
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
Libraries/LibWeb/Layout/TreeBuilder.cpp (1)
362-379: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMarker text is built by two separate paths.
create_and_attach_list_item_markerresolves the marker content, creates theGeneratedTextNode, and setschildren_are_inlineitself. The regular pseudo-element path builds the same result throughresolve_content(lines 583-600) plus the Rustcreate_content_itemcallback. The two paths must stay in agreement about content resolution, text-node creation,set_content, and the inline-children flag.Consider extracting the shared "attach resolved marker content to the marker box" step so both the nested-marker path and the pseudo-element path use one implementation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Libraries/LibWeb/Layout/TreeBuilder.cpp` around lines 362 - 379, Unify marker content attachment between create_and_attach_list_item_marker and the regular pseudo-element flow around resolve_content/create_content_item. Extract or reuse a shared helper that resolves marker content, creates the GeneratedTextNode, sets content, appends the node, and enables inline children, then update both paths to use it while preserving their existing marker setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Libraries/LibWeb/DOM/Node.cpp`:
- Around line 891-897: Update the insertion loop in Node insertion handling to
trigger invalidate_list_item_counters_for_list_owner() for both HTML li elements
and inserted elements whose computed display is list-item, matching the removal
path. Preserve the existing early break after invalidating the first qualifying
node.
---
Nitpick comments:
In `@Libraries/LibWeb/Layout/TreeBuilder.cpp`:
- Around line 362-379: Unify marker content attachment between
create_and_attach_list_item_marker and the regular pseudo-element flow around
resolve_content/create_content_item. Extract or reuse a shared helper that
resolves marker content, creates the GeneratedTextNode, sets content, appends
the node, and enables inline children, then update both paths to use it while
preserving their existing marker setup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: be97cfdc-bf6b-44a2-8602-60dc32ff4263
⛔ Files ignored due to path filters (5)
Tests/LibWeb/Screenshot/expected/ol-render-node-append-group-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ol-render-node-append-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ol-render-node-insert-last-group-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ol-render-node-insert-last-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ordered-list.pngis excluded by!**/*.png
📒 Files selected for processing (72)
Libraries/LibWeb/CSS/CountersSet.cppLibraries/LibWeb/CSS/CountersSet.hLibraries/LibWeb/CSS/Default.cssLibraries/LibWeb/CSS/Parser/PropertyParsing.cppLibraries/LibWeb/DOM/AbstractElement.cppLibraries/LibWeb/DOM/Element.cppLibraries/LibWeb/DOM/Element.hLibraries/LibWeb/DOM/Node.cppLibraries/LibWeb/DOM/Node.hLibraries/LibWeb/HTML/HTMLLIElement.cppLibraries/LibWeb/HTML/HTMLOListElement.cppLibraries/LibWeb/HTML/HTMLOListElement.hLibraries/LibWeb/Layout/LayoutRustBridge.cppLibraries/LibWeb/Layout/ListItemMarkerBox.cppLibraries/LibWeb/Layout/ListItemMarkerBox.hLibraries/LibWeb/Layout/TreeBuilder.cppLibraries/LibWeb/Painting/MarkerPaintable.cppLibraries/LibWeb/Painting/Paintable.cppLibraries/LibWeb/Rust/src/layout/block_formatting_context.rsLibraries/LibWeb/Rust/src/layout/formatting_context.rsLibraries/LibWeb/Rust/src/layout/inline_formatting_context.rsLibraries/LibWeb/Rust/src/layout/inline_level_iterator.rsLibraries/LibWeb/Rust/src/layout/layout_state.rsLibraries/LibWeb/Rust/src/layout/line_builder.rsLibraries/LibWeb/Rust/src/layout/node_facts.rsLibraries/LibWeb/Rust/src/layout/tree_builder.rsTests/LibWeb/Layout/expected/block-and-inline/list-markers-intruded-by-float.txtTests/LibWeb/Layout/expected/block-in-inline-in-floated-fieldset.txtTests/LibWeb/Layout/expected/css-pseudo-element-display-list-item.txtTests/LibWeb/Layout/expected/css/content-for-marker-in-list.txtTests/LibWeb/Layout/expected/css/content-for-marker.txtTests/LibWeb/Layout/expected/details-closed.txtTests/LibWeb/Layout/expected/details-open.txtTests/LibWeb/Layout/expected/details-summary-default-ua-style.txtTests/LibWeb/Layout/expected/empty-list-items.txtTests/LibWeb/Layout/expected/inside-list-item-content-offset.txtTests/LibWeb/Layout/expected/list-item-marker-content-height.txtTests/LibWeb/Layout/expected/list-item-marker-pseudo-placement.txtTests/LibWeb/Layout/expected/list-item-with-floated-child.txtTests/LibWeb/Layout/expected/list-marker-rtl.txtTests/LibWeb/Layout/expected/list-render-list-owner-is-document.txtTests/LibWeb/Layout/expected/list-render-list-owner-not-ol.txtTests/LibWeb/Layout/expected/list-render-no-list.txtTests/LibWeb/Layout/expected/ol-render-deep-hybrid-list-item-list.txtTests/LibWeb/Layout/expected/ol-render-item-values.txtTests/LibWeb/Layout/expected/ol-render-style-list-item.txtTests/LibWeb/Layout/expected/ordered-list.txtTests/LibWeb/Layout/expected/pseudo-element-content-replacement-list-item.txtTests/LibWeb/Layout/expected/ul-render.txtTests/LibWeb/Ref/expected/css/css-lists/counter-reset-reversed-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-details-summary-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-attributes-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-insert-remove-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-wrapped-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-html-attributes-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-implicit-increment-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-increment-suppression-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-nested-scopes-ref.htmlTests/LibWeb/Ref/expected/list-marker-baseline-alignment-ref.htmlTests/LibWeb/Ref/input/css/css-lists/counter-reset-reversed.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-details-summary.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-attributes.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-insert-remove.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-wrapped.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-html-attributes.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-implicit-increment.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-increment-suppression.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-nested-scopes.htmlTests/LibWeb/Ref/input/list-marker-baseline-alignment.htmlTests/LibWeb/Text/expected/css/counter-reset-reversed-serialization.txtTests/LibWeb/Text/expected/wpt-import/html/rendering/non-replaced-elements/lists/lists-styles-quirks.txtTests/LibWeb/Text/input/css/counter-reset-reversed-serialization.html
💤 Files with no reviewable changes (2)
- Libraries/LibWeb/HTML/HTMLOListElement.h
- Libraries/LibWeb/Painting/MarkerPaintable.cpp
| // AD-HOC: An inserted list item renumbers the list-item counter for its list owner's whole list. | ||
| for (auto& inserted_node : nodes) { | ||
| if (inserted_node->is_html_li_element()) { | ||
| static_cast<Element&>(*inserted_node).invalidate_list_item_counters_for_list_owner(); | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Inspect invalidate_list_item_counters_for_list_owner and all of its call sites.
set -euo pipefail
rg -nP --type=cpp -C6 '\binvalidate_list_item_counters_for_list_owner\s*\('
# Locate its definition and the list-owner resolution it relies on.
fd -t f 'Element.cpp' Libraries/LibWeb/DOM --exec rg -nP -C25 'invalidate_list_item_counters_for_list_owner'Repository: LadybirdBrowser/ladybird
Length of output: 162
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "tracked file:"
git ls-files | rg '(^|/)Node\.cpp$|(^|/)Element\.cpp$|(^|/)DOM/|List' | head -200
echo
echo "search for relevant identifiers:"
rg -n -C5 'invalidate_list_item_counters_for_list_owner|is_html_li_element|display.*list-item|list_item|list-item' --type=cpp --type=h | head -300
echo
echo "Node.cpp around reported lines:"
wc -l Libraries/LibWeb/DOM/Node.cpp
sed -n '860,1035p' Libraries/LibWeb/DOM/Node.cppRepository: LadybirdBrowser/ladybird
Length of output: 7707
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "find files with list-related names:"
fd -t f -i 'list|counter' Libraries/LibWeb | head -200
echo
echo "search likely DOM symbols more broadly:"
rg -n -C4 'list_element|query_selector|display\s*:|computed_style|display' Libraries/LibWeb --glob '*.{cpp,h}' | head -400Repository: LadybirdBrowser/ladybird
Length of output: 38040
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "node insert/remove sections:"
sed -n '840,890p' Libraries/LibWeb/DOM/Node.cpp
sed -n '980,1045p' Libraries/LibWeb/DOM/Node.cpp
echo
echo "find exact symbol across tracked files:"
python3 - <<'PY'
from pathlib import Path
queries = ['invalidate_list_item_counters_for_list_owner', 'list_owner', 'is_html_li_element']
for q in queries:
hits=[]
for p in Path('.').rglob('*'):
if any(part in {'.git','build','dist'} for part in p.parts):
continue
if p.is_file() and p.suffix in {'.cpp','.h','.idl'}:
try:
s=p.read_text(errors='ignore')
except Exception:
continue
if q in s:
hits.append(p)
print(q, len(hits))
for h in hits[:150]:
print(' ', h)
PY
echo
echo "Element list marker symbols:"
rg -n -C6 'marker|list_item|list-item|list-element|OL|UL|LI|invalidate|renumber|counter' Libraries/LibWeb --glob '*.{cpp,h}' | head -400Repository: LadybirdBrowser/ladybird
Length of output: 38761
Align list-item insertion with the removal path
The removal path handles both HTML <li> elements and elements with computed display: list-item, but the insertion path only checks is_html_li_element(). An inserted non-<li> element with display: list-item will not call invalidate_list_item_counters_for_list_owner(), so counters may not renumber consistently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Libraries/LibWeb/DOM/Node.cpp` around lines 891 - 897, Update the insertion
loop in Node insertion handling to trigger
invalidate_list_item_counters_for_list_owner() for both HTML li elements and
inserted elements whose computed display is list-item, matching the removal
path. Preserve the existing early break after invalidating the first qualifying
node.
Replaces the legacy leaf-box list marker path (single-font measurement in build_list_item_facts, centered draw_text at paint time that did not line up with the list item's text) with the css-lists-3 model: - <ol start/reversed> and <li value> map onto list-item counter presentational hints per the HTML rendering spec, and the parallel HTML ordinal machinery is deleted; markers are numbered by the list-item counter alone. - ::marker with content:normal resolves its content from list-style-type through the regular content pipeline, so text markers are block containers with generated text children and their own line box, painted like any other text. - Outside markers are positioned by aligning their first baseline with the list item's first-line baseline; inside markers now genuinely flow as inline content at the start of the list item instead of being drawn outside the box. - Markers with author content become marker boxes too and get the same outside positioning. - Symbolic markers (disc, circle, square, disclosure-*) and list-style-image keep the UA-image path in MarkerPaintable. - The spec's ::marker rule is added to the UA style sheet; white-space:pre preserves the marker suffix's trailing space. - Counter inheritance walks through ::first-letter/::first-line fragments, which never carry counters. - List mutations invalidate markers through the list owner, covering list items wrapped in non-list ancestors. The reversed-list screenshot expectation changes where a mid-list value attribute pins the sequence: the spec's implicit start-value algorithm counts backwards from the pinned counter-set, yielding 7,6,5,4,3 where the ordinal model produced 5,4,5,4,3. Firefox, which implements the counter-based numbering model, renders the same 7,6,5,4,3; Chrome still numbers reversed lists with the legacy ordinal algorithm and shows 5,4,5,4,3. The list item text in that test mirrors the legacy values, so the expectation image intentionally shows markers that do not match the item text.
e86ec6f to
35289b7
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Libraries/LibWeb/Layout/ListItemMarkerBox.cpp (1)
57-71: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard
relative_size()withhas_symbolic_counter_style()
LayoutRustBridge.cppcomputesmarker_is_symbolicusingis_symbolic(), then callsmarker->relative_size()wheneverlist_style_image()is absent. Forlist-style: url(marker.png) decimal,is_symbolic()is true, butMarkerPaintable::paint()returns when an image is present without setting marker dimensions, leaving the image outside the list marker box. Keeprelative_size()guarded as written and fix the image-only marker size path soLayoutRustBridge.cppdoes not enter the unresolved counter-style branch.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Libraries/LibWeb/Layout/ListItemMarkerBox.cpp` around lines 57 - 71, Update the marker sizing logic in LayoutRustBridge.cpp so image-only list markers do not enter the counter-style relative_size() path when list_style_image() is present. Preserve the existing relative_size() guard in ListItemMarkerBox::relative_size(), and ensure image markers receive valid dimensions or follow the appropriate image sizing path before MarkerPaintable::paint() handles them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@Libraries/LibWeb/Layout/ListItemMarkerBox.cpp`:
- Around line 57-71: Update the marker sizing logic in LayoutRustBridge.cpp so
image-only list markers do not enter the counter-style relative_size() path when
list_style_image() is present. Preserve the existing relative_size() guard in
ListItemMarkerBox::relative_size(), and ensure image markers receive valid
dimensions or follow the appropriate image sizing path before
MarkerPaintable::paint() handles them.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 2255532e-2daf-4c5e-affa-0fb2dab28097
⛔ Files ignored due to path filters (5)
Tests/LibWeb/Screenshot/expected/ol-render-node-append-group-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ol-render-node-append-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ol-render-node-insert-last-group-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ol-render-node-insert-last-reversed.pngis excluded by!**/*.pngTests/LibWeb/Screenshot/expected/ordered-list.pngis excluded by!**/*.png
📒 Files selected for processing (61)
Libraries/LibWeb/CSS/Default.cssLibraries/LibWeb/DOM/AbstractElement.cppLibraries/LibWeb/DOM/Element.cppLibraries/LibWeb/DOM/Element.hLibraries/LibWeb/DOM/Node.cppLibraries/LibWeb/DOM/Node.hLibraries/LibWeb/HTML/HTMLLIElement.cppLibraries/LibWeb/HTML/HTMLOListElement.cppLibraries/LibWeb/HTML/HTMLOListElement.hLibraries/LibWeb/Layout/LayoutRustBridge.cppLibraries/LibWeb/Layout/ListItemMarkerBox.cppLibraries/LibWeb/Layout/ListItemMarkerBox.hLibraries/LibWeb/Layout/TreeBuilder.cppLibraries/LibWeb/Painting/MarkerPaintable.cppLibraries/LibWeb/Painting/Paintable.cppLibraries/LibWeb/Rust/src/layout/block_formatting_context.rsLibraries/LibWeb/Rust/src/layout/formatting_context.rsLibraries/LibWeb/Rust/src/layout/inline_formatting_context.rsLibraries/LibWeb/Rust/src/layout/inline_level_iterator.rsLibraries/LibWeb/Rust/src/layout/layout_state.rsLibraries/LibWeb/Rust/src/layout/line_builder.rsLibraries/LibWeb/Rust/src/layout/node_facts.rsLibraries/LibWeb/Rust/src/layout/tree_builder.rsTests/LibWeb/Layout/expected/block-and-inline/list-markers-intruded-by-float.txtTests/LibWeb/Layout/expected/block-in-inline-in-floated-fieldset.txtTests/LibWeb/Layout/expected/css-pseudo-element-display-list-item.txtTests/LibWeb/Layout/expected/css/content-for-marker-in-list.txtTests/LibWeb/Layout/expected/css/content-for-marker.txtTests/LibWeb/Layout/expected/details-closed.txtTests/LibWeb/Layout/expected/details-open.txtTests/LibWeb/Layout/expected/details-summary-default-ua-style.txtTests/LibWeb/Layout/expected/empty-list-items.txtTests/LibWeb/Layout/expected/inside-list-item-content-offset.txtTests/LibWeb/Layout/expected/list-item-marker-content-height.txtTests/LibWeb/Layout/expected/list-item-marker-pseudo-placement.txtTests/LibWeb/Layout/expected/list-item-with-floated-child.txtTests/LibWeb/Layout/expected/list-marker-rtl.txtTests/LibWeb/Layout/expected/list-render-list-owner-is-document.txtTests/LibWeb/Layout/expected/list-render-list-owner-not-ol.txtTests/LibWeb/Layout/expected/list-render-no-list.txtTests/LibWeb/Layout/expected/ol-render-deep-hybrid-list-item-list.txtTests/LibWeb/Layout/expected/ol-render-item-values.txtTests/LibWeb/Layout/expected/ol-render-style-list-item.txtTests/LibWeb/Layout/expected/ordered-list.txtTests/LibWeb/Layout/expected/pseudo-element-content-replacement-list-item.txtTests/LibWeb/Layout/expected/ul-render.txtTests/LibWeb/Ref/expected/css/css-lists/counter-reset-reversed-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-attributes-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-insert-remove-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-wrapped-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-html-attributes-ref.htmlTests/LibWeb/Ref/expected/css/css-lists/list-item-counter-increment-suppression-ref.htmlTests/LibWeb/Ref/expected/list-marker-baseline-alignment-ref.htmlTests/LibWeb/Ref/input/css/css-lists/counter-reset-reversed.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-attributes.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-insert-remove.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-wrapped.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-html-attributes.htmlTests/LibWeb/Ref/input/css/css-lists/list-item-counter-increment-suppression.htmlTests/LibWeb/Ref/input/list-marker-baseline-alignment.htmlTests/LibWeb/Text/expected/wpt-import/html/rendering/non-replaced-elements/lists/lists-styles-quirks.txt
💤 Files with no reviewable changes (2)
- Libraries/LibWeb/HTML/HTMLOListElement.h
- Libraries/LibWeb/Painting/MarkerPaintable.cpp
🚧 Files skipped from review as they are similar to previous changes (54)
- Libraries/LibWeb/DOM/Node.h
- Libraries/LibWeb/Rust/src/layout/inline_formatting_context.rs
- Libraries/LibWeb/Rust/src/layout/formatting_context.rs
- Tests/LibWeb/Layout/expected/css/content-for-marker-in-list.txt
- Libraries/LibWeb/CSS/Default.css
- Tests/LibWeb/Ref/expected/css/css-lists/list-item-counter-increment-suppression-ref.html
- Tests/LibWeb/Layout/expected/list-marker-rtl.txt
- Tests/LibWeb/Layout/expected/details-open.txt
- Tests/LibWeb/Ref/expected/css/css-lists/counter-reset-reversed-ref.html
- Tests/LibWeb/Layout/expected/list-item-marker-content-height.txt
- Tests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-insert-remove.html
- Tests/LibWeb/Layout/expected/css-pseudo-element-display-list-item.txt
- Tests/LibWeb/Layout/expected/details-summary-default-ua-style.txt
- Libraries/LibWeb/DOM/AbstractElement.cpp
- Tests/LibWeb/Layout/expected/ul-render.txt
- Tests/LibWeb/Ref/input/css/css-lists/list-item-counter-increment-suppression.html
- Tests/LibWeb/Layout/expected/list-render-list-owner-is-document.txt
- Libraries/LibWeb/Layout/ListItemMarkerBox.h
- Tests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-wrapped-ref.html
- Libraries/LibWeb/Rust/src/layout/layout_state.rs
- Libraries/LibWeb/Layout/LayoutRustBridge.cpp
- Tests/LibWeb/Ref/input/css/css-lists/counter-reset-reversed.html
- Tests/LibWeb/Layout/expected/inside-list-item-content-offset.txt
- Tests/LibWeb/Ref/expected/css/css-lists/list-item-counter-html-attributes-ref.html
- Tests/LibWeb/Ref/expected/list-marker-baseline-alignment-ref.html
- Tests/LibWeb/Layout/expected/ol-render-deep-hybrid-list-item-list.txt
- Tests/LibWeb/Layout/expected/list-item-with-floated-child.txt
- Libraries/LibWeb/Painting/Paintable.cpp
- Tests/LibWeb/Layout/expected/pseudo-element-content-replacement-list-item.txt
- Tests/LibWeb/Layout/expected/list-render-list-owner-not-ol.txt
- Tests/LibWeb/Ref/input/css/css-lists/list-item-counter-html-attributes.html
- Tests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-insert-remove-ref.html
- Tests/LibWeb/Layout/expected/block-in-inline-in-floated-fieldset.txt
- Tests/LibWeb/Layout/expected/list-render-no-list.txt
- Tests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-wrapped.html
- Libraries/LibWeb/Rust/src/layout/inline_level_iterator.rs
- Tests/LibWeb/Ref/input/list-marker-baseline-alignment.html
- Libraries/LibWeb/Rust/src/layout/line_builder.rs
- Tests/LibWeb/Layout/expected/css/content-for-marker.txt
- Tests/LibWeb/Layout/expected/ordered-list.txt
- Tests/LibWeb/Layout/expected/ol-render-item-values.txt
- Tests/LibWeb/Layout/expected/empty-list-items.txt
- Libraries/LibWeb/Rust/src/layout/node_facts.rs
- Tests/LibWeb/Layout/expected/ol-render-style-list-item.txt
- Tests/LibWeb/Ref/expected/css/css-lists/list-item-counter-dynamic-attributes-ref.html
- Tests/LibWeb/Layout/expected/list-item-marker-pseudo-placement.txt
- Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs
- Libraries/LibWeb/Rust/src/layout/tree_builder.rs
- Tests/LibWeb/Layout/expected/block-and-inline/list-markers-intruded-by-float.txt
- Tests/LibWeb/Layout/expected/details-closed.txt
- Tests/LibWeb/Text/expected/wpt-import/html/rendering/non-replaced-elements/lists/lists-styles-quirks.txt
- Tests/LibWeb/Ref/input/css/css-lists/list-item-counter-dynamic-attributes.html
- Libraries/LibWeb/DOM/Node.cpp
- Libraries/LibWeb/DOM/Element.h
Replaces the legacy leaf-box list marker path (single-font measurement
in build_list_item_facts, centered draw_text at paint time that did not
line up with the list item's text) with the css-lists-3 model:
and- map onto list-item counter
presentational hints per the HTML rendering spec, and the parallel
HTML ordinal machinery is deleted; markers are numbered by the
list-item counter alone.
- ::marker with content:normal resolves its content from
- Outside markers are positioned by aligning their first baseline with
- Markers with author content become marker boxes too and get the same
- Symbolic markers (disc, circle, square, disclosure-*) and
- The spec's ::marker rule is added to the UA style sheet;
- Counter inheritance walks through ::first-letter/::first-line
- List mutations invalidate markers through the list owner, covering
list-style-type through the regular content pipeline, so text markers
are block containers with generated text children and their own line
box, painted like any other text.
the list item's first-line baseline; inside markers now genuinely
flow as inline content at the start of the list item instead of being
drawn outside the box.
outside positioning.
list-style-image keep the UA-image path in MarkerPaintable.
white-space:pre preserves the marker suffix's trailing space.
fragments, which never carry counters.
list items wrapped in non-list ancestors.
The reversed-list screenshot expectation changes where a mid-list value
attribute pins the sequence: the spec's implicit start-value algorithm
counts backwards from the pinned counter-set, yielding 7,6,5,4,3 where
the ordinal model produced 5,4,5,4,3. Firefox, which implements the
counter-based numbering model, renders the same 7,6,5,4,3; Chrome still
numbers reversed lists with the legacy ordinal algorithm and shows
5,4,5,4,3. The list item text in that test mirrors the legacy values,
so the expectation image intentionally shows markers that do not match
the item text.