diff options
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r-- | components/script/script_thread.rs | 70 |
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 { |