accessibility_tree/layout/flow/
root.rs

1use super::*;
2
3impl crate::dom::Document {
4    pub fn layout(
5        &self,
6        viewport: crate::primitives::Size<crate::primitives::CssPx>,
7    ) -> Vec<Fragment> {
8        BoxTreeRoot::construct(self).layout(viewport)
9    }
10}
11
12struct BoxTreeRoot(BlockFormattingContext);
13
14impl BoxTreeRoot {
15    pub fn construct(document: &dom::Document) -> Self {
16        let author_styles = &document.parse_stylesheets();
17        let context = Context {
18            document,
19            author_styles,
20        };
21        let root_element = document.root_element();
22        let style = style_for_element(context.author_styles, context.document, root_element, None);
23        let (contains_floats, boxes) = construct_for_root_element(&context, root_element, style);
24        Self(BlockFormattingContext {
25            contains_floats: contains_floats == ContainsFloats::Yes,
26            contents: BlockContainer::BlockLevelBoxes(boxes),
27        })
28    }
29}
30
31fn construct_for_root_element(
32    context: &Context,
33    root_element: dom::NodeId,
34    style: Arc<ComputedValues>,
35) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
36    let replaced = ReplacedContent::for_element(root_element, context);
37
38    let display_inside = match style.box_.display {
39        Display::None => return (ContainsFloats::No, Vec::new()),
40        Display::Contents if replaced.is_some() => {
41            // 'display: contents' computes to 'none' for replaced elements
42            return (ContainsFloats::No, Vec::new());
43        }
44        // https://drafts.csswg.org/css-display-3/#transformations
45        Display::Contents => DisplayInside::Flow,
46        // The root element is blockified, ignore DisplayOutside
47        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
48    };
49
50    if let Some(replaced) = replaced {
51        let _box = match replaced {};
52        #[allow(unreachable_code)]
53        {
54            return (ContainsFloats::No, vec![Arc::new(_box)]);
55        }
56    }
57
58    let contents = IndependentFormattingContext::construct(
59        context,
60        &style,
61        display_inside,
62        Contents::OfElement(root_element),
63    );
64    if style.box_.position.is_absolutely_positioned() {
65        (
66            ContainsFloats::No,
67            vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
68                AbsolutelyPositionedBox { style, contents },
69            ))],
70        )
71    } else if style.box_.float.is_floating() {
72        (
73            ContainsFloats::Yes,
74            vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox {
75                contents,
76                style,
77            }))],
78        )
79    } else {
80        (
81            ContainsFloats::No,
82            vec![Arc::new(BlockLevelBox::Independent { style, contents })],
83        )
84    }
85}
86
87impl BoxTreeRoot {
88    fn layout(&self, viewport: crate::primitives::Size<crate::primitives::CssPx>) -> Vec<Fragment> {
89        let initial_containing_block_size = Vec2 {
90            inline: Length { px: viewport.width },
91            block: Length {
92                px: viewport.height,
93            },
94        };
95
96        let initial_containing_block = ContainingBlock {
97            inline_size: initial_containing_block_size.inline,
98            block_size: LengthOrAuto::Length(initial_containing_block_size.block),
99            // FIXME: use the document’s mode:
100            // https://drafts.csswg.org/css-writing-modes/#principal-flow
101            mode: (WritingMode::HorizontalTb, Direction::Ltr),
102        };
103        let dummy_tree_rank = 0;
104        let mut absolutely_positioned_fragments = vec![];
105        let mut flow_children = self.0.layout(
106            &initial_containing_block,
107            dummy_tree_rank,
108            &mut absolutely_positioned_fragments,
109        );
110
111        let initial_containing_block = DefiniteContainingBlock {
112            size: initial_containing_block_size,
113            mode: initial_containing_block.mode,
114        };
115        flow_children.fragments.par_extend(
116            absolutely_positioned_fragments
117                .par_iter()
118                .map(|a| a.layout(&initial_containing_block)),
119        );
120        flow_children.fragments
121    }
122}