Skip to content

LibWeb: Make formatting contexts size their own root boxes - #10971

Merged
kalenikaliaksandr merged 1 commit into
LadybirdBrowser:masterfrom
kalenikaliaksandr:layout-fc-root-sizing
Aug 3, 2026
Merged

LibWeb: Make formatting contexts size their own root boxes#10971
kalenikaliaksandr merged 1 commit into
LadybirdBrowser:masterfrom
kalenikaliaksandr:layout-fc-root-sizing

Conversation

@kalenikaliaksandr

Copy link
Copy Markdown
Member

Root box sizing used to be the launching context's job: the block, inline, and abspos parents each computed a child's used sizes around its inner layout, the table context sized itself, and a two-phase finish callback plus a pre-created used-values whitelist papered over the places where that split leaked.

Now sizes flow down as constraints and come back up as results. LayoutInput carries the containing block's available space and percentage bases, how the root participates in its parent's layout (block-level, float, atomic inline, out-of-flow, item, or entry root), and parent-authoritative directives such as forced viewport sizes and the float-avoidance inline space. Each formatting-context run sizes its own root in a prelude, lays out its contents against the root's inner space, resolves the automatic block size in an epilogue, and returns plain results the parent uses to place the box. The parent probes float avoidance with the same non-committing sizing function the prelude later commits, so measure and commit cannot diverge. The completion protocol, the whitelist, and the table-offset side channel are gone.

Root box sizing used to be the launching context's job: the block,
inline, and abspos parents each computed a child's used sizes around
its inner layout, the table context sized itself, and a two-phase
finish callback plus a pre-created used-values whitelist papered over
the places where that split leaked.

Now sizes flow down as constraints and come back up as results.
LayoutInput carries the containing block's available space and
percentage bases, how the root participates in its parent's layout
(block-level, float, atomic inline, out-of-flow, item, or entry root),
and parent-authoritative directives such as forced viewport sizes and
the float-avoidance inline space. Each formatting-context run sizes
its own root in a prelude, lays out its contents against the root's
inner space, resolves the automatic block size in an epilogue, and
returns plain results the parent uses to place the box. The parent
probes float avoidance with the same non-committing sizing function
the prelude later commits, so measure and commit cannot diverge. The
completion protocol, the whitelist, and the table-offset side channel
are gone.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR refactors Rust layout execution from mutable FcFrame objects to FormattingContextRun. It adds shared root-sizing directives and sizing helpers, updates block, inline, table, grid, flex, SVG, and absolute-positioned layout, and changes C++/Rust viewport and root-layout plumbing.

Changes

Rust layout execution

Layer / File(s) Summary
Bridge and viewport plumbing
Libraries/LibWeb/DOM/Document.cpp, Libraries/LibWeb/Layout/LayoutRustBridge.*
Root and subtree layout calls use viewport dimensions without a document-element layout node. Paintable geometry reads require an explicit paintable.
Run, input, and sizing pipeline
Libraries/LibWeb/Rust/src/layout/formatting_context.rs, geometry.rs, sizing_context.rs, layout_state.rs
FormattingContextRun replaces FcFrame. Child layouts return completed results. LayoutInput carries root-sizing and parent-participation directives. Shared sizing handles block, atomic, intrinsic, and table measurements.
Block and inline layout
Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs, inline_formatting_context.rs
Block layout adds float-aware sizing probes and shared root finalization. Block and inline child layout uses run-based execution and direct child results.
Specialized formatting contexts
Libraries/LibWeb/Rust/src/layout/{flex,grid,table,replaced_with_children}_formatting_context.rs
Flex, grid, table, and replaced-content paths use FormattingContextRun, new sizing directives, and direct child-layout results.
SVG layout propagation
Libraries/LibWeb/Rust/src/layout/svg_formatting_context.rs
Nested SVG layout paths propagate FormattingContextRun and use the updated layout inputs.
Absolute-positioned layout
Libraries/LibWeb/Rust/src/layout/abspos_engine.rs
Absolute-positioned layout centralizes containing-block space and uses run-based child layout and replay.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Document
  participant LayoutRustBridge
  participant FormattingContextRun
  participant BlockFormattingContext
  participant AbsposEngine
  Document->>LayoutRustBridge: start root layout with viewport dimensions
  LayoutRustBridge->>FormattingContextRun: create run-based layout state
  FormattingContextRun->>BlockFormattingContext: execute root formatting context
  BlockFormattingContext->>FormattingContextRun: lay out child and return ChildLayoutResult
  FormattingContextRun->>AbsposEngine: dispatch absolute-positioned descendants
  AbsposEngine->>FormattingContextRun: replay positioned layout
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the root-box sizing refactor and matches the formatting-context, layout-input, float-avoidance, and completion-protocol changes.
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: 4

🤖 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/block_formatting_context.rs`:
- Around line 2340-2348: Align the float-root block-size resolution in
dimension_float_root with the block-level path by passing
self.sizing().available_space_for_block_size_resolution(...) instead of
input.available_space where resolving used block sizes. Preserve the existing
auto-size branching and ensure quirks-mode percentage height uses the same
containing-block basis as non-floating boxes.

In `@Libraries/LibWeb/Rust/src/layout/formatting_context.rs`:
- Around line 1379-1403: Update size_skipped_independent_root’s BlockLevel
branch to resolve automatic block size for skipped roots, matching the auto-size
handling in finalize_block_level_root() while retaining the existing
definite-size resolution performed by
resolve_block_level_root_block_size_before_body().

In `@Libraries/LibWeb/Rust/src/layout/sizing_context.rs`:
- Around line 1136-1155: Update the atomic inline root sizing flow around
dimension_atomic_root and finalize_atomic_root_block_size so block-axis
intrinsic constraints from input.available_space.block_size are preserved
through block-size resolution. Do not replace the original block available space
with AvailableSize::Indefinite when resolving the helpers; propagate the
intended available space consistently with the block/float paths, or explicitly
document and correctly propagate any intentionally different spaces.

In `@Libraries/LibWeb/Rust/src/layout/svg_formatting_context.rs`:
- Around line 713-715: Update the RootSizingDirectives initialization used by
layout_inside_child for the transformed SVGForeignObjectBox to set both forced
content sizes from the CSS-pixel dimensions calculated around lines 700-701,
instead of using RootSizingDirectives::default(). Preserve the existing
ParticipationInParentFormattingContext::Item setting so the child HTML
formatting context uses the transformed SVG viewport dimensions.
🪄 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: cd1f8387-2745-470c-b447-14601254e504

📥 Commits

Reviewing files that changed from the base of the PR and between ee8ae05 and 53efabe.

📒 Files selected for processing (15)
  • Libraries/LibWeb/DOM/Document.cpp
  • Libraries/LibWeb/Layout/LayoutRustBridge.cpp
  • Libraries/LibWeb/Layout/LayoutRustBridge.h
  • 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/replaced_with_children_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/sizing_context.rs
  • Libraries/LibWeb/Rust/src/layout/svg_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs
💤 Files with no reviewable changes (2)
  • Libraries/LibWeb/DOM/Document.cpp
  • Libraries/LibWeb/Rust/src/layout/layout_state.rs

Comment on lines 2340 to 2348
self.resolve_used_block_size_if_not_treated_as_auto(node, available_space, input.containing_block_constraints);
let facts = self.facts(node);
if facts.has_auto_content_box_size() || self.style(node).display().is_flex_inside() {
if self.facts(node).has_auto_content_box_size() || self.style(node).display().is_flex_inside() {
self.resolve_used_block_size_if_treated_as_auto(
node,
available_space,
input.containing_block_constraints,
None,
);
}

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 | 🟡 Minor | ⚡ Quick win

Float roots skip the quirks-mode block-size resolution space.

dimension_float_root resolves block sizes against input.available_space. The block-level path resolves them against self.sizing().available_space_for_block_size_resolution(...) (Lines 1658-1662 and Lines 2300-2305), which substitutes the quirks-mode percentage basis for a percentage height. A floating box with height: <percentage> in quirks mode therefore resolves against a different basis than an equivalent non-floating box.

Please confirm this difference is intended. If it is not, use the same helper here.

♻️ Proposed alignment with the block-level path
-    pub(crate) fn dimension_float_root(&self, node: Node, input: &LayoutInput) {
-        let available_space = input.available_space;
+    pub(crate) fn dimension_float_root(&self, node: Node, input: &LayoutInput) {
+        let available_space = input.available_space;
+        let resolution_space = self.sizing().available_space_for_block_size_resolution(
+            node,
+            available_space,
+            input.containing_block_constraints,
+        );
-        self.resolve_used_block_size_if_not_treated_as_auto(node, available_space, input.containing_block_constraints);
+        self.resolve_used_block_size_if_not_treated_as_auto(node, resolution_space, input.containing_block_constraints);
         if self.facts(node).has_auto_content_box_size() || self.style(node).display().is_flex_inside() {
             self.resolve_used_block_size_if_treated_as_auto(
                 node,
-                available_space,
+                resolution_space,
                 input.containing_block_constraints,
                 None,
             );
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.resolve_used_block_size_if_not_treated_as_auto(node, available_space, input.containing_block_constraints);
let facts = self.facts(node);
if facts.has_auto_content_box_size() || self.style(node).display().is_flex_inside() {
if self.facts(node).has_auto_content_box_size() || self.style(node).display().is_flex_inside() {
self.resolve_used_block_size_if_treated_as_auto(
node,
available_space,
input.containing_block_constraints,
None,
);
}
let resolution_space = self.sizing().available_space_for_block_size_resolution(
node,
available_space,
input.containing_block_constraints,
);
self.resolve_used_block_size_if_not_treated_as_auto(
node,
resolution_space,
input.containing_block_constraints,
);
if self.facts(node).has_auto_content_box_size() || self.style(node).display().is_flex_inside() {
self.resolve_used_block_size_if_treated_as_auto(
node,
resolution_space,
input.containing_block_constraints,
None,
);
}
🤖 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/block_formatting_context.rs` around lines
2340 - 2348, Align the float-root block-size resolution in dimension_float_root
with the block-level path by passing
self.sizing().available_space_for_block_size_resolution(...) instead of
input.available_space where resolving used block sizes. Preserve the existing
auto-size branching and ensure quirks-mode percentage height uses the same
containing-block basis as non-floating boxes.

Comment on lines +1379 to 1403
fn size_skipped_independent_root(
run: &FormattingContextRun,
parent_block: Option<&BlockFormattingContext>,
child: Node,
input: &LayoutInput,
) {
match input.participation {
ParticipationInParentFormattingContext::BlockLevel => {
let parent = parent_block.expect("a block-level run requires an enclosing block formatting context");
parent.commit_block_level_root_inline_size(child, input);
parent.resolve_block_level_root_block_size_before_body(child, input);
}
ParticipationInParentFormattingContext::Float => {
let parent = parent_block.expect("a floating run requires an enclosing block formatting context");
parent.dimension_float_root(child, input);
parent.finalize_float_root(child, input, None);
}
ParticipationInParentFormattingContext::AbsolutelyPositioned(abspos_inputs) => {
let engine = AbsposEngine::new(run.state, run.callbacks);
engine.dimension_out_of_flow_root(child, abspos_inputs);
engine.finalize_out_of_flow_root_after_inside_layout(child, abspos_inputs);
}
ParticipationInParentFormattingContext::AtomicInline | ParticipationInParentFormattingContext::Item | ParticipationInParentFormattingContext::Root => {}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the two block-level root sizing hooks used by the skipped path.
ast-grep run --pattern $'fn resolve_block_level_root_block_size_before_body($$$) {
  $$$
}' --lang rust Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs

ast-grep run --pattern $'fn commit_block_level_root_inline_size($$$) {
  $$$
}' --lang rust Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs

# Confirm whether resolve_used_block_size_if_treated_as_auto is reachable for childless block-level roots.
rg -n -C 5 'resolve_used_block_size_if_treated_as_auto' Libraries/LibWeb/Rust/src/layout

Repository: LadybirdBrowser/ladybird

Length of output: 14138


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== formatting_context relevant ranges =="
sed -n '1330,1410p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs
echo
sed -n '1545,1640p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs
echo

echo "== block formatting context block-size resolution hook =="
sed -n '755,795p' Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs
echo
sed -n '1790,1820p' Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs
echo

echo "== sizing hook =="
sed -n '957,1055p' Libraries/LibWeb/Rust/src/layout/sizing_context.rs
echo

echo "== deterministic call-site / predicate probe =="
python3 - <<'PY'
from pathlib import Path
p = Path('Libraries/LibWeb/Rust/src/layout/formatting_context.rs')
s = p.read_text()
for target in [
    'size_skipped_independent_root',
    'layout_inside_child',
    'size_block_level_root',
    'commit_block_level_root_inline_size',
    'resolve_block_level_root_block_size_before_body',
    'resolve_used_block_size_if_treated_as_auto',
    'finalize_block_level_root',
    'layout_inside',
]:
    idx = s.find(target)
    print(f'{target}: {idx}')
# extract lines and show whether each implementation contains specific calls
for line, name in enum:
    pass
PY
rg -n -C 8 "size_skipped_independent_root|layout_inside_child|layout_inside\\(" Libraries/LibWeb/Rust/src/layout/formatting_context.rs

Repository: LadybirdBrowser/ladybird

Length of output: 16366


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== BlockFormattingContext functions =="
rg -n -C 6 "pub\(crate\) fn commit_block_level_root_inline_size|fn resolve_block_level_root_block_size_before_body" Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs

echo
echo "== sizing.should_treat_block_size_as_auto implementation =="
rg -n -C 8 "fn should_treat_block_size_as_auto" Libraries/LibWeb/Rust/src/layout/sizing_context.rs

echo
echo "== SizingContext available_space_for_block_size_resolution =="
rg -n -C 6 "available_space_for_block_size_resolution" Libraries/LibWeb/Rust/src/layout/sizing_context.rs | sed -n '1,80p'

Repository: LadybirdBrowser/ladybird

Length of output: 2741


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== BlockFormattingContext sizing methods surrounding finalize hooks =="
sed -n '950,1015p' Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs

echo
echo "== finalize_block_level_root and child_layout calls nearby =="
sed -n '1760,1830p' Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs

echo
echo "== all occurrences of finalize_block_level_root =="
rg -n -C 5 "finalize_block_level_root" Libraries/LibWeb/Rust/src/layout

Repository: LadybirdBrowser/ladybird

Length of output: 8563


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== exact finalize_block_level_root definition =="
sed -n '1343,1375p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs

echo
echo "== exact finalize_block_level_root call sites =="
sed -n '1488,1535p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs
sed -n '1612,1628p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs

Repository: LadybirdBrowser/ladybird

Length of output: 4564


Resolve the automatic block size for skipped block-level roots.

The skipped call path can still reach the second branch in layout_inside_child(), but size_skipped_independent_root() only resolves non-auto block sizes in resolve_block_level_root_block_size_before_body() and skips finalize_block_level_root(). Add the same auto block-size resolution finalize_block_level_root() uses when skipping only definite inline/block-size cases.

🤖 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 1379 -
1403, Update size_skipped_independent_root’s BlockLevel branch to resolve
automatic block size for skipped roots, matching the auto-size handling in
finalize_block_level_root() while retaining the existing definite-size
resolution performed by resolve_block_level_root_block_size_before_body().

Comment on lines +1136 to +1155
let inline_definite_space = AvailableSpace {
inline_size: AvailableSize::definite(inline_size),
block_size: AvailableSize::Indefinite,
};
self.resolve_used_block_size_if_not_treated_as_auto(node, inline_definite_space, constraints);
if style.display().is_flex_inside() {
// Flex containers with an automatic block size are treated as max-content, so resolve it early.
self.resolve_used_block_size_if_treated_as_auto(node, inline_definite_space, constraints, None, || {
crate::layout::independent_root_automatic_block_size(
self.state,
&self.callbacks,
node,
self.used(node)
.available_inner_space_or_constraints_from(inline_definite_space),
constraints,
)
});
}
self.make_button_content_box_definite(node, layout_mode, available_space, constraints, None);
}

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare with the block-level root sizing path, which is the closest analogue.
ast-grep run --pattern $'fn dimension_block_level_root($$$) -> $_ {
  $$$
}' --lang rust Libraries/LibWeb/Rust/src/layout/formatting_context.rs

# Check whether any caller of dimension_atomic_root supplies an intrinsic block available size.
rg -n -C 8 '\bdimension_atomic_root\s*\(' Libraries/LibWeb/Rust/src/layout

Repository: LadybirdBrowser/ladybird

Length of output: 7293


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## dimension_atomic_root section"
sed -n '1038,1175p' Libraries/LibWeb/Rust/src/layout/sizing_context.rs

echo
echo "## dimension_block_level_root section"
sed -n '1308,1346p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs

echo
echo "## predicates definitions and uses"
rg -n -C 5 'should_treat_block_size_as_auto|should_treat_max_block_size_as_none|make_button_content_box_definite|calculate_inner_block_size' Libraries/LibWeb/Rust/src/layout/sizing_context.rs Libraries/LibWeb/Rust/src/layout/formatting_context.rs

echo
echo "## callers of dimension_atomic_root"
rg -n -C 4 '\bdimension_atomic_root\s*\(' Libraries/LibWeb/Rust/src

Repository: LadybirdBrowser/ladybird

Length of output: 46509


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## AtomicInline partitioning code"
sed -n '1180,1295p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs

echo
echo "## available space creation/partitioning paths"
rg -n -C 5 'AtomicInline|atomic inline|input.available_space|available_space.block_size|layout_input|LayoutInput::new|DimensionRoot|dimension.*root' Libraries/LibWeb/Rust/src/layout/formatting_context.rs Libraries/LibWeb/Rust/src/layout/sizing_context.rs

echo
echo "## intrinsic available-space helper implementation"
sed -n '1296,1308p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs

echo
echo "## structural probe: predicates around inline_definite_space calls"
python3 - <<'PY'
from pathlib import Path
p = Path('Libraries/LibWeb/Rust/src/layout/sizing_context.rs')
text = p.read_text()
start = text.index('pub(crate) fn dimension_atomic_root')
end = text.index('fn calculate_stretch_fit_inline_size', start)
block = text[start:end]
for name in [
    'should_treat_block_size_as_auto(node, inline_definite_space, constraints)',
    'should_treat_block_size_as_auto(node, available_space, constraints)',
    'should_treat_max_block_size_as_none(node, inline_definite_space.block_size, constraints)',
    'should_treat_max_block_size_as_none(node, available_space.block_size, constraints)',
]:
    print(f'{name}:', name in block)
PY

Repository: LadybirdBrowser/ladybird

Length of output: 44236


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## finalize_atomic_root_block_size"
sed -n '1548,1590p' Libraries/LibWeb/Rust/src/layout/formatting_context.rs

echo
echo "## atomic intrinsic blocks"
rg -n -C 6 'fn compute_block_size_for_replaced_element|fn should_treat_block_size_as_auto|fn calculate_inner_block_size|fn make_button_content_box_definite|compute.*block.*size|preferred_available_space|available_inner_space_or_constraints_from|ParticipationInParentFormattingContext::AtomicInline|AvailableSize::intrinsic' Libraries/LibWeb/Rust/src/layout/sizing_context.rs Libraries/LibWeb/Rust/src/layout/formatting_context.rs | sed -n '1,260p'

Repository: LadybirdBrowser/ladybird

Length of output: 28120


Keep the block-axis intrinsic constraint in atomic inline root sizing.

dimension_atomic_root passes input.available_space.block_size back to finalize_atomic_root_block_size, but the block-size resolution helpers run under AvailableSize::Indelinite. An atomic inline under min-content/max-content/block-content sizing will therefore have its block-space constraint treated away, unlike the block/float paths that pass the original available space through. Preserve the block-space constraint instead of forcing Indefinite, or document/propagate the intended different spaces.

🤖 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/sizing_context.rs` around lines 1136 - 1155,
Update the atomic inline root sizing flow around dimension_atomic_root and
finalize_atomic_root_block_size so block-axis intrinsic constraints from
input.available_space.block_size are preserved through block-size resolution. Do
not replace the original block available space with AvailableSize::Indefinite
when resolving the helpers; propagate the intended available space consistently
with the block/float paths, or explicitly document and correctly propagate any
intentionally different spaces.

Comment on lines +713 to +715
sizing: RootSizingDirectives::default(),
participation: ParticipationInParentFormattingContext::Item,
};

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 | ⚡ Quick win

Force the transformed foreign-object root size.

Lines 700-701 calculate the CSS-pixel size for the transformed SVGForeignObjectBox. layout_inside_child then starts an independent child run. RootSizingDirectives::default() does not preserve those dimensions as the child root size.

Set both forced content sizes. This keeps the HTML formatting context aligned with the SVG viewport after transforms.

Proposed fix
-                sizing: RootSizingDirectives::default(),
+                sizing: RootSizingDirectives {
+                    forced_content_inline_size: Some(transformed_rect.width),
+                    forced_content_block_size: Some(transformed_rect.height),
+                    ..RootSizingDirectives::default()
+                },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sizing: RootSizingDirectives::default(),
participation: ParticipationInParentFormattingContext::Item,
};
sizing: RootSizingDirectives {
forced_content_inline_size: Some(transformed_rect.width),
forced_content_block_size: Some(transformed_rect.height),
..RootSizingDirectives::default()
},
participation: ParticipationInParentFormattingContext::Item,
🤖 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/svg_formatting_context.rs` around lines 713
- 715, Update the RootSizingDirectives initialization used by
layout_inside_child for the transformed SVGForeignObjectBox to set both forced
content sizes from the CSS-pixel dimensions calculated around lines 700-701,
instead of using RootSizingDirectives::default(). Preserve the existing
ParticipationInParentFormattingContext::Item setting so the child HTML
formatting context uses the transformed SVG viewport dimensions.

@kalenikaliaksandr
kalenikaliaksandr enabled auto-merge (rebase) August 3, 2026 14:47
@kalenikaliaksandr
kalenikaliaksandr merged commit c344975 into LadybirdBrowser:master Aug 3, 2026
20 of 22 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