layout/
dom.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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 smallvec::SmallVec;
16use style::context::SharedStyleContext;
17use style::properties::ComputedValues;
18use style::selector_parser::PseudoElement;
19use style::values::specified::box_::DisplayOutside as StyloDisplayOutside;
20use web_atoms::{local_name, ns};
21
22use crate::cell::{ArcRefCell, WeakRefCell};
23use crate::context::LayoutContext;
24use crate::dom_traversal::{Contents, NodeAndStyleInfo};
25use crate::flexbox::FlexLevelBox;
26use crate::flow::inline::{InlineItem, SharedInlineStyles, WeakInlineItem};
27use crate::flow::{BlockLevelBox, BlockLevelCreator};
28use crate::fragment_tree::{Fragment, FragmentFlags};
29use crate::geom::PhysicalSize;
30use crate::layout_box_base::LayoutBoxBase;
31use crate::replaced::{CanvasInfo, IFrameInfo, ImageInfo, VideoInfo};
32use crate::style_ext::{
33    ComputedValuesExt, Display, DisplayGeneratingBox, DisplayLayoutInternal, DisplayOutside,
34};
35use crate::table::{TableLevelBox, WeakTableLevelBox};
36use crate::taffy::TaffyItemBox;
37
38#[derive(MallocSizeOf)]
39pub struct PseudoLayoutData {
40    pseudo: PseudoElement,
41    data: ArcRefCell<InnerDOMLayoutData>,
42}
43
44/// The data that is stored in each DOM node that is used by layout.
45#[derive(Default, MallocSizeOf)]
46pub struct InnerDOMLayoutData {
47    pub(super) self_box: ArcRefCell<Option<LayoutBox>>,
48    pub(super) pseudo_boxes: SmallVec<[PseudoLayoutData; 2]>,
49}
50
51impl InnerDOMLayoutData {
52    fn pseudo_layout_data(
53        &self,
54        pseudo_element: PseudoElement,
55    ) -> Option<ArcRefCell<InnerDOMLayoutData>> {
56        for pseudo_layout_data in self.pseudo_boxes.iter() {
57            if pseudo_element == pseudo_layout_data.pseudo {
58                return Some(pseudo_layout_data.data.clone());
59            }
60        }
61        None
62    }
63
64    fn create_pseudo_layout_data(
65        &mut self,
66        pseudo_element: PseudoElement,
67    ) -> ArcRefCell<InnerDOMLayoutData> {
68        let data: ArcRefCell<InnerDOMLayoutData> = Default::default();
69        self.pseudo_boxes.push(PseudoLayoutData {
70            pseudo: pseudo_element,
71            data: data.clone(),
72        });
73        data
74    }
75
76    fn fragments(&self) -> Vec<Fragment> {
77        self.self_box
78            .borrow()
79            .as_ref()
80            .and_then(|layout_box| layout_box.with_base(LayoutBoxBase::fragments))
81            .unwrap_or_default()
82    }
83
84    fn repair_style(&self, node: &ServoLayoutNode, context: &SharedStyleContext) {
85        if let Some(layout_object) = &*self.self_box.borrow() {
86            layout_object.repair_style(context, node, &node.style(context));
87        }
88
89        for pseudo_layout_data in self.pseudo_boxes.iter() {
90            let Some(node_with_pseudo) = node.with_pseudo(pseudo_layout_data.pseudo) else {
91                continue;
92            };
93            pseudo_layout_data
94                .data
95                .borrow()
96                .repair_style(&node_with_pseudo, context);
97        }
98    }
99
100    fn with_layout_box_base(&self, callback: impl Fn(&LayoutBoxBase)) {
101        if let Some(data) = self.self_box.borrow().as_ref() {
102            data.with_base(callback);
103        }
104    }
105
106    fn with_layout_box_base_including_pseudos(&self, callback: impl Fn(&LayoutBoxBase)) {
107        self.with_layout_box_base(&callback);
108        for pseudo_layout_data in self.pseudo_boxes.iter() {
109            pseudo_layout_data
110                .data
111                .borrow()
112                .with_layout_box_base(&callback);
113        }
114    }
115}
116
117/// A box that is stored in one of the `DOMLayoutData` slots.
118#[derive(Debug, MallocSizeOf)]
119pub(super) enum LayoutBox {
120    DisplayContents(SharedInlineStyles),
121    BlockLevel(ArcRefCell<BlockLevelBox>),
122    InlineLevel(InlineItem),
123    FlexLevel(ArcRefCell<FlexLevelBox>),
124    TableLevelBox(TableLevelBox),
125    TaffyItemBox(ArcRefCell<TaffyItemBox>),
126}
127
128impl LayoutBox {
129    pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T> {
130        Some(match self {
131            LayoutBox::DisplayContents(..) => return None,
132            LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().with_base(callback),
133            LayoutBox::InlineLevel(inline_item) => inline_item.with_base(callback),
134            LayoutBox::FlexLevel(flex_level_box) => flex_level_box.borrow().with_base(callback),
135            LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box.borrow().with_base(callback),
136            LayoutBox::TableLevelBox(table_box) => table_box.with_base(callback),
137        })
138    }
139
140    pub(crate) fn with_base_mut<T>(
141        &mut self,
142        callback: impl FnOnce(&mut LayoutBoxBase) -> T,
143    ) -> Option<T> {
144        Some(match self {
145            LayoutBox::DisplayContents(..) => return None,
146            LayoutBox::BlockLevel(block_level_box) => {
147                block_level_box.borrow_mut().with_base_mut(callback)
148            },
149            LayoutBox::InlineLevel(inline_item) => inline_item.with_base_mut(callback),
150            LayoutBox::FlexLevel(flex_level_box) => {
151                flex_level_box.borrow_mut().with_base_mut(callback)
152            },
153            LayoutBox::TaffyItemBox(taffy_item_box) => {
154                taffy_item_box.borrow_mut().with_base_mut(callback)
155            },
156            LayoutBox::TableLevelBox(table_box) => table_box.with_base_mut(callback),
157        })
158    }
159
160    fn repair_style(
161        &self,
162        context: &SharedStyleContext,
163        node: &ServoLayoutNode,
164        new_style: &ServoArc<ComputedValues>,
165    ) {
166        match self {
167            LayoutBox::DisplayContents(inline_shared_styles) => {
168                *inline_shared_styles.style.borrow_mut() = new_style.clone();
169                *inline_shared_styles.selected.borrow_mut() = node.selected_style(context);
170            },
171            LayoutBox::BlockLevel(block_level_box) => {
172                block_level_box
173                    .borrow_mut()
174                    .repair_style(context, node, new_style);
175            },
176            LayoutBox::InlineLevel(inline_item) => {
177                inline_item.repair_style(context, node, new_style);
178            },
179            LayoutBox::FlexLevel(flex_level_box) => flex_level_box
180                .borrow_mut()
181                .repair_style(context, node, new_style),
182            LayoutBox::TableLevelBox(table_level_box) => {
183                table_level_box.repair_style(context, node, new_style)
184            },
185            LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box
186                .borrow_mut()
187                .repair_style(context, node, new_style),
188        }
189    }
190
191    fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
192        match self {
193            Self::DisplayContents(_) => {
194                // This box can't have children, its contents get reparented to its parent.
195                // Therefore, no need to do anything.
196            },
197            Self::BlockLevel(block_level_box) => {
198                block_level_box.borrow().attached_to_tree(layout_box)
199            },
200            Self::InlineLevel(inline_item) => inline_item.attached_to_tree(layout_box),
201            Self::FlexLevel(flex_level_box) => flex_level_box.borrow().attached_to_tree(layout_box),
202            Self::TableLevelBox(table_level_box) => table_level_box.attached_to_tree(layout_box),
203            Self::TaffyItemBox(taffy_item_box) => {
204                taffy_item_box.borrow().attached_to_tree(layout_box)
205            },
206        }
207    }
208
209    fn downgrade(&self) -> WeakLayoutBox {
210        match self {
211            Self::DisplayContents(inline_shared_styles) => {
212                WeakLayoutBox::DisplayContents(inline_shared_styles.clone())
213            },
214            Self::BlockLevel(block_level_box) => {
215                WeakLayoutBox::BlockLevel(block_level_box.downgrade())
216            },
217            Self::InlineLevel(inline_item) => WeakLayoutBox::InlineLevel(inline_item.downgrade()),
218            Self::FlexLevel(flex_level_box) => WeakLayoutBox::FlexLevel(flex_level_box.downgrade()),
219            Self::TableLevelBox(table_level_box) => {
220                WeakLayoutBox::TableLevelBox(table_level_box.downgrade())
221            },
222            Self::TaffyItemBox(taffy_item_box) => {
223                WeakLayoutBox::TaffyItemBox(taffy_item_box.downgrade())
224            },
225        }
226    }
227}
228
229#[derive(Clone, Debug, MallocSizeOf)]
230pub(super) enum WeakLayoutBox {
231    DisplayContents(SharedInlineStyles),
232    BlockLevel(WeakRefCell<BlockLevelBox>),
233    InlineLevel(WeakInlineItem),
234    FlexLevel(WeakRefCell<FlexLevelBox>),
235    TableLevelBox(WeakTableLevelBox),
236    TaffyItemBox(WeakRefCell<TaffyItemBox>),
237}
238
239impl WeakLayoutBox {
240    pub(crate) fn upgrade(&self) -> Option<LayoutBox> {
241        Some(match self {
242            Self::DisplayContents(inline_shared_styles) => {
243                LayoutBox::DisplayContents(inline_shared_styles.clone())
244            },
245            Self::BlockLevel(block_level_box) => LayoutBox::BlockLevel(block_level_box.upgrade()?),
246            Self::InlineLevel(inline_item) => LayoutBox::InlineLevel(inline_item.upgrade()?),
247            Self::FlexLevel(flex_level_box) => LayoutBox::FlexLevel(flex_level_box.upgrade()?),
248            Self::TableLevelBox(table_level_box) => {
249                LayoutBox::TableLevelBox(table_level_box.upgrade()?)
250            },
251            Self::TaffyItemBox(taffy_item_box) => {
252                LayoutBox::TaffyItemBox(taffy_item_box.upgrade()?)
253            },
254        })
255    }
256}
257
258/// A wrapper for [`InnerDOMLayoutData`]. This is necessary to give the entire data
259/// structure interior mutability, as we will need to mutate the layout data of
260/// non-mutable DOM nodes.
261#[derive(Default, MallocSizeOf)]
262pub struct DOMLayoutData(AtomicRefCell<InnerDOMLayoutData>);
263
264// The implementation of this trait allows the data to be stored in the DOM.
265impl LayoutDataTrait for DOMLayoutData {}
266impl GenericLayoutDataTrait for DOMLayoutData {
267    fn as_any(&self) -> &dyn std::any::Any {
268        self
269    }
270}
271
272pub struct BoxSlot<'dom> {
273    pub(crate) slot: ArcRefCell<Option<LayoutBox>>,
274    pub(crate) marker: PhantomData<&'dom ()>,
275}
276
277impl From<ArcRefCell<Option<LayoutBox>>> for BoxSlot<'_> {
278    fn from(slot: ArcRefCell<Option<LayoutBox>>) -> Self {
279        Self {
280            slot,
281            marker: PhantomData,
282        }
283    }
284}
285
286/// A mutable reference to a `LayoutBox` stored in a DOM element.
287impl BoxSlot<'_> {
288    pub(crate) fn set(self, layout_box: LayoutBox) {
289        layout_box.attached_to_tree(layout_box.downgrade());
290        *self.slot.borrow_mut() = Some(layout_box);
291    }
292
293    pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> {
294        self.slot.borrow_mut().take()
295    }
296}
297
298impl Drop for BoxSlot<'_> {
299    fn drop(&mut self) {
300        if !std::thread::panicking() {
301            assert!(self.slot.borrow().is_some(), "failed to set a layout box");
302        }
303    }
304}
305
306pub(crate) trait NodeExt<'dom> {
307    /// Returns the relevant data wrapping into respective struct and its size in pixels.
308    fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)>;
309    fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
310    fn as_iframe(&self) -> Option<IFrameInfo>;
311    fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)>;
312    fn as_svg(&self) -> Option<SVGElementData<'dom>>;
313    fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
314
315    fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
316    fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
317    fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>>;
318    fn box_slot(&self) -> BoxSlot<'dom>;
319
320    /// Remove boxes for the element itself, and all of its pseudo-element boxes.
321    fn unset_all_boxes(&self);
322
323    /// Returns the [`NodeRenderingType`] for this [`LayoutNode`] which describes whether
324    /// the node is being rendered, delegating rendering, or not being rendered at all
325    /// based on whether it has a [`LayoutBox`] and what kind.
326    fn rendering_type(&self) -> NodeRenderingType;
327
328    fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
329    fn with_layout_box_base_including_pseudos(&self, callback: impl Fn(&LayoutBoxBase));
330
331    fn repair_style(&self, context: &SharedStyleContext);
332
333    /// Whether or not this node isolates downward flowing box tree rebuild damage and
334    /// fragment tree layout cache damage. Roughly, this corresponds to independent
335    /// formatting context boundaries.
336    ///
337    /// - The node's boxes themselves will be rebuilt, but not the descendant node's
338    ///   boxes.
339    /// - The node's fragment tree layout will be rebuilt, not the descendent node's
340    ///   fragment tree layout cache.
341    ///
342    /// When this node has no box yet, `false` is returned.
343    fn isolates_damage_for_damage_propagation(&self) -> bool;
344
345    /// Try to re-run box tree reconstruction from this point. This can succeed if the
346    /// node itself is still valid and isolates box tree damage from ancestors (for
347    /// instance, if it starts an independent formatting context). **Note:** This assumes
348    /// that no ancestors have box damage.
349    ///
350    /// Returns `true` if box tree reconstruction was sucessful and `false` otherwise.
351    fn rebuild_box_tree_from_independent_formatting_context(
352        &self,
353        layout_context: &LayoutContext,
354    ) -> bool;
355}
356
357impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
358    fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)> {
359        let (resource, metadata) = self.image_data()?;
360        let width = metadata.map(|metadata| metadata.width).unwrap_or_default();
361        let height = metadata.map(|metadata| metadata.height).unwrap_or_default();
362        let (mut width, mut height) = (width as f64, height as f64);
363        // Take `image_density` into account for calculating the size in pixels for images.
364        if let Some(density) = self.image_density().filter(|density| *density != 1.) {
365            width /= density;
366            height /= density;
367        }
368        Some((
369            ImageInfo {
370                image: resource,
371                showing_broken_image_icon: self.showing_broken_image_icon(),
372                url: self.image_url(),
373            },
374            PhysicalSize::new(width, height),
375        ))
376    }
377
378    fn as_svg(&self) -> Option<SVGElementData<'dom>> {
379        self.svg_data()
380    }
381
382    fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)> {
383        let data = self.media_data()?;
384        let natural_size = if let Some(frame) = data.current_frame {
385            Some(PhysicalSize::new(frame.width.into(), frame.height.into()))
386        } else {
387            data.metadata
388                .map(|meta| PhysicalSize::new(meta.width.into(), meta.height.into()))
389        };
390        Some((
391            VideoInfo {
392                image_key: data.current_frame.map(|frame| frame.image_key),
393            },
394            natural_size,
395        ))
396    }
397
398    fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
399        let canvas_data = self.canvas_data()?;
400        let source = canvas_data.image_key;
401        Some((
402            CanvasInfo { source },
403            PhysicalSize::new(canvas_data.width.into(), canvas_data.height.into()),
404        ))
405    }
406
407    fn as_iframe(&self) -> Option<IFrameInfo> {
408        match (self.iframe_pipeline_id(), self.iframe_browsing_context_id()) {
409            (Some(pipeline_id), Some(browsing_context_id)) => Some(IFrameInfo {
410                pipeline_id,
411                browsing_context_id,
412            }),
413            _ => None,
414        }
415    }
416
417    fn as_typeless_object_with_data_attribute(&self) -> Option<String> {
418        if self.type_id() !=
419            Some(ScriptLayoutNodeType::Element(
420                LayoutElementType::HTMLObjectElement,
421            ))
422        {
423            return None;
424        }
425
426        // TODO: This is the what the legacy layout system did, but really if Servo
427        // supports any `<object>` that's an image, it should support those with URLs
428        // and `type` attributes with image mime types.
429        let element = self.as_element()?;
430        if element.attribute(&ns!(), &local_name!("type")).is_some() {
431            return None;
432        }
433        element
434            .attribute_as_str(&ns!(), &local_name!("data"))
435            .map(|string| string.to_owned())
436    }
437
438    fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
439        if self.layout_data().is_none() {
440            self.initialize_layout_data::<DOMLayoutData>();
441        }
442        self.layout_data()
443            .unwrap()
444            .as_any()
445            .downcast_ref::<DOMLayoutData>()
446            .unwrap()
447            .0
448            .borrow_mut()
449    }
450
451    fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
452        self.layout_data().map(|data| {
453            data.as_any()
454                .downcast_ref::<DOMLayoutData>()
455                .unwrap()
456                .0
457                .borrow()
458        })
459    }
460
461    fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>> {
462        self.layout_data().map(|data| {
463            data.as_any()
464                .downcast_ref::<DOMLayoutData>()
465                .unwrap()
466                .0
467                .borrow_mut()
468        })
469    }
470
471    fn box_slot(&self) -> BoxSlot<'dom> {
472        let pseudo_element_chain = self.pseudo_element_chain();
473        let Some(primary) = pseudo_element_chain.primary else {
474            return self.ensure_inner_layout_data().self_box.clone().into();
475        };
476
477        let Some(secondary) = pseudo_element_chain.secondary else {
478            let primary_layout_data = self
479                .ensure_inner_layout_data()
480                .create_pseudo_layout_data(primary);
481            return primary_layout_data.borrow().self_box.clone().into();
482        };
483
484        // It's *very* important that this not borrow the element's main
485        // `InnerLayoutData`. Primary pseudo-elements are processed at the same recursion
486        // level as the main data, so the `BoxSlot` is created sequentially with other
487        // primary pseudo-elements and the element itself. The secondary pseudo-element is
488        // one level deep, so could be happening in parallel with the primary
489        // pseudo-elements or main element layout.
490        let primary_layout_data = self
491            .inner_layout_data()
492            .expect("Should already have element InnerLayoutData here.")
493            .pseudo_layout_data(primary)
494            .expect("Should already have primary pseudo-element InnerLayoutData here");
495        let secondary_layout_data = primary_layout_data
496            .borrow_mut()
497            .create_pseudo_layout_data(secondary);
498        secondary_layout_data.borrow().self_box.clone().into()
499    }
500
501    fn unset_all_boxes(&self) {
502        let mut layout_data = self.ensure_inner_layout_data();
503        *layout_data.self_box.borrow_mut() = None;
504        layout_data.pseudo_boxes.clear();
505
506        // Stylo already takes care of removing all layout data
507        // for DOM descendants of elements with `display: none`.
508    }
509
510    fn rendering_type(&self) -> NodeRenderingType {
511        let Some(layout_data) = self.inner_layout_data() else {
512            return NodeRenderingType::NotRendered;
513        };
514        match &*layout_data.self_box.borrow() {
515            Some(LayoutBox::DisplayContents(..)) => NodeRenderingType::DelegatesRendering,
516            Some(..) => NodeRenderingType::Rendered,
517            None => NodeRenderingType::NotRendered,
518        }
519    }
520
521    fn with_layout_box_base_including_pseudos(&self, callback: impl Fn(&LayoutBoxBase)) {
522        if let Some(inner_layout_data) = self.inner_layout_data() {
523            inner_layout_data.with_layout_box_base_including_pseudos(callback);
524        }
525    }
526
527    fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment> {
528        let Some(layout_data) = self.inner_layout_data() else {
529            return vec![];
530        };
531        match pseudo_element {
532            Some(pseudo_element) => layout_data
533                .pseudo_layout_data(pseudo_element)
534                .map(|pseudo_layout_data| pseudo_layout_data.borrow().fragments())
535                .unwrap_or_default(),
536            None => layout_data.fragments(),
537        }
538    }
539
540    fn repair_style(&self, context: &SharedStyleContext) {
541        if let Some(layout_data) = self.inner_layout_data() {
542            layout_data.repair_style(self, context);
543        }
544    }
545
546    fn isolates_damage_for_damage_propagation(&self) -> bool {
547        // Do not run incremental box and fragment tree layout at the `<body>` or root element as
548        // there is some special processing that must happen for these elements and it currently
549        // only happens when doing a full box tree construction traversal.
550        if self.as_element().is_some_and(|element| {
551            element.is_body_element_of_html_element_root() || element.is_root()
552        }) {
553            return false;
554        }
555
556        let Some(inner_layout_data) = self.inner_layout_data() else {
557            return false;
558        };
559        let self_box = inner_layout_data.self_box.borrow();
560        let Some(self_box) = &*self_box else {
561            return false;
562        };
563
564        match self_box {
565            LayoutBox::DisplayContents(..) => false,
566            LayoutBox::BlockLevel(block_level) => matches!(
567                &*block_level.borrow(),
568                BlockLevelBox::Independent(..) |
569                    BlockLevelBox::OutOfFlowFloatBox(..) |
570                    BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(..)
571            ),
572            LayoutBox::InlineLevel(inline_level) => matches!(
573                inline_level,
574                InlineItem::OutOfFlowAbsolutelyPositionedBox(..) | InlineItem::Atomic(..)
575            ),
576            LayoutBox::FlexLevel(..) => true,
577            LayoutBox::TableLevelBox(table_level_box) => matches!(
578                table_level_box,
579                TableLevelBox::Cell(..) | TableLevelBox::Caption(..),
580            ),
581            LayoutBox::TaffyItemBox(..) => true,
582        }
583    }
584
585    fn rebuild_box_tree_from_independent_formatting_context(
586        &self,
587        layout_context: &LayoutContext,
588    ) -> bool {
589        // Do not run incremental box tree layout at the `<body>` or root element as there
590        // is some special processing that must happen for these elements and it currently
591        // only happens when doing a full box tree construction traversal.
592        if self.as_element().is_some_and(|element| {
593            element.is_body_element_of_html_element_root() || element.is_root()
594        }) {
595            return false;
596        }
597
598        let layout_box = {
599            let Some(mut inner_layout_data) = self.inner_layout_data_mut() else {
600                return false;
601            };
602            inner_layout_data.pseudo_boxes.clear();
603            inner_layout_data.self_box.clone()
604        };
605
606        let layout_box = layout_box.borrow();
607        let Some(layout_box) = &*layout_box else {
608            return false;
609        };
610
611        let info = NodeAndStyleInfo::new(*self, self.style(&layout_context.style_context));
612        let box_style = info.style.get_box();
613        let Display::GeneratingBox(display) = box_style.display.into() else {
614            return false;
615        };
616        let contents = || {
617            assert!(
618                self.pseudo_element_chain().is_empty(),
619                "Shouldn't try to rebuild box tree from a pseudo-element"
620            );
621            Contents::for_element(info.node, layout_context)
622        };
623        match layout_box {
624            LayoutBox::DisplayContents(..) => false,
625            LayoutBox::BlockLevel(block_level) => {
626                let mut block_level = block_level.borrow_mut();
627                match &mut *block_level {
628                    BlockLevelBox::Independent(independent_formatting_context) => {
629                        let DisplayGeneratingBox::OutsideInside {
630                            outside: DisplayOutside::Block,
631                            inside: display_inside,
632                        } = display
633                        else {
634                            return false;
635                        };
636                        if !matches!(
637                            BlockLevelCreator::new_for_inflow_block_level_element(
638                                &info,
639                                display_inside,
640                                contents(),
641                                independent_formatting_context.propagated_data,
642                            ),
643                            BlockLevelCreator::Independent { .. }
644                        ) {
645                            return false;
646                        }
647                        independent_formatting_context.rebuild(layout_context, &info);
648                        true
649                    },
650                    BlockLevelBox::OutOfFlowFloatBox(float_box) => {
651                        if !info.style.clone_float().is_floating() {
652                            return false;
653                        }
654                        float_box.contents.rebuild(layout_context, &info);
655                        true
656                    },
657                    BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
658                        // Even if absolute positioning blockifies the outer display type, if the
659                        // original display was inline-level, then the box needs to be handled as
660                        // an inline-level in order to compute the static position correctly.
661                        // See `BlockContainerBuilder::handle_absolutely_positioned_element()`.
662                        if !info.style.clone_position().is_absolutely_positioned() ||
663                            box_style.original_display.outside() != StyloDisplayOutside::Block
664                        {
665                            return false;
666                        }
667                        positioned_box
668                            .borrow_mut()
669                            .context
670                            .rebuild(layout_context, &info);
671                        true
672                    },
673                    _ => false,
674                }
675            },
676            LayoutBox::InlineLevel(inline_level) => match inline_level {
677                InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
678                    if !info.style.clone_position().is_absolutely_positioned() {
679                        return false;
680                    }
681                    positioned_box
682                        .borrow_mut()
683                        .context
684                        .rebuild(layout_context, &info);
685                    true
686                },
687                InlineItem::Atomic(atomic_box, _, _) => {
688                    let flags = match contents() {
689                        Contents::NonReplaced(_) => FragmentFlags::empty(),
690                        Contents::Replaced(_) => FragmentFlags::IS_REPLACED,
691                        Contents::Widget(_) => FragmentFlags::IS_WIDGET,
692                    };
693                    if !info.style.is_atomic_inline_level(flags) {
694                        return false;
695                    }
696                    atomic_box.borrow_mut().rebuild(layout_context, &info);
697                    true
698                },
699                _ => false,
700            },
701            LayoutBox::FlexLevel(flex_level_box) => {
702                let mut flex_level_box = flex_level_box.borrow_mut();
703                match &mut *flex_level_box {
704                    FlexLevelBox::FlexItem(flex_item_box) => {
705                        if info.style.clone_position().is_absolutely_positioned() ||
706                            flex_item_box.style().clone_order() != info.style.clone_order()
707                        {
708                            return false;
709                        }
710                        flex_item_box
711                            .independent_formatting_context
712                            .rebuild(layout_context, &info)
713                    },
714                    FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
715                        if !info.style.clone_position().is_absolutely_positioned() {
716                            return false;
717                        }
718                        positioned_box
719                            .borrow_mut()
720                            .context
721                            .rebuild(layout_context, &info);
722                    },
723                }
724                true
725            },
726            LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
727                TableLevelBox::Caption(caption) => {
728                    if display !=
729                        DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCaption)
730                    {
731                        return false;
732                    }
733                    caption.borrow_mut().context.rebuild(layout_context, &info);
734                    true
735                },
736                TableLevelBox::Cell(table_cell) => {
737                    if display !=
738                        DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCell)
739                    {
740                        return false;
741                    }
742                    table_cell
743                        .borrow_mut()
744                        .context
745                        .rebuild(layout_context, &info);
746                    true
747                },
748                _ => false,
749            },
750            LayoutBox::TaffyItemBox(..) => false,
751        }
752    }
753}