1use script::layout_dom::ServoLayoutNode;
6
7use crate::context::LayoutContext;
8use crate::dom::{LayoutBox, NodeExt};
9use crate::flexbox::FlexLevelBox;
10use crate::flow::BlockLevelBox;
11use crate::flow::inline::InlineItem;
12use crate::fragment_tree::Fragment;
13
14pub(crate) struct LayoutRoot<'dom> {
37 node: ServoLayoutNode<'dom>,
38}
39
40impl<'dom> TryFrom<ServoLayoutNode<'dom>> for LayoutRoot<'dom> {
41 type Error = ();
42
43 fn try_from(node: ServoLayoutNode<'dom>) -> Result<Self, Self::Error> {
44 if !node.is_absolutely_positioned() {
45 return Err(());
46 }
47
48 let is_layout_root = node
50 .with_layout_box_base(|base| {
51 let fragments = base.fragments();
52 fragments.len() == 1 && matches!(fragments.first(), Some(Fragment::LayoutRoot(..)))
53 })
54 .unwrap_or(false);
55
56 if !is_layout_root {
57 return Err(());
58 }
59
60 Ok(Self { node })
61 }
62}
63
64impl<'dom> LayoutRoot<'dom> {
65 pub(crate) fn try_layout(&self, layout_context: &LayoutContext) -> bool {
66 let Some(inner_layout_data) = self.node.inner_layout_data_mut() else {
67 return false;
68 };
69 let layout_box = inner_layout_data.self_box.clone();
70
71 let layout_box = layout_box.borrow();
72 let Some(layout_box) = &*layout_box else {
73 return false;
74 };
75
76 let positioned_box = match layout_box {
77 LayoutBox::BlockLevel(block_level) => {
78 let mut block_level = block_level.borrow_mut();
79 match &mut *block_level {
80 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
81 positioned_box.clone()
82 },
83 _ => return false,
84 }
85 },
86 LayoutBox::InlineLevel(InlineItem::OutOfFlowAbsolutelyPositionedBox(
87 positioned_box,
88 _,
89 )) => positioned_box.clone(),
90 LayoutBox::FlexLevel(flex_level_box) => {
91 let mut flex_level_box = flex_level_box.borrow_mut();
92 match &mut *flex_level_box {
93 FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
94 positioned_box.clone()
95 },
96 _ => return false,
97 }
98 },
99 _ => return false,
100 };
101
102 let positioned_box = positioned_box.borrow();
103 let formatting_context = &positioned_box.context;
104 let fragments = formatting_context.base.fragments();
105 let Some(Fragment::LayoutRoot(layout_root_fragment)) = fragments.first() else {
106 return false;
107 };
108
109 let layout_inputs = formatting_context.layout_root_layout_inputs.borrow();
110 let Some(layout_inputs) = &*layout_inputs else {
111 return false;
112 };
113
114 layout_inputs
117 .layout(
118 layout_context,
119 formatting_context,
120 &layout_root_fragment.fragment,
121 )
122 .is_ok()
123 }
124
125 pub(crate) fn handle_failed_layout_root_layout(&self) {
126 self.node
127 .clear_fragments_and_dirty_fragment_caches_recursively();
128 }
129
130 pub(crate) fn node(&self) -> ServoLayoutNode<'dom> {
131 self.node
132 }
133}