Layout position: fixed in the initial containing block

This commit is contained in:
Simon Sapin 2019-12-12 22:21:33 +01:00
parent c44ee516a1
commit 5ebddf19e6
3 changed files with 97 additions and 25 deletions

View file

@ -220,6 +220,7 @@ fn layout_block_level_children<'a>(
}) })
.collect() .collect()
} else { } else {
let has_positioned_ancestor = positioning_context.has_positioned_ancestor();
let mut fragments = child_boxes let mut fragments = child_boxes
.par_iter() .par_iter()
.enumerate() .enumerate()
@ -234,7 +235,7 @@ fn layout_block_level_children<'a>(
/* float_context = */ None, /* float_context = */ None,
) )
}, },
PositioningContext::new, || PositioningContext::new_for_rayon(has_positioned_ancestor),
PositioningContext::append, PositioningContext::append,
) )
.collect(); .collect();

View file

@ -110,7 +110,7 @@ impl BoxTreeRoot {
}; };
let dummy_tree_rank = 0; let dummy_tree_rank = 0;
let mut positioning_context = PositioningContext::new(); let mut positioning_context = PositioningContext::new_for_initial_containing_block();
let mut independent_layout = self.0.layout( let mut independent_layout = self.0.layout(
layout_context, layout_context,
&mut positioning_context, &mut positioning_context,

View file

@ -10,7 +10,8 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::sizing::ContentSizesRequest; use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::style_ext::{ComputedValuesExt, DisplayInside};
use crate::{ContainingBlock, DefiniteContainingBlock}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelExtend};
use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
use style::computed_values::position::T as Position; use style::computed_values::position::T as Position;
use style::properties::ComputedValues; use style::properties::ComputedValues;
@ -23,7 +24,8 @@ pub(crate) struct AbsolutelyPositionedBox {
} }
pub(crate) struct PositioningContext<'box_tree> { pub(crate) struct PositioningContext<'box_tree> {
boxes: Vec<CollectedAbsolutelyPositionedBox<'box_tree>>, for_nearest_positioned_ancestor: Option<Vec<CollectedAbsolutelyPositionedBox<'box_tree>>>,
for_initial_containing_block: Vec<CollectedAbsolutelyPositionedBox<'box_tree>>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -123,12 +125,28 @@ impl AbsolutelyPositionedBox {
} }
impl<'box_tree> PositioningContext<'box_tree> { impl<'box_tree> PositioningContext<'box_tree> {
pub(crate) fn new() -> Self { pub(crate) fn new_for_initial_containing_block() -> Self {
Self { Self {
boxes: Vec::new(), for_nearest_positioned_ancestor: None,
for_initial_containing_block: Vec::new(),
} }
} }
pub(crate) fn new_for_rayon(has_positioned_ancestor: bool) -> Self {
Self {
for_nearest_positioned_ancestor: if has_positioned_ancestor {
Some(Vec::new())
} else {
None
},
for_initial_containing_block: Vec::new(),
}
}
pub(crate) fn has_positioned_ancestor(&self) -> bool {
self.for_nearest_positioned_ancestor.is_some()
}
pub(crate) fn for_maybe_position_relative( pub(crate) fn for_maybe_position_relative(
&mut self, &mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
@ -136,7 +154,7 @@ impl<'box_tree> PositioningContext<'box_tree> {
f: impl FnOnce(&mut Self) -> BoxFragment, f: impl FnOnce(&mut Self) -> BoxFragment,
) -> BoxFragment { ) -> BoxFragment {
if style.clone_position() == Position::Relative { if style.clone_position() == Position::Relative {
Self::for_positioned(layout_context, f) Self::for_positioned(layout_context, &mut self.for_initial_containing_block, f)
} else { } else {
f(self) f(self)
} }
@ -144,23 +162,48 @@ impl<'box_tree> PositioningContext<'box_tree> {
fn for_positioned( fn for_positioned(
layout_context: &LayoutContext, layout_context: &LayoutContext,
for_initial_containing_block: &mut Vec<CollectedAbsolutelyPositionedBox<'box_tree>>,
f: impl FnOnce(&mut Self) -> BoxFragment, f: impl FnOnce(&mut Self) -> BoxFragment,
) -> BoxFragment { ) -> BoxFragment {
let mut new = Self::new(); let mut new = Self {
for_nearest_positioned_ancestor: Some(Vec::new()),
for_initial_containing_block: std::mem::take(for_initial_containing_block),
};
let mut positioned_box_fragment = f(&mut new); let mut positioned_box_fragment = f(&mut new);
new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment); new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment);
*for_initial_containing_block = new.for_initial_containing_block;
positioned_box_fragment positioned_box_fragment
} }
pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) { pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) {
self.boxes.push(box_) if let Some(nearest) = &mut self.for_nearest_positioned_ancestor {
match box_
.absolutely_positioned_box
.contents
.style
.clone_position()
{
Position::Fixed => {}, // fall through
Position::Absolute => return nearest.push(box_),
Position::Static | Position::Relative => unreachable!(),
}
}
self.for_initial_containing_block.push(box_)
} }
pub(crate) fn append(&mut self, other: Self) { pub(crate) fn append(&mut self, other: Self) {
vec_append_owned( vec_append_owned(
&mut self.boxes, &mut self.for_initial_containing_block,
other.boxes, other.for_initial_containing_block,
); );
match (
self.for_nearest_positioned_ancestor.as_mut(),
other.for_nearest_positioned_ancestor,
) {
(Some(a), Some(b)) => vec_append_owned(a, b),
(None, None) => {},
_ => unreachable!(),
}
} }
pub(crate) fn adjust_static_positions( pub(crate) fn adjust_static_positions(
@ -168,15 +211,26 @@ impl<'box_tree> PositioningContext<'box_tree> {
tree_rank_in_parent: usize, tree_rank_in_parent: usize,
f: impl FnOnce(&mut Self) -> Vec<Fragment>, f: impl FnOnce(&mut Self) -> Vec<Fragment>,
) -> Vec<Fragment> { ) -> Vec<Fragment> {
let so_far = self.boxes.len(); let for_icb_so_far = self.for_initial_containing_block.len();
let for_nearest_so_far = self
.for_nearest_positioned_ancestor
.as_ref()
.map(|v| v.len());
let fragments = f(self); let fragments = f(self);
adjust_static_positions( adjust_static_positions(
&mut self.boxes[so_far..], &mut self.for_initial_containing_block[for_icb_so_far..],
&fragments, &fragments,
tree_rank_in_parent, tree_rank_in_parent,
); );
if let Some(nearest) = &mut self.for_nearest_positioned_ancestor {
adjust_static_positions(
&mut nearest[for_nearest_so_far.unwrap()..],
&fragments,
tree_rank_in_parent,
);
}
fragments fragments
} }
@ -186,12 +240,19 @@ impl<'box_tree> PositioningContext<'box_tree> {
initial_containing_block: &DefiniteContainingBlock, initial_containing_block: &DefiniteContainingBlock,
fragments: &mut Vec<Fragment>, fragments: &mut Vec<Fragment>,
) { ) {
CollectedAbsolutelyPositionedBox::layout_many( debug_assert!(self.for_nearest_positioned_ancestor.is_none());
layout_context,
&self.boxes, // Loop because its possible that we discover (the static position of)
fragments, // more absolutely-positioned boxes while doing layout for others.
initial_containing_block, while !self.for_initial_containing_block.is_empty() {
) CollectedAbsolutelyPositionedBox::layout_many(
layout_context,
&std::mem::take(&mut self.for_initial_containing_block),
fragments,
&mut self.for_initial_containing_block,
initial_containing_block,
)
}
} }
fn layout_in_positioned_ancestor( fn layout_in_positioned_ancestor(
@ -199,7 +260,8 @@ impl<'box_tree> PositioningContext<'box_tree> {
layout_context: &LayoutContext, layout_context: &LayoutContext,
positioned_box_fragment: &mut BoxFragment, positioned_box_fragment: &mut BoxFragment,
) { ) {
if !self.boxes.is_empty() { let for_here = self.for_nearest_positioned_ancestor.take().unwrap();
if !for_here.is_empty() {
let padding_rect = Rect { let padding_rect = Rect {
size: positioned_box_fragment.content_rect.size.clone(), size: positioned_box_fragment.content_rect.size.clone(),
// Ignore the content rects position in its own containing block: // Ignore the content rects position in its own containing block:
@ -213,8 +275,9 @@ impl<'box_tree> PositioningContext<'box_tree> {
let mut children = Vec::new(); let mut children = Vec::new();
CollectedAbsolutelyPositionedBox::layout_many( CollectedAbsolutelyPositionedBox::layout_many(
layout_context, layout_context,
&self.boxes, &for_here,
&mut children, &mut children,
&mut self.for_initial_containing_block,
&containing_block, &containing_block,
); );
positioned_box_fragment positioned_box_fragment
@ -233,21 +296,27 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> {
layout_context: &LayoutContext, layout_context: &LayoutContext,
boxes: &[Self], boxes: &[Self],
fragments: &mut Vec<Fragment>, fragments: &mut Vec<Fragment>,
for_initial_containing_block: &mut Vec<CollectedAbsolutelyPositionedBox<'box_tree>>,
containing_block: &DefiniteContainingBlock, containing_block: &DefiniteContainingBlock,
) { ) {
if layout_context.use_rayon { if layout_context.use_rayon {
fragments.par_extend(boxes.par_iter().map( fragments.par_extend(boxes.par_iter().mapfold_reduce_into(
|box_| { for_initial_containing_block,
|for_initial_containing_block, box_| {
Fragment::Box(box_.layout( Fragment::Box(box_.layout(
layout_context, layout_context,
for_initial_containing_block,
containing_block, containing_block,
)) ))
} },
Vec::new,
vec_append_owned,
)) ))
} else { } else {
fragments.extend(boxes.iter().map(|box_| { fragments.extend(boxes.iter().map(|box_| {
Fragment::Box(box_.layout( Fragment::Box(box_.layout(
layout_context, layout_context,
for_initial_containing_block,
containing_block, containing_block,
)) ))
})) }))
@ -257,6 +326,7 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> {
pub(crate) fn layout( pub(crate) fn layout(
&self, &self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
for_initial_containing_block: &mut Vec<CollectedAbsolutelyPositionedBox<'box_tree>>,
containing_block: &DefiniteContainingBlock, containing_block: &DefiniteContainingBlock,
) -> BoxFragment { ) -> BoxFragment {
let style = &self.absolutely_positioned_box.contents.style; let style = &self.absolutely_positioned_box.contents.style;
@ -318,7 +388,8 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> {
block_end: block_axis.margin_end, block_end: block_axis.margin_end,
}; };
PositioningContext::for_positioned(layout_context, |positioning_context| { let for_icb = for_initial_containing_block;
PositioningContext::for_positioned(layout_context, for_icb, |positioning_context| {
let size; let size;
let fragments; let fragments;
match self.absolutely_positioned_box.contents.as_replaced() { match self.absolutely_positioned_box.contents.as_replaced() {