aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml2
-rw-r--r--components/script/build.rs7
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py2
-rw-r--r--components/script/dom/globalscope.rs69
-rw-r--r--components/script/dom/htmlmediaelement.rs3
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/promise.rs2
-rw-r--r--components/script/dom/promiserejectionevent.rs114
-rw-r--r--components/script/dom/webidls/PromiseRejectionEvent.webidl16
-rw-r--r--components/script/dom/workerglobalscope.rs5
-rw-r--r--components/script/microtask.rs14
-rw-r--r--components/script/script_runtime.rs135
-rw-r--r--components/script/script_thread.rs14
-rw-r--r--components/script/task_source/dom_manipulation.rs21
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(|_| ())
}
}