aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/globalscope.rs58
-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
5 files changed, 189 insertions, 2 deletions
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 62eae2dedae..c38a5869d61 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;
@@ -135,6 +136,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 +187,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 +250,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 +639,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.
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;
+};