mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01: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
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue