From 832b90d4a50df10e2d1ef86d6d67f1a0d938de92 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 20 Feb 2018 13:48:44 +0100 Subject: [PATCH] mshtml: Added IDOMMouseEvent::relatedTarget implementation. Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/mshtml/htmldoc.c | 7 +++ dlls/mshtml/htmlelem.c | 7 +++ dlls/mshtml/htmlevent.c | 92 ++++++++++++++++++++++++++++++------ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/htmlwindow.c | 7 +++ dlls/mshtml/tests/events.js | 5 +- dlls/mshtml/xmlhttprequest.c | 7 +++ 7 files changed, 110 insertions(+), 16 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 25459bceeaf..4473b491fdf 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5039,6 +5039,12 @@ static compat_mode_t HTMLDocumentNode_get_compat_mode(DispatchEx *dispex) return This->document_mode; } +static nsISupports *HTMLDocumentNode_get_gecko_target(DispatchEx *dispex) +{ + HTMLDocumentNode *This = impl_from_DispatchEx(dispex); + return (nsISupports*)This->node.nsnode; +} + static void HTMLDocumentNode_bind_event(DispatchEx *dispex, eventid_t eid) { HTMLDocumentNode *This = impl_from_DispatchEx(dispex); @@ -5077,6 +5083,7 @@ static const event_target_vtbl_t HTMLDocumentNode_event_target_vtbl = { HTMLDocumentNode_get_compat_mode, NULL }, + HTMLDocumentNode_get_gecko_target, HTMLDocumentNode_bind_event, HTMLDocumentNode_get_parent_event_target, NULL, diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 28dd7161069..6379101b667 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -5430,6 +5430,12 @@ static HRESULT HTMLElement_populate_props(DispatchEx *dispex) return S_OK; } +static nsISupports *HTMLElement_get_gecko_target(DispatchEx *dispex) +{ + HTMLElement *This = impl_from_DispatchEx(dispex); + return (nsISupports*)This->node.nsnode; +} + static void HTMLElement_bind_event(DispatchEx *dispex, eventid_t eid) { HTMLElement *This = impl_from_DispatchEx(dispex); @@ -5521,6 +5527,7 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = { NULL, HTMLElement_populate_props }, + HTMLElement_get_gecko_target, HTMLElement_bind_event, HTMLElement_get_parent_event_target, HTMLElement_handle_event_default, diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 381d0dc2e21..685a1e3943a 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -293,6 +293,8 @@ static void remove_event_listener(EventTarget *event_target, const WCHAR *type_n } } +static HRESULT get_gecko_target(IEventTarget*,nsIDOMEventTarget**); + typedef struct { DispatchEx dispex; IHTMLEventObj IHTMLEventObj_iface; @@ -1459,8 +1461,37 @@ static HRESULT WINAPI DOMMouseEvent_get_button(IDOMMouseEvent *iface, USHORT *p) static HRESULT WINAPI DOMMouseEvent_get_relatedTarget(IDOMMouseEvent *iface, IEventTarget **p) { DOMEvent *This = impl_from_IDOMMouseEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + nsIDOMEventTarget *related_target; + nsIDOMNode *target_node; + HTMLDOMNode *node; + HRESULT hres; + nsresult nsres; + + TRACE("(%p)->(%p)\n", This, p); + + nsres = nsIDOMMouseEvent_GetRelatedTarget(This->mouse_event, &related_target); + if(NS_FAILED(nsres)) + return E_FAIL; + + if(!related_target) { + *p = NULL; + return S_OK; + } + + nsres = nsIDOMEventTarget_QueryInterface(related_target, &IID_nsIDOMNode, (void**)&target_node); + nsIDOMEventTarget_Release(related_target); + if(NS_FAILED(nsres)) { + FIXME("Only node targets supported\n"); + return E_NOTIMPL; + } + + hres = get_node(target_node, TRUE, &node); + nsIDOMNode_Release(target_node); + if(FAILED(hres)) + return hres; + + *p = &node->event_target.IEventTarget_iface; + return S_OK; } static HRESULT WINAPI DOMMouseEvent_initMouseEvent(IDOMMouseEvent *iface, BSTR type, @@ -1470,6 +1501,7 @@ static HRESULT WINAPI DOMMouseEvent_initMouseEvent(IDOMMouseEvent *iface, BSTR t IEventTarget *related_target) { DOMEvent *This = impl_from_IDOMMouseEvent(iface); + nsIDOMEventTarget *nstarget = NULL; nsAString type_str; nsresult nsres; HRESULT hres; @@ -1486,21 +1518,28 @@ static HRESULT WINAPI DOMMouseEvent_initMouseEvent(IDOMMouseEvent *iface, BSTR t if(view) FIXME("view argument is not supported\n"); - hres = IDOMEvent_initEvent(&This->IDOMEvent_iface, type, can_bubble, cancelable); - if(FAILED(hres)) - return hres; - - nsAString_InitDepend(&type_str, type); - nsres = nsIDOMMouseEvent_InitMouseEvent(This->mouse_event, &type_str, can_bubble, cancelable, - NULL /* FIXME */, detail, screen_x, screen_y, - client_x, client_y, ctrl_key, alt_key, shift_key, - meta_key, button, NULL /* FIXME */); - nsAString_Finish(&type_str); - if(NS_FAILED(nsres)) { - FIXME("InitMouseEvent failed: %08x\n", nsres); - return E_FAIL; + if(related_target) { + hres = get_gecko_target(related_target, &nstarget); + if(FAILED(hres)) + return hres; } + hres = IDOMEvent_initEvent(&This->IDOMEvent_iface, type, can_bubble, cancelable); + if(SUCCEEDED(hres)) { + nsAString_InitDepend(&type_str, type); + nsres = nsIDOMMouseEvent_InitMouseEvent(This->mouse_event, &type_str, can_bubble, cancelable, + NULL /* FIXME */, detail, screen_x, screen_y, + client_x, client_y, ctrl_key, alt_key, shift_key, + meta_key, button, nstarget); + nsAString_Finish(&type_str); + if(NS_FAILED(nsres)) { + FIXME("InitMouseEvent failed: %08x\n", nsres); + return E_FAIL; + } + } + + if(nstarget) + nsIDOMEventTarget_Release(nstarget); return S_OK; } @@ -3120,6 +3159,29 @@ static const IEventTargetVtbl EventTargetVtbl = { EventTarget_dispatchEvent }; +static EventTarget *unsafe_impl_from_IEventTarget(IEventTarget *iface) +{ + return iface && iface->lpVtbl == &EventTargetVtbl ? impl_from_IEventTarget(iface) : NULL; +} + +static HRESULT get_gecko_target(IEventTarget *target, nsIDOMEventTarget **ret) +{ + EventTarget *event_target = unsafe_impl_from_IEventTarget(target); + const event_target_vtbl_t *vtbl; + nsresult nsres; + + if(!event_target) { + WARN("Not our IEventTarget implementation\n"); + return E_INVALIDARG; + } + + vtbl = (const event_target_vtbl_t*)dispex_get_vtbl(&event_target->dispex); + nsres = nsISupports_QueryInterface(vtbl->get_gecko_target(&event_target->dispex), + &IID_nsIDOMEventTarget, (void**)ret); + assert(nsres == NS_OK); + return S_OK; +} + HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv) { if(IsEqualGUID(riid, &IID_IEventTarget)) { diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 182a36e552d..39bcf01c280 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -114,6 +114,7 @@ void detach_nsevent(HTMLDocumentNode*,const WCHAR*) DECLSPEC_HIDDEN; /* We extend dispex vtbl for EventTarget functions to avoid separated vtbl. */ typedef struct { dispex_static_data_vtbl_t dispex_vtbl; + nsISupports *(*get_gecko_target)(DispatchEx*); void (*bind_event)(DispatchEx*,eventid_t); EventTarget *(*get_parent_event_target)(DispatchEx*); HRESULT (*handle_event_default)(DispatchEx*,eventid_t,nsIDOMEvent*,BOOL*); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 3a34f5cac04..2ef62cc6c91 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3024,6 +3024,12 @@ static compat_mode_t HTMLWindow_get_compat_mode(DispatchEx *dispex) return This->doc->document_mode; } +static nsISupports *HTMLWindow_get_gecko_target(DispatchEx *dispex) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + return (nsISupports*)This->base.outer_window->nswindow; +} + static void HTMLWindow_bind_event(DispatchEx *dispex, eventid_t eid) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -3050,6 +3056,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { HTMLWindow_get_compat_mode, NULL }, + HTMLWindow_get_gecko_target, HTMLWindow_bind_event, NULL, NULL, diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index f645e3781b7..a6567c9f473 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -629,6 +629,7 @@ function test_mouse_event() { ok(e.pageX === 0, "pageX = " + e.pageX); ok(e.pageY === 0, "pageY = " + e.pageY); ok(e.which === 1, "which = " + e.which); + ok(e.relatedTarget === null, "relatedTarget = " + e.relatedTarget); e.initMouseEvent("test", true, true, window, 1, 2, 3, 4, 5, false, false, false, false, 1, document); ok(e.type === "test", "type = " + e.type); @@ -648,8 +649,9 @@ function test_mouse_event() { ok(e.button === 1, "button = " + e.button); ok(e.buttons === 0, "buttons = " + e.buttons); ok(e.which === 2, "which = " + e.which); + ok(e.relatedTarget === document, "relatedTarget = " + e.relatedTarget); - e.initMouseEvent("test", false, false, window, 9, 8, 7, 6, 5, true, true, true, true, 127, document); + e.initMouseEvent("test", false, false, window, 9, 8, 7, 6, 5, true, true, true, true, 127, document.body); ok(e.type === "test", "type = " + e.type); ok(e.cancelable === false, "cancelable = " + e.cancelable); ok(e.bubbles === false, "bubbles = " + e.bubbles); @@ -664,6 +666,7 @@ function test_mouse_event() { ok(e.metaKey === true, "metaKey = " + e.metaKey); ok(e.button === 127, "button = " + e.button); ok(e.which === 128, "which = " + e.which); + ok(e.relatedTarget === document.body, "relatedTarget = " + e.relatedTarget); e.initEvent("testevent", true, true); ok(e.type === "testevent", "type = " + e.type); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 393a5699048..ebe2561e8b9 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -738,6 +738,12 @@ static inline HTMLXMLHttpRequest *impl_from_DispatchEx(DispatchEx *iface) return CONTAINING_RECORD(iface, HTMLXMLHttpRequest, event_target.dispex); } +static nsISupports *HTMLXMLHttpRequest_get_gecko_target(DispatchEx *dispex) +{ + HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex); + return (nsISupports*)This->nsxhr; +} + static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) { HTMLXMLHttpRequest *This = impl_from_DispatchEx(dispex); @@ -775,6 +781,7 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) static event_target_vtbl_t HTMLXMLHttpRequest_event_target_vtbl = { {NULL}, + HTMLXMLHttpRequest_get_gecko_target, HTMLXMLHttpRequest_bind_event };