diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/globalscope.rs | 58 | ||||
-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 |
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; +}; |