aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2020-03-19 04:17:29 -0400
committerGitHub <noreply@github.com>2020-03-19 04:17:29 -0400
commitb945de4ea910a6c6c8e296089bc3b2baf2afa248 (patch)
tree2391f9e29ca4eced52942dc0ceedf528660aa3ec
parent2b0a48f291bf6968ce9d13822fd242d46f4f0412 (diff)
parent712f9340e81a0f2f3d98c6956b91f0e6d26bad3e (diff)
downloadservo-b945de4ea910a6c6c8e296089bc3b2baf2afa248.tar.gz
servo-b945de4ea910a6c6c8e296089bc3b2baf2afa248.zip
Auto merge of #25984 - mrobinson:refactor-positioning-context, r=nox
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. <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because this shouldn't change any behavior. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
-rw-r--r--components/layout_2020/positioned.rs169
1 files changed, 65 insertions, 104 deletions
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index b909ae2d471..b9dca32db12 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -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;