layout/fragment_tree/
fragment_tree.rs1use std::cell::Cell;
6use std::sync::Arc;
7
8use app_units::Au;
9use malloc_size_of_derive::MallocSizeOf;
10use paint_api::display_list::AxesScrollSensitivity;
11use servo_base::print_tree::PrintTree;
12use style::computed_values::position::T as Position;
13
14use super::{BoxFragment, ContainingBlockManager, Fragment};
15use crate::geom::PhysicalRect;
16
17#[derive(MallocSizeOf)]
18pub struct FragmentTree {
19 pub(crate) root_fragments: Vec<Fragment>,
28
29 scrollable_overflow: Cell<Option<PhysicalRect<Au>>>,
32
33 pub(crate) initial_containing_block: PhysicalRect<Au>,
35
36 pub viewport_scroll_sensitivity: AxesScrollSensitivity,
38}
39
40impl FragmentTree {
41 pub(crate) fn new(
42 root_fragments: Vec<Fragment>,
43 initial_containing_block: PhysicalRect<Au>,
44 viewport_scroll_sensitivity: AxesScrollSensitivity,
45 ) -> Self {
46 Self {
47 root_fragments,
48 scrollable_overflow: Cell::default(),
49 initial_containing_block,
50 viewport_scroll_sensitivity,
51 }
52 }
53
54 pub fn print(&self) {
55 let mut print_tree = PrintTree::new("Fragment Tree".to_string());
56 for fragment in &self.root_fragments {
57 fragment.print(&mut print_tree);
58 }
59 }
60
61 pub(crate) fn scrollable_overflow(&self) -> PhysicalRect<Au> {
62 if let Some(scrollable_overflow) = self.scrollable_overflow.get() {
63 return scrollable_overflow;
64 }
65 let scrollable_overflow = self.calculate_scrollable_overflow();
66 self.scrollable_overflow.set(Some(scrollable_overflow));
67 scrollable_overflow
68 }
69
70 pub(crate) fn clear_scrollable_overflow(&self) {
71 self.scrollable_overflow.set(None);
72 }
73
74 fn calculate_scrollable_overflow(&self) -> PhysicalRect<Au> {
77 let Some(first_root_fragment) = self.root_fragments.first() else {
78 return self.initial_containing_block;
79 };
80
81 let scrollable_overflow =
82 self.root_fragments
83 .iter()
84 .fold(self.initial_containing_block, |overflow, fragment| {
85 if fragment
91 .retrieve_box_fragment()
92 .is_some_and(|box_fragment| {
93 box_fragment.style().get_box().position == Position::Fixed
94 })
95 {
96 return overflow;
97 }
98
99 overflow.union(&fragment.scrollable_overflow_for_parent())
100 });
101
102 let first_root_fragment = match first_root_fragment {
107 Fragment::Box(fragment) | Fragment::Float(fragment) => fragment,
108 _ => return scrollable_overflow,
109 };
110 if !first_root_fragment.is_root_element() {
111 return scrollable_overflow;
112 }
113 first_root_fragment.clip_wholly_unreachable_scrollable_overflow(
114 scrollable_overflow,
115 self.initial_containing_block,
116 )
117 }
118
119 pub(crate) fn find<T>(
120 &self,
121 mut process_func: impl FnMut(&Fragment, usize, &PhysicalRect<Au>) -> Option<T>,
122 ) -> Option<T> {
123 let info = ContainingBlockManager {
124 for_non_absolute_descendants: &self.initial_containing_block,
125 for_absolute_descendants: None,
126 for_absolute_and_fixed_descendants: &self.initial_containing_block,
127 };
128 self.root_fragments
129 .iter()
130 .find_map(|child| child.find(&info, 0, &mut process_func))
131 }
132
133 pub(crate) fn body_fragment(&self) -> Option<Arc<BoxFragment>> {
135 fn find_body(children: &[Fragment]) -> Option<Arc<BoxFragment>> {
136 children.iter().find_map(|fragment| {
137 match fragment {
138 Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
139 if box_fragment.is_body_element_of_html_element_root() {
140 return Some(box_fragment.clone());
141 }
142
143 if box_fragment.is_root_element() || box_fragment.base.is_anonymous() {
150 find_body(&box_fragment.children)
151 } else {
152 None
153 }
154 },
155 Fragment::Positioning(positioning_fragment)
156 if positioning_fragment.base.is_anonymous() =>
157 {
158 find_body(&positioning_fragment.children)
162 },
163 _ => None,
164 }
165 })
166 }
167
168 find_body(&self.root_fragments)
169 }
170}