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:
parent
5bc2e83c7a
commit
d84f6f72cc
|
@ -52,6 +52,7 @@ typedef struct {
|
||||||
DISPID id;
|
DISPID id;
|
||||||
BSTR name;
|
BSTR name;
|
||||||
tid_t tid;
|
tid_t tid;
|
||||||
|
dispex_hook_invoke_t hook;
|
||||||
SHORT call_vtbl_off;
|
SHORT call_vtbl_off;
|
||||||
SHORT put_vtbl_off;
|
SHORT put_vtbl_off;
|
||||||
SHORT get_vtbl_off;
|
SHORT get_vtbl_off;
|
||||||
|
@ -230,7 +231,8 @@ static BOOL is_arg_type_supported(VARTYPE vt)
|
||||||
return FALSE;
|
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;
|
func_info_t *info;
|
||||||
BSTR name;
|
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->tid = tid;
|
||||||
info->func_disp_idx = -1;
|
info->func_disp_idx = -1;
|
||||||
info->prop_vt = VT_EMPTY;
|
info->prop_vt = VT_EMPTY;
|
||||||
|
info->hook = hook;
|
||||||
}else {
|
}else {
|
||||||
SysFreeString(name);
|
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 */
|
unsigned i = 7; /* skip IDispatch functions */
|
||||||
const DISPID *blacklist_iter;
|
|
||||||
ITypeInfo *typeinfo;
|
ITypeInfo *typeinfo;
|
||||||
FUNCDESC *funcdesc;
|
FUNCDESC *funcdesc;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
@ -339,20 +341,25 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
const dispex_hook_t *hook = NULL;
|
||||||
|
|
||||||
hres = ITypeInfo_GetFuncDesc(typeinfo, i++, &funcdesc);
|
hres = ITypeInfo_GetFuncDesc(typeinfo, i++, &funcdesc);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(blacklist_dispids) {
|
if(hooks) {
|
||||||
for(blacklist_iter = blacklist_dispids; *blacklist_iter != DISPID_UNKNOWN; blacklist_iter++) {
|
for(hook = hooks; hook->dispid != DISPID_UNKNOWN; hook++) {
|
||||||
if(*blacklist_iter == funcdesc->memid)
|
if(hook->dispid == funcdesc->memid)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(hook->dispid == DISPID_UNKNOWN)
|
||||||
|
hook = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!blacklist_dispids || *blacklist_iter == DISPID_UNKNOWN) {
|
if(!hook || hook->invoke) {
|
||||||
TRACE("adding...\n");
|
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);
|
ITypeInfo_ReleaseFuncDesc(typeinfo, funcdesc);
|
||||||
|
@ -361,11 +368,11 @@ static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp
|
||||||
return S_OK;
|
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;
|
HRESULT hres;
|
||||||
|
|
||||||
hres = process_interface(info, tid, NULL, blacklist_dispids);
|
hres = process_interface(info, tid, NULL, hooks);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
ERR("process_interface failed: %08x\n", 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))
|
if(FAILED(hres))
|
||||||
return 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)
|
if(func->func_disp_idx != -1)
|
||||||
return function_invoke(This, func, flags, dp, res, ei, caller);
|
return function_invoke(This, func, flags, dp, res, ei, caller);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
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);
|
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)
|
if(mode >= COMPAT_MODE_IE8)
|
||||||
dispex_info_add_interface(info, IElementSelector_tid, NULL);
|
dispex_info_add_interface(info, IElementSelector_tid, NULL);
|
||||||
|
|
|
@ -2051,6 +2051,11 @@ static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
|
||||||
return CONTAINING_RECORD(iface, EventTarget, 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)
|
static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
|
||||||
{
|
{
|
||||||
EventTarget *This = impl_from_IEventTarget(iface);
|
EventTarget *This = impl_from_IEventTarget(iface);
|
||||||
|
@ -2162,6 +2167,27 @@ static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *
|
||||||
return E_NOTIMPL;
|
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 = {
|
static const IEventTargetVtbl EventTargetVtbl = {
|
||||||
EventTarget_QueryInterface,
|
EventTarget_QueryInterface,
|
||||||
EventTarget_AddRef,
|
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)
|
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)
|
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)
|
static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)
|
||||||
|
|
|
@ -283,6 +283,14 @@ typedef struct {
|
||||||
dispex_data_t *delayed_init_info;
|
dispex_data_t *delayed_init_info;
|
||||||
} dispex_static_data_t;
|
} 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 {
|
struct DispatchEx {
|
||||||
IDispatchEx IDispatchEx_iface;
|
IDispatchEx IDispatchEx_iface;
|
||||||
|
|
||||||
|
@ -331,7 +339,7 @@ void dispex_unlink(DispatchEx*) DECLSPEC_HIDDEN;
|
||||||
void release_typelib(void) DECLSPEC_HIDDEN;
|
void release_typelib(void) DECLSPEC_HIDDEN;
|
||||||
HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**) DECLSPEC_HIDDEN;
|
HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**) DECLSPEC_HIDDEN;
|
||||||
const void *dispex_get_vtbl(DispatchEx*) 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;
|
compat_mode_t dispex_compat_mode(DispatchEx*) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
static inline void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *desc)
|
static inline void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *desc)
|
||||||
|
|
|
@ -62,6 +62,7 @@ function test_listener_order() {
|
||||||
document.body.onclick = record_call("body.onclick");
|
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(capture)"), true);
|
||||||
document.body.addEventListener("click", record_call("body.click(bubble)"), false);
|
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)"));
|
document.body.attachEvent("onclick", record_call("body.click(attached)"));
|
||||||
|
|
||||||
div.attachEvent("onclick", record_call("div.click(attached)"));
|
div.attachEvent("onclick", record_call("div.click(attached)"));
|
||||||
|
@ -74,9 +75,9 @@ function test_listener_order() {
|
||||||
div.click();
|
div.click();
|
||||||
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
|
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
|
||||||
+ "div.click(attached),div.click(bubble),div.onclick,div.click(capture1),"
|
+ "div.click(attached),div.click(bubble),div.onclick,div.click(capture1),"
|
||||||
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(attached),"
|
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(bubble2),"
|
||||||
+ "document.click(attached),document.click(bubble),document.onclick,"
|
+ "body.click(attached),document.click(attached),document.click(bubble),"
|
||||||
+ "window.click(bubble),", "calls = " + calls);
|
+ "document.onclick,window.click(bubble),", "calls = " + calls);
|
||||||
|
|
||||||
div.onclick = record_call("new div.onclick");
|
div.onclick = record_call("new div.onclick");
|
||||||
|
|
||||||
|
@ -84,9 +85,9 @@ function test_listener_order() {
|
||||||
div.click();
|
div.click();
|
||||||
ok(calls === "window.click(capture),document.click(capture),body.click(capture),"
|
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(attached),div.click(bubble),new div.onclick,div.click(capture1),"
|
||||||
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(attached),"
|
+ "div.click(capture2),body.onclick,body.click(bubble),body.click(bubble2),"
|
||||||
+ "document.click(attached),document.click(bubble),document.onclick,"
|
+ "body.click(attached),document.click(attached),document.click(bubble),"
|
||||||
+ "window.click(bubble),", "calls = " + calls);
|
+ "document.onclick,window.click(bubble),", "calls = " + calls);
|
||||||
|
|
||||||
next_test();
|
next_test();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue