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.rs53
1 files changed, 52 insertions, 1 deletions
diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs
index e0da74ae706..c6c33fc1a5d 100644
--- a/components/script/document_loader.rs
+++ b/components/script/document_loader.rs
@@ -5,10 +5,13 @@
//! Tracking of pending loads in a document.
//! https://html.spec.whatwg.org/multipage/#the-end
+use dom::bindings::js::JS;
+use dom::document::Document;
use msg::constellation_msg::PipelineId;
use net_traits::AsyncResponseTarget;
use net_traits::{PendingAsyncLoad, ResourceThread, LoadContext};
use std::sync::Arc;
+use std::thread;
use url::Url;
#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
@@ -41,6 +44,50 @@ impl LoadType {
}
}
+/// Canary value ensuring that manually added blocking loads (ie. ones that weren't
+/// created via DocumentLoader::prepare_async_load) are always removed by the time
+/// that the owner is destroyed.
+#[derive(JSTraceable, HeapSizeOf)]
+#[must_root]
+pub struct LoadBlocker {
+ /// The document whose load event is blocked by this object existing.
+ doc: JS<Document>,
+ /// The load that is blocking the document's load event.
+ load: Option<LoadType>,
+}
+
+impl LoadBlocker {
+ /// Mark the document's load event as blocked on this new load.
+ pub fn new(doc: &Document, load: LoadType) -> LoadBlocker {
+ doc.add_blocking_load(load.clone());
+ LoadBlocker {
+ doc: JS::from_ref(doc),
+ load: Some(load),
+ }
+ }
+
+ /// Remove this load from the associated document's list of blocking loads.
+ pub fn terminate(blocker: &mut Option<LoadBlocker>) {
+ if let Some(this) = blocker.as_mut() {
+ this.doc.finish_load(this.load.take().unwrap());
+ }
+ *blocker = None;
+ }
+
+ /// Return the url associated with this load.
+ pub fn url(&self) -> Option<&Url> {
+ self.load.as_ref().map(LoadType::url)
+ }
+}
+
+impl Drop for LoadBlocker {
+ fn drop(&mut self) {
+ if !thread::panicking() {
+ assert!(self.load.is_none());
+ }
+ }
+}
+
#[derive(JSTraceable, HeapSizeOf)]
pub struct DocumentLoader {
/// We use an `Arc<ResourceThread>` here in order to avoid file descriptor exhaustion when there
@@ -73,12 +120,16 @@ impl DocumentLoader {
}
}
+ pub fn add_blocking_load(&mut self, load: LoadType) {
+ self.blocking_loads.push(load);
+ }
+
/// 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 context = load.to_load_context();
let url = load.url().clone();
- self.blocking_loads.push(load);
+ self.add_blocking_load(load);
PendingAsyncLoad::new(context, (*self.resource_thread).clone(), url, self.pipeline)
}