aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r--components/script/script_thread.rs70
1 files changed, 67 insertions, 3 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 298323929c1..cf0116edef0 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -22,12 +22,14 @@ use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use devtools_traits::CSSError;
use document_loader::DocumentLoader;
+use dom::bindings::callback::ExceptionHandling;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
+use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, StringificationBehavior};
-use dom::bindings::global::GlobalRef;
+use dom::bindings::global::{GlobalRef, global_root_from_object};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootCollection};
use dom::bindings::js::{RootCollectionPtr, RootedReference};
@@ -59,8 +61,8 @@ use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use js::glue::GetWindowProxyClass;
-use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks};
-use js::jsapi::{JSTracer, SetWindowProxyClass};
+use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks, HandleObject};
+use js::jsapi::{JSTracer, SetWindowProxyClass, SetEnqueuePromiseJobCallback};
use js::jsval::UndefinedValue;
use js::rust::Runtime;
use mem::heap_size_of_self_and_children;
@@ -91,6 +93,7 @@ use std::borrow::ToOwned;
use std::cell::Cell;
use std::collections::{HashMap, HashSet};
use std::option::Option;
+use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;
use std::result::Result;
@@ -315,6 +318,18 @@ impl OpaqueSender<CommonScriptMsg> for Sender<MainThreadScriptMsg> {
}
}
+#[allow(unsafe_code)]
+unsafe extern "C" fn enqueue_job(_cx: *mut JSContext,
+ job: HandleObject,
+ _allocation_site: HandleObject,
+ _data: *mut c_void) -> bool {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = &*root.get().unwrap();
+ script_thread.enqueue_promise_job(job);
+ });
+ true
+}
+
/// Information for an entire page. Pages are top-level browsing contexts and can contain multiple
/// frames.
#[derive(JSTraceable)]
@@ -394,6 +409,16 @@ pub struct ScriptThread {
timer_event_port: Receiver<TimerEvent>,
content_process_shutdown_chan: IpcSender<()>,
+
+ flushing_job_queue: DOMRefCell<Vec<EnqueuedPromiseCallback>>,
+ promise_job_queue: DOMRefCell<Vec<EnqueuedPromiseCallback>>,
+ pending_promise_job_runnable: Cell<bool>,
+}
+
+#[derive(JSTraceable)]
+struct EnqueuedPromiseCallback {
+ callback: Rc<PromiseJobCallback>,
+ pipeline: PipelineId,
}
/// In the event of thread panic, all data on the stack runs its destructor. However, there
@@ -541,6 +566,7 @@ impl ScriptThread {
JS_SetWrapObjectCallbacks(runtime.rt(),
&WRAP_CALLBACKS);
SetWindowProxyClass(runtime.rt(), GetWindowProxyClass());
+ SetEnqueuePromiseJobCallback(runtime.rt(), Some(enqueue_job), ptr::null_mut());
}
// Ask the router to proxy IPC messages from the devtools to us.
@@ -599,6 +625,10 @@ impl ScriptThread {
timer_event_port: timer_event_port,
content_process_shutdown_chan: state.content_process_shutdown_chan,
+
+ promise_job_queue: DOMRefCell::new(vec![]),
+ flushing_job_queue: DOMRefCell::new(vec![]),
+ pending_promise_job_runnable: Cell::new(false),
}
}
@@ -2174,6 +2204,40 @@ impl ScriptThread {
location.Reload();
}
}
+
+ fn enqueue_promise_job(&self, job: HandleObject) {
+ let global = unsafe { global_root_from_object(job.get()) };
+ let pipeline = global.r().pipeline();
+ self.promise_job_queue.borrow_mut().push(EnqueuedPromiseCallback {
+ callback: PromiseJobCallback::new(job.get()),
+ pipeline: pipeline,
+ });
+ if !self.pending_promise_job_runnable.get() {
+ self.pending_promise_job_runnable.set(true);
+ let _ = self.dom_manipulation_task_source.queue(box FlushPromiseJobs, global.r());
+ }
+ }
+
+ fn flush_promise_jobs(&self) {
+ self.pending_promise_job_runnable.set(false);
+ {
+ let mut pending_queue = self.promise_job_queue.borrow_mut();
+ *self.flushing_job_queue.borrow_mut() = pending_queue.drain(..).collect();
+ }
+ for job in &*self.flushing_job_queue.borrow() {
+ if let Some(context) = self.find_child_context(job.pipeline) {
+ let _ = job.callback.Call_(&*context.active_window(), ExceptionHandling::Report);
+ }
+ }
+ self.flushing_job_queue.borrow_mut().clear();
+ }
+}
+
+struct FlushPromiseJobs;
+impl Runnable for FlushPromiseJobs {
+ fn main_thread_handler(self: Box<FlushPromiseJobs>, script_thread: &ScriptThread) {
+ script_thread.flush_promise_jobs();
+ }
}
impl Drop for ScriptThread {