diff options
author | Ms2ger <Ms2ger@gmail.com> | 2016-08-27 16:17:37 +0200 |
---|---|---|
committer | Ms2ger <Ms2ger@gmail.com> | 2016-09-02 11:44:44 +0200 |
commit | ae38c53de7443db395fc06be2df0802531576794 (patch) | |
tree | 31b2cc46ef98f120a8ff3137d84e33816d01f6cc /components/script/dom | |
parent | 92c3961743daddefc24846aad734ed5bce715978 (diff) | |
download | servo-ae38c53de7443db395fc06be2df0802531576794.tar.gz servo-ae38c53de7443db395fc06be2df0802531576794.zip |
Dispatch error events at the window object.
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/callback.rs | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 68 | ||||
-rw-r--r-- | components/script/dom/eventtarget.rs | 3 | ||||
-rw-r--r-- | components/script/dom/window.rs | 39 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 2 |
5 files changed, 86 insertions, 28 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index c7a09fcc4d8..7b837df1fed 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -191,7 +191,7 @@ impl<'a> Drop for CallSetup<'a> { JS_LeaveCompartment(self.cx, self.old_compartment); if self.handling == ExceptionHandling::Report { let _ac = JSAutoCompartment::new(self.cx, *self.exception_compartment); - report_pending_exception(self.cx); + report_pending_exception(self.cx, true); } } } diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index 6c26ae8502c..752f0d75b49 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; use dom::bindings::conversions::root_from_object; use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible}; -use dom::bindings::global::GlobalRef; +use dom::bindings::global::{GlobalRef, global_root_from_context}; use dom::bindings::str::USVString; use dom::domexception::{DOMErrorName, DOMException}; use js::error::{throw_range_error, throw_type_error}; @@ -132,11 +132,16 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, result: JS_SetPendingException(cx, thrown.handle()); } -struct ErrorInfo { - filename: String, - message: String, - lineno: c_uint, - column: c_uint, +/// A struct encapsulating information about a runtime script error. +pub struct ErrorInfo { + /// The error message. + pub message: String, + /// The file name. + pub filename: String, + /// The line number. + pub lineno: c_uint, + /// The column number. + pub column: c_uint, } impl ErrorInfo { @@ -192,7 +197,10 @@ impl ErrorInfo { } /// Report a pending exception, thereby clearing it. -pub unsafe fn report_pending_exception(cx: *mut JSContext) { +/// +/// The `dispatch_event` argument is temporary and non-standard; passing false +/// prevents dispatching the `error` event. +pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) { if JS_IsExceptionPending(cx) { rooted!(in(cx) let mut value = UndefinedValue()); if !JS_GetPendingException(cx, value.handle_mut()) { @@ -202,22 +210,31 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext) { } JS_ClearPendingException(cx); - if !value.is_object() { - match USVString::from_jsval(cx, value.handle(), ()) { - Ok(ConversionResult::Success(USVString(string))) => error!("Uncaught exception: {}", string), - _ => error!("Uncaught exception: failed to stringify primitive"), + let error_info = if value.is_object() { + rooted!(in(cx) let object = value.to_object()); + let error_info = ErrorInfo::from_native_error(cx, object.handle()) + .or_else(|| ErrorInfo::from_dom_exception(object.handle())); + match error_info { + Some(error_info) => error_info, + None => { + error!("Uncaught exception: failed to extract information"); + return; + } } - return; - } - - rooted!(in(cx) let object = value.to_object()); - let error_info = ErrorInfo::from_native_error(cx, object.handle()) - .or_else(|| ErrorInfo::from_dom_exception(object.handle())); - let error_info = match error_info { - Some(error_info) => error_info, - None => { - error!("Uncaught exception: failed to extract information"); - return; + } else { + match USVString::from_jsval(cx, value.handle(), ()) { + Ok(ConversionResult::Success(USVString(string))) => { + ErrorInfo { + message: format!("uncaught exception: {}", string), + filename: String::new(), + lineno: 0, + column: 0, + } + }, + _ => { + error!("Uncaught exception: failed to stringify primitive"); + return; + }, } }; @@ -226,6 +243,13 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext) { error_info.lineno, error_info.column, error_info.message); + + if dispatch_event { + let global = global_root_from_context(cx); + if let GlobalRef::Window(window) = global.r() { + window.report_an_error(error_info, value.handle()); + } + } } } diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index 29a6b4102f8..c941eb8e20e 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -427,7 +427,8 @@ impl EventTarget { // Step 1.8.2 unsafe { let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get()); - report_pending_exception(cx); + // FIXME(#13152): dispatch error event. + report_pending_exception(cx, false); } // Step 1.8.1 / 1.8.3 return None; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index b6bf6a35643..d1529b44b19 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -14,7 +14,7 @@ use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods}; -use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception}; +use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception, ErrorInfo}; use dom::bindings::global::{GlobalRef, global_root_from_object}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; @@ -30,7 +30,8 @@ use dom::crypto::Crypto; use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration}; use dom::document::Document; use dom::element::Element; -use dom::event::Event; +use dom::errorevent::ErrorEvent; +use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; use dom::history::History; use dom::htmliframeelement::build_mozbrowser_custom_event; @@ -273,6 +274,9 @@ pub struct Window { /// A list of scroll offsets for each scrollable element. scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>, + + /// https://html.spec.whatwg.org/multipage/#in-error-reporting-mode + in_error_reporting_mode: Cell<bool> } impl Window { @@ -952,7 +956,7 @@ impl<'a, T: Reflectable> ScriptHelpers for &'a T { code.len() as libc::size_t, rval) { debug!("error evaluating JS string"); - report_pending_exception(cx); + report_pending_exception(cx, true); } } @@ -1742,6 +1746,7 @@ impl Window { ignore_further_async_events: Arc::new(AtomicBool::new(false)), error_reporter: error_reporter, scroll_offsets: DOMRefCell::new(HashMap::new()), + in_error_reporting_mode: Cell::new(false), }; WindowBinding::Wrap(runtime.cx(), win) @@ -1749,6 +1754,34 @@ impl Window { pub fn live_devtools_updates(&self) -> bool { return self.devtools_wants_updates.get(); } + + /// https://html.spec.whatwg.org/multipage/#report-the-error + pub fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue) { + // Step 1. + if self.in_error_reporting_mode.get() { + return; + } + + // Step 2. + self.in_error_reporting_mode.set(true); + + // Steps 3-12. + let event = ErrorEvent::new(GlobalRef::Window(self), + atom!("error"), + EventBubbles::DoesNotBubble, + EventCancelable::Cancelable, + error_info.message.into(), + error_info.filename.into(), + error_info.lineno, + error_info.column, + value); + + // Step 13. + event.upcast::<Event>().fire(self.upcast::<EventTarget>()); + + // Step 14. + self.in_error_reporting_mode.set(false); + } } fn should_move_clip_rect(clip_rect: Rect<Au>, new_viewport: Rect<f32>) -> bool { diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 1b3c48b9c12..9f61753ca64 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -384,7 +384,7 @@ impl WorkerGlobalScope { unsafe { let _ac = JSAutoCompartment::new(self.runtime.cx(), self.reflector().get_jsobject().get()); - report_pending_exception(self.runtime.cx()); + report_pending_exception(self.runtime.cx(), true); } } } |