Jacek Caban : mshtml: Properly invoke event listeners in IE9+ mode.

Alexandre Julliard julliard at winehq.org
Wed Oct 25 13:58:43 CDT 2017


Module: wine
Branch: master
Commit: d1f1e93c4659032cd6e24d44a746bf35046d1bbd
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=d1f1e93c4659032cd6e24d44a746bf35046d1bbd

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Oct 25 18:13:26 2017 +0200

mshtml: Properly invoke event listeners in IE9+ mode.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/mshtml/htmlevent.c    | 55 ++++++++++++++++++++++++++++++++++++++++++----
 dlls/mshtml/htmlevent.h    |  3 ++-
 dlls/mshtml/tests/events.c | 42 +++++++++++++++++++++++++++++++++--
 3 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 8ca94eb..88282c0 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 97d34af..eaf42eb 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 ac7ae43..91ec4b6 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);
 }
 




More information about the wine-cvs mailing list