diff options
Diffstat (limited to 'components/layout_2020')
-rw-r--r-- | components/layout_2020/flow/inline.rs | 1 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 139 | ||||
-rw-r--r-- | components/layout_2020/flow/root.rs | 22 | ||||
-rw-r--r-- | components/layout_2020/positioned.rs | 329 |
4 files changed, 270 insertions, 221 deletions
diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 0a6fc8d87d6..82d946b42dc 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -245,7 +245,6 @@ impl InlineFormattingContext { }, }; ifc.positioning_context - .abspos .push(box_.layout(initial_start_corner, tree_rank)); }, InlineLevelBox::OutOfFlowFloatBox(_box_) => { diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 449789530e6..f524614f03d 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -18,7 +18,6 @@ use crate::{relative_adjustement, ContainingBlock}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; -use style::computed_values::position::T as Position; use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto}; use style::Zero; @@ -235,8 +234,8 @@ fn layout_block_level_children<'a>( /* float_context = */ None, ) }, - Default::default, - |left, right| left.append(right), + PositioningContext::new, + PositioningContext::append, ) .collect(); for fragment in &mut fragments { @@ -317,9 +316,7 @@ impl BlockLevelBox { )), }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { - positioning_context - .abspos - .push(box_.layout(Vec2::zero(), tree_rank)); + positioning_context.push(box_.layout(Vec2::zero(), tree_rank)); Fragment::Anonymous(AnonymousFragment::no_op( containing_block.style.writing_mode, )) @@ -433,80 +430,70 @@ fn layout_in_flow_non_replaced_block_level<'a>( min_box_size.block == Length::zero() && pb.block_end == Length::zero() && block_level_kind == BlockLevelKind::SameFormattingContextBlock; - let mut nested_positioning_context = PositioningContext { abspos: Vec::new() }; - let mut flow_layout = layout_contents( - if style.get_box().position == Position::Relative { - &mut nested_positioning_context - } else { - positioning_context - }, - &containing_block_for_children, - this_start_margin_can_collapse_with_children, - ); - let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); - if this_start_margin_can_collapse_with_children.0 { - block_margins_collapsed_with_children - .start - .adjoin_assign(&flow_layout.collapsible_margins_in_children.start); - if flow_layout - .collapsible_margins_in_children - .collapsed_through - { + + positioning_context.for_maybe_position_relative(layout_context, style, |positioning_context| { + let mut flow_layout = layout_contents( + positioning_context, + &containing_block_for_children, + this_start_margin_can_collapse_with_children, + ); + let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); + if this_start_margin_can_collapse_with_children.0 { block_margins_collapsed_with_children .start - .adjoin_assign(&std::mem::replace( - &mut flow_layout.collapsible_margins_in_children.end, - CollapsedMargin::zero(), - )); + .adjoin_assign(&flow_layout.collapsible_margins_in_children.start); + if flow_layout + .collapsible_margins_in_children + .collapsed_through + { + block_margins_collapsed_with_children + .start + .adjoin_assign(&std::mem::replace( + &mut flow_layout.collapsible_margins_in_children.end, + CollapsedMargin::zero(), + )); + } } - } - if this_end_margin_can_collapse_with_children { - block_margins_collapsed_with_children - .end - .adjoin_assign(&flow_layout.collapsible_margins_in_children.end); - } else { - flow_layout.content_block_size += flow_layout.collapsible_margins_in_children.end.solve(); - } - block_margins_collapsed_with_children.collapsed_through = - this_start_margin_can_collapse_with_children.0 && - this_end_margin_can_collapse_with_children && + if this_end_margin_can_collapse_with_children { + block_margins_collapsed_with_children + .end + .adjoin_assign(&flow_layout.collapsible_margins_in_children.end); + } else { + flow_layout.content_block_size += + flow_layout.collapsible_margins_in_children.end.solve(); + } + block_margins_collapsed_with_children.collapsed_through = + this_start_margin_can_collapse_with_children.0 && + this_end_margin_can_collapse_with_children && + flow_layout + .collapsible_margins_in_children + .collapsed_through; + let relative_adjustement = relative_adjustement(style, inline_size, block_size); + let block_size = block_size.auto_is(|| { flow_layout - .collapsible_margins_in_children - .collapsed_through; - let relative_adjustement = relative_adjustement(style, inline_size, block_size); - let block_size = block_size.auto_is(|| { - flow_layout - .content_block_size - .clamp_between_extremums(min_box_size.block, max_box_size.block) - }); - let content_rect = Rect { - start_corner: Vec2 { - block: pb.block_start + relative_adjustement.block, - inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, - }, - size: Vec2 { - block: block_size, - inline: inline_size, - }, - }; - if style.get_box().position == Position::Relative { - nested_positioning_context.layout_abspos( - layout_context, - &mut flow_layout.fragments, - &content_rect.size, - &padding, - style, - ) - } - BoxFragment { - style: style.clone(), - children: flow_layout.fragments, - content_rect, - padding, - border, - margin, - block_margins_collapsed_with_children, - } + .content_block_size + .clamp_between_extremums(min_box_size.block, max_box_size.block) + }); + let content_rect = Rect { + start_corner: Vec2 { + block: pb.block_start + relative_adjustement.block, + inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, + }, + size: Vec2 { + block: block_size, + inline: inline_size, + }, + }; + BoxFragment { + style: style.clone(), + children: flow_layout.fragments, + content_rect, + padding, + border, + margin, + block_margins_collapsed_with_children, + } + }) } /// https://drafts.csswg.org/css2/visudet.html#block-replaced-width diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 71d42643853..e668c882d0e 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -12,13 +12,12 @@ use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::Fragment; use crate::geom; use crate::geom::flow_relative::Vec2; +use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::PositioningContext; -use crate::positioned::{AbsolutelyPositionedBox, CollectedAbsolutelyPositionedBox}; use crate::replaced::ReplacedContent; use crate::sizing::ContentSizesRequest; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; use crate::DefiniteContainingBlock; -use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use script_layout_interface::wrapper_traits::LayoutNode; use servo_arc::Arc; use style::properties::ComputedValues; @@ -111,7 +110,7 @@ impl BoxTreeRoot { }; let dummy_tree_rank = 0; - let mut positioning_context = PositioningContext { abspos: Vec::new() }; + let mut positioning_context = PositioningContext::new(); let mut independent_layout = self.0.layout( layout_context, &mut positioning_context, @@ -119,18 +118,11 @@ impl BoxTreeRoot { dummy_tree_rank, ); - let map = |a: &CollectedAbsolutelyPositionedBox| { - a.layout(layout_context, &initial_containing_block) - }; - if layout_context.use_rayon { - independent_layout - .fragments - .par_extend(positioning_context.abspos.par_iter().map(map)) - } else { - independent_layout - .fragments - .extend(positioning_context.abspos.iter().map(map)) - } + positioning_context.layout_in_initial_containing_block( + layout_context, + &initial_containing_block, + &mut independent_layout.fragments, + ); FragmentTreeRoot(independent_layout.fragments) } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 0c2f0fe55f0..881e395ca7d 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -10,8 +10,9 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::sizing::ContentSizesRequest; use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::{ContainingBlock, DefiniteContainingBlock}; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use servo_arc::Arc; +use style::computed_values::position::T as Position; use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::Zero; @@ -21,10 +22,8 @@ pub(crate) struct AbsolutelyPositionedBox { pub contents: IndependentFormattingContext, } -#[derive(Default)] pub(crate) struct PositioningContext<'box_tree> { - /// With `position: absolute` - pub abspos: Vec<CollectedAbsolutelyPositionedBox<'box_tree>>, + boxes: Vec<CollectedAbsolutelyPositionedBox<'box_tree>>, } #[derive(Debug)] @@ -83,8 +82,8 @@ impl AbsolutelyPositionedBox { } } - pub(crate) fn layout<'a>( - &'a self, + pub(crate) fn layout( + &self, initial_start_corner: Vec2<Length>, tree_rank: usize, ) -> CollectedAbsolutelyPositionedBox { @@ -123,73 +122,143 @@ impl AbsolutelyPositionedBox { } } -impl PositioningContext<'_> { - /// Unlike `Vec::append`, this takes ownership of the other value. - pub(crate) fn append(&mut self, mut other: Self) { - if self.abspos.is_empty() { - self.abspos = other.abspos +impl<'box_tree> PositioningContext<'box_tree> { + pub(crate) fn new() -> Self { + Self { + boxes: Vec::new(), + } + } + + pub(crate) fn for_maybe_position_relative( + &mut self, + layout_context: &LayoutContext, + style: &ComputedValues, + f: impl FnOnce(&mut Self) -> BoxFragment, + ) -> BoxFragment { + if style.clone_position() == Position::Relative { + Self::for_positioned(layout_context, f) } else { - self.abspos.append(&mut other.abspos) + f(self) } } + fn for_positioned( + layout_context: &LayoutContext, + f: impl FnOnce(&mut Self) -> BoxFragment, + ) -> BoxFragment { + let mut new = Self::new(); + let mut positioned_box_fragment = f(&mut new); + new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment); + positioned_box_fragment + } + + pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) { + self.boxes.push(box_) + } + + pub(crate) fn append(&mut self, other: Self) { + vec_append_owned( + &mut self.boxes, + other.boxes, + ); + } + pub(crate) fn adjust_static_positions( &mut self, tree_rank_in_parent: usize, f: impl FnOnce(&mut Self) -> Vec<Fragment>, ) -> Vec<Fragment> { - let abspos_so_far = self.abspos.len(); + let so_far = self.boxes.len(); + let fragments = f(self); + adjust_static_positions( - &mut self.abspos[abspos_so_far..], + &mut self.boxes[so_far..], &fragments, tree_rank_in_parent, ); fragments } - pub(crate) fn layout_abspos( - self, + pub(crate) fn layout_in_initial_containing_block( + &mut self, layout_context: &LayoutContext, + initial_containing_block: &DefiniteContainingBlock, fragments: &mut Vec<Fragment>, - content_rect_size: &Vec2<Length>, - padding: &Sides<Length>, - style: &ComputedValues, ) { - if self.abspos.is_empty() { - return; - } - let padding_rect = Rect { - size: content_rect_size.clone(), - // Ignore the content rect’s position in its own containing block: - start_corner: Vec2::zero(), + CollectedAbsolutelyPositionedBox::layout_many( + layout_context, + &self.boxes, + fragments, + initial_containing_block, + ) + } + + fn layout_in_positioned_ancestor( + &mut self, + layout_context: &LayoutContext, + positioned_box_fragment: &mut BoxFragment, + ) { + if !self.boxes.is_empty() { + let padding_rect = Rect { + size: positioned_box_fragment.content_rect.size.clone(), + // Ignore the content rect’s position in its own containing block: + start_corner: Vec2::zero(), + } + .inflate(&positioned_box_fragment.padding); + let containing_block = DefiniteContainingBlock { + size: padding_rect.size.clone(), + style: &positioned_box_fragment.style, + }; + let mut children = Vec::new(); + CollectedAbsolutelyPositionedBox::layout_many( + layout_context, + &self.boxes, + &mut children, + &containing_block, + ); + positioned_box_fragment + .children + .push(Fragment::Anonymous(AnonymousFragment { + children, + rect: padding_rect, + mode: positioned_box_fragment.style.writing_mode, + })) } - .inflate(&padding); - let containing_block = DefiniteContainingBlock { - size: padding_rect.size.clone(), - style, - }; - let map = - |a: &CollectedAbsolutelyPositionedBox| a.layout(layout_context, &containing_block); - let children = if layout_context.use_rayon { - self.abspos.par_iter().map(map).collect() - } else { - self.abspos.iter().map(map).collect() - }; - fragments.push(Fragment::Anonymous(AnonymousFragment { - children, - rect: padding_rect, - mode: style.writing_mode, - })) } } -impl CollectedAbsolutelyPositionedBox<'_> { +impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { + pub(crate) fn layout_many( + layout_context: &LayoutContext, + boxes: &[Self], + fragments: &mut Vec<Fragment>, + containing_block: &DefiniteContainingBlock, + ) { + if layout_context.use_rayon { + fragments.par_extend(boxes.par_iter().map( + |box_| { + Fragment::Box(box_.layout( + layout_context, + containing_block, + )) + } + )) + } else { + fragments.extend(boxes.iter().map(|box_| { + Fragment::Box(box_.layout( + layout_context, + containing_block, + )) + })) + } + } + pub(crate) fn layout( &self, layout_context: &LayoutContext, containing_block: &DefiniteContainingBlock, - ) -> Fragment { + ) -> BoxFragment { let style = &self.absolutely_positioned_box.contents.style; let cbis = containing_block.size.inline; let cbbs = containing_block.size.block; @@ -249,94 +318,88 @@ impl CollectedAbsolutelyPositionedBox<'_> { block_end: block_axis.margin_end, }; - let mut positioning_context = PositioningContext { abspos: Vec::new() }; - let (size, mut fragments) = match self.absolutely_positioned_box.contents.as_replaced() { - Ok(replaced) => { - // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width - // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height - let style = &self.absolutely_positioned_box.contents.style; - let size = replaced_used_size.unwrap(); - let fragments = replaced.make_fragments(style, size.clone()); - (size, fragments) - }, - Err(non_replaced) => { - // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width - // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height - let inline_size = inline_axis.size.auto_is(|| { - let available_size = match inline_axis.anchor { - Anchor::Start(start) => { - cbis - start - pb.inline_sum() - margin.inline_sum() - }, - Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(), + PositioningContext::for_positioned(layout_context, |positioning_context| { + let size; + let fragments; + match self.absolutely_positioned_box.contents.as_replaced() { + Ok(replaced) => { + // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width + // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height + let style = &self.absolutely_positioned_box.contents.style; + size = replaced_used_size.unwrap(); + fragments = replaced.make_fragments(style, size.clone()); + }, + Err(non_replaced) => { + // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width + // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height + let inline_size = inline_axis.size.auto_is(|| { + let available_size = match inline_axis.anchor { + Anchor::Start(start) => { + cbis - start - pb.inline_sum() - margin.inline_sum() + }, + Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(), + }; + self.absolutely_positioned_box + .contents + .content_sizes + .shrink_to_fit(available_size) + }); + + let containing_block_for_children = ContainingBlock { + inline_size, + block_size: block_axis.size, + style, }; - self.absolutely_positioned_box - .contents - .content_sizes - .shrink_to_fit(available_size) - }); - - let containing_block_for_children = ContainingBlock { - inline_size, - block_size: block_axis.size, - style, - }; - // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows - assert_eq!( - containing_block.style.writing_mode, - containing_block_for_children.style.writing_mode, - "Mixed writing modes are not supported yet" - ); - let dummy_tree_rank = 0; - let independent_layout = non_replaced.layout( - layout_context, - &mut positioning_context, - &containing_block_for_children, - dummy_tree_rank, - ); - - let size = Vec2 { - inline: inline_size, - block: block_axis - .size - .auto_is(|| independent_layout.content_block_size), - }; - (size, independent_layout.fragments) - }, - }; - - let inline_start = match inline_axis.anchor { - Anchor::Start(start) => start + pb.inline_start + margin.inline_start, - Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline, - }; - let block_start = match block_axis.anchor { - Anchor::Start(start) => start + pb.block_start + margin.block_start, - Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block, - }; + // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows + assert_eq!( + containing_block.style.writing_mode, + containing_block_for_children.style.writing_mode, + "Mixed writing modes are not supported yet" + ); + let dummy_tree_rank = 0; + let independent_layout = non_replaced.layout( + layout_context, + positioning_context, + &containing_block_for_children, + dummy_tree_rank, + ); + + size = Vec2 { + inline: inline_size, + block: block_axis + .size + .auto_is(|| independent_layout.content_block_size), + }; + fragments = independent_layout.fragments + }, + }; - let content_rect = Rect { - start_corner: Vec2 { - inline: inline_start, - block: block_start, - }, - size, - }; + let inline_start = match inline_axis.anchor { + Anchor::Start(start) => start + pb.inline_start + margin.inline_start, + Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline, + }; + let block_start = match block_axis.anchor { + Anchor::Start(start) => start + pb.block_start + margin.block_start, + Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block, + }; - positioning_context.layout_abspos( - layout_context, - &mut fragments, - &content_rect.size, - &padding, - style, - ); + let content_rect = Rect { + start_corner: Vec2 { + inline: inline_start, + block: block_start, + }, + size, + }; - Fragment::Box(BoxFragment { - style: style.clone(), - children: fragments, - content_rect, - padding, - border, - margin, - block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), + BoxFragment { + style: style.clone(), + children: fragments, + content_rect, + padding, + border, + margin, + block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), + } }) } } @@ -468,3 +531,11 @@ fn adjust_static_positions( } } } + +fn vec_append_owned<T>(a: &mut Vec<T>, mut b: Vec<T>) { + if a.is_empty() { + *a = b + } else { + a.append(&mut b) + } +} |