diff options
Diffstat (limited to 'components/layout/fragment_tree/containing_block.rs')
-rw-r--r-- | components/layout/fragment_tree/containing_block.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/components/layout/fragment_tree/containing_block.rs b/components/layout/fragment_tree/containing_block.rs new file mode 100644 index 00000000000..6edd9bb379b --- /dev/null +++ b/components/layout/fragment_tree/containing_block.rs @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use style::computed_values::position::T as ComputedPosition; + +use crate::fragment_tree::Fragment; + +/// A data structure used to track the containing block when recursing +/// through the Fragment tree. It tracks the three types of containing +/// blocks (for all descendants, for absolute and fixed position +/// descendants, and for fixed position descendants). +pub(crate) struct ContainingBlockManager<'a, T> { + /// The containing block for all non-absolute descendants. "...if the element's + /// position is 'relative' or 'static', the containing block is formed by the + /// content edge of the nearest block container ancestor box." This is also + /// the case for 'position: sticky' elements. + /// <https://www.w3.org/TR/CSS2/visudet.html#containing-block-details> + pub for_non_absolute_descendants: &'a T, + + /// The containing block for absolute descendants. "If the element has + /// 'position: absolute', the containing block is + /// established by the nearest ancestor with a 'position' of 'absolute', + /// 'relative' or 'fixed', in the following way: + /// 1. In the case that the ancestor is an inline element, the containing + /// block is the bounding box around the padding boxes of the first and the + /// last inline boxes generated for that element. In CSS 2.1, if the inline + /// element is split across multiple lines, the containing block is + /// undefined. + /// 2. Otherwise, the containing block is formed by the padding edge of the + /// ancestor. + /// + /// <https://www.w3.org/TR/CSS2/visudet.html#containing-block-details> + /// If the ancestor forms a containing block for all descendants (see below), + /// this value will be None and absolute descendants will use the containing + /// block for fixed descendants. + pub for_absolute_descendants: Option<&'a T>, + + /// The containing block for fixed and absolute descendants. + /// "For elements whose layout is governed by the CSS box model, any value + /// other than none for the transform property also causes the element to + /// establish a containing block for all descendants. Its padding box will be + /// used to layout for all of its absolute-position descendants, + /// fixed-position descendants, and descendant fixed background attachments." + /// <https://w3c.github.io/csswg-drafts/css-transforms-1/#containing-block-for-all-descendants> + /// See `ComputedValues::establishes_containing_block_for_all_descendants` + /// for a list of conditions where an element forms a containing block for + /// all descendants. + pub for_absolute_and_fixed_descendants: &'a T, +} + +impl<'a, T> ContainingBlockManager<'a, T> { + pub(crate) fn get_containing_block_for_fragment(&self, fragment: &Fragment) -> &T { + if let Fragment::Box(box_fragment) = fragment { + match box_fragment.borrow().style.clone_position() { + ComputedPosition::Fixed => self.for_absolute_and_fixed_descendants, + ComputedPosition::Absolute => self + .for_absolute_descendants + .unwrap_or(self.for_absolute_and_fixed_descendants), + _ => self.for_non_absolute_descendants, + } + } else { + self.for_non_absolute_descendants + } + } + + pub(crate) fn new_for_non_absolute_descendants( + &self, + for_non_absolute_descendants: &'a T, + ) -> Self { + ContainingBlockManager { + for_non_absolute_descendants, + for_absolute_descendants: self.for_absolute_descendants, + for_absolute_and_fixed_descendants: self.for_absolute_and_fixed_descendants, + } + } + + pub(crate) fn new_for_absolute_descendants( + &self, + for_non_absolute_descendants: &'a T, + for_absolute_descendants: &'a T, + ) -> Self { + ContainingBlockManager { + for_non_absolute_descendants, + for_absolute_descendants: Some(for_absolute_descendants), + for_absolute_and_fixed_descendants: self.for_absolute_and_fixed_descendants, + } + } + + pub(crate) fn new_for_absolute_and_fixed_descendants( + &self, + for_non_absolute_descendants: &'a T, + for_absolute_and_fixed_descendants: &'a T, + ) -> Self { + ContainingBlockManager { + for_non_absolute_descendants, + for_absolute_descendants: None, + for_absolute_and_fixed_descendants, + } + } +} |