mshtml: Properly invoke event listeners in IE9+ mode.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2017-10-25 18:13:26 +02:00 committed by Alexandre Julliard
parent b96934bf4a
commit d1f1e93c46
3 changed files with 93 additions and 7 deletions

View File

@ -1292,6 +1292,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
const eventid_t eid = event->event_id;
const listener_container_t *container = get_listener_container(event_target, eid, FALSE);
const BOOL cancelable = event_info[eid].flags & EVENT_CANCELABLE;
const BOOL use_quirks = use_event_quirks(event_target);
event_listener_t *listener, listeners_buf[8], *listeners = listeners_buf;
unsigned listeners_cnt, listeners_size;
ConnectionPointContainer *cp_container = NULL;
@ -1299,9 +1300,10 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
VARIANT v;
HRESULT hres;
if(container && !list_empty(&container->listeners)) {
if(use_quirks && container && !list_empty(&container->listeners)
&& event->phase != DEP_CAPTURING_PHASE) {
listener = LIST_ENTRY(list_tail(&container->listeners), event_listener_t, entry);
if(listener->function && listener->type == LISTENER_TYPE_ONEVENT) {
if(listener && listener->function && listener->type == LISTENER_TYPE_ONEVENT) {
DISPID named_arg = DISPID_THIS;
VARIANTARG arg;
DISPPARAMS dp = {&arg, &named_arg, 1, 1};
@ -1337,6 +1339,16 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
LIST_FOR_EACH_ENTRY(listener, &container->listeners, event_listener_t, entry) {
if(!listener->function)
continue;
switch(listener->type) {
case LISTENER_TYPE_ONEVENT:
if(use_quirks || event->phase == DEP_CAPTURING_PHASE)
continue;
break;
case LISTENER_TYPE_ATTACHED:
if(event->phase == DEP_CAPTURING_PHASE)
continue;
break;
}
if(listeners_cnt == listeners_size) {
event_listener_t *new_listeners;
@ -1359,7 +1371,37 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
}
for(listener = listeners; listener < listeners + listeners_cnt; listener++) {
if(listener->type == LISTENER_TYPE_ATTACHED) {
if(listener->type != LISTENER_TYPE_ATTACHED) {
DISPID named_arg = DISPID_THIS;
VARIANTARG args[2];
DISPPARAMS dp = {args, &named_arg, 2, 1};
V_VT(args) = VT_DISPATCH;
V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
V_VT(args+1) = VT_DISPATCH;
V_DISPATCH(args+1) = event->in_fire_event
? (IDispatch*)event->event_obj : (IDispatch*)&event->IDOMEvent_iface;
V_VT(&v) = VT_EMPTY;
TRACE("%s >>>\n", debugstr_w(event_info[event->event_id].name));
hres = call_disp_func(listener->function, &dp, &v);
if(hres == S_OK) {
TRACE("%s <<< %s\n", debugstr_w(event_info[event->event_id].name),
debugstr_variant(&v));
if(cancelable) {
if(V_VT(&v) == VT_BOOL) {
if(!V_BOOL(&v))
IDOMEvent_preventDefault(&event->IDOMEvent_iface);
}else if(V_VT(&v) != VT_EMPTY) {
FIXME("unhandled result %s\n", debugstr_variant(&v));
}
}
VariantClear(&v);
}else {
WARN("%s <<< %08x\n", debugstr_w(event_info[event->event_id].name), hres);
}
}else {
VARIANTARG arg;
DISPPARAMS dp = {&arg, NULL, 1, 0};
@ -1588,7 +1630,9 @@ HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_va
if(SUCCEEDED(hres)) {
event_obj->event->event_obj = &event_obj->IHTMLEventObj_iface;
event_obj->event->in_fire_event++;
dispatch_event(&node->event_target, event_obj->event);
event_obj->event->in_fire_event--;
event_obj->event->event_obj = NULL;
}
@ -1826,7 +1870,10 @@ HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARI
listener->type = LISTENER_TYPE_ATTACHED;
IDispatch_AddRef(listener->function = disp);
list_add_head(&container->listeners, &listener->entry);
if(use_event_quirks(event_target))
list_add_head(&container->listeners, &listener->entry);
else
list_add_tail(&container->listeners, &listener->entry);
*res = VARIANT_TRUE;
return S_OK;

View File

@ -66,10 +66,11 @@ typedef struct {
EventTarget *target;
BOOL prevent_default;
BOOL stop_propagation;
USHORT phase;
DOM_EVENT_PHASE phase;
IHTMLEventObj *event_obj;
BOOL no_event_obj;
unsigned in_fire_event;
} DOMEvent;
void check_event_attr(HTMLDocumentNode*,nsIDOMHTMLElement*) DECLSPEC_HIDDEN;

View File

@ -93,6 +93,7 @@ static IHTMLWindow2 *window;
static IOleDocumentView *view;
static BOOL is_ie9plus;
static int document_mode;
static unsigned in_fire_event;
typedef struct {
LONG x;
@ -358,7 +359,9 @@ static void _elem_fire_event(unsigned line, IUnknown *unk, const char *event, VA
b = 100;
str = a2bstr(event);
in_fire_event++;
hres = IHTMLElement3_fireEvent(elem3, str, evobj, &b);
in_fire_event--;
SysFreeString(str);
ok_(__FILE__,line)(hres == S_OK, "fireEvent failed: %08x\n", hres);
ok_(__FILE__,line)(b == VARIANT_TRUE, "fireEvent returned %x\n", b);
@ -371,20 +374,51 @@ static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD
ok_(__FILE__,line) (id == DISPID_VALUE, "id = %d\n", id);
ok_(__FILE__,line) (wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags);
ok_(__FILE__,line) (pdp != NULL, "pdp == NULL\n");
todo_wine_if(document_mode >= 9)
ok_(__FILE__,line) (pdp->cArgs == (document_mode < 9 ? 1 : 2), "pdp->cArgs = %d\n", pdp->cArgs);
ok_(__FILE__,line) (pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs);
ok_(__FILE__,line) (pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n",
pdp->rgdispidNamedArgs[0]);
ok_(__FILE__,line) (V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg));
if(pdp->cArgs > 1)
ok_(__FILE__,line) (V_VT(pdp->rgvarg+1) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg));
ok_(__FILE__,line) (V_VT(pdp->rgvarg+1) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg+1));
ok_(__FILE__,line) (pvarRes != NULL, "pvarRes == NULL\n");
ok_(__FILE__,line) (pei != NULL, "pei == NULL");
ok_(__FILE__,line) (!pspCaller, "pspCaller != NULL\n");
if(dispiid)
_test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), dispiid);
if(pdp->cArgs > 1) {
IHTMLEventObj *window_event, *event_obj;
IDOMEvent *event;
HRESULT hres;
hres = IDispatch_QueryInterface(V_DISPATCH(pdp->rgvarg+1), &IID_IDOMEvent, (void**)&event);
if(in_fire_event)
ok(hres == E_NOINTERFACE, "QI(IID_IDOMEvent) returned %08x\n", hres);
else
ok(hres == S_OK, "Could not get IDOMEvent iface: %08x\n", hres);
hres = IDispatch_QueryInterface(V_DISPATCH(pdp->rgvarg+1), &IID_IHTMLEventObj, (void**)&event_obj);
if(in_fire_event)
ok(hres == S_OK, "Could not get IDOMEventObj iface: %08x\n", hres);
else
ok(hres == E_NOINTERFACE, "QI(IID_IHTMLEventObj) returned %08x\n", hres);
if(event)
IDOMEvent_Release(event);
if(event_obj)
IHTMLEventObj_Release(event_obj);
hres = IHTMLWindow2_get_event(window, &window_event);
ok(hres == S_OK, "get_event failed: %08x\n", hres);
if(window_event) {
todo_wine_if(in_fire_event)
ok(!iface_cmp((IUnknown*)V_DISPATCH(pdp->rgvarg+1), (IUnknown*)window_event),
"window_event != event arg\n");
IHTMLEventObj_Release(window_event);
}
}
}
#define test_attached_event_args(a,b,c,d,e) _test_attached_event_args(__LINE__,a,b,c,d,e)
@ -666,6 +700,7 @@ static void _test_event_srcfilter(unsigned line, IHTMLEventObj *event)
static void _test_event_obj(unsigned line, const char *type, const xy_test_t *xy)
{
IHTMLEventObj *event = _get_event_obj(line);
IDOMEvent *dom_event;
VARIANT v;
HRESULT hres;
@ -699,6 +734,9 @@ static void _test_event_obj(unsigned line, const char *type, const xy_test_t *xy
if(V_VT(&v) == VT_BOOL)
ok_(__FILE__,line)(V_BOOL(&v) == VARIANT_TRUE, "V_BOOL(returnValue) = %x\n", V_BOOL(&v));
hres = IHTMLEventObj_QueryInterface(event, &IID_IDOMEvent, (void**)&dom_event);
ok(hres == E_NOINTERFACE, "Could not get IDOMEvent iface: %08x\n", hres);
IHTMLEventObj_Release(event);
}