diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index 9fd038b2be4..8501398b5d4 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -42,7 +42,8 @@ use crate::sizing::{ ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, IntrinsicSizingMode, }; use crate::style_ext::{ - AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin, + AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, LayoutStyle, + PaddingBorderMargin, }; use crate::{ ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock, @@ -1052,7 +1053,7 @@ impl FlexContainer { containing_block_for_container: &ContainingBlock, ) -> (FlexRelativeVec2, FlexRelativeVec2>, bool) { let sizes: ContentBoxSizesAndPBMDeprecated = self - .style + .layout_style() .content_box_sizes_and_padding_border_margin(&containing_block_for_container.into()) .into(); @@ -1071,6 +1072,11 @@ impl FlexContainer { sizes.depends_on_block_constraints, ) } + + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Default(&self.style) + } } /// Align all flex lines per `align-content` according to @@ -1141,7 +1147,8 @@ impl<'a> FlexItem<'a> { pbm, depends_on_block_constraints, } = box_ - .style() + .independent_formatting_context + .layout_style() .content_box_sizes_and_padding_border_margin(&containing_block.into()) .into(); @@ -2281,7 +2288,9 @@ impl FlexItemBox { content_max_box_size, pbm, .. - } = style + } = self + .independent_formatting_context + .layout_style() .content_box_sizes_and_padding_border_margin(containing_block) .into(); let preferred_aspect_ratio = self diff --git a/components/layout_2020/flow/inline/inline_box.rs b/components/layout_2020/flow/inline/inline_box.rs index 2bb5a92d2b0..74bedba891b 100644 --- a/components/layout_2020/flow/inline/inline_box.rs +++ b/components/layout_2020/flow/inline/inline_box.rs @@ -15,7 +15,7 @@ use crate::context::LayoutContext; use crate::dom::NodeExt; use crate::dom_traversal::NodeAndStyleInfo; use crate::fragment_tree::BaseFragmentInfo; -use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; +use crate::style_ext::{LayoutStyle, PaddingBorderMargin}; use crate::ContainingBlock; #[derive(Debug)] @@ -52,6 +52,11 @@ impl InlineBox { ..*self } } + + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Default(&self.style) + } } #[derive(Debug, Default)] @@ -214,7 +219,9 @@ impl InlineBoxContainerState { font_metrics: Option<&FontMetrics>, ) -> Self { let style = inline_box.style.clone(); - let pbm = style.padding_border_margin(containing_block); + let pbm = inline_box + .layout_style() + .padding_border_margin(containing_block); let mut flags = InlineContainerStateFlags::empty(); if inline_container_needs_strut(&style, layout_context, Some(&pbm)) { diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index 4b138bfbd14..c366a8d72c6 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -2244,11 +2244,11 @@ impl<'layout_data> ContentSizesComputation<'layout_data> { let inline_box = inline_box.borrow(); let zero = Au::zero(); let writing_mode = self.constraint_space.writing_mode; - let padding = inline_box - .style + let layout_style = inline_box.layout_style(); + let padding = layout_style .padding(writing_mode) .percentages_relative_to(zero); - let border = inline_box.style.border_width(writing_mode); + let border = layout_style.border_width(writing_mode); let margin = inline_box .style .margin(writing_mode) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 06f9da7d326..19c34e1456b 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -38,7 +38,7 @@ use crate::layout_box_base::LayoutBoxBase; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::replaced::ReplacedContents; use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; -use crate::style_ext::{ComputedValuesExt, ContentBoxSizesAndPBM, PaddingBorderMargin}; +use crate::style_ext::{ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin}; use crate::{ ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock, SizeConstraint, @@ -105,19 +105,22 @@ impl BlockLevelBox { collected_margin: &mut CollapsedMargin, containing_block: &ContainingBlock, ) -> bool { - let style = match self { - BlockLevelBox::SameFormattingContextBlock { base, .. } => &base.style, + let layout_style = match self { + BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => { + contents.layout_style(base) + }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | BlockLevelBox::OutOfFlowFloatBox(_) => return true, BlockLevelBox::OutsideMarker(_) => return false, BlockLevelBox::Independent(ref context) => { // FIXME: If the element doesn't fit next to floats, it will get clearance. // In that case this should be returning false. - context.style() + context.layout_style() }, }; // FIXME: This should only return false when 'clear' causes clearance. + let style = layout_style.style(); if style.get_box().clear != StyleClear::None { return false; } @@ -126,7 +129,7 @@ impl BlockLevelBox { content_box_sizes, pbm, .. - } = style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into()); let margin = pbm.margin.auto_is(Au::zero); collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_start)); @@ -310,9 +313,11 @@ impl OutsideMarker { // TODO: This is the wrong containing block, as it should be the containing block of the // parent of this list item. What this means in practice is that the writing mode could be // wrong and padding defined as a percentage will be resolved incorrectly. - let pbm_of_list_item = self - .list_item_style() - .padding_border_margin(containing_block); + // + // TODO: This should use the LayoutStyle of the list item, not the default one. Currently + // they are the same, but this could change in the future. + let pbm_of_list_item = + LayoutStyle::Default(self.list_item_style()).padding_border_margin(containing_block); let content_rect = LogicalRect { start_corner: LogicalVec2 { inline: -max_inline_size - @@ -387,6 +392,11 @@ impl BlockFormattingContext { detailed_layout_info: None, } } + + #[inline] + pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> { + LayoutStyle::Default(&base.style) + } } /// Finds the min/max-content inline size of the block-level children of a block container. @@ -425,7 +435,7 @@ fn compute_inline_content_sizes_for_block_level_boxes( }, BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => { let inline_content_sizes_result = sizing::outer_inline( - &base.style, + &contents.layout_style(base), containing_block, &LogicalVec2::zero(), false, /* auto_block_size_stretches_to_containing_block */ @@ -568,6 +578,11 @@ impl BlockContainer { ), } } + + #[inline] + pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> { + LayoutStyle::Default(&base.style) + } } impl ComputeInlineContentSizes for BlockContainer { @@ -824,6 +839,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( collapsible_with_parent_start_margin: Option, ) -> BoxFragment { let style = &base.style; + let layout_style = contents.layout_style(base); let containing_block_writing_mode = containing_block.style.writing_mode; let get_inline_content_sizes = |constraint_space: &ConstraintSpace| { base.inline_content_sizes(layout_context, constraint_space, contents) @@ -837,7 +853,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( available_block_size, } = solve_containing_block_padding_and_border_for_in_flow_box( containing_block, - style, + &layout_style, get_inline_content_sizes, false, /* is_table */ ); @@ -1071,6 +1087,7 @@ impl IndependentNonReplacedContents { base.inline_content_sizes(layout_context, constraint_space, self) .sizes }; + let layout_style = self.layout_style(base); let ContainingBlockPaddingAndBorder { containing_block: containing_block_for_children, pbm, @@ -1079,7 +1096,7 @@ impl IndependentNonReplacedContents { available_block_size, } = solve_containing_block_padding_and_border_for_in_flow_box( containing_block, - &base.style, + &layout_style, get_inline_content_sizes, self.is_table(), ); @@ -1163,7 +1180,9 @@ impl IndependentNonReplacedContents { content_box_sizes, pbm, depends_on_block_constraints, - } = style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + } = self + .layout_style(base) + .content_box_sizes_and_padding_border_margin(&containing_block.into()); let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(&pbm); @@ -1468,8 +1487,8 @@ impl ReplacedContents { containing_block: &ContainingBlock, mut sequential_layout_state: Option<&mut SequentialLayoutState>, ) -> BoxFragment { - let content_box_sizes_and_pbm = base - .style + let content_box_sizes_and_pbm = self + .layout_style(base) .content_box_sizes_and_padding_border_margin(&containing_block.into()); let pbm = &content_box_sizes_and_pbm.pbm; let content_size = self.used_size_as_if_inline_element( @@ -1618,10 +1637,11 @@ struct ResolvedMargins { /// inline size could then be incorrect. fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( containing_block: &ContainingBlock<'_>, - style: &'a Arc, + layout_style: &'a LayoutStyle, get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes, is_table: bool, ) -> ContainingBlockPaddingAndBorder<'a> { + let style = layout_style.style(); if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) { // // > Anonymous block boxes are ignored when resolving percentage values that would @@ -1650,7 +1670,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( content_box_sizes, pbm, depends_on_block_constraints, - } = style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into()); let margin = pbm.margin.auto_is(Au::zero); let pbm_sums = pbm.padding + pbm.border + margin; @@ -2140,8 +2160,9 @@ impl IndependentFormattingContext { ) -> IndependentLayoutResult { let style = self.style(); let container_writing_mode = containing_block.style.writing_mode; - let content_box_sizes_and_pbm = - style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + let content_box_sizes_and_pbm = self + .layout_style() + .content_box_sizes_and_padding_border_margin(&containing_block.into()); let pbm = &content_box_sizes_and_pbm.pbm; let margin = pbm.margin.auto_is(Au::zero); let pbm_sums = pbm.padding + pbm.border + margin; diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 8c0a5987956..4d1a17cc5c3 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -21,7 +21,7 @@ use crate::layout_box_base::LayoutBoxBase; use crate::positioned::PositioningContext; use crate::replaced::ReplacedContents; use crate::sizing::{self, ComputeInlineContentSizes, InlineContentSizesResult}; -use crate::style_ext::{AspectRatio, DisplayInside}; +use crate::style_ext::{AspectRatio, DisplayInside, LayoutStyle}; use crate::table::Table; use crate::taffy::TaffyContainer; use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2}; @@ -217,7 +217,7 @@ impl IndependentFormattingContext { auto_block_size_stretches_to_containing_block: bool, ) -> InlineContentSizesResult { sizing::outer_inline( - self.style(), + &self.layout_style(), containing_block, auto_minimum, auto_block_size_stretches_to_containing_block, @@ -242,6 +242,18 @@ impl IndependentFormattingContext { }, } } + + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + match &self.contents { + IndependentFormattingContextContents::NonReplaced(content) => { + content.layout_style(&self.base) + }, + IndependentFormattingContextContents::Replaced(content) => { + content.layout_style(&self.base) + }, + } + } } impl IndependentNonReplacedContents { @@ -279,6 +291,16 @@ impl IndependentNonReplacedContents { } } + #[inline] + pub(crate) fn layout_style<'a>(&'a self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> { + match self { + IndependentNonReplacedContents::Flow(fc) => fc.layout_style(base), + IndependentNonReplacedContents::Flex(fc) => fc.layout_style(), + IndependentNonReplacedContents::Grid(fc) => fc.layout_style(), + IndependentNonReplacedContents::Table(fc) => fc.layout_style(), + } + } + #[inline] pub(crate) fn preferred_aspect_ratio(&self) -> Option { // TODO: support preferred aspect ratios on non-replaced boxes. diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 93cb9482500..379fe920b1a 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -467,7 +467,9 @@ impl HoistedAbsolutelyPositionedBox { content_box_sizes, pbm, .. - } = style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + } = context + .layout_style() + .content_box_sizes_and_padding_border_margin(&containing_block.into()); let containing_block = &containing_block.into(); let is_table = context.is_table(); diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index 3b0509ba8e3..fe45344fcab 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -31,8 +31,9 @@ use crate::context::LayoutContext; use crate::dom::NodeExt; use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment}; use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size, Sizes}; +use crate::layout_box_base::LayoutBoxBase; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; -use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM}; +use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle}; use crate::{ConstraintSpace, ContainingBlock, SizeConstraint}; #[derive(Debug)] @@ -567,6 +568,11 @@ impl ReplacedContents { block: block_size, } } + + #[inline] + pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> { + LayoutStyle::Default(&base.style) + } } impl ComputeInlineContentSizes for ReplacedContents { diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index e363279540c..72cd9c60a4b 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -8,13 +8,12 @@ use std::cell::LazyCell; use std::ops::{Add, AddAssign}; use app_units::Au; -use style::properties::ComputedValues; use style::values::computed::LengthPercentage; use style::Zero; use crate::context::LayoutContext; use crate::geom::Size; -use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM}; +use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle}; use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2}; #[derive(PartialEq)] @@ -111,7 +110,7 @@ impl From for ContentSizes { #[allow(clippy::too_many_arguments)] pub(crate) fn outer_inline( - style: &ComputedValues, + layout_style: &LayoutStyle, containing_block: &IndefiniteContainingBlock, auto_minimum: &LogicalVec2, auto_block_size_stretches_to_containing_block: bool, @@ -125,12 +124,13 @@ pub(crate) fn outer_inline( content_box_sizes, pbm, mut depends_on_block_constraints, - } = style.content_box_sizes_and_padding_border_margin(containing_block); + } = layout_style.content_box_sizes_and_padding_border_margin(containing_block); let margin = pbm.margin.map(|v| v.auto_is(Au::zero)); let pbm_sums = LogicalVec2 { block: pbm.padding_border_sums.block + margin.block_sum(), inline: pbm.padding_border_sums.inline + margin.inline_sum(), }; + let style = layout_style.style(); let content_size = LazyCell::new(|| { let constraint_space = if establishes_containing_block { let available_block_size = containing_block diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index ec3befaaec3..b38ace1ee74 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -278,23 +278,10 @@ pub(crate) trait ComputedValuesExt { box_size: LogicalVec2>, pbm: &PaddingBorderMargin, ) -> LogicalVec2>; - fn content_box_sizes_and_padding_border_margin( - &self, - containing_block: &IndefiniteContainingBlock, - ) -> ContentBoxSizesAndPBM; - fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin; - fn padding_border_margin_with_writing_mode_and_containing_block_inline_size( - &self, - writing_mode: WritingMode, - containing_block_inline_size: Au, - ) -> PaddingBorderMargin; - fn padding(&self, containing_block_writing_mode: WritingMode) - -> LogicalSides; fn border_style_color( &self, containing_block_writing_mode: WritingMode, ) -> LogicalSides; - fn border_width(&self, containing_block_writing_mode: WritingMode) -> LogicalSides; fn physical_margin(&self) -> PhysicalSides>; fn margin( &self, @@ -445,129 +432,6 @@ impl ComputedValuesExt for ComputedValues { } } - fn content_box_sizes_and_padding_border_margin( - &self, - containing_block: &IndefiniteContainingBlock, - ) -> ContentBoxSizesAndPBM { - // - // If max size properties or preferred size properties are set to a value containing - // indefinite percentages, we treat the entire value as the initial value of the property. - // However, for min size properties, as well as for margins and paddings, - // we instead resolve indefinite percentages against zero. - let containing_block_size = containing_block.size.map(|value| value.non_auto()); - let containing_block_size_auto_is_zero = - containing_block_size.map(|value| value.unwrap_or_else(Au::zero)); - let writing_mode = containing_block.writing_mode; - let pbm = self.padding_border_margin_with_writing_mode_and_containing_block_inline_size( - writing_mode, - containing_block.size.inline.auto_is(Au::zero), - ); - let box_size = self.box_size(writing_mode); - let min_size = self.min_box_size(writing_mode); - let max_size = self.max_box_size(writing_mode); - let depends_on_block_constraints = |size: &Size| { - match size { - // fit-content is like clamp(min-content, stretch, max-content), but currently - // min-content and max-content have the same behavior in the block axis, - // so there is no dependency on block constraints. - // TODO: for flex and grid layout, min-content and max-content should be different. - // TODO: We are assuming that Size::Initial doesn't stretch. However, it may actually - // stretch flex and grid items depending on the CSS Align properties, in that case - // the caller needs to take care of it. - Size::Stretch => true, - Size::Numeric(length_percentage) => length_percentage.has_percentage(), - _ => false, - } - }; - - let depends_on_block_constraints = depends_on_block_constraints(&box_size.block) || - depends_on_block_constraints(&min_size.block) || - depends_on_block_constraints(&max_size.block) || - self.depends_on_block_constraints_due_to_relative_positioning(writing_mode); - - let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block_size); - let content_box_size = self - .content_box_size_for_box_size(box_size, &pbm) - .map(|v| v.map(Au::from)); - let min_size = min_size.percentages_relative_to_basis(&containing_block_size_auto_is_zero); - let content_min_box_size = self - .content_min_box_size_for_min_size(min_size, &pbm) - .map(|v| v.map(Au::from)); - let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block_size); - let content_max_box_size = self - .content_max_box_size_for_max_size(max_size, &pbm) - .map(|v| v.map(Au::from)); - ContentBoxSizesAndPBM { - content_box_sizes: LogicalVec2 { - block: Sizes::new( - content_box_size.block, - content_min_box_size.block, - content_max_box_size.block, - ), - inline: Sizes::new( - content_box_size.inline, - content_min_box_size.inline, - content_max_box_size.inline, - ), - }, - pbm, - depends_on_block_constraints, - } - } - - 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, - containing_block.size.inline, - ) - } - - fn padding_border_margin_with_writing_mode_and_containing_block_inline_size( - &self, - writing_mode: WritingMode, - containing_block_inline_size: Au, - ) -> PaddingBorderMargin { - let padding = self - .padding(writing_mode) - .percentages_relative_to(containing_block_inline_size); - let border = self.border_width(writing_mode); - let margin = self - .margin(writing_mode) - .percentages_relative_to(containing_block_inline_size); - PaddingBorderMargin { - padding_border_sums: LogicalVec2 { - inline: padding.inline_sum() + border.inline_sum(), - block: padding.block_sum() + border.block_sum(), - }, - padding, - border, - margin, - } - } - - fn padding( - &self, - containing_block_writing_mode: WritingMode, - ) -> LogicalSides { - if self.get_box().display.inside() == stylo::DisplayInside::Table && - self.get_inherited_table().border_collapse == BorderCollapse::Collapse - { - // https://drafts.csswg.org/css-tables/#collapsed-style-overrides - // > The padding of the table-root is ignored (as if it was set to 0px). - return LogicalSides::zero(); - } - let padding = self.get_padding().clone(); - LogicalSides::from_physical( - &PhysicalSides::new( - padding.padding_top.0, - padding.padding_right.0, - padding.padding_bottom.0, - padding.padding_left.0, - ), - containing_block_writing_mode, - ) - } - fn border_style_color( &self, containing_block_writing_mode: WritingMode, @@ -578,36 +442,6 @@ impl ComputedValuesExt for ComputedValues { ) } - fn border_width(&self, containing_block_writing_mode: WritingMode) -> LogicalSides { - let border = self.get_border(); - if self.get_box().display.inside() == stylo::DisplayInside::Table && - !matches!(self.pseudo(), Some(PseudoElement::ServoTableGrid)) && - self.get_inherited_table().border_collapse == BorderCollapse::Collapse - { - // For tables in collapsed-borders mode we halve the border widths, because - // > in this model, the width of the table includes half the table border. - // https://www.w3.org/TR/CSS22/tables.html#collapsing-borders - return LogicalSides::from_physical( - &PhysicalSides::new( - border.border_top_width / 2, - border.border_right_width / 2, - border.border_bottom_width / 2, - border.border_left_width / 2, - ), - containing_block_writing_mode, - ); - } - LogicalSides::from_physical( - &PhysicalSides::new( - border.border_top_width, - border.border_right_width, - border.border_bottom_width, - border.border_left_width, - ), - containing_block_writing_mode, - ) - } - fn physical_margin(&self) -> PhysicalSides> { fn convert(inset: &Margin) -> LengthPercentageOrAuto<'_> { match inset { @@ -969,6 +803,183 @@ impl ComputedValuesExt for ComputedValues { } } +pub(crate) enum LayoutStyle<'a> { + Default(&'a ComputedValues), + Table(&'a ComputedValues), +} + +impl LayoutStyle<'_> { + #[inline] + pub(crate) fn style(&self) -> &ComputedValues { + match self { + Self::Default(style) => style, + Self::Table(style) => style, + } + } + + pub(crate) fn content_box_sizes_and_padding_border_margin( + &self, + containing_block: &IndefiniteContainingBlock, + ) -> ContentBoxSizesAndPBM { + // + // If max size properties or preferred size properties are set to a value containing + // indefinite percentages, we treat the entire value as the initial value of the property. + // However, for min size properties, as well as for margins and paddings, + // we instead resolve indefinite percentages against zero. + let containing_block_size = containing_block.size.map(|value| value.non_auto()); + let containing_block_size_auto_is_zero = + containing_block_size.map(|value| value.unwrap_or_else(Au::zero)); + let writing_mode = containing_block.writing_mode; + let pbm = self.padding_border_margin_with_writing_mode_and_containing_block_inline_size( + writing_mode, + containing_block.size.inline.auto_is(Au::zero), + ); + let style = self.style(); + let box_size = style.box_size(writing_mode); + let min_size = style.min_box_size(writing_mode); + let max_size = style.max_box_size(writing_mode); + let depends_on_block_constraints = |size: &Size| { + match size { + // fit-content is like clamp(min-content, stretch, max-content), but currently + // min-content and max-content have the same behavior in the block axis, + // so there is no dependency on block constraints. + // TODO: for flex and grid layout, min-content and max-content should be different. + // TODO: We are assuming that Size::Initial doesn't stretch. However, it may actually + // stretch flex and grid items depending on the CSS Align properties, in that case + // the caller needs to take care of it. + Size::Stretch => true, + Size::Numeric(length_percentage) => length_percentage.has_percentage(), + _ => false, + } + }; + + let depends_on_block_constraints = depends_on_block_constraints(&box_size.block) || + depends_on_block_constraints(&min_size.block) || + depends_on_block_constraints(&max_size.block) || + style.depends_on_block_constraints_due_to_relative_positioning(writing_mode); + + let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block_size); + let content_box_size = style + .content_box_size_for_box_size(box_size, &pbm) + .map(|v| v.map(Au::from)); + let min_size = min_size.percentages_relative_to_basis(&containing_block_size_auto_is_zero); + let content_min_box_size = style + .content_min_box_size_for_min_size(min_size, &pbm) + .map(|v| v.map(Au::from)); + let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block_size); + let content_max_box_size = style + .content_max_box_size_for_max_size(max_size, &pbm) + .map(|v| v.map(Au::from)); + ContentBoxSizesAndPBM { + content_box_sizes: LogicalVec2 { + block: Sizes::new( + content_box_size.block, + content_min_box_size.block, + content_max_box_size.block, + ), + inline: Sizes::new( + content_box_size.inline, + content_min_box_size.inline, + content_max_box_size.inline, + ), + }, + pbm, + depends_on_block_constraints, + } + } + + pub(crate) 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, + containing_block.size.inline, + ) + } + + pub(crate) fn padding_border_margin_with_writing_mode_and_containing_block_inline_size( + &self, + writing_mode: WritingMode, + containing_block_inline_size: Au, + ) -> PaddingBorderMargin { + let padding = self + .padding(writing_mode) + .percentages_relative_to(containing_block_inline_size); + let style = self.style(); + let border = self.border_width(writing_mode); + let margin = style + .margin(writing_mode) + .percentages_relative_to(containing_block_inline_size); + PaddingBorderMargin { + padding_border_sums: LogicalVec2 { + inline: padding.inline_sum() + border.inline_sum(), + block: padding.block_sum() + border.block_sum(), + }, + padding, + border, + margin, + } + } + + pub(crate) fn padding( + &self, + containing_block_writing_mode: WritingMode, + ) -> LogicalSides { + let style = self.style(); + if matches!(self, Self::Table(_)) && + style.get_inherited_table().border_collapse == BorderCollapse::Collapse + { + // https://drafts.csswg.org/css-tables/#collapsed-style-overrides + // > The padding of the table-root is ignored (as if it was set to 0px). + return LogicalSides::zero(); + } + let padding = self.style().get_padding().clone(); + LogicalSides::from_physical( + &PhysicalSides::new( + padding.padding_top.0, + padding.padding_right.0, + padding.padding_bottom.0, + padding.padding_left.0, + ), + containing_block_writing_mode, + ) + } + + pub(crate) fn border_width( + &self, + containing_block_writing_mode: WritingMode, + ) -> LogicalSides { + let style = self.style(); + let border = style.get_border(); + if matches!(self, Self::Table(_)) && + style.get_inherited_table().border_collapse == BorderCollapse::Collapse + { + // For tables in collapsed-borders mode we halve the border widths, because + // > in this model, the width of the table includes half the table border. + // https://www.w3.org/TR/CSS22/tables.html#collapsing-borders + return LogicalSides::from_physical( + &PhysicalSides::new( + border.border_top_width / 2, + border.border_right_width / 2, + border.border_bottom_width / 2, + border.border_left_width / 2, + ), + containing_block_writing_mode, + ); + } + LogicalSides::from_physical( + &PhysicalSides::new( + border.border_top_width, + border.border_right_width, + border.border_bottom_width, + border.border_left_width, + ), + containing_block_writing_mode, + ) + } +} + impl From for Display { fn from(packed: stylo::Display) -> Self { let outside = packed.outside(); diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 91af3d59447..531f7b8429d 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -38,7 +38,9 @@ use crate::geom::{ }; use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; -use crate::style_ext::{BorderStyleColor, Clamp, ComputedValuesExt, PaddingBorderMargin}; +use crate::style_ext::{ + BorderStyleColor, Clamp, ComputedValuesExt, LayoutStyle, PaddingBorderMargin, +}; use crate::table::{SpecificTableOrTableCellInfo, TableSlotCoordinates}; use crate::{ ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock, WritingMode, @@ -121,9 +123,12 @@ impl CollapsedBorder { Self { style_color, width } } - fn from_style(style: &ComputedValues, writing_mode: WritingMode) -> LogicalSides { - let border_style_color = style.border_style_color(writing_mode); - let border_width = style.border_width(writing_mode); + fn from_layout_style( + layout_style: &LayoutStyle, + writing_mode: WritingMode, + ) -> LogicalSides { + let border_style_color = layout_style.style().border_style_color(writing_mode); + let border_width = layout_style.border_width(writing_mode); LogicalSides { inline_start: Self::new(border_style_color.inline_start, border_width.inline_start), inline_end: Self::new(border_style_color.inline_end, border_width.inline_end), @@ -285,12 +290,10 @@ impl<'a> TableLayout<'a> { _ => continue, }; - let padding = cell - .base - .style + let layout_style = cell.layout_style(); + let padding = layout_style .padding(writing_mode) .percentages_relative_to(Au::zero()); - let border = self .get_collapsed_border_widths_for_area(LogicalSides { inline_start: column_index, @@ -298,7 +301,7 @@ impl<'a> TableLayout<'a> { block_start: row_index, block_end: row_index + cell.rowspan, }) - .unwrap_or_else(|| cell.base.style.border_width(writing_mode)); + .unwrap_or_else(|| layout_style.border_width(writing_mode)); let padding_border_sums = LogicalVec2 { inline: padding.inline_sum() + border.inline_sum(), @@ -1217,16 +1220,14 @@ impl<'a> TableLayout<'a> { self.get_collapsed_border_style_colors_for_area(area), self.table.style.writing_mode, ); + let layout_style = cell.layout_style(); let border = self .get_collapsed_border_widths_for_area(area) .unwrap_or_else(|| { - cell.base - .style + layout_style .border_width(containing_block_for_table.style.writing_mode) }); - let padding: LogicalSides = cell - .base - .style + let padding: LogicalSides = layout_style .padding(containing_block_for_table.style.writing_mode) .percentages_relative_to(self.basis_for_cell_padding_percentage); let inline_border_padding_sum = border.inline_sum() + padding.inline_sum(); @@ -1651,9 +1652,8 @@ impl<'a> TableLayout<'a> { containing_block_for_table: &ContainingBlock, ) -> IndependentLayout { let table_writing_mode = containing_block_for_children.style.writing_mode; - self.pbm = self - .table - .style + let layout_style = self.table.layout_style(); + self.pbm = layout_style .padding_border_margin_with_writing_mode_and_containing_block_inline_size( table_writing_mode, containing_block_for_table.size.inline, @@ -1690,9 +1690,7 @@ impl<'a> TableLayout<'a> { let offset_from_wrapper = -self.pbm.padding - self.pbm.border; let mut current_block_offset = offset_from_wrapper.block_start; - let depends_on_block_constraints = self - .table - .style + let depends_on_block_constraints = layout_style .content_box_sizes_and_padding_border_margin(&containing_block_for_table.into()) .depends_on_block_constraints; @@ -2234,8 +2232,8 @@ impl<'a> TableLayout<'a> { }; let mut apply_border = - |style: &ComputedValues, block: &Range, inline: &Range| { - let border = CollapsedBorder::from_style(style, writing_mode); + |layout_style: &LayoutStyle, block: &Range, inline: &Range| { + let border = CollapsedBorder::from_layout_style(layout_style, writing_mode); collapsed_borders.block[block.start].max_assign(&border.block_start, inline); collapsed_borders.block[block.end].max_assign(&border.block_end, inline); collapsed_borders.inline[inline.start].max_assign(&border.inline_start, block); @@ -2243,18 +2241,34 @@ impl<'a> TableLayout<'a> { }; let all_rows = 0..self.table.size.height; let all_columns = 0..self.table.size.width; - apply_border(&self.table.grid_style, &all_rows, &all_columns); + apply_border(&self.table.layout_style_for_grid(), &all_rows, &all_columns); for column_group in &self.table.column_groups { - apply_border(&column_group.style, &all_rows, &column_group.track_range); + apply_border( + &column_group.layout_style(), + &all_rows, + &column_group.track_range, + ); } for (column_index, column) in self.table.columns.iter().enumerate() { - apply_border(&column.style, &all_rows, &(column_index..column_index + 1)); + apply_border( + &column.layout_style(), + &all_rows, + &(column_index..column_index + 1), + ); } for row_group in &self.table.row_groups { - apply_border(&row_group.style, &row_group.track_range, &all_columns); + apply_border( + &row_group.layout_style(), + &row_group.track_range, + &all_columns, + ); } for (row_index, row) in self.table.rows.iter().enumerate() { - apply_border(&row.style, &(row_index..row_index + 1), &all_columns); + apply_border( + &row.layout_style(), + &(row_index..row_index + 1), + &all_columns, + ); } for row_index in 0..self.table.size.height { for column_index in 0..self.table.size.width { @@ -2264,7 +2278,7 @@ impl<'a> TableLayout<'a> { }; apply_border( - &cell.base.style, + &cell.layout_style(), &(row_index..row_index + cell.rowspan), &(column_index..column_index + cell.colspan), ); @@ -2752,9 +2766,9 @@ impl ComputeInlineContentSizes for Table { constraint_space: &ConstraintSpace, ) -> InlineContentSizesResult { let writing_mode = constraint_space.writing_mode; + let layout_style = self.layout_style(); let mut layout = TableLayout::new(self); - layout.pbm = self - .style + layout.pbm = layout_style .padding_border_margin_with_writing_mode_and_containing_block_inline_size( writing_mode, Au::zero(), @@ -2769,11 +2783,10 @@ impl ComputeInlineContentSizes for Table { // Padding and border should apply to the table grid, but they will be taken into // account when computing the inline content sizes of the table wrapper (our parent), so // this code removes their contribution from the inline content size of the caption. - let padding = self - .style + let padding = layout_style .padding(writing_mode) .percentages_relative_to(Au::zero()); - let border = self.style.border_width(writing_mode); + let border = layout_style.border_width(writing_mode); caption_minimum_inline_size -= padding.inline_sum() + border.inline_sum(); table_content_sizes .min_content @@ -2790,7 +2803,38 @@ impl ComputeInlineContentSizes for Table { } } +impl Table { + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Table(&self.style) + } + + #[inline] + pub(crate) fn layout_style_for_grid(&self) -> LayoutStyle { + LayoutStyle::Default(&self.grid_style) + } +} + +impl TableTrack { + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Default(&self.style) + } +} + +impl TableTrackGroup { + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Default(&self.style) + } +} + impl TableSlotCell { + #[inline] + fn layout_style(&self) -> LayoutStyle { + self.contents.layout_style(&self.base) + } + fn effective_vertical_align(&self) -> VerticalAlignKeyword { match self.base.style.clone_vertical_align() { VerticalAlign::Keyword(VerticalAlignKeyword::Top) => VerticalAlignKeyword::Top, diff --git a/components/layout_2020/taffy/layout.rs b/components/layout_2020/taffy/layout.rs index 3a29b2e6c3a..ffbbbb6633c 100644 --- a/components/layout_2020/taffy/layout.rs +++ b/components/layout_2020/taffy/layout.rs @@ -27,7 +27,7 @@ use crate::geom::{ }; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; -use crate::style_ext::ComputedValuesExt; +use crate::style_ext::LayoutStyle; use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize}; const DUMMY_NODE_ID: taffy::NodeId = taffy::NodeId::new(u64::MAX); @@ -136,7 +136,9 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { let style = independent_context.style(); // Adjust known_dimensions from border box to content box - let pbm = style.padding_border_margin(containing_block); + let pbm = independent_context + .layout_style() + .padding_border_margin(containing_block); let pb_sum = pbm.padding_border_sums.map(|v| v.to_f32_px()); let margin_sum = pbm.margin.auto_is(Au::zero).sum().map(|v| v.to_f32_px()); let content_box_inset = pb_sum + margin_sum; @@ -387,7 +389,8 @@ impl ComputeInlineContentSizes for TaffyContainer { _ => panic!("Servo is only configured to use Taffy for CSS Grid layout"), }; - let pb_sums = style + let pb_sums = self + .layout_style() .padding_border_margin(containing_block) .padding_border_sums; @@ -428,7 +431,7 @@ impl TaffyContainer { let container_style = &content_box_size_override.style; let align_items = container_style.clone_align_items(); let justify_items = container_style.clone_justify_items(); - let pbm = container_style.padding_border_margin(containing_block); + let pbm = self.layout_style().padding_border_margin(containing_block); let known_dimensions = taffy::Size { width: Some( @@ -625,4 +628,9 @@ impl TaffyContainer { detailed_layout_info: container_ctx.detailed_layout_info, } } + + #[inline] + pub(crate) fn layout_style(&self) -> LayoutStyle { + LayoutStyle::Default(&self.style) + } }