aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/positioned.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout_2020/positioned.rs')
-rw-r--r--components/layout_2020/positioned.rs329
1 files changed, 200 insertions, 129 deletions
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)
+ }
+}