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