mshtml: Properly invoke event listeners in IE9+ mode.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b96934bf4a
commit
d1f1e93c46
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue