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