layout: Align table-cell contents safely (#39491)

As resolved in https://github.com/w3c/csswg-drafts/issues/12220, when
resolving `align-content: normal` on a table cell, we will now use safe
alignment.

The difference only matters when the contents of the cell are taller
than the cell, which doesn't typically happen. But in Servo it's
observable when there are collapsed rows.

Testing: Adding new tests. Some fail because we don't support
`align-content` yet.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-09-26 09:44:23 +02:00 committed by GitHub
parent 92dd54b1ec
commit 858208bd25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 260 additions and 4 deletions

View file

@ -2819,12 +2819,11 @@ impl TableSlotCell {
let cell_content_rect = cell_rect.deflate(&(layout.padding + layout.border));
let content_block_size = layout.layout.content_block_size;
let free_space = || Au::zero().max(cell_content_rect.size.block - content_block_size);
let vertical_align_offset = match self.effective_vertical_align() {
VerticalAlignKeyword::Top => Au::zero(),
VerticalAlignKeyword::Bottom => cell_content_rect.size.block - content_block_size,
VerticalAlignKeyword::Middle => {
(cell_content_rect.size.block - content_block_size).scale_by(0.5)
},
VerticalAlignKeyword::Bottom => free_space(),
VerticalAlignKeyword::Middle => free_space().scale_by(0.5),
_ => {
cell_baseline -
(layout.padding.block_start + layout.border.block_start) -

View file

@ -126411,6 +126411,62 @@
{}
]
],
"align-content-table-cell-002.html": [
"1082be469bfa7fa23981ebd3793d7d321901640a",
[
null,
[
[
"/css/reference/ref-filled-green-300px-square.html",
"=="
]
],
{}
]
],
"align-content-table-cell-003.html": [
"cf156a07bf9ae928ae0a69d566e27042fc4b52d7",
[
null,
[
[
"/css/reference/ref-filled-green-300px-square.html",
"=="
]
],
{}
]
],
"align-content-table-cell-004.html": [
"103c95947cd842b1ecb55d54f9e20097911794d1",
[
null,
[
[
"/css/reference/ref-filled-green-300px-square.html",
"=="
]
],
{}
]
],
"align-content-table-cell-005.html": [
"b311489d44445c3811ed792ed7fc4fc86690cac5",
[
null,
[
[
"/css/reference/ref-filled-green-300px-square.html",
"=="
],
[
"/css/css-align/blocks/align-content-table-cell-005-ref-alt.html",
"=="
]
],
{}
]
],
"justify-items-anonymous.html": [
"641dea1f54b2f0cea29bc4c4c82e023a479e3d3c",
[
@ -424536,6 +424592,10 @@
"align-content-block-overflow-000-ref.html": [
"8ca5407e4ca0a65d3a98e322c90d4cada8fef15b",
[]
],
"align-content-table-cell-005-ref-alt.html": [
"771c8f72adf18d011985a002d67e9519c1fa3900",
[]
]
},
"content-distribution": {

View file

@ -0,0 +1,2 @@
[align-content-table-cell-004.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[align-content-table-cell-005.html]
expected: FAIL

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-align/#distribution-block">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/12220">
<link rel="match" href="../../reference/ref-filled-green-300px-square.html">
<meta name="assert" content="
The contents of the cells are 600px tall, but since we are collapsing one row,
the cells shrink to be only 300px tall. Therefore, the contents overflow.
Since the cells have the default `align-content: normal`, the alignment is
decided depending on `vertical-align`:
- `vertical-align: top` maps to `align-self: safe start`
- `vertical-align: middle` maps to `align-self: safe center`
- `vertical-align: bottom` maps to `align-self: safe end`
">
<style>
table {
overflow: hidden;
}
tr {
height: 300px;
}
td::before {
content: "";
display: block;
width: 50px;
height: 600px;
background: linear-gradient(to bottom, green 50%, red 50%);
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<table cellspacing="0" cellpadding="0">
<tr>
<td rowspan="2" style="vertical-align: top"></td>
<td rowspan="2" style="vertical-align: middle"></td>
<td rowspan="2" style="vertical-align: bottom"></td>
<td rowspan="2" style="overflow: hidden; vertical-align: top"></td>
<td rowspan="2" style="overflow: hidden; vertical-align: middle"></td>
<td rowspan="2" style="overflow: hidden; vertical-align: bottom"></td>
</tr>
<tr style="visibility: collapse"></tr>
</table>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-align/#distribution-blocks">
<link rel="help" href="https://drafts.csswg.org/css-align/#valdef-overflow-position-safe">
<link rel="match" href="../../reference/ref-filled-green-300px-square.html">
<meta name="assert" content="
The contents of the cells are 600px tall, but since we are collapsing one row,
the cells shrink to be only 300px tall. Therefore, the contents overflow.
This test checks various safe alignments, which should behave as `start`.
">
<style>
table {
overflow: hidden;
}
tr {
height: 300px;
}
td::before {
content: "";
display: block;
width: 50px;
height: 600px;
background: linear-gradient(to bottom, green 50%, red 50%);
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<table cellspacing="0" cellpadding="0">
<tr>
<td rowspan="2" style="align-content: safe start"></td>
<td rowspan="2" style="align-content: safe center"></td>
<td rowspan="2" style="align-content: safe end"></td>
<td rowspan="2" style="overflow: hidden; align-content: safe start"></td>
<td rowspan="2" style="overflow: hidden; align-content: safe center"></td>
<td rowspan="2" style="overflow: hidden; align-content: safe end"></td>
</tr>
<tr style="visibility: collapse"></tr>
</table>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-align/#distribution-blocks">
<link rel="help" href="https://drafts.csswg.org/css-align/#valdef-overflow-position-unsafe">
<link rel="match" href="../../reference/ref-filled-green-300px-square.html">
<meta name="assert" content="
The contents of the cells are 600px tall, but since we are collapsing one row,
the cells shrink to be only 300px tall. Therefore, the contents overflow.
This test checks various unsafe alignments.
">
<style>
table {
overflow: hidden;
}
tr {
height: 300px;
}
td::before {
content: "";
display: block;
width: 50px;
height: 600px;
background: linear-gradient(to bottom, var(--gradient));
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<table cellspacing="0" cellpadding="0">
<tr>
<td rowspan="2" style="align-content: unsafe start; --gradient: green 50%, red 50%"></td>
<td rowspan="2" style="align-content: unsafe center; --gradient: red 25%, green 25% 75%, red 75%"></td>
<td rowspan="2" style="align-content: unsafe end; --gradient: red 50%, green 50%"></td>
<td rowspan="2" style="overflow: hidden; align-content: unsafe start; --gradient: green 50%, red 50%"></td>
<td rowspan="2" style="overflow: hidden; align-content: unsafe center; --gradient: red 25%, green 25% 75%, red 75%"></td>
<td rowspan="2" style="overflow: hidden; align-content: unsafe end; --gradient: red 50%, green 50%"></td>
</tr>
<tr style="visibility: collapse"></tr>
</table>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset="utf-8">
<!--
This is an alternative expectation for UAs that have not implemented
the “smart” default behavior for overflow alignment on boxes that aren't
scroll containers.
The text says that there should be no red, but that's for the main
expectation. In this alternative one, a bit of red is expected.
-->
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="float: left; width: 50px; height: 150px; background: green"></div>
<div style="float: left; width: 100px; height: 150px; background: red"></div>
<div style="float: left; width: 150px; height: 150px; background: green"></div>
<div style="clear: left"></div>
<div style="float: left; width: 100px; height: 150px; background: green"></div>
<div style="float: left; width: 50px; height: 150px; background: red"></div>
<div style="float: left; width: 150px; height: 150px; background: green"></div>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-align/#distribution-blocks">
<link rel="help" href="https://drafts.csswg.org/css-align/#auto-safety">
<link rel="match" href="../../reference/ref-filled-green-300px-square.html">
<link rel="match" href="align-content-table-cell-005-ref-alt.html">
<meta name="assert" content="
The contents of the cells are 600px tall, but since we are collapsing one row,
the cells shrink to be only 300px tall. Therefore, the contents overflow.
This test checks various alignments with no overflow alignment specified,
they should behave as unsafe.
However, for cells which aren't scroll containers, UAs that have not implemented
the “smart” default behavior must behave as safe, hence there are 2 expectations.
">
<style>
table {
overflow: hidden;
}
tr {
height: 300px;
}
td::before {
content: "";
display: block;
width: 50px;
height: 600px;
background: linear-gradient(to bottom, var(--gradient));
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<table cellspacing="0" cellpadding="0">
<tr>
<td rowspan="2" style="align-content: start; --gradient: green 50%, red 50%"></td>
<td rowspan="2" style="align-content: center; --gradient: red 25%, green 25% 75%, red 75%"></td>
<td rowspan="2" style="align-content: end; --gradient: red 50%, green 50%"></td>
<td rowspan="2" style="overflow: hidden; align-content: start; --gradient: green 50%, red 50%"></td>
<td rowspan="2" style="overflow: hidden; align-content: center; --gradient: red 25%, green 25% 75%, red 75%"></td>
<td rowspan="2" style="overflow: hidden; align-content: end; --gradient: red 50%, green 50%"></td>
</tr>
<tr style="visibility: collapse"></tr>
</table>