mshtml: Use event target vtbl to construct target chain in fire_event_obj.

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-19 17:01:33 +02:00 committed by Alexandre Julliard
parent 9e0c990be1
commit 57b830526b
9 changed files with 95 additions and 85 deletions

View File

@ -5030,6 +5030,15 @@ static void HTMLDocumentNode_bind_event(DispatchEx *dispex, eventid_t eid)
ensure_doc_nsevent_handler(This, eid);
}
static EventTarget *HTMLDocumentNode_get_parent_event_target(DispatchEx *dispex)
{
HTMLDocumentNode *This = impl_from_DispatchEx(dispex);
if(!This->window)
return NULL;
IHTMLWindow2_AddRef(&This->window->base.IHTMLWindow2_iface);
return &This->window->event_target;
}
static ConnectionPointContainer *HTMLDocumentNode_get_cp_container(DispatchEx *dispex)
{
HTMLDocumentNode *This = impl_from_DispatchEx(dispex);
@ -5048,6 +5057,7 @@ static const event_target_vtbl_t HTMLDocumentNode_event_target_vtbl = {
NULL
},
HTMLDocumentNode_bind_event,
HTMLDocumentNode_get_parent_event_target,
NULL,
HTMLDocumentNode_get_cp_container
};

View File

@ -5191,7 +5191,7 @@ HRESULT HTMLElement_handle_event(HTMLDOMNode *iface, DWORD eid, nsIDOMEvent *eve
switch(code) {
case VK_F1: /* DOM_VK_F1 */
TRACE("F1 pressed\n");
fire_event(This->node.doc, EVENTID_HELP, TRUE, &This->node, NULL);
fire_event(This->node.doc, EVENTID_HELP, TRUE, &This->node.event_target, NULL);
*prevent_default = TRUE;
}
@ -5356,6 +5356,27 @@ static HRESULT HTMLElement_handle_event_default(DispatchEx *dispex, eventid_t ei
return This->node.vtbl->handle_event(&This->node, eid, nsevent, prevent_default);
}
static EventTarget *HTMLElement_get_parent_event_target(DispatchEx *dispex)
{
HTMLElement *This = impl_from_DispatchEx(dispex);
HTMLDOMNode *node;
nsIDOMNode *nsnode;
nsresult nsres;
HRESULT hres;
nsres = nsIDOMNode_GetParentNode(This->node.nsnode, &nsnode);
assert(nsres == NS_OK);
if(!nsnode)
return NULL;
hres = get_node(This->node.doc, nsnode, TRUE, &node);
nsIDOMNode_Release(nsnode);
if(FAILED(hres))
return NULL;
return &node->event_target;
}
static ConnectionPointContainer *HTMLElement_get_cp_container(DispatchEx *dispex)
{
HTMLElement *This = impl_from_DispatchEx(dispex);
@ -5394,6 +5415,7 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = {
HTMLElement_populate_props
},
HTMLElement_bind_event,
HTMLElement_get_parent_event_target,
HTMLElement_handle_event_default,
HTMLElement_get_cp_container
};

View File

@ -1063,16 +1063,15 @@ void call_event_handlers(HTMLEventObj *event_obj, EventTarget *event_target, eve
}
}
static void fire_event_obj(HTMLDocumentNode *doc, eventid_t eid, HTMLEventObj *event_obj,
HTMLDOMNode *target)
static void fire_event_obj(HTMLDocumentNode *doc, eventid_t eid, HTMLEventObj *event_obj, EventTarget *event_target)
{
EventTarget *target_chain_buf[8], **target_chain = target_chain_buf;
unsigned chain_cnt, chain_buf_size, i;
IHTMLEventObj *prev_event;
nsIDOMNode *parent, *nsnode = NULL;
const event_target_vtbl_t *vtbl;
BOOL prevent_default = FALSE;
HTMLInnerWindow *window;
HTMLDOMNode *node;
UINT16 node_type = 0;
nsresult nsres;
EventTarget *iter;
HRESULT hres;
TRACE("(%p) %s\n", doc, debugstr_w(event_info[eid].name));
@ -1088,84 +1087,62 @@ static void fire_event_obj(HTMLDocumentNode *doc, eventid_t eid, HTMLEventObj *e
prev_event = window->event;
window->event = event_obj ? &event_obj->IHTMLEventObj_iface : NULL;
if(target) {
nsIDOMNode_GetNodeType(target->nsnode, &node_type);
nsnode = target->nsnode;
nsIDOMNode_AddRef(nsnode);
}
iter = event_target;
IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
switch(node_type) {
case ELEMENT_NODE:
do {
hres = get_node(doc, nsnode, FALSE, &node);
if(SUCCEEDED(hres) && node) {
call_event_handlers(event_obj, &node->event_target, eid);
node_release(node);
chain_cnt = 0;
chain_buf_size = sizeof(target_chain_buf)/sizeof(*target_chain_buf);
do {
if(chain_cnt == chain_buf_size) {
EventTarget **new_chain;
if(target_chain == target_chain_buf) {
new_chain = heap_alloc(chain_buf_size * 2 * sizeof(*new_chain));
if(!new_chain)
break;
memcpy(new_chain, target_chain, chain_buf_size * sizeof(*new_chain));
}else {
new_chain = heap_realloc(target_chain, chain_buf_size * 2 * sizeof(*new_chain));
if(!new_chain)
break;
}
chain_buf_size *= 2;
target_chain = new_chain;
}
if(!(event_info[eid].flags & EVENT_BUBBLES) || (event_obj && event_obj->cancel_bubble))
break;
target_chain[chain_cnt++] = iter;
nsIDOMNode_GetParentNode(nsnode, &parent);
nsIDOMNode_Release(nsnode);
nsnode = parent;
if(!nsnode)
break;
nsIDOMNode_GetNodeType(nsnode, &node_type);
}while(node_type == ELEMENT_NODE);
if(!(vtbl = dispex_get_vtbl(&iter->dispex)) || !vtbl->get_parent_event_target)
break;
iter = vtbl->get_parent_event_target(&iter->dispex);
} while(iter);
for(i = 0; i < chain_cnt; i++) {
call_event_handlers(event_obj, target_chain[i], eid);
if(!(event_info[eid].flags & EVENT_BUBBLES) || (event_obj && event_obj->cancel_bubble))
break;
/* fallthrough */
case DOCUMENT_NODE:
call_event_handlers(event_obj, &doc->node.event_target, eid);
if(!(event_info[eid].flags & EVENT_BUBBLES) || (event_obj && event_obj->cancel_bubble))
break;
/* fallthrough */
default: /* window object */
call_event_handlers(event_obj, &doc->window->event_target, eid);
}
if(nsnode)
nsIDOMNode_Release(nsnode);
if(event_obj && event_obj->prevent_default)
prevent_default = TRUE;
window->event = prev_event;
if(target && !prevent_default && (event_info[eid].flags & EVENT_HASDEFAULTHANDLERS)) {
nsnode = target->nsnode;
nsIDOMNode_AddRef(nsnode);
do {
hres = get_node(doc, nsnode, TRUE, &node);
if(FAILED(hres))
if(event_info[eid].flags & EVENT_HASDEFAULTHANDLERS) {
for(i = 0; !prevent_default && i < chain_cnt; i++) {
vtbl = dispex_get_vtbl(&target_chain[i]->dispex);
if(!vtbl || !vtbl->handle_event_default)
continue;
hres = vtbl->handle_event_default(&event_target->dispex, eid, event_obj ? event_obj->nsevent : NULL, &prevent_default);
if(FAILED(hres) || (event_obj && event_obj->cancel_bubble))
break;
if(node) {
const event_target_vtbl_t *vtbl = dispex_get_vtbl(&node->event_target.dispex);
if(vtbl && vtbl->handle_event_default)
hres = vtbl->handle_event_default(&node->event_target.dispex, eid, event_obj ? event_obj->nsevent : NULL, &prevent_default);
node_release(node);
if(FAILED(hres) || prevent_default || (event_obj && event_obj->cancel_bubble))
break;
}
nsres = nsIDOMNode_GetParentNode(nsnode, &parent);
if(NS_FAILED(nsres))
break;
nsIDOMNode_Release(nsnode);
nsnode = parent;
} while(nsnode);
if(nsnode)
nsIDOMNode_Release(nsnode);
}
}
for(i = 0; i < chain_cnt; i++)
IDispatchEx_Release(&target_chain[i]->dispex.IDispatchEx_iface);
if(target_chain != target_chain_buf)
heap_free(target_chain);
if(prevent_default && event_obj && event_obj->nsevent) {
TRACE("calling PreventDefault\n");
nsIDOMEvent_PreventDefault(event_obj->nsevent);
@ -1174,7 +1151,7 @@ static void fire_event_obj(HTMLDocumentNode *doc, eventid_t eid, HTMLEventObj *e
htmldoc_release(&doc->basedoc);
}
void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, HTMLDOMNode *target, nsIDOMEvent *nsevent)
void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, EventTarget *target, nsIDOMEvent *nsevent)
{
HTMLEventObj *event_obj = NULL;
HRESULT hres;
@ -1184,7 +1161,7 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, HTMLDOMNod
if(!event_obj)
return;
hres = set_event_info(event_obj, &target->event_target, eid, doc, nsevent);
hres = set_event_info(event_obj, target, eid, doc, nsevent);
if(FAILED(hres)) {
IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
return;
@ -1236,13 +1213,13 @@ HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *even
if(event_obj) {
hres = set_event_info(event_obj, &node->event_target, eid, node->doc, NULL);
if(SUCCEEDED(hres))
fire_event_obj(node->doc, eid, event_obj, node);
fire_event_obj(node->doc, eid, event_obj, &node->event_target);
IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
if(FAILED(hres))
return hres;
}else {
fire_event(node->doc, eid, TRUE, node, NULL);
fire_event(node->doc, eid, TRUE, &node->event_target, NULL);
}
*cancelled = VARIANT_TRUE; /* FIXME */

View File

@ -58,7 +58,7 @@ typedef enum {
eventid_t str_to_eid(LPCWSTR) DECLSPEC_HIDDEN;
void check_event_attr(HTMLDocumentNode*,nsIDOMHTMLElement*) DECLSPEC_HIDDEN;
void release_event_target(EventTarget*) DECLSPEC_HIDDEN;
void fire_event(HTMLDocumentNode*,eventid_t,BOOL,HTMLDOMNode*,nsIDOMEvent*) DECLSPEC_HIDDEN;
void fire_event(HTMLDocumentNode*,eventid_t,BOOL,EventTarget*,nsIDOMEvent*) DECLSPEC_HIDDEN;
HRESULT set_event_handler(EventTarget*,eventid_t,VARIANT*) DECLSPEC_HIDDEN;
HRESULT get_event_handler(EventTarget*,eventid_t,VARIANT*) DECLSPEC_HIDDEN;
HRESULT attach_event(EventTarget*,BSTR,IDispatch*,VARIANT_BOOL*) DECLSPEC_HIDDEN;
@ -83,6 +83,7 @@ void detach_nsevent(HTMLDocumentNode*,const WCHAR*) DECLSPEC_HIDDEN;
typedef struct {
dispex_static_data_vtbl_t dispex_vtbl;
void (*bind_event)(DispatchEx*,eventid_t);
EventTarget *(*get_parent_event_target)(DispatchEx*);
HRESULT (*handle_event_default)(DispatchEx*,eventid_t,nsIDOMEvent*,BOOL*);
ConnectionPointContainer *(*get_cp_container)(DispatchEx*);
} event_target_vtbl_t;

View File

@ -2155,7 +2155,7 @@ static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VAR
return E_FAIL;
}
fire_event(This->inner_window->doc, EVENTID_MESSAGE, TRUE, NULL, NULL);
fire_event(This->inner_window->doc, EVENTID_MESSAGE, TRUE, &This->inner_window->event_target, NULL);
return S_OK;
}

View File

@ -1499,7 +1499,7 @@ static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuList
if(FAILED(hres))
return NS_ERROR_FAILURE;
fire_event(This->doc->basedoc.doc_node /* FIXME */, EVENTID_CONTEXTMENU, TRUE, node, aEvent);
fire_event(This->doc->basedoc.doc_node /* FIXME */, EVENTID_CONTEXTMENU, TRUE, &node->event_target, aEvent);
nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event);
assert(NS_SUCCEEDED(nsres));

View File

@ -269,8 +269,8 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event
if(doc->nsdoc) {
flush_pending_tasks(doc->basedoc.task_magic);
fire_event(doc, EVENTID_LOAD, TRUE, &doc->node, event);
fire_event(doc, EVENTID_LOAD, TRUE, NULL, event);
fire_event(doc, EVENTID_LOAD, TRUE, &doc->node.event_target, event);
fire_event(doc, EVENTID_LOAD, TRUE, &doc->window->event_target, event);
}else {
ERR("NULL nsdoc\n");
nsres = NS_ERROR_FAILURE;
@ -328,17 +328,17 @@ static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent *
switch(eid) {
case EVENTID_FOCUS:
if(doc->event_vector[EVENTID_FOCUSIN])
fire_event(doc, EVENTID_FOCUSIN, TRUE, node, NULL);
fire_event(doc, EVENTID_FOCUSIN, TRUE, &node->event_target, NULL);
break;
case EVENTID_BLUR:
if(doc->event_vector[EVENTID_FOCUSOUT])
fire_event(doc, EVENTID_FOCUSOUT, TRUE, node, NULL);
fire_event(doc, EVENTID_FOCUSOUT, TRUE, &node->event_target, NULL);
break;
default:
break;
}
fire_event(doc, eid, TRUE, node, event);
fire_event(doc, eid, TRUE, &node->event_target, event);
node_release(node);
return NS_OK;

View File

@ -449,11 +449,11 @@ static void notif_readystate(HTMLOuterWindow *window)
call_property_onchanged(&window->doc_obj->basedoc.cp_container, DISPID_READYSTATE);
fire_event(window->base.inner_window->doc, EVENTID_READYSTATECHANGE, FALSE,
&window->base.inner_window->doc->node, NULL);
&window->base.inner_window->doc->node.event_target, NULL);
if(window->frame_element)
fire_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE,
TRUE, &window->frame_element->element.node, NULL);
TRUE, &window->frame_element->element.node.event_target, NULL);
}
typedef struct {

View File

@ -737,7 +737,7 @@ static void fire_readystatechange_proc(task_t *_task)
return;
task->elem->pending_readystatechange_event = FALSE;
fire_event(task->elem->element.node.doc, EVENTID_READYSTATECHANGE, FALSE, &task->elem->element.node, NULL);
fire_event(task->elem->element.node.doc, EVENTID_READYSTATECHANGE, FALSE, &task->elem->element.node.event_target, NULL);
}
static void fire_readystatechange_task_destr(task_t *_task)
@ -773,7 +773,7 @@ static void set_script_elem_readystate(HTMLScriptElement *script_elem, READYSTAT
}else {
script_elem->pending_readystatechange_event = FALSE;
fire_event(script_elem->element.node.doc, EVENTID_READYSTATECHANGE, FALSE,
&script_elem->element.node, NULL);
&script_elem->element.node.event_target, NULL);
}
}
}