Skip to main content

layout/fragment_tree/
positioning_fragment.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 std::sync::Arc;
6
7use app_units::Au;
8use atomic_refcell::AtomicRefCell;
9use malloc_size_of_derive::MallocSizeOf;
10use servo_arc::Arc as ServoArc;
11use servo_base::print_tree::PrintTree;
12use style::properties::ComputedValues;
13
14use super::{BaseFragment, BaseFragmentInfo, Fragment};
15use crate::fragment_tree::ContainingBlockCalculation;
16use crate::geom::PhysicalRect;
17
18/// Can contain child fragments with relative coordinates, but does not contribute to painting
19/// itself. [`PositioningFragment`]s may be completely anonymous, or just non-painting Fragments
20/// generated by boxes.
21#[derive(MallocSizeOf)]
22pub(crate) struct PositioningFragment {
23    pub base: BaseFragment,
24    pub children: Vec<Fragment>,
25
26    /// The scrollable overflow of this anonymous fragment's children.
27    scrollable_overflow: AtomicRefCell<Option<PhysicalRect<Au>>>,
28
29    /// This [`PositioningFragment`]'s containing block rectangle in coordinates relative to
30    /// the initial containing block, but not taking into account any transforms.
31    pub cumulative_containing_block_rect: AtomicRefCell<PhysicalRect<Au>>,
32}
33
34impl PositioningFragment {
35    pub fn new_anonymous(
36        style: ServoArc<ComputedValues>,
37        rect: PhysicalRect<Au>,
38        children: Vec<Fragment>,
39    ) -> Arc<Self> {
40        Self::new_with_base_fragment_info(BaseFragmentInfo::anonymous(), style, rect, children)
41    }
42
43    pub fn new_empty(
44        base_fragment_info: BaseFragmentInfo,
45        rect: PhysicalRect<Au>,
46        style: ServoArc<ComputedValues>,
47    ) -> Arc<Self> {
48        Self::new_with_base_fragment_info(base_fragment_info, style, rect, Vec::new())
49    }
50
51    fn new_with_base_fragment_info(
52        base_fragment_info: BaseFragmentInfo,
53        style: ServoArc<ComputedValues>,
54        rect: PhysicalRect<Au>,
55        children: Vec<Fragment>,
56    ) -> Arc<Self> {
57        Arc::new(Self {
58            base: BaseFragment::new(base_fragment_info, style.into(), rect),
59            children,
60            scrollable_overflow: Default::default(),
61            cumulative_containing_block_rect: Default::default(),
62        })
63    }
64
65    pub(crate) fn set_containing_block(&self, containing_block: &PhysicalRect<Au>) {
66        *self.cumulative_containing_block_rect.borrow_mut() = *containing_block;
67    }
68
69    pub fn offset_by_containing_block(
70        &self,
71        rect: &PhysicalRect<Au>,
72        containing_block_computation: ContainingBlockCalculation<'_>,
73    ) -> PhysicalRect<Au> {
74        containing_block_computation.ensure();
75        rect.translate(
76            self.cumulative_containing_block_rect
77                .borrow()
78                .origin
79                .to_vector(),
80        )
81    }
82
83    /// Get the scrollable overflow for this [`PositioningFragment`] relative to its
84    /// containing block, recalculating scrollable overflow when necessary, for instance
85    /// after a style change.
86    pub(crate) fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> {
87        *self
88            .scrollable_overflow
89            .borrow_mut()
90            .get_or_insert_with(|| self.calculate_scrollable_overflow())
91    }
92
93    /// Clear the scrollable overflow on this [`PositioningFragment`]. This is called
94    /// during damage propagation when a fragment is preserved, itself or one of its
95    /// descendants has scrollable overflow damage.
96    pub(crate) fn clear_scrollable_overflow(&self) {
97        *self.scrollable_overflow.borrow_mut() = None;
98    }
99
100    fn calculate_scrollable_overflow(&self) -> PhysicalRect<Au> {
101        self.children
102            .iter()
103            .fold(PhysicalRect::zero(), |acc, child| {
104                acc.union(
105                    &child
106                        .scrollable_overflow_for_parent()
107                        .translate(self.base.rect().origin.to_vector()),
108                )
109            })
110    }
111
112    pub fn print(&self, tree: &mut PrintTree) {
113        tree.new_level(format!(
114            "PositioningFragment\
115                \nbase={:?}\
116                \nrect={:?}\
117                \nscrollable_overflow={:?}",
118            self.base,
119            self.base.rect(),
120            self.scrollable_overflow
121        ));
122
123        for child in &self.children {
124            child.print(tree);
125        }
126        tree.end_level();
127    }
128}