Skip to content

LibWeb: Prepare layout for result-carried fragment trees - #11035

Merged
kalenikaliaksandr merged 3 commits into
LadybirdBrowser:masterfrom
kalenikaliaksandr:layout-upstream-prep
Aug 7, 2026
Merged

LibWeb: Prepare layout for result-carried fragment trees#11035
kalenikaliaksandr merged 3 commits into
LadybirdBrowser:masterfrom
kalenikaliaksandr:layout-upstream-prep

Conversation

@kalenikaliaksandr

Copy link
Copy Markdown
Member
  • Resolve relpos percentage-inset definiteness on the owner side — compute_inset no longer climbs out of the running formatting context to read ancestor used values. parent computes the beyond-anonymous-root answer at spawn and carries it as a run input.
  • Register anchor candidates instead of scanning all used values — anchor() resolution stops enumerating every used-values entry per lookup (O(all boxes) for a membership test). Boxes carrying anchor names register at used-values allocation, preserving the completion-order acceptability semantics in commit, measurement, and replay states.
  • Shift inline containing block rects by relative insets — a rendering fix: an absolutely positioned box whose containing block is a relatively positioned inline (or nested in relpos inlines) didn't follow the inline's shifted fragments. The stored rect is now correct at production

compute_inset climbed the containing block chain past anonymous boxes
to read has_definite_block_size() of the first non-anonymous ancestor
whenever a position: relative box carries block-axis percentage insets.
The climb escapes the running formatting context when its root is
anonymous (anonymous flex or grid items, anonymous table wrappers), and
then reads used values of boxes the running context does not own.

The planned fragment-tree layout needs every formatting context run to
be a function of its declared inputs: a run replayed from a result
cache executes without its ancestors on the stack, and once working
records become run-owned state that dies when the run returns, a box
above the run root is not addressable at all. Reads that walk out of
the run are exactly what forces the global used-values store and its
freeze-time fix-ups to keep existing, so each one converted now is one
less dependency the later series has to break.
anchor_lookup enumerated every used-values entry in the layout state
and shipped all their shells across the FFI boundary on each anchor()
resolution: the most global read in the layout engine, and O(all boxes)
per lookup even though the C++ side only uses the array as a "has used
values" membership test.

A scan over the whole record store makes the store itself load-bearing
as an index, which blocks two things the fragment-tree direction needs.
Working records cannot become run-owned state that dies at freeze while
anything still enumerates them globally, and a subtree skipped on a
future result-cache hit allocates no records at all, so anchor
candidacy has to be an explicit output a run can publish and a cached
result can republish — never a side effect of iterating whatever
happens to exist. Converting the scan into registration removes the
last consumer that needs the store to be enumerable.
An absolutely positioned box whose containing block is a relatively
positioned inline did not move with the inline's own inset, nor with
insets of relative inline ancestors the inline is nested in, while the
inline's fragments themselves were shifted at commit time — the stored
containing block rectangle disagreed with the fragments it is generated
from.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

NodeWithStyle tracks anchor names, and LayoutState retains matching anchor shells. Formatting-context runs now propagate block-axis percentage-inset rules to absolute-positioned layout. Inline containing-block geometry includes relative offsets. A new text test covers direct and nested relative inline cases.

Changes

Anchor and inset layout

Layer / File(s) Summary
Anchor candidate tracking
Libraries/LibWeb/Layout/Node.cpp, Libraries/LibWeb/Rust/src/layout/node_data.rs, Libraries/LibWeb/Rust/src/layout/layout_state.rs, Libraries/LibWeb/Rust/src/layout/abspos_engine.rs
Nodes track whether computed styles contain anchor names. LayoutState registers matching shells and exposes them for anchor lookup.
Percentage-inset resolution
Libraries/LibWeb/Rust/src/layout/geometry.rs, Libraries/LibWeb/Rust/src/layout/formatting_context.rs, Libraries/LibWeb/Rust/src/layout/abspos_engine.rs, Libraries/LibWeb/Rust/src/layout/sizing_context.rs
Formatting-context runs carry the block-axis percentage-inset policy. Inset computation resolves percentage bases through the formatting-context root and shared definiteness helpers.
Formatting-context callers and inline geometry
Libraries/LibWeb/Rust/src/layout/{block,flex,grid,inline}_formatting_context.rs, Tests/LibWeb/Text/{input,expected}/css/abspos-cb-inline-relative-inset-shift.*
Layout callers pass the new inset inputs. Inline containing-block rectangles include accumulated relative offsets. A text test covers direct and nested cases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description directly matches the changes for percentage-inset handling, anchor candidate registration, and inline containing-block rect shifts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Libraries/LibWeb/Rust/src/layout/formatting_context.rs (1)

1882-1906: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Pass the replayed abspos context flag through anonymous formatting-context roots.

run_abspos_layout_pass and rust_layout_replay_saved_abspos_layout start new FormattingContextRun objects with treat_block_axis_percentage_insets_as_auto_beyond_root = false, while rust_layout_run_root_layout propagates this flag with treat_block_axis_percentage_insets_as_auto_beyond_anonymous_child_root. If the abspos queue contains anonymous formatting-context roots, saved replay loses that propagation and treats percentage insets on those boxes as non-auto. Use the same propagation flag when building the replay run and enqueue it, and apply the same pattern in run_abspos_layout_pass if the queue can include anonymous roots.

🤖 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/Rust/src/layout/formatting_context.rs` around lines 1882 -
1906, Propagate
treat_block_axis_percentage_insets_as_auto_beyond_anonymous_child_root through
the abspos replay path: use the same flag when constructing the
FormattingContextRun in rust_layout_replay_saved_abspos_layout and when
enqueuing it, matching rust_layout_run_root_layout. Apply the corresponding
change in run_abspos_layout_pass so anonymous formatting-context roots retain
the flag and percentage insets are treated consistently.
🤖 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/Rust/src/layout/abspos_engine.rs`:
- Line 1788: Preserve the percentage-inset definiteness policy when queuing
deferred absolute-positioned roots instead of hard-coding false in
FormattingContextRun::new. Store the policy with each queued root or recompute
it before construction, ensuring
resolve_block_axis_percentage_inset_basis_is_definite() treats anonymous roots
with an indefinite block-axis basis as indefinite; add coverage for a relative
descendant’s top/bottom percentage beneath that root.

---

Outside diff comments:
In `@Libraries/LibWeb/Rust/src/layout/formatting_context.rs`:
- Around line 1882-1906: Propagate
treat_block_axis_percentage_insets_as_auto_beyond_anonymous_child_root through
the abspos replay path: use the same flag when constructing the
FormattingContextRun in rust_layout_replay_saved_abspos_layout and when
enqueuing it, matching rust_layout_run_root_layout. Apply the corresponding
change in run_abspos_layout_pass so anonymous formatting-context roots retain
the flag and percentage insets are treated consistently.
🪄 Autofix

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: fbf93c6c-e3c1-4e65-bd78-12d321e61748

📥 Commits

Reviewing files that changed from the base of the PR and between 99659b2 and 6b5a56c.

📒 Files selected for processing (13)
  • Libraries/LibWeb/Layout/Node.cpp
  • Libraries/LibWeb/Rust/src/layout/abspos_engine.rs
  • Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/flex_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/geometry.rs
  • Libraries/LibWeb/Rust/src/layout/grid_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/inline_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/layout_state.rs
  • Libraries/LibWeb/Rust/src/layout/node_data.rs
  • Libraries/LibWeb/Rust/src/layout/sizing_context.rs
  • Tests/LibWeb/Text/expected/css/abspos-cb-inline-relative-inset-shift.txt
  • Tests/LibWeb/Text/input/css/abspos-cb-inline-relative-inset-shift.html

}
let run =
crate::layout::FormattingContextRun::new(state, root, LayoutMode::Normal, callbacks, should_collect_devtools_layout_data);
crate::layout::FormattingContextRun::new(state, root, LayoutMode::Normal, callbacks, should_collect_devtools_layout_data, false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Preserve the percentage-inset policy for deferred abspos layout.

Line 1788 hard-codes the policy to false. When root is an anonymous formatting-context root with an indefinite block-axis basis beyond that root, layout_inside_child() propagates this incorrect value. resolve_block_axis_percentage_inset_basis_is_definite() then treats the anonymous root as definite. A relative descendant resolves top or bottom percentages as lengths instead of auto.

Store this policy with each queued abspos root, or recompute it before constructing this run. Add coverage for an abspos descendant below an anonymous formatting-context root with an indefinite block size.

🤖 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/Rust/src/layout/abspos_engine.rs` at line 1788, Preserve the
percentage-inset definiteness policy when queuing deferred absolute-positioned
roots instead of hard-coding false in FormattingContextRun::new. Store the
policy with each queued root or recompute it before construction, ensuring
resolve_block_axis_percentage_inset_basis_is_definite() treats anonymous roots
with an indefinite block-axis basis as indefinite; add coverage for a relative
descendant’s top/bottom percentage beneath that root.

@kalenikaliaksandr
kalenikaliaksandr merged commit 6e419a7 into LadybirdBrowser:master Aug 7, 2026
15 checks passed
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