From 3de3d07054d586d60be9d36f6c5725c3f28134fb Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 13 Sep 2012 12:28:09 +0200 Subject: [PATCH] mshtml: Added support for event object in HTMLElement::fireEvent. --- dlls/mshtml/htmlevent.c | 156 +++++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 49 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index eecff1cb6c4..6f1260a78a7 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -788,6 +788,11 @@ static const IHTMLEventObjVtbl HTMLEventObjVtbl = { HTMLEventObj_get_srcFilter }; +static inline HTMLEventObj *unsafe_impl_from_IHTMLEventObj(IHTMLEventObj *iface) +{ + return iface->lpVtbl == &HTMLEventObjVtbl ? impl_from_IHTMLEventObj(iface) : NULL; +} + static const tid_t HTMLEventObj_iface_tids[] = { IHTMLEventObj_tid, 0 @@ -800,7 +805,7 @@ static dispex_static_data_t HTMLEventObj_dispex = { HTMLEventObj_iface_tids }; -static HTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEvent *nsevent) +static HTMLEventObj *create_event(void) { HTMLEventObj *ret; @@ -810,39 +815,43 @@ static HTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEven ret->IHTMLEventObj_iface.lpVtbl = &HTMLEventObjVtbl; ret->ref = 1; - ret->type = eid != EVENTID_LAST ? event_info+eid : NULL; - - ret->nsevent = nsevent; - if(nsevent) { - nsIDOMEvent_AddRef(nsevent); - }else if(eid != EVENTID_LAST && event_types[event_info[eid].type]) { - nsAString type_str; - nsresult nsres; - - nsAString_InitDepend(&type_str, event_types[event_info[eid].type]); - nsres = nsIDOMHTMLDocument_CreateEvent(target->doc->nsdoc, &type_str, &ret->nsevent); - nsAString_Finish(&type_str); - if(NS_FAILED(nsres)) { - ERR("Could not create event: %08x\n", nsres); - IHTMLEventObj_Release(&ret->IHTMLEventObj_iface); - return NULL; - } - } - - ret->target = target; - if(target) - IHTMLDOMNode_AddRef(&target->IHTMLDOMNode_iface); init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLEventObj_iface, &HTMLEventObj_dispex); return ret; } +static HRESULT set_event_info(HTMLEventObj *event, HTMLDOMNode *target, eventid_t eid, nsIDOMEvent *nsevent) +{ + event->type = event_info+eid; + event->nsevent = nsevent; + + if(nsevent) { + nsIDOMEvent_AddRef(nsevent); + }else if(event_types[event_info[eid].type]) { + nsAString type_str; + nsresult nsres; + + nsAString_InitDepend(&type_str, event_types[event_info[eid].type]); + nsres = nsIDOMHTMLDocument_CreateEvent(target->doc->nsdoc, &type_str, &event->nsevent); + nsAString_Finish(&type_str); + if(NS_FAILED(nsres)) { + ERR("Could not create event: %08x\n", nsres); + return E_FAIL; + } + } + + event->target = target; + if(target) + IHTMLDOMNode_AddRef(&target->IHTMLDOMNode_iface); + return S_OK; +} + HRESULT create_event_obj(IHTMLEventObj **ret) { HTMLEventObj *event; - event = create_event(NULL, EVENTID_LAST, NULL); + event = create_event(); if(!event) return E_OUTOFMEMORY; @@ -1021,9 +1030,8 @@ static void call_event_handlers(HTMLDocumentNode *doc, HTMLEventObj *event_obj, } } -void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode *target, nsIDOMEvent *nsevent) +static void fire_event_obj(HTMLDocumentNode *doc, eventid_t eid, HTMLEventObj *event_obj, nsIDOMNode *target) { - HTMLEventObj *event_obj = NULL; IHTMLEventObj *prev_event; nsIDOMNode *parent, *nsnode; BOOL prevent_default = FALSE; @@ -1037,17 +1045,7 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode window = doc->window; prev_event = window->event; - if(set_event) { - hres = get_node(doc, target, TRUE, &node); - if(FAILED(hres)) - return; - - event_obj = create_event(node, eid, nsevent); - node_release(node); - window->event = &event_obj->IHTMLEventObj_iface; - }else { - window->event = NULL; - } + window->event = &event_obj->IHTMLEventObj_iface; nsIDOMNode_GetNodeType(target, &node_type); nsnode = target; @@ -1111,8 +1109,6 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode if(event_obj && event_obj->prevent_default) prevent_default = TRUE; window->event = prev_event; - if(event_obj) - IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface); if(!prevent_default && (event_info[eid].flags & EVENT_HASDEFAULTHANDLERS)) { nsIDOMNode_AddRef(target); @@ -1125,7 +1121,7 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode if(node) { if(node->vtbl->handle_event) - hres = node->vtbl->handle_event(node, eid, nsevent, &prevent_default); + hres = node->vtbl->handle_event(node, eid, event_obj ? event_obj->nsevent : NULL, &prevent_default); node_release(node); if(FAILED(hres) || prevent_default || (event_obj && event_obj->cancel_bubble)) break; @@ -1143,15 +1139,46 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode nsIDOMNode_Release(nsnode); } - if(prevent_default && nsevent) { + if(prevent_default && event_obj && event_obj->nsevent) { TRACE("calling PreventDefault\n"); - nsIDOMEvent_PreventDefault(nsevent); + nsIDOMEvent_PreventDefault(event_obj->nsevent); } } -HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_obj, VARIANT_BOOL *cancelled) +void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode *target, nsIDOMEvent *nsevent) { + HTMLEventObj *event_obj = NULL; + HTMLDOMNode *node; + HRESULT hres; + + if(set_event) { + hres = get_node(doc, target, TRUE, &node); + if(FAILED(hres)) + return; + + event_obj = create_event(); + node_release(node); + if(!event_obj) + return; + + hres = set_event_info(event_obj, node, eid, nsevent); + if(FAILED(hres)) { + IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface); + return; + } + } + + fire_event_obj(doc, eid, event_obj, target); + + if(event_obj) + IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface); +} + +HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_var, VARIANT_BOOL *cancelled) +{ + HTMLEventObj *event_obj = NULL; eventid_t eid; + HRESULT hres; eid = attr_to_eid(event_name); if(eid == EVENTID_LAST) { @@ -1159,15 +1186,46 @@ HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *even return E_INVALIDARG; } - if(event_obj && V_VT(event_obj) != VT_EMPTY && V_VT(event_obj) != VT_ERROR) - FIXME("event_obj not implemented\n"); + if(event_var && V_VT(event_var) != VT_EMPTY && V_VT(event_var) != VT_ERROR) { + if(V_VT(event_var) != VT_DISPATCH) { + FIXME("event_var %s not supported\n", debugstr_variant(event_var)); + return E_NOTIMPL; + } - if(!(event_info[eid].flags & EVENT_DEFAULTLISTENER)) { - FIXME("not EVENT_DEFAULTEVENTHANDLER\n"); - return E_NOTIMPL; + if(V_DISPATCH(event_var)) { + IHTMLEventObj *event_iface; + + hres = IDispatch_QueryInterface(V_DISPATCH(event_var), &IID_IHTMLEventObj, (void**)&event_iface); + if(FAILED(hres)) { + FIXME("No IHTMLEventObj iface\n"); + return hres; + } + + event_obj = unsafe_impl_from_IHTMLEventObj(event_iface); + if(!event_obj) { + ERR("Not our IHTMLEventObj?\n"); + IHTMLEventObj_Release(event_iface); + return E_FAIL; + } + } } - fire_event(node->doc, eid, TRUE, node->nsnode, NULL); + if(event_obj) { + hres = set_event_info(event_obj, node, eid, NULL); + if(SUCCEEDED(hres)) + fire_event_obj(node->doc, eid, event_obj, node->nsnode); + + IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface); + if(FAILED(hres)) + return hres; + }else { + if(!(event_info[eid].flags & EVENT_DEFAULTLISTENER)) { + FIXME("not EVENT_DEFAULTEVENTHANDLER\n"); + return E_NOTIMPL; + } + + fire_event(node->doc, eid, TRUE, node->nsnode, NULL); + } *cancelled = VARIANT_TRUE; /* FIXME */ return S_OK;