mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: Defer some table sizing logic to the parent formatting context (#34889)
A box is usually sized by the formatting context in which it participates. However, tables have some special sizing behaviors, and these were in conflict. Instead of letting tables attempting to re-resolve their inline table, which failed to e.g. take flex properties into account or resolve sizing keywords correctly, now tables will trust the inline size determined by the parent. They will only floor it by the min-content size, and maybe shrink the final size due to collapsed columns. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
1ce6495f0d
commit
ceec1759f6
12 changed files with 43 additions and 61 deletions
|
@ -842,6 +842,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
|
||||||
containing_block,
|
containing_block,
|
||||||
style,
|
style,
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
|
false, /* is_table */
|
||||||
);
|
);
|
||||||
let ResolvedMargins {
|
let ResolvedMargins {
|
||||||
margin,
|
margin,
|
||||||
|
@ -1083,6 +1084,7 @@ impl IndependentNonReplacedContents {
|
||||||
containing_block,
|
containing_block,
|
||||||
&base.style,
|
&base.style,
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
|
self.is_table(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let layout = self.layout(
|
let layout = self.layout(
|
||||||
|
@ -1219,9 +1221,15 @@ impl IndependentNonReplacedContents {
|
||||||
.sizes
|
.sizes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: the automatic inline size should take `justify-self` into account.
|
||||||
|
let automatic_inline_size = if self.is_table() {
|
||||||
|
Size::FitContent
|
||||||
|
} else {
|
||||||
|
Size::Stretch
|
||||||
|
};
|
||||||
let compute_inline_size = |stretch_size| {
|
let compute_inline_size = |stretch_size| {
|
||||||
content_box_sizes.inline.resolve(
|
content_box_sizes.inline.resolve(
|
||||||
Size::Stretch,
|
automatic_inline_size,
|
||||||
Au::zero(),
|
Au::zero(),
|
||||||
stretch_size,
|
stretch_size,
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
|
@ -1613,6 +1621,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
containing_block: &ContainingBlock<'_>,
|
containing_block: &ContainingBlock<'_>,
|
||||||
style: &'a Arc<ComputedValues>,
|
style: &'a Arc<ComputedValues>,
|
||||||
get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
|
get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
|
||||||
|
is_table: bool,
|
||||||
) -> ContainingBlockPaddingAndBorder<'a> {
|
) -> ContainingBlockPaddingAndBorder<'a> {
|
||||||
if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
|
if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
|
||||||
// <https://drafts.csswg.org/css2/#anonymous-block-level>
|
// <https://drafts.csswg.org/css2/#anonymous-block-level>
|
||||||
|
@ -1672,8 +1681,14 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
None, /* TODO: support preferred aspect ratios on non-replaced boxes */
|
None, /* TODO: support preferred aspect ratios on non-replaced boxes */
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
// TODO: the automatic inline size should take `justify-self` into account.
|
||||||
|
let automatic_inline_size = if is_table {
|
||||||
|
Size::FitContent
|
||||||
|
} else {
|
||||||
|
Size::Stretch
|
||||||
|
};
|
||||||
let inline_size = content_box_sizes.inline.resolve(
|
let inline_size = content_box_sizes.inline.resolve(
|
||||||
Size::Stretch,
|
automatic_inline_size,
|
||||||
Au::zero(),
|
Au::zero(),
|
||||||
available_inline_size,
|
available_inline_size,
|
||||||
get_inline_content_sizes,
|
get_inline_content_sizes,
|
||||||
|
|
|
@ -73,8 +73,8 @@ pub(crate) struct IndependentLayout {
|
||||||
pub content_block_size: Au,
|
pub content_block_size: Au,
|
||||||
|
|
||||||
/// The contents of a table may force it to become wider than what we would expect
|
/// The contents of a table may force it to become wider than what we would expect
|
||||||
/// from 'width' and 'min-width'. This is the resulting inline content size,
|
/// from 'width' and 'min-width'. It can also become smaller due to collapsed columns.
|
||||||
/// or None for non-table layouts.
|
/// This is the resulting inline content size, or None for non-table layouts.
|
||||||
pub content_inline_size_for_table: Option<Au>,
|
pub content_inline_size_for_table: Option<Au>,
|
||||||
|
|
||||||
/// The offset of the last inflow baseline of this layout in the content area, if
|
/// The offset of the last inflow baseline of this layout in the content area, if
|
||||||
|
@ -182,6 +182,14 @@ impl IndependentFormattingContext {
|
||||||
self.base.base_fragment_info
|
self.base.base_fragment_info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_table(&self) -> bool {
|
||||||
|
match &self.contents {
|
||||||
|
IndependentFormattingContextContents::NonReplaced(content) => content.is_table(),
|
||||||
|
IndependentFormattingContextContents::Replaced(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn inline_content_sizes(
|
pub(crate) fn inline_content_sizes(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
|
@ -204,19 +212,13 @@ impl IndependentFormattingContext {
|
||||||
auto_minimum: &LogicalVec2<Au>,
|
auto_minimum: &LogicalVec2<Au>,
|
||||||
auto_block_size_stretches_to_containing_block: bool,
|
auto_block_size_stretches_to_containing_block: bool,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
let is_table = matches!(
|
|
||||||
self.contents,
|
|
||||||
IndependentFormattingContextContents::NonReplaced(
|
|
||||||
IndependentNonReplacedContents::Table(_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
sizing::outer_inline(
|
sizing::outer_inline(
|
||||||
self.style(),
|
self.style(),
|
||||||
containing_block,
|
containing_block,
|
||||||
auto_minimum,
|
auto_minimum,
|
||||||
auto_block_size_stretches_to_containing_block,
|
auto_block_size_stretches_to_containing_block,
|
||||||
self.is_replaced(),
|
self.is_replaced(),
|
||||||
is_table,
|
self.is_table(),
|
||||||
true, /* establishes_containing_block */
|
true, /* establishes_containing_block */
|
||||||
|padding_border_sums| self.preferred_aspect_ratio(padding_border_sums),
|
|padding_border_sums| self.preferred_aspect_ratio(padding_border_sums),
|
||||||
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
|
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
|
||||||
|
@ -278,6 +280,11 @@ impl IndependentNonReplacedContents {
|
||||||
// TODO: support preferred aspect ratios on non-replaced boxes.
|
// TODO: support preferred aspect ratios on non-replaced boxes.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_table(&self) -> bool {
|
||||||
|
matches!(self, Self::Table(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeInlineContentSizes for IndependentNonReplacedContents {
|
impl ComputeInlineContentSizes for IndependentNonReplacedContents {
|
||||||
|
|
|
@ -465,6 +465,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
..
|
..
|
||||||
} = style.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
} = style.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
||||||
let containing_block = &containing_block.into();
|
let containing_block = &containing_block.into();
|
||||||
|
let is_table = context.is_table();
|
||||||
|
|
||||||
let shared_fragment = self.fragment.borrow();
|
let shared_fragment = self.fragment.borrow();
|
||||||
let static_position_rect = shared_fragment
|
let static_position_rect = shared_fragment
|
||||||
|
@ -496,6 +497,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
alignment: inline_alignment,
|
alignment: inline_alignment,
|
||||||
flip_anchor: shared_fragment.original_parent_writing_mode.is_bidi_ltr() !=
|
flip_anchor: shared_fragment.original_parent_writing_mode.is_bidi_ltr() !=
|
||||||
containing_block_writing_mode.is_bidi_ltr(),
|
containing_block_writing_mode.is_bidi_ltr(),
|
||||||
|
is_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
// When the "static-position rect" doesn't come into play, we re-resolve "align-self"
|
// When the "static-position rect" doesn't come into play, we re-resolve "align-self"
|
||||||
|
@ -519,6 +521,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
static_position_rect_axis: static_position_rect.get_axis(AxisDirection::Block),
|
static_position_rect_axis: static_position_rect.get_axis(AxisDirection::Block),
|
||||||
alignment: block_alignment,
|
alignment: block_alignment,
|
||||||
flip_anchor: false,
|
flip_anchor: false,
|
||||||
|
is_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let IndependentFormattingContextContents::Replaced(replaced) = &context.contents {
|
if let IndependentFormattingContextContents::Replaced(replaced) = &context.contents {
|
||||||
|
@ -747,6 +750,7 @@ struct AbsoluteAxisSolver<'a> {
|
||||||
static_position_rect_axis: RectAxis,
|
static_position_rect_axis: RectAxis,
|
||||||
alignment: AlignFlags,
|
alignment: AlignFlags,
|
||||||
flip_anchor: bool,
|
flip_anchor: bool,
|
||||||
|
is_table: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbsoluteAxisSolver<'_> {
|
impl AbsoluteAxisSolver<'_> {
|
||||||
|
@ -825,7 +829,8 @@ impl AbsoluteAxisSolver<'_> {
|
||||||
self.computed_margin_start.auto_is(Au::zero) -
|
self.computed_margin_start.auto_is(Au::zero) -
|
||||||
self.computed_margin_end.auto_is(Au::zero);
|
self.computed_margin_end.auto_is(Au::zero);
|
||||||
let initial_behavior = match self.alignment.value() {
|
let initial_behavior = match self.alignment.value() {
|
||||||
AlignFlags::STRETCH | AlignFlags::NORMAL | AlignFlags::AUTO => Size::Stretch,
|
AlignFlags::NORMAL | AlignFlags::AUTO if !self.is_table => Size::Stretch,
|
||||||
|
AlignFlags::STRETCH => Size::Stretch,
|
||||||
_ => Size::FitContent,
|
_ => Size::FitContent,
|
||||||
};
|
};
|
||||||
let size = solve_size(initial_behavior, stretch_size);
|
let size = solve_size(initial_behavior, stretch_size);
|
||||||
|
|
|
@ -803,36 +803,12 @@ impl<'a> TableLayout<'a> {
|
||||||
let style = &self.table.style;
|
let style = &self.table.style;
|
||||||
self.pbm = style.padding_border_margin(containing_block_for_table);
|
self.pbm = style.padding_border_margin(containing_block_for_table);
|
||||||
|
|
||||||
|
// These diverge a little from the specification, but should be roughtly equivalent
|
||||||
|
// to what the spec calls "resolved-table-width" and "used width of a table".
|
||||||
// https://drafts.csswg.org/css-tables/#resolved-table-width
|
// https://drafts.csswg.org/css-tables/#resolved-table-width
|
||||||
// * If inline-size computes to 'auto', this is the stretch-fit size
|
|
||||||
// (https://drafts.csswg.org/css-sizing-3/#stretch-fit-size).
|
|
||||||
// * Otherwise, it's the resulting length (with percentages resolved).
|
|
||||||
// In both cases, it's clamped between min-inline-size and max-inline-size.
|
|
||||||
// This diverges a little from the specification.
|
|
||||||
let resolved_table_width = containing_block_for_children.size.inline;
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-tables/#used-width-of-table
|
// https://drafts.csswg.org/css-tables/#used-width-of-table
|
||||||
// * If table-root has a computed value for inline-size different than auto:
|
let resolved_table_width = containing_block_for_children.size.inline;
|
||||||
// use the maximum of the resolved table width, GRIDMIN and CAPMIN.
|
let used_width_of_table = resolved_table_width.max(grid_min_max.min_content);
|
||||||
// * If auto: use the resolved_table_width, clamped between GRIDMIN and GRIDMAX,
|
|
||||||
// but at least as big as min-inline-size and CAPMIN.
|
|
||||||
// This diverges a little from the specification, but should be equivalent
|
|
||||||
// (other than using the stretch-fit size instead of the containing block width).
|
|
||||||
let used_width_of_table = match style
|
|
||||||
.content_box_size_deprecated(containing_block_for_table, &self.pbm)
|
|
||||||
.inline
|
|
||||||
{
|
|
||||||
LengthPercentage(_) => resolved_table_width.max(grid_min_max.min_content),
|
|
||||||
Auto => {
|
|
||||||
let min_width: Au = style
|
|
||||||
.content_min_box_size_deprecated(containing_block_for_table, &self.pbm)
|
|
||||||
.inline
|
|
||||||
.auto_is(Au::zero);
|
|
||||||
resolved_table_width
|
|
||||||
.clamp(grid_min_max.min_content, grid_min_max.max_content)
|
|
||||||
.max(min_width)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Padding and border should apply to the table grid, but they are properties of the
|
// Padding and border should apply to the table grid, but they are properties of the
|
||||||
// parent element (the table wrapper). In order to account for this, we subtract the
|
// parent element (the table wrapper). In order to account for this, we subtract the
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
[table-justify-self-stretch.html]
|
[table-justify-self-stretch.html]
|
||||||
[.item 1]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[.item 3]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[.item 5]
|
[.item 5]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[table-as-item-inflexible-in-row-1.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[table-as-item-inflexible-in-row-2.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[table-as-item-narrow-content.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[table-as-item-stretch-cross-size-3.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[table-item-flex-percentage-min-width.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[explicitly-sized-grid-item-as-table.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,6 +1,3 @@
|
||||||
[td-box-sizing-003.html]
|
[td-box-sizing-003.html]
|
||||||
[table 9]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[table 10]
|
[table 10]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue