mshtml: Store current IHTMLEventObj in DOMEvent and create it in fire_event_obj if needed.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2017-10-20 15:09:15 +02:00 committed by Alexandre Julliard
parent aa6882cba8
commit aaa576463c
3 changed files with 39 additions and 29 deletions

View File

@ -223,7 +223,7 @@ static eventid_t attr_to_eid(const WCHAR *str)
return EVENTID_LAST;
}
struct HTMLEventObj {
typedef struct {
DispatchEx dispex;
IHTMLEventObj IHTMLEventObj_iface;
@ -232,7 +232,7 @@ struct HTMLEventObj {
const event_info_t *type;
DOMEvent *event;
VARIANT return_value;
};
} HTMLEventObj;
static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface)
{
@ -1204,7 +1204,7 @@ static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
return hres;
}
static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, HTMLEventObj *event_obj, VARIANT *retv)
static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, IHTMLEventObj *event_obj, VARIANT *retv)
{
DISPPARAMS dp = {NULL,NULL,0,0};
VARIANT event_arg;
@ -1213,7 +1213,7 @@ static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, HTMLEventObj *event_
if(event_obj) {
V_VT(&event_arg) = VT_DISPATCH;
V_DISPATCH(&event_arg) = (IDispatch*)&event_obj->IHTMLEventObj_iface;
V_DISPATCH(&event_arg) = (IDispatch*)event_obj;
dp.rgvarg = &event_arg;
dp.cArgs = 1;
}
@ -1252,7 +1252,7 @@ static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
return FALSE;
}
void call_event_handlers(HTMLEventObj *event_obj, EventTarget *event_target, DOMEvent *event)
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);
@ -1299,7 +1299,7 @@ void call_event_handlers(HTMLEventObj *event_obj, EventTarget *event_target, DOM
int i;
V_VT(&arg) = VT_DISPATCH;
V_DISPATCH(&arg) = (IDispatch*)&event_obj->dispex.IDispatchEx_iface;
V_DISPATCH(&arg) = (IDispatch*)event->event_obj;
i = handler_vector->handler_cnt;
while(i--) {
@ -1347,7 +1347,7 @@ void call_event_handlers(HTMLEventObj *event_obj, EventTarget *event_target, DOM
TRACE("cp %s [%u] >>>\n", debugstr_w(event_info[eid].name), i);
hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid,
cp->data->pass_event_arg ? event_obj : NULL, &v);
cp->data->pass_event_arg ? event->event_obj : NULL, &v);
if(hres == S_OK) {
TRACE("cp %s [%u] <<<\n", debugstr_w(event_info[eid].name), i);
@ -1370,11 +1370,12 @@ void call_event_handlers(HTMLEventObj *event_obj, EventTarget *event_target, DOM
}
}
static void fire_event_obj(EventTarget *event_target, DOMEvent *event, HTMLEventObj *event_obj)
static void fire_event_obj(EventTarget *event_target, DOMEvent *event)
{
EventTarget *target_chain_buf[8], **target_chain = target_chain_buf;
unsigned chain_cnt, chain_buf_size, i;
const event_target_vtbl_t *vtbl, *target_vtbl;
HTMLEventObj *event_obj_ref = NULL;
IHTMLEventObj *prev_event = NULL;
EventTarget *iter;
DWORD event_flags;
@ -1418,15 +1419,23 @@ static void fire_event_obj(EventTarget *event_target, DOMEvent *event, HTMLEvent
iter = vtbl->get_parent_event_target(&iter->dispex);
} while(iter);
if(!event->event_obj && !event->no_event_obj) {
event_obj_ref = alloc_event_obj(event);
if(event_obj_ref) {
event_obj_ref->type = event_info + event->event_id;
event->event_obj = &event_obj_ref->IHTMLEventObj_iface;
}
}
target_vtbl = dispex_get_vtbl(&event_target->dispex);
if(target_vtbl && target_vtbl->set_current_event)
prev_event = target_vtbl->set_current_event(&event_target->dispex, event_obj ? &event_obj->IHTMLEventObj_iface : NULL);
prev_event = target_vtbl->set_current_event(&event_target->dispex, event->event_obj);
event->target = event_target;
IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
for(i = 0; i < chain_cnt; i++) {
call_event_handlers(event_obj, target_chain[i], event);
call_event_handlers(target_chain[i], event);
if(!(event_flags & EVENT_BUBBLES) || event->stop_propagation)
break;
}
@ -1452,6 +1461,11 @@ static void fire_event_obj(EventTarget *event_target, DOMEvent *event, HTMLEvent
}
}
if(event_obj_ref) {
event->event_obj = NULL;
IHTMLEventObj_Release(&event_obj_ref->IHTMLEventObj_iface);
}
for(i = 0; i < chain_cnt; i++)
IDispatchEx_Release(&target_chain[i]->dispex.IDispatchEx_iface);
if(target_chain != target_chain_buf)
@ -1460,7 +1474,6 @@ static void fire_event_obj(EventTarget *event_target, DOMEvent *event, HTMLEvent
void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, EventTarget *target, nsIDOMEvent *nsevent)
{
HTMLEventObj *event_obj = NULL;
DOMEvent *event;
HRESULT hres;
@ -1471,19 +1484,11 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, EventTarge
if(FAILED(hres))
return;
if(set_event) {
event_obj = alloc_event_obj(event);
if(!event_obj) {
IDOMEvent_Release(&event->IDOMEvent_iface);
return;
}
event_obj->type = event_info + eid;
}
if(!set_event)
event->no_event_obj = TRUE;
fire_event_obj(target, event, event_obj);
fire_event_obj(target, event);
if(event_obj)
IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
IDOMEvent_Release(&event->IDOMEvent_iface);
}
@ -1533,11 +1538,13 @@ HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *even
if(!event_obj->event)
hres = create_document_event(node->doc, eid, &event_obj->event);
if(SUCCEEDED(hres))
fire_event_obj(&node->event_target, event_obj->event, event_obj);
if(SUCCEEDED(hres)) {
event_obj->event->event_obj = &event_obj->IHTMLEventObj_iface;
fire_event_obj(&node->event_target, event_obj->event);
event_obj->event->event_obj = NULL;
}
if(event_obj)
IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
if(FAILED(hres))
return hres;

View File

@ -66,6 +66,9 @@ typedef struct {
EventTarget *target;
BOOL prevent_default;
BOOL stop_propagation;
IHTMLEventObj *event_obj;
BOOL no_event_obj;
} DOMEvent;
eventid_t str_to_eid(LPCWSTR) DECLSPEC_HIDDEN;
@ -84,8 +87,7 @@ HRESULT create_event_obj(IHTMLEventObj**) DECLSPEC_HIDDEN;
void bind_target_event(HTMLDocumentNode*,EventTarget*,const WCHAR*,IDispatch*) DECLSPEC_HIDDEN;
HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode*,eventid_t) DECLSPEC_HIDDEN;
typedef struct HTMLEventObj HTMLEventObj;
void call_event_handlers(HTMLEventObj*,EventTarget*,DOMEvent*);
void call_event_handlers(EventTarget*,DOMEvent*);
HRESULT create_document_event_str(HTMLDocumentNode*,const WCHAR*,IDOMEvent**) DECLSPEC_HIDDEN;
HRESULT create_event_from_nsevent(nsIDOMEvent*,DOMEvent**) DECLSPEC_HIDDEN;

View File

@ -194,7 +194,8 @@ static nsresult NSAPI XMLHttpReqEventListener_HandleEvent(nsIDOMEventListener *i
hres = create_event_from_nsevent(nsevent, &event);
if(SUCCEEDED(hres) ){
call_event_handlers(NULL, &This->xhr->event_target, event);
event->no_event_obj = TRUE;
call_event_handlers(&This->xhr->event_target, event);
IDOMEvent_Release(&event->IDOMEvent_iface);
}
return NS_OK;