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 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::text_run::TextRun;
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#[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(|base| base.fragments().clone()))
82 .unwrap_or_default()
83 }
84
85 fn repair_style(&self, node: &ServoLayoutNode, 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 FnOnce(&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, mut callback: impl FnMut(&LayoutBoxBase)) {
108 self.with_layout_box_base(&mut callback);
109 for pseudo_layout_data in self.pseudo_boxes.iter() {
110 pseudo_layout_data
111 .data
112 .borrow()
113 .with_layout_box_base(&mut callback);
114 }
115 }
116}
117
118#[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 Text(ArcRefCell<TextRun>),
128}
129
130impl LayoutBox {
131 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> Option<T> {
132 Some(match self {
133 LayoutBox::DisplayContents(..) | LayoutBox::Text(..) => return None,
134 LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().with_base(callback),
135 LayoutBox::InlineLevel(inline_item) => inline_item.with_base(callback),
136 LayoutBox::FlexLevel(flex_level_box) => flex_level_box.borrow().with_base(callback),
137 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box.borrow().with_base(callback),
138 LayoutBox::TableLevelBox(table_box) => table_box.with_base(callback),
139 })
140 }
141
142 pub(crate) fn with_base_mut<T>(
143 &mut self,
144 callback: impl FnOnce(&mut LayoutBoxBase) -> T,
145 ) -> Option<T> {
146 Some(match self {
147 LayoutBox::DisplayContents(..) | LayoutBox::Text(..) => return None,
148 LayoutBox::BlockLevel(block_level_box) => {
149 block_level_box.borrow_mut().with_base_mut(callback)
150 },
151 LayoutBox::InlineLevel(inline_item) => inline_item.with_base_mut(callback),
152 LayoutBox::FlexLevel(flex_level_box) => {
153 flex_level_box.borrow_mut().with_base_mut(callback)
154 },
155 LayoutBox::TaffyItemBox(taffy_item_box) => {
156 taffy_item_box.borrow_mut().with_base_mut(callback)
157 },
158 LayoutBox::TableLevelBox(table_box) => table_box.with_base_mut(callback),
159 })
160 }
161
162 fn repair_style(
163 &self,
164 context: &SharedStyleContext,
165 node: &ServoLayoutNode,
166 new_style: &ServoArc<ComputedValues>,
167 ) {
168 match self {
169 LayoutBox::DisplayContents(inline_shared_styles) => {
170 *inline_shared_styles.style.borrow_mut() = new_style.clone();
171 *inline_shared_styles.selected.borrow_mut() = node.selected_style(context);
172 },
173 LayoutBox::BlockLevel(block_level_box) => {
174 block_level_box
175 .borrow_mut()
176 .repair_style(context, node, new_style);
177 },
178 LayoutBox::InlineLevel(inline_item) => {
179 inline_item.repair_style(context, node, new_style);
180 },
181 LayoutBox::FlexLevel(flex_level_box) => flex_level_box
182 .borrow_mut()
183 .repair_style(context, node, new_style),
184 LayoutBox::TableLevelBox(table_level_box) => {
185 table_level_box.repair_style(context, node, new_style)
186 },
187 LayoutBox::TaffyItemBox(taffy_item_box) => taffy_item_box
188 .borrow_mut()
189 .repair_style(context, node, new_style),
190 LayoutBox::Text(..) => {
191 },
193 }
194 }
195
196 fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
197 match self {
198 Self::DisplayContents(_) => {
199 },
202 Self::BlockLevel(block_level_box) => {
203 block_level_box.borrow().attached_to_tree(layout_box)
204 },
205 Self::InlineLevel(inline_item) => inline_item.attached_to_tree(layout_box),
206 Self::FlexLevel(flex_level_box) => flex_level_box.borrow().attached_to_tree(layout_box),
207 Self::TableLevelBox(table_level_box) => table_level_box.attached_to_tree(layout_box),
208 Self::TaffyItemBox(taffy_item_box) => {
209 taffy_item_box.borrow().attached_to_tree(layout_box)
210 },
211 Self::Text(..) => {
212 },
214 }
215 }
216
217 fn downgrade(&self) -> WeakLayoutBox {
218 match self {
219 Self::DisplayContents(inline_shared_styles) => {
220 WeakLayoutBox::DisplayContents(inline_shared_styles.clone())
221 },
222 Self::BlockLevel(block_level_box) => {
223 WeakLayoutBox::BlockLevel(block_level_box.downgrade())
224 },
225 Self::InlineLevel(inline_item) => WeakLayoutBox::InlineLevel(inline_item.downgrade()),
226 Self::FlexLevel(flex_level_box) => WeakLayoutBox::FlexLevel(flex_level_box.downgrade()),
227 Self::TableLevelBox(table_level_box) => {
228 WeakLayoutBox::TableLevelBox(table_level_box.downgrade())
229 },
230 Self::TaffyItemBox(taffy_item_box) => {
231 WeakLayoutBox::TaffyItemBox(taffy_item_box.downgrade())
232 },
233 Self::Text(text_run) => WeakLayoutBox::Text(text_run.downgrade()),
234 }
235 }
236}
237
238#[derive(Clone, Debug, MallocSizeOf)]
239pub(super) enum WeakLayoutBox {
240 DisplayContents(SharedInlineStyles),
241 BlockLevel(WeakRefCell<BlockLevelBox>),
242 InlineLevel(WeakInlineItem),
243 FlexLevel(WeakRefCell<FlexLevelBox>),
244 TableLevelBox(WeakTableLevelBox),
245 TaffyItemBox(WeakRefCell<TaffyItemBox>),
246 Text(WeakRefCell<TextRun>),
247}
248
249impl WeakLayoutBox {
250 pub(crate) fn upgrade(&self) -> Option<LayoutBox> {
251 Some(match self {
252 Self::DisplayContents(inline_shared_styles) => {
253 LayoutBox::DisplayContents(inline_shared_styles.clone())
254 },
255 Self::BlockLevel(block_level_box) => LayoutBox::BlockLevel(block_level_box.upgrade()?),
256 Self::InlineLevel(inline_item) => LayoutBox::InlineLevel(inline_item.upgrade()?),
257 Self::FlexLevel(flex_level_box) => LayoutBox::FlexLevel(flex_level_box.upgrade()?),
258 Self::TableLevelBox(table_level_box) => {
259 LayoutBox::TableLevelBox(table_level_box.upgrade()?)
260 },
261 Self::TaffyItemBox(taffy_item_box) => {
262 LayoutBox::TaffyItemBox(taffy_item_box.upgrade()?)
263 },
264 Self::Text(text_run) => LayoutBox::Text(text_run.upgrade()?),
265 })
266 }
267}
268
269#[derive(Default, MallocSizeOf)]
273pub struct DOMLayoutData(AtomicRefCell<InnerDOMLayoutData>);
274
275impl LayoutDataTrait for DOMLayoutData {}
277impl GenericLayoutDataTrait for DOMLayoutData {
278 fn as_any(&self) -> &dyn std::any::Any {
279 self
280 }
281}
282
283pub struct BoxSlot<'dom> {
284 pub(crate) slot: ArcRefCell<Option<LayoutBox>>,
285 pub(crate) marker: PhantomData<&'dom ()>,
286}
287
288impl From<ArcRefCell<Option<LayoutBox>>> for BoxSlot<'_> {
289 fn from(slot: ArcRefCell<Option<LayoutBox>>) -> Self {
290 Self {
291 slot,
292 marker: PhantomData,
293 }
294 }
295}
296
297impl BoxSlot<'_> {
299 pub(crate) fn set(self, layout_box: LayoutBox) {
300 layout_box.attached_to_tree(layout_box.downgrade());
301 *self.slot.borrow_mut() = Some(layout_box);
302 }
303
304 pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> {
305 self.slot.borrow_mut().take()
306 }
307
308 pub(crate) fn take_layout_box_as_text_run(&self) -> Option<ArcRefCell<TextRun>> {
312 match self.take_layout_box()? {
313 LayoutBox::Text(old_text_run) => Some(old_text_run),
314 _ => None,
315 }
316 }
317}
318
319impl Drop for BoxSlot<'_> {
320 fn drop(&mut self) {
321 if !std::thread::panicking() {
322 assert!(self.slot.borrow().is_some(), "failed to set a layout box");
323 }
324 }
325}
326
327pub(crate) trait NodeExt<'dom> {
328 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)>;
330 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
331 fn as_iframe(&self) -> Option<IFrameInfo>;
332 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)>;
333 fn as_svg(&self) -> Option<SVGElementData<'dom>>;
334 fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
335
336 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
337 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
338 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>>;
339 fn box_slot(&self) -> BoxSlot<'dom>;
340
341 fn unset_all_boxes(&self);
343
344 fn clear_fragments_and_dirty_fragment_caches(&self);
347
348 fn clear_fragments_and_dirty_fragment_caches_recursively(&self);
352
353 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self);
356
357 fn rendering_type(&self) -> NodeRenderingType;
361
362 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
363 fn with_layout_box_base(&self, callback: impl FnMut(&LayoutBoxBase));
364 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase));
365
366 fn repair_style(&self, context: &SharedStyleContext);
367
368 fn isolates_damage_for_damage_propagation(&self) -> bool;
379
380 fn rebuild_box_tree_from_independent_formatting_context(
387 &self,
388 layout_context: &LayoutContext,
389 ) -> bool;
390
391 fn is_absolutely_positioned(&self) -> bool;
394}
395
396impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
397 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)> {
398 let (resource, metadata) = self.image_data()?;
399 let width = metadata.map(|metadata| metadata.width).unwrap_or_default();
400 let height = metadata.map(|metadata| metadata.height).unwrap_or_default();
401 let (mut width, mut height) = (width as f64, height as f64);
402 if let Some(density) = self.image_density().filter(|density| *density != 1.) {
404 width /= density;
405 height /= density;
406 }
407 Some((
408 ImageInfo {
409 image: resource,
410 showing_broken_image_icon: self.showing_broken_image_icon(),
411 url: self.image_url(),
412 },
413 PhysicalSize::new(width, height),
414 ))
415 }
416
417 fn as_svg(&self) -> Option<SVGElementData<'dom>> {
418 self.svg_data()
419 }
420
421 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)> {
422 let data = self.media_data()?;
423 let natural_size = if let Some(frame) = data.current_frame {
424 Some(PhysicalSize::new(frame.width.into(), frame.height.into()))
425 } else {
426 data.metadata
427 .map(|meta| PhysicalSize::new(meta.width.into(), meta.height.into()))
428 };
429 Some((
430 VideoInfo {
431 image_key: data.current_frame.map(|frame| frame.image_key),
432 poster_url: data.poster_url,
433 },
434 natural_size,
435 ))
436 }
437
438 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
439 let canvas_data = self.canvas_data()?;
440 let source = canvas_data.image_key;
441 Some((
442 CanvasInfo { source },
443 PhysicalSize::new(canvas_data.width.into(), canvas_data.height.into()),
444 ))
445 }
446
447 fn as_iframe(&self) -> Option<IFrameInfo> {
448 match (self.iframe_pipeline_id(), self.iframe_browsing_context_id()) {
449 (Some(pipeline_id), Some(browsing_context_id)) => Some(IFrameInfo {
450 pipeline_id,
451 browsing_context_id,
452 }),
453 _ => None,
454 }
455 }
456
457 fn as_typeless_object_with_data_attribute(&self) -> Option<String> {
458 if self.type_id() !=
459 Some(ScriptLayoutNodeType::Element(
460 LayoutElementType::HTMLObjectElement,
461 ))
462 {
463 return None;
464 }
465
466 let element = self.as_element()?;
470 if element.attribute(&ns!(), &local_name!("type")).is_some() {
471 return None;
472 }
473 element
474 .attribute_as_str(&ns!(), &local_name!("data"))
475 .map(|string| string.to_owned())
476 }
477
478 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
479 if self.layout_data().is_none() {
480 self.initialize_layout_data::<DOMLayoutData>();
481 }
482 self.layout_data()
483 .unwrap()
484 .as_any()
485 .downcast_ref::<DOMLayoutData>()
486 .unwrap()
487 .0
488 .borrow_mut()
489 }
490
491 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
492 self.layout_data().map(|data| {
493 data.as_any()
494 .downcast_ref::<DOMLayoutData>()
495 .unwrap()
496 .0
497 .borrow()
498 })
499 }
500
501 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>> {
502 self.layout_data().map(|data| {
503 data.as_any()
504 .downcast_ref::<DOMLayoutData>()
505 .unwrap()
506 .0
507 .borrow_mut()
508 })
509 }
510
511 fn box_slot(&self) -> BoxSlot<'dom> {
512 let pseudo_element_chain = self.pseudo_element_chain();
513 let Some(primary) = pseudo_element_chain.primary else {
514 return self.ensure_inner_layout_data().self_box.clone().into();
515 };
516
517 let Some(secondary) = pseudo_element_chain.secondary else {
518 let primary_layout_data = self
519 .ensure_inner_layout_data()
520 .create_pseudo_layout_data(primary);
521 return primary_layout_data.borrow().self_box.clone().into();
522 };
523
524 let primary_layout_data = self
531 .inner_layout_data()
532 .expect("Should already have element InnerLayoutData here.")
533 .pseudo_layout_data(primary)
534 .expect("Should already have primary pseudo-element InnerLayoutData here");
535 let secondary_layout_data = primary_layout_data
536 .borrow_mut()
537 .create_pseudo_layout_data(secondary);
538 secondary_layout_data.borrow().self_box.clone().into()
539 }
540
541 fn unset_all_boxes(&self) {
542 let mut layout_data = self.ensure_inner_layout_data();
543 *layout_data.self_box.borrow_mut() = None;
544 layout_data.pseudo_boxes.clear();
545
546 }
549
550 fn clear_fragments_and_dirty_fragment_caches_recursively(&self) {
551 self.clear_fragments_and_dirty_fragment_caches();
552 self.clear_fragments_and_dirty_fragment_caches_of_descendants();
553 }
554
555 fn clear_fragments_and_dirty_fragment_caches(&self) {
556 self.with_layout_box_base_including_pseudos(|base| {
557 base.clear_fragments_and_dirty_fragment_cache()
558 });
559 }
560
561 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self) {
562 for child in self.flat_tree_children() {
563 child.clear_fragments_and_dirty_fragment_caches_recursively();
564 }
565 }
566
567 fn rendering_type(&self) -> NodeRenderingType {
568 let Some(layout_data) = self.inner_layout_data() else {
569 return NodeRenderingType::NotRendered;
570 };
571 match &*layout_data.self_box.borrow() {
572 Some(LayoutBox::DisplayContents(..)) => NodeRenderingType::DelegatesRendering,
573 Some(..) => NodeRenderingType::Rendered,
574 None => NodeRenderingType::NotRendered,
575 }
576 }
577
578 fn with_layout_box_base(&self, callback: impl FnMut(&LayoutBoxBase)) {
579 if let Some(inner_layout_data) = self.inner_layout_data() {
580 inner_layout_data.with_layout_box_base(callback);
581 }
582 }
583
584 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase)) {
585 if let Some(inner_layout_data) = self.inner_layout_data() {
586 inner_layout_data.with_layout_box_base_including_pseudos(callback);
587 }
588 }
589
590 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment> {
591 let Some(layout_data) = self.inner_layout_data() else {
592 return vec![];
593 };
594 match pseudo_element {
595 Some(pseudo_element) => layout_data
596 .pseudo_layout_data(pseudo_element)
597 .map(|pseudo_layout_data| pseudo_layout_data.borrow().fragments())
598 .unwrap_or_default(),
599 None => layout_data.fragments(),
600 }
601 }
602
603 fn repair_style(&self, context: &SharedStyleContext) {
604 if let Some(layout_data) = self.inner_layout_data() {
605 layout_data.repair_style(self, context);
606 }
607 }
608
609 fn isolates_damage_for_damage_propagation(&self) -> bool {
610 if self.as_element().is_some_and(|element| {
614 element.is_body_element_of_html_element_root() || element.is_root()
615 }) {
616 return false;
617 }
618
619 let Some(inner_layout_data) = self.inner_layout_data() else {
620 return false;
621 };
622 let self_box = inner_layout_data.self_box.borrow();
623 let Some(self_box) = &*self_box else {
624 return false;
625 };
626
627 match self_box {
628 LayoutBox::DisplayContents(..) => false,
629 LayoutBox::BlockLevel(block_level) => matches!(
630 &*block_level.borrow(),
631 BlockLevelBox::Independent(..) |
632 BlockLevelBox::OutOfFlowFloatBox(..) |
633 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(..)
634 ),
635 LayoutBox::InlineLevel(inline_level) => matches!(
636 inline_level,
637 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) | InlineItem::Atomic(..)
638 ),
639 LayoutBox::FlexLevel(..) => true,
640 LayoutBox::TableLevelBox(table_level_box) => matches!(
641 table_level_box,
642 TableLevelBox::Cell(..) | TableLevelBox::Caption(..),
643 ),
644 LayoutBox::TaffyItemBox(..) => true,
645 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
646 }
647 }
648
649 fn rebuild_box_tree_from_independent_formatting_context(
650 &self,
651 layout_context: &LayoutContext,
652 ) -> bool {
653 if self.as_element().is_some_and(|element| {
657 element.is_body_element_of_html_element_root() || element.is_root()
658 }) {
659 return false;
660 }
661
662 let layout_box = {
663 let Some(mut inner_layout_data) = self.inner_layout_data_mut() else {
664 return false;
665 };
666 inner_layout_data.pseudo_boxes.clear();
667 inner_layout_data.self_box.clone()
668 };
669
670 let layout_box = layout_box.borrow();
671 let Some(layout_box) = &*layout_box else {
672 return false;
673 };
674
675 let info = NodeAndStyleInfo::new(*self, self.style(&layout_context.style_context));
676 let box_style = info.style.get_box();
677 let Display::GeneratingBox(display) = box_style.display.into() else {
678 return false;
679 };
680 let contents = || {
681 assert!(
682 self.pseudo_element_chain().is_empty(),
683 "Shouldn't try to rebuild box tree from a pseudo-element"
684 );
685 Contents::for_element(info.node, layout_context)
686 };
687 match layout_box {
688 LayoutBox::DisplayContents(..) => false,
689 LayoutBox::BlockLevel(block_level) => {
690 let mut block_level = block_level.borrow_mut();
691 match &mut *block_level {
692 BlockLevelBox::Independent(independent_formatting_context) => {
693 let DisplayGeneratingBox::OutsideInside {
694 outside: DisplayOutside::Block,
695 inside: display_inside,
696 } = display
697 else {
698 return false;
699 };
700 if !matches!(
701 BlockLevelCreator::new_for_inflow_block_level_element(
702 &info,
703 display_inside,
704 contents(),
705 independent_formatting_context.propagated_data,
706 ),
707 BlockLevelCreator::Independent { .. }
708 ) {
709 return false;
710 }
711 independent_formatting_context.rebuild(layout_context, &info);
712 true
713 },
714 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
715 if !info.style.clone_float().is_floating() {
716 return false;
717 }
718 float_box.contents.rebuild(layout_context, &info);
719 true
720 },
721 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
722 if !info.style.clone_position().is_absolutely_positioned() ||
727 box_style.original_display.outside() != StyloDisplayOutside::Block
728 {
729 return false;
730 }
731 positioned_box
732 .borrow_mut()
733 .context
734 .rebuild(layout_context, &info);
735 true
736 },
737 _ => false,
738 }
739 },
740 LayoutBox::InlineLevel(inline_level) => match inline_level {
741 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
742 if !info.style.clone_position().is_absolutely_positioned() {
743 return false;
744 }
745 positioned_box
746 .borrow_mut()
747 .context
748 .rebuild(layout_context, &info);
749 true
750 },
751 InlineItem::Atomic(atomic_box, _, _) => {
752 let flags = match contents() {
753 Contents::NonReplaced(_) => FragmentFlags::empty(),
754 Contents::Replaced(_) => FragmentFlags::IS_REPLACED,
755 Contents::Widget(_) => FragmentFlags::IS_WIDGET,
756 };
757 if !info.style.is_atomic_inline_level(flags) {
758 return false;
759 }
760 atomic_box.borrow_mut().rebuild(layout_context, &info);
761 true
762 },
763 _ => false,
764 },
765 LayoutBox::FlexLevel(flex_level_box) => {
766 let mut flex_level_box = flex_level_box.borrow_mut();
767 match &mut *flex_level_box {
768 FlexLevelBox::FlexItem(flex_item_box) => {
769 if info.style.clone_position().is_absolutely_positioned() ||
770 flex_item_box.style().clone_order() != info.style.clone_order()
771 {
772 return false;
773 }
774 flex_item_box
775 .independent_formatting_context
776 .rebuild(layout_context, &info)
777 },
778 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
779 if !info.style.clone_position().is_absolutely_positioned() {
780 return false;
781 }
782 positioned_box
783 .borrow_mut()
784 .context
785 .rebuild(layout_context, &info);
786 },
787 }
788 true
789 },
790 LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
791 TableLevelBox::Caption(caption) => {
792 if display !=
793 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCaption)
794 {
795 return false;
796 }
797 caption.borrow_mut().context.rebuild(layout_context, &info);
798 true
799 },
800 TableLevelBox::Cell(table_cell) => {
801 if display !=
802 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCell)
803 {
804 return false;
805 }
806 table_cell
807 .borrow_mut()
808 .context
809 .rebuild(layout_context, &info);
810 true
811 },
812 _ => false,
813 },
814 LayoutBox::TaffyItemBox(..) => false,
815 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
816 }
817 }
818
819 fn is_absolutely_positioned(&self) -> bool {
820 self.as_element().is_some_and(|element| {
821 element
822 .element_data()
823 .styles
824 .primary()
825 .clone_position()
826 .is_absolutely_positioned()
827 })
828 }
829}