script/event_loop/
document_collection.rs1use std::collections::hash_map;
6
7use rustc_hash::{FxBuildHasher, FxHashMap};
8use servo_base::id::{BrowsingContextId, PipelineId};
9
10use crate::dom::bindings::inheritance::Castable;
11use crate::dom::bindings::root::{Dom, DomRoot};
12use crate::dom::bindings::trace::HashMapTracedValues;
13use crate::dom::document::Document;
14use crate::dom::globalscope::GlobalScope;
15use crate::dom::html::htmliframeelement::HTMLIFrameElement;
16use crate::dom::window::Window;
17
18#[derive(JSTraceable)]
22#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
23pub(crate) struct DocumentCollection {
24 map: HashMapTracedValues<PipelineId, Dom<Document>, FxBuildHasher>,
25}
26
27impl DocumentCollection {
28 pub(crate) fn insert(&mut self, pipeline_id: PipelineId, doc: &Document) {
29 self.map.insert(pipeline_id, Dom::from_ref(doc));
30 }
31
32 pub(crate) fn remove(&mut self, pipeline_id: PipelineId) -> Option<DomRoot<Document>> {
33 self.map
34 .remove(&pipeline_id)
35 .map(|ref doc| DomRoot::from_ref(&**doc))
36 }
37
38 pub(crate) fn find_document(&self, pipeline_id: PipelineId) -> Option<DomRoot<Document>> {
39 self.map
40 .get(&pipeline_id)
41 .map(|doc| DomRoot::from_ref(&**doc))
42 .filter(|document| !document.window_detached())
43 }
44
45 pub(crate) fn find_window(&self, pipeline_id: PipelineId) -> Option<DomRoot<Window>> {
46 self.find_document(pipeline_id)
47 .map(|doc| DomRoot::from_ref(doc.window()))
48 .filter(|window| window.pipeline_id() == pipeline_id)
49 }
50
51 pub(crate) fn find_global(&self, pipeline_id: PipelineId) -> Option<DomRoot<GlobalScope>> {
52 self.find_window(pipeline_id)
53 .map(|window| DomRoot::from_ref(window.upcast()))
54 }
55
56 pub(crate) fn find_iframe(
57 &self,
58 pipeline_id: PipelineId,
59 browsing_context_id: BrowsingContextId,
60 ) -> Option<DomRoot<HTMLIFrameElement>> {
61 self.find_document(pipeline_id).and_then(|document| {
62 document
63 .iframes()
64 .get(browsing_context_id)
65 .map(|iframe| iframe.element.as_rooted())
66 })
67 }
68
69 pub(crate) fn iter(&self) -> DocumentsIter<'_> {
70 DocumentsIter {
71 iter: self.map.iter(),
72 }
73 }
74
75 pub(crate) fn documents_in_order(&self) -> Vec<PipelineId> {
93 DocumentTree::new(self).documents_in_order()
94 }
95}
96
97impl Default for DocumentCollection {
98 fn default() -> Self {
99 Self {
100 map: HashMapTracedValues::new_fx(),
101 }
102 }
103}
104
105pub(crate) struct DocumentsIter<'a> {
106 iter: hash_map::Iter<'a, PipelineId, Dom<Document>>,
107}
108
109impl Iterator for DocumentsIter<'_> {
110 type Item = (PipelineId, DomRoot<Document>);
111
112 fn next(&mut self) -> Option<(PipelineId, DomRoot<Document>)> {
113 self.iter
114 .next()
115 .map(|(id, doc)| (*id, DomRoot::from_ref(&**doc)))
116 }
117
118 fn size_hint(&self) -> (usize, Option<usize>) {
119 self.iter.size_hint()
120 }
121}
122
123#[derive(Default)]
124struct DocumentTreeNode {
125 parent: Option<PipelineId>,
126 children: Vec<PipelineId>,
127}
128
129#[derive(Default)]
140struct DocumentTree {
141 tree: FxHashMap<PipelineId, DocumentTreeNode>,
142}
143
144impl DocumentTree {
145 fn new(documents: &DocumentCollection) -> Self {
146 let mut tree = DocumentTree::default();
147 for (id, document) in documents.iter() {
148 let children: Vec<PipelineId> = document
149 .iframes()
150 .iter()
151 .filter_map(|iframe| iframe.pipeline_id())
152 .filter(|iframe_pipeline_id| documents.find_document(*iframe_pipeline_id).is_some())
153 .collect();
154 for child in &children {
155 tree.tree.entry(*child).or_default().parent = Some(id);
156 }
157 tree.tree.entry(id).or_default().children = children;
158 }
159 tree
160 }
161
162 fn documents_in_order(&self) -> Vec<PipelineId> {
163 let mut list = Vec::new();
164 for (id, node) in self.tree.iter() {
165 if node.parent.is_none() {
166 self.process_node_for_documents_in_order(*id, &mut list);
167 }
168 }
169 list
170 }
171
172 fn process_node_for_documents_in_order(&self, id: PipelineId, list: &mut Vec<PipelineId>) {
173 list.push(id);
174 for child in self
175 .tree
176 .get(&id)
177 .expect("Should have found child node")
178 .children
179 .iter()
180 {
181 self.process_node_for_documents_in_order(*child, list);
182 }
183 }
184}