Skip to content

render: let an overflowing inline-block wrap instead of running one line - #750

Open
alexskinner wants to merge 1 commit into
h4ckf0r0day:mainfrom
alexskinner:fix/inline-block-list-wrapping
Open

render: let an overflowing inline-block wrap instead of running one line#750
alexskinner wants to merge 1 commit into
h4ckf0r0day:mainfrom
alexskinner:fix/inline-block-list-wrapping

Conversation

@alexskinner

Copy link
Copy Markdown
Contributor

What changed

Fixes #737.

An auto-width inline-block without in-flow block children is built as a NoWrap flex row so that a short control shrink-fits to one max-content line (dom.rs, inline-block branch of the node builder). CSS shrink-to-fit is min(max-content, available) though, and nothing enforced the available half: when the max-content line is wider than the containing block the box simply overflowed. Wikipedia's .cslist — an inline-block <ul> of inline-block <li>s with ::after commas — ran as one ~1000px line. Inside the infobox <td> that line became the table's min-content floor, so the width:22em table laid out at 641px instead of 310px and the article text beside the float collapsed to a few characters per line.

Two changes, both in crates/obscura-render/src/dom.rs:

  • wrap_overflowing_inline_blocks — a post-preliminary-layout repair in the same chain as repair_intrinsic_column_flex_negative_margins: any such NoWrap inline-block whose margin box exceeds its parent's content box is switched to Wrap, and Taffy is re-run. Boxes that fit keep their single max-content line, so the two-word-button case the NoWrap approximation exists for is unchanged.
  • The table sizing pass temporarily switches those inline-blocks to Wrap while measuring the table's and each cell's min-content width (nowrap_inline_block_rows / set_flex_wrap), then restores NoWrap for the max-content and final passes. Without this the table floor is computed before the repair can run.

Validation

  • New test overflowing_inline_block_list_wraps_inside_its_container in tests/layout_test.rs: the list stays ≤352px and wraps onto several lines (was 1023px on one line).
  • cargo test -p obscura-render --test layout_test: same 11 pre-existing failures as main on this machine, +1 pass. Note that on this machine main already fails table_width_uses_local_space_and_keeps_width_hints_shrinkable (a <table style="width:300px"> lays out at the viewport width in the unit harness), so I could not assert the table half of the fix in the harness; it is validated end-to-end below.
  • End-to-end through an embedding host, https://en.wikipedia.org/wiki/Rust_(programming_language) at 1280×900: .infobox 641px → 310px. Chrome on the same page/viewport: 309.76px (22em at the infobox's 14.08px computed font-size — the 352px figure in the issue assumed a 16px root). Article text flows normally beside the float.
  • Fixture matrix (all now 352px wide, wrapping): inline-block ul/li with and without ::after; inline li; div/span equivalents; the same list inside a width:352px table (was 1000px).

Rendering

Layout only. Fixture, viewport 1280×900, DSF 1:

<style>ul{display:inline-block;margin:0;padding:0;list-style:none} li{display:inline-block;padding-right:.25em} li:after{content:", "}</style>
<div style="width:352px"><ul><li>Alef</li><li>BETA</li>…17 items…</ul></div>
<table style="width:352px"><tr><td><ul>…same list…</ul></td></tr></table>

Before: ul 1023×20 (one line, overflowing), table 1000px. After: ul 352×74, table 352px.

Performance

The repair pass is one id_map scan plus a style read per node, and triggers a relayout only when an overflowing inline-block exists (previously a mis-rendered page). The table path adds two set_style sweeps over the inline-block set per min-content measurement; that set is usually empty or tiny. No hot-path change otherwise.

Checklist

  • The change is focused and does not remove existing behavior without justification.
  • Tests cover the failure or feature.
  • Existing tests pass, including render and no-render configurations when affected. (Same pre-existing failure set as main.)
  • I checked for CPU, latency, and memory regressions.
  • Public API or user-facing behavior changes are documented. (No API change.)

An auto-width inline-block without block children is built as a NoWrap
flex row so a short control shrink-fits to its max-content line. CSS
shrink-to-fit is min(max-content, available), though: when that line is
wider than the containing block the box must wrap internally. An
inline-block <ul> of inline-block <li>s (Wikipedia's `.cslist`) instead
ran as one ~1000px line, and inside an infobox cell that line became the
table's min-content floor, pushing a `width:22em` table from 310px to
641px and squeezing the article text beside it to one character per line.

Two changes:

- After the preliminary layout, switch any such NoWrap inline-block whose
  margin box exceeds its parent's content box to Wrap and re-run Taffy,
  alongside the other post-layout repairs.
- While measuring a table's (and each cell's) min-content width, treat
  those inline-blocks as Wrap so the floor reflects breakable content,
  then restore NoWrap for the max-content and final passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Article text collapses to one character per line on en.wikipedia.org at >=1150px viewport

1 participant