layout: Take percentage columns into account when sizing table grid min and max (#35167)

The specification doesn't say how to deal with percentages when
determining the minimum and maximum size of a table grid, so follow the
approach that Chromium uses.

Essentially, figure out the "missing" percentage from the non-percentage
columns and then use that to work backwards to fine the size of the
percentage ones.

This change is larger than one might expect, because this percentage
approach shouldn't happen for tables that are descendants of a flex,
grid or table container (except when there is an interceding absolute).
We have to pass this information down when building the box tree. This
will also make it easier to improve propagated text decorations in the
future.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-27 16:04:37 +01:00 committed by GitHub
parent d5fcc5a5d5
commit 6b04bc6263
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 228 additions and 226 deletions

View file

@ -646,12 +646,51 @@ impl<'a> TableLayout<'a> {
// https://drafts.csswg.org/css-tables/#gridmax:
// > The row/column-grid width maximum (GRIDMAX) width is the sum of the max-content width of
// > all the columns plus cell spacing or borders.
let mut grid_min_max = self
.columns
.iter()
.fold(ContentSizes::zero(), |result, measure| {
result + measure.content_sizes
});
//
// The specification doesn't say what to do with columns with percentages, so we follow the
// approach that LayoutNG takes here. We try to figure out the size contribution
// of the percentage columns, by working backward to find the calculated
// percentage of non-percent columns and using that to calculate the size of the
// percent columns.
let mut largest_percentage_column_max_size = Au::zero();
let mut percent_sum = 0.;
let mut non_percent_columns_max_sum = Au::zero();
let mut grid_min_max = ContentSizes::zero();
for column in self.columns.iter() {
match column.percentage {
Some(percentage) if !percentage.is_zero() => {
largest_percentage_column_max_size.max_assign(
column
.content_sizes
.max_content
.scale_by(1.0 / percentage.0),
);
percent_sum += percentage.0;
},
_ => {
non_percent_columns_max_sum += column.content_sizes.max_content;
},
}
grid_min_max += column.content_sizes;
}
grid_min_max
.max_content
.max_assign(largest_percentage_column_max_size);
// Do not take into account percentage of columns when this table is a descendant
// of a flex, grid, or table container. These modes with percentage columns can
// cause inline width to become infinitely wide.
if !percent_sum.is_zero() &&
self.table
.percentage_columns_allowed_for_inline_content_sizes
{
let total_inline_size =
non_percent_columns_max_sum.scale_by(1.0 / (1.0 - percent_sum.min(1.0)));
grid_min_max.max_content.max_assign(total_inline_size);
}
assert!(
grid_min_max.min_content <= grid_min_max.max_content,
"GRIDMAX should never be smaller than GRIDMIN {:?}",