layout: Fix table geometry when collapsed borders have different sizes (#35122)

Even though when painting the collapsed borders we were using the right
size, when sizing the table we were treating cells as having a border
of half the maximum border size along the entire grid line.

Now we only take the maximum among the borders adjacent to the cell.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-01-23 03:17:06 -08:00 committed by GitHub
parent 0af1204aa3
commit 8740c03682
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 121 additions and 16 deletions

View file

@ -2181,15 +2181,25 @@ impl<'a> TableLayout<'a> {
area: LogicalSides<usize>,
) -> Option<LogicalSides<Au>> {
let collapsed_borders = self.collapsed_borders.as_ref()?;
let inline_start = &collapsed_borders.inline[area.inline_start];
let inline_end = &collapsed_borders.inline[area.inline_end];
let block_start = &collapsed_borders.block[area.block_start];
let block_end = &collapsed_borders.block[area.block_end];
let columns = || area.inline_start..area.inline_end;
let rows = || area.block_start..area.block_end;
let max_width = |slice: &[CollapsedBorder]| {
let slice_widths = slice.iter().map(|collapsed_border| collapsed_border.width);
slice_widths.max().unwrap_or_default()
};
Some(area.map_inline_and_block_axes(
|column| max_width(&collapsed_borders.inline[*column].list[rows()]) / 2,
|row| max_width(&collapsed_borders.block[*row].list[columns()]) / 2,
))
}
fn get_collapsed_border_widths_for_table(&self) -> Option<LogicalSides<Au>> {
let collapsed_borders = self.collapsed_borders.as_ref()?;
Some(LogicalSides {
inline_start: inline_start.max_width / 2,
inline_end: inline_end.max_width / 2,
block_start: block_start.max_width / 2,
block_end: block_end.max_width / 2,
inline_start: collapsed_borders.inline[0].max_width / 2,
inline_end: collapsed_borders.inline[self.table.size.width].max_width / 2,
block_start: collapsed_borders.block[0].max_width / 2,
block_end: collapsed_borders.block[self.table.size.height].max_width / 2,
})
}
}
@ -2705,19 +2715,13 @@ impl TableLayoutStyle<'_> {
pub(crate) fn halved_collapsed_border_widths(&self) -> LogicalSides<Au> {
debug_assert!(self.collapses_borders());
let area = LogicalSides {
inline_start: 0,
inline_end: self.table.size.width,
block_start: 0,
block_end: self.table.size.height,
};
if let Some(layout) = self.layout {
layout.get_collapsed_border_widths_for_area(area)
layout.get_collapsed_border_widths_for_table()
} else {
// TODO: this should be cached.
let mut layout = TableLayout::new(self.table);
layout.compute_border_collapse(self.style().writing_mode);
layout.get_collapsed_border_widths_for_area(area)
layout.get_collapsed_border_widths_for_table()
}
.expect("Collapsed borders should be computed")
}

View file

@ -105335,6 +105335,19 @@
{}
]
],
"border-collapse-006.html": [
"f96c40cf95075703a67e9b13ef5b6f9e4e663ff8",
[
null,
[
[
"/css/reference/ref-filled-green-200px-square.html",
"=="
]
],
{}
]
],
"border-collapse-applies-to-016.xht": [
"f102d6a799b195388f57396024532947e3357303",
[

View file

@ -0,0 +1,88 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Test (Tables): collapsing borders with different widths</title>
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="http://www.w3.org/TR/CSS2/tables.html#collapsing-borders" />
<link rel="match" href="../../reference/ref-filled-green-200px-square.html">
<style>
table { border-collapse: collapse; background: green }
td { padding: 0; background: red; }
td div { height: 25px; background: green; }
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="float: left; min-width: 200px; background: red">
<!--
https://drafts.csswg.org/css2/#collapsing-borders
> Borders are centered on the grid lines between the cells.
That is, the column needs to be big enough to contain:
- Half of the left border form the 1st row, i.e. 75px.
- Half of the right border form the 2nd row, i.e. 50px.
Therefore, the column is max(75px, 50px) = 75px wide,
and it goes from position 75px to position 150px.
In the 1st row there is no remaining available space,
so the div becomes 0px wide.
In the 2nd row there are 75px - 50px = 25px of available space,
so the div becomes 25px wide.
-->
<table>
<tr>
<td style="border-left: 150px solid green">
<div></div>
</td>
</tr>
<tr>
<td style="border-right: 100px solid green">
<div></div>
</td>
</tr>
</table>
<!-- Same situation, but with explicit widths on the divs -->
<table>
<tr>
<td style="border-left: 150px solid green">
<div style="width: 0px"></div>
</td>
</tr>
<tr>
<td style="border-right: 100px solid green">
<div style="width: 25px"></div>
</td>
</tr>
</table>
<!-- Same situation, but with the rows swapped -->
<table>
<tr>
<td style="border-right: 100px solid green">
<div></div>
</td>
</tr>
<tr>
<td style="border-left: 150px solid green">
<div></div>
</td>
</tr>
</table>
<!-- Same situation, but with explicit widths and the rows swapped -->
<table>
<tr>
<td style="border-left: 150px solid green">
<div style="width: 0px"></div>
</td>
</tr>
<tr>
<td style="border-right: 100px solid green">
<div style="width: 25px"></div>
</td>
</tr>
</table>
</div>