script/layout_dom/
iterators.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::iter::FusedIterator;
6
7use layout_api::{DangerousStyleNode, LayoutElement, LayoutNode};
8use style::dom::{DomChildren, TElement, TShadowRoot};
9
10use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode, ServoLayoutNode};
11
12pub struct ReverseChildrenIterator<'dom> {
13    current: Option<ServoLayoutNode<'dom>>,
14}
15
16impl<'dom> Iterator for ReverseChildrenIterator<'dom> {
17    type Item = ServoLayoutNode<'dom>;
18
19    #[expect(unsafe_code)]
20    fn next(&mut self) -> Option<Self::Item> {
21        let node = self.current;
22        self.current = node.and_then(|node| unsafe { node.dangerous_previous_sibling() });
23        node
24    }
25}
26
27pub enum ServoLayoutNodeChildrenIterator<'dom> {
28    /// Iterating over the children of a node
29    Node(Option<ServoLayoutNode<'dom>>),
30    /// Iterating over the assigned nodes of a `HTMLSlotElement`
31    Slottables(<Vec<ServoDangerousStyleNode<'dom>> as IntoIterator>::IntoIter),
32}
33
34impl<'dom> ServoLayoutNodeChildrenIterator<'dom> {
35    #[expect(unsafe_code)]
36    pub(super) fn new_for_flat_tree(parent: ServoLayoutNode<'dom>) -> Self {
37        if let Some(element) = parent.as_element() {
38            if let Some(shadow) = element.shadow_root() {
39                return Self::new_for_flat_tree(shadow.as_node().layout_node());
40            };
41
42            let element = unsafe { element.dangerous_style_element() };
43            let slotted_nodes = element.slotted_nodes();
44            if !slotted_nodes.is_empty() {
45                #[expect(clippy::unnecessary_to_owned)] // Clippy is wrong.
46                return Self::Slottables(slotted_nodes.to_owned().into_iter());
47            }
48        }
49
50        Self::Node(unsafe { parent.dangerous_first_child() })
51    }
52
53    #[expect(unsafe_code)]
54    pub(super) fn new_for_dom_tree(parent: ServoLayoutNode<'dom>) -> Self {
55        Self::Node(unsafe { parent.dangerous_first_child() })
56    }
57}
58
59impl<'dom> Iterator for ServoLayoutNodeChildrenIterator<'dom> {
60    type Item = ServoLayoutNode<'dom>;
61
62    fn next(&mut self) -> Option<Self::Item> {
63        match self {
64            Self::Node(node) => {
65                #[expect(unsafe_code)]
66                let next_sibling = unsafe { (*node)?.dangerous_next_sibling() };
67                std::mem::replace(node, next_sibling)
68            },
69            Self::Slottables(slots) => slots.next().map(|node| node.layout_node()),
70        }
71    }
72}
73
74impl FusedIterator for ServoLayoutNodeChildrenIterator<'_> {}
75
76pub enum DOMDescendantIterator<'dom> {
77    /// Iterating over the children of a node, including children of a potential
78    /// [ShadowRoot](crate::dom::shadow_root::ShadowRoot)
79    Children(DomChildren<ServoDangerousStyleNode<'dom>>),
80    /// Iterating over the content's of a [`<slot>`](HTMLSlotElement) element.
81    Slottables {
82        slot: ServoDangerousStyleElement<'dom>,
83        index: usize,
84    },
85}
86
87impl<'dom> Iterator for DOMDescendantIterator<'dom> {
88    type Item = ServoDangerousStyleNode<'dom>;
89
90    fn next(&mut self) -> Option<Self::Item> {
91        match self {
92            Self::Children(children) => children.next(),
93            Self::Slottables { slot, index } => {
94                let slottables = slot.slotted_nodes();
95                let slot = slottables.get(*index)?;
96                *index += 1;
97                Some(*slot)
98            },
99        }
100    }
101}