diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2020-03-19 04:17:29 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-19 04:17:29 -0400 |
commit | b945de4ea910a6c6c8e296089bc3b2baf2afa248 (patch) | |
tree | 2391f9e29ca4eced52942dc0ceedf528660aa3ec | |
parent | 2b0a48f291bf6968ce9d13822fd242d46f4f0412 (diff) | |
parent | 712f9340e81a0f2f3d98c6956b91f0e6d26bad3e (diff) | |
download | servo-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.rs | 169 |
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; |