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::{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::{InlineItem, SharedInlineStyles, WeakInlineItem};
29use crate::flow::{BlockLevelBox, BlockLevelCreator};
30use crate::fragment_tree::{Fragment, FragmentFlags};
31use crate::geom::PhysicalSize;
32use crate::layout_box_base::LayoutBoxBase;
33use crate::replaced::{CanvasInfo, IFrameInfo, ImageInfo, VideoInfo};
34use crate::style_ext::{
35 ComputedValuesExt, Display, DisplayGeneratingBox, DisplayLayoutInternal, DisplayOutside,
36};
37use crate::table::{TableLevelBox, WeakTableLevelBox};
38use crate::taffy::TaffyItemBox;
39
40#[derive(MallocSizeOf)]
41pub struct PseudoLayoutData {
42 pseudo: PseudoElement,
43 data: ArcRefCell<InnerDOMLayoutData>,
44}
45
46#[derive(Default, MallocSizeOf)]
48pub struct InnerDOMLayoutData {
49 pub(super) self_box: ArcRefCell<Option<LayoutBox>>,
50 pub(super) pseudo_boxes: SmallVec<[PseudoLayoutData; 2]>,
51}
52
53impl InnerDOMLayoutData {
54 fn pseudo_layout_data(
55 &self,
56 pseudo_element: PseudoElement,
57 ) -> Option<ArcRefCell<InnerDOMLayoutData>> {
58 for pseudo_layout_data in self.pseudo_boxes.iter() {
59 if pseudo_element == pseudo_layout_data.pseudo {
60 return Some(pseudo_layout_data.data.clone());
61 }
62 }
63 None
64 }
65
66 fn create_pseudo_layout_data(
67 &mut self,
68 pseudo_element: PseudoElement,
69 ) -> ArcRefCell<InnerDOMLayoutData> {
70 let data: ArcRefCell<InnerDOMLayoutData> = Default::default();
71 self.pseudo_boxes.push(PseudoLayoutData {
72 pseudo: pseudo_element,
73 data: data.clone(),
74 });
75 data
76 }
77
78 fn fragments(&self) -> Vec<Fragment> {
79 self.with_fragments(<[Fragment]>::to_vec)
80 .unwrap_or_default()
81 }
82
83 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T> {
85 let self_box = self.self_box.borrow();
86 let layout_box = self_box.as_ref()?;
87 layout_box.with_base(|base| callback(&base.fragments()))
88 }
89
90 fn repair_style(&self, node: &ServoLayoutNode, context: &SharedStyleContext) {
91 if let Some(layout_object) = &*self.self_box.borrow() {
92 layout_object.repair_style(context, node, &node.style(context));
93 }
94
95 for pseudo_layout_data in self.pseudo_boxes.iter() {
96 let Some(node_with_pseudo) = node.with_pseudo(pseudo_layout_data.pseudo) else {
97 continue;
98 };
99 pseudo_layout_data
100 .data
101 .borrow()
102 .repair_style(&node_with_pseudo, context);
103 }
104 }
105
106 fn with_layout_box_base(&self, callback: impl FnOnce(&LayoutBoxBase)) {
107 if let Some(data) = self.self_box.borrow().as_ref() {
108 data.with_base(callback);
109 }
110 }
111
112 fn with_layout_box_base_including_pseudos(&self, mut callback: impl FnMut(&LayoutBoxBase)) {
113 self.with_layout_box_base(&mut callback);
114 for pseudo_layout_data in self.pseudo_boxes.iter() {
115 pseudo_layout_data
116 .data
117 .borrow()
118 .with_layout_box_base(&mut callback);
119 }
120 }
121}
122
123#[derive(Debug, MallocSizeOf)]
125pub(super) enum LayoutBox {
126 DisplayContents(SharedInlineStyles),
127 BlockLevel(ArcRefCell<BlockLevelBox>),
128 InlineLevel(InlineItem),
129 FlexLevel(ArcRefCell<FlexLevelBox>),
130 TableLevelBox(TableLevelBox),
131 TaffyItemBox(ArcRefCell<TaffyItemBox>),
132 Text(ArcRefCell<TextRun>),
133}
134
135impl LayoutBox {
136 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T> {
137 Some(match self {
138 LayoutBox::DisplayContents(..) | LayoutBox::Text(..) => return None,
139 LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().with_base(callback),
140 LayoutBox::InlineLevel(inline_item) => inline_item.with_base(callback),
141 LayoutBox::FlexLevel(flex_level_box) => flex_level_box.borrow().with_base(callback),
142 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box.borrow().with_base(callback),
143 LayoutBox::TableLevelBox(table_box) => table_box.with_base(callback),
144 })
145 }
146
147 pub(crate) fn with_base_mut<T>(
148 &mut self,
149 callback: impl FnOnce(&mut LayoutBoxBase) -> T,
150 ) -> Option<T> {
151 Some(match self {
152 LayoutBox::DisplayContents(..) | LayoutBox::Text(..) => return None,
153 LayoutBox::BlockLevel(block_level_box) => {
154 block_level_box.borrow_mut().with_base_mut(callback)
155 },
156 LayoutBox::InlineLevel(inline_item) => inline_item.with_base_mut(callback),
157 LayoutBox::FlexLevel(flex_level_box) => {
158 flex_level_box.borrow_mut().with_base_mut(callback)
159 },
160 LayoutBox::TaffyItemBox(taffy_item_box) => {
161 taffy_item_box.borrow_mut().with_base_mut(callback)
162 },
163 LayoutBox::TableLevelBox(table_box) => table_box.with_base_mut(callback),
164 })
165 }
166
167 fn repair_style(
168 &self,
169 context: &SharedStyleContext,
170 node: &ServoLayoutNode,
171 new_style: &ServoArc<ComputedValues>,
172 ) {
173 match self {
174 LayoutBox::DisplayContents(inline_shared_styles) => {
175 *inline_shared_styles.style.borrow_mut() = new_style.clone();
176 *inline_shared_styles.selected.borrow_mut() = node.selected_style(context);
177 },
178 LayoutBox::BlockLevel(block_level_box) => {
179 block_level_box
180 .borrow_mut()
181 .repair_style(context, node, new_style);
182 },
183 LayoutBox::InlineLevel(inline_item) => {
184 inline_item.repair_style(context, node, new_style);
185 },
186 LayoutBox::FlexLevel(flex_level_box) => flex_level_box
187 .borrow_mut()
188 .repair_style(context, node, new_style),
189 LayoutBox::TableLevelBox(table_level_box) => {
190 table_level_box.repair_style(context, node, new_style)
191 },
192 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box
193 .borrow_mut()
194 .repair_style(context, node, new_style),
195 LayoutBox::Text(..) => {
196 },
198 }
199 }
200
201 fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
202 match self {
203 Self::DisplayContents(_) => {
204 },
207 Self::BlockLevel(block_level_box) => {
208 block_level_box.borrow().attached_to_tree(layout_box)
209 },
210 Self::InlineLevel(inline_item) => inline_item.attached_to_tree(layout_box),
211 Self::FlexLevel(flex_level_box) => flex_level_box.borrow().attached_to_tree(layout_box),
212 Self::TableLevelBox(table_level_box) => table_level_box.attached_to_tree(layout_box),
213 Self::TaffyItemBox(taffy_item_box) => {
214 taffy_item_box.borrow().attached_to_tree(layout_box)
215 },
216 Self::Text(..) => {
217 },
219 }
220 }
221
222 fn downgrade(&self) -> WeakLayoutBox {
223 match self {
224 Self::DisplayContents(inline_shared_styles) => {
225 WeakLayoutBox::DisplayContents(inline_shared_styles.clone())
226 },
227 Self::BlockLevel(block_level_box) => {
228 WeakLayoutBox::BlockLevel(block_level_box.downgrade())
229 },
230 Self::InlineLevel(inline_item) => WeakLayoutBox::InlineLevel(inline_item.downgrade()),
231 Self::FlexLevel(flex_level_box) => WeakLayoutBox::FlexLevel(flex_level_box.downgrade()),
232 Self::TableLevelBox(table_level_box) => {
233 WeakLayoutBox::TableLevelBox(table_level_box.downgrade())
234 },
235 Self::TaffyItemBox(taffy_item_box) => {
236 WeakLayoutBox::TaffyItemBox(taffy_item_box.downgrade())
237 },
238 Self::Text(text_run) => WeakLayoutBox::Text(text_run.downgrade()),
239 }
240 }
241}
242
243#[derive(Clone, Debug, MallocSizeOf)]
244pub(super) enum WeakLayoutBox {
245 DisplayContents(SharedInlineStyles),
246 BlockLevel(WeakRefCell<BlockLevelBox>),
247 InlineLevel(WeakInlineItem),
248 FlexLevel(WeakRefCell<FlexLevelBox>),
249 TableLevelBox(WeakTableLevelBox),
250 TaffyItemBox(WeakRefCell<TaffyItemBox>),
251 Text(WeakRefCell<TextRun>),
252}
253
254impl WeakLayoutBox {
255 pub(crate) fn upgrade(&self) -> Option<LayoutBox> {
256 Some(match self {
257 Self::DisplayContents(inline_shared_styles) => {
258 LayoutBox::DisplayContents(inline_shared_styles.clone())
259 },
260 Self::BlockLevel(block_level_box) => LayoutBox::BlockLevel(block_level_box.upgrade()?),
261 Self::InlineLevel(inline_item) => LayoutBox::InlineLevel(inline_item.upgrade()?),
262 Self::FlexLevel(flex_level_box) => LayoutBox::FlexLevel(flex_level_box.upgrade()?),
263 Self::TableLevelBox(table_level_box) => {
264 LayoutBox::TableLevelBox(table_level_box.upgrade()?)
265 },
266 Self::TaffyItemBox(taffy_item_box) => {
267 LayoutBox::TaffyItemBox(taffy_item_box.upgrade()?)
268 },
269 Self::Text(text_run) => LayoutBox::Text(text_run.upgrade()?),
270 })
271 }
272}
273
274#[derive(Default, MallocSizeOf)]
278pub struct DOMLayoutData(AtomicRefCell<InnerDOMLayoutData>);
279
280impl LayoutDataTrait for DOMLayoutData {}
282impl GenericLayoutDataTrait for DOMLayoutData {
283 fn as_any(&self) -> &dyn std::any::Any {
284 self
285 }
286
287 fn set_text_run_selection(&self, new_range: Option<RangeAny<Utf32CodeUnits>>) -> bool {
288 let inner = self.0.borrow();
289 if inner
292 .pseudo_boxes
293 .iter()
294 .any(|pseudo_box| matches!(pseudo_box.pseudo, PseudoElement::FirstLetter))
295 {
296 return false;
297 }
298 if let Some(LayoutBox::Text(text_run)) = &*inner.self_box.borrow() {
299 *text_run.borrow().run_data.selection.borrow_mut() = new_range;
300 true
301 } else {
302 false
303 }
304 }
305}
306
307pub struct BoxSlot<'dom> {
308 pub(crate) slot: ArcRefCell<Option<LayoutBox>>,
309 pub(crate) marker: PhantomData<&'dom ()>,
310}
311
312impl From<ArcRefCell<Option<LayoutBox>>> for BoxSlot<'_> {
313 fn from(slot: ArcRefCell<Option<LayoutBox>>) -> Self {
314 Self {
315 slot,
316 marker: PhantomData,
317 }
318 }
319}
320
321impl BoxSlot<'_> {
323 pub(crate) fn set(self, layout_box: LayoutBox) {
324 layout_box.attached_to_tree(layout_box.downgrade());
325 *self.slot.borrow_mut() = Some(layout_box);
326 }
327
328 pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> {
329 self.slot.borrow_mut().take()
330 }
331
332 pub(crate) fn take_layout_box_as_text_run(&self) -> Option<ArcRefCell<TextRun>> {
336 match self.take_layout_box()? {
337 LayoutBox::Text(old_text_run) => Some(old_text_run),
338 _ => None,
339 }
340 }
341}
342
343impl Drop for BoxSlot<'_> {
344 fn drop(&mut self) {
345 if !std::thread::panicking() {
346 assert!(self.slot.borrow().is_some(), "failed to set a layout box");
347 }
348 }
349}
350
351pub(crate) trait NodeExt<'dom> {
352 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)>;
354 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
355 fn as_iframe(&self) -> Option<IFrameInfo>;
356 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)>;
357 fn as_svg(&self) -> Option<SVGElementData<'dom>>;
358 fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
359
360 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
361 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
362 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>>;
363 fn box_slot(&self) -> BoxSlot<'dom>;
364
365 fn unset_all_boxes(&self);
367
368 fn clear_fragments_and_dirty_fragment_caches(&self);
371
372 fn clear_fragments_and_dirty_fragment_caches_recursively(&self);
376
377 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self);
380
381 fn rendering_type(&self) -> NodeRenderingType;
385
386 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
387
388 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T>;
390 fn with_layout_box_base(&self, callback: impl FnMut(&LayoutBoxBase));
391 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase));
392
393 fn repair_style(&self, context: &SharedStyleContext);
394
395 fn isolates_damage_for_damage_propagation(&self) -> bool;
406
407 fn rebuild_box_tree_from_independent_formatting_context(
414 &self,
415 layout_context: &LayoutContext,
416 ) -> bool;
417
418 fn is_absolutely_positioned(&self) -> bool;
421}
422
423impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
424 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)> {
425 let (resource, metadata) = self.image_data()?;
426 let width = metadata.map(|metadata| metadata.width).unwrap_or_default();
427 let height = metadata.map(|metadata| metadata.height).unwrap_or_default();
428 let (mut width, mut height) = (width as f64, height as f64);
429 if let Some(density) = self.image_density().filter(|density| *density != 1.) {
431 width /= density;
432 height /= density;
433 }
434 Some((
435 ImageInfo {
436 image: resource,
437 showing_broken_image_icon: self.showing_broken_image_icon(),
438 url: self.image_url(),
439 },
440 PhysicalSize::new(width, height),
441 ))
442 }
443
444 fn as_svg(&self) -> Option<SVGElementData<'dom>> {
445 self.svg_data()
446 }
447
448 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)> {
449 let data = self.media_data()?;
450 let natural_size = if let Some(frame) = data.current_frame {
451 Some(PhysicalSize::new(frame.width.into(), frame.height.into()))
452 } else {
453 data.metadata
454 .map(|meta| PhysicalSize::new(meta.width.into(), meta.height.into()))
455 };
456 Some((
457 VideoInfo {
458 image_key: data.current_frame.map(|frame| frame.image_key),
459 poster_url: data.poster_url,
460 },
461 natural_size,
462 ))
463 }
464
465 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
466 let canvas_data = self.canvas_data()?;
467 let source = canvas_data.image_key;
468 Some((
469 CanvasInfo { source },
470 PhysicalSize::new(canvas_data.width.into(), canvas_data.height.into()),
471 ))
472 }
473
474 fn as_iframe(&self) -> Option<IFrameInfo> {
475 match (self.iframe_pipeline_id(), self.iframe_browsing_context_id()) {
476 (Some(pipeline_id), Some(browsing_context_id)) => Some(IFrameInfo {
477 pipeline_id,
478 browsing_context_id,
479 }),
480 _ => None,
481 }
482 }
483
484 fn as_typeless_object_with_data_attribute(&self) -> Option<String> {
485 if self.type_id() !=
486 Some(ScriptLayoutNodeType::Element(
487 LayoutElementType::HTMLObjectElement,
488 ))
489 {
490 return None;
491 }
492
493 let element = self.as_element()?;
497 if element.attribute(&ns!(), &local_name!("type")).is_some() {
498 return None;
499 }
500 element
501 .attribute_as_str(&ns!(), &local_name!("data"))
502 .map(|string| string.to_owned())
503 }
504
505 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
506 if self.layout_data().is_none() {
507 self.initialize_layout_data::<DOMLayoutData>();
508 }
509 self.layout_data()
510 .unwrap()
511 .as_any()
512 .downcast_ref::<DOMLayoutData>()
513 .unwrap()
514 .0
515 .borrow_mut()
516 }
517
518 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
519 self.layout_data().map(|data| {
520 data.as_any()
521 .downcast_ref::<DOMLayoutData>()
522 .unwrap()
523 .0
524 .borrow()
525 })
526 }
527
528 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>> {
529 self.layout_data().map(|data| {
530 data.as_any()
531 .downcast_ref::<DOMLayoutData>()
532 .unwrap()
533 .0
534 .borrow_mut()
535 })
536 }
537
538 fn box_slot(&self) -> BoxSlot<'dom> {
539 let pseudo_element_chain = self.pseudo_element_chain();
540 let Some(primary) = pseudo_element_chain.primary else {
541 return self.ensure_inner_layout_data().self_box.clone().into();
542 };
543
544 let Some(secondary) = pseudo_element_chain.secondary else {
545 let primary_layout_data = self
546 .ensure_inner_layout_data()
547 .create_pseudo_layout_data(primary);
548 return primary_layout_data.borrow().self_box.clone().into();
549 };
550
551 let primary_layout_data = self
558 .inner_layout_data()
559 .expect("Should already have element InnerLayoutData here.")
560 .pseudo_layout_data(primary)
561 .expect("Should already have primary pseudo-element InnerLayoutData here");
562 let secondary_layout_data = primary_layout_data
563 .borrow_mut()
564 .create_pseudo_layout_data(secondary);
565 secondary_layout_data.borrow().self_box.clone().into()
566 }
567
568 fn unset_all_boxes(&self) {
569 let mut layout_data = self.ensure_inner_layout_data();
570 *layout_data.self_box.borrow_mut() = None;
571 layout_data.pseudo_boxes.clear();
572
573 }
576
577 fn clear_fragments_and_dirty_fragment_caches_recursively(&self) {
578 self.clear_fragments_and_dirty_fragment_caches();
579 self.clear_fragments_and_dirty_fragment_caches_of_descendants();
580 }
581
582 fn clear_fragments_and_dirty_fragment_caches(&self) {
583 self.with_layout_box_base_including_pseudos(|base| {
584 base.clear_fragments_and_dirty_fragment_cache()
585 });
586 }
587
588 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self) {
589 for child in self.flat_tree_children() {
590 child.clear_fragments_and_dirty_fragment_caches_recursively();
591 }
592 }
593
594 fn rendering_type(&self) -> NodeRenderingType {
595 let Some(layout_data) = self.inner_layout_data() else {
596 return NodeRenderingType::NotRendered;
597 };
598 match &*layout_data.self_box.borrow() {
599 Some(LayoutBox::DisplayContents(..)) => NodeRenderingType::DelegatesRendering,
600 Some(..) => NodeRenderingType::Rendered,
601 None => NodeRenderingType::NotRendered,
602 }
603 }
604
605 fn with_layout_box_base(&self, callback: impl FnMut(&LayoutBoxBase)) {
606 if let Some(inner_layout_data) = self.inner_layout_data() {
607 inner_layout_data.with_layout_box_base(callback);
608 }
609 }
610
611 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase)) {
612 if let Some(inner_layout_data) = self.inner_layout_data() {
613 inner_layout_data.with_layout_box_base_including_pseudos(callback);
614 }
615 }
616
617 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment> {
618 let Some(layout_data) = self.inner_layout_data() else {
619 return vec![];
620 };
621 match pseudo_element {
622 Some(pseudo_element) => layout_data
623 .pseudo_layout_data(pseudo_element)
624 .map(|pseudo_layout_data| pseudo_layout_data.borrow().fragments())
625 .unwrap_or_default(),
626 None => layout_data.fragments(),
627 }
628 }
629
630 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T> {
631 self.inner_layout_data()?.with_fragments(callback)
632 }
633
634 fn repair_style(&self, context: &SharedStyleContext) {
635 if let Some(layout_data) = self.inner_layout_data() {
636 layout_data.repair_style(self, context);
637 }
638 }
639
640 fn isolates_damage_for_damage_propagation(&self) -> bool {
641 if self.as_element().is_some_and(|element| {
645 element.is_body_element_of_html_element_root() || element.is_root()
646 }) {
647 return false;
648 }
649
650 let Some(inner_layout_data) = self.inner_layout_data() else {
651 return false;
652 };
653 let self_box = inner_layout_data.self_box.borrow();
654 let Some(self_box) = &*self_box else {
655 return false;
656 };
657
658 match self_box {
659 LayoutBox::DisplayContents(..) => false,
660 LayoutBox::BlockLevel(block_level) => matches!(
661 &*block_level.borrow(),
662 BlockLevelBox::Independent(..) |
663 BlockLevelBox::OutOfFlowFloatBox(..) |
664 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(..)
665 ),
666 LayoutBox::InlineLevel(inline_level) => matches!(
667 inline_level,
668 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) | InlineItem::Atomic(..)
669 ),
670 LayoutBox::FlexLevel(..) => true,
671 LayoutBox::TableLevelBox(table_level_box) => matches!(
672 table_level_box,
673 TableLevelBox::Cell(..) | TableLevelBox::Caption(..),
674 ),
675 LayoutBox::TaffyItemBox(..) => true,
676 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
677 }
678 }
679
680 fn rebuild_box_tree_from_independent_formatting_context(
681 &self,
682 layout_context: &LayoutContext,
683 ) -> bool {
684 if self.as_element().is_some_and(|element| {
688 element.is_body_element_of_html_element_root() || element.is_root()
689 }) {
690 return false;
691 }
692
693 let layout_box = {
694 let Some(mut inner_layout_data) = self.inner_layout_data_mut() else {
695 return false;
696 };
697 inner_layout_data.pseudo_boxes.clear();
698 inner_layout_data.self_box.clone()
699 };
700
701 let layout_box = layout_box.borrow();
702 let Some(layout_box) = &*layout_box else {
703 return false;
704 };
705
706 let info = NodeAndStyleInfo::new(*self, self.style(&layout_context.style_context));
707 let box_style = info.style.get_box();
708 let Display::GeneratingBox(display) = box_style.display.into() else {
709 return false;
710 };
711 let contents = || {
712 assert!(
713 self.pseudo_element_chain().is_empty(),
714 "Shouldn't try to rebuild box tree from a pseudo-element"
715 );
716 Contents::for_element(info.node, layout_context)
717 };
718 match layout_box {
719 LayoutBox::DisplayContents(..) => false,
720 LayoutBox::BlockLevel(block_level) => {
721 let mut block_level = block_level.borrow_mut();
722 match &mut *block_level {
723 BlockLevelBox::Independent(independent_formatting_context) => {
724 let DisplayGeneratingBox::OutsideInside {
725 outside: DisplayOutside::Block,
726 inside: display_inside,
727 } = display
728 else {
729 return false;
730 };
731 if !matches!(
732 BlockLevelCreator::new_for_inflow_block_level_element(
733 &info,
734 display_inside,
735 contents(),
736 independent_formatting_context.propagated_data,
737 ),
738 BlockLevelCreator::Independent { .. }
739 ) {
740 return false;
741 }
742 independent_formatting_context.rebuild(layout_context, &info);
743 true
744 },
745 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
746 if !info.style.clone_float().is_floating() {
747 return false;
748 }
749 float_box.contents.rebuild(layout_context, &info);
750 true
751 },
752 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
753 if !info.style.clone_position().is_absolutely_positioned() ||
758 box_style.original_display.outside() != StyloDisplayOutside::Block
759 {
760 return false;
761 }
762 positioned_box
763 .borrow_mut()
764 .context
765 .rebuild(layout_context, &info);
766 true
767 },
768 _ => false,
769 }
770 },
771 LayoutBox::InlineLevel(inline_level) => match inline_level {
772 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
773 if !info.style.clone_position().is_absolutely_positioned() {
774 return false;
775 }
776 positioned_box
777 .borrow_mut()
778 .context
779 .rebuild(layout_context, &info);
780 true
781 },
782 InlineItem::Atomic(atomic_box, _, _) => {
783 let flags = match contents() {
784 Contents::NonReplaced(_) => FragmentFlags::empty(),
785 Contents::Replaced(_) => FragmentFlags::IS_REPLACED,
786 Contents::Widget(_) => FragmentFlags::IS_WIDGET,
787 };
788 if !info.style.is_atomic_inline_level(flags) {
789 return false;
790 }
791 atomic_box.borrow_mut().rebuild(layout_context, &info);
792 true
793 },
794 _ => false,
795 },
796 LayoutBox::FlexLevel(flex_level_box) => {
797 let mut flex_level_box = flex_level_box.borrow_mut();
798 match &mut *flex_level_box {
799 FlexLevelBox::FlexItem(flex_item_box) => {
800 if info.style.clone_position().is_absolutely_positioned() ||
801 flex_item_box.style().clone_order() != info.style.clone_order()
802 {
803 return false;
804 }
805 flex_item_box
806 .independent_formatting_context
807 .rebuild(layout_context, &info)
808 },
809 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
810 if !info.style.clone_position().is_absolutely_positioned() {
811 return false;
812 }
813 positioned_box
814 .borrow_mut()
815 .context
816 .rebuild(layout_context, &info);
817 },
818 }
819 true
820 },
821 LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
822 TableLevelBox::Caption(caption) => {
823 if display !=
824 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCaption)
825 {
826 return false;
827 }
828 caption.borrow_mut().context.rebuild(layout_context, &info);
829 true
830 },
831 TableLevelBox::Cell(table_cell) => {
832 if display !=
833 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCell)
834 {
835 return false;
836 }
837 table_cell
838 .borrow_mut()
839 .context
840 .rebuild(layout_context, &info);
841 true
842 },
843 _ => false,
844 },
845 LayoutBox::TaffyItemBox(..) => false,
846 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
847 }
848 }
849
850 fn is_absolutely_positioned(&self) -> bool {
851 self.as_element().is_some_and(|element| {
852 element
853 .element_data()
854 .styles
855 .primary()
856 .clone_position()
857 .is_absolutely_positioned()
858 })
859 }
860}