layout: Add an indefinite containing block for intrinsic sizing (#33204)

When computing the min-content or max-content size of an element we
need to ignore `inline-size`, `min-inline-size` and `max-inline-size`.

However, we should take the block-axis sizing properties into account.
That's because the contents could have percentages depending on them,
which can then affect their inline size via an aspect ratio.

Therefore, this patch adds `IndefiniteContainingBlock`, which is similar
to `ContainingBlock`, but it allows an indefinite inline-size. This
struct is then passed arround during intrinsic sizing.

More refinement will be needed in follow-up patches in order to fully
address the problem.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Oriol Brufau 2024-08-29 16:10:46 +02:00 committed by GitHub
parent 46dbe4ce32
commit 93abdf7cb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 600 additions and 332 deletions

View file

@ -9,7 +9,6 @@ use app_units::Au;
use atomic_refcell::AtomicRefMut;
use itertools::izip;
use style::computed_values::position::T as Position;
use style::logical_geometry::WritingMode;
use style::properties::longhands::align_items::computed_value::T as AlignItems;
use style::properties::longhands::align_self::computed_value::T as AlignSelf;
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
@ -35,7 +34,7 @@ use crate::positioned::{
};
use crate::sizing::{ContentSizes, IntrinsicSizingMode};
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::ContainingBlock;
use crate::{ContainingBlock, IndefiniteContainingBlock};
// FIMXE: “Flex items […] `z-index` values other than `auto` create a stacking context
// even if `position` is `static` (behaving exactly as if `position` were `relative`).”
@ -305,19 +304,27 @@ impl FlexContainer {
pub fn inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
writing_mode: WritingMode,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
match self.config.flex_axis {
FlexAxis::Row => self.main_content_sizes(layout_context, writing_mode, || {
FlexAxis::Row => {
self.main_content_sizes(layout_context, containing_block_for_children, || {
unreachable!(
"Unexpected FlexContext query during row flex intrinsic size calculation."
)
}),
FlexAxis::Column => self.cross_content_sizes(layout_context),
})
},
FlexAxis::Column => {
self.cross_content_sizes(layout_context, containing_block_for_children)
},
}
}
fn cross_content_sizes(&mut self, layout_context: &LayoutContext) -> ContentSizes {
fn cross_content_sizes(
&mut self,
layout_context: &LayoutContext,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
// <https://drafts.csswg.org/css-flexbox/#intrinsic-cross-sizes>
assert_eq!(
self.config.flex_axis,
@ -331,10 +338,15 @@ impl FlexContainer {
FlexLevelBox::FlexItem(item) => {
// TODO: For the max-content size we should distribute items into
// columns, and sum the column sizes and gaps.
content_sizes.max_assign(
item.independent_formatting_context
.inline_content_sizes(layout_context),
);
// TODO: Use the proper automatic minimum size.
let ifc = &mut item.independent_formatting_context;
content_sizes.max_assign(ifc.inline_content_sizes(
layout_context,
&containing_block_for_children.new_for_intrinsic_inline_size_of_child(
&ifc.style().clone(),
&LogicalVec2::zero(),
),
));
},
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => {},
}
@ -345,7 +357,7 @@ impl FlexContainer {
fn main_content_sizes<'a>(
&self,
layout_context: &LayoutContext,
writing_mode: WritingMode,
containing_block_for_children: &IndefiniteContainingBlock,
flex_context_getter: impl Fn() -> &'a FlexContext<'a>,
) -> ContentSizes {
// - TODO: calculate intrinsic cross sizes when container is a column
@ -372,7 +384,7 @@ impl FlexContainer {
let info = item.main_content_size_info(
layout_context,
writing_mode,
containing_block_for_children,
container_is_horizontal,
self.config.flex_axis,
self.config.main_start_cross_start_sides_are,
@ -514,7 +526,7 @@ impl FlexContainer {
let container_main_size = match self.config.flex_axis {
FlexAxis::Row => containing_block.inline_size,
FlexAxis::Column => containing_block.block_size.auto_is(|| {
self.main_content_sizes(layout_context, self.style.writing_mode, || &flex_context)
self.main_content_sizes(layout_context, &containing_block.into(), || &flex_context)
.max_content
}),
};
@ -905,16 +917,17 @@ fn allocate_free_cross_space_for_flex_line(
impl<'a> FlexItem<'a> {
fn new(flex_context: &FlexContext, box_: &'a mut FlexItemBox) -> Self {
let containing_block = flex_context.containing_block;
let parent_writing_mode = containing_block.effective_writing_mode();
let item_writing_mode = box_.style().effective_writing_mode();
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
assert_eq!(
containing_block.effective_writing_mode(),
box_.style().effective_writing_mode(),
parent_writing_mode, item_writing_mode,
"Mixed writing modes are not supported yet"
);
let container_is_horizontal = containing_block.effective_writing_mode().is_horizontal();
let item_is_horizontal = box_.style().effective_writing_mode().is_horizontal();
let container_is_horizontal = parent_writing_mode.is_horizontal();
let item_is_horizontal = item_writing_mode.is_horizontal();
let cross_axis_is_item_block_axis = cross_axis_is_item_block_axis(
container_is_horizontal,
item_is_horizontal,
@ -979,6 +992,8 @@ impl<'a> FlexItem<'a> {
flex_context.container_definite_inner_size,
cross_axis_is_item_block_axis,
flex_relative_content_box_size,
flex_relative_content_min_size,
flex_relative_content_max_size,
padding_border,
|item| {
let min_size = flex_context
@ -1585,6 +1600,7 @@ impl FlexItem<'_> {
);
// … and also the items inline axis.
let flex_axis = flex_context.config.flex_axis;
match &mut self.box_.independent_formatting_context {
IndependentFormattingContext::Replaced(replaced) => {
let pbm = replaced.style.padding_border_margin(containing_block);
@ -1602,11 +1618,7 @@ impl FlexItem<'_> {
box_size,
&pbm,
);
let cross_size = flex_context
.config
.flex_axis
.vec2_to_flex_relative(size)
.cross;
let cross_size = flex_axis.vec2_to_flex_relative(size).cross;
let fragments = replaced.contents.make_fragments(
&replaced.style,
size.to_physical_size(container_writing_mode),
@ -1642,23 +1654,34 @@ impl FlexItem<'_> {
.effective_writing_mode()
.is_horizontal(),
item_is_horizontal,
flex_context.config.flex_axis,
flex_axis,
);
let (inline_size, block_size) = if cross_axis_is_item_block_axis {
(used_main_size, cross_size)
} else {
(
cross_size.auto_is(|| {
let content_contributions = non_replaced.outer_inline_content_sizes(
flex_context.layout_context,
container_writing_mode,
Au::zero,
let style = non_replaced.style.clone();
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(
&style,
AuOrAuto::LengthPercentage(used_main_size),
);
containing_block
.inline_size
let content_contributions = non_replaced
.inline_content_sizes(
flex_context.layout_context,
&containing_block_for_children,
)
.map(|size| {
size.clamp_between_extremums(
self.content_min_size.cross,
self.content_max_size.cross,
)
});
(containing_block.inline_size - self.pbm_auto_is_zero.cross)
.min(content_contributions.max_content)
.max(content_contributions.min_content) -
self.pbm_auto_is_zero.cross
.max(content_contributions.min_content)
}),
// The main size of a flex item is considered to be definite if its flex basis is definite
// or the flex container has a definite main size.
@ -1874,7 +1897,7 @@ impl FlexItemBox {
fn main_content_size_info<'a>(
&mut self,
layout_context: &LayoutContext,
container_writing_mode: WritingMode,
containing_block: &IndefiniteContainingBlock,
container_is_horizontal: bool,
flex_axis: FlexAxis,
main_start_cross_start: MainStartCrossStart,
@ -1886,25 +1909,8 @@ impl FlexItemBox {
let cross_axis_is_item_block_axis =
cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis);
let pbm = style.padding_border_margin_for_intrinsic_size(item_writing_mode);
let box_size = style
.box_size(item_writing_mode)
.map(|v| v.percentage_relative_to(Length::zero()));
let content_box_size = style
.content_box_size_for_box_size(box_size, &pbm)
.map(|v| v.map(Au::from));
let min_size = style
.min_box_size(item_writing_mode)
.map(|v| v.percentage_relative_to(Length::zero()));
let content_min_size = style
.content_min_box_size_for_min_size(min_size, &pbm)
.map(|v| v.map(Au::from));
let max_size = style
.max_box_size(item_writing_mode)
.map(|v| v.map(|v| v.percentage_relative_to(Length::zero())));
let content_max_size = style
.content_max_box_size_for_max_size(max_size, &pbm)
.map(|v| v.map(Au::from));
let (content_box_size, content_min_size, content_max_size, pbm) =
style.content_box_sizes_and_padding_border_margin(containing_block);
let automatic_min_size = self.automatic_min_size(
layout_context,
cross_axis_is_item_block_axis,
@ -1942,9 +1948,11 @@ impl FlexItemBox {
let content_contribution_sizes = match flex_axis {
FlexAxis::Row => self
.independent_formatting_context
.outer_inline_content_sizes(layout_context, container_writing_mode, || {
automatic_min_size
}),
.outer_inline_content_sizes(
layout_context,
containing_block,
&content_min_size_no_auto,
),
FlexAxis::Column => self
.layout_for_block_content_size(
flex_context_getter(),
@ -1982,6 +1990,8 @@ impl FlexItemBox {
},
cross_axis_is_item_block_axis,
content_box_size,
content_min_size_no_auto,
content_max_size,
padding_border,
block_content_size_callback,
);
@ -2142,8 +2152,14 @@ impl FlexItemBox {
// > preferred aspect ratio, by any definite minimum and maximum cross sizes converted through the
// > aspect ratio.
let main_content_size = if cross_axis_is_item_block_axis {
let block_size = content_box_size.cross.map(|v| {
v.clamp_between_extremums(min_size.cross.auto_is(Au::zero), max_size.cross)
});
let style = self.independent_formatting_context.style().clone();
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_size);
self.independent_formatting_context
.inline_content_sizes(layout_context)
.inline_content_sizes(layout_context, &containing_block_for_children)
.min_content
} else {
block_content_size_callback(self)
@ -2178,16 +2194,19 @@ impl FlexItemBox {
container_definite_inner_size: FlexRelativeVec2<Option<Au>>,
cross_axis_is_item_block_axis: bool,
content_box_size: FlexRelativeVec2<AuOrAuto>,
min_size: FlexRelativeVec2<Au>,
max_size: FlexRelativeVec2<Option<Au>>,
padding_border_sums: FlexRelativeVec2<Au>,
block_content_size_callback: impl FnOnce(&mut FlexItemBox) -> Au,
) -> (Au, bool) {
let flex_item = &mut self.independent_formatting_context;
let style = flex_item.style();
let used_flex_basis = match &flex_item.style().get_position().flex_basis {
let used_flex_basis = match &style.get_position().flex_basis {
FlexBasis::Content => FlexBasis::Content,
FlexBasis::Size(Size::LengthPercentage(length_percentage)) => {
let apply_box_sizing = |length: Au| {
match flex_item.style().get_position().box_sizing {
match style.get_position().box_sizing {
BoxSizing::ContentBox => length,
BoxSizing::BorderBox => {
// This may make `length` negative,
@ -2250,7 +2269,15 @@ impl FlexItemBox {
let flex_basis = if cross_axis_is_item_block_axis {
// The main axis is the inline axis, so we can get the content size from the normal
// preferred widths calculation.
flex_item.inline_content_sizes(layout_context).max_content
let style = style.clone();
let block_size = content_box_size
.cross
.map(|v| v.clamp_between_extremums(min_size.cross, max_size.cross));
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_size);
flex_item
.inline_content_sizes(layout_context, &containing_block_for_children)
.max_content
} else {
block_content_size_callback(self)
};
@ -2305,8 +2332,14 @@ impl FlexItemBox {
if will_stretch {
containing_block_inline_size_minus_pbm
} else {
let inline_content_sizes =
non_replaced.inline_content_sizes(flex_context.layout_context);
let style = non_replaced.style.clone();
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style(&style);
let inline_content_sizes = non_replaced.inline_content_sizes(
flex_context.layout_context,
&containing_block_for_children,
);
containing_block_inline_size_minus_pbm
.min(inline_content_sizes.max_content)
.max(inline_content_sizes.min_content)

View file

@ -18,7 +18,7 @@ use servo_arc::Arc;
use style::computed_values::float::T as FloatProperty;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style::values::computed::{Clear, Length};
use style::values::computed::Clear;
use style::values::specified::text::TextDecorationLine;
use crate::context::LayoutContext;
@ -28,8 +28,8 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, CollapsedMargin};
use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
use crate::positioned::PositioningContext;
use crate::style_ext::{ComputedValuesExt, DisplayInside, PaddingBorderMargin};
use crate::ContainingBlock;
use crate::style_ext::{Clamp, ComputedValuesExt, DisplayInside, PaddingBorderMargin};
use crate::{ContainingBlock, IndefiniteContainingBlock};
/// A floating box.
#[derive(Debug, Serialize)]
@ -905,35 +905,44 @@ impl FloatBox {
IndependentFormattingContext::NonReplaced(ref mut non_replaced) => {
// Calculate inline size.
// https://drafts.csswg.org/css2/#float-width
let box_size = non_replaced.style.content_box_size(containing_block, &pbm);
let max_box_size = non_replaced
.style
.content_max_box_size(containing_block, &pbm);
let min_box_size = non_replaced
.style
let style = non_replaced.style.clone();
let box_size = style
.content_box_size(containing_block, &pbm)
.map(|v| v.map(Au::from));
let max_box_size = style
.content_max_box_size(containing_block, &pbm)
.map(|v| v.map(Au::from));
let min_box_size = style
.content_min_box_size(containing_block, &pbm)
.auto_is(Length::zero);
.map(|v| v.map(Au::from))
.auto_is(Au::zero);
let tentative_inline_size = box_size.inline.auto_is(|| {
let available_size =
containing_block.inline_size - pbm_sums.inline_sum();
non_replaced
.inline_content_sizes(layout_context)
.shrink_to_fit(available_size)
.into()
});
let inline_size = tentative_inline_size
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
let block_size = box_size.block.map(|size| {
size.clamp_between_extremums(min_box_size.block, max_box_size.block)
});
let tentative_inline_size = box_size.inline.auto_is(|| {
let available_size =
containing_block.inline_size - pbm_sums.inline_sum();
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(
&style, block_size,
);
non_replaced
.inline_content_sizes(
layout_context,
&containing_block_for_children,
)
.shrink_to_fit(available_size)
});
let inline_size = tentative_inline_size
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
// Calculate block size.
// https://drafts.csswg.org/css2/#block-root-margin
// FIXME(pcwalton): Is a tree rank of zero correct here?
let containing_block_for_children = ContainingBlock {
inline_size: inline_size.into(),
block_size: block_size.map(|t| t.into()),
inline_size,
block_size,
style: &non_replaced.style,
};
let independent_layout = non_replaced.layout(
@ -944,13 +953,13 @@ impl FloatBox {
);
let (block_size, inline_size) =
match independent_layout.content_inline_size_for_table {
Some(inline_size) => (
independent_layout.content_block_size.into(),
inline_size.into(),
),
Some(inline_size) => {
(independent_layout.content_block_size, inline_size)
},
None => (
block_size.auto_is(|| {
Length::from(independent_layout.content_block_size)
independent_layout
.content_block_size
.clamp_between_extremums(
min_box_size.block,
max_box_size.block,
@ -960,8 +969,8 @@ impl FloatBox {
),
};
content_size = LogicalVec2 {
inline: inline_size.into(),
block: block_size.into(),
inline: inline_size,
block: block_size,
};
children = independent_layout.fragments;
},

View file

@ -94,7 +94,6 @@ use style::computed_values::text_wrap_mode::T as TextWrapMode;
use style::computed_values::vertical_align::T as VerticalAlign;
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
use style::context::QuirksMode;
use style::logical_geometry::WritingMode;
use style::properties::style_structs::InheritedText;
use style::properties::ComputedValues;
use style::values::computed::{Clear, Length};
@ -128,7 +127,7 @@ use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::sizing::ContentSizes;
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::ContainingBlock;
use crate::{ContainingBlock, IndefiniteContainingBlock};
// From gfxFontConstants.h in Firefox.
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
@ -1557,9 +1556,9 @@ impl InlineFormattingContext {
pub(super) fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
ContentSizesComputation::compute(self, layout_context, containing_block_writing_mode)
ContentSizesComputation::compute(self, layout_context, containing_block_for_children)
}
pub(super) fn layout(
@ -1954,13 +1953,19 @@ impl IndependentFormattingContext {
.content_min_box_size(layout.containing_block, &pbm)
.map(|v| v.map(Au::from))
.auto_is(Au::zero);
let block_size = box_size
.block
.map(|v| v.clamp_between_extremums(min_box_size.block, max_box_size.block));
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
let tentative_inline_size = box_size.inline.auto_is(|| {
let style = non_replaced.style.clone();
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_size);
let available_size =
layout.containing_block.inline_size - pbm_sums.inline_sum();
non_replaced
.inline_content_sizes(layout.layout_context)
.inline_content_sizes(layout.layout_context, &containing_block_for_children)
.shrink_to_fit(available_size)
});
@ -1969,9 +1974,6 @@ impl IndependentFormattingContext {
// always results in that size.
let inline_size = tentative_inline_size
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
let block_size = box_size
.block
.map(|v| v.clamp_between_extremums(min_box_size.block, max_box_size.block));
let containing_block_for_children = ContainingBlock {
inline_size,
@ -2259,7 +2261,7 @@ fn inline_container_needs_strut(
/// A struct which takes care of computing [`ContentSizes`] for an [`InlineFormattingContext`].
struct ContentSizesComputation<'layout_data> {
layout_context: &'layout_data LayoutContext<'layout_data>,
containing_block_writing_mode: WritingMode,
containing_block: &'layout_data IndefiniteContainingBlock<'layout_data>,
paragraph: ContentSizes,
current_line: ContentSizes,
/// Size for whitepsace pending to be added to this line.
@ -2297,14 +2299,14 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
let zero = Length::zero();
let padding = inline_box
.style
.padding(self.containing_block_writing_mode)
.padding(self.containing_block.style.writing_mode)
.percentages_relative_to(zero);
let border = inline_box
.style
.border_width(self.containing_block_writing_mode);
.border_width(self.containing_block.style.writing_mode);
let margin = inline_box
.style
.margin(self.containing_block_writing_mode)
.margin(self.containing_block.style.writing_mode)
.percentages_relative_to(zero)
.auto_is(Length::zero);
@ -2379,8 +2381,8 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
let outer = atomic.outer_inline_content_sizes(
self.layout_context,
self.containing_block_writing_mode,
Au::zero,
self.containing_block,
&LogicalVec2::zero(),
);
if !inline_formatting_context
@ -2428,11 +2430,11 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
fn compute(
inline_formatting_context: &InlineFormattingContext,
layout_context: &'layout_data LayoutContext,
containing_block_writing_mode: WritingMode,
containing_block: &'layout_data IndefiniteContainingBlock,
) -> ContentSizes {
Self {
layout_context,
containing_block_writing_mode,
containing_block,
paragraph: ContentSizes::zero(),
current_line: ContentSizes::zero(),
pending_whitespace: Au::zero(),

View file

@ -36,7 +36,7 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, Positioning
use crate::replaced::ReplacedContent;
use crate::sizing::{self, ContentSizes};
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::ContainingBlock;
use crate::{ContainingBlock, IndefiniteContainingBlock};
mod construct;
pub mod float;
@ -227,10 +227,10 @@ impl OutsideMarker {
sequential_layout_state: Option<&mut SequentialLayoutState>,
collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
) -> Fragment {
let containing_block_writing_mode = containing_block.effective_writing_mode();
let content_sizes = self
.block_container
.inline_content_sizes(layout_context, containing_block_writing_mode);
let content_sizes = self.block_container.inline_content_sizes(
layout_context,
&IndefiniteContainingBlock::new_for_style(&self.marker_style),
);
let containing_block_for_children = ContainingBlock {
inline_size: content_sizes.max_content,
block_size: AuOrAuto::auto(),
@ -244,6 +244,8 @@ impl OutsideMarker {
sequential_layout_state,
collapsible_with_parent_start_margin.unwrap_or(CollapsibleWithParentStartMargin(false)),
);
let containing_block_writing_mode = containing_block.effective_writing_mode();
let max_inline_size =
flow_layout
.fragments
@ -357,7 +359,7 @@ impl BlockFormattingContext {
fn calculate_inline_content_size_for_block_level_boxes(
boxes: &[ArcRefCell<BlockLevelBox>],
layout_context: &LayoutContext,
writing_mode: WritingMode,
containing_block: &IndefiniteContainingBlock,
) -> ContentSizes {
let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| {
match &mut *box_.borrow_mut() {
@ -366,7 +368,11 @@ fn calculate_inline_content_size_for_block_level_boxes(
BlockLevelBox::OutOfFlowFloatBox(ref mut float_box) => {
let size = float_box
.contents
.outer_inline_content_sizes(layout_context, writing_mode, Au::zero)
.outer_inline_content_sizes(
layout_context,
containing_block,
&LogicalVec2::zero(),
)
.max(ContentSizes::zero());
let style_box = &float_box.contents.style().get_box();
Some((size, style_box.float, style_box.clear))
@ -376,12 +382,11 @@ fn calculate_inline_content_size_for_block_level_boxes(
} => {
let size = sizing::outer_inline(
style,
writing_mode,
|| {
contents
.inline_content_sizes(layout_context, style.effective_writing_mode())
&containing_block,
&LogicalVec2::zero(),
|containing_block_for_children| {
contents.inline_content_sizes(layout_context, containing_block_for_children)
},
Au::zero,
)
.max(ContentSizes::zero());
// A block in the same BFC can overlap floats, it's not moved next to them,
@ -391,7 +396,11 @@ fn calculate_inline_content_size_for_block_level_boxes(
},
BlockLevelBox::Independent(ref mut independent) => {
let size = independent
.outer_inline_content_sizes(layout_context, writing_mode, Au::zero)
.outer_inline_content_sizes(
layout_context,
containing_block,
&LogicalVec2::zero(),
)
.max(ContentSizes::zero());
Some((size, Float::None, independent.style().get_box().clear))
},
@ -498,16 +507,16 @@ impl BlockContainer {
pub(super) fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
writing_mode: WritingMode,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
match &self {
Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes(
boxes,
layout_context,
writing_mode,
containing_block_for_children,
),
Self::InlineFormattingContext(context) => {
context.inline_content_sizes(layout_context, writing_mode)
context.inline_content_sizes(layout_context, containing_block_for_children)
},
}
}

View file

@ -5,7 +5,7 @@
use app_units::Au;
use serde::Serialize;
use servo_arc::Arc;
use style::logical_geometry::WritingMode;
use style::logical_geometry::Direction;
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use style::values::specified::text::TextDecorationLine;
@ -19,9 +19,9 @@ use crate::fragment_tree::{BaseFragmentInfo, Fragment, FragmentFlags};
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::{self, ContentSizes};
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use crate::style_ext::{AspectRatio, DisplayInside};
use crate::table::Table;
use crate::ContainingBlock;
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock, LogicalVec2};
/// <https://drafts.csswg.org/css-display/#independent-formatting-context>
#[derive(Debug, Serialize)]
@ -36,7 +36,7 @@ pub(crate) struct NonReplacedFormattingContext {
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
/// If it was requested during construction
pub content_sizes: Option<ContentSizes>,
pub content_sizes: Option<(AuOrAuto, ContentSizes)>,
pub contents: NonReplacedFormattingContextContents,
}
@ -176,30 +176,56 @@ impl IndependentFormattingContext {
}
}
pub fn inline_content_sizes(&mut self, layout_context: &LayoutContext) -> ContentSizes {
pub(crate) fn inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
match self {
Self::NonReplaced(inner) => inner.inline_content_sizes(layout_context),
Self::Replaced(inner) => inner.contents.inline_content_sizes(&inner.style),
Self::NonReplaced(inner) => {
inner.inline_content_sizes(layout_context, containing_block_for_children)
},
Self::Replaced(inner) => inner
.contents
.inline_content_sizes(layout_context, containing_block_for_children),
}
}
pub fn outer_inline_content_sizes(
pub(crate) fn outer_inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
get_auto_minimum: impl FnOnce() -> Au,
containing_block: &IndefiniteContainingBlock,
auto_minimum: &LogicalVec2<Au>,
) -> ContentSizes {
match self {
Self::NonReplaced(non_replaced) => non_replaced.outer_inline_content_sizes(
layout_context,
containing_block_writing_mode,
get_auto_minimum,
Self::NonReplaced(non_replaced) => sizing::outer_inline(
&non_replaced.style.clone(),
containing_block,
auto_minimum,
|containing_block_for_children| {
non_replaced.inline_content_sizes(layout_context, containing_block_for_children)
},
),
Self::Replaced(replaced) => sizing::outer_inline(
&replaced.style,
containing_block_writing_mode,
|| replaced.contents.inline_content_sizes(&replaced.style),
get_auto_minimum,
containing_block,
auto_minimum,
|containing_block_for_children| {
match (
containing_block_for_children.size.block,
replaced.preferred_aspect_ratio(containing_block),
) {
(AuOrAuto::LengthPercentage(block_size), Some(ratio)) => {
return ratio
.compute_dependent_size(Direction::Inline, block_size)
.into();
},
_ => {},
}
replaced
.contents
.inline_content_sizes(layout_context, containing_block_for_children)
},
),
}
}
@ -234,46 +260,59 @@ impl NonReplacedFormattingContext {
}
}
pub fn inline_content_sizes(&mut self, layout_context: &LayoutContext) -> ContentSizes {
let writing_mode = self.style.effective_writing_mode();
let contents = &mut self.contents;
*self
.content_sizes
.get_or_insert_with(|| contents.inline_content_sizes(layout_context, writing_mode))
}
pub fn outer_inline_content_sizes(
pub(crate) fn inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
get_auto_minimum: impl FnOnce() -> Au,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
sizing::outer_inline(
&self.style,
containing_block_writing_mode,
|| {
*self.content_sizes.get_or_insert_with(|| {
assert_eq!(
containing_block_for_children.size.inline,
AuOrAuto::Auto,
"inline_content_sizes() got non-auto containing block inline-size",
);
if let Some((previous_cb_block_size, result)) = self.content_sizes {
if previous_cb_block_size == containing_block_for_children.size.block {
return result;
}
// TODO: Should we keep multiple caches for various block sizes?
}
self.content_sizes
.insert((
containing_block_for_children.size.block,
self.contents
.inline_content_sizes(layout_context, self.style.effective_writing_mode())
})
},
get_auto_minimum,
)
.inline_content_sizes(layout_context, &containing_block_for_children),
))
.1
}
}
impl NonReplacedFormattingContextContents {
pub fn inline_content_sizes(
pub(crate) fn inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
writing_mode: WritingMode,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
match self {
Self::Flow(inner) => inner
.contents
.inline_content_sizes(layout_context, writing_mode),
Self::Flex(inner) => inner.inline_content_sizes(layout_context, writing_mode),
Self::Table(table) => table.inline_content_sizes(layout_context, writing_mode),
.inline_content_sizes(layout_context, containing_block_for_children),
Self::Flex(inner) => {
inner.inline_content_sizes(layout_context, containing_block_for_children)
},
Self::Table(table) => {
table.inline_content_sizes(layout_context, containing_block_for_children)
},
}
}
}
impl ReplacedFormattingContext {
pub(crate) fn preferred_aspect_ratio(
&self,
containing_block: &IndefiniteContainingBlock,
) -> Option<AspectRatio> {
self.contents
.preferred_aspect_ratio(containing_block, &self.style)
}
}

View file

@ -24,7 +24,7 @@ pub type AuOrAuto = AutoOr<Au>;
pub type LengthOrAuto = AutoOr<Length>;
pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>;
#[derive(Clone, Copy, Serialize)]
#[derive(Clone, Copy, PartialEq, Serialize)]
pub struct LogicalVec2<T> {
pub inline: T,
pub block: T,
@ -150,7 +150,7 @@ impl<T: Clone> LogicalVec2<AutoOr<T>> {
}
impl LogicalVec2<LengthPercentageOrAuto<'_>> {
pub fn percentages_relative_to(
pub(crate) fn percentages_relative_to(
&self,
containing_block: &ContainingBlock,
) -> LogicalVec2<LengthOrAuto> {
@ -165,8 +165,32 @@ impl LogicalVec2<LengthPercentageOrAuto<'_>> {
}
}
impl LogicalVec2<LengthPercentageOrAuto<'_>> {
pub(crate) fn percentages_relative_to_basis(
&self,
basis: &LogicalVec2<Length>,
) -> LogicalVec2<LengthOrAuto> {
LogicalVec2 {
inline: self.inline.percentage_relative_to(basis.inline),
block: self.block.percentage_relative_to(basis.block),
}
}
}
impl LogicalVec2<LengthPercentageOrAuto<'_>> {
pub(crate) fn maybe_percentages_relative_to_basis(
&self,
basis: &LogicalVec2<Option<Length>>,
) -> LogicalVec2<LengthOrAuto> {
LogicalVec2 {
inline: self.inline.maybe_percentage_relative_to(basis.inline),
block: self.block.maybe_percentage_relative_to(basis.block),
}
}
}
impl LogicalVec2<Option<&'_ LengthPercentage>> {
pub fn percentages_relative_to(
pub(crate) fn percentages_relative_to(
&self,
containing_block: &ContainingBlock,
) -> LogicalVec2<Option<Length>> {
@ -183,6 +207,22 @@ impl LogicalVec2<Option<&'_ LengthPercentage>> {
}
}
impl LogicalVec2<Option<&'_ LengthPercentage>> {
pub(crate) fn maybe_percentages_relative_to_basis(
&self,
basis: &LogicalVec2<Option<Length>>,
) -> LogicalVec2<Option<Length>> {
LogicalVec2 {
inline: self
.inline
.and_then(|v| v.maybe_percentage_relative_to(basis.inline)),
block: self
.block
.and_then(|v| v.maybe_percentage_relative_to(basis.block)),
}
}
}
impl<T: Zero> LogicalRect<T> {
pub fn zero() -> Self {
Self {

View file

@ -31,10 +31,76 @@ pub use fragment_tree::FragmentTree;
use geom::AuOrAuto;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style_ext::ComputedValuesExt;
use style_ext::{Clamp, ComputedValuesExt};
use crate::geom::LogicalVec2;
/// A containing block useful for calculating inline content sizes, which may
/// have inline sizes that depend on block sizes due to aspect ratio.
pub(crate) struct IndefiniteContainingBlock<'a> {
pub size: LogicalVec2<AuOrAuto>,
pub style: &'a ComputedValues,
}
impl<'a> IndefiniteContainingBlock<'a> {
fn new_for_style(style: &'a ComputedValues) -> Self {
Self::new_for_style_and_block_size(style, AuOrAuto::Auto)
}
/// Creates an [`IndefiniteContainingBlock`] with the provided style and block size,
/// and the inline size is set to auto.
/// This is useful when finding the min-content or max-content size of an element,
/// since then we ignore its 'inline-size', 'min-inline-size' and 'max-inline-size'.
fn new_for_style_and_block_size(style: &'a ComputedValues, block_size: AuOrAuto) -> Self {
Self {
size: LogicalVec2 {
inline: AuOrAuto::Auto,
block: block_size,
},
style,
}
}
fn new_for_intrinsic_inline_size_of_child(
&self,
style: &'a ComputedValues,
auto_minimum: &LogicalVec2<Au>,
) -> Self {
let (content_box_size, content_min_size, content_max_size, _) =
style.content_box_sizes_and_padding_border_margin(&self);
let block_size = content_box_size.block.map(|v| {
v.clamp_between_extremums(
content_min_size.block.auto_is(|| auto_minimum.block),
content_max_size.block,
)
});
IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size)
}
}
impl<'a> From<&'_ ContainingBlock<'a>> for IndefiniteContainingBlock<'a> {
fn from(containing_block: &ContainingBlock<'a>) -> Self {
Self {
size: LogicalVec2 {
inline: AuOrAuto::LengthPercentage(containing_block.inline_size),
block: containing_block.block_size,
},
style: containing_block.style,
}
}
}
impl<'a> From<&'_ DefiniteContainingBlock<'a>> for IndefiniteContainingBlock<'a> {
fn from(containing_block: &DefiniteContainingBlock<'a>) -> Self {
Self {
size: containing_block
.size
.map(|v| AuOrAuto::LengthPercentage(*v)),
style: containing_block.style,
}
}
}
pub struct ContainingBlock<'a> {
inline_size: Au,
block_size: AuOrAuto,
@ -47,6 +113,23 @@ impl<'a> ContainingBlock<'a> {
}
}
impl<'a> TryFrom<&'_ IndefiniteContainingBlock<'a>> for ContainingBlock<'a> {
type Error = &'static str;
fn try_from(
indefinite_containing_block: &IndefiniteContainingBlock<'a>,
) -> Result<Self, Self::Error> {
match indefinite_containing_block.size.inline {
AuOrAuto::Auto => Err("ContainingBlock doesn't accept auto inline sizes"),
AuOrAuto::LengthPercentage(inline_size) => Ok(ContainingBlock {
inline_size,
block_size: indefinite_containing_block.size.block,
style: indefinite_containing_block.style,
}),
}
}
}
struct DefiniteContainingBlock<'a> {
size: LogicalVec2<Au>,
style: &'a ComputedValues,

View file

@ -27,7 +27,7 @@ use crate::geom::{
PhysicalPoint, PhysicalRect, ToLogical,
};
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use crate::{ContainingBlock, DefiniteContainingBlock};
use crate::{ContainingBlock, DefiniteContainingBlock, IndefiniteContainingBlock};
#[derive(Debug, Serialize)]
pub(crate) struct AbsolutelyPositionedBox {
@ -578,8 +578,16 @@ impl HoistedAbsolutelyPositionedBox {
let margin_sum = inline_axis.margin_start + inline_axis.margin_end;
let available_size =
cbis - anchor - pbm.padding_border_sums.inline - margin_sum;
let style = non_replaced.style.clone();
let containing_block_for_children =
IndefiniteContainingBlock::from(containing_block)
.new_for_intrinsic_inline_size_of_child(
&style,
&LogicalVec2::zero(),
);
non_replaced
.inline_content_sizes(layout_context)
.inline_content_sizes(layout_context, &containing_block_for_children)
.shrink_to_fit(available_size)
});

View file

@ -29,8 +29,8 @@ use crate::dom::NodeExt;
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::sizing::ContentSizes;
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::{AuOrAuto, ContainingBlock};
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
#[derive(Debug, Serialize)]
pub(crate) struct ReplacedContent {
@ -238,7 +238,7 @@ impl ReplacedContent {
LogicalVec2::from_physical_size(&intrinsic_size, style.effective_writing_mode())
}
pub fn inline_size_over_block_size_intrinsic_ratio(
pub(crate) fn inline_size_over_block_size_intrinsic_ratio(
&self,
style: &ComputedValues,
) -> Option<CSSFloat> {
@ -251,11 +251,16 @@ impl ReplacedContent {
})
}
pub fn inline_content_sizes(&self, style: &ComputedValues) -> ContentSizes {
pub fn inline_content_sizes(
&self,
_: &LayoutContext,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
// FIXME: min/max-content of replaced elements is not defined in
// https://dbaron.org/css/intrinsic/
// This seems sensible?
self.flow_relative_intrinsic_size(style)
self.flow_relative_intrinsic_size(containing_block_for_children.style)
.inline
.unwrap_or(Au::zero())
.into()
@ -331,6 +336,18 @@ impl ReplacedContent {
}
}
pub(crate) fn preferred_aspect_ratio(
&self,
containing_block: &IndefiniteContainingBlock,
style: &ComputedValues,
) -> Option<AspectRatio> {
style.preferred_aspect_ratio(
self.inline_size_over_block_size_intrinsic_ratio(style),
containing_block.try_into().ok().as_ref(),
containing_block.style.effective_writing_mode(),
)
}
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
///
@ -345,10 +362,7 @@ impl ReplacedContent {
) -> LogicalVec2<Au> {
let mode = style.effective_writing_mode();
let intrinsic_size = self.flow_relative_intrinsic_size(style);
let intrinsic_ratio = style.preferred_aspect_ratio(
self.inline_size_over_block_size_intrinsic_ratio(style),
containing_block,
);
let intrinsic_ratio = self.preferred_aspect_ratio(&containing_block.into(), style);
let box_size = box_size.unwrap_or(
style

View file

@ -8,13 +8,11 @@ use std::ops::{Add, AddAssign};
use app_units::Au;
use serde::Serialize;
use style::logical_geometry::WritingMode;
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style::Zero;
use crate::style_ext::{Clamp, ComputedValuesExt};
use crate::{AuOrAuto, IndefiniteContainingBlock, LogicalVec2};
#[derive(PartialEq)]
pub(crate) enum IntrinsicSizingMode {
@ -111,70 +109,31 @@ impl From<Au> for ContentSizes {
pub(crate) fn outer_inline(
style: &ComputedValues,
containing_block_writing_mode: WritingMode,
get_content_size: impl FnOnce() -> ContentSizes,
get_auto_minimum: impl FnOnce() -> Au,
containing_block: &IndefiniteContainingBlock,
auto_minimum: &LogicalVec2<Au>,
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> ContentSizes,
) -> ContentSizes {
let padding = style.padding(containing_block_writing_mode);
let border = style.border_width(containing_block_writing_mode);
let margin = style.margin(containing_block_writing_mode);
// For margins and paddings, a cyclic percentage is resolved against zero
// for determining intrinsic size contributions.
// https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution
let zero = Length::zero();
let pb_lengths = Au::from(
border.inline_sum() +
padding.inline_start.percentage_relative_to(zero) +
padding.inline_end.percentage_relative_to(zero),
);
let mut m_lengths = zero;
if let Some(m) = margin.inline_start.non_auto() {
m_lengths += m.percentage_relative_to(zero)
}
if let Some(m) = margin.inline_end.non_auto() {
m_lengths += m.percentage_relative_to(zero)
}
let box_sizing = style.get_position().box_sizing;
let inline_size = style
.box_size(containing_block_writing_mode)
.inline
.non_auto()
// Percentages for 'width' are treated as 'auto'
.and_then(|lp| lp.to_length());
let min_inline_size = style
.min_box_size(containing_block_writing_mode)
.inline
// Percentages for 'min-width' are treated as zero
.percentage_relative_to(zero)
.map(Au::from)
.auto_is(get_auto_minimum);
let max_inline_size = style
.max_box_size(containing_block_writing_mode)
.inline
// Percentages for 'max-width' are treated as 'none'
.and_then(|lp| lp.to_length())
.map(Au::from);
let clamp = |l: Au| l.clamp_between_extremums(min_inline_size, max_inline_size);
let border_box_sizes = match inline_size {
Some(non_auto) => {
let clamped = clamp(non_auto.into());
let border_box_size = match box_sizing {
BoxSizing::ContentBox => clamped + pb_lengths,
BoxSizing::BorderBox => clamped,
let (content_box_size, content_min_size, content_max_size, pbm) =
style.content_box_sizes_and_padding_border_margin(containing_block);
let content_min_size = LogicalVec2 {
inline: content_min_size.inline.auto_is(|| auto_minimum.inline),
block: content_min_size.block.auto_is(|| auto_minimum.block),
};
border_box_size.into()
let pbm_inline_sum = pbm.padding_border_sums.inline +
pbm.margin.inline_start.auto_is(Au::zero) +
pbm.margin.inline_end.auto_is(Au::zero);
let adjust = |v: Au| {
v.clamp_between_extremums(content_min_size.inline, content_max_size.inline) + pbm_inline_sum
};
match content_box_size.inline {
AuOrAuto::LengthPercentage(inline_size) => adjust(inline_size).into(),
AuOrAuto::Auto => {
let block_size = content_box_size
.block
.map(|v| v.clamp_between_extremums(content_min_size.block, content_max_size.block));
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size);
get_content_size(&containing_block_for_children).map(adjust)
},
None => get_content_size().map(|content_box_size| {
match box_sizing {
// Clamp to 'min-width' and 'max-width', which are sizing the…
BoxSizing::ContentBox => clamp(content_box_size) + pb_lengths,
BoxSizing::BorderBox => clamp(content_box_size + pb_lengths),
}
}),
};
border_box_sizes.map(|s| s + m_lengths.into())
}

View file

@ -30,7 +30,7 @@ use crate::geom::{
AuOrAuto, LengthOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides,
PhysicalSize,
};
use crate::ContainingBlock;
use crate::{ContainingBlock, IndefiniteContainingBlock};
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum Display {
@ -233,11 +233,25 @@ pub(crate) trait ComputedValuesExt {
box_size: LogicalVec2<Option<Length>>,
pbm: &PaddingBorderMargin,
) -> LogicalVec2<Option<Length>>;
fn content_box_sizes_and_padding_border_margin(
&self,
containing_block: &IndefiniteContainingBlock,
) -> (
LogicalVec2<AuOrAuto>,
LogicalVec2<AuOrAuto>,
LogicalVec2<Option<Au>>,
PaddingBorderMargin,
);
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin;
fn padding_border_margin_for_intrinsic_size(
&self,
writing_mode: WritingMode,
) -> 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,
@ -263,7 +277,8 @@ pub(crate) trait ComputedValuesExt {
fn preferred_aspect_ratio(
&self,
natural_aspect_ratio: Option<CSSFloat>,
containing_block: &ContainingBlock,
containing_block: Option<&ContainingBlock>,
containing_block_writing_mode: WritingMode,
) -> Option<AspectRatio>;
fn background_is_transparent(&self) -> bool;
fn get_webrender_primitive_flags(&self) -> wr::PrimitiveFlags;
@ -431,6 +446,49 @@ impl ComputedValuesExt for ComputedValues {
}
}
fn content_box_sizes_and_padding_border_margin(
&self,
containing_block: &IndefiniteContainingBlock,
) -> (
LogicalVec2<AuOrAuto>,
LogicalVec2<AuOrAuto>,
LogicalVec2<Option<Au>>,
PaddingBorderMargin,
) {
// <https://drafts.csswg.org/css-sizing-3/#cyclic-percentage-contribution>
// 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(|v| v.non_auto().map(Into::into));
let containing_block_size_auto_is_zero =
containing_block_size.map(|v| v.unwrap_or_else(Length::zero));
let writing_mode = self.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)
.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 = self
.min_box_size(writing_mode)
.percentages_relative_to_basis(&containing_block_size_auto_is_zero);
let content_min_size = self
.content_min_box_size_for_min_size(min_size, &pbm)
.map(|v| v.map(Au::from));
let max_size = self
.max_box_size(writing_mode)
.maybe_percentages_relative_to_basis(&containing_block_size);
let content_max_size = self
.content_max_box_size_for_max_size(max_size, &pbm)
.map(|v| v.map(Au::from));
(content_box_size, content_min_size, content_max_size, pbm)
}
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin {
let cbis = containing_block.inline_size;
let padding = self
@ -473,6 +531,30 @@ impl ComputedValuesExt for ComputedValues {
}
}
fn padding_border_margin_with_writing_mode_and_containing_block_inline_size(
&self,
writing_mode: WritingMode,
containing_block_inline_size: Au,
) -> PaddingBorderMargin {
let containing_block_inline_size = containing_block_inline_size.into();
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()).into(),
block: (padding.block_sum() + border.block_sum()).into(),
},
padding: padding.into(),
border: border.into(),
margin: margin.map(|margin_side| margin_side.map(Into::into)),
}
}
fn padding(
&self,
containing_block_writing_mode: WritingMode,
@ -677,7 +759,8 @@ impl ComputedValuesExt for ComputedValues {
fn preferred_aspect_ratio(
&self,
natural_aspect_ratio: Option<CSSFloat>,
containing_block: &ContainingBlock,
containing_block: Option<&ContainingBlock>,
containing_block_writing_mode: WritingMode,
) -> Option<AspectRatio> {
let GenericAspectRatio {
auto,
@ -728,7 +811,12 @@ impl ComputedValuesExt for ComputedValues {
let box_sizing_adjustment = match self.clone_box_sizing() {
BoxSizing::ContentBox => LogicalVec2::zero(),
BoxSizing::BorderBox => {
self.padding_border_margin(containing_block)
match containing_block {
Some(containing_block) => self.padding_border_margin(containing_block),
None => self.padding_border_margin_for_intrinsic_size(
containing_block_writing_mode,
),
}
.padding_border_sums
},
};

View file

@ -35,7 +35,7 @@ use crate::positioned::{relative_adjustement, PositioningContext, PositioningCon
use crate::sizing::ContentSizes;
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::table::TableSlotCoordinates;
use crate::ContainingBlock;
use crate::{ContainingBlock, IndefiniteContainingBlock};
/// A result of a final or speculative layout of a single cell in
/// the table. Note that this is only done for slots that are not
@ -201,10 +201,10 @@ impl<'a> TableLayout<'a> {
let (size, min_size, max_size) =
get_outer_sizes_from_style(&cell.style, writing_mode, &padding_border_sums);
let mut inline_content_sizes = cell
.contents
.contents
.inline_content_sizes(layout_context, writing_mode);
let mut inline_content_sizes = cell.contents.contents.inline_content_sizes(
layout_context,
&IndefiniteContainingBlock::new_for_style(&cell.style),
);
inline_content_sizes.min_content += padding_border_sums.inline;
inline_content_sizes.max_content += padding_border_sums.inline;
@ -677,13 +677,7 @@ impl<'a> TableLayout<'a> {
.captions
.iter()
.map(|caption| {
let size;
let min_size;
let max_size;
let padding_border_sums;
let size_is_auto;
{
let context = caption.context.borrow();
let mut context = caption.context.borrow_mut();
let padding = context
.style
.padding(writing_mode)
@ -695,34 +689,30 @@ impl<'a> TableLayout<'a> {
.percentages_relative_to(Length::zero())
.auto_is(Length::zero);
padding_border_sums = LogicalVec2 {
let padding_border_sums = LogicalVec2 {
inline: (padding.inline_sum() + border.inline_sum() + margin.inline_sum())
.into(),
block: (padding.block_sum() + border.block_sum() + margin.block_sum())
.into(),
block: (padding.block_sum() + border.block_sum() + margin.block_sum()).into(),
};
(size, min_size, max_size) = get_outer_sizes_from_style(
&context.style,
writing_mode,
&padding_border_sums,
);
size_is_auto = context.style.box_size(writing_mode).inline.is_auto();
}
let (size, min_size, max_size) =
get_outer_sizes_from_style(&context.style, writing_mode, &padding_border_sums);
let size_is_auto = context.style.box_size(writing_mode).inline.is_auto();
// If an inline size is defined it should serve as the upper limit and lower limit
// of the caption inline size.
let inline_size = if !size_is_auto {
if !size_is_auto {
size.inline
} else {
let inline_content_sizes = caption
.context
.borrow_mut()
.inline_content_sizes(layout_context);
let style = context.style.clone();
let inline_content_sizes = context.inline_content_sizes(
layout_context,
&IndefiniteContainingBlock::new_for_style(&style),
);
inline_content_sizes.min_content + padding_border_sums.inline
};
inline_size.min(max_size.inline).max(min_size.inline)
}
.min(max_size.inline)
.max(min_size.inline)
})
.max()
.unwrap_or_default()
@ -2432,8 +2422,9 @@ impl Table {
pub(crate) fn inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
writing_mode: WritingMode,
containing_block_for_children: &IndefiniteContainingBlock,
) -> ContentSizes {
let writing_mode = containing_block_for_children.style.effective_writing_mode();
let mut layout = TableLayout::new(self);
let mut table_content_sizes = layout.compute_grid_min_max(layout_context, writing_mode);

View file

@ -176439,6 +176439,19 @@
{}
]
],
"percentage-padding-005.html": [
"928286a590407bd5607fe4797b19be3b4ecb14d8",
[
null,
[
[
"/css/reference/ref-filled-green-100px-square-only.html",
"=="
]
],
{}
]
],
"percentage-size-subitems-001.html": [
"70f3953052a3a770c6cd15ee169607a00fc452b0",
[

View file

@ -1,2 +0,0 @@
[flex-basis-011.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[flex-minimum-height-flex-items-015.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[flexbox-flex-direction-column-percentage-ignored.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[item-with-max-height-and-scrollbar.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[nested-flex-image-loading-invalidates-intrinsic-sizes.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[percentage-heights-014.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[position-fixed-001.html]
expected: FAIL

View file

@ -1,3 +0,0 @@
[aspect-ratio-affects-container-width-when-height-changes.html]
[#container 1]
expected: FAIL

View file

@ -1,2 +0,0 @@
[intrinsic-percent-replaced-001.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[intrinsic-percent-replaced-dynamic-002.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[intrinsic-percent-replaced-dynamic-003.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[intrinsic-percent-replaced-dynamic-004.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[intrinsic-percent-replaced-dynamic-006.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[intrinsic-percent-replaced-dynamic-009.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[calc-rounding-002.html]
expected: FAIL

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#item-margins">
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#intrinsic-main-sizes">
<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
<meta name="assert" content="The flex container becomes 100px tall because the padding percentage of the item resolves against its width.">
<p>Test passes if there is a filled green square.</p>
<div style="display: flex; background: green; flex-direction: column; width: 100px;">
<div style="width: 100px; padding-bottom: 100%"></div>
</div>