aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/fragment_tree/containing_block.rs
blob: 5bd02a678677588134c290f9dc2236809661fd2c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* 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 crate::fragments::Fragment;
use style::computed_values::position::T as ComputedPosition;

/// 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.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 {
        return 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 {
        return 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 {
        return ContainingBlockManager {
            for_non_absolute_descendants,
            for_absolute_descendants: None,
            for_absolute_and_fixed_descendants,
        };
    }
}