Skip to main content

layout/fragment_tree/
containing_block.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use style::computed_values::position::T as ComputedPosition;
6
7use crate::fragment_tree::Fragment;
8
9/// A data structure used to track the containing block when recursing
10/// through the Fragment tree. It tracks the three types of containing
11/// blocks (for all descendants, for absolute and fixed position
12/// descendants, and for fixed position descendants).
13pub(crate) struct ContainingBlockManager<'a, T> {
14    /// The containing block for all non-absolute descendants. "...if the element's
15    /// position is 'relative' or 'static', the containing block is formed by the
16    /// content edge of the nearest block container ancestor box." This is also
17    /// the case for 'position: sticky' elements.
18    /// <https://www.w3.org/TR/CSS2/visudet.html#containing-block-details>
19    pub for_non_absolute_descendants: &'a T,
20
21    /// The containing block for absolute descendants. "If the element has
22    /// 'position: absolute', the containing block is
23    /// established by the nearest ancestor with a 'position' of 'absolute',
24    /// 'relative' or 'fixed', in the following way:
25    ///   1. In the case that the ancestor is an inline element, the containing
26    ///      block is the bounding box around the padding boxes of the first and the
27    ///      last inline boxes generated for that element. In CSS 2.1, if the inline
28    ///      element is split across multiple lines, the containing block is
29    ///      undefined.
30    ///   2. Otherwise, the containing block is formed by the padding edge of the
31    ///      ancestor.
32    ///
33    /// <https://www.w3.org/TR/CSS2/visudet.html#containing-block-details>
34    /// If the ancestor forms a containing block for all descendants (see below),
35    /// this value will be None and absolute descendants will use the containing
36    /// block for fixed descendants.
37    pub for_absolute_descendants: Option<&'a T>,
38
39    /// The containing block for fixed and absolute descendants.
40    /// "For elements whose layout is governed by the CSS box model, any value
41    /// other than none for the transform property also causes the element to
42    /// establish a containing block for all descendants. Its padding box will be
43    /// used to layout for all of its absolute-position descendants,
44    /// fixed-position descendants, and descendant fixed background attachments."
45    /// <https://w3c.github.io/csswg-drafts/css-transforms-1/#containing-block-for-all-descendants>
46    /// See `ComputedValues::establishes_containing_block_for_all_descendants`
47    /// for a list of conditions where an element forms a containing block for
48    /// all descendants.
49    pub for_absolute_and_fixed_descendants: &'a T,
50}
51
52impl<'a, T> ContainingBlockManager<'a, T> {
53    pub(crate) fn get_containing_block_for_fragment(&self, fragment: &Fragment) -> &T {
54        let Some(box_fragment) = fragment.retrieve_box_fragment() else {
55            return self.for_non_absolute_descendants;
56        };
57        match box_fragment.style().clone_position() {
58            ComputedPosition::Fixed => self.for_absolute_and_fixed_descendants,
59            ComputedPosition::Absolute => self
60                .for_absolute_descendants
61                .unwrap_or(self.for_absolute_and_fixed_descendants),
62            _ => self.for_non_absolute_descendants,
63        }
64    }
65
66    pub(crate) fn new_for_non_absolute_descendants(
67        &self,
68        for_non_absolute_descendants: &'a T,
69    ) -> Self {
70        ContainingBlockManager {
71            for_non_absolute_descendants,
72            for_absolute_descendants: self.for_absolute_descendants,
73            for_absolute_and_fixed_descendants: self.for_absolute_and_fixed_descendants,
74        }
75    }
76
77    pub(crate) fn new_for_absolute_descendants(
78        &self,
79        for_non_absolute_descendants: &'a T,
80        for_absolute_descendants: &'a T,
81    ) -> Self {
82        ContainingBlockManager {
83            for_non_absolute_descendants,
84            for_absolute_descendants: Some(for_absolute_descendants),
85            for_absolute_and_fixed_descendants: self.for_absolute_and_fixed_descendants,
86        }
87    }
88
89    pub(crate) fn new_for_absolute_and_fixed_descendants(
90        &self,
91        for_non_absolute_descendants: &'a T,
92        for_absolute_and_fixed_descendants: &'a T,
93    ) -> Self {
94        ContainingBlockManager {
95            for_non_absolute_descendants,
96            for_absolute_descendants: None,
97            for_absolute_and_fixed_descendants,
98        }
99    }
100}