mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
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>
This commit is contained in:
parent
f7ddac249b
commit
9858ec81f9
14 changed files with 379 additions and 120 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue