Bug 311117

Summary: Potential bug in table border code caught in code review
Product: WebKit Reporter: Sam Weinig <sam>
Component: TablesAssignee: Karl Dubost <karlcow>
Status: RESOLVED FIXED    
Severity: Normal CC: fantasai.bugs, karlcow, webkit-bug-importer, zalan
Priority: P2 Keywords: InRadar
Version: Safari 18   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://github.com/web-platform-tests/wpt/pull/58929

Sam Weinig
Reported 2026-03-30 10:21:13 PDT
I was working on a separate border issue and I noticed a weirdness in RenderTable::outerBorderTop(). ``` inline LayoutUnit RenderTable::outerBorderTop() const { if (writingMode().isHorizontal()) return writingMode().isBlockTopToBottom() ? outerBorderBefore() : outerBorderAfter(); return writingMode().isInlineTopToBottom() ? outerBorderStart() : borderEnd(); } ``` Notice that it uses `borderEnd()` for the last conditional, not `outerBorderEnd()`. All the other variants of this function only use "outerBorder*()` calls. For instance, `RenderTable::outerBorderRight()`: ``` inline LayoutUnit RenderTable::outerBorderRight() const { if (writingMode().isHorizontal()) return writingMode().isInlineLeftToRight() ? outerBorderEnd() : outerBorderStart(); return writingMode().isBlockLeftToRight() ? outerBorderAfter() : outerBorderBefore(); } ``` This looks like an accidental typo (otherwise, I would expect some kind of comment explaining the inconsistency in the pattern). I haven't tried to figure out how to trigger this code or make a test case, but wanted to file the bug so I or someone else might take a look in the future.
Attachments
Karl Dubost
Comment 1 2026-03-30 19:24:52 PDT
This was changed in https://searchfox.org/wubkat/diff/72e07604aff9e355a3b669b908981bb66e8e597a/Source/WebCore/rendering/RenderTableInlines.h#96 It had the right term before. I didn't manage to create a test offering a visual difference. Plus there are other bugs getting into the way. table { writing-mode: vertical-rl; direction: rtl; border-collapse: collapse; border: none; } td { width: 30px; height: 30px; } /* First row: thin border (what borderEnd sees) */ .thin td { border: 2px solid blue; } /* Second row: thick border (what outerBorderEnd sees) */ .thick td { border: 40px solid red; } <table> <tbody> <tr class="thin"> <td></td> <td></td> </tr> <tr class="thick"> <td></td> <td></td> </tr> </tbody> </table> The table must have `border: none` If the table has a visible border (e.g. `border: 2px solid black`), then `outerBorderEnd()` returns early at line 1536-1537 with the table's own border value — it never reaches the section iteration loop. Both `borderEnd()` and `outerBorderEnd()` would return the same value, and the bug is invisible. https://searchfox.org/wubkat/rev/9234d58780c9dd9eaf6c8ad43dac914866768956/Source/WebCore/rendering/RenderTable.cpp#1536-1537 ```cpp if (tb.hasVisibleStyle()) return CollapsedBorderValue::adjustedCollapsedBorderWidth(Style::evaluate<float>(tb.width, Style::ZoomNeeded { }), protect(document())->deviceScaleFactor(), !writingMode().isInlineFlipped()); ``` With `border: none`, `outerBorderEnd()` falls through to the loop (line 1539-1546) that iterates all sections and finds the thick border from row 2. https://searchfox.org/wubkat/rev/9234d58780c9dd9eaf6c8ad43dac914866768956/Source/WebCore/rendering/RenderTable.cpp#1539-1546 ```cpp bool allHidden = true; for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) { LayoutUnit sw = section->outerBorderEnd(); if (sw < 0) continue; allHidden = false; borderWidth = std::max(borderWidth, sw); } ``` But the bug has no really noticeable visual effect.
Radar WebKit Bug Importer
Comment 2 2026-03-30 19:26:54 PDT
Karl Dubost
Comment 3 2026-03-30 19:44:41 PDT
CSS 2.2 §17.6.2 https://www.w3.org/TR/CSS22/tables.html#collapsing-borders - "initial left and right border width" from first row only - "subsequent rows" with larger borders spilling into margin - "Any borders that spill into the margin are taken into account when determining if the table overflows some ancestor" CSS Tables Level 3: https://drafts.csswg.org/css-tables-3/#computing-cell-measures - Defines "table intrinsic offsets" (§3.8.2) as "half the winning border-width" for collapsed-borders mode - Has an open issue about this: "Handling of intrinsic offsets when in border collapsing mode" (https://github.com/w3c/csswg-drafts/issues/608) - Does not replicate the CSS 2.2 "first row" vs "all rows" distinction or the "spill into margin" overflow language - Does not mention ink/visual/scrollable overflow for collapsed borders at all there is an open issue (#608) specifically about collapsed border intrinsic offsets. https://github.com/w3c/csswg-drafts/issues/608 Now I wonder if it was intentional from Elika.
Karl Dubost
Comment 4 2026-03-30 19:46:29 PDT
EWS
Comment 5 2026-04-01 16:51:41 PDT
Committed 310404@main (6885c2bcb70b): <https://commits.webkit.org/310404@main> Reviewed commits have been landed. Closing PR #61737 and removing active labels.
Karl Dubost
Comment 6 2026-04-01 16:56:45 PDT
Submitted web-platform-tests pull request: https://github.com/web-platform-tests/wpt/pull/58929
Note You need to log in before you can comment on or make changes to this bug.