aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOriol Brufau <obrufau@igalia.com>2025-03-11 22:32:28 +0100
committerGitHub <noreply@github.com>2025-03-11 21:32:28 +0000
commit9858ec81f9aef6d9df5425d1852fce882071602c (patch)
tree84cb99722dfd4dd76e428a93ff873be49de7864b
parentf7ddac249b73527a96180442670f024517e107e2 (diff)
downloadservo-9858ec81f9aef6d9df5425d1852fce882071602c.tar.gz
servo-9858ec81f9aef6d9df5425d1852fce882071602c.zip
layout: Fix interaction of margin and stretch size on block-level boxes (#35904)
The CSSWG resolved that `block-size: stretch` on a block-level box stretches the margin box to fill the parent. However, if the parent doesn't have padding nor border, and doesn't establish an independent formatting context, then we assume that the margins will collapse. Therefore, we treat the margins as zero when resolving the stretch size, regardless of whether they will actually end up collapsing. https://github.com/w3c/csswg-drafts/issues/11044#issuecomment-2599101601 https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing Signed-off-by: Oriol Brufau <obrufau@igalia.com>
-rw-r--r--components/layout_2020/flow/mod.rs69
-rw-r--r--components/layout_2020/geom.rs42
-rw-r--r--components/layout_2020/positioned.rs42
-rw-r--r--components/layout_2020/replaced.rs7
-rw-r--r--components/layout_2020/style_ext.rs20
-rw-r--r--components/layout_2020/table/layout.rs10
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-002.html.ini3
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-003.html.ini2
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-004.html.ini21
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-005.html.ini9
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-006.html.ini2
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-007.html.ini30
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-008.html.ini240
-rw-r--r--tests/wpt/meta/css/css-sizing/stretch/block-height-010.html.ini2
14 files changed, 379 insertions, 120 deletions
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index cccce1ee3aa..0fb44aba158 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -32,8 +32,8 @@ use crate::fragment_tree::{
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
};
use crate::geom::{
- AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
- Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
+ AuOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
+ PhysicalSides, Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
};
use crate::layout_box_base::LayoutBoxBase;
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
@@ -278,12 +278,17 @@ impl OutsideMarker {
style: &self.marker_style,
};
+ // A ::marker can't have a stretch size (must be auto), so this doesn't matter.
+ // https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
+ let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
+
let flow_layout = self.block_container.layout(
layout_context,
positioning_context,
&containing_block_for_children,
sequential_layout_state,
collapsible_with_parent_start_margin.unwrap_or(CollapsibleWithParentStartMargin(false)),
+ ignore_block_margins_for_stretch,
);
let max_inline_size =
@@ -364,12 +369,18 @@ impl BlockFormattingContext {
None
};
+ // Since this is an independent formatting context, we don't ignore block margins when
+ // resolving a stretch block size of the children.
+ // https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
+ let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
+
let flow_layout = self.contents.layout(
layout_context,
positioning_context,
containing_block,
sequential_layout_state.as_mut(),
CollapsibleWithParentStartMargin(false),
+ ignore_block_margins_for_stretch,
);
debug_assert!(
!flow_layout
@@ -561,6 +572,7 @@ impl BlockContainer {
containing_block: &ContainingBlock,
sequential_layout_state: Option<&mut SequentialLayoutState>,
collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> FlowLayout {
match self {
BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
@@ -570,6 +582,7 @@ impl BlockContainer {
containing_block,
sequential_layout_state,
collapsible_with_parent_start_margin,
+ ignore_block_margins_for_stretch,
),
BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
layout_context,
@@ -613,6 +626,7 @@ fn layout_block_level_children(
containing_block: &ContainingBlock,
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> FlowLayout {
let mut placement_state =
PlacementState::new(collapsible_with_parent_start_margin, containing_block);
@@ -625,6 +639,7 @@ fn layout_block_level_children(
containing_block,
sequential_layout_state,
&mut placement_state,
+ ignore_block_margins_for_stretch,
),
None => layout_block_level_children_in_parallel(
layout_context,
@@ -632,6 +647,7 @@ fn layout_block_level_children(
child_boxes,
containing_block,
&mut placement_state,
+ ignore_block_margins_for_stretch,
),
};
@@ -659,6 +675,7 @@ fn layout_block_level_children_in_parallel(
child_boxes: &[ArcRefCell<BlockLevelBox>],
containing_block: &ContainingBlock,
placement_state: &mut PlacementState,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> Vec<Fragment> {
let collects_for_nearest_positioned_ancestor =
positioning_context.collects_for_nearest_positioned_ancestor();
@@ -676,6 +693,7 @@ fn layout_block_level_children_in_parallel(
containing_block,
/* sequential_layout_state = */ None,
/* collapsible_with_parent_start_margin = */ None,
+ ignore_block_margins_for_stretch,
);
(fragment, child_positioning_context)
})
@@ -702,6 +720,7 @@ fn layout_block_level_children_sequentially(
containing_block: &ContainingBlock,
sequential_layout_state: &mut SequentialLayoutState,
placement_state: &mut PlacementState,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> Vec<Fragment> {
// Because floats are involved, we do layout for this block formatting context in tree
// order without parallelism. This enables mutable access to a `SequentialLayoutState` that
@@ -718,6 +737,7 @@ fn layout_block_level_children_sequentially(
Some(CollapsibleWithParentStartMargin(
placement_state.next_in_flow_margin_collapses_with_parent_start_margin,
)),
+ ignore_block_margins_for_stretch,
);
placement_state
@@ -740,6 +760,7 @@ impl BlockLevelBox {
containing_block: &ContainingBlock,
sequential_layout_state: Option<&mut SequentialLayoutState>,
collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> Fragment {
match self {
BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => Fragment::Box(
@@ -756,6 +777,7 @@ impl BlockLevelBox {
contents,
sequential_layout_state,
collapsible_with_parent_start_margin,
+ ignore_block_margins_for_stretch,
)
},
)),
@@ -771,6 +793,7 @@ impl BlockLevelBox {
positioning_context,
containing_block,
sequential_layout_state,
+ ignore_block_margins_for_stretch,
)
},
),
@@ -842,6 +865,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
contents: &BlockContainer,
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> BoxFragment {
let style = &base.style;
let layout_style = contents.layout_style(base);
@@ -860,6 +884,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
containing_block,
&layout_style,
get_inline_content_sizes,
+ ignore_block_margins_for_stretch,
);
let ResolvedMargins {
margin,
@@ -951,12 +976,23 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
},
};
+ // https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
+ // > If this is a block axis size, and the element is in a Block Layout formatting context,
+ // > and the parent element does not have a block-start border or padding and is not an
+ // > independent formatting context, treat the element’s block-start margin as zero
+ // > for the purpose of calculating this size. Do the same for the block-end margin.
+ let ignore_block_margins_for_stretch = LogicalSides1D::new(
+ pbm.border.block_start.is_zero() && pbm.padding.block_start.is_zero(),
+ pbm.border.block_end.is_zero() && pbm.padding.block_end.is_zero(),
+ );
+
let flow_layout = contents.layout(
layout_context,
positioning_context,
&containing_block_for_children,
sequential_layout_state.as_deref_mut(),
CollapsibleWithParentStartMargin(start_margin_can_collapse_with_children),
+ ignore_block_margins_for_stretch,
);
let mut content_block_size: Au = flow_layout.content_block_size;
@@ -1078,6 +1114,7 @@ impl IndependentNonReplacedContents {
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
sequential_layout_state: Option<&mut SequentialLayoutState>,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> BoxFragment {
if let Some(sequential_layout_state) = sequential_layout_state {
return self.layout_in_flow_block_level_sequentially(
@@ -1086,6 +1123,7 @@ impl IndependentNonReplacedContents {
positioning_context,
containing_block,
sequential_layout_state,
+ ignore_block_margins_for_stretch,
);
}
@@ -1104,6 +1142,7 @@ impl IndependentNonReplacedContents {
containing_block,
&layout_style,
get_inline_content_sizes,
+ ignore_block_margins_for_stretch,
);
let layout = self.layout(
@@ -1177,6 +1216,7 @@ impl IndependentNonReplacedContents {
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock<'_>,
sequential_layout_state: &mut SequentialLayoutState,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> BoxFragment {
let style = &base.style;
let containing_block_writing_mode = containing_block.style.writing_mode;
@@ -1218,13 +1258,12 @@ impl IndependentNonReplacedContents {
});
// Then compute a tentative block size, only taking extrinsic values into account.
- let margin = pbm.margin.auto_is(Au::zero);
- let pbm_sums = pbm.padding + pbm.border + margin;
+ let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
let available_block_size = containing_block
.size
.block
.to_definite()
- .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
+ .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
let (preferred_block_size, min_block_size, max_block_size) = content_box_sizes
.block
.resolve_each_extrinsic(Size::FitContent, Au::zero(), available_block_size);
@@ -1478,6 +1517,7 @@ impl ReplacedContents {
layout_context: &LayoutContext,
containing_block: &ContainingBlock,
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> BoxFragment {
let content_box_sizes_and_pbm = self
.layout_style(base)
@@ -1487,6 +1527,7 @@ impl ReplacedContents {
containing_block,
&base.style,
&content_box_sizes_and_pbm,
+ ignore_block_margins_for_stretch,
);
let margin_inline_start;
@@ -1631,6 +1672,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
containing_block: &ContainingBlock<'_>,
layout_style: &'a LayoutStyle,
get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> ContainingBlockPaddingAndBorder<'a> {
let style = layout_style.style();
if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
@@ -1663,16 +1705,14 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
depends_on_block_constraints,
} = 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;
+ let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
let writing_mode = style.writing_mode;
- let available_inline_size =
- Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
+ let available_inline_size = Au::zero().max(containing_block.size.inline - pbm_sums.inline);
let available_block_size = containing_block
.size
.block
.to_definite()
- .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
+ .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
// https://drafts.csswg.org/css2/#the-height-property
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
@@ -2125,6 +2165,7 @@ impl IndependentFormattingContext {
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
sequential_layout_state: Option<&mut SequentialLayoutState>,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> BoxFragment {
match &self.contents {
IndependentFormattingContextContents::NonReplaced(contents) => contents
@@ -2134,6 +2175,7 @@ impl IndependentFormattingContext {
positioning_context,
containing_block,
sequential_layout_state,
+ ignore_block_margins_for_stretch,
),
IndependentFormattingContextContents::Replaced(contents) => contents
.layout_in_flow_block_level(
@@ -2141,6 +2183,7 @@ impl IndependentFormattingContext {
layout_context,
containing_block,
sequential_layout_state,
+ ignore_block_margins_for_stretch,
),
}
}
@@ -2161,6 +2204,11 @@ impl IndependentFormattingContext {
let (fragments, content_rect, baselines) = match &self.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
+ // Floats and atomic inlines can't collapse margins with their parent,
+ // so don't ignore block margins when resolving a stretch block size.
+ // https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
+ let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
+
// https://drafts.csswg.org/css2/visudet.html#float-replaced-width
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
let content_size = replaced
@@ -2168,6 +2216,7 @@ impl IndependentFormattingContext {
containing_block,
style,
&content_box_sizes_and_pbm,
+ ignore_block_margins_for_stretch,
)
.to_physical_size(container_writing_mode);
let fragments = replaced.make_fragments(layout_context, style, content_size);
diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs
index eeaf95c8c5d..6dd87b5e087 100644
--- a/components/layout_2020/geom.rs
+++ b/components/layout_2020/geom.rs
@@ -48,6 +48,12 @@ pub struct LogicalSides<T> {
pub block_end: T,
}
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct LogicalSides1D<T> {
+ pub start: T,
+ pub end: T,
+}
+
impl<T: fmt::Debug> fmt::Debug for LogicalVec2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact
@@ -356,6 +362,16 @@ impl<T: Copy> LogicalSides<T> {
block: self.block_start,
}
}
+
+ #[inline]
+ pub(crate) fn inline_sides(&self) -> LogicalSides1D<T> {
+ LogicalSides1D::new(self.inline_start, self.inline_end)
+ }
+
+ #[inline]
+ pub(crate) fn block_sides(&self) -> LogicalSides1D<T> {
+ LogicalSides1D::new(self.block_start, self.block_end)
+ }
}
impl LogicalSides<LengthPercentage> {
@@ -447,6 +463,32 @@ impl From<LogicalSides<Au>> for LogicalSides<CSSPixelLength> {
}
}
+impl<T> LogicalSides1D<T> {
+ #[inline]
+ pub(crate) fn new(start: T, end: T) -> Self {
+ Self { start, end }
+ }
+}
+
+impl<T> LogicalSides1D<AutoOr<T>> {
+ #[inline]
+ pub(crate) fn either_specified(&self) -> bool {
+ !self.start.is_auto() || !self.end.is_auto()
+ }
+
+ #[inline]
+ pub(crate) fn either_auto(&self) -> bool {
+ self.start.is_auto() || self.end.is_auto()
+ }
+}
+
+impl<T: Add + Copy> LogicalSides1D<T> {
+ #[inline]
+ pub(crate) fn sum(&self) -> T::Output {
+ self.start + self.end
+ }
+}
+
impl<T> LogicalRect<T> {
pub fn max_inline_position(&self) -> T
where
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index 635d2a23ae5..fbdd9538a1f 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -25,8 +25,8 @@ use crate::fragment_tree::{
SpecificLayoutInfo,
};
use crate::geom::{
- AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint,
- PhysicalRect, PhysicalVec, Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
+ AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2,
+ PhysicalPoint, PhysicalRect, PhysicalVec, Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
};
use crate::sizing::ContentSizes;
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, DisplayInside};
@@ -483,10 +483,7 @@ impl HoistedAbsolutelyPositionedBox {
// When the "static-position rect" doesn't come into play, we do not do any alignment
// in the inline axis.
- let inline_box_offsets = AbsoluteBoxOffsets {
- start: box_offset.inline_start,
- end: box_offset.inline_end,
- };
+ let inline_box_offsets = box_offset.inline_sides();
let inline_alignment = match inline_box_offsets.either_specified() {
true => style.clone_justify_self().0.0,
false => shared_fragment.resolved_alignment.inline,
@@ -510,10 +507,7 @@ impl HoistedAbsolutelyPositionedBox {
// When the "static-position rect" doesn't come into play, we re-resolve "align-self"
// against this containing block.
- let block_box_offsets = AbsoluteBoxOffsets {
- start: box_offset.block_start,
- end: box_offset.block_end,
- };
+ let block_box_offsets = box_offset.block_sides();
let block_alignment = match block_box_offsets.either_specified() {
true => style.clone_align_self().0.0,
false => shared_fragment.resolved_alignment.block,
@@ -540,7 +534,7 @@ impl HoistedAbsolutelyPositionedBox {
inline: inline_axis_solver.inset_sum(),
block: block_axis_solver.inset_sum(),
};
- let automatic_size = |alignment: AlignFlags, offsets: &AbsoluteBoxOffsets<_>| {
+ let automatic_size = |alignment: AlignFlags, offsets: &LogicalSides1D<_>| {
if alignment.value() == AlignFlags::STRETCH && !offsets.either_auto() {
Size::Stretch
} else {
@@ -733,28 +727,6 @@ impl LogicalRect<Au> {
}
}
-#[derive(Debug)]
-struct AbsoluteBoxOffsets<T> {
- start: T,
- end: T,
-}
-
-impl AbsoluteBoxOffsets<LengthPercentageOrAuto<'_>> {
- pub(crate) fn either_specified(&self) -> bool {
- !self.start.is_auto() || !self.end.is_auto()
- }
-
- pub(crate) fn either_auto(&self) -> bool {
- self.start.is_auto() || self.end.is_auto()
- }
-}
-
-impl AbsoluteBoxOffsets<Au> {
- pub(crate) fn sum(&self) -> Au {
- self.start + self.end
- }
-}
-
struct AxisResult {
size: SizeConstraint,
margin_start: Au,
@@ -769,7 +741,7 @@ struct AbsoluteAxisSolver<'a> {
computed_margin_end: AuOrAuto,
computed_sizes: Sizes,
avoid_negative_margin_start: bool,
- box_offsets: AbsoluteBoxOffsets<LengthPercentageOrAuto<'a>>,
+ box_offsets: LogicalSides1D<LengthPercentageOrAuto<'a>>,
static_position_rect_axis: RectAxis,
alignment: AlignFlags,
flip_anchor: bool,
@@ -918,7 +890,7 @@ impl AbsoluteAxisSolver<'_> {
None,
),
(Some(start), Some(end)) => {
- let offsets = AbsoluteBoxOffsets {
+ let offsets = LogicalSides1D {
start: start.to_used_value(self.containing_size),
end: end.to_used_value(self.containing_size),
};
diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs
index 3ac8fa8f103..00d273ccf74 100644
--- a/components/layout_2020/replaced.rs
+++ b/components/layout_2020/replaced.rs
@@ -30,7 +30,9 @@ use crate::cell::ArcRefCell;
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::geom::{
+ LogicalSides1D, 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, LayoutStyle};
@@ -434,6 +436,7 @@ impl ReplacedContents {
containing_block: &ContainingBlock,
style: &ComputedValues,
content_box_sizes_and_pbm: &ContentBoxSizesAndPBM,
+ ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> LogicalVec2<Au> {
let pbm = &content_box_sizes_and_pbm.pbm;
self.used_size_as_if_inline_element_from_content_box_sizes(
@@ -442,7 +445,7 @@ impl ReplacedContents {
self.preferred_aspect_ratio(style, &pbm.padding_border_sums),
content_box_sizes_and_pbm.content_box_sizes.as_ref(),
Size::FitContent.into(),
- pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum(),
+ pbm.sums_auto_is_zero(ignore_block_margins_for_stretch),
)
}
diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs
index 7e382cc1cb2..e9aff0cf73f 100644
--- a/components/layout_2020/style_ext.rs
+++ b/components/layout_2020/style_ext.rs
@@ -31,8 +31,8 @@ use webrender_api as wr;
use crate::dom_traversal::Contents;
use crate::fragment_tree::FragmentFlags;
use crate::geom::{
- AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize, Size,
- Sizes,
+ AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalSides,
+ PhysicalSize, Size, Sizes,
};
use crate::table::TableLayoutStyle;
use crate::{ContainingBlock, IndefiniteContainingBlock};
@@ -150,6 +150,22 @@ impl PaddingBorderMargin {
padding_border_sums: LogicalVec2::zero(),
}
}
+
+ pub(crate) fn sums_auto_is_zero(
+ &self,
+ ignore_block_margins: LogicalSides1D<bool>,
+ ) -> LogicalVec2<Au> {
+ let margin = self.margin.auto_is(Au::zero);
+ let mut sums = self.padding_border_sums;
+ sums.inline += margin.inline_sum();
+ if !ignore_block_margins.start {
+ sums.block += margin.block_start;
+ }
+ if !ignore_block_margins.end {
+ sums.block += margin.block_end;
+ }
+ sums
+ }
}
/// Resolved `aspect-ratio` property with respect to a specific element. Depends
diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs
index bfd0b94ca12..8c526d0aed9 100644
--- a/components/layout_2020/table/layout.rs
+++ b/components/layout_2020/table/layout.rs
@@ -35,8 +35,8 @@ use crate::fragment_tree::{
PositioningFragment, SpecificLayoutInfo,
};
use crate::geom::{
- LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
- PhysicalVec, Size, SizeConstraint, ToLogical, ToLogicalWithContainingBlock,
+ LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
+ PhysicalSides, PhysicalVec, Size, SizeConstraint, ToLogical, ToLogicalWithContainingBlock,
};
use crate::positioned::{PositioningContext, PositioningContextLength, relative_adjustement};
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
@@ -1499,6 +1499,11 @@ impl<'a> TableLayout<'a> {
style: &self.table.style,
};
+ // The parent of a caption is the table wrapper, which establishes an independent
+ // formatting context. Therefore, we don't ignore block margins when resolving a
+ // stretch block size. https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
+ let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
+
let mut box_fragment = context.layout_in_flow_block_level(
layout_context,
positioning_context
@@ -1506,6 +1511,7 @@ impl<'a> TableLayout<'a> {
.unwrap_or(parent_positioning_context),
containing_block,
None, /* sequential_layout_state */
+ ignore_block_margins_for_stretch,
);
if let Some(mut positioning_context) = positioning_context.take() {
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-002.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-002.html.ini
deleted file mode 100644
index 285685433cb..00000000000
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-002.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[block-height-002.html]
- [main > div > div 2]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-003.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-003.html.ini
deleted file mode 100644
index ad728db419f..00000000000
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-003.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[block-height-003.html]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-004.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-004.html.ini
deleted file mode 100644
index 4cadbd9108e..00000000000
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-004.html.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-[block-height-004.html]
- [.inner 1]
- expected: FAIL
-
- [.inner 2]
- expected: FAIL
-
- [.inner 3]
- expected: FAIL
-
- [.inner 4]
- expected: FAIL
-
- [.inner 5]
- expected: FAIL
-
- [.inner 6]
- expected: FAIL
-
- [.inner 7]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-005.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-005.html.ini
index 97779092dce..29344216d66 100644
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-005.html.ini
+++ b/tests/wpt/meta/css/css-sizing/stretch/block-height-005.html.ini
@@ -1,12 +1,3 @@
[block-height-005.html]
- [.float + div 1]
- expected: FAIL
-
- [.float + div 2]
- expected: FAIL
-
- [.float + div 3]
- expected: FAIL
-
[.float + div 4]
expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-006.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-006.html.ini
deleted file mode 100644
index 0a16b3f94b4..00000000000
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-006.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[block-height-006.html]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-007.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-007.html.ini
deleted file mode 100644
index 2f0c3cc04f4..00000000000
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-007.html.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[block-height-007.html]
- [.child 1]
- expected: FAIL
-
- [.child 3]
- expected: FAIL
-
- [.child 5]
- expected: FAIL
-
- [.child 7]
- expected: FAIL
-
- [.child 9]
- expected: FAIL
-
- [.child 11]
- expected: FAIL
-
- [.child 13]
- expected: FAIL
-
- [.child 15]
- expected: FAIL
-
- [.child 17]
- expected: FAIL
-
- [.child 19]
- expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-008.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-008.html.ini
index 3ad3ab37586..18912fcef7f 100644
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-008.html.ini
+++ b/tests/wpt/meta/css/css-sizing/stretch/block-height-008.html.ini
@@ -1,240 +1,480 @@
[block-height-008.html]
+ [.child 1]
+ expected: FAIL
+
[.child 2]
expected: FAIL
+ [.child 3]
+ expected: FAIL
+
[.child 4]
expected: FAIL
+ [.child 5]
+ expected: FAIL
+
[.child 6]
expected: FAIL
+ [.child 7]
+ expected: FAIL
+
[.child 8]
expected: FAIL
+ [.child 9]
+ expected: FAIL
+
[.child 10]
expected: FAIL
+ [.child 11]
+ expected: FAIL
+
[.child 12]
expected: FAIL
+ [.child 13]
+ expected: FAIL
+
[.child 14]
expected: FAIL
+ [.child 15]
+ expected: FAIL
+
[.child 16]
expected: FAIL
+ [.child 17]
+ expected: FAIL
+
[.child 18]
expected: FAIL
+ [.child 19]
+ expected: FAIL
+
[.child 20]
expected: FAIL
+ [.child 21]
+ expected: FAIL
+
[.child 22]
expected: FAIL
+ [.child 23]
+ expected: FAIL
+
[.child 24]
expected: FAIL
+ [.child 25]
+ expected: FAIL
+
[.child 26]
expected: FAIL
+ [.child 27]
+ expected: FAIL
+
[.child 28]
expected: FAIL
+ [.child 29]
+ expected: FAIL
+
[.child 30]
expected: FAIL
+ [.child 31]
+ expected: FAIL
+
[.child 32]
expected: FAIL
+ [.child 33]
+ expected: FAIL
+
[.child 34]
expected: FAIL
+ [.child 35]
+ expected: FAIL
+
[.child 36]
expected: FAIL
+ [.child 37]
+ expected: FAIL
+
[.child 38]
expected: FAIL
+ [.child 39]
+ expected: FAIL
+
[.child 40]
expected: FAIL
+ [.child 41]
+ expected: FAIL
+
[.child 42]
expected: FAIL
+ [.child 43]
+ expected: FAIL
+
[.child 44]
expected: FAIL
+ [.child 45]
+ expected: FAIL
+
[.child 46]
expected: FAIL
+ [.child 47]
+ expected: FAIL
+
[.child 48]
expected: FAIL
+ [.child 49]
+ expected: FAIL
+
[.child 50]
expected: FAIL
+ [.child 51]
+ expected: FAIL
+
[.child 52]
expected: FAIL
+ [.child 53]
+ expected: FAIL
+
[.child 54]
expected: FAIL
+ [.child 55]
+ expected: FAIL
+
[.child 56]
expected: FAIL
+ [.child 57]
+ expected: FAIL
+
[.child 58]
expected: FAIL
+ [.child 59]
+ expected: FAIL
+
[.child 60]
expected: FAIL
+ [.child 61]
+ expected: FAIL
+
[.child 62]
expected: FAIL
+ [.child 63]
+ expected: FAIL
+
[.child 64]
expected: FAIL
+ [.child 65]
+ expected: FAIL
+
[.child 66]
expected: FAIL
+ [.child 67]
+ expected: FAIL
+
[.child 68]
expected: FAIL
+ [.child 69]
+ expected: FAIL
+
[.child 70]
expected: FAIL
+ [.child 71]
+ expected: FAIL
+
[.child 72]
expected: FAIL
+ [.child 73]
+ expected: FAIL
+
[.child 74]
expected: FAIL
+ [.child 75]
+ expected: FAIL
+
[.child 76]
expected: FAIL
+ [.child 77]
+ expected: FAIL
+
[.child 78]
expected: FAIL
+ [.child 79]
+ expected: FAIL
+
[.child 80]
expected: FAIL
+ [.child 81]
+ expected: FAIL
+
[.child 82]
expected: FAIL
+ [.child 83]
+ expected: FAIL
+
[.child 84]
expected: FAIL
+ [.child 85]
+ expected: FAIL
+
[.child 86]
expected: FAIL
+ [.child 87]
+ expected: FAIL
+
[.child 88]
expected: FAIL
+ [.child 89]
+ expected: FAIL
+
[.child 90]
expected: FAIL
+ [.child 91]
+ expected: FAIL
+
[.child 92]
expected: FAIL
+ [.child 93]
+ expected: FAIL
+
[.child 94]
expected: FAIL
+ [.child 95]
+ expected: FAIL
+
[.child 96]
expected: FAIL
+ [.child 97]
+ expected: FAIL
+
[.child 98]
expected: FAIL
+ [.child 99]
+ expected: FAIL
+
[.child 100]
expected: FAIL
+ [.child 101]
+ expected: FAIL
+
[.child 102]
expected: FAIL
+ [.child 103]
+ expected: FAIL
+
[.child 104]
expected: FAIL
+ [.child 105]
+ expected: FAIL
+
[.child 106]
expected: FAIL
+ [.child 107]
+ expected: FAIL
+
[.child 108]
expected: FAIL
+ [.child 109]
+ expected: FAIL
+
[.child 110]
expected: FAIL
+ [.child 111]
+ expected: FAIL
+
[.child 112]
expected: FAIL
+ [.child 113]
+ expected: FAIL
+
[.child 114]
expected: FAIL
+ [.child 115]
+ expected: FAIL
+
[.child 116]
expected: FAIL
+ [.child 117]
+ expected: FAIL
+
[.child 118]
expected: FAIL
+ [.child 119]
+ expected: FAIL
+
[.child 120]
expected: FAIL
+ [.child 121]
+ expected: FAIL
+
[.child 122]
expected: FAIL
+ [.child 123]
+ expected: FAIL
+
[.child 124]
expected: FAIL
+ [.child 125]
+ expected: FAIL
+
[.child 126]
expected: FAIL
+ [.child 127]
+ expected: FAIL
+
[.child 128]
expected: FAIL
+ [.child 129]
+ expected: FAIL
+
[.child 130]
expected: FAIL
+ [.child 131]
+ expected: FAIL
+
[.child 132]
expected: FAIL
+ [.child 133]
+ expected: FAIL
+
[.child 134]
expected: FAIL
+ [.child 135]
+ expected: FAIL
+
[.child 136]
expected: FAIL
+ [.child 137]
+ expected: FAIL
+
[.child 138]
expected: FAIL
+ [.child 139]
+ expected: FAIL
+
[.child 140]
expected: FAIL
+ [.child 141]
+ expected: FAIL
+
[.child 142]
expected: FAIL
+ [.child 143]
+ expected: FAIL
+
[.child 144]
expected: FAIL
+ [.child 145]
+ expected: FAIL
+
[.child 146]
expected: FAIL
+ [.child 147]
+ expected: FAIL
+
[.child 148]
expected: FAIL
+ [.child 149]
+ expected: FAIL
+
[.child 150]
expected: FAIL
+ [.child 151]
+ expected: FAIL
+
[.child 152]
expected: FAIL
+ [.child 153]
+ expected: FAIL
+
[.child 154]
expected: FAIL
+ [.child 155]
+ expected: FAIL
+
[.child 156]
expected: FAIL
+ [.child 157]
+ expected: FAIL
+
[.child 158]
expected: FAIL
+ [.child 159]
+ expected: FAIL
+
[.child 160]
expected: FAIL
diff --git a/tests/wpt/meta/css/css-sizing/stretch/block-height-010.html.ini b/tests/wpt/meta/css/css-sizing/stretch/block-height-010.html.ini
deleted file mode 100644
index 54ea4eca6d2..00000000000
--- a/tests/wpt/meta/css/css-sizing/stretch/block-height-010.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[block-height-010.html]
- expected: FAIL