Skip to main content

script/dom/node/
traversal.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 js::context::NoGC;
6use script_bindings::dom::UnrootedDom;
7use script_bindings::inheritance::Castable;
8
9use crate::dom::types::{HTMLSlotElement, ShadowRoot};
10use crate::dom::{Element, Node};
11
12pub(crate) trait NoGcTraversal {
13    fn parent<'a>(no_gc: &'a NoGC, node: &Node) -> Option<UnrootedDom<'a, Node>>;
14    fn children<'a>(no_gc: &'a NoGC, node: &Node) -> impl Iterator<Item = UnrootedDom<'a, Node>>;
15}
16
17pub(crate) struct LightDomNoGcTraversal;
18
19impl NoGcTraversal for LightDomNoGcTraversal {
20    fn parent<'a>(no_gc: &'a NoGC, node: &Node) -> Option<UnrootedDom<'a, Node>> {
21        node.get_parent_node_unrooted(no_gc)
22    }
23    fn children<'a>(no_gc: &'a NoGC, node: &Node) -> impl Iterator<Item = UnrootedDom<'a, Node>> {
24        node.children_unrooted(no_gc)
25    }
26}
27
28pub(crate) struct FlatTreeForSelectionNoGcTraversal;
29
30impl NoGcTraversal for FlatTreeForSelectionNoGcTraversal {
31    fn parent<'a>(no_gc: &'a NoGC, node: &Node) -> Option<UnrootedDom<'a, Node>> {
32        if let Some(shadow_root) = node.downcast::<ShadowRoot>() {
33            return Some(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
34        }
35        if let Some(assigned_slot) = node.assigned_slot_unrooted(no_gc) {
36            return Some(UnrootedDom::upcast(assigned_slot));
37        }
38        node.get_parent_node_unrooted(no_gc)
39    }
40
41    fn children<'a>(no_gc: &'a NoGC, node: &Node) -> impl Iterator<Item = UnrootedDom<'a, Node>> {
42        if let Some(shadow_root) = node
43            .downcast::<Element>()
44            .and_then(|element| element.shadow_root_unrooted(no_gc))
45        {
46            return FlatTreeChildIterator {
47                no_gc,
48                next_child: Some(UnrootedDom::from_ref(shadow_root.upcast(), no_gc)),
49            };
50        }
51
52        if let Some(slot) = node.downcast::<HTMLSlotElement>() &&
53            let Some(first_node) = slot.assigned_nodes().first()
54        {
55            return FlatTreeChildIterator {
56                no_gc,
57                next_child: Some(UnrootedDom::from_ref(first_node.node(), no_gc)),
58            };
59        }
60
61        FlatTreeChildIterator {
62            no_gc,
63            next_child: node.first_child().get_unrooted(no_gc),
64        }
65    }
66}
67
68struct FlatTreeChildIterator<'no_gc> {
69    no_gc: &'no_gc NoGC,
70    next_child: Option<UnrootedDom<'no_gc, Node>>,
71}
72
73impl<'no_gc> Iterator for FlatTreeChildIterator<'no_gc> {
74    type Item = UnrootedDom<'no_gc, Node>;
75
76    fn next(&mut self) -> Option<Self::Item> {
77        let child = self.next_child.take()?;
78        self.next_child = child.next_flat_tree_sibling_unrooted(self.no_gc);
79        Some(child)
80    }
81}