Jacek Caban : mshtml: Store all attached listeners before calling them in call_event_handlers.

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


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

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

mshtml: Store all attached listeners before calling them in call_event_handlers.

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

---

 dlls/mshtml/htmlevent.c | 99 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 70 insertions(+), 29 deletions(-)

diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index d64238f..19a76e0 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -35,6 +35,16 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
 
+typedef enum {
+    LISTENER_TYPE_ONEVENT,
+    LISTENER_TYPE_ATTACHED
+} listener_type_t;
+
+typedef struct {
+    listener_type_t type;
+    IDispatch *function;
+} event_listener_t;
+
 typedef struct {
     struct wine_rb_entry entry;
     eventid_t event_id;
@@ -1258,14 +1268,16 @@ static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
 static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
 {
     const eventid_t eid = event->event_id;
-    handler_vector_t *handler_vector = get_handler_vector(event_target, eid, FALSE);
+    handler_vector_t *container = get_handler_vector(event_target, eid, FALSE);
     const BOOL cancelable = event_info[eid].flags & EVENT_CANCELABLE;
+    event_listener_t *listener, listeners_buf[8], *listeners = listeners_buf;
+    unsigned listeners_cnt, listeners_size;
     ConnectionPointContainer *cp_container = NULL;
     const event_target_vtbl_t *vtbl;
     VARIANT v;
     HRESULT hres;
 
-    if(handler_vector && handler_vector->handler_prop) {
+    if(container && container->handler_prop) {
         DISPID named_arg = DISPID_THIS;
         VARIANTARG arg;
         DISPPARAMS dp = {&arg, &named_arg, 1, 1};
@@ -1278,7 +1290,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
         V_VT(&v) = VT_EMPTY;
 
         TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
-        hres = call_disp_func(handler_vector->handler_prop, &dp, &v);
+        hres = call_disp_func(container->handler_prop, &dp, &v);
         if(hres == S_OK) {
             TRACE("%s <<< %s\n", debugstr_w(event_info[eid].name), debugstr_variant(&v));
 
@@ -1296,40 +1308,69 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
         }
     }
 
-    if(handler_vector && handler_vector->handler_cnt) {
-        VARIANTARG arg;
-        DISPPARAMS dp = {&arg, NULL, 1, 0};
-        int i;
-
-        V_VT(&arg) = VT_DISPATCH;
-        V_DISPATCH(&arg) = (IDispatch*)event->event_obj;
+    listeners_cnt = 0;
+    listeners_size = sizeof(listeners_buf)/sizeof(*listeners_buf);
 
-        i = handler_vector->handler_cnt;
+    if(container) {
+        unsigned i = container->handler_cnt;
         while(i--) {
-            if(handler_vector->handlers[i]) {
-                V_VT(&v) = VT_EMPTY;
-
-                TRACE("%s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
-                hres = call_disp_func(handler_vector->handlers[i], &dp, &v);
-                if(hres == S_OK) {
-                    TRACE("%s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
-
-                    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);
+            if(!container->handlers[i])
+                continue;
+
+            if(listeners_cnt == listeners_size) {
+                event_listener_t *new_listeners;
+                if(listeners == listeners_buf) {
+                    new_listeners = heap_alloc(listeners_size * 2 * sizeof(*new_listeners));
+                    if(!new_listeners)
+                        break;
+                    memcpy(new_listeners, listeners, listeners_cnt * sizeof(*listeners));
                 }else {
-                    WARN("%s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
+                    new_listeners = heap_realloc(listeners, listeners_size * 2 * sizeof(*new_listeners));
                 }
+                listeners = new_listeners;
+                listeners_size *= 2;
             }
+
+            listeners[listeners_cnt].type = LISTENER_TYPE_ATTACHED;
+            IDispatch_AddRef(listeners[listeners_cnt].function = container->handlers[i]);
+            listeners_cnt++;
         }
     }
 
+    for(listener = listeners; listener < listeners + listeners_cnt; listener++) {
+        if(listener->type == LISTENER_TYPE_ATTACHED) {
+            VARIANTARG arg;
+            DISPPARAMS dp = {&arg, NULL, 1, 0};
+
+            V_VT(&arg) = VT_DISPATCH;
+            V_DISPATCH(&arg) = (IDispatch*)event->event_obj;
+            V_VT(&v) = VT_EMPTY;
+
+            TRACE("%s attached >>>\n", debugstr_w(event_info[eid].name));
+            hres = call_disp_func(listener->function, &dp, &v);
+            if(hres == S_OK) {
+                TRACE("%s attached <<<\n", debugstr_w(event_info[eid].name));
+
+                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 attached <<< %08x\n", debugstr_w(event_info[eid].name), hres);
+            }
+        }
+    }
+
+    if(listeners != listeners_buf)
+        heap_free(listeners);
+    if(event->phase == DEP_CAPTURING_PHASE)
+        return;
+
     if((vtbl = dispex_get_vtbl(&event_target->dispex)) && vtbl->get_cp_container)
         cp_container = vtbl->get_cp_container(&event_target->dispex);
     if(cp_container) {




More information about the wine-cvs mailing list