mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Layout position: fixed
in the initial containing block
This commit is contained in:
parent
c44ee516a1
commit
5ebddf19e6
3 changed files with 97 additions and 25 deletions
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,20 +240,28 @@ impl<'box_tree> PositioningContext<'box_tree> {
|
||||||
initial_containing_block: &DefiniteContainingBlock,
|
initial_containing_block: &DefiniteContainingBlock,
|
||||||
fragments: &mut Vec<Fragment>,
|
fragments: &mut Vec<Fragment>,
|
||||||
) {
|
) {
|
||||||
|
debug_assert!(self.for_nearest_positioned_ancestor.is_none());
|
||||||
|
|
||||||
|
// Loop because it’s possible that we discover (the static position of)
|
||||||
|
// more absolutely-positioned boxes while doing layout for others.
|
||||||
|
while !self.for_initial_containing_block.is_empty() {
|
||||||
CollectedAbsolutelyPositionedBox::layout_many(
|
CollectedAbsolutelyPositionedBox::layout_many(
|
||||||
layout_context,
|
layout_context,
|
||||||
&self.boxes,
|
&std::mem::take(&mut self.for_initial_containing_block),
|
||||||
fragments,
|
fragments,
|
||||||
|
&mut self.for_initial_containing_block,
|
||||||
initial_containing_block,
|
initial_containing_block,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn layout_in_positioned_ancestor(
|
fn layout_in_positioned_ancestor(
|
||||||
&mut self,
|
&mut self,
|
||||||
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 rect’s position in its own containing block:
|
// Ignore the content rect’s 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() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue