From d5fcc5a5d50d270a1e96d91507a5c224240300bb Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Mon, 27 Jan 2025 07:02:32 -0800 Subject: [PATCH] layout: Improve fixed table layout (#35170) If `width` is indefinite, treat the outer size as zero, instead of treating the content size as zero and then adding padding and borders. Also, we don't want a default minimum of zero to get added padding and borders, and then defeat the point baove. So just ignore minimums and maximums. That seems to roughly match what other browsers do, but as usual, the details are not interoperable, e.g. some browsers may obey min or max sizing properties in some cases. Signed-off-by: Oriol Brufau --- components/layout_2020/geom.rs | 15 ++- components/layout_2020/table/layout.rs | 122 +++++++++--------- .../borders/border-applies-to-006.xht.ini | 2 - .../border-color-applies-to-006.xht.ini | 2 - .../tables/fixed-table-layout-003e07.xht.ini | 2 - .../tables/fixed-table-layout-003e08.xht.ini | 2 - .../tables/fixed-table-layout-003e09.xht.ini | 2 - .../tables/fixed-table-layout-003e10.xht.ini | 2 - .../tables/fixed-table-layout-003e11.xht.ini | 2 - .../tables/fixed-table-layout-003e12.xht.ini | 2 - .../tables/fixed-table-layout-003f03.xht.ini | 2 - .../tables/fixed-table-layout-003f04.xht.ini | 2 - .../tables/fixed-table-layout-003f05.xht.ini | 2 - .../tables/fixed-table-layout-003f06.xht.ini | 2 - .../tables/fixed-table-layout-003f07.xht.ini | 2 - .../tables/fixed-table-layout-003f08.xht.ini | 2 - 16 files changed, 69 insertions(+), 96 deletions(-) delete mode 100644 tests/wpt/meta/css/CSS2/borders/border-applies-to-006.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/borders/border-color-applies-to-006.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e07.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e08.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e09.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e10.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e11.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e12.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f03.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f04.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f05.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f06.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f07.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f08.xht.ini diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index 7114d4dc900..eb4f625906f 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -10,7 +10,7 @@ use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; use app_units::Au; use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode}; use style::values::computed::{ - CSSPixelLength, LengthPercentage, MaxSize as StyleMaxSize, Size as StyleSize, + CSSPixelLength, LengthPercentage, MaxSize as StyleMaxSize, Percentage, Size as StyleSize, }; use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr; use style::Zero; @@ -672,11 +672,6 @@ impl Default for Size { } impl Size { - #[inline] - pub(crate) fn is_numeric(&self) -> bool { - matches!(self, Self::Numeric(_)) - } - #[inline] pub(crate) fn is_initial(&self) -> bool { matches!(self, Self::Initial) @@ -747,6 +742,14 @@ impl From for Size { } } +impl Size { + #[inline] + pub(crate) fn to_percentage(&self) -> Option { + self.to_numeric() + .and_then(|length_percentage| length_percentage.to_percentage()) + } +} + impl LogicalVec2> { pub(crate) fn maybe_percentages_relative_to_basis( &self, diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index dcc3a6edd00..8a6d82c532f 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -216,6 +216,7 @@ pub(crate) struct TableLayout<'a> { basis_for_cell_padding_percentage: Au, /// Information about collapsed borders. collapsed_borders: Option, + is_in_fixed_mode: bool, } #[derive(Clone, Debug)] @@ -239,6 +240,15 @@ impl Zero for CellOrTrackMeasure { impl<'a> TableLayout<'a> { fn new(table: &'a Table) -> TableLayout<'a> { + // It's not clear whether `inline-size: stretch` allows fixed table mode or not, + // we align with Gecko and Blink. + // . + let is_in_fixed_mode = table.style.get_table().clone_table_layout() == + TableLayoutMode::Fixed && + !matches!( + table.style.box_size(table.style.writing_mode).inline, + Size::Initial | Size::MaxContent + ); Self { table, pbm: PaddingBorderMargin::zero(), @@ -254,6 +264,7 @@ impl<'a> TableLayout<'a> { cells_laid_out: Vec::new(), basis_for_cell_padding_percentage: Au::zero(), collapsed_borders: None, + is_in_fixed_mode, } } @@ -264,15 +275,6 @@ impl<'a> TableLayout<'a> { layout_context: &LayoutContext, writing_mode: WritingMode, ) { - // It's not clear whether `inline-size: stretch` allows fixed table mode or not, - // we align with Gecko and Blink. - // . - let is_in_fixed_mode = self.table.style.get_table().clone_table_layout() == - TableLayoutMode::Fixed && - !matches!( - self.table.style.box_size(writing_mode).inline, - Size::Initial | Size::MaxContent - ); let row_measures = vec![LogicalVec2::zero(); self.table.size.width]; self.cell_measures = vec![row_measures; self.table.size.height]; @@ -305,46 +307,39 @@ impl<'a> TableLayout<'a> { preferred: preferred_size, min: min_size, max: max_size, - inline_preferred_size_is_auto, percentage: percentage_size, } = CellOrColumnOuterSizes::new( &cell.base.style, writing_mode, &padding_border_sums, + self.is_in_fixed_mode, ); // // > When a table-root is laid out in fixed mode, the content of its table-cells is ignored // > for the purpose of width computation, the aggregation algorithm for column sizing considers // > only table-cells belonging to the first row track - let inline_measure = if is_in_fixed_mode && row_index > 0 { - CellOrTrackMeasure::zero() + let inline_measure = if self.is_in_fixed_mode { + if row_index > 0 { + CellOrTrackMeasure::zero() + } else { + CellOrTrackMeasure { + content_sizes: preferred_size.inline.into(), + percentage: percentage_size.inline, + } + } } else { - let mut inline_content_sizes = - cell.inline_content_sizes(layout_context, is_in_fixed_mode); - inline_content_sizes.min_content += padding_border_sums.inline; - inline_content_sizes.max_content += padding_border_sums.inline; + let inline_content_sizes = cell.inline_content_sizes(layout_context) + + padding_border_sums.inline.into(); assert!( inline_content_sizes.max_content >= inline_content_sizes.min_content, "the max-content size should never be smaller than the min-content size" ); // These formulas differ from the spec, but seem to match Gecko and Blink. - let outer_min_content_width = if is_in_fixed_mode { - if inline_preferred_size_is_auto { - // This is an outer size, but we deliberately ignore borders and padding. - // This is like allowing the content-box width to be negative. - Au::zero() - } else { - preferred_size - .inline - .clamp_between_extremums(min_size.inline, max_size.inline) - } - } else { - inline_content_sizes - .min_content - .clamp_between_extremums(min_size.inline, max_size.inline) - }; + let outer_min_content_width = inline_content_sizes + .min_content + .clamp_between_extremums(min_size.inline, max_size.inline); let outer_max_content_width = if self.columns[column_index].constrained { inline_content_sizes .min_content @@ -494,9 +489,11 @@ impl<'a> TableLayout<'a> { for column_index in 0..self.table.size.width { let column = &mut self.columns[column_index]; - let column_measure = self - .table - .get_column_measure_for_column_at_index(writing_mode, column_index); + let column_measure = self.table.get_column_measure_for_column_at_index( + writing_mode, + column_index, + self.is_in_fixed_mode, + ); column.content_sizes = column_measure.content_sizes; column.percentage = column_measure.percentage; @@ -2563,6 +2560,7 @@ impl Table { &self, writing_mode: WritingMode, column_index: usize, + is_in_fixed_mode: bool, ) -> CellOrTrackMeasure { let column = match self.columns.get(column_index) { Some(column) => column, @@ -2574,8 +2572,12 @@ impl Table { min: min_size, max: max_size, percentage: percentage_size, - .. - } = CellOrColumnOuterSizes::new(&column.style, writing_mode, &Default::default()); + } = CellOrColumnOuterSizes::new( + &column.style, + writing_mode, + &Default::default(), + is_in_fixed_mode, + ); CellOrTrackMeasure { content_sizes: ContentSizes { @@ -2772,15 +2774,7 @@ impl TableSlotCell { } } - fn inline_content_sizes( - &self, - layout_context: &LayoutContext, - is_in_fixed_mode: bool, - ) -> ContentSizes { - if is_in_fixed_mode { - return ContentSizes::zero(); - }; - + fn inline_content_sizes(&self, layout_context: &LayoutContext) -> ContentSizes { let constraint_space = ConstraintSpace::new_for_style_and_ratio( &self.base.style, None, /* TODO: support preferred aspect ratios on non-replaced boxes */ @@ -2883,20 +2877,15 @@ fn get_size_percentage_contribution( // > min(percentage width, percentage max-width). // > If the computed values are not percentages, then 0% is used for width, and an // > infinite percentage is used for max-width. - let get_contribution_for_axis = - |size: &Size, max_size: &Size| { - let size_percentage = size - .to_numeric() - .and_then(|length_percentage| length_percentage.to_percentage()); - let max_size_percentage = max_size - .to_numeric() - .and_then(|length_percentage| length_percentage.to_percentage()); - max_two_optional_percentages(size_percentage, max_size_percentage) - }; - LogicalVec2 { - inline: get_contribution_for_axis(&size.inline, &max_size.inline), - block: get_contribution_for_axis(&size.block, &max_size.block), + inline: max_two_optional_percentages( + size.inline.to_percentage(), + max_size.inline.to_percentage(), + ), + block: max_two_optional_percentages( + size.block.to_percentage(), + max_size.block.to_percentage(), + ), } } @@ -2905,7 +2894,6 @@ struct CellOrColumnOuterSizes { preferred: LogicalVec2, max: LogicalVec2>, percentage: LogicalVec2>, - inline_preferred_size_is_auto: bool, } impl CellOrColumnOuterSizes { @@ -2913,6 +2901,7 @@ impl CellOrColumnOuterSizes { style: &Arc, writing_mode: WritingMode, padding_border_sums: &LogicalVec2, + is_in_fixed_mode: bool, ) -> Self { let box_sizing = style.get_position().box_sizing; let outer_size = |size: LogicalVec2| match box_sizing { @@ -2923,7 +2912,7 @@ impl CellOrColumnOuterSizes { }, }; - let outer_size_for_max = |size: LogicalVec2>| match box_sizing { + let outer_option_size = |size: LogicalVec2>| match box_sizing { BoxSizing::ContentBox => size.map_inline_and_block_axes( |inline| inline.map(|inline| inline + padding_border_sums.inline), |block| block.map(|block| block + padding_border_sums.block), @@ -2943,14 +2932,23 @@ impl CellOrColumnOuterSizes { }; let size = style.box_size(writing_mode); + if is_in_fixed_mode { + return Self { + percentage: size.map(|v| v.to_percentage()), + preferred: outer_option_size(size.map(get_size_for_axis)) + .map(|v| v.unwrap_or_default()), + min: LogicalVec2::default(), + max: LogicalVec2::default(), + }; + } + let min_size = style.min_box_size(writing_mode); let max_size = style.max_box_size(writing_mode); Self { min: outer_size(min_size.map(|v| get_size_for_axis(v).unwrap_or_default())), preferred: outer_size(size.map(|v| get_size_for_axis(v).unwrap_or_default())), - max: outer_size_for_max(max_size.map(get_size_for_axis)), - inline_preferred_size_is_auto: !size.inline.is_numeric(), + max: outer_option_size(max_size.map(get_size_for_axis)), percentage: get_size_percentage_contribution(&size, &max_size), } } diff --git a/tests/wpt/meta/css/CSS2/borders/border-applies-to-006.xht.ini b/tests/wpt/meta/css/CSS2/borders/border-applies-to-006.xht.ini deleted file mode 100644 index d135fb40166..00000000000 --- a/tests/wpt/meta/css/CSS2/borders/border-applies-to-006.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[border-applies-to-006.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/borders/border-color-applies-to-006.xht.ini b/tests/wpt/meta/css/CSS2/borders/border-color-applies-to-006.xht.ini deleted file mode 100644 index 88916941dc5..00000000000 --- a/tests/wpt/meta/css/CSS2/borders/border-color-applies-to-006.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[border-color-applies-to-006.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e07.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e07.xht.ini deleted file mode 100644 index 992c95d7f1a..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e07.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003e07.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e08.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e08.xht.ini deleted file mode 100644 index 2229fd68f72..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e08.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003e08.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e09.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e09.xht.ini deleted file mode 100644 index 975703becce..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e09.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003e09.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e10.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e10.xht.ini deleted file mode 100644 index 1729d8ed270..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e10.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003e10.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e11.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e11.xht.ini deleted file mode 100644 index c68abad62fb..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e11.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003e11.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e12.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e12.xht.ini deleted file mode 100644 index 9bf489dc19c..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003e12.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003e12.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f03.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f03.xht.ini deleted file mode 100644 index bb669562829..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f03.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003f03.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f04.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f04.xht.ini deleted file mode 100644 index 2fac48ecc06..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f04.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003f04.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f05.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f05.xht.ini deleted file mode 100644 index 00957756ac4..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f05.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003f05.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f06.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f06.xht.ini deleted file mode 100644 index fdf1ce8e25e..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f06.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003f06.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f07.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f07.xht.ini deleted file mode 100644 index 8615dc4a13b..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f07.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003f07.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f08.xht.ini b/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f08.xht.ini deleted file mode 100644 index 02211151900..00000000000 --- a/tests/wpt/meta/css/CSS2/tables/fixed-table-layout-003f08.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fixed-table-layout-003f08.xht] - expected: FAIL