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