Commit 32ce98e9 authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

mshtml: Expose an EventTarget interface on the outer window for events' target dispatch.

parent 04a74bdb
......@@ -318,6 +318,21 @@ static void remove_event_listener(EventTarget *event_target, const WCHAR *type_n
}
}
static IEventTarget *get_event_target_iface(EventTarget *event_target)
{
const event_target_vtbl_t *vtbl = dispex_get_vtbl(&event_target->dispex);
IEventTarget *ret;
if(vtbl->get_dispatch_this) {
IDispatch *disp = vtbl->get_dispatch_this(&event_target->dispex);
IDispatch_QueryInterface(disp, &IID_IEventTarget, (void**)&ret);
}else {
ret = &event_target->IEventTarget_iface;
IEventTarget_AddRef(ret);
}
return ret;
}
static HRESULT get_gecko_target(IEventTarget*,nsIDOMEventTarget**);
typedef struct {
......@@ -1049,7 +1064,7 @@ static HRESULT WINAPI DOMEvent_get_currentTarget(IDOMEvent *iface, IEventTarget
TRACE("(%p)->(%p)\n", This, p);
if(This->current_target)
IEventTarget_AddRef(*p = &This->current_target->IEventTarget_iface);
*p = get_event_target_iface(This->current_target);
else
*p = NULL;
return S_OK;
......@@ -1082,7 +1097,7 @@ static HRESULT WINAPI DOMEvent_get_target(IDOMEvent *iface, IEventTarget **p)
TRACE("(%p)->(%p)\n", This, p);
if(This->target)
IEventTarget_AddRef(*p = &This->target->IEventTarget_iface);
*p = get_event_target_iface(This->target);
else
*p = NULL;
return S_OK;
......@@ -3573,10 +3588,10 @@ static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
static void call_event_handlers(EventTarget *event_target, DOMEvent *event, dispatch_mode_t dispatch_mode)
{
const listener_container_t *container = get_listener_container(event_target, event->type, FALSE);
const event_target_vtbl_t *vtbl = dispex_get_vtbl(&event_target->dispex);
event_listener_t *listener, listeners_buf[8], *listeners = listeners_buf;
unsigned listeners_cnt, listeners_size;
ConnectionPointContainer *cp_container = NULL;
const event_target_vtbl_t *vtbl = NULL;
BOOL skip_onevent_listener = FALSE;
VARIANT v;
HRESULT hres;
......@@ -3597,9 +3612,14 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
V_VT(&arg) = VT_DISPATCH;
V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
V_VT(&v) = VT_EMPTY;
if(vtbl->get_dispatch_this)
V_DISPATCH(&arg) = vtbl->get_dispatch_this(&event_target->dispex);
IDispatch_AddRef(V_DISPATCH(&arg));
TRACE("%p %s >>>\n", event_target, debugstr_w(event->type));
hres = call_disp_func(listener->function, &dp, &v);
IDispatch_Release(V_DISPATCH(&arg));
if(hres == S_OK) {
TRACE("%p %s <<< %s\n", event_target, debugstr_w(event->type), debugstr_variant(&v));
......@@ -3673,6 +3693,10 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
V_VT(args) = VT_DISPATCH;
V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
if(vtbl->get_dispatch_this)
V_DISPATCH(args) = vtbl->get_dispatch_this(&event_target->dispex);
IDispatch_AddRef(V_DISPATCH(args));
V_VT(args+1) = VT_DISPATCH;
V_DISPATCH(args+1) = dispatch_mode == DISPATCH_LEGACY
? (IDispatch*)event->event_obj : (IDispatch*)&event->IDOMEvent_iface;
......@@ -3680,6 +3704,8 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
TRACE("%p %s >>>\n", event_target, debugstr_w(event->type));
hres = call_disp_func(listener->function, &dp, &v);
IDispatch_Release(V_DISPATCH(args));
if(hres == S_OK) {
TRACE("%p %s <<< %s\n", event_target, debugstr_w(event->type),
debugstr_variant(&v));
......@@ -3729,8 +3755,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
if(listeners != listeners_buf)
free(listeners);
if(event->phase != DEP_CAPTURING_PHASE && event_info[event->event_id].dispid
&& (vtbl = dispex_get_vtbl(&event_target->dispex))->get_cp_container)
if(event->phase != DEP_CAPTURING_PHASE && event_info[event->event_id].dispid && vtbl->get_cp_container)
cp_container = vtbl->get_cp_container(&event_target->dispex);
if(cp_container) {
if(cp_container->cps) {
......
......@@ -128,6 +128,7 @@ void detach_nsevent(HTMLDocumentNode*,const WCHAR*);
/* We extend dispex vtbl for EventTarget functions to avoid separated vtbl. */
typedef struct {
dispex_static_data_vtbl_t dispex_vtbl;
IDispatch *(*get_dispatch_this)(DispatchEx*);
nsISupports *(*get_gecko_target)(DispatchEx*);
void (*bind_event)(DispatchEx*,eventid_t);
EventTarget *(*get_parent_event_target)(DispatchEx*);
......
......@@ -260,9 +260,19 @@ static HRESULT WINAPI outer_window_QueryInterface(IHTMLWindow2 *iface, REFIID ri
}else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
*ppv = &This->base.IHTMLWindow2_iface;
return S_OK;
}else {
return EventTarget_QI(&This->base.inner_window->event_target, riid, ppv);
}else if(IsEqualGUID(&IID_IEventTarget, riid)) {
if(!This->base.inner_window->doc || This->base.inner_window->doc->document_mode < COMPAT_MODE_IE9) {
*ppv = NULL;
return E_NOINTERFACE;
}
*ppv = &This->IEventTarget_iface;
IHTMLWindow2_AddRef(&This->base.IHTMLWindow2_iface);
return S_OK;
}
WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI outer_window_AddRef(IHTMLWindow2 *iface)
......@@ -3771,6 +3781,100 @@ static const IDispatchExVtbl WindowDispExVtbl = {
WindowDispEx_GetNameSpaceParent
};
static inline HTMLOuterWindow *impl_from_IEventTarget(IEventTarget *iface)
{
return CONTAINING_RECORD(iface, HTMLOuterWindow, IEventTarget_iface);
}
static HRESULT WINAPI WindowEventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IHTMLWindow2_QueryInterface(&This->base.IHTMLWindow2_iface, riid, ppv);
}
static ULONG WINAPI WindowEventTarget_AddRef(IEventTarget *iface)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IHTMLWindow2_AddRef(&This->base.IHTMLWindow2_iface);
}
static ULONG WINAPI WindowEventTarget_Release(IEventTarget *iface)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IHTMLWindow2_Release(&This->base.IHTMLWindow2_iface);
}
static HRESULT WINAPI WindowEventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IDispatchEx_GetTypeInfoCount(&This->base.IDispatchEx_iface, pctinfo);
}
static HRESULT WINAPI WindowEventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IDispatchEx_GetTypeInfo(&This->base.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
}
static HRESULT WINAPI WindowEventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IDispatchEx_GetIDsOfNames(&This->base.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId);
}
static HRESULT WINAPI WindowEventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IDispatchEx_Invoke(&This->base.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams,
pVarResult, pExcepInfo, puArgErr);
}
static HRESULT WINAPI WindowEventTarget_addEventListener(IEventTarget *iface, BSTR type, IDispatch *listener,
VARIANT_BOOL capture)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IEventTarget_addEventListener(&This->base.inner_window->event_target.IEventTarget_iface, type, listener, capture);
}
static HRESULT WINAPI WindowEventTarget_removeEventListener(IEventTarget *iface, BSTR type, IDispatch *listener,
VARIANT_BOOL capture)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IEventTarget_removeEventListener(&This->base.inner_window->event_target.IEventTarget_iface, type, listener, capture);
}
static HRESULT WINAPI WindowEventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event_iface, VARIANT_BOOL *result)
{
HTMLOuterWindow *This = impl_from_IEventTarget(iface);
return IEventTarget_dispatchEvent(&This->base.inner_window->event_target.IEventTarget_iface, event_iface, result);
}
static const IEventTargetVtbl EventTargetVtbl = {
WindowEventTarget_QueryInterface,
WindowEventTarget_AddRef,
WindowEventTarget_Release,
WindowEventTarget_GetTypeInfoCount,
WindowEventTarget_GetTypeInfo,
WindowEventTarget_GetIDsOfNames,
WindowEventTarget_Invoke,
WindowEventTarget_addEventListener,
WindowEventTarget_removeEventListener,
WindowEventTarget_dispatchEvent
};
static inline HTMLWindow *impl_from_IServiceProvider(IServiceProvider *iface)
{
return CONTAINING_RECORD(iface, HTMLWindow, IServiceProvider_iface);
......@@ -4075,6 +4179,12 @@ static compat_mode_t HTMLWindow_get_compat_mode(DispatchEx *dispex)
return lock_document_mode(This->doc);
}
static IDispatch *HTMLWindow_get_dispatch_this(DispatchEx *dispex)
{
HTMLInnerWindow *This = impl_from_DispatchEx(dispex);
return (IDispatch*)&This->base.outer_window->base.IHTMLWindow2_iface;
}
static nsISupports *HTMLWindow_get_gecko_target(DispatchEx *dispex)
{
HTMLInnerWindow *This = impl_from_DispatchEx(dispex);
......@@ -4193,6 +4303,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = {
.next_dispid = HTMLWindow_next_dispid,
.get_compat_mode = HTMLWindow_get_compat_mode,
},
.get_dispatch_this = HTMLWindow_get_dispatch_this,
.get_gecko_target = HTMLWindow_get_gecko_target,
.bind_event = HTMLWindow_bind_event,
.set_current_event = HTMLWindow_set_current_event
......@@ -4351,6 +4462,7 @@ HRESULT create_outer_window(GeckoBrowser *browser, mozIDOMWindowProxy *mozwindow
if(!window)
return E_OUTOFMEMORY;
window->base.IHTMLWindow2_iface.lpVtbl = &outer_window_HTMLWindow2Vtbl;
window->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
window->base.outer_window = window;
window->base.inner_window = NULL;
......
......@@ -551,6 +551,7 @@ struct HTMLWindow {
struct HTMLOuterWindow {
HTMLWindow base;
IEventTarget IEventTarget_iface;
nsCycleCollectingAutoRefCnt ccref;
LONG task_magic;
......
......@@ -1469,8 +1469,26 @@ EVENT_HANDLER_FUNC_OBJ(onvisibilitychange);
static HRESULT WINAPI onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
IEventTarget *event_target;
IHTMLWindow2 *window2;
IDOMEvent *event;
HRESULT hres;
CHECK_EXPECT(onbeforeunload);
test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller);
hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDOMEvent, (void**)&event);
ok(hres == S_OK, "Could not get IDOMEvent iface: %08lx\n", hres);
hres = IDOMEvent_get_target(event, &event_target);
ok(hres == S_OK, "get_target failed: %08lx\n", hres);
IDOMEvent_Release(event);
hres = IEventTarget_QueryInterface(event_target, &IID_IHTMLWindow2, (void**)&window2);
ok(hres == S_OK, "Could not get IHTMLWindow2 iface: %08lx\n", hres);
ok(window2 == window, "event_target's window iface != window\n");
IHTMLWindow2_Release(window2);
IEventTarget_Release(event_target);
return S_OK;
}
......
......@@ -197,6 +197,21 @@ static BOOL skip_loadobject_tests;
static IActiveScriptSite *site, *site2;
static SCRIPTSTATE state, state2;
static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2)
{
IUnknown *unk1, *unk2;
if(iface1 == iface2)
return TRUE;
IUnknown_QueryInterface(iface1, &IID_IHTMLWindow2, (void**)&unk1);
IUnknown_Release(unk1);
IUnknown_QueryInterface(iface2, &IID_IHTMLWindow2, (void**)&unk2);
IUnknown_Release(unk2);
return unk1 == unk2;
}
static BOOL init_key(const WCHAR *key_name, const WCHAR *def_value, BOOL init)
{
HKEY hkey;
......@@ -4483,6 +4498,9 @@ static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHA
hres = IHTMLDocument2_get_parentWindow(doc, &window);
ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres);
todo_wine
ok(iface_cmp((IUnknown *)window, (IUnknown *)window_dispex), "window != dispex_window\n");
code = SysAllocString(codew);
lang = SysAllocString(langw);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment