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);
}