layout/fragment_tree/
positioning_fragment.rs1use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8use app_units::Au;
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::SharedStyle;
16use crate::fragment_tree::CumulativeContentRectCalculation;
17use crate::geom::{PhysicalRect, SyncPhysicalRectAu};
18
19#[derive(MallocSizeOf)]
23pub(crate) struct PositioningFragment {
24 pub base: BaseFragment,
25
26 pub style: SharedStyle,
28
29 pub children: Vec<Fragment>,
30
31 scrollable_overflow: SyncPhysicalRectAu,
33 scrollable_overflow_is_up_to_date: AtomicBool,
34
35 pub cumulative_parent_content_rect: SyncPhysicalRectAu,
39
40 is_line_box: bool,
42}
43
44impl PositioningFragment {
45 pub fn new_anonymous(
46 style: ServoArc<ComputedValues>,
47 rect: PhysicalRect<Au>,
48 children: Vec<Fragment>,
49 is_line_box: bool,
50 ) -> Arc<Self> {
51 Self::new_with_base_fragment_info(
52 BaseFragmentInfo::anonymous(),
53 style,
54 rect,
55 children,
56 is_line_box,
57 )
58 }
59
60 pub fn new_empty(
61 base_fragment_info: BaseFragmentInfo,
62 rect: PhysicalRect<Au>,
63 style: ServoArc<ComputedValues>,
64 ) -> Arc<Self> {
65 Self::new_with_base_fragment_info(base_fragment_info, style, rect, Vec::new(), false)
66 }
67
68 fn new_with_base_fragment_info(
69 base_fragment_info: BaseFragmentInfo,
70 style: ServoArc<ComputedValues>,
71 rect: PhysicalRect<Au>,
72 children: Vec<Fragment>,
73 is_line_box: bool,
74 ) -> Arc<Self> {
75 Arc::new(Self {
76 base: BaseFragment::new(base_fragment_info, rect),
77 style: style.into(),
78 children,
79 scrollable_overflow: Default::default(),
80 scrollable_overflow_is_up_to_date: AtomicBool::new(false),
81 cumulative_parent_content_rect: Default::default(),
82 is_line_box,
83 })
84 }
85
86 #[inline]
87 pub(crate) fn set_cumulative_content_rect(&self, content_rect: &PhysicalRect<Au>) {
88 self.cumulative_parent_content_rect.set(*content_rect);
89 }
90
91 pub fn offset_by_containing_block(
92 &self,
93 rect: &PhysicalRect<Au>,
94 cumulative_content_rect_calculation: CumulativeContentRectCalculation<'_>,
95 ) -> PhysicalRect<Au> {
96 cumulative_content_rect_calculation.ensure();
97 rect.translate(self.cumulative_parent_content_rect.origin().to_vector())
98 }
99
100 pub(crate) fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> {
104 if self
105 .scrollable_overflow_is_up_to_date
106 .load(Ordering::Acquire)
107 {
108 self.scrollable_overflow.get()
109 } else {
110 let rect = self.calculate_scrollable_overflow();
111 self.scrollable_overflow.set(rect);
112 self.scrollable_overflow_is_up_to_date
113 .store(true, Ordering::Release);
114 rect
115 }
116 }
117
118 pub(crate) fn clear_scrollable_overflow(&self) {
122 self.scrollable_overflow_is_up_to_date
123 .store(false, Ordering::Release);
124 }
125
126 fn calculate_scrollable_overflow(&self) -> PhysicalRect<Au> {
127 self.children
128 .iter()
129 .fold(PhysicalRect::zero(), |acc, child| {
130 acc.union(
131 &child
132 .scrollable_overflow_for_parent()
133 .translate(self.base.rect().origin.to_vector()),
134 )
135 })
136 }
137
138 pub(crate) fn is_line_box(&self) -> bool {
139 self.is_line_box
140 }
141
142 pub fn print(&self, tree: &mut PrintTree) {
143 tree.new_level(format!(
144 "PositioningFragment\
145 \nbase={:?}\
146 \nrect={:?}\
147 \nscrollable_overflow={:?}",
148 self.base,
149 self.base.rect(),
150 self.scrollable_overflow
151 ));
152
153 for child in &self.children {
154 child.print(tree);
155 }
156 tree.end_level();
157 }
158}