From 057dd1e9eb46749f3e38bf7fbbf05392d8fbe1fd Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Fri, 27 Sep 2024 10:16:07 -0700 Subject: [PATCH] Make ComputedValuesExt expose keywords for the sizing properties (#33558) This will allow callers to start obeying `min-content`, `max-content`, `fit-content` and `stretch` in follow-up patches. The old functionality is kept as deprecated methods that we should eventually remove. This patch has very little impact on the existing behavior, just some very minimal implementation of the keywords for css tables. This also overhauls fixed-layout-2.html since: - It had code that wasn't doing anything - It had wrong expecations in prose - The logic seemed broken in general - All browsers were failing one testcase Signed-off-by: Oriol Brufau --- components/layout_2020/flexbox/layout.rs | 12 +- components/layout_2020/flow/float.rs | 6 +- components/layout_2020/flow/inline/mod.rs | 6 +- components/layout_2020/flow/mod.rs | 22 +- components/layout_2020/geom.rs | 228 +++++++++++------- components/layout_2020/lib.rs | 2 +- components/layout_2020/positioned.rs | 6 +- components/layout_2020/replaced.rs | 6 +- components/layout_2020/sizing.rs | 2 +- components/layout_2020/style_ext.rs | 157 ++++++++---- components/layout_2020/table/layout.rs | 55 +++-- tests/wpt/meta/MANIFEST.json | 2 +- .../table-width-redistribution-fixed.html.ini | 3 - .../tests/css/css-tables/fixed-layout-2.html | 180 ++++++++------ 14 files changed, 419 insertions(+), 268 deletions(-) diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index c7f7c4a86b8..5aab37df248 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -936,10 +936,10 @@ impl FlexContainer { .padding_border_margin(containing_block_for_container); let max_box_size = self .style - .content_max_box_size(containing_block_for_container, &pbm); + .content_max_box_size_deprecated(containing_block_for_container, &pbm); let min_box_size = self .style - .content_min_box_size(containing_block_for_container, &pbm) + .content_min_box_size_deprecated(containing_block_for_container, &pbm) .auto_is(Au::zero); let max_box_size = self.config.flex_axis.vec2_to_flex_relative(max_box_size); @@ -1012,15 +1012,15 @@ impl<'a> FlexItem<'a> { let pbm = box_.style().padding_border_margin(containing_block); let content_box_size = box_ .style() - .content_box_size(containing_block, &pbm) + .content_box_size_deprecated(containing_block, &pbm) .map(|v| v.map(Au::from)); let max_size = box_ .style() - .content_max_box_size(containing_block, &pbm) + .content_max_box_size_deprecated(containing_block, &pbm) .map(|v| v.map(Au::from)); let min_size = box_ .style() - .content_min_box_size(containing_block, &pbm) + .content_min_box_size_deprecated(containing_block, &pbm) .map(|v| v.map(Au::from)); let margin_auto_is_zero = flex_context.sides_to_flex_relative(pbm.margin.auto_is(Au::zero)); @@ -2005,7 +2005,7 @@ impl FlexItemBox { cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis); let (content_box_size, content_min_size, content_max_size, pbm) = - style.content_box_sizes_and_padding_border_margin(containing_block); + style.content_box_sizes_and_padding_border_margin_deprecated(containing_block); let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding); let border = main_start_cross_start.sides_to_flex_relative(pbm.border); let margin = main_start_cross_start.sides_to_flex_relative(pbm.margin); diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 73e12ac2298..b4d77b35e80 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -915,13 +915,13 @@ impl FloatBox { // https://drafts.csswg.org/css2/#float-width let style = non_replaced.style.clone(); let box_size = style - .content_box_size(containing_block, &pbm) + .content_box_size_deprecated(containing_block, &pbm) .map(|v| v.map(Au::from)); let max_box_size = style - .content_max_box_size(containing_block, &pbm) + .content_max_box_size_deprecated(containing_block, &pbm) .map(|v| v.map(Au::from)); let min_box_size = style - .content_min_box_size(containing_block, &pbm) + .content_min_box_size_deprecated(containing_block, &pbm) .map(|v| v.map(Au::from)) .auto_is(Au::zero); diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index 8a26e38a466..56d17bd54b9 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -1929,15 +1929,15 @@ impl IndependentFormattingContext { IndependentFormattingContext::NonReplaced(non_replaced) => { let box_size = non_replaced .style - .content_box_size(layout.containing_block, &pbm) + .content_box_size_deprecated(layout.containing_block, &pbm) .map(|v| v.map(Au::from)); let max_box_size = non_replaced .style - .content_max_box_size(layout.containing_block, &pbm) + .content_max_box_size_deprecated(layout.containing_block, &pbm) .map(|v| v.map(Au::from)); let min_box_size = non_replaced .style - .content_min_box_size(layout.containing_block, &pbm) + .content_min_box_size_deprecated(layout.containing_block, &pbm) .map(|v| v.map(Au::from)) .auto_is(Au::zero); let block_size = box_size diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 9c469650d48..09c4d0e2a16 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -135,10 +135,10 @@ impl BlockLevelBox { } let min_size = style - .content_min_box_size(containing_block, &pbm) + .content_min_box_size_deprecated(containing_block, &pbm) .auto_is(Au::zero); - let max_size = style.content_max_box_size(containing_block, &pbm); - let prefered_size = style.content_box_size(containing_block, &pbm); + let max_size = style.content_max_box_size_deprecated(containing_block, &pbm); + let prefered_size = style.content_box_size_deprecated(containing_block, &pbm); let inline_size = prefered_size .inline .auto_is(|| { @@ -1048,11 +1048,15 @@ impl NonReplacedFormattingContext { sequential_layout_state: &mut SequentialLayoutState, ) -> BoxFragment { let pbm = self.style.padding_border_margin(containing_block); - let box_size = self.style.content_box_size(containing_block, &pbm); - let max_box_size = self.style.content_max_box_size(containing_block, &pbm); + let box_size = self + .style + .content_box_size_deprecated(containing_block, &pbm); + let max_box_size = self + .style + .content_max_box_size_deprecated(containing_block, &pbm); let min_box_size = self .style - .content_min_box_size(containing_block, &pbm) + .content_min_box_size_deprecated(containing_block, &pbm) .auto_is(Au::zero); let block_size = box_size.block.map(|block_size| { block_size.clamp_between_extremums(min_box_size.block, max_box_size.block) @@ -1424,10 +1428,10 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( style: &'a Arc, ) -> ContainingBlockPaddingAndBorder<'a> { let pbm = style.padding_border_margin(containing_block); - let box_size = style.content_box_size(containing_block, &pbm); - let max_box_size = style.content_max_box_size(containing_block, &pbm); + let box_size = style.content_box_size_deprecated(containing_block, &pbm); + let max_box_size = style.content_max_box_size_deprecated(containing_block, &pbm); let min_box_size = style - .content_min_box_size(containing_block, &pbm) + .content_min_box_size_deprecated(containing_block, &pbm) .auto_is(Au::zero); // https://drafts.csswg.org/css2/#the-width-property diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index 906a9808154..0d97e45b2d2 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -9,7 +9,9 @@ use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; use app_units::Au; use serde::Serialize; use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode}; -use style::values::computed::{CSSPixelLength, LengthPercentage}; +use style::values::computed::{ + CSSPixelLength, LengthPercentage, MaxSize as StyleMaxSize, Size as StyleSize, +}; use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr; use style::Zero; use style_traits::CSSPixel; @@ -145,89 +147,6 @@ impl LogicalVec2> { } } -impl LogicalVec2> { - pub(crate) fn percentages_relative_to( - &self, - containing_block: &ContainingBlock, - ) -> LogicalVec2 { - LogicalVec2 { - inline: self - .inline - .map(|value| value.to_used_value(containing_block.inline_size)), - block: { - self.block - .non_auto() - .and_then(|value| { - value.maybe_to_used_value(containing_block.block_size.non_auto()) - }) - .map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage) - }, - } - } -} - -impl LogicalVec2> { - pub(crate) fn percentages_relative_to_basis( - &self, - basis: &LogicalVec2, - ) -> LogicalVec2 { - LogicalVec2 { - inline: self.inline.map(|value| value.to_used_value(basis.inline)), - block: self.block.map(|value| value.to_used_value(basis.block)), - } - } -} - -impl LogicalVec2> { - pub(crate) fn maybe_percentages_relative_to_basis( - &self, - basis: &LogicalVec2>, - ) -> LogicalVec2 { - LogicalVec2 { - inline: self - .inline - .non_auto() - .and_then(|value| value.maybe_to_used_value(basis.inline)) - .map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage), - block: self - .block - .non_auto() - .and_then(|value| value.maybe_to_used_value(basis.block)) - .map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage), - } - } -} - -impl LogicalVec2> { - pub(crate) fn percentages_relative_to( - &self, - containing_block: &ContainingBlock, - ) -> LogicalVec2> { - LogicalVec2 { - inline: self - .inline - .map(|lp| lp.to_used_value(containing_block.inline_size)), - block: self - .block - .and_then(|lp| lp.maybe_to_used_value(containing_block.block_size.non_auto())), - } - } -} - -impl LogicalVec2> { - pub(crate) fn maybe_percentages_relative_to_basis( - &self, - basis: &LogicalVec2>, - ) -> LogicalVec2> { - LogicalVec2 { - inline: self - .inline - .and_then(|v| v.maybe_to_used_value(basis.inline)), - block: self.block.and_then(|v| v.maybe_to_used_value(basis.block)), - } - } -} - impl LogicalRect { pub fn zero() -> Self { Self { @@ -701,3 +620,144 @@ impl ToLogicalWithContainingBlock> for PhysicalRect { } } } + +/// The possible keywords accepted by the sizing properties. +/// +#[derive(Clone)] +pub(crate) enum SizeKeyword { + /// Represents an `auto` value for the preferred and minimum size properties, + /// or `none` for the maximum size properties. + /// + /// + Initial, + /// + MinContent, + /// + MaxContent, + /// + FitContent, + /// + Stretch, +} + +/// The possible values accepted by the sizing properties, +/// with numeric `` resolved as a `T`. +/// +#[derive(Clone)] +pub(crate) enum Size { + Keyword(SizeKeyword), + Numeric(T), +} + +impl Default for Size { + #[inline] + fn default() -> Self { + Self::Keyword(SizeKeyword::Initial) + } +} + +impl Size { + #[inline] + pub(crate) fn is_keyword(&self) -> bool { + matches!(self, Self::Keyword(_)) + } + + #[inline] + pub(crate) fn to_numeric(&self) -> Option { + match self { + Self::Keyword(_) => None, + Self::Numeric(numeric) => Some(numeric).cloned(), + } + } + + #[inline] + pub(crate) fn to_auto_or(&self) -> AutoOr { + self.to_numeric() + .map_or(AutoOr::Auto, AutoOr::LengthPercentage) + } + + #[inline] + pub fn map(&self, f: impl FnOnce(T) -> U) -> Size { + match self { + Size::Keyword(keyword) => Size::Keyword(keyword.clone()), + Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())), + } + } + + #[inline] + pub fn maybe_map(&self, f: impl FnOnce(T) -> Option) -> Option> { + Some(match self { + Size::Keyword(keyword) => Size::Keyword(keyword.clone()), + Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())?), + }) + } +} + +impl From for Size { + fn from(size: StyleSize) -> Self { + match size { + StyleSize::LengthPercentage(length) => Size::Numeric(length.0), + StyleSize::Auto => Size::Keyword(SizeKeyword::Initial), + StyleSize::MinContent => Size::Keyword(SizeKeyword::MinContent), + StyleSize::MaxContent => Size::Keyword(SizeKeyword::MaxContent), + StyleSize::FitContent => Size::Keyword(SizeKeyword::FitContent), + StyleSize::Stretch => Size::Keyword(SizeKeyword::Stretch), + } + } +} + +impl From for Size { + fn from(max_size: StyleMaxSize) -> Self { + match max_size { + StyleMaxSize::LengthPercentage(length) => Size::Numeric(length.0), + StyleMaxSize::None => Size::Keyword(SizeKeyword::Initial), + StyleMaxSize::MinContent => Size::Keyword(SizeKeyword::MinContent), + StyleMaxSize::MaxContent => Size::Keyword(SizeKeyword::MaxContent), + StyleMaxSize::FitContent => Size::Keyword(SizeKeyword::FitContent), + StyleMaxSize::Stretch => Size::Keyword(SizeKeyword::Stretch), + } + } +} + +impl LogicalVec2> { + pub(crate) fn percentages_relative_to( + &self, + containing_block: &ContainingBlock, + ) -> LogicalVec2> { + LogicalVec2 { + inline: self + .inline + .map(|lp| lp.to_used_value(containing_block.inline_size)), + block: self + .block + .maybe_map(|lp| lp.maybe_to_used_value(containing_block.block_size.non_auto())) + .unwrap_or_default(), + } + } + + pub(crate) fn maybe_percentages_relative_to_basis( + &self, + basis: &LogicalVec2>, + ) -> LogicalVec2> { + LogicalVec2 { + inline: self + .inline + .maybe_map(|v| v.maybe_to_used_value(basis.inline)) + .unwrap_or_default(), + block: self + .block + .maybe_map(|v| v.maybe_to_used_value(basis.block)) + .unwrap_or_default(), + } + } + + pub(crate) fn percentages_relative_to_basis( + &self, + basis: &LogicalVec2, + ) -> LogicalVec2> { + LogicalVec2 { + inline: self.inline.map(|value| value.to_used_value(basis.inline)), + block: self.block.map(|value| value.to_used_value(basis.block)), + } + } +} diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 800fd54216e..d7fe1851bd6 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -66,7 +66,7 @@ impl<'a> IndefiniteContainingBlock<'a> { auto_minimum: &LogicalVec2, ) -> Self { let (content_box_size, content_min_size, content_max_size, _) = - style.content_box_sizes_and_padding_border_margin(self); + style.content_box_sizes_and_padding_border_margin_deprecated(self); let block_size = content_box_size.block.map(|v| { v.clamp_between_extremums( content_min_size.block.auto_is(|| auto_minimum.block), diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index f51e781150f..8f29162f549 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -476,7 +476,7 @@ impl HoistedAbsolutelyPositionedBox { }, IndependentFormattingContext::NonReplaced(non_replaced) => non_replaced .style - .content_box_size(&indefinite_containing_block, &pbm), + .content_box_size_deprecated(&indefinite_containing_block, &pbm), }; let shared_fragment = self.fragment.borrow(); @@ -561,10 +561,10 @@ impl HoistedAbsolutelyPositionedBox { // https://drafts.csswg.org/css2/#min-max-heights let min_size = non_replaced .style - .content_min_box_size(&indefinite_containing_block, &pbm) + .content_min_box_size_deprecated(&indefinite_containing_block, &pbm) .map(|t| t.map(Au::from).auto_is(Au::zero)); let max_size = style - .content_max_box_size(&containing_block.into(), &pbm) + .content_max_box_size_deprecated(&containing_block.into(), &pbm) .map(|t| t.map(Au::from)); // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index f0e4648a5a9..b54682a287d 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -427,15 +427,15 @@ impl ReplacedContent { pbm: &PaddingBorderMargin, ) -> LogicalVec2 { let box_size = style - .content_box_size(containing_block, pbm) + .content_box_size_deprecated(containing_block, pbm) // We need to clamp to zero here to obtain the proper aspect // ratio when box-sizing is border-box and the inner box size // would otherwise be negative. .map(|value| value.map(|value| value.max(Au::zero()))); let min_box_size = style - .content_min_box_size(containing_block, pbm) + .content_min_box_size_deprecated(containing_block, pbm) .auto_is(Au::zero); - let max_box_size = style.content_max_box_size(containing_block, pbm); + let max_box_size = style.content_max_box_size_deprecated(containing_block, pbm); self.used_size_as_if_inline_element_from_content_box_sizes( containing_block, style, diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index abffe3548a0..521779120ff 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -121,7 +121,7 @@ pub(crate) fn outer_inline( get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> ContentSizes, ) -> ContentSizes { let (content_box_size, content_min_size, content_max_size, pbm) = - style.content_box_sizes_and_padding_border_margin(containing_block); + style.content_box_sizes_and_padding_border_margin_deprecated(containing_block); let content_min_size = LogicalVec2 { inline: content_min_size.inline.auto_is(|| auto_minimum.inline), block: content_min_size.block.auto_is(|| auto_minimum.block), diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index 40596bf30a4..00f64abf039 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -16,11 +16,8 @@ use style::properties::ComputedValues; use style::servo::selector_parser::PseudoElement; use style::values::computed::basic_shape::ClipPath; use style::values::computed::image::Image as ComputedImageLayer; -use style::values::computed::{ - AlignItems, BorderStyle, LengthPercentage, NonNegativeLengthPercentage, Size, -}; +use style::values::computed::{AlignItems, BorderStyle, LengthPercentage}; use style::values::generics::box_::Perspective; -use style::values::generics::length::MaxSize; use style::values::generics::position::{GenericAspectRatio, PreferredRatio}; use style::values::specified::align::AlignFlags; use style::values::specified::{box_ as stylo, Overflow}; @@ -32,7 +29,7 @@ use crate::dom_traversal::Contents; use crate::fragment_tree::FragmentFlags; use crate::geom::{ AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize, - PhysicalVec, + PhysicalVec, Size, }; use crate::{ContainingBlock, IndefiniteContainingBlock}; @@ -190,48 +187,72 @@ pub(crate) trait ComputedValuesExt { fn box_size( &self, containing_block_writing_mode: WritingMode, - ) -> LogicalVec2>; + ) -> LogicalVec2>; fn min_box_size( &self, containing_block_writing_mode: WritingMode, - ) -> LogicalVec2>; + ) -> LogicalVec2>; fn max_box_size( &self, containing_block_writing_mode: WritingMode, - ) -> LogicalVec2>; + ) -> LogicalVec2>; fn content_box_size( &self, containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, + ) -> LogicalVec2>; + fn content_box_size_deprecated( + &self, + containing_block: &ContainingBlock, + pbm: &PaddingBorderMargin, ) -> LogicalVec2; fn content_box_size_for_box_size( &self, - box_size: LogicalVec2, + box_size: LogicalVec2>, pbm: &PaddingBorderMargin, - ) -> LogicalVec2; + ) -> LogicalVec2>; fn content_min_box_size( &self, containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, + ) -> LogicalVec2>; + fn content_min_box_size_deprecated( + &self, + containing_block: &ContainingBlock, + pbm: &PaddingBorderMargin, ) -> LogicalVec2; fn content_min_box_size_for_min_size( &self, - box_size: LogicalVec2, + box_size: LogicalVec2>, pbm: &PaddingBorderMargin, - ) -> LogicalVec2; + ) -> LogicalVec2>; fn content_max_box_size( &self, containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, + ) -> LogicalVec2>; + fn content_max_box_size_deprecated( + &self, + containing_block: &ContainingBlock, + pbm: &PaddingBorderMargin, ) -> LogicalVec2>; fn content_max_box_size_for_max_size( &self, - box_size: LogicalVec2>, + box_size: LogicalVec2>, pbm: &PaddingBorderMargin, - ) -> LogicalVec2>; + ) -> LogicalVec2>; fn content_box_sizes_and_padding_border_margin( &self, containing_block: &IndefiniteContainingBlock, + ) -> ( + LogicalVec2>, + LogicalVec2>, + LogicalVec2>, + PaddingBorderMargin, + ); + fn content_box_sizes_and_padding_border_margin_deprecated( + &self, + containing_block: &IndefiniteContainingBlock, ) -> ( LogicalVec2, LogicalVec2, @@ -309,12 +330,12 @@ impl ComputedValuesExt for ComputedValues { fn box_size( &self, containing_block_writing_mode: WritingMode, - ) -> LogicalVec2> { + ) -> LogicalVec2> { let position = self.get_position(); LogicalVec2::from_physical_size( &PhysicalSize::new( - size_to_length(&position.width), - size_to_length(&position.height), + position.clone_width().into(), + position.clone_height().into(), ), containing_block_writing_mode, ) @@ -323,12 +344,12 @@ impl ComputedValuesExt for ComputedValues { fn min_box_size( &self, containing_block_writing_mode: WritingMode, - ) -> LogicalVec2> { + ) -> LogicalVec2> { let position = self.get_position(); LogicalVec2::from_physical_size( &PhysicalSize::new( - size_to_length(&position.min_width), - size_to_length(&position.min_height), + position.clone_min_width().into(), + position.clone_min_height().into(), ), containing_block_writing_mode, ) @@ -337,20 +358,13 @@ impl ComputedValuesExt for ComputedValues { fn max_box_size( &self, containing_block_writing_mode: WritingMode, - ) -> LogicalVec2> { - fn unwrap(max_size: &MaxSize) -> Option<&LengthPercentage> { - match max_size { - MaxSize::LengthPercentage(length) => Some(&length.0), - MaxSize::None | - MaxSize::MinContent | - MaxSize::MaxContent | - MaxSize::FitContent | - MaxSize::Stretch => None, - } - } + ) -> LogicalVec2> { let position = self.get_position(); LogicalVec2::from_physical_size( - &PhysicalSize::new(unwrap(&position.max_width), unwrap(&position.max_height)), + &PhysicalSize::new( + position.clone_max_width().into(), + position.clone_max_height().into(), + ), containing_block_writing_mode, ) } @@ -359,18 +373,27 @@ impl ComputedValuesExt for ComputedValues { &self, containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, - ) -> LogicalVec2 { + ) -> LogicalVec2> { let box_size = self .box_size(containing_block.style.writing_mode) .percentages_relative_to(containing_block); self.content_box_size_for_box_size(box_size, pbm) } - fn content_box_size_for_box_size( + fn content_box_size_deprecated( &self, - box_size: LogicalVec2, + containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, ) -> LogicalVec2 { + self.content_box_size(containing_block, pbm) + .map(Size::to_auto_or) + } + + fn content_box_size_for_box_size( + &self, + box_size: LogicalVec2>, + pbm: &PaddingBorderMargin, + ) -> LogicalVec2> { match self.get_position().box_sizing { BoxSizing::ContentBox => box_size, BoxSizing::BorderBox => LogicalVec2 { @@ -390,18 +413,27 @@ impl ComputedValuesExt for ComputedValues { &self, containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, - ) -> LogicalVec2 { + ) -> LogicalVec2> { let box_size = self .min_box_size(containing_block.style.writing_mode) .percentages_relative_to(containing_block); self.content_min_box_size_for_min_size(box_size, pbm) } - fn content_min_box_size_for_min_size( + fn content_min_box_size_deprecated( &self, - min_box_size: LogicalVec2, + containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, ) -> LogicalVec2 { + self.content_min_box_size(containing_block, pbm) + .map(Size::to_auto_or) + } + + fn content_min_box_size_for_min_size( + &self, + min_box_size: LogicalVec2>, + pbm: &PaddingBorderMargin, + ) -> LogicalVec2> { match self.get_position().box_sizing { BoxSizing::ContentBox => min_box_size, BoxSizing::BorderBox => LogicalVec2 { @@ -420,7 +452,7 @@ impl ComputedValuesExt for ComputedValues { &self, containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, - ) -> LogicalVec2> { + ) -> LogicalVec2> { let max_box_size = self .max_box_size(containing_block.style.writing_mode) .percentages_relative_to(containing_block); @@ -428,11 +460,20 @@ impl ComputedValuesExt for ComputedValues { self.content_max_box_size_for_max_size(max_box_size, pbm) } - fn content_max_box_size_for_max_size( + fn content_max_box_size_deprecated( &self, - max_box_size: LogicalVec2>, + containing_block: &ContainingBlock, pbm: &PaddingBorderMargin, ) -> LogicalVec2> { + self.content_max_box_size(containing_block, pbm) + .map(Size::to_numeric) + } + + fn content_max_box_size_for_max_size( + &self, + max_box_size: LogicalVec2>, + pbm: &PaddingBorderMargin, + ) -> LogicalVec2> { match self.get_position().box_sizing { BoxSizing::ContentBox => max_box_size, BoxSizing::BorderBox => { @@ -454,9 +495,9 @@ impl ComputedValuesExt for ComputedValues { &self, containing_block: &IndefiniteContainingBlock, ) -> ( - LogicalVec2, - LogicalVec2, - LogicalVec2>, + LogicalVec2>, + LogicalVec2>, + LogicalVec2>, PaddingBorderMargin, ) { // @@ -493,6 +534,25 @@ impl ComputedValuesExt for ComputedValues { (content_box_size, content_min_size, content_max_size, pbm) } + fn content_box_sizes_and_padding_border_margin_deprecated( + &self, + containing_block: &IndefiniteContainingBlock, + ) -> ( + LogicalVec2, + LogicalVec2, + LogicalVec2>, + PaddingBorderMargin, + ) { + let (content_box_size, content_min_size, content_max_size, pbm) = + self.content_box_sizes_and_padding_border_margin(containing_block); + ( + content_box_size.map(Size::to_auto_or), + content_min_size.map(Size::to_auto_or), + content_max_size.map(Size::to_numeric), + pbm, + ) + } + fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin { self.padding_border_margin_with_writing_mode_and_containing_block_inline_size( containing_block.style.writing_mode, @@ -998,15 +1058,6 @@ impl From for Display { } } -fn size_to_length(size: &Size) -> LengthPercentageOrAuto { - match size { - Size::LengthPercentage(length) => LengthPercentageOrAuto::LengthPercentage(&length.0), - Size::Auto | Size::MinContent | Size::MaxContent | Size::FitContent | Size::Stretch => { - LengthPercentageOrAuto::Auto - }, - } -} - pub(crate) trait Clamp: Sized { fn clamp_below_max(self, max: Option) -> Self; fn clamp_between_extremums(self, min: Self, max: Option) -> Self; diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 14b6d5f54b6..143ab82db2b 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -33,8 +33,8 @@ use crate::fragment_tree::{ PositioningFragment, }; use crate::geom::{ - AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, - PhysicalRect, PhysicalSides, ToLogical, ToLogicalWithContainingBlock, + AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, + Size, SizeKeyword, ToLogical, ToLogicalWithContainingBlock, }; use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength}; use crate::sizing::ContentSizes; @@ -245,9 +245,15 @@ 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 && - !self.table.style.box_size(writing_mode).inline.is_auto(); + !matches!( + self.table.style.box_size(writing_mode).inline, + Size::Keyword(SizeKeyword::Initial | SizeKeyword::MaxContent) + ); let row_measures = vec![LogicalVec2::zero(); self.table.size.width]; self.cell_measures = vec![row_measures; self.table.size.height]; @@ -369,8 +375,8 @@ impl<'a> TableLayout<'a> { self.rows = vec![RowLayout::default(); self.table.size.height]; self.columns = vec![ColumnLayout::default(); self.table.size.width]; - let is_length = |size: &LengthPercentageOrAuto| { - size.non_auto().is_some_and(|size| !size.has_percentage()) + let is_length = |size: &Size| { + size.to_numeric().is_some_and(|size| !size.has_percentage()) }; for column_index in 0..self.table.size.width { @@ -837,13 +843,13 @@ impl<'a> TableLayout<'a> { // This diverges a little from the specification, but should be equivalent // (other than using the stretch-fit size instead of the containing block width). let used_width_of_table = match style - .content_box_size(containing_block_for_table, &self.pbm) + .content_box_size_deprecated(containing_block_for_table, &self.pbm) .inline { LengthPercentage(_) => resolved_table_width.max(grid_min_max.min_content), Auto => { let min_width: Au = style - .content_min_box_size(containing_block_for_table, &self.pbm) + .content_min_box_size_deprecated(containing_block_for_table, &self.pbm) .inline .auto_is(Au::zero); resolved_table_width @@ -1587,12 +1593,12 @@ impl<'a> TableLayout<'a> { // the resulting length, properly clamped between min-block-size and max-block-size. let style = &self.table.style; let table_height_from_style = match style - .content_box_size(containing_block_for_table, &self.pbm) + .content_box_size_deprecated(containing_block_for_table, &self.pbm) .block { LengthPercentage(_) => containing_block_for_children.block_size, Auto => style - .content_min_box_size(containing_block_for_table, &self.pbm) + .content_min_box_size_deprecated(containing_block_for_table, &self.pbm) .block .map(Au::from), } @@ -2711,7 +2717,7 @@ impl Table { .style .box_size(writing_mode) .block - .non_auto() + .to_numeric() .and_then(|size| size.to_length()) .map_or_else(Au::zero, Au::from); let percentage_contribution = @@ -2841,12 +2847,13 @@ fn get_size_percentage_contribution_from_style( let max_size = style.max_box_size(writing_mode); let get_contribution_for_axis = - |size: LengthPercentageOrAuto<'_>, max_size: Option<&ComputedLengthPercentage>| { + |size: Size, max_size: Size| { let size_percentage = size - .non_auto() + .to_numeric() .and_then(|length_percentage| length_percentage.to_percentage()) .unwrap_or(Percentage(0.)); let max_size_percentage = max_size + .to_numeric() .and_then(|length_percentage| length_percentage.to_percentage()) .unwrap_or(Percentage(f32::INFINITY)); Percentage(size_percentage.0.min(max_size_percentage.0)) @@ -2871,22 +2878,22 @@ fn get_outer_sizes_from_style( block: size.block.max(padding_border_sums.block), }, }; - let get_size_for_axis = |size: &LengthPercentageOrAuto<'_>| { - size.non_auto() - .and_then(|size| size.to_length()) - .map_or_else(Au::zero, Au::from) - }; - let get_max_size_for_axis = |size: &Option<&ComputedLengthPercentage>| { - size.and_then(|length_percentage| length_percentage.to_length()) - .map_or(MAX_AU, Au::from) + let get_size_for_axis = |size: &Size| { + // TODO(#32853): This treats all sizing keywords as `auto`. + size.to_numeric() + .and_then(|length_percentage| length_percentage.to_length()) + .map(Au::from) }; let size = style.box_size(writing_mode); + let min_size = style.min_box_size(writing_mode); + let max_size = style.max_box_size(writing_mode); ( - outer_size(size.map(get_size_for_axis)), - outer_size(style.min_box_size(writing_mode).map(get_size_for_axis)), - outer_size(style.max_box_size(writing_mode).map(get_max_size_for_axis)), - size.inline.is_auto(), + outer_size(size.map(|v| get_size_for_axis(v).unwrap_or(Au(0)))), + outer_size(min_size.map(|v| get_size_for_axis(v).unwrap_or(Au(0)))), + outer_size(max_size.map(|v| get_size_for_axis(v).unwrap_or(MAX_AU))), + // TODO(#32853): This treats all sizing keywords as `auto`. + size.inline.is_keyword(), ) } diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index 5d809dda394..6f46349cb4e 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -565151,7 +565151,7 @@ ] ], "fixed-layout-2.html": [ - "dcbabb1ff7460ce563c3f127b9215e7b1211434b", + "3b7f65feccf578e7ead60186bf48517d750428be", [ null, {} diff --git a/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution-fixed.html.ini b/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution-fixed.html.ini index 5785f7d52c7..b0b62481a73 100644 --- a/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution-fixed.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution-fixed.html.ini @@ -1,7 +1,4 @@ [table-width-redistribution-fixed.html] - [table 3] - expected: FAIL - [table 15] expected: FAIL diff --git a/tests/wpt/tests/css/css-tables/fixed-layout-2.html b/tests/wpt/tests/css/css-tables/fixed-layout-2.html index dcbabb1ff74..3b7f65feccf 100644 --- a/tests/wpt/tests/css/css-tables/fixed-layout-2.html +++ b/tests/wpt/tests/css/css-tables/fixed-layout-2.html @@ -1,84 +1,116 @@ - - - - + +table-layout:fixed with various widths + -
+ + -

Fixed Layout

-

Checks whether fixed layout is implemented properly (width is not definite)

- -
-

This should be a 100px-wide blue square:

-

Table-layout:fixed does not apply to width:auto tables

- - -
- -
-
- -
-

This should be a 100px-wide blue square:

-

Table-layout:fixed does not apply to width:max-content tables

- - -
- -
-
- -
-

This should be a 100px-wide blue square:

-

Table-layout:fixed does apply to width:min-content/fit-content tables

- - -
- -
-
- - -
-
-
-
+ +
+

Fixed Layout

+

Checks whether fixed layout is implemented properly

+ + + +