script/dom/node/
traversal.rs1use 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}