← All issues

Table Rendering: RenderTableRow Promoted to RenderBlock

27d1a32

Source/WebCore/rendering/RenderLayer.cpp

- if (auto* boxRenderer = dynamicDowncast<RenderBox>(ancestor)) {
- // Rows and cells share the same coordinate space (that of the section).
- // Omit them when computing our xpos/ypos.
- if (!is<RenderTableRow>(boxRenderer))
- localPoint += boxRenderer->topLeftLocationOffset();
- }
+ if (auto* boxRenderer = dynamicDowncast<RenderBox>(ancestor))
+ localPoint += boxRenderer->topLeftLocationOffset();
ancestor = ancestor->parent();
- if (auto* tableRow = dynamicDowncast<RenderTableRow>(ancestor)) {
- // Put ourselves into the row coordinate space.
- localPoint -= tableRow->topLeftLocationOffset();
- }

Source/WebCore/rendering/RenderTableSection.cpp

- // Cell Y = m_rowPos[rowIndex] (section-relative)
+ // Cell Y = 0 (row-relative; the row itself carries the section offset)

This is a foundational coordinate-system change to WebKit's table rendering. RenderTableRow is promoted from RenderBox to RenderBlock, making table rows proper containing blocks for absolutely positioned descendants. Previously, the containingBlock() walk skipped non-RenderBlock ancestors, so a <tr> extending RenderBox was invisible — absolutely positioned children escaped past it. The style system patched around this by forcing position: static on rows. Cells accumulated positions relative to the section (RenderTableSection), and every subsystem that needed to convert coordinates had bespoke row-skipping or offset-correction logic. This commit removes roughly ten such workarounds.

Before:                                          After:

Nearest positioned ancestor                      RenderTableRow (RenderBlock)
  (e.g. viewport or positioned div)                └─ RenderTableCell
  └─ abspos child  ◄── escapes past                    └─ abspos descendant  ──► sized/positioned
        RenderTableSection                                                        relative to row
          (coordinate origin for cells)
          └─ RenderTableRow (RenderBox, not a containing block)
               └─ RenderTableCell

Coordinate origin for cells:
  Before: section-relative (m_rowPos[rowIndex] baked into cell position)
  After:  row-relative     (cell Y = 0; row carries the section offset)

This simultaneously shifts the coordinate origin for every cell in every table, introduces RenderLayer creation for positioned rows, wires in out-of-flow layout for a previously-static element type, and adjusts sticky constraint logic — all in one commit.

The change touches layer positioning, hit testing, paint, sticky layout, fragmented flow, and out-of-flow layout. Positioned <tr> elements now create RenderLayer, meaning dynamic style changes that add/remove position: relative on a row after layout exercise the layer creation/destruction path in a new context. The clearNeedsLayout() call was moved from RenderTableRow::layout() to RenderTableSection::layoutRows() — if layoutRows can exit early during a relayout triggered mid-traversal, rows may have needsLayout() cleared without their dimensions being finalized.

🔒

A sweeping coordinate-system change across the table rendering pipeline — several new code paths and interaction edges are worth security investigation.

Subscribe to read more