mshtml: Added support for event object in HTMLElement::fireEvent.

This commit is contained in:
Jacek Caban 2012-09-13 12:28:09 +02:00 committed by Alexandre Julliard
parent fffb717b1b
commit 3de3d07054
1 changed files with 107 additions and 49 deletions

View File

@ -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;