Skip to content

Let an inline root claim abspos boxes on behalf of its inline spans - #1167

Merged
nicoburns merged 5 commits into
mainfrom
devin/1791576351-inline-span-root-claims
Oct 9, 2026
Merged

nicoburns merged 5 commits into
mainfrom
devin/1791576351-inline-span-root-claims

Conversation

@nicoburns

@nicoburns nicoburns commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Summary

An ultra-minimal alternative to #1164 (itself a minimal version of #974). Compare the two and merge at most one.

An inline span has no layout node, so today an out-of-flow box whose containing block is a span (e.g. position: relative on an <a>) bubbles past it to a further ancestor. Here the inline root claims such boxes in the span's place, so they are positioned against the root's padding box by the regular compute_oof_layout pass. Span geometry is not resolved.

root claims = root's own claims
            | claims of every inline span that has an inline box below it
  • In RunMode::PerformLayout, inline layout's existing loop over inline boxes walks each box's ancestors up to the root (inline_span_cb_flags) and ORs the span claims together. The result is written to TextLayout::span_cb_flags before the TextLayout is put back on the node.
  • Node::layout_style() copies it into two new StyleFlags (SPAN_ABSOLUTE_CB, SPAN_FIXED_CB), which is_containing_block() ORs in. The only reader is compute_oof_layout, which runs after inline layout returns.
  • inline_containing_block_claims is containing_block_claims without the properties that don't apply to non-atomic inlines (transforms, containment).
  • No invalidation is needed: a style change on a span damages the root with RELAYOUT, which recomputes the flags, and a cache hit skips compute_oof_layout too.
  • No change to how inline layout collects or positions candidates, and no Taffy change.

Known imprecision

Claims are per inline root, not per box:

  • An abspos box beside a containing-block span (not inside it) is claimed by the root too, if that span has an inline box below it.
  • A fixed box is trapped at the root if any span in the root with an inline box below it has a filter.

Roots with no such span behave exactly as before.

Verification

  • No unit tests are added: the behaviour is an approximation (root padding box rather than span fragments), so it is not pinned by tests.
  • WPT (see the report below): four tests newly pass; the three box-shadow/slice-inline-fragmentation-* tests newly fail because they need span fragment geometry.
  • Layout time against main on saved real pages (one full resolve_layout() with all layout caches cleared, release build, pinned core): Wikipedia "Barack Obama" 19.26 ms -> 19.41 ms (+0.7%, from the ancestor walk); BBC News 5.11 ms -> 5.09 ms (within noise).

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/058ee880f4b3405ba452dbd2fb6b2284
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/058ee880f4b3405ba452dbd2fb6b2284?variant=devin-insiders
Requested by: @nicoburns

WPT results

Subtests: 4 newly passing, 3 newly failing (net +1).

Subtest changes by area (6 areas)
+ css               | +1 (+4 / -3) | 59.64% -> 59.64% ( +0.00%) | 118006 -> 118007 / 197863
-   css-backgrounds | -3 (+0 / -3) | 73.51% -> 73.47% ( -0.04%) |   5117 ->   5114 /   6961
-     box-shadow    | -3 (+0 / -3) | 37.50% ->  0.00% (-37.50%) |      3 ->      0 /      8
+   css-inline      | +1 (+1 / -0) | 39.67% -> 39.75% ( +0.08%) |    484 ->    485 /   1220
+   css-position    | +2 (+2 / -0) | 65.97% -> 66.09% ( +0.12%) |   1144 ->   1146 /   1734
+   filter-effects  | +1 (+1 / -0) | 53.26% -> 53.30% ( +0.03%) |   1762 ->   1763 /   3308
Full diff (7 changed tests)
- PASS => FAIL  [0/1]  -1  css/css-backgrounds/box-shadow/slice-inline-fragmentation-001.html
- PASS => FAIL  [0/1]  -1  css/css-backgrounds/box-shadow/slice-inline-fragmentation-002.html
- PASS => FAIL  [0/1]  -1  css/css-backgrounds/box-shadow/slice-inline-fragmentation-003.html
+ FAIL => PASS  [1/1]  +1  css/css-inline/empty-span-scroll.html
+ FAIL => PASS  [1/1]  +1  css/css-position/nested-inline-abspos-child-with-siblings.html
+ FAIL => PASS  [1/1]  +1  css/css-position/nested-inline-abspos-child.html
+ FAIL => PASS  [1/1]  +1  css/filter-effects/filtered-inline-is-container.html

Generated by the WPT workflow.

@staging-devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access that start with 'Devin'.

  • Disable automatic comment, CI, and merge conflict monitoring

@nicoburns
nicoburns merged commit 7832c17 into main Oct 9, 2026
14 of 15 checks passed
staging-devin-ai-integration Bot pushed a commit that referenced this pull request Oct 9, 2026
Cargo.toml: parley and parlance from crates.io (0.12, 0.1), as #1159 does.
Cargo.lock: main's lockfile with the winkin, fontwich and stylo fork entries
resolved on top at the revisions the branch pins.
layout/inline.rs stays deleted and node/text.rs stays the branch's; #1167's
change to them is carried over in the next commit.
staging-devin-ai-integration Bot pushed a commit that referenced this pull request Oct 9, 2026
…inline layout

main computes, in layout/inline.rs, the out-of-flow positions an inline span
is a containing block for, and stores them on the Parley TextLayout. This
branch replaces both, so the same is done in layout/inline/lines.rs as the
inline boxes are placed, and each backend's TextLayout holds the flags.
staging-devin-ai-integration Bot pushed a commit that referenced this pull request Oct 10, 2026
… now

The text backend commits that follow move and replace layout/inline.rs and the
Parley TextLayout, which #1167 changed. Its blitz-dom part is taken out here so
that they apply as written, and is put back for the shared inline layout once
they have. The stylo_taffy part stays.
staging-devin-ai-integration Bot pushed a commit that referenced this pull request Oct 10, 2026
…nline layout

main computes, in layout/inline.rs, the out-of-flow positions an inline span
is a containing block for, and stores them on the Parley TextLayout. The text
backend commits replace both, so the same is done in layout/inline/lines.rs as
the inline boxes are placed, and each backend's TextLayout holds the flags,
which Node::layout_style reads as on main.
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.

1 participant