diff options
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r-- | components/script/script_task.rs | 65 |
1 files changed, 61 insertions, 4 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs index d463d1d8107..fcf29605b80 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)) => @@ -1636,10 +1671,32 @@ impl ScriptTask { let is_javascript = incomplete.url.scheme == "javascript"; let parse_input = if is_javascript { + use url::percent_encoding::percent_decode_to; + + // Turn javascript: URL into JS code to eval, according to the steps in + // https://html.spec.whatwg.org/multipage/#javascript-protocol let _ar = JSAutoRequest::new(self.get_cx()); - let evalstr = incomplete.url.non_relative_scheme_data().unwrap(); + let mut script_source_bytes = Vec::new(); + // Start with the scheme data of the parsed URL (5.), while percent-decoding (8.) + percent_decode_to(incomplete.url.non_relative_scheme_data().unwrap().as_bytes(), + &mut script_source_bytes); + // Append question mark and query component, if any (6.), while percent-decoding (8.) + if let Some(ref query) = incomplete.url.query { + script_source_bytes.push(b'?'); + percent_decode_to(query.as_bytes(), &mut script_source_bytes); + } + // Append number sign and fragment component if any (7.), while percent-decoding (8.) + if let Some(ref fragment) = incomplete.url.fragment { + script_source_bytes.push(b'#'); + percent_decode_to(fragment.as_bytes(), &mut script_source_bytes); + } + + // UTF-8 decode (9.) + let script_source = String::from_utf8_lossy(&script_source_bytes); + + // Script source is ready to be evaluated (11.) let mut jsval = RootedValue::new(self.get_cx(), UndefinedValue()); - window.evaluate_js_on_global_with_result(evalstr, jsval.handle_mut()); + window.evaluate_js_on_global_with_result(&script_source, jsval.handle_mut()); let strval = DOMString::from_jsval(self.get_cx(), jsval.handle(), StringificationBehavior::Empty); strval.unwrap_or(DOMString::new()) |