mshtml: Hook addEventListener InvokeEx calls to allow capture default value.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2017-11-24 15:09:13 +01:00 committed by Alexandre Julliard
parent 5bc2e83c7a
commit d84f6f72cc
5 changed files with 76 additions and 20 deletions

View File

@ -52,6 +52,7 @@ typedef struct {
DISPID id;
BSTR name;
tid_t tid;
dispex_hook_invoke_t hook;
SHORT call_vtbl_off;
SHORT put_vtbl_off;
SHORT get_vtbl_off;
@ -230,7 +231,8 @@ static BOOL is_arg_type_supported(VARTYPE vt)
return FALSE;
}
static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti)
static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti,
dispex_hook_invoke_t hook)
{
func_info_t *info;
BSTR name;
@ -262,6 +264,7 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc,
info->tid = tid;
info->func_disp_idx = -1;
info->prop_vt = VT_EMPTY;
info->hook = hook;
}else {
SysFreeString(name);
}
@ -326,10 +329,9 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc,
}
}
static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp_typeinfo, const DISPID *blacklist_dispids)
static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp_typeinfo, const dispex_hook_t *hooks)
{
unsigned i = 7; /* skip IDispatch functions */
const DISPID *blacklist_iter;
ITypeInfo *typeinfo;
FUNCDESC *funcdesc;
HRESULT hres;
@ -339,20 +341,25 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp
return hres;
while(1) {
const dispex_hook_t *hook = NULL;
hres = ITypeInfo_GetFuncDesc(typeinfo, i++, &funcdesc);
if(FAILED(hres))
break;
if(blacklist_dispids) {
for(blacklist_iter = blacklist_dispids; *blacklist_iter != DISPID_UNKNOWN; blacklist_iter++) {
if(*blacklist_iter == funcdesc->memid)
if(hooks) {
for(hook = hooks; hook->dispid != DISPID_UNKNOWN; hook++) {
if(hook->dispid == funcdesc->memid)
break;
}
if(hook->dispid == DISPID_UNKNOWN)
hook = NULL;
}
if(!blacklist_dispids || *blacklist_iter == DISPID_UNKNOWN) {
if(!hook || hook->invoke) {
TRACE("adding...\n");
add_func_info(data, tid, funcdesc, disp_typeinfo ? disp_typeinfo : typeinfo);
add_func_info(data, tid, funcdesc, disp_typeinfo ? disp_typeinfo : typeinfo,
hook ? hook->invoke : NULL);
}
ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc);
@ -361,11 +368,11 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp
return S_OK;
}
void dispex_info_add_interface(dispex_data_t *info, tid_t tid, const DISPID *blacklist_dispids)
void dispex_info_add_interface(dispex_data_t *info, tid_t tid, const dispex_hook_t *hooks)
{
HRESULT hres;
hres = process_interface(info, tid, NULL, blacklist_dispids);
hres = process_interface(info, tid, NULL, hooks);
if(FAILED(hres))
ERR("process_interface failed: %08x\n", hres);
}
@ -1239,6 +1246,12 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD
if(FAILED(hres))
return hres;
if(func->hook) {
hres = func->hook(This, lcid, flags, dp, res, ei, caller);
if(hres != S_FALSE)
return hres;
}
if(func->func_disp_idx != -1)
return function_invoke(This, func, flags, dp, res, ei, caller);

View File

@ -5398,11 +5398,14 @@ static IHTMLEventObj *HTMLElement_set_current_event(DispatchEx *dispex, IHTMLEve
void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode)
{
static const DISPID elem2_ie11_blacklist[] = {DISPID_IHTMLELEMENT2_DOSCROLL, DISPID_UNKNOWN};
static const dispex_hook_t elem2_ie11_hooks[] = {
{DISPID_IHTMLELEMENT2_DOSCROLL, NULL},
{DISPID_UNKNOWN}
};
HTMLDOMNode_init_dispex_info(info, mode);
dispex_info_add_interface(info, IHTMLElement2_tid, mode >= COMPAT_MODE_IE11 ? elem2_ie11_blacklist : NULL);
dispex_info_add_interface(info, IHTMLElement2_tid, mode >= COMPAT_MODE_IE11 ? elem2_ie11_hooks : NULL);
if(mode >= COMPAT_MODE_IE8)
dispex_info_add_interface(info, IElementSelector_tid, NULL);

View File

@ -2051,6 +2051,11 @@ static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
return CONTAINING_RECORD(iface, EventTarget, IEventTarget_iface);
}
static inline EventTarget *impl_from_DispatchEx(DispatchEx *iface)
{
return CONTAINING_RECORD(iface, EventTarget, dispex);
}
static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
{
EventTarget *This = impl_from_IEventTarget(iface);
@ -2162,6 +2167,27 @@ static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *
return E_NOTIMPL;
}
HRESULT IEventTarget_addEventListener_hook(DispatchEx *dispex, LCID lcid, WORD flags,
DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
{
/* If only two arguments were given, implicitly set capture to false */
if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) {
VARIANT args[3];
DISPPARAMS new_dp = {args, NULL, 3, 0};
V_VT(args) = VT_BOOL;
V_BOOL(args) = VARIANT_FALSE;
args[1] = dp->rgvarg[0];
args[2] = dp->rgvarg[1];
TRACE("implicit capture\n");
return IDispatchEx_InvokeEx(&dispex->IDispatchEx_iface, DISPID_IEVENTTARGET_ADDEVENTLISTENER,
lcid, flags, &new_dp, res, ei, caller);
}
return S_FALSE; /* fallback to default */
}
static const IEventTargetVtbl EventTargetVtbl = {
EventTarget_QueryInterface,
EventTarget_AddRef,
@ -2210,8 +2236,13 @@ HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
void EventTarget_init_dispex_info(dispex_data_t *dispex_info, compat_mode_t compat_mode)
{
static const dispex_hook_t IEventTarget_hooks[] = {
{DISPID_IEVENTTARGET_ADDEVENTLISTENER, IEventTarget_addEventListener_hook},
{DISPID_UNKNOWN}
};
if(compat_mode >= COMPAT_MODE_IE9)
dispex_info_add_interface(dispex_info, IEventTarget_tid, NULL);
dispex_info_add_interface(dispex_info, IEventTarget_tid, IEventTarget_hooks);
}
static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)

View File

@ -283,6 +283,14 @@ typedef struct {
dispex_data_t *delayed_init_info;
} dispex_static_data_t;
typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,
EXCEPINFO*,IServiceProvider*);
typedef struct {
DISPID dispid;
dispex_hook_invoke_t invoke;
} dispex_hook_t;
struct DispatchEx {
IDispatchEx IDispatchEx_iface;
@ -331,7 +339,7 @@ void dispex_unlink(DispatchEx*) DECLSPEC_HIDDEN;
void release_typelib(void) DECLSPEC_HIDDEN;
HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**) DECLSPEC_HIDDEN;
const void *dispex_get_vtbl(DispatchEx*) DECLSPEC_HIDDEN;
void dispex_info_add_interface(dispex_data_t*,tid_t,const DISPID*) DECLSPEC_HIDDEN;
void dispex_info_add_interface(dispex_data_t*,tid_t,const dispex_hook_t*) DECLSPEC_HIDDEN;
compat_mode_t dispex_compat_mode(DispatchEx*) DECLSPEC_HIDDEN;
static inline void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *desc)

View File

@ -62,6 +62,7 @@ function test_listener_order() {
document.body.onclick = record_call("body.onclick");
document.body.addEventListener("click", record_call("body.click(capture)"), true);
document.body.addEventListener("click", record_call("body.click(bubble)"), false);
document.body.addEventListener("click", record_call("body.click(bubble2)"));
document.body.attachEvent("onclick", record_call("body.click(attached)"));
div.attachEvent("onclick", record_call("div.click(attached)"));
@ -74,9 +75,9 @@ function test_listener_order() {
div.click();
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
+ "div.click(attached),div.click(bubble),div.onclick,div.click(capture1),"
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(attached),"
+ "document.click(attached),document.click(bubble),document.onclick,"
+ "window.click(bubble),", "calls = " + calls);
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(bubble2),"
+ "body.click(attached),document.click(attached),document.click(bubble),"
+ "document.onclick,window.click(bubble),", "calls = " + calls);
div.onclick = record_call("new div.onclick");
@ -84,9 +85,9 @@ function test_listener_order() {
div.click();
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
+ "div.click(attached),div.click(bubble),new div.onclick,div.click(capture1),"
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(attached),"
+ "document.click(attached),document.click(bubble),document.onclick,"
+ "window.click(bubble),", "calls = " + calls);
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(bubble2),"
+ "body.click(attached),document.click(attached),document.click(bubble),"
+ "document.onclick,window.click(bubble),", "calls = " + calls);
next_test();
}