aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/document_loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/document_loader.rs')
-rw-r--r--components/script/document_loader.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs
new file mode 100644
index 00000000000..6b8dfcea801
--- /dev/null
+++ b/components/script/document_loader.rs
@@ -0,0 +1,110 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! Tracking of pending loads in a document.
+//! https://html.spec.whatwg.org/multipage/#the-end
+
+use script_task::{ScriptMsg, ScriptChan};
+use msg::constellation_msg::{PipelineId};
+use net_traits::{LoadResponse, Metadata, load_whole_resource, ResourceTask, PendingAsyncLoad};
+use url::Url;
+
+use std::sync::mpsc::Receiver;
+
+#[jstraceable]
+#[derive(PartialEq, Clone)]
+pub enum LoadType {
+ Image(Url),
+ Script(Url),
+ Subframe(Url),
+ Stylesheet(Url),
+ PageSource(Url),
+}
+
+impl LoadType {
+ fn url(&self) -> &Url {
+ match *self {
+ LoadType::Image(ref url) |
+ LoadType::Script(ref url) |
+ LoadType::Subframe(ref url) |
+ LoadType::Stylesheet(ref url) |
+ LoadType::PageSource(ref url) => url,
+ }
+ }
+}
+
+#[jstraceable]
+pub struct DocumentLoader {
+ pub resource_task: ResourceTask,
+ notifier_data: Option<NotifierData>,
+ blocking_loads: Vec<LoadType>,
+}
+
+#[jstraceable]
+pub struct NotifierData {
+ pub script_chan: Box<ScriptChan + Send>,
+ pub pipeline: PipelineId,
+}
+
+impl DocumentLoader {
+ pub fn new(existing: &DocumentLoader) -> DocumentLoader {
+ DocumentLoader::new_with_task(existing.resource_task.clone(), None, None)
+ }
+
+ pub fn new_with_task(resource_task: ResourceTask,
+ data: Option<NotifierData>,
+ initial_load: Option<Url>,)
+ -> DocumentLoader {
+ let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();
+
+ DocumentLoader {
+ resource_task: resource_task,
+ notifier_data: data,
+ blocking_loads: initial_loads,
+ }
+ }
+
+ /// Create a new pending network request, which can be initiated at some point in
+ /// the future.
+ pub fn prepare_async_load(&mut self, load: LoadType) -> PendingAsyncLoad {
+ let url = load.url().clone();
+ self.blocking_loads.push(load);
+ let pipeline = self.notifier_data.as_ref().map(|data| data.pipeline);
+ PendingAsyncLoad::new(self.resource_task.clone(), url, pipeline)
+ }
+
+ /// Create and initiate a new network request.
+ pub fn load_async(&mut self, load: LoadType) -> Receiver<LoadResponse> {
+ let pending = self.prepare_async_load(load);
+ pending.load()
+ }
+
+ /// Create, initiate, and await the response for a new network request.
+ pub fn load_sync(&mut self, load: LoadType) -> Result<(Metadata, Vec<u8>), String> {
+ self.blocking_loads.push(load.clone());
+ let result = load_whole_resource(&self.resource_task, load.url().clone());
+ self.finish_load(load);
+ result
+ }
+
+ /// Mark an in-progress network request complete.
+ pub fn finish_load(&mut self, load: LoadType) {
+ let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == load);
+ self.blocking_loads.remove(idx.expect("unknown completed load"));
+
+ if let Some(NotifierData { ref script_chan, pipeline }) = self.notifier_data {
+ if !self.is_blocked() {
+ script_chan.send(ScriptMsg::DocumentLoadsComplete(pipeline)).unwrap();
+ }
+ }
+ }
+
+ pub fn is_blocked(&self) -> bool {
+ !self.blocking_loads.is_empty()
+ }
+
+ pub fn inhibit_events(&mut self) {
+ self.notifier_data = None;
+ }
+}