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
};