diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 2 | ||||
-rw-r--r-- | components/script/build.rs | 7 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 2 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 69 | ||||
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 3 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/promise.rs | 2 | ||||
-rw-r--r-- | components/script/dom/promiserejectionevent.rs | 114 | ||||
-rw-r--r-- | components/script/dom/webidls/PromiseRejectionEvent.webidl | 16 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 5 | ||||
-rw-r--r-- | components/script/microtask.rs | 14 | ||||
-rw-r--r-- | components/script/script_runtime.rs | 135 | ||||
-rw-r--r-- | components/script/script_thread.rs | 14 | ||||
-rw-r--r-- | components/script/task_source/dom_manipulation.rs | 21 |
14 files changed, 379 insertions, 26 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index ece8095f021..12cb7c6c667 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -68,7 +68,7 @@ metrics = {path = "../metrics"} mitochondria = "1.1.2" mime = "0.2.1" mime_guess = "1.8.0" -mozjs = "0.9.0" +mozjs = "0.9.3" msg = {path = "../msg"} net_traits = {path = "../net_traits"} num-traits = "0.2" diff --git a/components/script/build.rs b/components/script/build.rs index d801137c59c..6bce87d65b5 100644 --- a/components/script/build.rs +++ b/components/script/build.rs @@ -79,9 +79,10 @@ struct Bytes<'a>(&'a str); impl<'a> fmt::Debug for Bytes<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("b\"")?; - formatter.write_str(self.0)?; - formatter.write_str("\" as &'static [u8]") + // https://github.com/rust-lang/rust/issues/55223 + // should technically be just `write!(formatter, "b\"{}\"", self.0) + // but the referenced issue breaks promotion in the surrounding code + write!(formatter, "{{ const FOO: &[u8] = b\"{}\"; FOO }}", self.0) } } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index fd2df0799c6..c9271bb03dc 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -6207,7 +6207,7 @@ class CGDictionary(CGThing): descriptorProvider, isMember="Dictionary", defaultValue=member.defaultValue, - exceptionCode="return Err(());")) + exceptionCode="return Err(());\n")) for member in dictionary.members] def define(self): diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 62eae2dedae..a3e879326bc 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -30,6 +30,7 @@ use ipc_channel::ipc::IpcSender; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; use js::glue::{IsWrapper, UnwrapObject}; use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment}; +use js::jsapi::{Heap, HandleObject}; use js::jsapi::{JSAutoCompartment, JSContext}; use js::jsapi::JSObject; use js::panic::maybe_resume_unwind; @@ -55,6 +56,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use task::TaskCanceller; use task_source::TaskSourceName; +use task_source::dom_manipulation::DOMManipulationTaskSource; use task_source::file_reading::FileReadingTaskSource; use task_source::networking::NetworkingTaskSource; use task_source::performance_timeline::PerformanceTimelineTaskSource; @@ -135,6 +137,23 @@ pub struct GlobalScope { /// Vector storing references of all eventsources. event_source_tracker: DOMTracker<EventSource>, + + /// Storage for watching rejected promises waiting for some client to + /// consume their rejection. + /// Promises in this list have been rejected in the last turn of the + /// event loop without the rejection being handled. + /// Note that this can contain nullptrs in place of promises removed because + /// they're consumed before it'd be reported. + /// + /// <https://html.spec.whatwg.org/multipage/#about-to-be-notified-rejected-promises-list> + uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>, + + /// Promises in this list have previously been reported as rejected + /// (because they were in the above list), but the rejection was handled + /// in the last turn of the event loop. + /// + /// <https://html.spec.whatwg.org/multipage/#outstanding-rejected-promises-weak-set> + consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>, } impl GlobalScope { @@ -169,6 +188,8 @@ impl GlobalScope { microtask_queue, list_auto_close_worker: Default::default(), event_source_tracker: DOMTracker::new(), + uncaught_rejections: Default::default(), + consumed_rejections: Default::default(), } } @@ -230,6 +251,39 @@ impl GlobalScope { GlobalScope::from_object(obj) } + pub fn add_uncaught_rejection(&self, rejection: HandleObject) { + self.uncaught_rejections.borrow_mut().push(Heap::boxed(rejection.get())); + } + + pub fn remove_uncaught_rejection(&self, rejection: HandleObject) { + let mut uncaught_rejections = self.uncaught_rejections.borrow_mut(); + + if let Some(index) = uncaught_rejections.iter().position(|promise| *promise == Heap::boxed(rejection.get())) { + uncaught_rejections.remove(index); + } + } + + pub fn get_uncaught_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> { + &self.uncaught_rejections + } + + pub fn add_consumed_rejection(&self, rejection: HandleObject) { + self.consumed_rejections.borrow_mut().push(Heap::boxed(rejection.get())); + } + + pub fn remove_consumed_rejection(&self, rejection: HandleObject) { + let mut consumed_rejections = self.consumed_rejections.borrow_mut(); + + if let Some(index) = consumed_rejections.iter().position(|promise| *promise == Heap::boxed(rejection.get())) { + consumed_rejections.remove(index); + } + } + + pub fn get_consumed_rejections(&self) -> &DomRefCell<Vec<Box<Heap<*mut JSObject>>>> { + &self.consumed_rejections + } + + #[allow(unsafe_code)] pub fn get_cx(&self) -> *mut JSContext { Runtime::get() } @@ -586,7 +640,10 @@ impl GlobalScope { /// Perform a microtask checkpoint. pub fn perform_a_microtask_checkpoint(&self) { self.microtask_queue - .checkpoint(|_| Some(DomRoot::from_ref(self))); + .checkpoint( + |_| Some(DomRoot::from_ref(self)), + vec![DomRoot::from_ref(self)] + ); } /// Enqueue a microtask for subsequent execution. @@ -624,6 +681,16 @@ impl GlobalScope { unreachable!(); } + pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource { + if let Some(window) = self.downcast::<Window>() { + return window.dom_manipulation_task_source(); + } + if let Some(worker) = self.downcast::<WorkerGlobalScope>() { + return worker.dom_manipulation_task_source(); + } + unreachable!(); + } + /// Channel to send messages to the file reading task source of /// this of this global scope. pub fn file_reading_task_source(&self) -> FileReadingTaskSource { diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 6756e6838b0..ba0dfd896fe 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1038,6 +1038,9 @@ impl HTMLMediaElement { }, _ => {}, }, + PlayerEvent::PositionChanged(_) => { + // TODO: Support for HTMLMediaElement seeking and related API properties #21998 + }, PlayerEvent::EndOfStream => { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "If the media data can be fetched but is found by inspection to be in diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 3587a11a0ad..88b50d54f2f 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -428,6 +428,7 @@ pub mod processinginstruction; pub mod progressevent; pub mod promise; pub mod promisenativehandler; +pub mod promiserejectionevent; pub mod radionodelist; pub mod range; pub mod request; diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 8112794f1c9..e7e40fb188b 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -93,7 +93,7 @@ impl Promise { } #[allow(unsafe_code, unrooted_must_root)] - unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> { + pub unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> { assert!(IsPromiseObject(obj)); let promise = Promise { reflector: Reflector::new(), diff --git a/components/script/dom/promiserejectionevent.rs b/components/script/dom/promiserejectionevent.rs new file mode 100644 index 00000000000..500e59643cd --- /dev/null +++ b/components/script/dom/promiserejectionevent.rs @@ -0,0 +1,114 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::EventBinding::EventMethods; +use dom::bindings::codegen::Bindings::PromiseRejectionEventBinding; +use dom::bindings::codegen::Bindings::PromiseRejectionEventBinding::PromiseRejectionEventMethods; +use dom::bindings::error::Fallible; +use dom::bindings::inheritance::Castable; +use dom::bindings::reflector::reflect_dom_object; +use dom::bindings::root::DomRoot; +use dom::bindings::str::DOMString; +use dom::bindings::trace::RootedTraceableBox; +use dom::event::{Event, EventBubbles, EventCancelable}; +use dom::globalscope::GlobalScope; +use dom::promise::Promise; +use dom_struct::dom_struct; +use js::jsapi::{Heap, JSContext}; +use js::jsval::JSVal; +use js::rust::HandleValue; +use servo_atoms::Atom; +use std::rc::Rc; + +#[dom_struct] +pub struct PromiseRejectionEvent { + event: Event, + #[ignore_malloc_size_of = "Rc"] + promise: Rc<Promise>, + #[ignore_malloc_size_of = "Defined in rust-mozjs"] + reason: Heap<JSVal>, +} + +impl PromiseRejectionEvent { + #[allow(unrooted_must_root)] + fn new_inherited(promise: Rc<Promise>) -> Self { + PromiseRejectionEvent { + event: Event::new_inherited(), + promise, + reason: Heap::default() + } + } + + #[allow(unrooted_must_root)] + pub fn new( + global: &GlobalScope, + type_: Atom, + bubbles: EventBubbles, + cancelable: EventCancelable, + promise: Rc<Promise>, + reason: HandleValue + ) -> DomRoot<Self> { + let ev = reflect_dom_object( + Box::new(PromiseRejectionEvent::new_inherited(promise)), + global, + PromiseRejectionEventBinding::Wrap + ); + + { + let event = ev.upcast::<Event>(); + event.init_event( + type_, + bool::from(bubbles), + bool::from(cancelable) + ); + + ev.reason.set(reason.get()); + } + ev + } + + #[allow(unrooted_must_root)] + pub fn Constructor( + global: &GlobalScope, + type_: DOMString, + init: RootedTraceableBox<PromiseRejectionEventBinding::PromiseRejectionEventInit> + ) -> Fallible<DomRoot<Self>> { + let reason = init.reason.handle(); + let promise = match init.promise.as_ref() { + Some(promise) => promise.clone(), + None => Promise::new(global) + }; + let bubbles = EventBubbles::from(init.parent.bubbles); + let cancelable = EventCancelable::from(init.parent.cancelable); + + let event = PromiseRejectionEvent::new( + global, + Atom::from(type_), + bubbles, + cancelable, + promise, + reason + ); + Ok(event) + } +} + +impl PromiseRejectionEventMethods for PromiseRejectionEvent { + #[allow(unrooted_must_root)] + // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-promise + fn Promise(&self) -> Rc<Promise> { + self.promise.clone() + } + + #[allow(unsafe_code)] + // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason + unsafe fn Reason(&self, _cx: *mut JSContext) -> JSVal { + self.reason.get() + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.event.IsTrusted() + } +} diff --git a/components/script/dom/webidls/PromiseRejectionEvent.webidl b/components/script/dom/webidls/PromiseRejectionEvent.webidl new file mode 100644 index 00000000000..5e94062f2ff --- /dev/null +++ b/components/script/dom/webidls/PromiseRejectionEvent.webidl @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://html.spec.whatwg.org/multipage/#the-promiserejectionevent-interface + +[Constructor(DOMString type, optional PromiseRejectionEventInit eventInitDict), Exposed=(Window,Worker)] +interface PromiseRejectionEvent : Event { + readonly attribute Promise<any> promise; + readonly attribute any reason; +}; + +dictionary PromiseRejectionEventInit : EventInit { + /* required */ Promise<any> promise; + any reason; +}; diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index fa2d0a449cf..edcdb329af8 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -43,6 +43,7 @@ use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use task::TaskCanceller; +use task_source::dom_manipulation::DOMManipulationTaskSource; use task_source::file_reading::FileReadingTaskSource; use task_source::networking::NetworkingTaskSource; use task_source::performance_timeline::PerformanceTimelineTaskSource; @@ -419,6 +420,10 @@ impl WorkerGlobalScope { } } + pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource { + DOMManipulationTaskSource(self.script_chan(), self.pipeline_id()) + } + pub fn file_reading_task_source(&self) -> FileReadingTaskSource { FileReadingTaskSource(self.script_chan(), self.pipeline_id()) } diff --git a/components/script/microtask.rs b/components/script/microtask.rs index a4221dd92dc..1a707d8fc3f 100644 --- a/components/script/microtask.rs +++ b/components/script/microtask.rs @@ -15,6 +15,7 @@ use dom::htmlimageelement::ImageElementMicrotask; use dom::htmlmediaelement::MediaElementMicrotask; use dom::mutationobserver::MutationObserver; use msg::constellation_msg::PipelineId; +use script_runtime::notify_about_rejected_promises; use script_thread::ScriptThread; use std::cell::Cell; use std::mem; @@ -59,7 +60,7 @@ impl MicrotaskQueue { /// <https://html.spec.whatwg.org/multipage/#perform-a-microtask-checkpoint> /// Perform a microtask checkpoint, executing all queued microtasks until the queue is empty. - pub fn checkpoint<F>(&self, target_provider: F) + pub fn checkpoint<F>(&self, target_provider: F, globalscopes: Vec<DomRoot<GlobalScope>>) where F: Fn(PipelineId) -> Option<DomRoot<GlobalScope>>, { @@ -70,7 +71,7 @@ impl MicrotaskQueue { // Step 1 self.performing_a_microtask_checkpoint.set(true); - // Steps 2-7 + // Steps 2 while !self.microtask_queue.borrow().is_empty() { rooted_vec!(let mut pending_queue); mem::swap(&mut *pending_queue, &mut *self.microtask_queue.borrow_mut()); @@ -98,9 +99,14 @@ impl MicrotaskQueue { } } - //TODO: Step 8 - notify about rejected promises + // Step 3 + for global in globalscopes.into_iter() { + notify_about_rejected_promises(&global); + } + + // TODO: Step 4 - Cleanup Indexed Database transactions. - // Step 9 + // Step 5 self.performing_a_microtask_checkpoint.set(false); } } diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 18138dcc2b0..2ab4ef986f0 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -8,24 +8,34 @@ use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback; use dom::bindings::conversions::get_dom_class; use dom::bindings::conversions::private_from_object; +use dom::bindings::inheritance::Castable; use dom::bindings::refcounted::{LiveDOMReferences, trace_refcounted_objects}; +use dom::bindings::refcounted::{Trusted, TrustedPromise}; +use dom::bindings::reflector::DomObject; use dom::bindings::root::trace_roots; use dom::bindings::settings_stack; use dom::bindings::trace::{JSTraceable, trace_traceables}; use dom::bindings::utils::DOM_CALLBACKS; +use dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; +use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; +use dom::promise::Promise; +use dom::promiserejectionevent::PromiseRejectionEvent; use js::glue::CollectServoSizes; use js::glue::SetBuildId; -use js::jsapi::{DisableIncrementalGC, GCDescription, GCProgress, HandleObject}; +use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress}; +use js::jsapi::{Heap, HandleObject}; use js::jsapi::{JSContext, JSTracer, SetDOMCallbacks, SetGCSliceCallback}; use js::jsapi::{JSGCInvocationKind, JSGCStatus, JS_AddExtraGCRootsTracer, JS_SetGCCallback}; use js::jsapi::{JSGCMode, JSGCParamKey, JS_SetGCParameter, JS_SetGlobalJitCompilerOption}; use js::jsapi::{JSJitCompilerOption, JS_SetOffthreadIonCompilationEnabled, JS_SetParallelParsingEnabled}; -use js::jsapi::{JSObject, SetPreserveWrapperCallback, SetEnqueuePromiseJobCallback}; -use js::jsapi::{SetBuildIdOp, BuildIdCharVector}; +use js::jsapi::{JSObject, PromiseRejectionHandlingState, SetPreserveWrapperCallback}; +use js::jsapi::{SetBuildIdOp, SetEnqueuePromiseJobCallback, SetPromiseRejectionTrackerCallback}; use js::jsapi::ContextOptionsRef; use js::panic::wrap_panic; +use js::rust::Handle; use js::rust::Runtime as RustRuntime; +use js::rust::wrappers::{GetPromiseIsHandled, GetPromiseResult}; use malloc_size_of::MallocSizeOfOps; use microtask::{EnqueuedPromiseCallback, Microtask}; use msg::constellation_msg::PipelineId; @@ -43,7 +53,7 @@ use std::panic::AssertUnwindSafe; use std::ptr; use style::thread_state::{self, ThreadState}; use task::TaskBox; -use task_source::TaskSourceName; +use task_source::{TaskSource, TaskSourceName}; use time::{Tm, now}; /// Common messages used to control the event loops in both the script and the worker @@ -140,6 +150,122 @@ unsafe extern "C" fn enqueue_job( ) } +#[allow(unsafe_code)] +/// https://html.spec.whatwg.org/multipage/#the-hostpromiserejectiontracker-implementation +unsafe extern "C" fn promise_rejection_tracker( + cx: *mut JSContext, + promise: HandleObject, + state: PromiseRejectionHandlingState, + _data: *mut c_void +) { + // TODO: Step 2 - If script's muted errors is true, terminate these steps. + + // Step 3. + let global = GlobalScope::from_context(cx); + + wrap_panic(AssertUnwindSafe(|| { + match state { + // Step 4. + PromiseRejectionHandlingState::Unhandled => { + global.add_uncaught_rejection(promise); + }, + // Step 5. + PromiseRejectionHandlingState::Handled => { + // Step 5-1. + if global.get_uncaught_rejections().borrow().contains(&Heap::boxed(promise.get())) { + global.remove_uncaught_rejection(promise); + return; + } + + // Step 5-2. + if !global.get_consumed_rejections().borrow().contains(&Heap::boxed(promise.get())) { + global.add_consumed_rejection(promise); + return; + } + + // Step 5-3. + global.remove_consumed_rejection(promise); + + // TODO: Step 5-4 - Queue a task to fire `rejectionhandled` event + } + }; + }), ()); +} + +#[allow(unsafe_code, unrooted_must_root)] +/// https://html.spec.whatwg.org/multipage/#notify-about-rejected-promises +pub fn notify_about_rejected_promises(global: &GlobalScope) { + unsafe { + let cx = global.get_cx(); + + // Step 2. + if global.get_uncaught_rejections().borrow().len() > 0 { + // Step 1. + let uncaught_rejections: Vec<TrustedPromise> = global.get_uncaught_rejections() + .borrow() + .iter() + .map(|promise| { + let promise = Promise::new_with_js_promise(Handle::from_raw(promise.handle()), cx); + + TrustedPromise::new(promise) + }) + .collect(); + + // Step 3. + global.get_uncaught_rejections().borrow_mut().clear(); + + let target = Trusted::new(global.upcast::<EventTarget>()); + + // Step 4. + global.dom_manipulation_task_source().queue( + task!(unhandled_rejection_event: move || { + let target = target.root(); + let cx = target.global().get_cx(); + + for promise in uncaught_rejections { + let promise = promise.root(); + + // Step 4-1. + let promise_is_handled = GetPromiseIsHandled(promise.reflector().get_jsobject()); + if promise_is_handled { + continue; + } + + // Step 4-2. + rooted!(in(cx) let reason = GetPromiseResult(promise.reflector().get_jsobject())); + + let event = PromiseRejectionEvent::new( + &target.global(), + atom!("unhandledrejection"), + EventBubbles::DoesNotBubble, + EventCancelable::Cancelable, + promise, + reason.handle() + ); + + let event_status = event.upcast::<Event>().fire(&target); + + // Step 4-3. + if event_status == EventStatus::Canceled { + // TODO: The promise rejection is not handled; we need to add it back to the list. + } + + // TODO: Step 4-4 - If [[PromiseIsHandled]] is false, add promise to consumed_rejections + } + }), + global.upcast(), + ).unwrap(); + } + + if global.get_consumed_rejections().borrow().len() > 0 { + // FIXME(cybai): Implement `rejectionhandled` event instead of clearing the whole + // consumed rejections + // https://html.spec.whatwg.org/multipage/#the-hostpromiserejectiontracker-implementation + global.get_consumed_rejections().borrow_mut().clear(); + } + } +} + #[derive(JSTraceable)] pub struct Runtime(RustRuntime); @@ -182,6 +308,7 @@ pub unsafe fn new_rt_and_cx() -> Runtime { DisableIncrementalGC(cx); SetEnqueuePromiseJobCallback(cx, Some(enqueue_job), ptr::null_mut()); + SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut()); set_gc_zeal_options(cx); diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 931b0d230ef..8795a65cd13 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -501,7 +501,7 @@ pub struct ScriptThread { /// events in the event queue. chan: MainThreadScriptChan, - dom_manipulation_task_sender: Sender<MainThreadScriptMsg>, + dom_manipulation_task_sender: Box<ScriptChan>, media_element_task_sender: Sender<MainThreadScriptMsg>, @@ -1020,7 +1020,7 @@ impl ScriptThread { task_queue, chan: MainThreadScriptChan(chan.clone()), - dom_manipulation_task_sender: chan.clone(), + dom_manipulation_task_sender: boxed_script_sender.clone(), media_element_task_sender: chan.clone(), user_interaction_task_sender: chan.clone(), networking_task_sender: boxed_script_sender.clone(), @@ -3200,8 +3200,16 @@ impl ScriptThread { } fn perform_a_microtask_checkpoint(&self) { + let globals = self.documents.borrow() + .iter() + .map(|(_id, document)| document.global()) + .collect(); + self.microtask_queue - .checkpoint(|id| self.documents.borrow().find_global(id)) + .checkpoint( + |id| self.documents.borrow().find_global(id), + globals + ) } } diff --git a/components/script/task_source/dom_manipulation.rs b/components/script/task_source/dom_manipulation.rs index ad01f514e95..376927da742 100644 --- a/components/script/task_source/dom_manipulation.rs +++ b/components/script/task_source/dom_manipulation.rs @@ -8,17 +8,21 @@ use dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask}; use dom::eventtarget::EventTarget; use dom::window::Window; use msg::constellation_msg::PipelineId; -use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory}; -use script_thread::MainThreadScriptMsg; +use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; use servo_atoms::Atom; -use servo_channel::Sender; use std::fmt; use std::result::Result; use task::{TaskCanceller, TaskOnce}; use task_source::{TaskSource, TaskSourceName}; -#[derive(Clone, JSTraceable)] -pub struct DOMManipulationTaskSource(pub Sender<MainThreadScriptMsg>, pub PipelineId); +#[derive(JSTraceable)] +pub struct DOMManipulationTaskSource(pub Box<ScriptChan + Send>, pub PipelineId); + +impl Clone for DOMManipulationTaskSource { + fn clone(&self) -> DOMManipulationTaskSource { + DOMManipulationTaskSource(self.0.clone(), self.1.clone()) + } +} impl fmt::Debug for DOMManipulationTaskSource { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -33,13 +37,14 @@ impl TaskSource for DOMManipulationTaskSource { where T: TaskOnce + 'static, { - let msg = MainThreadScriptMsg::Common(CommonScriptMsg::Task( + let msg_task = CommonScriptMsg::Task( ScriptThreadEventCategory::ScriptEvent, Box::new(canceller.wrap_task(task)), Some(self.1), DOMManipulationTaskSource::NAME, - )); - self.0.send(msg).map_err(|_| ()) + ); + + self.0.send(msg_task).map_err(|_| ()) } } |