Skip to content

LibWeb: Move table grid formation fully into Rust - #10927

Merged
kalenikaliaksandr merged 1 commit into
LadybirdBrowser:masterfrom
kalenikaliaksandr:libweb-rust-table-grid
Jul 29, 2026
Merged

LibWeb: Move table grid formation fully into Rust#10927
kalenikaliaksandr merged 1 commit into
LadybirdBrowser:masterfrom
kalenikaliaksandr:libweb-rust-table-grid

Conversation

@kalenikaliaksandr

Copy link
Copy Markdown
Member

The Rust table formatting context already formed its own row and column grid, while layout tree fixup constructed a duplicate C++ TableGrid and queried every slot through an opaque FFI object. This kept two copies of the formation algorithm and made missing-cell fixup cross the bridge for each grid position.

Share the Rust grid builder with layout tree fixup and mirror the bounded table spans into unused NodeData padding so grid formation needs no read callbacks. Keep the missing-cell mutation callback while C++ still owns layout boxes, and move the painting-only border comparator next to its caller. This removes the C++ TableGrid and its four bridge callbacks without changing NodeData's size.

@ladybird-bot

Copy link
Copy Markdown
Collaborator

Hello!

One or more of the commit messages in this PR do not match the Ladybird code submission policy, please check the lint_commits CI job for more details on which commits were flagged and why.
Please do not close this PR and open another, instead modify your commit message(s) with git commit --amend and force push those changes to update this PR.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4a9e7fdf-ea8a-4642-9a32-3d051898d94a

📥 Commits

Reviewing files that changed from the base of the PR and between 8b2b8e3 and d0e50a9.

📒 Files selected for processing (13)
  • Libraries/LibWeb/CMakeLists.txt
  • Libraries/LibWeb/DOM/Element.cpp
  • Libraries/LibWeb/Layout/LayoutRustBridge.cpp
  • Libraries/LibWeb/Layout/Node.cpp
  • Libraries/LibWeb/Layout/Node.h
  • Libraries/LibWeb/Layout/TableGrid.cpp
  • Libraries/LibWeb/Layout/TableGrid.h
  • Libraries/LibWeb/Layout/TreeBuilder.cpp
  • Libraries/LibWeb/Painting/TableBordersPainting.cpp
  • Libraries/LibWeb/Rust/src/layout/formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/node_data.rs
  • Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/tree_builder.rs
💤 Files with no reviewable changes (6)
  • Libraries/LibWeb/CMakeLists.txt
  • Libraries/LibWeb/Layout/TableGrid.cpp
  • Libraries/LibWeb/Layout/TableGrid.h
  • Libraries/LibWeb/Rust/src/layout/formatting_context.rs
  • Libraries/LibWeb/Layout/LayoutRustBridge.cpp
  • Libraries/LibWeb/Layout/TreeBuilder.cpp
🚧 Files skipped from review as they are similar to previous changes (5)
  • Libraries/LibWeb/Rust/src/layout/node_data.rs
  • Libraries/LibWeb/DOM/Element.cpp
  • Libraries/LibWeb/Layout/Node.h
  • Libraries/LibWeb/Layout/Node.cpp
  • Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs

📝 Walkthrough

Walkthrough

Table span data now synchronizes into Rust-backed node state. Rust owns occupancy-aware table-grid calculation, while C++ TableGrid FFI usage is removed. Tree-builder table fixup and border conflict sorting use the updated implementations.

Changes

Table layout migration

Layer / File(s) Summary
Table span state synchronization
Libraries/LibWeb/Rust/src/layout/node_data.rs, Libraries/LibWeb/Layout/Node.*, Libraries/LibWeb/DOM/Element.cpp, Libraries/LibWeb/Layout/LayoutRustBridge.cpp, Libraries/LibWeb/Rust/src/layout/formatting_context.rs
Node data stores column and row spans, DOM changes synchronize them, and obsolete span fields are removed from table box facts.
Shared Rust table-grid calculation
Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs, Libraries/LibWeb/CMakeLists.txt, Libraries/LibWeb/Painting/TableBordersPainting.cpp
Rust grid construction tracks occupied coordinates and uses the revised TableTree interface; C++ TableGrid source registration is removed and border comparison is implemented locally.
Tree-builder table fixup integration
Libraries/LibWeb/Rust/src/layout/tree_builder.rs, Libraries/LibWeb/Layout/TreeBuilder.cpp
Tree-builder callbacks no longer expose C++ TableGrid operations, and missing-cell fixup uses the shared Rust grid and occupancy data.

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

Sequence Diagram(s)

sequenceDiagram
  participant DOM
  participant NodeWithStyle
  participant TableFormattingContext
  participant TreeBuilderHost
  DOM->>NodeWithStyle: change colspan, rowspan, or span
  NodeWithStyle->>TableFormattingContext: synchronize table span data
  TableFormattingContext->>TableFormattingContext: calculate_table_grid
  TableFormattingContext-->>TreeBuilderHost: return occupancy-aware TableGrid
  TreeBuilderHost->>TreeBuilderHost: fix missing table cells from occupancy
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description accurately matches the table-grid refactor, NodeData span mirroring, bridge cleanup, and painting comparator move.
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.

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

🧹 Nitpick comments (1)
Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs (1)

624-742: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Grid-growing algorithm looks correct; consider extracting process_row from a closure.

Traced the occupancy/column-growth logic end-to-end (skip-ahead over occupied slots, column_count/row_count growth, and the final span clipping against rows.len()/column_count) — no off-by-one or out-of-bounds issues found; index bounds are always established before use.

process_row is a 9-parameter closure that captures nothing from the enclosing scope — it could be a plain generic function (fn process_row<T: TableTree>(...)) instead, which would simplify the borrow patterns and make the algorithm easier to follow independent of calculate_table_grid's local state.

♻️ Sketch of the refactor
-    let process_row = |tree: &T,
-                       row: Node,
-                       row_group: Option<Node>,
-                       cells: &mut Vec<TableCell>,
-                       rows: &mut Vec<Row>,
-                       occupancy: &mut HashSet<(usize, usize)>,
-                       column_count: &mut usize,
-                       row_count: &mut usize,
-                       current_row: &mut usize| {
+    fn process_row<T: TableTree>(
+        tree: &T,
+        row: Node,
+        row_group: Option<Node>,
+        cells: &mut Vec<TableCell>,
+        rows: &mut Vec<Row>,
+        occupancy: &mut HashSet<(usize, usize)>,
+        column_count: &mut usize,
+        row_count: &mut usize,
+        current_row: &mut usize,
+    ) {
         // ...body unchanged...
-    };
+    }
🤖 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/table_formatting_context.rs` around lines
624 - 742, Extract the capture-free process_row closure inside
calculate_table_grid into a local or module-level generic function named
process_row<T: TableTree>, preserving its parameters, row/cell occupancy
updates, span handling, and row creation behavior. Update both call sites in
calculate_table_grid to invoke the function without changing the grid-growing
algorithm.
🤖 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/Layout/Node.cpp`:
- Around line 1097-1110: Update NodeWithStyle::synchronize_table_span_data and
the table placement flow so a cell with rowSpan=0 retains its special “through
remaining rows” semantics instead of being normalized by the Rust grid builder
to a one-row span. Propagate an explicit representation or flag for zero row
spans, and have placement extend the cell through all remaining rows while
preserving existing behavior for positive row spans.

---

Nitpick comments:
In `@Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs`:
- Around line 624-742: Extract the capture-free process_row closure inside
calculate_table_grid into a local or module-level generic function named
process_row<T: TableTree>, preserving its parameters, row/cell occupancy
updates, span handling, and row creation behavior. Update both call sites in
calculate_table_grid to invoke the function without changing the grid-growing
algorithm.
🪄 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: 9a91efbc-4657-459e-b8c3-17b45eda01dc

📥 Commits

Reviewing files that changed from the base of the PR and between 729bb3b and 71bced7.

📒 Files selected for processing (13)
  • Libraries/LibWeb/CMakeLists.txt
  • Libraries/LibWeb/DOM/Element.cpp
  • Libraries/LibWeb/Layout/LayoutRustBridge.cpp
  • Libraries/LibWeb/Layout/Node.cpp
  • Libraries/LibWeb/Layout/Node.h
  • Libraries/LibWeb/Layout/TableGrid.cpp
  • Libraries/LibWeb/Layout/TableGrid.h
  • Libraries/LibWeb/Layout/TreeBuilder.cpp
  • Libraries/LibWeb/Painting/TableBordersPainting.cpp
  • Libraries/LibWeb/Rust/src/layout/formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/node_data.rs
  • Libraries/LibWeb/Rust/src/layout/table_formatting_context.rs
  • Libraries/LibWeb/Rust/src/layout/tree_builder.rs
💤 Files with no reviewable changes (6)
  • Libraries/LibWeb/CMakeLists.txt
  • Libraries/LibWeb/Layout/TableGrid.cpp
  • Libraries/LibWeb/Layout/TreeBuilder.cpp
  • Libraries/LibWeb/Layout/TableGrid.h
  • Libraries/LibWeb/Rust/src/layout/formatting_context.rs
  • Libraries/LibWeb/Layout/LayoutRustBridge.cpp

Comment thread Libraries/LibWeb/Layout/Node.cpp
The Rust table formatting context already formed its own row and column
grid, while layout tree fixup constructed a duplicate C++ TableGrid and
queried every slot through an opaque FFI object. This kept two copies of
the formation algorithm and made missing-cell fixup cross the bridge for
each grid position.

Share the Rust grid builder with layout tree fixup and mirror the
bounded table spans into unused NodeData padding so grid formation
needs no read callbacks. Keep the missing-cell mutation callback while
C++ still owns layout boxes, and move the painting-only border
comparator next to its caller. This removes the C++ TableGrid and its
four bridge callbacks without changing NodeData's size.
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.

2 participants