mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Avoid recomputing inline_content_sizes() when not needed (#33806)
The result of `inline_content_sizes()` may depend on the block size of the containing block, so we were always recomputing in case we got a different block size. However, if no content has a vertical percentage or stretches vertically, then we don't need to recompute: the result will be the same anyways. Signed-off-by: Oriol Brufau <obrufau@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
821bed1d11
commit
b9ed45942d
12 changed files with 257 additions and 139 deletions
|
@ -171,7 +171,7 @@ where
|
|||
let non_replaced = NonReplacedFormattingContext {
|
||||
base_fragment_info: info.into(),
|
||||
style: info.style.clone(),
|
||||
content_sizes: None,
|
||||
content_sizes_result: None,
|
||||
contents: NonReplacedFormattingContextContents::Flow(
|
||||
block_formatting_context,
|
||||
),
|
||||
|
|
|
@ -31,7 +31,7 @@ use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2};
|
|||
use crate::positioned::{
|
||||
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
|
||||
};
|
||||
use crate::sizing::{ContentSizes, IntrinsicSizingMode};
|
||||
use crate::sizing::{ContentSizes, InlineContentSizesResult, IntrinsicSizingMode};
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
|
@ -336,6 +336,7 @@ struct FlexItemBoxInlineContentSizesInfo {
|
|||
min_flex_factors: DesiredFlexFractionAndGrowOrShrinkFactor,
|
||||
max_flex_factors: DesiredFlexFractionAndGrowOrShrinkFactor,
|
||||
min_content_main_size_for_multiline_container: Au,
|
||||
depends_on_block_constraints: bool,
|
||||
}
|
||||
|
||||
impl FlexContainer {
|
||||
|
@ -348,7 +349,7 @@ impl FlexContainer {
|
|||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
match self.config.flex_axis {
|
||||
FlexAxis::Row => {
|
||||
self.main_content_sizes(layout_context, containing_block_for_children, || {
|
||||
|
@ -367,14 +368,15 @@ impl FlexContainer {
|
|||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
// <https://drafts.csswg.org/css-flexbox/#intrinsic-cross-sizes>
|
||||
assert_eq!(
|
||||
self.config.flex_axis,
|
||||
FlexAxis::Column,
|
||||
"The cross axis should be the inline one"
|
||||
);
|
||||
let mut content_sizes = ContentSizes::zero();
|
||||
let mut sizes = ContentSizes::zero();
|
||||
let mut depends_on_block_constraints = false;
|
||||
for kid in self.children.iter() {
|
||||
let kid = &mut *kid.borrow_mut();
|
||||
match kid {
|
||||
|
@ -383,17 +385,22 @@ impl FlexContainer {
|
|||
// columns, and sum the column sizes and gaps.
|
||||
// TODO: Use the proper automatic minimum size.
|
||||
let ifc = &mut item.independent_formatting_context;
|
||||
content_sizes.max_assign(ifc.outer_inline_content_sizes(
|
||||
let result = ifc.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block_for_children,
|
||||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
));
|
||||
);
|
||||
sizes.max_assign(result.sizes);
|
||||
depends_on_block_constraints |= result.depends_on_block_constraints;
|
||||
},
|
||||
FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => {},
|
||||
}
|
||||
}
|
||||
content_sizes
|
||||
InlineContentSizesResult {
|
||||
sizes,
|
||||
depends_on_block_constraints,
|
||||
}
|
||||
}
|
||||
|
||||
fn main_content_sizes<'a>(
|
||||
|
@ -401,7 +408,7 @@ impl FlexContainer {
|
|||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
flex_context_getter: impl Fn() -> &'a FlexContext<'a>,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
// - TODO: calculate intrinsic cross sizes when container is a column
|
||||
// (and check for ‘writing-mode’?)
|
||||
// - TODO: Collapsed flex items need to be skipped for intrinsic size calculation.
|
||||
|
@ -483,6 +490,7 @@ impl FlexContainer {
|
|||
} else {
|
||||
Au::zero()
|
||||
};
|
||||
let mut container_depends_on_block_constraints = false;
|
||||
|
||||
for FlexItemBoxInlineContentSizesInfo {
|
||||
outer_flex_base_size,
|
||||
|
@ -492,6 +500,7 @@ impl FlexContainer {
|
|||
min_flex_factors,
|
||||
max_flex_factors,
|
||||
min_content_main_size_for_multiline_container,
|
||||
depends_on_block_constraints,
|
||||
} in item_infos.iter()
|
||||
{
|
||||
// > 4. Add each item’s flex base size to the product of its flex grow factor (scaled flex shrink
|
||||
|
@ -528,11 +537,16 @@ impl FlexContainer {
|
|||
container_min_content_size
|
||||
.max_assign(*min_content_main_size_for_multiline_container);
|
||||
}
|
||||
|
||||
container_depends_on_block_constraints |= depends_on_block_constraints;
|
||||
}
|
||||
|
||||
ContentSizes {
|
||||
min_content: container_min_content_size,
|
||||
max_content: container_max_content_size,
|
||||
InlineContentSizesResult {
|
||||
sizes: ContentSizes {
|
||||
min_content: container_min_content_size,
|
||||
max_content: container_max_content_size,
|
||||
},
|
||||
depends_on_block_constraints: container_depends_on_block_constraints,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,6 +587,7 @@ impl FlexContainer {
|
|||
FlexAxis::Row => containing_block.inline_size,
|
||||
FlexAxis::Column => containing_block.block_size.auto_is(|| {
|
||||
self.main_content_sizes(layout_context, &containing_block.into(), || &flex_context)
|
||||
.sizes
|
||||
.max_content
|
||||
}),
|
||||
};
|
||||
|
@ -1023,7 +1038,7 @@ impl<'a> FlexItem<'a> {
|
|||
flex_context.config.flex_axis,
|
||||
);
|
||||
|
||||
let (content_box_size, min_size, max_size, pbm) = box_
|
||||
let (content_box_size, min_size, max_size, pbm, _) = box_
|
||||
.style()
|
||||
.content_box_sizes_and_padding_border_margin_deprecated(&containing_block.into());
|
||||
|
||||
|
@ -1735,6 +1750,7 @@ impl FlexItem<'_> {
|
|||
&containing_block_for_children,
|
||||
&containing_block.into(),
|
||||
)
|
||||
.sizes
|
||||
.map(|size| {
|
||||
size.clamp_between_extremums(
|
||||
self.content_min_size.cross,
|
||||
|
@ -2008,7 +2024,7 @@ impl FlexItemBox {
|
|||
let cross_axis_is_item_block_axis =
|
||||
cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis);
|
||||
|
||||
let (content_box_size, content_min_size, content_max_size, pbm) =
|
||||
let (content_box_size, content_min_size, content_max_size, pbm, _) =
|
||||
style.content_box_sizes_and_padding_border_margin_deprecated(containing_block);
|
||||
let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding);
|
||||
let border = main_start_cross_start.sides_to_flex_relative(pbm.border);
|
||||
|
@ -2069,17 +2085,23 @@ impl FlexItemBox {
|
|||
|
||||
// Compute the min-content and max-content contributions of the item.
|
||||
// <https://drafts.csswg.org/css-flexbox/#intrinsic-item-contributions>
|
||||
let content_contribution_sizes = match flex_axis {
|
||||
FlexAxis::Row => self
|
||||
.independent_formatting_context
|
||||
.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&content_min_size_no_auto,
|
||||
item_with_auto_cross_size_stretches_to_container_size,
|
||||
),
|
||||
FlexAxis::Column => self
|
||||
.layout_for_block_content_size(
|
||||
let (content_contribution_sizes, depends_on_block_constraints) = match flex_axis {
|
||||
FlexAxis::Row => {
|
||||
let InlineContentSizesResult {
|
||||
sizes,
|
||||
depends_on_block_constraints,
|
||||
} = self
|
||||
.independent_formatting_context
|
||||
.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&content_min_size_no_auto,
|
||||
item_with_auto_cross_size_stretches_to_container_size,
|
||||
);
|
||||
(sizes, depends_on_block_constraints)
|
||||
},
|
||||
FlexAxis::Column => {
|
||||
let size = self.layout_for_block_content_size(
|
||||
flex_context_getter(),
|
||||
&pbm,
|
||||
content_box_size,
|
||||
|
@ -2087,8 +2109,9 @@ impl FlexItemBox {
|
|||
content_max_size,
|
||||
item_with_auto_cross_size_stretches_to_container_size,
|
||||
IntrinsicSizingMode::Contribution,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
(size.into(), true)
|
||||
},
|
||||
};
|
||||
|
||||
let content_box_size = flex_axis.vec2_to_flex_relative(content_box_size);
|
||||
|
@ -2155,6 +2178,7 @@ impl FlexItemBox {
|
|||
min_flex_factors,
|
||||
max_flex_factors,
|
||||
min_content_main_size_for_multiline_container,
|
||||
depends_on_block_constraints,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2282,6 +2306,7 @@ impl FlexItemBox {
|
|||
&containing_block_for_children,
|
||||
containing_block,
|
||||
)
|
||||
.sizes
|
||||
.min_content
|
||||
} else {
|
||||
block_content_size_callback(self)
|
||||
|
@ -2444,6 +2469,7 @@ impl FlexItemBox {
|
|||
&containing_block_for_children,
|
||||
containing_block,
|
||||
)
|
||||
.sizes
|
||||
.max_content;
|
||||
if let Some(ratio) = ratio {
|
||||
max_content.clamp_between_extremums(
|
||||
|
@ -2522,11 +2548,12 @@ impl FlexItemBox {
|
|||
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,
|
||||
);
|
||||
inline_content_sizes
|
||||
non_replaced
|
||||
.inline_content_sizes(
|
||||
flex_context.layout_context,
|
||||
&containing_block_for_children,
|
||||
)
|
||||
.sizes
|
||||
.shrink_to_fit(containing_block_inline_size_minus_pbm)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -126,7 +126,7 @@ use crate::fragment_tree::{
|
|||
};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::ContentSizes;
|
||||
use crate::sizing::{ContentSizes, InlineContentSizesResult};
|
||||
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
|
@ -1565,7 +1565,7 @@ impl InlineFormattingContext {
|
|||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
ContentSizesComputation::compute(self, layout_context, containing_block_for_children)
|
||||
}
|
||||
|
||||
|
@ -2184,16 +2184,23 @@ struct ContentSizesComputation<'layout_data> {
|
|||
/// Stack of ending padding, margin, and border to add to the length
|
||||
/// when an inline box finishes.
|
||||
ending_inline_pbm_stack: Vec<Au>,
|
||||
depends_on_block_constraints: bool,
|
||||
}
|
||||
|
||||
impl<'layout_data> ContentSizesComputation<'layout_data> {
|
||||
fn traverse(mut self, inline_formatting_context: &InlineFormattingContext) -> ContentSizes {
|
||||
fn traverse(
|
||||
mut self,
|
||||
inline_formatting_context: &InlineFormattingContext,
|
||||
) -> InlineContentSizesResult {
|
||||
for inline_item in inline_formatting_context.inline_items.iter() {
|
||||
self.process_item(&mut inline_item.borrow_mut(), inline_formatting_context);
|
||||
}
|
||||
|
||||
self.forced_line_break();
|
||||
self.paragraph
|
||||
InlineContentSizesResult {
|
||||
sizes: self.paragraph,
|
||||
depends_on_block_constraints: self.depends_on_block_constraints,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_item(
|
||||
|
@ -2299,12 +2306,16 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
|||
self.line_break_opportunity();
|
||||
}
|
||||
|
||||
let outer = atomic.outer_inline_content_sizes(
|
||||
let InlineContentSizesResult {
|
||||
sizes: outer,
|
||||
depends_on_block_constraints,
|
||||
} = atomic.outer_inline_content_sizes(
|
||||
self.layout_context,
|
||||
self.containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
);
|
||||
self.depends_on_block_constraints |= depends_on_block_constraints;
|
||||
|
||||
if !inline_formatting_context
|
||||
.next_character_prevents_soft_wrap_opportunity(*offset_in_text)
|
||||
|
@ -2356,7 +2367,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
|||
inline_formatting_context: &InlineFormattingContext,
|
||||
layout_context: &'layout_data LayoutContext,
|
||||
containing_block: &'layout_data IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
Self {
|
||||
layout_context,
|
||||
containing_block,
|
||||
|
@ -2366,6 +2377,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
|||
had_content_yet_for_min_content: false,
|
||||
had_content_yet_for_max_content: false,
|
||||
ending_inline_pbm_stack: Vec::new(),
|
||||
depends_on_block_constraints: false,
|
||||
}
|
||||
.traverse(inline_formatting_context)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ use crate::geom::{
|
|||
};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
||||
use crate::replaced::ReplacedContent;
|
||||
use crate::sizing::{self, ContentSizes};
|
||||
use crate::sizing::{self, ContentSizes, InlineContentSizesResult};
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
|
@ -234,7 +234,7 @@ impl OutsideMarker {
|
|||
&IndefiniteContainingBlock::new_for_style(&self.marker_style),
|
||||
);
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size: content_sizes.max_content,
|
||||
inline_size: content_sizes.sizes.max_content,
|
||||
block_size: AuOrAuto::auto(),
|
||||
style: &self.marker_style,
|
||||
};
|
||||
|
@ -361,28 +361,29 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
|||
boxes: &[ArcRefCell<BlockLevelBox>],
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| {
|
||||
match &mut *box_.borrow_mut() {
|
||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
|
||||
BlockLevelBox::OutsideMarker { .. } => None,
|
||||
BlockLevelBox::OutOfFlowFloatBox(ref mut float_box) => {
|
||||
let size = float_box
|
||||
.contents
|
||||
.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
)
|
||||
.max(ContentSizes::zero());
|
||||
let inline_content_sizes_result = float_box.contents.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
);
|
||||
let style_box = &float_box.contents.style().get_box();
|
||||
Some((size, style_box.float, style_box.clear))
|
||||
Some((
|
||||
inline_content_sizes_result,
|
||||
style_box.float,
|
||||
style_box.clear,
|
||||
))
|
||||
},
|
||||
BlockLevelBox::SameFormattingContextBlock {
|
||||
style, contents, ..
|
||||
} => {
|
||||
let size = sizing::outer_inline(
|
||||
let inline_content_sizes_result = sizing::outer_inline(
|
||||
style,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
|
@ -390,30 +391,34 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
|||
|containing_block_for_children| {
|
||||
contents.inline_content_sizes(layout_context, containing_block_for_children)
|
||||
},
|
||||
)
|
||||
.max(ContentSizes::zero());
|
||||
);
|
||||
// A block in the same BFC can overlap floats, it's not moved next to them,
|
||||
// so we shouldn't add its size to the size of the floats.
|
||||
// Instead, we treat it like an independent block with 'clear: both'.
|
||||
Some((size, Float::None, Clear::Both))
|
||||
Some((inline_content_sizes_result, Float::None, Clear::Both))
|
||||
},
|
||||
BlockLevelBox::Independent(ref mut independent) => {
|
||||
let size = independent
|
||||
.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
)
|
||||
.max(ContentSizes::zero());
|
||||
Some((size, Float::None, independent.style().get_box().clear))
|
||||
let inline_content_sizes_result = independent.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
);
|
||||
Some((
|
||||
inline_content_sizes_result,
|
||||
Float::None,
|
||||
independent.style().get_box().clear,
|
||||
))
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/// When iterating the block-level boxes to compute the inline content sizes,
|
||||
/// this struct contains the data accumulated up to the current box.
|
||||
#[derive(Default)]
|
||||
struct AccumulatedData {
|
||||
/// Whether the inline size depends on the block one.
|
||||
depends_on_block_constraints: bool,
|
||||
/// The maximum size seen so far, not including trailing uncleared floats.
|
||||
max_size: ContentSizes,
|
||||
/// The size of the trailing uncleared floats with 'float: left'.
|
||||
|
@ -447,37 +452,44 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
|||
}
|
||||
}
|
||||
|
||||
let accumulate = |mut data: AccumulatedData, (size, float, clear)| {
|
||||
data.clear_floats(clear);
|
||||
match float {
|
||||
Float::Left => data.left_floats = data.left_floats.union(&size),
|
||||
Float::Right => data.right_floats = data.right_floats.union(&size),
|
||||
Float::None => {
|
||||
data.max_size = data
|
||||
.max_size
|
||||
.max(data.left_floats.union(&data.right_floats).union(&size));
|
||||
data.left_floats = ContentSizes::zero();
|
||||
data.right_floats = ContentSizes::zero();
|
||||
},
|
||||
}
|
||||
data
|
||||
};
|
||||
let zero = AccumulatedData {
|
||||
max_size: ContentSizes::zero(),
|
||||
left_floats: ContentSizes::zero(),
|
||||
right_floats: ContentSizes::zero(),
|
||||
};
|
||||
let accumulate =
|
||||
|mut data: AccumulatedData,
|
||||
(inline_content_sizes_result, float, clear): (InlineContentSizesResult, _, _)| {
|
||||
let size = inline_content_sizes_result.sizes.max(ContentSizes::zero());
|
||||
let depends_on_block_constraints =
|
||||
inline_content_sizes_result.depends_on_block_constraints;
|
||||
data.depends_on_block_constraints |= depends_on_block_constraints;
|
||||
data.clear_floats(clear);
|
||||
match float {
|
||||
Float::Left => data.left_floats = data.left_floats.union(&size),
|
||||
Float::Right => data.right_floats = data.right_floats.union(&size),
|
||||
Float::None => {
|
||||
data.max_size = data
|
||||
.max_size
|
||||
.max(data.left_floats.union(&data.right_floats).union(&size));
|
||||
data.left_floats = ContentSizes::zero();
|
||||
data.right_floats = ContentSizes::zero();
|
||||
},
|
||||
}
|
||||
data
|
||||
};
|
||||
let data = if layout_context.use_rayon {
|
||||
boxes
|
||||
.par_iter()
|
||||
.filter_map(get_box_info)
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.fold(zero, accumulate)
|
||||
.fold(AccumulatedData::default(), accumulate)
|
||||
} else {
|
||||
boxes.iter().filter_map(get_box_info).fold(zero, accumulate)
|
||||
boxes
|
||||
.iter()
|
||||
.filter_map(get_box_info)
|
||||
.fold(AccumulatedData::default(), accumulate)
|
||||
};
|
||||
data.max_size_including_uncleared_floats()
|
||||
InlineContentSizesResult {
|
||||
depends_on_block_constraints: data.depends_on_block_constraints,
|
||||
sizes: data.max_size_including_uncleared_floats(),
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockContainer {
|
||||
|
@ -512,7 +524,7 @@ impl BlockContainer {
|
|||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
match &self {
|
||||
Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes(
|
||||
boxes,
|
||||
|
@ -1984,6 +1996,7 @@ impl IndependentFormattingContext {
|
|||
);
|
||||
non_replaced
|
||||
.inline_content_sizes(layout_context, &containing_block_for_children)
|
||||
.sizes
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#float-width
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, FragmentFlag
|
|||
use crate::geom::LogicalSides;
|
||||
use crate::positioned::PositioningContext;
|
||||
use crate::replaced::ReplacedContent;
|
||||
use crate::sizing::{self, ContentSizes};
|
||||
use crate::sizing::{self, InlineContentSizesResult};
|
||||
use crate::style_ext::{AspectRatio, DisplayInside};
|
||||
use crate::table::Table;
|
||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock, LogicalVec2};
|
||||
|
@ -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<(AuOrAuto, ContentSizes)>,
|
||||
pub content_sizes_result: Option<(AuOrAuto, InlineContentSizesResult)>,
|
||||
pub contents: NonReplacedFormattingContextContents,
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ impl IndependentFormattingContext {
|
|||
Self::NonReplaced(NonReplacedFormattingContext {
|
||||
style: Arc::clone(&node_and_style_info.style),
|
||||
base_fragment_info,
|
||||
content_sizes: None,
|
||||
content_sizes_result: None,
|
||||
contents,
|
||||
})
|
||||
},
|
||||
|
@ -187,7 +187,7 @@ impl IndependentFormattingContext {
|
|||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
match self {
|
||||
Self::NonReplaced(inner) => {
|
||||
inner.inline_content_sizes(layout_context, containing_block_for_children)
|
||||
|
@ -206,7 +206,7 @@ impl IndependentFormattingContext {
|
|||
containing_block: &IndefiniteContainingBlock,
|
||||
auto_minimum: &LogicalVec2<Au>,
|
||||
auto_block_size_stretches_to_containing_block: bool,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
match self {
|
||||
Self::NonReplaced(non_replaced) => non_replaced.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
|
@ -274,20 +274,22 @@ impl NonReplacedFormattingContext {
|
|||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
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 {
|
||||
if let Some((previous_cb_block_size, result)) = self.content_sizes_result {
|
||||
if !result.depends_on_block_constraints ||
|
||||
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
|
||||
self.content_sizes_result
|
||||
.insert((
|
||||
containing_block_for_children.size.block,
|
||||
self.contents
|
||||
|
@ -302,7 +304,7 @@ impl NonReplacedFormattingContext {
|
|||
containing_block: &IndefiniteContainingBlock,
|
||||
auto_minimum: &LogicalVec2<Au>,
|
||||
auto_block_size_stretches_to_containing_block: bool,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
sizing::outer_inline(
|
||||
&self.style.clone(),
|
||||
containing_block,
|
||||
|
@ -320,7 +322,7 @@ impl NonReplacedFormattingContextContents {
|
|||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
match self {
|
||||
Self::Flow(inner) => inner
|
||||
.contents
|
||||
|
|
|
@ -65,7 +65,7 @@ impl<'a> IndefiniteContainingBlock<'a> {
|
|||
style: &'a ComputedValues,
|
||||
auto_minimum: &LogicalVec2<Au>,
|
||||
) -> Self {
|
||||
let (content_box_size, content_min_size, content_max_size, _) =
|
||||
let (content_box_size, content_min_size, content_max_size, _, _) =
|
||||
style.content_box_sizes_and_padding_border_margin_deprecated(self);
|
||||
let block_size = content_box_size.block.map(|v| {
|
||||
v.clamp_between_extremums(
|
||||
|
|
|
@ -587,6 +587,7 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
);
|
||||
non_replaced
|
||||
.inline_content_sizes(layout_context, &containing_block_for_children)
|
||||
.sizes
|
||||
.shrink_to_fit(available_size)
|
||||
});
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ use crate::context::LayoutContext;
|
|||
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::sizing::InlineContentSizesResult;
|
||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
|
@ -263,21 +263,27 @@ impl ReplacedContent {
|
|||
_: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
preferred_aspect_ratio: Option<AspectRatio>,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
// FIXME: min/max-content of replaced elements is not defined in
|
||||
// https://dbaron.org/css/intrinsic/
|
||||
// This seems sensible?
|
||||
let block_size = containing_block_for_children.size.block;
|
||||
let inline_size = match (block_size, preferred_aspect_ratio) {
|
||||
(AuOrAuto::LengthPercentage(block_size), Some(ratio)) => {
|
||||
ratio.compute_dependent_size(Direction::Inline, block_size)
|
||||
match (block_size, preferred_aspect_ratio) {
|
||||
(AuOrAuto::LengthPercentage(block_size), Some(ratio)) => InlineContentSizesResult {
|
||||
sizes: ratio
|
||||
.compute_dependent_size(Direction::Inline, block_size)
|
||||
.into(),
|
||||
depends_on_block_constraints: true,
|
||||
},
|
||||
_ => self
|
||||
.flow_relative_intrinsic_size(containing_block_for_children.style)
|
||||
.inline
|
||||
.unwrap_or_else(Au::zero),
|
||||
};
|
||||
inline_size.into()
|
||||
_ => InlineContentSizesResult {
|
||||
sizes: self
|
||||
.flow_relative_intrinsic_size(containing_block_for_children.style)
|
||||
.inline
|
||||
.unwrap_or_else(Au::zero)
|
||||
.into(),
|
||||
depends_on_block_constraints: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_fragments(
|
||||
|
|
|
@ -118,10 +118,15 @@ pub(crate) fn outer_inline(
|
|||
containing_block: &IndefiniteContainingBlock,
|
||||
auto_minimum: &LogicalVec2<Au>,
|
||||
auto_block_size_stretches_to_containing_block: bool,
|
||||
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> ContentSizes,
|
||||
) -> ContentSizes {
|
||||
let (content_box_size, content_min_size, content_max_size, pbm) =
|
||||
style.content_box_sizes_and_padding_border_margin_deprecated(containing_block);
|
||||
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> InlineContentSizesResult,
|
||||
) -> InlineContentSizesResult {
|
||||
let (
|
||||
content_box_size,
|
||||
content_min_size,
|
||||
content_max_size,
|
||||
pbm,
|
||||
mut depends_on_block_constraints,
|
||||
) = style.content_box_sizes_and_padding_border_margin_deprecated(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),
|
||||
|
@ -132,11 +137,15 @@ pub(crate) fn outer_inline(
|
|||
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::LengthPercentage(inline_size) => InlineContentSizesResult {
|
||||
sizes: adjust(inline_size).into(),
|
||||
depends_on_block_constraints: false,
|
||||
},
|
||||
AuOrAuto::Auto => {
|
||||
let block_size = if content_box_size.block.is_auto() &&
|
||||
auto_block_size_stretches_to_containing_block
|
||||
{
|
||||
depends_on_block_constraints = true;
|
||||
let outer_block_size = containing_block.size.block;
|
||||
outer_block_size.map(|v| v - pbm.padding_border_sums.block - margin.block_sum())
|
||||
} else {
|
||||
|
@ -145,7 +154,18 @@ pub(crate) fn outer_inline(
|
|||
.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)
|
||||
let content_result = get_content_size(&containing_block_for_children);
|
||||
InlineContentSizesResult {
|
||||
sizes: content_result.sizes.map(adjust),
|
||||
depends_on_block_constraints: content_result.depends_on_block_constraints &&
|
||||
depends_on_block_constraints,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize)]
|
||||
pub(crate) struct InlineContentSizesResult {
|
||||
pub sizes: ContentSizes,
|
||||
pub depends_on_block_constraints: bool,
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use crate::dom_traversal::Contents;
|
|||
use crate::fragment_tree::FragmentFlags;
|
||||
use crate::geom::{
|
||||
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize,
|
||||
PhysicalVec, Size,
|
||||
PhysicalVec, Size, SizeKeyword,
|
||||
};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
|
@ -249,6 +249,7 @@ pub(crate) trait ComputedValuesExt {
|
|||
LogicalVec2<Size<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
PaddingBorderMargin,
|
||||
bool, /* depends_on_block_constraints */
|
||||
);
|
||||
fn content_box_sizes_and_padding_border_margin_deprecated(
|
||||
&self,
|
||||
|
@ -258,6 +259,7 @@ pub(crate) trait ComputedValuesExt {
|
|||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<Option<Au>>,
|
||||
PaddingBorderMargin,
|
||||
bool, /* depends_on_block_constraints */
|
||||
);
|
||||
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin;
|
||||
fn padding_border_margin_for_intrinsic_size(
|
||||
|
@ -499,6 +501,7 @@ impl ComputedValuesExt for ComputedValues {
|
|||
LogicalVec2<Size<Au>>,
|
||||
LogicalVec2<Size<Au>>,
|
||||
PaddingBorderMargin,
|
||||
bool, /* depends_on_block_constraints */
|
||||
) {
|
||||
// <https://drafts.csswg.org/css-sizing-3/#cyclic-percentage-contribution>
|
||||
// If max size properties or preferred size properties are set to a value containing
|
||||
|
@ -513,25 +516,45 @@ impl ComputedValuesExt for ComputedValues {
|
|||
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 box_size = self.box_size(writing_mode);
|
||||
let min_size = self.min_box_size(writing_mode);
|
||||
let max_size = self.max_box_size(writing_mode);
|
||||
let depends_on_block_constraints = |size: &Size<LengthPercentage>| {
|
||||
match size {
|
||||
// fit-content is like clamp(min-content, stretch, max-content), but currently
|
||||
// min-content and max-content have the same behavior in the block axis,
|
||||
// so there is no dependency on block constraints.
|
||||
// TODO: for flex and grid layout, min-content and max-content should be different.
|
||||
// TODO: We are assuming that Size::Initial doesn't stretch. However, it may actually
|
||||
// stretch flex and grid items depending on the CSS Align properties, in that case
|
||||
// the caller needs to take care of it.
|
||||
Size::Keyword(SizeKeyword::Stretch) => true,
|
||||
Size::Numeric(length_percentage) => length_percentage.has_percentage(),
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
let depends_on_block_constraints = depends_on_block_constraints(&box_size.block) ||
|
||||
depends_on_block_constraints(&min_size.block) ||
|
||||
depends_on_block_constraints(&max_size.block);
|
||||
let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block_size);
|
||||
let content_box_size = self
|
||||
.content_box_size_for_box_size(box_size, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let min_size = self
|
||||
.min_box_size(writing_mode)
|
||||
.percentages_relative_to_basis(&containing_block_size_auto_is_zero);
|
||||
let min_size = min_size.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 max_size = max_size.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)
|
||||
(
|
||||
content_box_size,
|
||||
content_min_size,
|
||||
content_max_size,
|
||||
pbm,
|
||||
depends_on_block_constraints,
|
||||
)
|
||||
}
|
||||
|
||||
fn content_box_sizes_and_padding_border_margin_deprecated(
|
||||
|
@ -542,14 +565,21 @@ impl ComputedValuesExt for ComputedValues {
|
|||
LogicalVec2<AuOrAuto>,
|
||||
LogicalVec2<Option<Au>>,
|
||||
PaddingBorderMargin,
|
||||
bool, /* depends_on_block_constraints */
|
||||
) {
|
||||
let (content_box_size, content_min_size, content_max_size, pbm) =
|
||||
self.content_box_sizes_and_padding_border_margin(containing_block);
|
||||
let (
|
||||
content_box_size,
|
||||
content_min_size,
|
||||
content_max_size,
|
||||
pbm,
|
||||
depends_on_block_constraints,
|
||||
) = self.content_box_sizes_and_padding_border_margin(containing_block);
|
||||
(
|
||||
content_box_size.map(Size::to_auto_or),
|
||||
content_min_size.map(Size::to_auto_or),
|
||||
content_max_size.map(Size::to_numeric),
|
||||
pbm,
|
||||
depends_on_block_constraints,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ impl Table {
|
|||
IndependentFormattingContext::NonReplaced(NonReplacedFormattingContext {
|
||||
base_fragment_info: (&anonymous_info).into(),
|
||||
style: grid_and_wrapper_style,
|
||||
content_sizes: None,
|
||||
content_sizes_result: None,
|
||||
contents: NonReplacedFormattingContextContents::Table(table),
|
||||
})
|
||||
}
|
||||
|
@ -858,7 +858,7 @@ where
|
|||
context: ArcRefCell::new(NonReplacedFormattingContext {
|
||||
style: info.style.clone(),
|
||||
base_fragment_info: info.into(),
|
||||
content_sizes: None,
|
||||
content_sizes_result: None,
|
||||
contents,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ use crate::geom::{
|
|||
Size, SizeKeyword, ToLogical, ToLogicalWithContainingBlock,
|
||||
};
|
||||
use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength};
|
||||
use crate::sizing::ContentSizes;
|
||||
use crate::sizing::{ContentSizes, InlineContentSizesResult};
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::table::TableSlotCoordinates;
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
@ -298,10 +298,13 @@ impl<'a> TableLayout<'a> {
|
|||
let mut inline_content_sizes = if is_in_fixed_mode {
|
||||
ContentSizes::zero()
|
||||
} else {
|
||||
cell.contents.contents.inline_content_sizes(
|
||||
layout_context,
|
||||
&IndefiniteContainingBlock::new_for_style(&cell.style),
|
||||
)
|
||||
cell.contents
|
||||
.contents
|
||||
.inline_content_sizes(
|
||||
layout_context,
|
||||
&IndefiniteContainingBlock::new_for_style(&cell.style),
|
||||
)
|
||||
.sizes
|
||||
};
|
||||
inline_content_sizes.min_content += padding_border_sums.inline;
|
||||
inline_content_sizes.max_content += padding_border_sums.inline;
|
||||
|
@ -784,6 +787,7 @@ impl<'a> TableLayout<'a> {
|
|||
&LogicalVec2::zero(),
|
||||
false, /* auto_block_size_stretches_to_containing_block */
|
||||
)
|
||||
.sizes
|
||||
.min_content
|
||||
})
|
||||
.max()
|
||||
|
@ -2611,7 +2615,7 @@ impl Table {
|
|||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
) -> InlineContentSizesResult {
|
||||
let writing_mode = containing_block_for_children.style.writing_mode;
|
||||
let mut layout = TableLayout::new(self);
|
||||
let mut table_content_sizes = layout.compute_grid_min_max(layout_context, writing_mode);
|
||||
|
@ -2638,7 +2642,10 @@ impl Table {
|
|||
.max_assign(caption_minimum_inline_size);
|
||||
}
|
||||
|
||||
table_content_sizes
|
||||
InlineContentSizesResult {
|
||||
sizes: table_content_sizes,
|
||||
depends_on_block_constraints: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_column_measure_for_column_at_index(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue