| commit 2b82584c108cf3a8f6f071f8459bc3b216972c68 | |
| Author: Josh Matthews <josh@joshmatthews.net> | |
| Date: Fri Jan 13 19:17:40 2017 -0500 | |
| Set the proper filename and line number for inline compiled event handlers. | |
| diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs | |
| index de1ac8f..8384aaf 100644 | |
| --- a/components/script/dom/bindings/utils.rs | |
| +++ b/components/script/dom/bindings/utils.rs | |
| @@ -22,8 +22,8 @@ use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT, RUST_JSID_IS_ST | |
| use js::glue::{RUST_JSID_TO_INT, RUST_JSID_TO_STRING, UnwrapObject}; | |
| use js::jsapi::{CallArgs, DOMCallbacks, GetGlobalForObjectCrossCompartment}; | |
| use js::jsapi::{HandleId, HandleObject, HandleValue, Heap, JSAutoCompartment, JSContext}; | |
| -use js::jsapi::{JSJitInfo, JSObject, JSTracer, JSWrapObjectCallbacks}; | |
| -use js::jsapi::{JS_DeletePropertyById, JS_EnumerateStandardClasses}; | |
| +use js::jsapi::{JSJitInfo, JSObject, JSTracer, JSWrapObjectCallbacks, AutoFilename}; | |
| +use js::jsapi::{JS_DeletePropertyById, JS_EnumerateStandardClasses, DescribeScriptedCaller}; | |
| use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetLatin1StringCharsAndLength}; | |
| use js::jsapi::{JS_GetProperty, JS_GetPrototype, JS_GetReservedSlot, JS_HasProperty}; | |
| use js::jsapi::{JS_HasPropertyById, JS_IsExceptionPending, JS_IsGlobalObject}; | |
| @@ -32,7 +32,7 @@ use js::jsapi::{JS_StringHasLatin1Chars, MutableHandleValue, ObjectOpResult}; | |
| use js::jsval::{JSVal, UndefinedValue}; | |
| use js::rust::{GCMethods, ToString, get_object_class, is_dom_class}; | |
| use libc; | |
| -use std::ffi::CString; | |
| +use std::ffi::{CString, CStr}; | |
| use std::os::raw::c_void; | |
| use std::ptr; | |
| use std::slice; | |
| @@ -513,3 +513,32 @@ unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi:: | |
| pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { | |
| instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), | |
| }; | |
| + | |
| +pub struct ScriptedCaller { | |
| + pub filename: String, | |
| + pub line: usize, | |
| + pub column: usize, | |
| +} | |
| + | |
| +pub fn describe_scripted_caller() -> Option<ScriptedCaller> { | |
| + let cx = Runtime::get(); | |
| + let mut fname = AutoFilename { | |
| + ss_: ptr::null_mut(), | |
| + filename_: [0, 0], | |
| + }; | |
| + let mut lineno = 0; | |
| + let mut column = 0; | |
| + let ok = unsafe { | |
| + DescribeScriptedCaller(cx, &mut fname, &mut lineno, &mut column) | |
| + }; | |
| + if ok { | |
| + Some(ScriptedCaller { | |
| + filename: unsafe { CStr::from_ptr(fname.get()).to_string_lossy().into() }, | |
| + line: lineno as usize, | |
| + column: column as usize, | |
| + }) | |
| + } else { | |
| + //TODO: get the entry global? how to figure out line/column, in that case? | |
| + None | |
| + } | |
| +} | |
| diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs | |
| index 09cafb6..81262e6 100644 | |
| --- a/components/script/dom/eventtarget.rs | |
| +++ b/components/script/dom/eventtarget.rs | |
| @@ -71,8 +71,9 @@ pub enum ListenerPhase { | |
| #[derive(JSTraceable, Clone, PartialEq)] | |
| struct InternalRawUncompiledHandler { | |
| source: DOMString, | |
| - url: ServoUrl, | |
| + filename: String, | |
| line: usize, | |
| + column: usize, | |
| } | |
| /// A representation of an event handler, either compiled or uncompiled raw source, or null. | |
| @@ -348,14 +349,16 @@ impl EventTarget { | |
| /// Store the raw uncompiled event handler for on-demand compilation later. | |
| /// https://html.spec.whatwg.org/multipage/#event-handler-attributes:event-handler-content-attributes-3 | |
| pub fn set_event_handler_uncompiled(&self, | |
| - url: ServoUrl, | |
| + filename: String, | |
| line: usize, | |
| + column: usize, | |
| ty: &str, | |
| source: DOMString) { | |
| let handler = InternalRawUncompiledHandler { | |
| source: source, | |
| line: line, | |
| - url: url, | |
| + column: column, | |
| + filename: filename, | |
| }; | |
| self.set_inline_event_listener(Atom::from(ty), | |
| Some(InlineEventListener::Uncompiled(handler))); | |
| @@ -387,7 +390,7 @@ impl EventTarget { | |
| // Step 1.6 | |
| let window = document.window(); | |
| - let url_serialized = CString::new(handler.url.to_string()).unwrap(); | |
| + let url_serialized = CString::new(handler.filename).unwrap(); | |
| let name = CString::new(&**ty).unwrap(); | |
| static mut ARG_NAMES: [*const c_char; 1] = [b"event\0" as *const u8 as *const c_char]; | |
| diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs | |
| index ea9b177..02becb3 100644 | |
| --- a/components/script/dom/htmlbodyelement.rs | |
| +++ b/components/script/dom/htmlbodyelement.rs | |
| @@ -9,7 +9,9 @@ use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyEle | |
| use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; | |
| use dom::bindings::inheritance::Castable; | |
| use dom::bindings::js::{LayoutJS, Root}; | |
| +use dom::bindings::reflector::DomObject; | |
| use dom::bindings::str::DOMString; | |
| +use dom::bindings::utils::describe_scripted_caller; | |
| use dom::document::Document; | |
| use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; | |
| use dom::eventtarget::EventTarget; | |
| @@ -169,9 +171,14 @@ impl VirtualMethods for HTMLBodyElement { | |
| &local_name!("onresize") | &local_name!("onunload") | &local_name!("onerror") | |
| => { | |
| let evtarget = window.upcast::<EventTarget>(); // forwarded event | |
| - let source_line = 1; //TODO(#9604) obtain current JS execution line | |
| - evtarget.set_event_handler_uncompiled(window.get_url(), | |
| - source_line, | |
| + let caller = describe_scripted_caller(); | |
| + let (filename, line, column) = match caller { | |
| + Some(c) => (c.filename, c.line, c.column), | |
| + None => (window.get_url().to_string(), 1, 0), | |
| + }; | |
| + evtarget.set_event_handler_uncompiled(filename, | |
| + line, | |
| + column, | |
| &name[2..], | |
| DOMString::from((**attr.value()).to_owned())); | |
| false | |
| diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs | |
| index 6725fdb..f351818 100644 | |
| --- a/components/script/dom/htmlelement.rs | |
| +++ b/components/script/dom/htmlelement.rs | |
| @@ -14,7 +14,9 @@ use dom::bindings::error::{Error, ErrorResult}; | |
| use dom::bindings::inheritance::{ElementTypeId, HTMLElementTypeId, NodeTypeId}; | |
| use dom::bindings::inheritance::Castable; | |
| use dom::bindings::js::{JS, MutNullableJS, Root, RootedReference}; | |
| +use dom::bindings::reflector::DomObject; | |
| use dom::bindings::str::DOMString; | |
| +use dom::bindings::utils::describe_scripted_caller; | |
| use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner}; | |
| use dom::document::{Document, FocusType}; | |
| use dom::domstringmap::DOMStringMap; | |
| @@ -511,9 +513,14 @@ impl VirtualMethods for HTMLElement { | |
| match (attr.local_name(), mutation) { | |
| (name, AttributeMutation::Set(_)) if name.starts_with("on") => { | |
| let evtarget = self.upcast::<EventTarget>(); | |
| - let source_line = 1; //TODO(#9604) get current JS execution line | |
| - evtarget.set_event_handler_uncompiled(window_from_node(self).get_url(), | |
| - source_line, | |
| + let caller = describe_scripted_caller(); | |
| + let (filename, line, column) = match caller { | |
| + Some(c) => (c.filename, c.line, c.column), | |
| + None => (window_from_node(self).get_url().to_string(), 1, 0), | |
| + }; | |
| + evtarget.set_event_handler_uncompiled(filename, | |
| + line, | |
| + column, | |
| &name[2..], | |
| // FIXME(ajeffrey): Convert directly from AttrValue to DOMString | |
| DOMString::from(&**attr.value())); | |
| diff --git a/tests/wpt/mozilla/tests/mozilla/track_line.html b/tests/wpt/mozilla/tests/mozilla/track_line.html | |
| index b181b70..3e037bd 100644 | |
| --- a/tests/wpt/mozilla/tests/mozilla/track_line.html | |
| +++ b/tests/wpt/mozilla/tests/mozilla/track_line.html | |
| @@ -7,16 +7,26 @@ | |
| setup({allow_uncaught_exception:true}); | |
| var t = async_test("error event has proper line number"); | |
| var errors = 0; | |
| -var expected_lines = [21, 4]; | |
| +var expected_lines = [[location.href, 27], | |
| + [location.href, 31], | |
| + [location.href.replace('track_line.html', 'resources/external.js'), 4]]; | |
| window.addEventListener('error', t.step_func(function(e) { | |
| assert_true(e instanceof ErrorEvent); | |
| - assert_equals(e.lineno, expected_lines[errors]); | |
| + var expected = expected_lines[errors]; | |
| + assert_equals(e.filename, expected[0]); | |
| + assert_equals(e.lineno, expected[1]); | |
| errors++; | |
| - if (errors == 2) { | |
| + if (errors == expected_lines.length) { | |
| t.done(); | |
| } | |
| }), true); | |
| </script> | |
| +<div id="testdiv"></div> | |
| +<script> | |
| + var div = document.querySelector('#testdiv'); | |
| + div.setAttribute('onclick', 'this_is_a_js_error'); | |
| + div.dispatchEvent(new Event('click')); | |
| +</script> | |
| <script> | |
| this_is_a_js_error | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment