script/
document_loader.rs1use net_traits::request::RequestBuilder;
10use net_traits::{BoxedFetchCallback, ResourceThreads, fetch_async};
11use script_bindings::script_runtime::temp_cx;
12use servo_url::ServoUrl;
13
14use crate::dom::bindings::cell::DomRefCell;
15use crate::dom::bindings::root::Dom;
16use crate::dom::document::Document;
17use crate::fetch::FetchCanceller;
18
19#[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
20pub(crate) enum LoadType {
21 Image(#[no_trace] ServoUrl),
22 Script(#[no_trace] ServoUrl),
23 Subframe(#[no_trace] ServoUrl),
24 Stylesheet(#[no_trace] ServoUrl),
25 PageSource(#[no_trace] ServoUrl),
26 Media,
27}
28
29#[derive(JSTraceable, MallocSizeOf)]
33#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
34pub(crate) struct LoadBlocker {
35 doc: Dom<Document>,
37 load: Option<LoadType>,
39}
40
41impl LoadBlocker {
42 pub(crate) fn new(doc: &Document, load: LoadType) -> LoadBlocker {
44 doc.loader_mut().add_blocking_load(load.clone());
45 LoadBlocker {
46 doc: Dom::from_ref(doc),
47 load: Some(load),
48 }
49 }
50
51 pub(crate) fn terminate(
53 blocker: &DomRefCell<Option<LoadBlocker>>,
54 cx: &mut js::context::JSContext,
55 ) {
56 let Some(load) = blocker
57 .borrow_mut()
58 .as_mut()
59 .and_then(|blocker| blocker.load.take())
60 else {
61 return;
62 };
63
64 if let Some(blocker) = blocker.borrow().as_ref() {
65 blocker.doc.finish_load(load, cx);
66 }
67
68 *blocker.borrow_mut() = None;
69 }
70}
71
72impl Drop for LoadBlocker {
73 #[expect(unsafe_code)]
74 fn drop(&mut self) {
75 if let Some(load) = self.load.take() {
76 let mut cx = unsafe { temp_cx() };
77 self.doc.finish_load(load, &mut cx);
78 }
79 }
80}
81
82#[derive(JSTraceable, MallocSizeOf)]
83pub(crate) struct DocumentLoader {
84 #[no_trace]
85 resource_threads: ResourceThreads,
86 blocking_loads: Vec<LoadType>,
87 events_inhibited: bool,
88 cancellers: Vec<FetchCanceller>,
89}
90
91impl DocumentLoader {
92 pub(crate) fn new(existing: &DocumentLoader) -> DocumentLoader {
93 DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
94 }
95
96 pub(crate) fn new_with_threads(
97 resource_threads: ResourceThreads,
98 initial_load: Option<ServoUrl>,
99 ) -> DocumentLoader {
100 debug!("Initial blocking load {:?}.", initial_load);
101 let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
102
103 DocumentLoader {
104 resource_threads,
105 blocking_loads: initial_loads,
106 events_inhibited: false,
107 cancellers: Vec::new(),
108 }
109 }
110
111 pub(crate) fn cancel_all_loads(&mut self) -> Vec<FetchCanceller> {
113 self.cancellers.drain(..).collect()
114 }
115
116 fn add_blocking_load(&mut self, load: LoadType) {
118 debug!(
119 "Adding blocking load {:?} ({}).",
120 load,
121 self.blocking_loads.len()
122 );
123 self.blocking_loads.push(load);
124 }
125
126 pub(crate) fn fetch_async_with_callback(
128 &mut self,
129 load: LoadType,
130 request: RequestBuilder,
131 callback: BoxedFetchCallback,
132 ) {
133 self.add_blocking_load(load);
134 self.fetch_async_background(request, callback);
135 }
136
137 pub(crate) fn fetch_async_background(
139 &mut self,
140 request: RequestBuilder,
141 callback: BoxedFetchCallback,
142 ) {
143 self.cancellers.push(FetchCanceller::new(
144 request.id,
145 request.keep_alive,
146 self.resource_threads.core_thread.clone(),
147 ));
148 fetch_async(&self.resource_threads.core_thread, request, None, callback);
149 }
150
151 pub(crate) fn finish_load(&mut self, load: &LoadType) {
153 debug!(
154 "Removing blocking load {:?} ({}).",
155 load,
156 self.blocking_loads.len()
157 );
158 let idx = self
159 .blocking_loads
160 .iter()
161 .position(|unfinished| *unfinished == *load);
162 match idx {
163 Some(i) => {
164 self.blocking_loads.remove(i);
165 },
166 None => warn!("unknown completed load {:?}", load),
167 }
168 }
169
170 pub(crate) fn is_blocked(&self) -> bool {
171 !self.blocking_loads.is_empty()
173 }
174
175 pub(crate) fn is_only_blocked_by_iframes(&self) -> bool {
176 self.blocking_loads
177 .iter()
178 .all(|load| matches!(*load, LoadType::Subframe(_)))
179 }
180
181 pub(crate) fn inhibit_events(&mut self) {
182 self.events_inhibited = true;
183 }
184
185 pub(crate) fn events_inhibited(&self) -> bool {
186 self.events_inhibited
187 }
188
189 pub(crate) fn resource_threads(&self) -> &ResourceThreads {
190 &self.resource_threads
191 }
192}