1use std::fmt::{Debug, Formatter};
6use std::sync::atomic::{AtomicBool, Ordering};
7
8use app_units::Au;
9use atomic_refcell::AtomicRefCell;
10use euclid::Point2D;
11use layout_api::LayoutDamage;
12use malloc_size_of_derive::MallocSizeOf;
13use servo_arc::Arc;
14use style::computed_values::position::T as Position;
15use style::logical_geometry::WritingMode;
16use style::properties::ComputedValues;
17use style::values::specified::align::AlignFlags;
18use style_traits::CSSPixel;
19
20use crate::context::LayoutContext;
21use crate::dom::{LayoutBox, WeakLayoutBox};
22use crate::flow::CollapsibleWithParentStartMargin;
23use crate::formatting_contexts::Baselines;
24use crate::fragment_tree::{
25 BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, Fragment, FragmentStatus,
26 SpecificLayoutInfo,
27};
28use crate::geom::LogicalSides1D;
29use crate::positioned::{PositioningContext, relative_adjustement};
30use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult, SizeConstraint};
31use crate::{ArcRefCell, ConstraintSpace, ContainingBlock, ContainingBlockSize};
32
33#[derive(MallocSizeOf)]
40pub(crate) struct LayoutBoxBase {
41 pub base_fragment_info: BaseFragmentInfo,
42 pub style: Arc<ComputedValues>,
43 pub cached_inline_content_size:
44 AtomicRefCell<Option<Box<(SizeConstraint, InlineContentSizesResult)>>>,
45 pub outer_inline_content_sizes_depend_on_content: AtomicBool,
46 pub cached_layout_result: AtomicRefCell<Option<LayoutResultAndInputs>>,
47 pub fragments: AtomicRefCell<Vec<Fragment>>,
48 pub parent_box: Option<WeakLayoutBox>,
49}
50
51impl LayoutBoxBase {
52 pub(crate) fn new(base_fragment_info: BaseFragmentInfo, style: Arc<ComputedValues>) -> Self {
53 Self {
54 base_fragment_info,
55 style,
56 cached_inline_content_size: AtomicRefCell::default(),
57 outer_inline_content_sizes_depend_on_content: AtomicBool::new(true),
58 cached_layout_result: AtomicRefCell::default(),
59 fragments: AtomicRefCell::default(),
60 parent_box: None,
61 }
62 }
63
64 pub(crate) fn inline_content_sizes(
67 &self,
68 layout_context: &LayoutContext,
69 constraint_space: &ConstraintSpace,
70 layout_box: &impl ComputeInlineContentSizes,
71 ) -> InlineContentSizesResult {
72 let mut cache = self.cached_inline_content_size.borrow_mut();
73 if let Some(cached_inline_content_size) = cache.as_ref() {
74 let (previous_cb_block_size, result) = **cached_inline_content_size;
75 if !result.depends_on_block_constraints ||
76 previous_cb_block_size == constraint_space.block_size
77 {
78 return result;
79 }
80 }
82
83 let result =
84 layout_box.compute_inline_content_sizes_with_fixup(layout_context, constraint_space);
85 *cache = Some(Box::new((constraint_space.block_size, result)));
86 result
87 }
88
89 pub(crate) fn fragments(&self) -> Vec<Fragment> {
90 self.fragments.borrow().clone()
91 }
92
93 pub(crate) fn add_fragment(&self, fragment: Fragment) {
94 self.fragments.borrow_mut().push(fragment);
95 }
96
97 pub(crate) fn set_fragment(&self, fragment: Fragment) {
98 *self.fragments.borrow_mut() = vec![fragment];
99 }
100
101 pub(crate) fn clear_fragments(&self) {
102 self.fragments.borrow_mut().clear();
103 }
104
105 pub(crate) fn clear_fragments_and_fragment_cache(&self) {
106 self.fragments.borrow_mut().clear();
107 *self.cached_layout_result.borrow_mut() = None;
108 }
109
110 pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
111 self.style = new_style.clone();
112 for fragment in self.fragments.borrow_mut().iter_mut() {
113 if let Some(mut base) = fragment.base_mut() {
114 base.repair_style(new_style);
115 }
116 }
117 }
118
119 #[expect(unused)]
120 pub(crate) fn parent_box(&self) -> Option<LayoutBox> {
121 self.parent_box.as_ref().and_then(WeakLayoutBox::upgrade)
122 }
123
124 pub(crate) fn add_damage(
125 &self,
126 element_damage: LayoutDamage,
127 damage_from_children: LayoutDamage,
128 ) -> LayoutDamage {
129 self.clear_fragments_and_fragment_cache();
130
131 if !element_damage.is_empty() ||
132 damage_from_children.contains(LayoutDamage::RECOMPUTE_INLINE_CONTENT_SIZES)
133 {
134 *self.cached_inline_content_size.borrow_mut() = None;
135 }
136
137 let mut damage_for_parent = element_damage | damage_from_children;
138
139 damage_for_parent.set(
150 LayoutDamage::RECOMPUTE_INLINE_CONTENT_SIZES,
151 !element_damage.is_empty() ||
152 (!self.base_fragment_info.is_anonymous() &&
153 self.outer_inline_content_sizes_depend_on_content
154 .load(Ordering::Relaxed)),
155 );
156
157 damage_for_parent
158 }
159
160 pub(crate) fn cached_same_formatting_context_block_if_applicable(
161 &self,
162 containing_block: &ContainingBlock,
163 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
164 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
165 has_inline_parent: bool,
166 ) -> Option<ArcRefCell<BoxFragment>> {
167 let mut cached_layout_result = self.cached_layout_result.borrow_mut();
168 let Some(LayoutResultAndInputs::SameFormattingContextBlock(result)) =
169 &mut *cached_layout_result
170 else {
171 return None;
172 };
173
174 if result.containing_block_size != containing_block.size ||
175 result.containing_block_writing_mode != containing_block.style.writing_mode ||
176 result.containing_block_justify_items !=
177 containing_block.style.clone_justify_items().computed.0.0 ||
178 result.collapsible_with_parent_start_margin != collapsible_with_parent_start_margin ||
179 result.ignore_block_margins_for_stretch != ignore_block_margins_for_stretch ||
180 result.has_inline_parent != has_inline_parent
181 {
182 return None;
183 }
184
185 let fragment = result.result.fragment.clone();
186 {
187 let mut borrowed_fragment = fragment.borrow_mut();
188
189 borrowed_fragment.base.status = FragmentStatus::PositionMaybeChanged;
194
195 borrowed_fragment.base.rect.origin = result.result.original_offset;
196 if self.style.clone_position() == Position::Relative {
197 borrowed_fragment.base.rect.origin +=
198 relative_adjustement(&self.style, containing_block)
199 .to_physical_vector(containing_block.style.writing_mode)
200 }
201 }
202
203 Some(fragment)
204 }
205
206 pub(crate) fn cache_same_formatting_context_block_layout(
207 &self,
208 containing_block: &ContainingBlock,
209 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
210 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
211 has_inline_parent: bool,
212 fragment: ArcRefCell<BoxFragment>,
213 ) {
214 let mut original_offset;
215 {
216 let borrowed_fragment = fragment.borrow();
217 original_offset = borrowed_fragment.content_rect().origin;
218 if self.style.clone_position() == Position::Relative {
219 original_offset -= relative_adjustement(&self.style, containing_block)
220 .to_physical_vector(containing_block.style.writing_mode)
221 }
222 }
223
224 *self.cached_layout_result.borrow_mut() =
225 Some(LayoutResultAndInputs::SameFormattingContextBlock(Box::new(
226 SameFormattingContextBlockLayoutResultAndInputs {
227 result: SameFormattingContextBlockLayoutResult {
228 fragment,
229 original_offset,
230 },
231 containing_block_size: containing_block.size.clone(),
232 containing_block_writing_mode: containing_block.style.writing_mode,
233 containing_block_justify_items: containing_block
234 .style
235 .clone_justify_items()
236 .computed
237 .0
238 .0,
239 collapsible_with_parent_start_margin,
240 ignore_block_margins_for_stretch,
241 has_inline_parent,
242 },
243 )));
244 }
245}
246
247impl Debug for LayoutBoxBase {
248 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
249 f.debug_struct("LayoutBoxBase").finish()
250 }
251}
252
253#[derive(MallocSizeOf)]
254pub(crate) enum LayoutResultAndInputs {
255 IndependentFormattingContext(Box<IndependentFormattingContextLayoutResultAndInputs>),
256 SameFormattingContextBlock(Box<SameFormattingContextBlockLayoutResultAndInputs>),
257}
258
259#[derive(Clone, MallocSizeOf)]
260pub(crate) struct IndependentFormattingContextLayoutResult {
261 pub fragments: Vec<Fragment>,
262
263 pub content_block_size: Au,
265
266 pub collapsible_margins_in_children: CollapsedBlockMargins,
269
270 pub content_inline_size_for_table: Option<Au>,
274
275 pub baselines: Baselines,
279
280 pub depends_on_block_constraints: bool,
282
283 pub specific_layout_info: Option<SpecificLayoutInfo>,
285}
286
287#[derive(MallocSizeOf)]
290pub(crate) struct IndependentFormattingContextLayoutResultAndInputs {
291 pub result: IndependentFormattingContextLayoutResult,
293
294 pub containing_block_for_children_size: ContainingBlockSize,
297
298 pub positioning_context: PositioningContext,
301}
302
303#[derive(Clone, MallocSizeOf)]
304pub(crate) struct SameFormattingContextBlockLayoutResult {
305 pub fragment: ArcRefCell<BoxFragment>,
306 original_offset: Point2D<Au, CSSPixel>,
307}
308
309#[derive(MallocSizeOf)]
312pub(crate) struct SameFormattingContextBlockLayoutResultAndInputs {
313 pub result: SameFormattingContextBlockLayoutResult,
314 pub containing_block_size: ContainingBlockSize,
316 pub containing_block_writing_mode: WritingMode,
318 pub containing_block_justify_items: AlignFlags,
320 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
323 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
325 has_inline_parent: bool,
327}