1use std::marker::PhantomData;
6
7use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
8use layout_api::{
9 GenericLayoutDataTrait, LayoutDataTrait, LayoutElement, LayoutElementType, LayoutNode,
10 LayoutNodeType as ScriptLayoutNodeType, NodeRenderingType, SVGElementData,
11};
12use malloc_size_of_derive::MallocSizeOf;
13use script::layout_dom::ServoLayoutNode;
14use servo_arc::Arc as ServoArc;
15use servo_base::text::{AssumeUnder4GB, RangeAny, Utf32CodeUnits};
16use smallvec::SmallVec;
17use style::context::SharedStyleContext;
18use style::properties::ComputedValues;
19use style::selector_parser::PseudoElement;
20use style::values::specified::box_::DisplayOutside as StyloDisplayOutside;
21use web_atoms::{local_name, ns};
22
23use crate::cell::{ArcRefCell, WeakRefCell};
24use crate::context::LayoutContext;
25use crate::dom_traversal::{Contents, NodeAndStyleInfo};
26use crate::flexbox::FlexLevelBox;
27use crate::flow::inline::text_run::TextRun;
28use crate::flow::inline::{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, TaffyItemBoxInner};
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 fn set_element_selection(&self, selected: bool) -> bool {
307 let inner = self.0.borrow();
308 let inner_box = inner.self_box.borrow();
309 let Some(inner_box) = &*inner_box else {
310 return false;
311 };
312
313 match inner_box {
314 LayoutBox::DisplayContents(..) => false,
315 LayoutBox::BlockLevel(block_level_box) => match &*block_level_box.borrow() {
316 BlockLevelBox::Independent(independent_formatting_context) => {
317 independent_formatting_context.set_selection(selected)
318 },
319 _ => false,
320 },
321 LayoutBox::InlineLevel(inline_item) => match inline_item {
322 InlineItem::Atomic(atomic_item, ..) => atomic_item.borrow().set_selection(selected),
323 _ => false,
324 },
325 LayoutBox::FlexLevel(flex_level_box) => match &*flex_level_box.borrow() {
326 FlexLevelBox::FlexItem(flex_item) => flex_item
327 .independent_formatting_context
328 .set_selection(selected),
329 _ => false,
330 },
331 LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
332 TableLevelBox::Caption(caption) => caption.borrow().context.set_selection(selected),
333 TableLevelBox::Cell(cell) => cell.borrow().context.set_selection(selected),
334 _ => false,
335 },
336 LayoutBox::TaffyItemBox(taffy_item_box) => {
337 match &taffy_item_box.borrow().taffy_level_box {
338 TaffyItemBoxInner::InFlowBox(independent_formatting_context) => {
339 independent_formatting_context.set_selection(selected)
340 },
341 _ => false,
342 }
343 },
344 LayoutBox::Text(..) => false,
345 }
346 }
347
348 fn rendered_text(&self, range: RangeAny<Utf32CodeUnits>) -> Option<String> {
349 let inner = self.0.borrow();
350 let self_box = inner.self_box.borrow();
351
352 let Some(LayoutBox::Text(text_run)) = self_box.as_ref() else {
353 return None;
354 };
355
356 let text_run = text_run.borrow();
357 let range_in_text_run = text_run.run_data.map_dom_range_to_transformed_range(range);
358 let start_in_ifc = text_run.run_data.character_range_in_ifc_text.start;
359
360 let string = text_run.run_data.text_content.get()?;
361 let start =
362 (range_in_text_run.start + start_in_ifc).to_utf8_code_units_in(AssumeUnder4GB, string);
363 let end =
364 (range_in_text_run.end + start_in_ifc).to_utf8_code_units_in(AssumeUnder4GB, string);
365 Some(string[start.0 as usize..end.0 as usize].to_owned())
366 }
367}
368
369pub struct BoxSlot<'dom> {
370 pub(crate) slot: ArcRefCell<Option<LayoutBox>>,
371 pub(crate) marker: PhantomData<&'dom ()>,
372}
373
374impl From<ArcRefCell<Option<LayoutBox>>> for BoxSlot<'_> {
375 fn from(slot: ArcRefCell<Option<LayoutBox>>) -> Self {
376 Self {
377 slot,
378 marker: PhantomData,
379 }
380 }
381}
382
383impl BoxSlot<'_> {
385 pub(crate) fn set(self, layout_box: LayoutBox) {
386 layout_box.attached_to_tree(layout_box.downgrade());
387 *self.slot.borrow_mut() = Some(layout_box);
388 }
389
390 pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> {
391 self.slot.borrow_mut().take()
392 }
393
394 pub(crate) fn take_layout_box_as_text_run(&self) -> Option<ArcRefCell<TextRun>> {
398 match self.take_layout_box()? {
399 LayoutBox::Text(old_text_run) => Some(old_text_run),
400 _ => None,
401 }
402 }
403}
404
405impl Drop for BoxSlot<'_> {
406 fn drop(&mut self) {
407 if !std::thread::panicking() {
408 assert!(self.slot.borrow().is_some(), "failed to set a layout box");
409 }
410 }
411}
412
413pub(crate) trait NodeExt<'dom> {
414 fn is_html_br_element(&self) -> bool;
416 fn is_html_wbr_element(&self) -> bool;
418 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)>;
420 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
421 fn as_iframe(&self) -> Option<IFrameInfo>;
422 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)>;
423 fn as_svg(&self) -> Option<SVGElementData<'dom>>;
424 fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
425
426 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
427 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
428 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>>;
429 fn box_slot(&self) -> BoxSlot<'dom>;
430
431 fn unset_all_boxes(&self);
433
434 fn clear_fragments_and_dirty_fragment_caches(&self);
437
438 fn clear_fragments_and_dirty_fragment_caches_recursively(&self);
442
443 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self);
446
447 fn rendering_type(&self) -> NodeRenderingType;
451
452 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
453
454 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T>;
456 fn with_layout_box_base(&self, callback: impl FnMut(&LayoutBoxBase));
457 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase));
458
459 fn repair_style(&self, context: &SharedStyleContext);
460
461 fn isolates_damage_for_damage_propagation(&self) -> bool;
472
473 fn rebuild_box_tree_from_independent_formatting_context(
480 &self,
481 layout_context: &LayoutContext,
482 ) -> bool;
483
484 fn is_absolutely_positioned(&self) -> bool;
487}
488
489impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
490 fn is_html_br_element(&self) -> bool {
491 self.as_html_element()
492 .is_some_and(|element| element.local_name() == &local_name!("br"))
493 }
494
495 fn is_html_wbr_element(&self) -> bool {
496 self.as_html_element()
497 .is_some_and(|element| element.local_name() == &local_name!("wbr"))
498 }
499
500 fn as_image(&self) -> Option<(ImageInfo, PhysicalSize<f64>)> {
501 let (resource, metadata) = self.image_data()?;
502 let width = metadata.map(|metadata| metadata.width).unwrap_or_default();
503 let height = metadata.map(|metadata| metadata.height).unwrap_or_default();
504 let (mut width, mut height) = (width as f64, height as f64);
505 if let Some(density) = self.image_density().filter(|density| *density != 1.) {
507 width /= density;
508 height /= density;
509 }
510 Some((
511 ImageInfo {
512 image: resource,
513 showing_broken_image_icon: self.showing_broken_image_icon(),
514 url: self.image_url(),
515 },
516 PhysicalSize::new(width, height),
517 ))
518 }
519
520 fn as_svg(&self) -> Option<SVGElementData<'dom>> {
521 self.svg_data()
522 }
523
524 fn as_video(&self) -> Option<(VideoInfo, Option<PhysicalSize<f64>>)> {
525 let data = self.media_data()?;
526 let natural_size = if let Some(frame) = data.current_frame {
527 Some(PhysicalSize::new(frame.width.into(), frame.height.into()))
528 } else {
529 data.metadata
530 .map(|meta| PhysicalSize::new(meta.width.into(), meta.height.into()))
531 };
532 Some((
533 VideoInfo {
534 image_key: data.current_frame.map(|frame| frame.image_key),
535 poster_url: data.poster_url,
536 },
537 natural_size,
538 ))
539 }
540
541 fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
542 let canvas_data = self.canvas_data()?;
543 let source = canvas_data.image_key;
544 Some((
545 CanvasInfo { source },
546 PhysicalSize::new(canvas_data.width.into(), canvas_data.height.into()),
547 ))
548 }
549
550 fn as_iframe(&self) -> Option<IFrameInfo> {
551 match (self.iframe_pipeline_id(), self.iframe_browsing_context_id()) {
552 (Some(pipeline_id), Some(browsing_context_id)) => Some(IFrameInfo {
553 pipeline_id,
554 browsing_context_id,
555 }),
556 _ => None,
557 }
558 }
559
560 fn as_typeless_object_with_data_attribute(&self) -> Option<String> {
561 if self.type_id() !=
562 Some(ScriptLayoutNodeType::Element(
563 LayoutElementType::HTMLObjectElement,
564 ))
565 {
566 return None;
567 }
568
569 let element = self.as_element()?;
573 if element.attribute(&ns!(), &local_name!("type")).is_some() {
574 return None;
575 }
576 element
577 .attribute_as_str(&ns!(), &local_name!("data"))
578 .map(|string| string.to_owned())
579 }
580
581 fn ensure_inner_layout_data(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
582 if self.layout_data().is_none() {
583 self.initialize_layout_data::<DOMLayoutData>();
584 }
585 self.layout_data()
586 .unwrap()
587 .as_any()
588 .downcast_ref::<DOMLayoutData>()
589 .unwrap()
590 .0
591 .borrow_mut()
592 }
593
594 fn inner_layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
595 self.layout_data().map(|data| {
596 data.as_any()
597 .downcast_ref::<DOMLayoutData>()
598 .unwrap()
599 .0
600 .borrow()
601 })
602 }
603
604 fn inner_layout_data_mut(&self) -> Option<AtomicRefMut<'dom, InnerDOMLayoutData>> {
605 self.layout_data().map(|data| {
606 data.as_any()
607 .downcast_ref::<DOMLayoutData>()
608 .unwrap()
609 .0
610 .borrow_mut()
611 })
612 }
613
614 fn box_slot(&self) -> BoxSlot<'dom> {
615 let pseudo_element_chain = self.pseudo_element_chain();
616 let Some(primary) = pseudo_element_chain.primary else {
617 return self.ensure_inner_layout_data().self_box.clone().into();
618 };
619
620 let Some(secondary) = pseudo_element_chain.secondary else {
621 let primary_layout_data = self
622 .ensure_inner_layout_data()
623 .create_pseudo_layout_data(primary);
624 return primary_layout_data.borrow().self_box.clone().into();
625 };
626
627 let primary_layout_data = self
634 .inner_layout_data()
635 .expect("Should already have element InnerLayoutData here.")
636 .pseudo_layout_data(primary)
637 .expect("Should already have primary pseudo-element InnerLayoutData here");
638 let secondary_layout_data = primary_layout_data
639 .borrow_mut()
640 .create_pseudo_layout_data(secondary);
641 secondary_layout_data.borrow().self_box.clone().into()
642 }
643
644 fn unset_all_boxes(&self) {
645 let mut layout_data = self.ensure_inner_layout_data();
646 *layout_data.self_box.borrow_mut() = None;
647 layout_data.pseudo_boxes.clear();
648
649 }
652
653 fn clear_fragments_and_dirty_fragment_caches_recursively(&self) {
654 self.clear_fragments_and_dirty_fragment_caches();
655 self.clear_fragments_and_dirty_fragment_caches_of_descendants();
656 }
657
658 fn clear_fragments_and_dirty_fragment_caches(&self) {
659 self.with_layout_box_base_including_pseudos(|base| {
660 base.clear_fragments_and_dirty_fragment_cache()
661 });
662 }
663
664 fn clear_fragments_and_dirty_fragment_caches_of_descendants(&self) {
665 for child in self.flat_tree_children() {
666 child.clear_fragments_and_dirty_fragment_caches_recursively();
667 }
668 }
669
670 fn rendering_type(&self) -> NodeRenderingType {
671 let Some(layout_data) = self.inner_layout_data() else {
672 return NodeRenderingType::NotRendered;
673 };
674 match &*layout_data.self_box.borrow() {
675 Some(LayoutBox::DisplayContents(..)) => NodeRenderingType::DelegatesRendering,
676 Some(..) => NodeRenderingType::Rendered,
677 None => NodeRenderingType::NotRendered,
678 }
679 }
680
681 fn with_layout_box_base(&self, callback: impl FnMut(&LayoutBoxBase)) {
682 if let Some(inner_layout_data) = self.inner_layout_data() {
683 inner_layout_data.with_layout_box_base(callback);
684 }
685 }
686
687 fn with_layout_box_base_including_pseudos(&self, callback: impl FnMut(&LayoutBoxBase)) {
688 if let Some(inner_layout_data) = self.inner_layout_data() {
689 inner_layout_data.with_layout_box_base_including_pseudos(callback);
690 }
691 }
692
693 fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment> {
694 let Some(layout_data) = self.inner_layout_data() else {
695 return vec![];
696 };
697 match pseudo_element {
698 Some(pseudo_element) => layout_data
699 .pseudo_layout_data(pseudo_element)
700 .map(|pseudo_layout_data| pseudo_layout_data.borrow().fragments())
701 .unwrap_or_default(),
702 None => layout_data.fragments(),
703 }
704 }
705
706 fn with_fragments<T>(&self, callback: impl FnOnce(&[Fragment]) -> T) -> Option<T> {
707 self.inner_layout_data()?.with_fragments(callback)
708 }
709
710 fn repair_style(&self, context: &SharedStyleContext) {
711 if let Some(layout_data) = self.inner_layout_data() {
712 layout_data.repair_style(self, context);
713 }
714 }
715
716 fn isolates_damage_for_damage_propagation(&self) -> bool {
717 if self.as_element().is_some_and(|element| {
721 element.is_body_element_of_html_element_root() || element.is_root()
722 }) {
723 return false;
724 }
725
726 let Some(inner_layout_data) = self.inner_layout_data() else {
727 return false;
728 };
729 let self_box = inner_layout_data.self_box.borrow();
730 let Some(self_box) = &*self_box else {
731 return false;
732 };
733
734 match self_box {
735 LayoutBox::DisplayContents(..) => false,
736 LayoutBox::BlockLevel(block_level) => matches!(
737 &*block_level.borrow(),
738 BlockLevelBox::Independent(..) |
739 BlockLevelBox::OutOfFlowFloatBox(..) |
740 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(..)
741 ),
742 LayoutBox::InlineLevel(inline_level) => matches!(
743 inline_level,
744 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) | InlineItem::Atomic(..)
745 ),
746 LayoutBox::FlexLevel(..) => true,
747 LayoutBox::TableLevelBox(table_level_box) => matches!(
748 table_level_box,
749 TableLevelBox::Cell(..) | TableLevelBox::Caption(..),
750 ),
751 LayoutBox::TaffyItemBox(..) => true,
752 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
753 }
754 }
755
756 fn rebuild_box_tree_from_independent_formatting_context(
757 &self,
758 layout_context: &LayoutContext,
759 ) -> bool {
760 if self.as_element().is_some_and(|element| {
764 element.is_body_element_of_html_element_root() || element.is_root()
765 }) {
766 return false;
767 }
768
769 let layout_box = {
770 let Some(mut inner_layout_data) = self.inner_layout_data_mut() else {
771 return false;
772 };
773 inner_layout_data.pseudo_boxes.clear();
774 inner_layout_data.self_box.clone()
775 };
776
777 let layout_box = layout_box.borrow();
778 let Some(layout_box) = &*layout_box else {
779 return false;
780 };
781
782 let info = NodeAndStyleInfo::new(*self, self.style(&layout_context.style_context));
783 let box_style = info.style.get_box();
784 let Display::GeneratingBox(display) = box_style.display.into() else {
785 return false;
786 };
787 let contents = || {
788 assert!(
789 self.pseudo_element_chain().is_empty(),
790 "Shouldn't try to rebuild box tree from a pseudo-element"
791 );
792 Contents::for_element(info.node, layout_context)
793 };
794 match layout_box {
795 LayoutBox::DisplayContents(..) => false,
796 LayoutBox::BlockLevel(block_level) => {
797 let mut block_level = block_level.borrow_mut();
798 match &mut *block_level {
799 BlockLevelBox::Independent(independent_formatting_context) => {
800 if box_style.position.is_absolutely_positioned() ||
801 box_style.float.is_floating()
802 {
803 return false;
804 }
805 let DisplayGeneratingBox::OutsideInside {
806 outside: DisplayOutside::Block,
807 inside: display_inside,
808 } = display
809 else {
810 return false;
811 };
812 if !matches!(
813 BlockLevelCreator::new_for_inflow_block_level_element(
814 &info,
815 display_inside,
816 contents(),
817 independent_formatting_context.propagated_data,
818 ),
819 BlockLevelCreator::Independent { .. }
820 ) {
821 return false;
822 }
823 independent_formatting_context.rebuild(layout_context, &info);
824 true
825 },
826 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
827 if !info.style.get_float().is_floating() {
828 return false;
829 }
830 float_box.contents.rebuild(layout_context, &info);
831 true
832 },
833 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
834 if !info.style.get_box().position.is_absolutely_positioned() ||
839 box_style.original_display.outside() != StyloDisplayOutside::Block
840 {
841 return false;
842 }
843 positioned_box
844 .borrow_mut()
845 .context
846 .rebuild(layout_context, &info);
847 true
848 },
849 _ => false,
850 }
851 },
852 LayoutBox::InlineLevel(inline_level) => match inline_level {
853 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
854 if !info.style.get_box().position.is_absolutely_positioned() {
855 return false;
856 }
857 positioned_box
858 .borrow_mut()
859 .context
860 .rebuild(layout_context, &info);
861 true
862 },
863 InlineItem::Atomic(atomic_box, _, _) => {
864 let flags = match contents() {
865 Contents::NonReplaced(_) => FragmentFlags::empty(),
866 Contents::Replaced(_) => FragmentFlags::IS_REPLACED,
867 Contents::Widget(_) => FragmentFlags::IS_WIDGET,
868 };
869 if !info.style.is_atomic_inline_level(flags) {
870 return false;
871 }
872 atomic_box.borrow_mut().rebuild(layout_context, &info);
873 true
874 },
875 _ => false,
876 },
877 LayoutBox::FlexLevel(flex_level_box) => {
878 let mut flex_level_box = flex_level_box.borrow_mut();
879 match &mut *flex_level_box {
880 FlexLevelBox::FlexItem(flex_item_box) => {
881 if info.style.get_box().position.is_absolutely_positioned() ||
882 !flex_item_box.style().order_equals(&info.style)
883 {
884 return false;
885 }
886 flex_item_box
887 .independent_formatting_context
888 .rebuild(layout_context, &info)
889 },
890 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
891 if !info.style.get_box().position.is_absolutely_positioned() {
892 return false;
893 }
894 positioned_box
895 .borrow_mut()
896 .context
897 .rebuild(layout_context, &info);
898 },
899 }
900 true
901 },
902 LayoutBox::TableLevelBox(table_level_box) => match table_level_box {
903 TableLevelBox::Caption(caption) => {
904 if display !=
905 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCaption)
906 {
907 return false;
908 }
909 caption.borrow_mut().context.rebuild(layout_context, &info);
910 true
911 },
912 TableLevelBox::Cell(table_cell) => {
913 if display !=
914 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableCell)
915 {
916 return false;
917 }
918 table_cell
919 .borrow_mut()
920 .context
921 .rebuild(layout_context, &info);
922 true
923 },
924 _ => false,
925 },
926 LayoutBox::TaffyItemBox(..) => false,
927 LayoutBox::Text(..) => unreachable!("An element should never be a text node"),
928 }
929 }
930
931 fn is_absolutely_positioned(&self) -> bool {
932 self.as_element().is_some_and(|element| {
933 element
934 .element_data()
935 .styles
936 .primary()
937 .get_box()
938 .position
939 .is_absolutely_positioned()
940 })
941 }
942}