diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 8ca94eb4e6c..88282c028a8 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -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; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 97d34af70a2..eaf42eb8596 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -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; diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index ac7ae43a27b..91ec4b6dea7 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -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); }