mshtml: Added support for connection point HTML notification.

This commit is contained in:
Jacek Caban 2009-11-23 19:28:43 +01:00 committed by Alexandre Julliard
parent 19415addec
commit 1c5c822b07
8 changed files with 199 additions and 36 deletions

View File

@ -198,7 +198,7 @@ static const IConnectionPointVtbl ConnectionPointVtbl =
ConnectionPoint_EnumConnections
};
void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid)
void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *container, REFIID riid, cp_static_data_t *data)
{
cp->lpConnectionPointVtbl = &ConnectionPointVtbl;
cp->container = CONPTCONT(container);
@ -206,6 +206,7 @@ void ConnectionPoint_Init(ConnectionPoint *cp, ConnectionPointContainer *contain
cp->sinks_size = 0;
cp->iid = riid;
cp->next = NULL;
cp->data = data;
cp->next = container->cp_list;
container->cp_list = cp;

View File

@ -103,6 +103,7 @@ static REFIID tid_ids[] = {
&DIID_DispHTMLTableRow,
&DIID_DispHTMLUnknownElement,
&DIID_DispHTMLWindow2,
&DIID_HTMLDocumentEvents,
&IID_IHTMLAnchorElement,
&IID_IHTMLBodyElement,
&IID_IHTMLBodyElement2,
@ -304,6 +305,61 @@ static dispex_data_t *preprocess_dispex_data(DispatchEx *This)
return data;
}
static int id_cmp(const void *p1, const void *p2)
{
return *(DISPID*)p1 - *(DISPID*)p2;
}
HRESULT get_dispids(tid_t tid, DWORD *ret_size, DISPID **ret)
{
unsigned i, func_cnt;
FUNCDESC *funcdesc;
ITypeInfo *ti;
TYPEATTR *attr;
DISPID *ids;
HRESULT hres;
hres = get_typeinfo(tid, &ti);
if(FAILED(hres))
return hres;
hres = ITypeInfo_GetTypeAttr(ti, &attr);
if(FAILED(hres)) {
ITypeInfo_Release(ti);
return hres;
}
func_cnt = attr->cFuncs;
ITypeInfo_ReleaseTypeAttr(ti, attr);
ids = heap_alloc(func_cnt*sizeof(DISPID));
if(!ids) {
ITypeInfo_Release(ti);
return E_OUTOFMEMORY;
}
for(i=0; i < func_cnt; i++) {
hres = ITypeInfo_GetFuncDesc(ti, i, &funcdesc);
if(FAILED(hres))
break;
ids[i] = funcdesc->memid;
ITypeInfo_ReleaseFuncDesc(ti, funcdesc);
}
ITypeInfo_Release(ti);
if(FAILED(hres)) {
heap_free(ids);
return hres;
}
qsort(ids, func_cnt, sizeof(DISPID), id_cmp);
*ret_size = func_cnt;
*ret = ids;
return S_OK;
}
static CRITICAL_SECTION cs_dispex_static_data;
static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg =
{

View File

@ -771,7 +771,7 @@ HTMLElement *HTMLBodyElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *ns
HTMLTextContainer_Init(&ret->textcont, doc, nselem, &HTMLBodyElement_dispex);
ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink);
ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink, NULL);
nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLBodyElement,
(void**)&ret->nsbody);

View File

@ -1706,6 +1706,8 @@ static BOOL htmldoc_qi(HTMLDocument *This, REFIID riid, void **ppv)
return TRUE;
}
static cp_static_data_t HTMLDocumentEvents_data = { HTMLDocumentEvents_tid };
static void init_doc(HTMLDocument *doc, IUnknown *unk_impl, IDispatchEx *dispex)
{
doc->lpHTMLDocument2Vtbl = &HTMLDocumentVtbl;
@ -1727,9 +1729,9 @@ static void init_doc(HTMLDocument *doc, IUnknown *unk_impl, IDispatchEx *dispex)
HTMLDocument_Hlink_Init(doc);
ConnectionPointContainer_Init(&doc->cp_container, (IUnknown*)HTMLDOC(doc));
ConnectionPoint_Init(&doc->cp_propnotif, &doc->cp_container, &IID_IPropertyNotifySink);
ConnectionPoint_Init(&doc->cp_htmldocevents, &doc->cp_container, &DIID_HTMLDocumentEvents);
ConnectionPoint_Init(&doc->cp_htmldocevents2, &doc->cp_container, &DIID_HTMLDocumentEvents2);
ConnectionPoint_Init(&doc->cp_propnotif, &doc->cp_container, &IID_IPropertyNotifySink, NULL);
ConnectionPoint_Init(&doc->cp_htmldocevents, &doc->cp_container, &DIID_HTMLDocumentEvents, &HTMLDocumentEvents_data);
ConnectionPoint_Init(&doc->cp_htmldocevents2, &doc->cp_container, &DIID_HTMLDocumentEvents2, NULL);
}
static void destroy_htmldoc(HTMLDocument *This)
@ -1839,6 +1841,7 @@ HRESULT create_doc_from_nsdoc(nsIDOMHTMLDocument *nsdoc, HTMLDocumentObj *doc_ob
HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)nsdoc);
doc->node.vtbl = &HTMLDocumentNodeImplVtbl;
doc->node.cp_container = &doc->basedoc.cp_container;
hres = CoInternetCreateSecurityManager(NULL, &doc->secmgr, 0);
if(FAILED(hres)) {

View File

@ -24,6 +24,7 @@
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
#include "mshtmdid.h"
#include "mshtml_private.h"
#include "htmlevent.h"
@ -118,6 +119,7 @@ typedef struct {
LPCWSTR name;
LPCWSTR attr_name;
DWORD type;
DISPID dispid;
DWORD flags;
} event_info_t;
@ -126,24 +128,42 @@ typedef struct {
#define EVENT_FORWARDBODY 0x0004
static const event_info_t event_info[] = {
{beforeunloadW, onbeforeunloadW, EVENTT_NONE, EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
{blurW, onblurW, EVENTT_HTML, EVENT_DEFAULTLISTENER},
{changeW, onchangeW, EVENTT_HTML, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{clickW, onclickW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{dblclickW, ondblclickW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{dragW, ondragW, EVENTT_MOUSE, 0},
{dragstartW, ondragstartW, EVENTT_MOUSE, 0},
{focusW, onfocusW, EVENTT_HTML, EVENT_DEFAULTLISTENER},
{keydownW, onkeydownW, EVENTT_KEY, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{keyupW, onkeyupW, EVENTT_KEY, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{loadW, onloadW, EVENTT_HTML, 0},
{mousedownW, onmousedownW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{mouseoutW, onmouseoutW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{mouseoverW, onmouseoverW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{mouseupW, onmouseupW, EVENTT_MOUSE, EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{pasteW, onpasteW, EVENTT_NONE, 0},
{readystatechangeW, onreadystatechangeW, EVENTT_NONE, 0},
{selectstartW, onselectstartW, EVENTT_MOUSE, 0}
{beforeunloadW, onbeforeunloadW, EVENTT_NONE, DISPID_EVMETH_ONBEFOREUNLOAD,
EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
{blurW, onblurW, EVENTT_HTML, DISPID_EVMETH_ONBLUR,
EVENT_DEFAULTLISTENER},
{changeW, onchangeW, EVENTT_HTML, DISPID_EVMETH_ONCHANGE,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{clickW, onclickW, EVENTT_MOUSE, DISPID_EVMETH_ONCLICK,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{dblclickW, ondblclickW, EVENTT_MOUSE, DISPID_EVMETH_ONDBLCLICK,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{dragW, ondragW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAG,
0},
{dragstartW, ondragstartW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAGSTART,
0},
{focusW, onfocusW, EVENTT_HTML, DISPID_EVMETH_ONFOCUS,
EVENT_DEFAULTLISTENER},
{keydownW, onkeydownW, EVENTT_KEY, DISPID_EVMETH_ONKEYDOWN,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{keyupW, onkeyupW, EVENTT_KEY, DISPID_EVMETH_ONKEYUP,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{loadW, onloadW, EVENTT_HTML, DISPID_EVMETH_ONLOAD,
0},
{mousedownW, onmousedownW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{mouseoutW, onmouseoutW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOUT,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{mouseoverW, onmouseoverW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOVER,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{mouseupW, onmouseupW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEUP,
EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
{pasteW, onpasteW, EVENTT_NONE, DISPID_EVMETH_ONPASTE,
0},
{readystatechangeW, onreadystatechangeW, EVENTT_NONE, DISPID_EVMETH_ONREADYSTATECHANGE,
0},
{selectstartW, onselectstartW, EVENTT_MOUSE, DISPID_EVMETH_ONSELECTSTART,
0}
};
eventid_t str_to_eid(LPCWSTR str)
@ -738,17 +758,68 @@ static IHTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEve
return HTMLEVENTOBJ(ret);
}
static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, event_target_t *event_target,
eventid_t eid, IDispatch *this_obj)
static HRESULT call_cp_func(IDispatch *disp, DISPID dispid)
{
handler_vector_t *handler_vector;
DISPPARAMS dp = {NULL,NULL,0,0};
ULONG argerr;
EXCEPINFO ei;
VARIANT vres;
HRESULT hres;
V_VT(&vres) = VT_EMPTY;
memset(&ei, 0, sizeof(ei));
hres = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, &vres, &ei, &argerr);
if(SUCCEEDED(hres) && V_VT(&vres) != VT_EMPTY) {
FIXME("handle result %s\n", debugstr_variant(&vres));
VariantClear(&vres);
}
return hres;
}
static BOOL is_cp_event(ConnectionPoint *cp, DISPID dispid)
{
cp_static_data_t *data;
unsigned min, max, i;
HRESULT hres;
data = cp->data;
if(!data)
return FALSE;
if(!data->ids) {
hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
if(FAILED(hres))
return hres;
}
min = 0;
max = data->id_cnt;
while(min <= max) {
i = (min+max)/2;
if(data->ids[i] == dispid)
return TRUE;
if(data->ids[i] < dispid)
min = i+1;
else
max = i-1;
}
return FALSE;
}
static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, event_target_t *event_target,
ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj)
{
handler_vector_t *handler_vector = NULL;
DWORD i;
HRESULT hres;
if(!event_target || !(handler_vector = event_target->event_table[eid]))
return;
if(event_target)
handler_vector = event_target->event_table[eid];
if(handler_vector->handler_prop) {
if(handler_vector && handler_vector->handler_prop) {
DISPID named_arg = DISPID_THIS;
VARIANTARG arg;
DISPPARAMS dp = {&arg, &named_arg, 1, 1};
@ -764,7 +835,7 @@ static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj,
WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
}
if(handler_vector->handler_cnt) {
if(handler_vector && handler_vector->handler_cnt) {
VARIANTARG arg;
DISPPARAMS dp = {&arg, NULL, 1, 0};
@ -782,6 +853,26 @@ static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj,
}
}
}
if(cp_container) {
ConnectionPoint *cp;
if(cp_container->forward_container)
cp_container = cp_container->forward_container;
for(cp = cp_container->cp_list; cp; cp = cp->next) {
if(cp->sinks_size && is_cp_event(cp, event_info[eid].dispid)) {
for(i=0; i < cp->sinks_size; i++) {
TRACE("cp %s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid);
if(hres == S_OK)
TRACE("cp %s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
else
WARN("cp %s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
}
}
}
}
}
void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOMEvent *nsevent)
@ -805,7 +896,8 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOM
do {
node = get_node(doc, nsnode, FALSE);
if(node)
call_event_handlers(doc, event_obj, *get_node_event_target(node), eid, (IDispatch*)HTMLDOMNODE(node));
call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container, eid,
(IDispatch*)HTMLDOMNODE(node));
if(!(event_info[eid].flags & EVENT_BUBBLE))
break;
@ -831,14 +923,15 @@ void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOM
if(NS_SUCCEEDED(nsres) && nsbody) {
node = get_node(doc, (nsIDOMNode*)nsbody, FALSE);
if(node)
call_event_handlers(doc, event_obj, *get_node_event_target(node), eid, (IDispatch*)HTMLDOMNODE(node));
call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container,
eid, (IDispatch*)HTMLDOMNODE(node));
nsIDOMHTMLElement_Release(nsbody);
}else {
ERR("Could not get body: %08x\n", nsres);
}
}
call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, eid,
call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, &doc->basedoc.cp_container, eid,
(IDispatch*)HTMLDOC(&doc->basedoc));
break;

View File

@ -584,7 +584,7 @@ HTMLElement *HTMLTable_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
HTMLElement_Init(&ret->element, doc, nselem, &HTMLTable_dispex);
ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents);
ConnectionPoint_Init(&ret->cp, &ret->element.cp_container, &DIID_HTMLTableEvents, NULL);
nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLTableElement, (void**)&ret->nstable);
if(NS_FAILED(nsres))

View File

@ -189,5 +189,5 @@ void HTMLTextContainer_Init(HTMLTextContainer *This, HTMLDocumentNode *doc, nsID
HTMLElement_Init(&This->element, doc, nselem, dispex_data);
ConnectionPoint_Init(&This->cp, &This->element.cp_container, &DIID_HTMLTextContainerEvents);
ConnectionPoint_Init(&This->cp, &This->element.cp_container, &DIID_HTMLTextContainerEvents, NULL);
}

View File

@ -80,6 +80,7 @@ typedef enum {
DispHTMLTableRow_tid,
DispHTMLUnknownElement_tid,
DispHTMLWindow2_tid,
HTMLDocumentEvents_tid,
IHTMLAnchorElement_tid,
IHTMLBodyElement_tid,
IHTMLBodyElement2_tid,
@ -158,6 +159,7 @@ void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*);
void release_dispex(DispatchEx*);
BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**);
HRESULT get_dispids(tid_t,DWORD*,DISPID**);
typedef struct HTMLDocumentNode HTMLDocumentNode;
typedef struct HTMLDocumentObj HTMLDocumentObj;
@ -261,6 +263,12 @@ typedef enum {
EDITMODE
} USERMODE;
typedef struct {
tid_t tid;
DWORD id_cnt;
DISPID *ids;
} cp_static_data_t;
typedef struct ConnectionPointContainer {
const IConnectionPointContainerVtbl *lpConnectionPointContainerVtbl;
@ -282,6 +290,7 @@ struct ConnectionPoint {
DWORD sinks_size;
const IID *iid;
cp_static_data_t *data;
ConnectionPoint *next;
};
@ -449,6 +458,7 @@ struct HTMLDOMNode {
nsIDOMNode *nsnode;
HTMLDocumentNode *doc;
event_target_t *event_target;
ConnectionPointContainer *cp_container;
HTMLDOMNode *next;
};
@ -620,7 +630,7 @@ void HTMLDocumentNode_SecMgr_Init(HTMLDocumentNode*);
HRESULT HTMLCurrentStyle_Create(HTMLElement*,IHTMLCurrentStyle**);
void ConnectionPoint_Init(ConnectionPoint*,ConnectionPointContainer*,REFIID);
void ConnectionPoint_Init(ConnectionPoint*,ConnectionPointContainer*,REFIID,cp_static_data_t*);
void ConnectionPointContainer_Init(ConnectionPointContainer*,IUnknown*);
void ConnectionPointContainer_Destroy(ConnectionPointContainer*);