aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout_2020')
-rw-r--r--components/layout_2020/flow/inline.rs1
-rw-r--r--components/layout_2020/flow/mod.rs139
-rw-r--r--components/layout_2020/flow/root.rs22
-rw-r--r--components/layout_2020/positioned.rs329
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)
+ }
+}