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