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 100 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.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,
}
}
}