aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2015-10-21 16:42:30 -0400
committerJosh Matthews <josh@joshmatthews.net>2015-11-06 10:41:38 -0500
commit989e80036e078a19003f0e4eb069671b5222c77b (patch)
tree3fe8c22b82bd0521d87b4ef63464406da6555c7a /components/script
parent9fea6d2e46dd917f16a5f1ec0f6484e8164c7a3a (diff)
downloadservo-989e80036e078a19003f0e4eb069671b5222c77b.tar.gz
servo-989e80036e078a19003f0e4eb069671b5222c77b.zip
Implement cancellable runnables.
Additionally, make image load events cancellable. Resolves #7731.
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/htmlimageelement.rs9
-rw-r--r--components/script/dom/window.rs19
-rw-r--r--components/script/script_task.rs39
4 files changed, 62 insertions, 8 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index df5c84d3778..48f6ed39032 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -79,6 +79,7 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
use std::sync::mpsc::{Receiver, Sender};
use string_cache::{Atom, Namespace};
use style::properties::PropertyDeclarationBlock;
@@ -246,7 +247,7 @@ impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) {
}
-no_jsmanaged_fields!(bool, f32, f64, String, Url);
+no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool);
no_jsmanaged_fields!(usize, u8, u16, u32, u64);
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
no_jsmanaged_fields!(Sender<T>);
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 098938c8285..e05a50e6027 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -110,13 +110,16 @@ impl HTMLImageElement {
let trusted_node = Trusted::new(window.get_cx(), self, window.script_chan());
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
let script_chan = window.script_chan();
+ let wrapper = window.get_runnable_wrapper();
ROUTER.add_route(responder_receiver.to_opaque(), box move |message| {
// Return the image via a message to the script task, which marks the element
// as dirty and triggers a reflow.
let image_response = message.to().unwrap();
- script_chan.send(CommonScriptMsg::RunnableMsg(UpdateReplacedElement,
- box ImageResponseHandlerRunnable::new(
- trusted_node.clone(), image_response))).unwrap();
+ let runnable = ImageResponseHandlerRunnable::new(
+ trusted_node.clone(), image_response);
+ let runnable = wrapper.wrap_runnable(runnable);
+ script_chan.send(CommonScriptMsg::RunnableMsg(
+ UpdateReplacedElement, runnable)).unwrap();
});
image_cache.request_image(img_url,
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 9682b89cba6..a485d881533 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -53,7 +53,7 @@ use num::traits::ToPrimitive;
use page::Page;
use profile_traits::mem;
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
-use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg};
+use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg, RunnableWrapper};
use script_task::{SendableMainThreadScriptChan, MainThreadScriptChan, MainThreadTimerEventChan};
use script_traits::{TimerEventChan, TimerEventId, TimerEventRequest, TimerSource};
use selectors::parser::PseudoElement;
@@ -66,6 +66,7 @@ use std::ffi::CString;
use std::io::{Write, stderr, stdout};
use std::rc::Rc;
use std::sync::Arc;
+use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
use std::sync::mpsc::{Sender, channel};
use string_cache::Atom;
@@ -209,7 +210,11 @@ pub struct Window {
/// The current state of the window object
current_state: Cell<WindowState>,
- current_viewport: Cell<Rect<Au>>
+ current_viewport: Cell<Rect<Au>>,
+
+ /// A flag to prevent async events from attempting to interact with this window.
+ #[ignore_heap_size_of = "defined in std"]
+ ignore_further_async_events: Arc<AtomicBool>,
}
impl Window {
@@ -219,6 +224,7 @@ impl Window {
*self.js_runtime.borrow_for_script_deallocation() = None;
self.browsing_context.set(None);
self.current_state.set(WindowState::Zombie);
+ self.ignore_further_async_events.store(true, Ordering::Relaxed);
}
}
@@ -781,6 +787,12 @@ impl<'a, T: Reflectable> ScriptHelpers for &'a T {
}
impl Window {
+ pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
+ RunnableWrapper {
+ cancelled: self.ignore_further_async_events.clone()
+ }
+ }
+
pub fn clear_js_runtime(&self) {
self.Document().upcast::<Node>().teardown();
@@ -798,6 +810,7 @@ impl Window {
self.current_state.set(WindowState::Zombie);
*self.js_runtime.borrow_mut() = None;
self.browsing_context.set(None);
+ self.ignore_further_async_events.store(true, Ordering::Relaxed);
}
/// https://drafts.csswg.org/cssom-view/#dom-window-scroll
@@ -1260,6 +1273,8 @@ impl Window {
devtools_markers: DOMRefCell::new(HashSet::new()),
devtools_wants_updates: Cell::new(false),
webdriver_script_chan: DOMRefCell::new(None),
+
+ ignore_further_async_events: Arc::new(AtomicBool::new(false)),
};
WindowBinding::Wrap(runtime.cx(), win)
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index ac67e4a5996..dda6faaa85b 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -95,6 +95,7 @@ use std::option::Option;
use std::ptr;
use std::rc::Rc;
use std::result::Result;
+use std::sync::atomic::{Ordering, AtomicBool};
use std::sync::mpsc::{Receiver, Select, Sender, channel};
use std::sync::{Arc, Mutex};
use string_cache::Atom;
@@ -158,7 +159,38 @@ impl InProgressLoad {
}
}
+/// Encapsulated state required to create cancellable runnables from non-script threads.
+pub struct RunnableWrapper {
+ pub cancelled: Arc<AtomicBool>,
+}
+
+impl RunnableWrapper {
+ pub fn wrap_runnable<T: Runnable + Send + 'static>(&self, runnable: T) -> Box<Runnable + Send> {
+ box CancellableRunnable {
+ cancelled: self.cancelled.clone(),
+ inner: box runnable,
+ }
+ }
+}
+
+/// A runnable that can be discarded by toggling a shared flag.
+pub struct CancellableRunnable<T: Runnable + Send> {
+ cancelled: Arc<AtomicBool>,
+ inner: Box<T>,
+}
+
+impl<T: Runnable + Send> Runnable for CancellableRunnable<T> {
+ fn is_cancelled(&self) -> bool {
+ self.cancelled.load(Ordering::Relaxed)
+ }
+
+ fn handler(self: Box<CancellableRunnable<T>>) {
+ self.inner.handler()
+ }
+}
+
pub trait Runnable {
+ fn is_cancelled(&self) -> bool { false }
fn handler(self: Box<Self>);
}
@@ -990,10 +1022,13 @@ impl ScriptTask {
runnable.handler(self),
MainThreadScriptMsg::DocumentLoadsComplete(id) =>
self.handle_loads_complete(id),
- MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) =>
+ MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => {
// The category of the runnable is ignored by the pattern, however
// it is still respected by profiling (see categorize_msg).
- runnable.handler(),
+ if !runnable.is_cancelled() {
+ runnable.handler()
+ }
+ }
MainThreadScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) =>
LiveDOMReferences::cleanup(addr),
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>