1use std::marker::PhantomData;
6
7use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
8use layout_api::{
9 GenericLayoutDataTrait, LayoutDataTrait, LayoutElement, LayoutElementType, LayoutNode,
10 LayoutNodeType as ScriptLayoutNodeType, NodeRenderingType, SVGElementData,
11};
12use malloc_size_of_derive::MallocSizeOf;
13use script::layout_dom::ServoLayoutNode;
14use servo_arc::Arc as ServoArc;
15use servo_base::text::{AssumeUnder4GB, RangeAny, Utf32CodeUnits};
16use smallvec::SmallVec;
17use style::context::SharedStyleContext;
18use style::properties::ComputedValues;
19use style::selector_parser::PseudoElement;
20use style::values::specified::box_::DisplayOutside as StyloDisplayOutside;
21use web_atoms::{local_name, ns};
22
23use crate::cell::{ArcRefCell, WeakRefCell};
24use crate::context::LayoutContext;
25use crate::dom_traversal::{Contents, NodeAndStyleInfo};
26use crate::flexbox::FlexLevelBox;
27use crate::flow::inline::text_run::TextRun;
28use crate::flow::inline::{
29 InlineFormattingContext, InlineItem, SharedInlineStyles, WeakInlineItem,
30};
31use crate::flow::{BlockLevelBox, BlockLevelCreator};
32use crate::formatting_contexts::IndependentFormattingContext;
33use crate::fragment_tree::{Fragment, FragmentFlags};
34use crate::geom::PhysicalSize;
35use crate::layout_box_base::LayoutBoxBase;
36use crate::replaced::{CanvasInfo, IFrameInfo, ImageInfo, VideoInfo};
37use crate::style_ext::{
38 ComputedValuesExt, Display, DisplayGeneratingBox, DisplayLayoutInternal, DisplayOutside,
39};
40use crate::table::{TableLevelBox, WeakTableLevelBox};
41use crate::taffy::{TaffyItemBox, TaffyItemBoxInner};
42
43#[derive(MallocSizeOf)]
44pub struct PseudoLayoutData {
45 pseudo: PseudoElement,
46 data: ArcRefCell<InnerDOMLayoutData>,
47}
48
49#[derive(Default, MallocSizeOf)]
51pub struct InnerDOMLayoutData {
52 pub(super) self_box: ArcRefCell<Option<LayoutBox>>,
53 pub(super) pseudo_boxes: SmallVec<[PseudoLayoutData; 2]>,
54}
55
56impl InnerDOMLayoutData {
57 fn pseudo_layout_data(
58 &self,
59 pseudo_element: PseudoElement,
60 ) -> Option<ArcRefCell<InnerDOMLayoutData>> {
61 for pseudo_layout_data in self.pseudo_boxes.iter() {
62 if pseudo_element == pseudo_layout_data.pseudo {
63 return Some(pseudo_layout_data.data.clone());
64 }
65 }
66 None
67 }
68
69 fn create_pseudo_layout_data(
70 &mut self,
71 pseudo_element: PseudoElement,
72 ) -> ArcRefCell<InnerDOMLayoutData> {
73 let data: ArcRefCell<InnerDOMLayoutData> = Default::default();
74 self.pseudo_boxes.push(PseudoLayoutData {
75 pseudo: pseudo_element,
76 data: data.clone(),
77 });
78 data
79 }
80
81 fn fragments(&self) -> Vec<Fragment> {
82 self.with_fragments(<[Fragment]>::to_vec)
83 .unwrap_or_default()
84 }
85
86 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T> {
88 let self_box = self.self_box.borrow();
89 let layout_box = self_box.as_ref()?;
90 layout_box.with_base(|base| callback(&base.fragments()))
91 }
92
93 fn repair_style(&self, node: &ServoLayoutNode, context: &SharedStyleContext) {
94 if let Some(layout_object) = &*self.self_box.borrow() {
95 layout_object.repair_style(context, node, &node.style(context));
96 }
97
98 for pseudo_layout_data in self.pseudo_boxes.iter() {
99 let Some(node_with_pseudo) = node.with_pseudo(pseudo_layout_data.pseudo) else {
100 continue;
101 };
102 pseudo_layout_data
103 .data
104 .borrow()
105 .repair_style(&node_with_pseudo, context);
106 }
107 }
108
109 fn with_layout_box_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T> {
110 self.self_box
111 .borrow()
112 .as_ref()
113 .and_then(|data| data.with_base(callback))
114 }
115
116 fn with_layout_box_base_including_pseudos(&self, mut callback: impl FnMut(&LayoutBoxBase)) {
117 self.with_layout_box_base(&mut callback);
118 for pseudo_layout_data in self.pseudo_boxes.iter() {
119 pseudo_layout_data
120 .data
121 .borrow()
122 .with_layout_box_base(&mut callback);
123 }
124 }
125}
126
127#[derive(Debug, MallocSizeOf)]
129pub(super) enum LayoutBox {
130 DisplayContents(SharedInlineStyles),
131 BlockLevel(ArcRefCell<BlockLevelBox>),
132 InlineLevel(InlineItem),
133 FlexLevel(ArcRefCell<FlexLevelBox>),
134 TableLevelBox(TableLevelBox),
135 TaffyItemBox(ArcRefCell<TaffyItemBox>),
136 Text(ArcRefCell<TextRun>),
137 Widget(ArcRefCell<IndependentFormattingContext>),
138}
139
140impl LayoutBox {
141 fn parent(&self) -> Option<LayoutBox> {
142 match self {
143 LayoutBox::Text(text_run) => text_run
144 .borrow()
145 .parent_box
146 .as_ref()
147 .and_then(WeakLayoutBox::upgrade),
148 _ => self.with_base(|base| base.parent_box()).flatten(),
149 }
150 }
151
152 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T> {
153 Some(match self {
154 LayoutBox::DisplayContents(..) | LayoutBox::Text(..) => return None,
155 LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().with_base(callback),
156 LayoutBox::InlineLevel(inline_item) => inline_item.with_base(callback),
157 LayoutBox::FlexLevel(flex_level_box) => flex_level_box.borrow().with_base(callback),
158 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box.borrow().with_base(callback),
159 LayoutBox::TableLevelBox(table_box) => table_box.with_base(callback),
160 LayoutBox::Widget(widget_context) => callback(&widget_context.borrow().base),
161 })
162 }
163
164 pub(crate) fn with_base_mut<T>(
165 &mut self,
166 callback: impl FnOnce(&mut LayoutBoxBase) -> T,
167 ) -> Option<T> {
168 Some(match self {
169 LayoutBox::DisplayContents(..) | LayoutBox::Text(..) => return None,
170 LayoutBox::BlockLevel(block_level_box) => {
171 block_level_box.borrow_mut().with_base_mut(callback)
172 },
173 LayoutBox::InlineLevel(inline_item) => inline_item.with_base_mut(callback),
174 LayoutBox::FlexLevel(flex_level_box) => {
175 flex_level_box.borrow_mut().with_base_mut(callback)
176 },
177 LayoutBox::TaffyItemBox(taffy_item_box) => {
178 taffy_item_box.borrow_mut().with_base_mut(callback)
179 },
180 LayoutBox::TableLevelBox(table_box) => table_box.with_base_mut(callback),
181 LayoutBox::Widget(widget_context) => callback(&mut widget_context.borrow_mut().base),
182 })
183 }
184
185 fn repair_style(
186 &self,
187 context: &SharedStyleContext,
188 node: &ServoLayoutNode,
189 new_style: &ServoArc<ComputedValues>,
190 ) {
191 match self {
192 LayoutBox::DisplayContents(inline_shared_styles) => {
193 *inline_shared_styles.style.borrow_mut() = new_style.clone();
194 *inline_shared_styles.selected.borrow_mut() = node.selected_style(context);
195 },
196 LayoutBox::BlockLevel(block_level_box) => {
197 block_level_box
198 .borrow_mut()
199 .repair_style(context, node, new_style);
200 },
201 LayoutBox::InlineLevel(inline_item) => {
202 inline_item.repair_style(context, node, new_style);
203 },
204 LayoutBox::FlexLevel(flex_level_box) => flex_level_box
205 .borrow_mut()
206 .repair_style(context, node, new_style),
207 LayoutBox::TableLevelBox(table_level_box) => {
208 table_level_box.repair_style(context, node, new_style)
209 },
210 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box
211 .borrow_mut()
212 .repair_style(context, node, new_style),
213 LayoutBox::Text(..) => {
214 },
216 LayoutBox::Widget(widget_context) => widget_context
217 .borrow_mut()
218 .repair_style(context, node, new_style),
219 }
220 }
221
222 fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
223 match self {
224 Self::DisplayContents(_) => {
225 },
228 Self::BlockLevel(block_level_box) => {
229 block_level_box.borrow().attached_to_tree(layout_box)
230 },
231 Self::InlineLevel(inline_item) => inline_item.attached_to_tree(layout_box),
232 Self::FlexLevel(flex_level_box) => flex_level_box.borrow().attached_to_tree(layout_box),
233 Self::TableLevelBox(table_level_box) => table_level_box.attached_to_tree(layout_box),
234 Self::TaffyItemBox(taffy_item_box) => {
235 taffy_item_box.borrow().attached_to_tree(layout_box)
236 },
237 Self::Text(..) => {
238 },
240 LayoutBox::Widget(widget_context) => {
241 widget_context.borrow().attached_to_tree(layout_box)
242 },
243 }
244 }
245
246 fn downgrade(&self) -> WeakLayoutBox {
247 match self {
248 Self::DisplayContents(inline_shared_styles) => {
249 WeakLayoutBox::DisplayContents(inline_shared_styles.clone())
250 },
251 Self::BlockLevel(block_level_box) => {
252 WeakLayoutBox::BlockLevel(block_level_box.downgrade())
253 },
254 Self::InlineLevel(inline_item) => WeakLayoutBox::InlineLevel(inline_item.downgrade()),
255 Self::FlexLevel(flex_level_box) => WeakLayoutBox::FlexLevel(flex_level_box.downgrade()),
256 Self::TableLevelBox(table_level_box) => {
257 WeakLayoutBox::TableLevelBox(table_level_box.downgrade())
258 },
259 Self::TaffyItemBox(taffy_item_box) => {
260 WeakLayoutBox::TaffyItemBox(taffy_item_box.downgrade())
261 },
262 Self::Text(text_run) => WeakLayoutBox::Text(text_run.downgrade()),
263 Self::Widget(widget_context) => WeakLayoutBox::Widget(widget_context.downgrade()),
264 }
265 }
266
267 fn with_independent_formatting_context<T>(
268 &self,
269 callback: impl FnOnce(&IndependentFormattingContext) -> Option<T>,
270 ) -> Option<T> {
271 match self {
272 LayoutBox::DisplayContents(..) => None,
273 LayoutBox::BlockLevel(block_level_box) => match &*block_level_box.borrow() {
274 BlockLevelBox::Independent(independent_formatting_context) => {
275 callback(independent_formatting_context)
276 },
277 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned) => {
278 callback(&positioned.borrow().context)
279 },
280 BlockLevelBox::OutOfFlowFloatBox(float) => callback(&float.contents),
281 BlockLevelBox::OutsideMarker(..) |
282 BlockLevelBox::SameFormattingContextBlock(..) => None,
283 },
284 LayoutBox::InlineLevel(inline_item) => match inline_item {
285 InlineItem::Atomic(atomic_item, ..) => callback(&atomic_item.borrow()),
286 InlineItem::OutOfFlowFloatBox(float) => callback(&float.borrow().contents),
287 InlineItem::OutOfFlowAbsolutelyPositionedBox(absolute, ..) => {
288 callback(&absolute.borrow().context)
289 },
290 InlineItem::StartInlineBox(..) |
291 InlineItem::EndInlineBox(..) |
292 InlineItem::TextRun(..) |
293 InlineItem::BlockLevel(..) => None,
294 },
295 LayoutBox::FlexLevel(flex_level_box) => match &*flex_level_box.borrow() {
296 FlexLevelBox::FlexItem(flex_item) => {
297 callback(&flex_item.independent_formatting_context)
298 },
299 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(absolute) => {
300 callback(&absolute.borrow().context)
301 },
302 },
303 LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
304 TableLevelBox::Caption(caption) => callback(&caption.borrow().context),
305 TableLevelBox::Cell(cell) => callback(&cell.borrow().context),
306 TableLevelBox::TrackGroup(..) | TableLevelBox::Track(..) => None,
307 },
308 LayoutBox::TaffyItemBox(taffy_item_box) => {
309 match &taffy_item_box.borrow().taffy_level_box {
310 TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
311 callback(independent_formatting_context)
312 },
313 TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(absolute) => {
314 callback(&absolute.borrow().context)
315 },
316 }
317 },
318 LayoutBox::Text(..) => None,
319 LayoutBox::Widget(widget_context) => callback(&widget_context.borrow()),
320 }
321 }
322
323 pub(crate) fn with_inline_formatting_context<T>(
324 &self,
325 callback: impl FnOnce(&InlineFormattingContext) -> Option<T>,
326 ) -> Option<T> {
327 if let LayoutBox::BlockLevel(block_level_box) = self &&
328 let BlockLevelBox::SameFormattingContextBlock(same_formatting_context_block) =
329 &*block_level_box.borrow() &&
330 let Some(inline_formatting_context) = same_formatting_context_block
331 .contents
332 .inline_formatting_context()
333 {
334 return callback(inline_formatting_context);
335 }
336
337 self.with_independent_formatting_context(|independent_formatting_context| {
338 independent_formatting_context
339 .inline_formatting_context()
340 .and_then(callback)
341 })
342 }
343
344 pub(crate) fn layout_box_for_containing_inline_formatting_context(&self) -> Option<LayoutBox> {
345 let mut current = self.parent()?;
346 while let LayoutBox::InlineLevel(InlineItem::StartInlineBox(..)) = current {
347 current = current.parent()?;
348 }
349 Some(current)
350 }
351}
352
353#[derive(Clone, Debug, MallocSizeOf)]
354pub(super) enum WeakLayoutBox {
355 DisplayContents(SharedInlineStyles),
356 BlockLevel(WeakRefCell<BlockLevelBox>),
357 InlineLevel(WeakInlineItem),
358 FlexLevel(WeakRefCell<FlexLevelBox>),
359 TableLevelBox(WeakTableLevelBox),
360 TaffyItemBox(WeakRefCell<TaffyItemBox>),
361 Text(WeakRefCell<TextRun>),
362 Widget(WeakRefCell<IndependentFormattingContext>),
363}
364
365impl WeakLayoutBox {
366 pub(crate) fn upgrade(&self) -> Option<LayoutBox> {
367 Some(match self {
368 Self::DisplayContents(inline_shared_styles) => {
369 LayoutBox::DisplayContents(inline_shared_styles.clone())
370 },
371 Self::BlockLevel(block_level_box) => LayoutBox::BlockLevel(block_level_box.upgrade()?),
372 Self::InlineLevel(inline_item) => LayoutBox::InlineLevel(inline_item.upgrade()?),
373 Self::FlexLevel(flex_level_box) => LayoutBox::FlexLevel(flex_level_box.upgrade()?),
374 Self::TableLevelBox(table_level_box) => {
375 LayoutBox::TableLevelBox(table_level_box.upgrade()?)
376 },
377 Self::TaffyItemBox(taffy_item_box) => {
378 LayoutBox::TaffyItemBox(taffy_item_box.upgrade()?)
379 },
380 Self::Text(text_run) => LayoutBox::Text(text_run.upgrade()?),
381 Self::Widget(widget_context) => LayoutBox::Widget(widget_context.upgrade()?),
382 })
383 }
384}
385
386#[derive(Default, MallocSizeOf)]
390pub struct DOMLayoutData(AtomicRefCell<InnerDOMLayoutData>);
391
392impl LayoutDataTrait for DOMLayoutData {}
394impl GenericLayoutDataTrait for DOMLayoutData {
395 fn as_any(&self) -> &dyn std::any::Any {
396 self
397 }
398
399 fn set_text_run_selection(&self, new_range: Option<RangeAny<Utf32CodeUnits>>) -> bool {
400 let inner = self.0.borrow();
401 if inner
404 .pseudo_boxes
405 .iter()
406 .any(|pseudo_box| matches!(pseudo_box.pseudo, PseudoElement::FirstLetter))
407 {
408 return false;
409 }
410 if let Some(LayoutBox::Text(text_run)) = &*inner.self_box.borrow() {
411 *text_run.borrow().run_data.selection.borrow_mut() = new_range;
412 true
413 } else {
414 false
415 }
416 }
417
418 fn set_element_selection(&self, selected: bool) -> bool {
419 let inner = self.0.borrow();
420 let inner_box = inner.self_box.borrow();
421 let Some(inner_box) = &*inner_box else {
422 return false;
423 };
424 inner_box
425 .with_independent_formatting_context(|independent_formatting_context| {
426 Some(independent_formatting_context.set_selection(selected))
427 })
428 .unwrap_or(false)
429 }
430
431 fn rendered_text(&self, range: RangeAny<Utf32CodeUnits>) -> Option<String> {
432 let inner = self.0.borrow();
433 let self_box = inner.self_box.borrow();
434
435 let Some(LayoutBox::Text(text_run)) = self_box.as_ref() else {
436 return None;
437 };
438
439 let text_run = text_run.borrow();
440 let range_in_text_run = text_run.run_data.map_dom_range_to_transformed_range(range);
441 let start_in_ifc = text_run.run_data.character_range_in_ifc_text.start;
442
443 let string = text_run.run_data.text_content.get()?;
444 let start =
445 (range_in_text_run.start + start_in_ifc).to_utf8_code_units_in(AssumeUnder4GB, string);
446 let end =
447 (range_in_text_run.end + start_in_ifc).to_utf8_code_units_in(AssumeUnder4GB, string);
448 Some(string[start.0 as usize..end.0 as usize].to_owned())
449 }
450}
451
452pub struct BoxSlot<'dom> {
453 pub(crate) slot: ArcRefCell<Option<LayoutBox>>,
454 pub(crate) marker: PhantomData<&'dom ()>,
455}
456
457impl From<ArcRefCell<Option<LayoutBox>>> for BoxSlot<'_> {
458 fn from(slot: ArcRefCell<Option<LayoutBox>>) -> Self {
459 Self {
460 slot,
461 marker: PhantomData,
462 }
463 }
464}
465
466impl BoxSlot<'_> {
468 pub(crate) fn set(self, layout_box: LayoutBox) {
469 layout_box.attached_to_tree(layout_box.downgrade());
470 *self.slot.borrow_mut() = Some(layout_box);
471 }
472
473 pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> {
474 self.slot.borrow_mut().take()
475 }
476
477 pub(crate) fn take_layout_box_as_text_run(&self) -> Option<ArcRefCell<TextRun>> {
481 match self.take_layout_box()? {
482 LayoutBox::Text(old_text_run) => Some(old_text_run),
483 _ => None,
484 }
485 }
486}
487
488impl Drop for BoxSlot<'_> {
489 fn drop(&mut self) {
490 if !std::thread::panicking() {
491 assert!(self.slot.borrow().is_some(), "failed to set a layout box");
492 }
493 }
494}
495
496pub(crate) trait NodeExt<'dom> {
497 fn is_html_br_element(&self) -> bool;
499 fn is_html_wbr_element(&self) -> bool;
501 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)>;
503 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
504 fn as_iframe(&self) -> Option<IFrameInfo>;
505 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)>;
506 fn as_svg(&self) -> Option<SVGElementData<'dom>>;
507 fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
508
509 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
510 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
511 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>>;
512 fn box_slot(&self) -> BoxSlot<'dom>;
513
514 fn unset_all_boxes(&self);
516
517 fn clear_fragments_and_dirty_fragment_caches(&self);
520
521 fn clear_fragments_and_dirty_fragment_caches_recursively(&self);
525
526 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self);
529
530 fn rendering_type(&self) -> NodeRenderingType;
534
535 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
536
537 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T>;
539 fn with_layout_box_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T>;
542 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase));
543
544 fn repair_style(&self, context: &SharedStyleContext);
545
546 fn isolates_damage_for_damage_propagation(&self) -> bool;
557
558 fn rebuild_box_tree_from_independent_formatting_context(
565 &self,
566 layout_context: &LayoutContext,
567 ) -> bool;
568
569 fn is_absolutely_positioned(&self) -> bool;
572}
573
574impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
575 fn is_html_br_element(&self) -> bool {
576 self.as_html_element()
577 .is_some_and(|element| element.local_name() == &local_name!("br"))
578 }
579
580 fn is_html_wbr_element(&self) -> bool {
581 self.as_html_element()
582 .is_some_and(|element| element.local_name() == &local_name!("wbr"))
583 }
584
585 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)> {
586 let (resource, metadata) = self.image_data()?;
587 let width = metadata.map(|metadata| metadata.width).unwrap_or_default();
588 let height = metadata.map(|metadata| metadata.height).unwrap_or_default();
589 let (mut width, mut height) = (width as f64, height as f64);
590 if let Some(density) = self.image_density().filter(|density| *density != 1.) {
592 width /= density;
593 height /= density;
594 }
595 Some((
596 ImageInfo {
597 load_time: self.load_time(),
598 image: resource,
599 showing_broken_image_icon: self.showing_broken_image_icon(),
600 url: self.image_url(),
601 },
602 PhysicalSize::new(width, height),
603 ))
604 }
605
606 fn as_svg(&self) -> Option<SVGElementData<'dom>> {
607 self.svg_data()
608 }
609
610 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)> {
611 let data = self.media_data()?;
612 let natural_size = if let Some(frame) = data.current_frame {
613 Some(PhysicalSize::new(frame.width.into(), frame.height.into()))
614 } else {
615 data.metadata
616 .map(|meta| PhysicalSize::new(meta.width.into(), meta.height.into()))
617 };
618 Some((
619 VideoInfo {
620 image_key: data.current_frame.map(|frame| frame.image_key),
621 poster_or_src_url: data.poster_or_src_url,
622 },
623 natural_size,
624 ))
625 }
626
627 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
628 let canvas_data = self.canvas_data()?;
629 let source = canvas_data.image_key;
630 Some((
631 CanvasInfo { source },
632 PhysicalSize::new(canvas_data.width.into(), canvas_data.height.into()),
633 ))
634 }
635
636 fn as_iframe(&self) -> Option<IFrameInfo> {
637 match (self.iframe_pipeline_id(), self.iframe_browsing_context_id()) {
638 (Some(pipeline_id), Some(browsing_context_id)) => Some(IFrameInfo {
639 pipeline_id,
640 browsing_context_id,
641 }),
642 _ => None,
643 }
644 }
645
646 fn as_typeless_object_with_data_attribute(&self) -> Option<String> {
647 if self.type_id() !=
648 Some(ScriptLayoutNodeType::Element(
649 LayoutElementType::HTMLObjectElement,
650 ))
651 {
652 return None;
653 }
654
655 let element = self.as_element()?;
659 if element.attribute(&ns!(), &local_name!("type")).is_some() {
660 return None;
661 }
662 element
663 .attribute_as_str(&ns!(), &local_name!("data"))
664 .map(|string| string.to_owned())
665 }
666
667 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
668 if self.layout_data().is_none() {
669 self.initialize_layout_data::<DOMLayoutData>();
670 }
671 self.layout_data()
672 .unwrap()
673 .as_any()
674 .downcast_ref::<DOMLayoutData>()
675 .unwrap()
676 .0
677 .borrow_mut()
678 }
679
680 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
681 self.layout_data().map(|data| {
682 data.as_any()
683 .downcast_ref::<DOMLayoutData>()
684 .unwrap()
685 .0
686 .borrow()
687 })
688 }
689
690 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>> {
691 self.layout_data().map(|data| {
692 data.as_any()
693 .downcast_ref::<DOMLayoutData>()
694 .unwrap()
695 .0
696 .borrow_mut()
697 })
698 }
699
700 fn box_slot(&self) -> BoxSlot<'dom> {
701 let pseudo_element_chain = self.pseudo_element_chain();
702 let Some(primary) = pseudo_element_chain.primary else {
703 return self.ensure_inner_layout_data().self_box.clone().into();
704 };
705
706 let Some(secondary) = pseudo_element_chain.secondary else {
707 let primary_layout_data = self
708 .ensure_inner_layout_data()
709 .create_pseudo_layout_data(primary);
710 return primary_layout_data.borrow().self_box.clone().into();
711 };
712
713 let primary_layout_data = self
720 .inner_layout_data()
721 .expect("Should already have element InnerLayoutData here.")
722 .pseudo_layout_data(primary)
723 .expect("Should already have primary pseudo-element InnerLayoutData here");
724 let secondary_layout_data = primary_layout_data
725 .borrow_mut()
726 .create_pseudo_layout_data(secondary);
727 secondary_layout_data.borrow().self_box.clone().into()
728 }
729
730 fn unset_all_boxes(&self) {
731 let mut layout_data = self.ensure_inner_layout_data();
732 *layout_data.self_box.borrow_mut() = None;
733 layout_data.pseudo_boxes.clear();
734
735 }
738
739 fn clear_fragments_and_dirty_fragment_caches_recursively(&self) {
740 self.clear_fragments_and_dirty_fragment_caches();
741 self.clear_fragments_and_dirty_fragment_caches_of_descendants();
742 }
743
744 fn clear_fragments_and_dirty_fragment_caches(&self) {
745 self.with_layout_box_base_including_pseudos(|base| {
746 base.clear_fragments_and_dirty_fragment_cache()
747 });
748 }
749
750 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self) {
751 for child in self.flat_tree_children() {
752 child.clear_fragments_and_dirty_fragment_caches_recursively();
753 }
754 }
755
756 fn rendering_type(&self) -> NodeRenderingType {
757 let Some(layout_data) = self.inner_layout_data() else {
758 return NodeRenderingType::NotRendered;
759 };
760 match &*layout_data.self_box.borrow() {
761 Some(LayoutBox::DisplayContents(..)) => NodeRenderingType::DelegatesRendering,
762 Some(..) => NodeRenderingType::Rendered,
763 None => NodeRenderingType::NotRendered,
764 }
765 }
766
767 fn with_layout_box_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T> {
768 let pseudo_element_chain = self.pseudo_element_chain();
769 let inner_layout_data = self.inner_layout_data()?;
770 let Some(primary) = pseudo_element_chain.primary else {
771 return inner_layout_data.with_layout_box_base(callback);
772 };
773
774 let primary_data = inner_layout_data.pseudo_layout_data(primary)?;
775 drop(inner_layout_data);
776 let Some(secondary) = pseudo_element_chain.secondary else {
777 return primary_data.borrow().with_layout_box_base(callback);
778 };
779
780 primary_data
781 .borrow()
782 .pseudo_layout_data(secondary)?
783 .borrow()
784 .with_layout_box_base(callback)
785 }
786
787 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase)) {
788 if let Some(inner_layout_data) = self.inner_layout_data() {
789 inner_layout_data.with_layout_box_base_including_pseudos(callback);
790 }
791 }
792
793 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment> {
794 let Some(layout_data) = self.inner_layout_data() else {
795 return vec![];
796 };
797 match pseudo_element {
798 Some(pseudo_element) => layout_data
799 .pseudo_layout_data(pseudo_element)
800 .map(|pseudo_layout_data| pseudo_layout_data.borrow().fragments())
801 .unwrap_or_default(),
802 None => layout_data.fragments(),
803 }
804 }
805
806 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T> {
807 self.inner_layout_data()?.with_fragments(callback)
808 }
809
810 fn repair_style(&self, context: &SharedStyleContext) {
811 if let Some(layout_data) = self.inner_layout_data() {
812 layout_data.repair_style(self, context);
813 }
814 }
815
816 fn isolates_damage_for_damage_propagation(&self) -> bool {
817 if self.as_element().is_some_and(|element| {
821 element.is_body_element_of_html_element_root() || element.is_root()
822 }) {
823 return false;
824 }
825
826 let Some(inner_layout_data) = self.inner_layout_data() else {
827 return false;
828 };
829 let self_box = inner_layout_data.self_box.borrow();
830 let Some(self_box) = &*self_box else {
831 return false;
832 };
833
834 match self_box {
835 LayoutBox::DisplayContents(..) => false,
836 LayoutBox::BlockLevel(block_level) => matches!(
837 &*block_level.borrow(),
838 BlockLevelBox::Independent(..) |
839 BlockLevelBox::OutOfFlowFloatBox(..) |
840 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(..)
841 ),
842 LayoutBox::InlineLevel(inline_level) => matches!(
843 inline_level,
844 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) | InlineItem::Atomic(..)
845 ),
846 LayoutBox::FlexLevel(..) => true,
847 LayoutBox::TableLevelBox(table_level_box) => matches!(
848 table_level_box,
849 TableLevelBox::Cell(..) | TableLevelBox::Caption(..),
850 ),
851 LayoutBox::TaffyItemBox(..) => true,
852 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
853 LayoutBox::Widget(..) => unreachable!("Widgets are always pseudo-elements."),
854 }
855 }
856
857 fn rebuild_box_tree_from_independent_formatting_context(
858 &self,
859 layout_context: &LayoutContext,
860 ) -> bool {
861 if self.as_element().is_some_and(|element| {
865 element.is_body_element_of_html_element_root() || element.is_root()
866 }) {
867 return false;
868 }
869
870 let layout_box = {
871 let Some(mut inner_layout_data) = self.inner_layout_data_mut() else {
872 return false;
873 };
874 inner_layout_data.pseudo_boxes.clear();
875 inner_layout_data.self_box.clone()
876 };
877
878 let layout_box = layout_box.borrow();
879 let Some(layout_box) = &*layout_box else {
880 return false;
881 };
882
883 let info = NodeAndStyleInfo::new(*self, self.style(&layout_context.style_context));
884 let box_style = info.style.get_box();
885 let Display::GeneratingBox(display) = box_style.display.into() else {
886 return false;
887 };
888 let contents = || {
889 assert!(
890 self.pseudo_element_chain().is_empty(),
891 "Shouldn't try to rebuild box tree from a pseudo-element"
892 );
893 Contents::for_element(info.node, layout_context)
894 };
895 match layout_box {
896 LayoutBox::DisplayContents(..) => false,
897 LayoutBox::BlockLevel(block_level) => {
898 let mut block_level = block_level.borrow_mut();
899 match &mut *block_level {
900 BlockLevelBox::Independent(independent_formatting_context) => {
901 if box_style.position.is_absolutely_positioned() ||
902 box_style.float.is_floating()
903 {
904 return false;
905 }
906 let DisplayGeneratingBox::OutsideInside {
907 outside: DisplayOutside::Block,
908 inside: display_inside,
909 } = display
910 else {
911 return false;
912 };
913 if !matches!(
914 BlockLevelCreator::new_for_inflow_block_level_element(
915 &info,
916 display_inside,
917 contents(),
918 independent_formatting_context.propagated_data,
919 ),
920 BlockLevelCreator::Independent { .. }
921 ) {
922 return false;
923 }
924 independent_formatting_context.rebuild(layout_context, &info);
925 true
926 },
927 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
928 if !info.style.get_float().is_floating() {
929 return false;
930 }
931 float_box.contents.rebuild(layout_context, &info);
932 true
933 },
934 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
935 if !info.style.get_box().position.is_absolutely_positioned() ||
940 box_style.original_display.outside() != StyloDisplayOutside::Block
941 {
942 return false;
943 }
944 positioned_box
945 .borrow_mut()
946 .context
947 .rebuild(layout_context, &info);
948 true
949 },
950 _ => false,
951 }
952 },
953 LayoutBox::InlineLevel(inline_level) => match inline_level {
954 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
955 if !info.style.get_box().position.is_absolutely_positioned() {
956 return false;
957 }
958 positioned_box
959 .borrow_mut()
960 .context
961 .rebuild(layout_context, &info);
962 true
963 },
964 InlineItem::Atomic(atomic_box, _, _) => {
965 let flags = match contents() {
966 Contents::NonReplaced(_) => FragmentFlags::empty(),
967 Contents::Replaced(_) => FragmentFlags::IS_REPLACED,
968 Contents::Widget(_) => FragmentFlags::IS_WIDGET,
969 };
970 if !info.style.is_atomic_inline_level(flags) {
971 return false;
972 }
973 atomic_box.borrow_mut().rebuild(layout_context, &info);
974 true
975 },
976 _ => false,
977 },
978 LayoutBox::FlexLevel(flex_level_box) => {
979 let mut flex_level_box = flex_level_box.borrow_mut();
980 match &mut *flex_level_box {
981 FlexLevelBox::FlexItem(flex_item_box) => {
982 if info.style.get_box().position.is_absolutely_positioned() ||
983 !flex_item_box.style().order_equals(&info.style)
984 {
985 return false;
986 }
987 flex_item_box
988 .independent_formatting_context
989 .rebuild(layout_context, &info)
990 },
991 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
992 if !info.style.get_box().position.is_absolutely_positioned() {
993 return false;
994 }
995 positioned_box
996 .borrow_mut()
997 .context
998 .rebuild(layout_context, &info);
999 },
1000 }
1001 true
1002 },
1003 LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
1004 TableLevelBox::Caption(caption) => {
1005 if display !=
1006 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCaption)
1007 {
1008 return false;
1009 }
1010 caption.borrow_mut().context.rebuild(layout_context, &info);
1011 true
1012 },
1013 TableLevelBox::Cell(table_cell) => {
1014 if display !=
1015 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCell)
1016 {
1017 return false;
1018 }
1019 table_cell
1020 .borrow_mut()
1021 .context
1022 .rebuild(layout_context, &info);
1023 true
1024 },
1025 _ => false,
1026 },
1027 LayoutBox::TaffyItemBox(..) => false,
1028 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
1029 LayoutBox::Widget(..) => unreachable!("Widgets are always pseudo-elements."),
1030 }
1031 }
1032
1033 fn is_absolutely_positioned(&self) -> bool {
1034 self.as_element().is_some_and(|element| {
1035 element
1036 .element_data()
1037 .styles
1038 .primary()
1039 .get_box()
1040 .position
1041 .is_absolutely_positioned()
1042 })
1043 }
1044}