[PATCH 2/9] mshtml: Store all event listeners in a list.
Jacek Caban <[email protected]>
| Newsgroups | gmane.comp.emulators.wine.patches |
|---|---|
| Message-ID | <[email protected]> |
Signed-off-by: Jacek Caban <[email protected]> --- dlls/mshtml/htmlevent.c | 270 ++++++++++++++++++++++++++---------------------- 1 file changed, 147 insertions(+), 123 deletions(-)
0002-mshtml-Store-all-event-listeners-on-a-list.diff
(text/x-patch, 15.9 KB)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 19a76e07ae..8ca94eb4e6 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -41,6 +41,7 @@ typedef enum {
} listener_type_t;
typedef struct {
+ struct list entry;
listener_type_t type;
IDispatch *function;
} event_listener_t;
@@ -48,10 +49,8 @@ typedef struct {
typedef struct {
struct wine_rb_entry entry;
eventid_t event_id;
- IDispatch *handler_prop;
- DWORD handler_cnt;
- IDispatch **handlers;
-} handler_vector_t;
+ struct list listeners;
+} listener_container_t;
static const WCHAR abortW[] = {'a','b','o','r','t',0};
static const WCHAR beforeactivateW[] = {'b','e','f','o','r','e','a','c','t','i','v','a','t','e',0};
@@ -233,6 +232,56 @@ static eventid_t attr_to_eid(const WCHAR *str)
return EVENTID_LAST;
}
+static listener_container_t *get_listener_container(EventTarget *event_target, eventid_t eid, BOOL alloc)
+{
+ const event_target_vtbl_t *vtbl;
+ listener_container_t *container;
+ struct wine_rb_entry *entry;
+
+ entry = wine_rb_get(&event_target->handler_map, (const void*)eid);
+ if(entry)
+ return WINE_RB_ENTRY_VALUE(entry, listener_container_t, entry);
+ if(!alloc)
+ return NULL;
+
+ if(event_info[eid].flags & EVENT_FIXME)
+ FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
+
+ container = heap_alloc(sizeof(*container));
+ if(!container)
+ return NULL;
+
+ container->event_id = eid;
+ list_init(&container->listeners);
+ vtbl = dispex_get_vtbl(&event_target->dispex);
+ if(vtbl->bind_event)
+ vtbl->bind_event(&event_target->dispex, eid);
+ else
+ FIXME("Unsupported event binding on target %p\n", event_target);
+
+ wine_rb_put(&event_target->handler_map, (const void*)eid, &container->entry);
+ return container;
+}
+
+static void remove_event_listener(EventTarget *event_target, eventid_t eid, listener_type_t type, IDispatch *function)
+{
+ listener_container_t *container;
+ event_listener_t *listener;
+
+ container = get_listener_container(event_target, eid, FALSE);
+ if(!container)
+ return;
+
+ LIST_FOR_EACH_ENTRY(listener, &container->listeners, event_listener_t, entry) {
+ if(listener->function == function && listener->type == type) {
+ IDispatch_Release(listener->function);
+ list_remove(&listener->entry);
+ heap_free(listener);
+ break;
+ }
+ }
+}
+
typedef struct {
DispatchEx dispex;
IHTMLEventObj IHTMLEventObj_iface;
@@ -1169,33 +1218,6 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven
return S_OK;
}
-static handler_vector_t *get_handler_vector(EventTarget *event_target, eventid_t eid, BOOL alloc)
-{
- const event_target_vtbl_t *vtbl;
- handler_vector_t *handler_vector;
- struct wine_rb_entry *entry;
-
- entry = wine_rb_get(&event_target->handler_map, (const void*)eid);
- if(entry)
- return WINE_RB_ENTRY_VALUE(entry, handler_vector_t, entry);
- if(!alloc)
- return NULL;
-
- handler_vector = heap_alloc_zero(sizeof(*handler_vector));
- if(!handler_vector)
- return NULL;
-
- handler_vector->event_id = eid;
- vtbl = dispex_get_vtbl(&event_target->dispex);
- if(vtbl->bind_event)
- vtbl->bind_event(&event_target->dispex, eid);
- else
- FIXME("Unsupported event binding on target %p\n", event_target);
-
- wine_rb_put(&event_target->handler_map, (const void*)eid, &handler_vector->entry);
- return handler_vector;
-}
-
static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
{
IDispatchEx *dispex;
@@ -1268,7 +1290,7 @@ 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 *container = get_handler_vector(event_target, eid, FALSE);
+ const listener_container_t *container = get_listener_container(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;
@@ -1277,34 +1299,34 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
VARIANT v;
HRESULT hres;
- if(container && container->handler_prop) {
- DISPID named_arg = DISPID_THIS;
- VARIANTARG arg;
- DISPPARAMS dp = {&arg, &named_arg, 1, 1};
+ if(container && !list_empty(&container->listeners)) {
+ listener = LIST_ENTRY(list_tail(&container->listeners), event_listener_t, entry);
+ if(listener->function && listener->type == LISTENER_TYPE_ONEVENT) {
+ DISPID named_arg = DISPID_THIS;
+ VARIANTARG arg;
+ DISPPARAMS dp = {&arg, &named_arg, 1, 1};
- if(!use_event_quirks(event_target))
- FIXME("Event argument not supported\n");
-
- V_VT(&arg) = VT_DISPATCH;
- V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
- V_VT(&v) = VT_EMPTY;
-
- TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
- 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));
-
- 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));
+ V_VT(&arg) = VT_DISPATCH;
+ V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
+ V_VT(&v) = VT_EMPTY;
+
+ TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
+ hres = call_disp_func(listener->function, &dp, &v);
+ if(hres == S_OK) {
+ TRACE("%s <<< %s\n", debugstr_w(event_info[eid].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[eid].name), hres);
}
- VariantClear(&v);
- }else {
- WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
}
}
@@ -1312,9 +1334,8 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
listeners_size = sizeof(listeners_buf)/sizeof(*listeners_buf);
if(container) {
- unsigned i = container->handler_cnt;
- while(i--) {
- if(!container->handlers[i])
+ LIST_FOR_EACH_ENTRY(listener, &container->listeners, event_listener_t, entry) {
+ if(!listener->function)
continue;
if(listeners_cnt == listeners_size) {
@@ -1331,8 +1352,8 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
listeners_size *= 2;
}
- listeners[listeners_cnt].type = LISTENER_TYPE_ATTACHED;
- IDispatch_AddRef(listeners[listeners_cnt].function = container->handlers[i]);
+ listeners[listeners_cnt].type = listener->type;
+ IDispatch_AddRef(listeners[listeners_cnt].function = listener->function);
listeners_cnt++;
}
}
@@ -1642,9 +1663,36 @@ static HRESULT get_event_dispex_ref(EventTarget *event_target, eventid_t eid, BO
return dispex_get_dprop_ref(&event_target->dispex, buf, alloc, ret);
}
+static event_listener_t *get_onevent_listener(EventTarget *event_target, eventid_t eid, BOOL alloc)
+{
+ listener_container_t *container;
+ event_listener_t *listener;
+
+ container = get_listener_container(event_target, eid, alloc);
+ if(!container)
+ return NULL;
+
+ LIST_FOR_EACH_ENTRY_REV(listener, &container->listeners, event_listener_t, entry) {
+ if(listener->type == LISTENER_TYPE_ONEVENT)
+ return listener;
+ }
+
+ if(!alloc)
+ return NULL;
+
+ listener = heap_alloc(sizeof(*listener));
+ if(!listener)
+ return NULL;
+
+ listener->type = LISTENER_TYPE_ONEVENT;
+ listener->function = NULL;
+ list_add_tail(&container->listeners, &listener->entry);
+ return listener;
+}
+
static void remove_event_handler(EventTarget *event_target, eventid_t eid)
{
- handler_vector_t *handler_vector;
+ event_listener_t *listener;
VARIANT *store;
HRESULT hres;
@@ -1652,16 +1700,16 @@ static void remove_event_handler(EventTarget *event_target, eventid_t eid)
if(SUCCEEDED(hres))
VariantClear(store);
- handler_vector = get_handler_vector(event_target, eid, FALSE);
- if(handler_vector && handler_vector->handler_prop) {
- IDispatch_Release(handler_vector->handler_prop);
- handler_vector->handler_prop = NULL;
+ listener = get_onevent_listener(event_target, eid, FALSE);
+ if(listener && listener->function) {
+ IDispatch_Release(listener->function);
+ listener->function = NULL;
}
}
static HRESULT set_event_handler_disp(EventTarget *event_target, eventid_t eid, IDispatch *disp)
{
- handler_vector_t *handler_vector;
+ event_listener_t *listener;
if(event_info[eid].flags & EVENT_FIXME)
FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
@@ -1670,15 +1718,14 @@ static HRESULT set_event_handler_disp(EventTarget *event_target, eventid_t eid,
if(!disp)
return S_OK;
- handler_vector = get_handler_vector(event_target, eid, TRUE);
- if(!handler_vector)
+ listener = get_onevent_listener(event_target, eid, TRUE);
+ if(!listener)
return E_OUTOFMEMORY;
- if(handler_vector->handler_prop)
- IDispatch_Release(handler_vector->handler_prop);
+ if(listener->function)
+ IDispatch_Release(listener->function);
- handler_vector->handler_prop = disp;
- IDispatch_AddRef(disp);
+ IDispatch_AddRef(listener->function = disp);
return S_OK;
}
@@ -1707,7 +1754,7 @@ HRESULT set_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var
/*
* Setting event handler to string is a rare case and we don't want to
- * complicate nor increase memory of handler_vector_t for that. Instead,
+ * complicate nor increase memory of listener_container_t for that. Instead,
* we store the value in DispatchEx, which can already handle custom
* properties.
*/
@@ -1734,7 +1781,7 @@ HRESULT set_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var
HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
{
- handler_vector_t *handler_vector;
+ event_listener_t *listener;
VARIANT *v;
HRESULT hres;
@@ -1744,10 +1791,10 @@ HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var
return VariantCopy(var, v);
}
- handler_vector = get_handler_vector(event_target, eid, FALSE);
- if(handler_vector && handler_vector->handler_prop) {
+ listener = get_onevent_listener(event_target, eid, FALSE);
+ if(listener && listener->function) {
V_VT(var) = VT_DISPATCH;
- V_DISPATCH(var) = handler_vector->handler_prop;
+ V_DISPATCH(var) = listener->function;
IDispatch_AddRef(V_DISPATCH(var));
}else {
V_VT(var) = VT_NULL;
@@ -1758,9 +1805,9 @@ HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var
HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARIANT_BOOL *res)
{
- handler_vector_t *handler_vector;
+ listener_container_t *container;
+ event_listener_t *listener;
eventid_t eid;
- DWORD i = 0;
eid = attr_to_eid(name);
if(eid == EVENTID_LAST) {
@@ -1769,28 +1816,17 @@ HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARI
return S_OK;
}
- if(event_info[eid].flags & EVENT_FIXME)
- FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
-
- handler_vector = get_handler_vector(event_target, eid, TRUE);
- if(!handler_vector)
+ container = get_listener_container(event_target, eid, TRUE);
+ if(!container)
return E_OUTOFMEMORY;
- while(i < handler_vector->handler_cnt && handler_vector->handlers[i])
- i++;
- if(i == handler_vector->handler_cnt) {
- if(i)
- handler_vector->handlers = heap_realloc_zero(handler_vector->handlers,
- (i + 1) * sizeof(*handler_vector->handlers));
- else
- handler_vector->handlers = heap_alloc_zero(sizeof(*handler_vector->handlers));
- if(!handler_vector->handlers)
- return E_OUTOFMEMORY;
- handler_vector->handler_cnt++;
- }
+ listener = heap_alloc(sizeof(*listener));
+ if(!listener)
+ return E_OUTOFMEMORY;
- IDispatch_AddRef(disp);
- handler_vector->handlers[i] = disp;
+ listener->type = LISTENER_TYPE_ATTACHED;
+ IDispatch_AddRef(listener->function = disp);
+ list_add_head(&container->listeners, &listener->entry);
*res = VARIANT_TRUE;
return S_OK;
@@ -1798,9 +1834,7 @@ HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARI
HRESULT detach_event(EventTarget *event_target, BSTR name, IDispatch *disp)
{
- handler_vector_t *handler_vector;
eventid_t eid;
- unsigned i;
eid = attr_to_eid(name);
if(eid == EVENTID_LAST) {
@@ -1808,17 +1842,7 @@ HRESULT detach_event(EventTarget *event_target, BSTR name, IDispatch *disp)
return S_OK;
}
- handler_vector = get_handler_vector(event_target, eid, FALSE);
- if(!handler_vector)
- return S_OK;
-
- for(i = 0; i < handler_vector->handler_cnt; i++) {
- if(handler_vector->handlers[i] == disp) {
- IDispatch_Release(handler_vector->handlers[i]);
- handler_vector->handlers[i] = NULL;
- }
- }
-
+ remove_event_listener(event_target, eid, LISTENER_TYPE_ATTACHED, disp);
return S_OK;
}
@@ -2073,7 +2097,7 @@ HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)
{
- return (INT_PTR)key - WINE_RB_ENTRY_VALUE(entry, handler_vector_t, entry)->event_id;
+ return (INT_PTR)key - WINE_RB_ENTRY_VALUE(entry, listener_container_t, entry)->event_id;
}
void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_data_t *dispex_data,
@@ -2099,16 +2123,16 @@ void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_
void release_event_target(EventTarget *event_target)
{
- handler_vector_t *iter, *iter2;
- unsigned i;
+ listener_container_t *iter, *iter2;
- WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &event_target->handler_map, handler_vector_t, entry) {
- if(iter->handler_prop)
- IDispatch_Release(iter->handler_prop);
- for(i = 0; i < iter->handler_cnt; i++)
- if(iter->handlers[i])
- IDispatch_Release(iter->handlers[i]);
- heap_free(iter->handlers);
+ WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &event_target->handler_map, listener_container_t, entry) {
+ while(!list_empty(&iter->listeners)) {
+ event_listener_t *listener = LIST_ENTRY(list_head(&iter->listeners), event_listener_t, entry);
+ if(listener->function)
+ IDispatch_Release(listener->function);
+ list_remove(&listener->entry);
+ heap_free(listener);
+ }
heap_free(iter);
}
}