mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
layout_2020: Refactor PositioningContext to be simpler and smaller
Add a few helper methods which allow removing duplicate code in PositioningContext. These methods will also be used to properly implement hoisting in inline layout.
This commit is contained in:
parent
5bf45b2622
commit
712f9340e8
1 changed files with 65 additions and 104 deletions
|
@ -172,6 +172,19 @@ impl PositioningContext {
|
|||
self.for_nearest_positioned_ancestor.is_some()
|
||||
}
|
||||
|
||||
fn new_for_style(style: &ComputedValues) -> Option<Self> {
|
||||
if style.establishes_containing_block_for_all_descendants() {
|
||||
Some(Self::new_for_containing_block_for_all_descendants())
|
||||
} else if style.establishes_containing_block() {
|
||||
Some(Self {
|
||||
for_nearest_positioned_ancestor: Some(Vec::new()),
|
||||
for_nearest_containing_block_for_all_descendants: Vec::new(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
||||
/// `PositioningContext`, create a new positioning context if necessary for the fragment and
|
||||
/// lay out the fragment and all its children. Returns the newly created `BoxFragment`.
|
||||
|
@ -182,82 +195,59 @@ impl PositioningContext {
|
|||
style: &ComputedValues,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
debug_assert!(style.clone_position() != Position::Fixed);
|
||||
debug_assert!(style.clone_position() != Position::Absolute);
|
||||
// Try to create a context, but if one isn't necessary, simply create the fragment
|
||||
// using the given closure and the current `PositioningContext`.
|
||||
let mut new_context = match Self::new_for_style(style) {
|
||||
Some(new_context) => new_context,
|
||||
None => return fragment_layout_fn(self),
|
||||
};
|
||||
|
||||
if style.establishes_containing_block_for_all_descendants() {
|
||||
let mut fragment = Self::layout_containing_block_for_all_descendants(
|
||||
layout_context,
|
||||
fragment_layout_fn,
|
||||
);
|
||||
if style.clone_position() == Position::Relative {
|
||||
fragment.content_rect.start_corner +=
|
||||
&relative_adjustement(style, containing_block);
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
let mut new_fragment = fragment_layout_fn(&mut new_context);
|
||||
new_context.layout_collected_children(layout_context, &mut new_fragment);
|
||||
|
||||
// If the new context has any hoisted boxes for the nearest containing block for
|
||||
// all descendants than collect them and pass them up the tree.
|
||||
vec_append_owned(
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
new_context.for_nearest_containing_block_for_all_descendants,
|
||||
);
|
||||
|
||||
if style.clone_position() == Position::Relative {
|
||||
let mut fragment = Self::create_and_layout_positioned(
|
||||
layout_context,
|
||||
style,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
fragment_layout_fn,
|
||||
);
|
||||
fragment.content_rect.start_corner += &relative_adjustement(style, containing_block);
|
||||
return fragment;
|
||||
new_fragment.content_rect.start_corner +=
|
||||
&relative_adjustement(style, containing_block);
|
||||
}
|
||||
|
||||
// We don't need to create a new PositioningContext for this Fragment, so
|
||||
// we pass in the current one to the fragment layout closure.
|
||||
fragment_layout_fn(self)
|
||||
new_fragment
|
||||
}
|
||||
|
||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
||||
/// `PositioningContext`, create a positioning context a positioned fragment and lay out the
|
||||
/// fragment and all its children. Returns the resulting `BoxFragment`.
|
||||
/// `PositioningContext`, create a positioning context for a positioned fragment and lay out
|
||||
/// the fragment and all its children. Returns the resulting `BoxFragment`.
|
||||
fn create_and_layout_positioned(
|
||||
layout_context: &LayoutContext,
|
||||
style: &ComputedValues,
|
||||
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
if style.establishes_containing_block_for_all_descendants() {
|
||||
return Self::layout_containing_block_for_all_descendants(
|
||||
layout_context,
|
||||
fragment_layout_fn,
|
||||
);
|
||||
}
|
||||
|
||||
let mut new = Self {
|
||||
for_nearest_positioned_ancestor: Some(Vec::new()),
|
||||
for_nearest_containing_block_for_all_descendants: std::mem::take(
|
||||
for_nearest_containing_block_for_all_descendants,
|
||||
),
|
||||
let mut new_context = match Self::new_for_style(style) {
|
||||
Some(new_context) => new_context,
|
||||
None => unreachable!(),
|
||||
};
|
||||
let mut positioned_box_fragment = fragment_layout_fn(&mut new);
|
||||
new.layout_positioned_fragment_children(layout_context, &mut positioned_box_fragment);
|
||||
|
||||
let mut new_fragment = fragment_layout_fn(&mut new_context);
|
||||
new_context.layout_collected_children(layout_context, &mut new_fragment);
|
||||
*for_nearest_containing_block_for_all_descendants =
|
||||
new.for_nearest_containing_block_for_all_descendants;
|
||||
positioned_box_fragment
|
||||
new_context.for_nearest_containing_block_for_all_descendants;
|
||||
new_fragment
|
||||
}
|
||||
|
||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
||||
/// `PositioningContext`, create a positioning context for a fragment that establishes a
|
||||
/// containing block for all descendants and lay out the fragment and all its children using
|
||||
/// the new positioning context. Returns the resulting `BoxFragment`.
|
||||
fn layout_containing_block_for_all_descendants(
|
||||
// Lay out the hoisted boxes collected into this `PositioningContext` and add them
|
||||
// to the given `BoxFragment`.
|
||||
fn layout_collected_children(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
||||
) -> BoxFragment {
|
||||
let mut containing_block_for_all_descendants =
|
||||
Self::new_for_containing_block_for_all_descendants();
|
||||
debug_assert!(containing_block_for_all_descendants
|
||||
.for_nearest_positioned_ancestor
|
||||
.is_none());
|
||||
|
||||
let mut new_fragment = fragment_layout_fn(&mut containing_block_for_all_descendants);
|
||||
|
||||
new_fragment: &mut BoxFragment,
|
||||
) {
|
||||
let padding_rect = Rect {
|
||||
size: new_fragment.content_rect.size.clone(),
|
||||
// Ignore the content rect’s position in its own containing block:
|
||||
|
@ -269,28 +259,30 @@ impl PositioningContext {
|
|||
style: &new_fragment.style,
|
||||
};
|
||||
|
||||
let take_hoisted_boxes_pending_layout = |context: &mut Self| match context
|
||||
.for_nearest_positioned_ancestor
|
||||
.as_mut()
|
||||
{
|
||||
Some(fragments) => std::mem::take(fragments),
|
||||
None => std::mem::take(&mut context.for_nearest_containing_block_for_all_descendants),
|
||||
};
|
||||
|
||||
// Loop because it’s possible that we discover (the static position of)
|
||||
// more absolutely-positioned boxes while doing layout for others.
|
||||
let mut new_child_fragments = Vec::new();
|
||||
while !containing_block_for_all_descendants
|
||||
.for_nearest_containing_block_for_all_descendants
|
||||
.is_empty()
|
||||
{
|
||||
let mut hoisted_boxes = take_hoisted_boxes_pending_layout(self);
|
||||
let mut laid_out_child_fragments = Vec::new();
|
||||
while !hoisted_boxes.is_empty() {
|
||||
HoistedAbsolutelyPositionedBox::layout_many(
|
||||
layout_context,
|
||||
&std::mem::take(
|
||||
&mut containing_block_for_all_descendants
|
||||
.for_nearest_containing_block_for_all_descendants,
|
||||
),
|
||||
&mut new_child_fragments,
|
||||
&mut containing_block_for_all_descendants
|
||||
.for_nearest_containing_block_for_all_descendants,
|
||||
&hoisted_boxes,
|
||||
&mut laid_out_child_fragments,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
&containing_block,
|
||||
)
|
||||
);
|
||||
hoisted_boxes = take_hoisted_boxes_pending_layout(self);
|
||||
}
|
||||
|
||||
new_fragment.children.extend(new_child_fragments);
|
||||
new_fragment
|
||||
new_fragment.children.extend(laid_out_child_fragments);
|
||||
}
|
||||
|
||||
pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox) {
|
||||
|
@ -378,35 +370,6 @@ impl PositioningContext {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_positioned_fragment_children(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
positioned_box_fragment: &mut BoxFragment,
|
||||
) {
|
||||
let for_here = self.for_nearest_positioned_ancestor.take().unwrap();
|
||||
if !for_here.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();
|
||||
HoistedAbsolutelyPositionedBox::layout_many(
|
||||
layout_context,
|
||||
&for_here,
|
||||
&mut children,
|
||||
&mut self.for_nearest_containing_block_for_all_descendants,
|
||||
&containing_block,
|
||||
);
|
||||
positioned_box_fragment.children.extend(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HoistedAbsolutelyPositionedBox {
|
||||
|
@ -506,12 +469,10 @@ impl HoistedAbsolutelyPositionedBox {
|
|||
block_end: block_axis.margin_end,
|
||||
};
|
||||
|
||||
let for_containing_block_for_all_descendants =
|
||||
for_nearest_containing_block_for_all_descendants;
|
||||
PositioningContext::create_and_layout_positioned(
|
||||
layout_context,
|
||||
style,
|
||||
for_containing_block_for_all_descendants,
|
||||
for_nearest_containing_block_for_all_descendants,
|
||||
|positioning_context| {
|
||||
let size;
|
||||
let fragments;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue