Commit a54b322f authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

mshtml: Implement node cycle collection using the dispex.

parent ac572bc4
......@@ -33,6 +33,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
#define MAX_ARGS 16
ExternalCycleCollectionParticipant dispex_ccp;
static CRITICAL_SECTION cs_dispex_static_data;
static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg =
{
......@@ -1969,6 +1971,34 @@ static IDispatchExVtbl DispatchExVtbl = {
DispatchEx_GetNameSpaceParent
};
BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv)
{
if(IsEqualGUID(&IID_IDispatch, riid))
*ppv = &This->IDispatchEx_iface;
else if(IsEqualGUID(&IID_IDispatchEx, riid))
*ppv = &This->IDispatchEx_iface;
else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) {
*ppv = &dispex_ccp;
return TRUE;
}else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
*ppv = &This->IDispatchEx_iface;
return TRUE;
}else if(IsEqualGUID(&IID_IDispatchJS, riid))
*ppv = NULL;
else if(IsEqualGUID(&IID_UndocumentedScriptIface, riid))
*ppv = NULL;
else if(IsEqualGUID(&IID_IMarshal, riid))
*ppv = NULL;
else if(IsEqualGUID(&IID_IManagedObject, riid))
*ppv = NULL;
else
return FALSE;
if(*ppv)
IUnknown_AddRef((IUnknown*)*ppv);
return TRUE;
}
BOOL dispex_query_interface_no_cc(DispatchEx *This, REFIID riid, void **ppv)
{
if(IsEqualGUID(&IID_IDispatch, riid))
......@@ -1991,12 +2021,15 @@ BOOL dispex_query_interface_no_cc(DispatchEx *This, REFIID riid, void **ppv)
return TRUE;
}
void dispex_traverse(DispatchEx *This, nsCycleCollectionTraversalCallback *cb)
static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb)
{
DispatchEx *This = impl_from_IDispatchEx(p);
dynamic_prop_t *prop;
describe_cc_node(&This->ccref, This->info->desc->name, cb);
if(!This->dynamic_data)
return;
return NS_OK;
for(prop = This->dynamic_data->props; prop < This->dynamic_data->props + This->dynamic_data->prop_cnt; prop++) {
if(V_VT(&prop->var) == VT_DISPATCH)
......@@ -2014,9 +2047,11 @@ void dispex_traverse(DispatchEx *This, nsCycleCollectionTraversalCallback *cb)
note_cc_edge((nsISupports*)V_DISPATCH(&iter->val), "func_val", cb);
}
}
return NS_OK;
}
void dispex_unlink(DispatchEx *This)
void dispex_props_unlink(DispatchEx *This)
{
dynamic_prop_t *prop;
......@@ -2044,6 +2079,33 @@ void dispex_unlink(DispatchEx *This)
}
}
static nsresult NSAPI dispex_unlink(void *p)
{
DispatchEx *This = impl_from_IDispatchEx(p);
if(This->info->desc->vtbl->unlink)
This->info->desc->vtbl->unlink(This);
dispex_props_unlink(This);
return NS_OK;
}
static void NSAPI dispex_delete_cycle_collectable(void *p)
{
DispatchEx *This = impl_from_IDispatchEx(p);
release_dispex(This);
}
void init_dispex_cc(void)
{
static const CCObjCallback dispex_ccp_callback = {
dispex_traverse,
dispex_unlink,
dispex_delete_cycle_collectable
};
ccp_init(&dispex_ccp, &dispex_ccp_callback);
}
const void *dispex_get_vtbl(DispatchEx *dispex)
{
return dispex->info->desc->vtbl;
......@@ -2083,7 +2145,7 @@ void release_dispex(DispatchEx *This)
free(This->dynamic_data);
destructor:
if(This->info->desc->vtbl && This->info->desc->vtbl->destructor)
if(This->info->desc->vtbl)
This->info->desc->vtbl->destructor(This);
}
......
......@@ -308,13 +308,6 @@ static HRESULT DocumentType_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
return S_OK;
}
static void DocumentType_destructor(HTMLDOMNode *iface)
{
DocumentType *This = DocumentType_from_HTMLDOMNode(iface);
HTMLDOMNode_destructor(&This->node);
}
static HRESULT DocumentType_clone(HTMLDOMNode *iface, nsIDOMNode *nsnode, HTMLDOMNode **ret)
{
DocumentType *This = DocumentType_from_HTMLDOMNode(iface);
......@@ -326,7 +319,6 @@ static const cpc_entry_t DocumentType_cpc[] = {{NULL}};
static const NodeImplVtbl DocumentTypeImplVtbl = {
.qi = DocumentType_QI,
.destructor = DocumentType_destructor,
.cpc_entries = DocumentType_cpc,
.clone = DocumentType_clone
};
......@@ -366,7 +358,9 @@ static IHTMLEventObj *DocumentType_set_current_event(DispatchEx *dispex, IHTMLEv
static const event_target_vtbl_t DocumentType_event_target_vtbl = {
{
NULL,
.destructor = HTMLDOMNode_destructor,
.traverse = HTMLDOMNode_traverse,
.unlink = HTMLDOMNode_unlink
},
.get_gecko_target = DocumentType_get_gecko_target,
.get_parent_event_target = DocumentType_get_parent_event_target,
......@@ -6070,6 +6064,9 @@ static HRESULT HTMLDocumentNode_location_hook(DispatchEx *dispex, WORD flags, DI
static const event_target_vtbl_t HTMLDocumentNode_event_target_vtbl = {
{
.destructor = HTMLDOMNode_destructor,
.traverse = HTMLDOMNode_traverse,
.unlink = HTMLDOMNode_unlink,
.get_name = HTMLDocumentNode_get_name,
.invoke = HTMLDocumentNode_invoke,
.next_dispid = HTMLDocumentNode_next_dispid,
......
......@@ -6874,8 +6874,6 @@ void HTMLElement_destructor(HTMLDOMNode *iface)
}
free(This->filter);
HTMLDOMNode_destructor(&This->node);
}
HRESULT HTMLElement_clone(HTMLDOMNode *iface, nsIDOMNode *nsnode, HTMLDOMNode **ret)
......@@ -7354,6 +7352,9 @@ static const tid_t HTMLElement_iface_tids[] = {
const event_target_vtbl_t HTMLElement_event_target_vtbl = {
{
.destructor = HTMLDOMNode_destructor,
.traverse = HTMLDOMNode_traverse,
.unlink = HTMLDOMNode_unlink,
.get_dispid = HTMLElement_get_dispid,
.get_name = HTMLElement_get_name,
.invoke = HTMLElement_invoke,
......
......@@ -4478,6 +4478,27 @@ static HRESULT get_gecko_target(IEventTarget *target, nsIDOMEventTarget **ret)
return S_OK;
}
HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
{
if(IsEqualGUID(riid, &IID_IEventTarget)) {
if(use_event_quirks(event_target)) {
WARN("IEventTarget queried, but not supported by in document mode\n");
*ppv = NULL;
return E_NOINTERFACE;
}
IEventTarget_AddRef(&event_target->IEventTarget_iface);
*ppv = &event_target->IEventTarget_iface;
return S_OK;
}
if(dispex_query_interface(&event_target->dispex, riid, ppv))
return *ppv ? S_OK : E_NOINTERFACE;
WARN("(%p)->(%s %p)\n", event_target, debugstr_mshtml_guid(riid), ppv);
*ppv = NULL;
return E_NOINTERFACE;
}
HRESULT EventTarget_QI_no_cc(EventTarget *event_target, REFIID riid, void **ppv)
{
if(IsEqualGUID(riid, &IID_IEventTarget)) {
......
......@@ -35,8 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
static HTMLDOMNode *get_node_obj(IHTMLDOMNode*);
static HRESULT create_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**);
static ExternalCycleCollectionParticipant node_ccp;
typedef struct {
DispatchEx dispex;
IHTMLDOMChildrenCollection IHTMLDOMChildrenCollection_iface;
......@@ -499,9 +497,7 @@ static HRESULT WINAPI HTMLDOMNode_QueryInterface(IHTMLDOMNode *iface,
static ULONG WINAPI HTMLDOMNode_AddRef(IHTMLDOMNode *iface)
{
HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
LONG ref;
ref = ccref_incr(&This->event_target.dispex.ccref, (nsISupports*)&This->IHTMLDOMNode_iface);
LONG ref = dispex_ref_incr(&This->event_target.dispex);
TRACE("(%p) ref=%ld\n", This, ref);
......@@ -511,7 +507,7 @@ static ULONG WINAPI HTMLDOMNode_AddRef(IHTMLDOMNode *iface)
static ULONG WINAPI HTMLDOMNode_Release(IHTMLDOMNode *iface)
{
HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
LONG ref = ccref_decr(&This->event_target.dispex.ccref, (nsISupports*)&This->IHTMLDOMNode_iface, &node_ccp);
LONG ref = dispex_ref_decr(&This->event_target.dispex);
TRACE("(%p) ref=%ld\n", This, ref);
......@@ -1423,6 +1419,49 @@ static const IHTMLDOMNode3Vtbl HTMLDOMNode3Vtbl = {
HTMLDOMNode3_isSupported
};
static inline HTMLDOMNode *HTMLDOMNode_from_DispatchEx(DispatchEx *iface)
{
return CONTAINING_RECORD(iface, HTMLDOMNode, event_target.dispex);
}
void HTMLDOMNode_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb)
{
HTMLDOMNode *This = HTMLDOMNode_from_DispatchEx(dispex);
if(This->vtbl->traverse)
This->vtbl->traverse(This, cb);
if(This->nsnode)
note_cc_edge((nsISupports*)This->nsnode, "nsnode", cb);
if(This->doc && &This->doc->node != This)
note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb);
}
void HTMLDOMNode_unlink(DispatchEx *dispex)
{
HTMLDOMNode *This = HTMLDOMNode_from_DispatchEx(dispex);
if(This->vtbl->unlink)
This->vtbl->unlink(This);
unlink_ref(&This->nsnode);
if(This->doc) {
HTMLDocumentNode *doc = This->doc;
This->doc = NULL;
if(&doc->node != This)
IHTMLDOMNode_Release(&doc->node.IHTMLDOMNode_iface);
}
}
void HTMLDOMNode_destructor(DispatchEx *dispex)
{
HTMLDOMNode *This = HTMLDOMNode_from_DispatchEx(dispex);
release_event_target(&This->event_target);
if(This->vtbl->destructor)
This->vtbl->destructor(This);
free(This);
}
HRESULT HTMLDOMNode_QI(HTMLDOMNode *This, REFIID riid, void **ppv)
{
TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
......@@ -1437,29 +1476,14 @@ HRESULT HTMLDOMNode_QI(HTMLDOMNode *This, REFIID riid, void **ppv)
*ppv = &This->IHTMLDOMNode2_iface;
}else if(IsEqualGUID(&IID_IHTMLDOMNode3, riid)) {
*ppv = &This->IHTMLDOMNode3_iface;
}else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) {
*ppv = &node_ccp;
return S_OK;
}else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
*ppv = &This->IHTMLDOMNode_iface;
return S_OK;
}else {
return EventTarget_QI_no_cc(&This->event_target, riid, ppv);
return EventTarget_QI(&This->event_target, riid, ppv);
}
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
void HTMLDOMNode_destructor(HTMLDOMNode *This)
{
release_event_target(&This->event_target);
if(This->nsnode)
nsIDOMNode_Release(This->nsnode);
if(This->doc && &This->doc->node != This)
IHTMLDOMNode_Release(&This->doc->node.IHTMLDOMNode_iface);
}
static HRESULT HTMLDOMNode_clone(HTMLDOMNode *This, nsIDOMNode *nsnode, HTMLDOMNode **ret)
{
return create_node(This->doc, nsnode, ret);
......@@ -1477,7 +1501,6 @@ static const cpc_entry_t HTMLDOMNode_cpc[] = {{NULL}};
static const NodeImplVtbl HTMLDOMNodeImplVtbl = {
.qi = HTMLDOMNode_QI,
.destructor = HTMLDOMNode_destructor,
.cpc_entries = HTMLDOMNode_cpc,
.clone = HTMLDOMNode_clone
};
......@@ -1503,13 +1526,19 @@ void HTMLDOMNode_Init(HTMLDocumentNode *doc, HTMLDOMNode *node, nsIDOMNode *nsno
assert(nsres == NS_OK);
}
static const dispex_static_data_vtbl_t HTMLDOMNode_dispex_vtbl = {
.destructor = HTMLDOMNode_destructor,
.traverse = HTMLDOMNode_traverse,
.unlink = HTMLDOMNode_unlink
};
static const tid_t HTMLDOMNode_iface_tids[] = {
IHTMLDOMNode_tid,
0
};
static dispex_static_data_t HTMLDOMNode_dispex = {
"Node",
NULL,
&HTMLDOMNode_dispex_vtbl,
IHTMLDOMNode_tid,
HTMLDOMNode_iface_tids,
HTMLDOMNode_init_dispex_info
......@@ -1575,73 +1604,6 @@ static HRESULT create_node(HTMLDocumentNode *doc, nsIDOMNode *nsnode, HTMLDOMNod
return S_OK;
}
static nsresult NSAPI HTMLDOMNode_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb)
{
HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
TRACE("%p\n", This);
describe_cc_node(&This->event_target.dispex.ccref, "HTMLDOMNode", cb);
if(This->nsnode)
note_cc_edge((nsISupports*)This->nsnode, "This->nsnode", cb);
if(This->doc && &This->doc->node != This)
note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "This->doc", cb);
dispex_traverse(&This->event_target.dispex, cb);
if(This->vtbl->traverse)
This->vtbl->traverse(This, cb);
return NS_OK;
}
static nsresult NSAPI HTMLDOMNode_unlink(void *p)
{
HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
TRACE("%p\n", This);
if(This->vtbl->unlink)
This->vtbl->unlink(This);
dispex_unlink(&This->event_target.dispex);
unlink_ref(&This->nsnode);
if(This->doc && &This->doc->node != This) {
HTMLDocumentNode *doc = This->doc;
This->doc = NULL;
IHTMLDOMNode_Release(&doc->node.IHTMLDOMNode_iface);
}else {
This->doc = NULL;
}
return NS_OK;
}
static void NSAPI HTMLDOMNode_delete_cycle_collectable(void *p)
{
HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
TRACE("(%p)\n", This);
if(This->vtbl->unlink)
This->vtbl->unlink(This);
This->vtbl->destructor(This);
release_dispex(&This->event_target.dispex);
free(This);
}
void init_node_cc(void)
{
static const CCObjCallback node_ccp_callback = {
HTMLDOMNode_traverse,
HTMLDOMNode_unlink,
HTMLDOMNode_delete_cycle_collectable
};
ccp_init(&node_ccp, &node_ccp_callback);
}
HRESULT get_node(nsIDOMNode *nsnode, BOOL create, HTMLDOMNode **ret)
{
nsIDOMDocument *dom_document;
......
......@@ -352,11 +352,16 @@ static const cpc_entry_t HTMLDOMTextNode_cpc[] = {{NULL}};
static const NodeImplVtbl HTMLDOMTextNodeImplVtbl = {
.qi = HTMLDOMTextNode_QI,
.destructor = HTMLDOMNode_destructor,
.cpc_entries = HTMLDOMTextNode_cpc,
.clone = HTMLDOMTextNode_clone
};
static const dispex_static_data_vtbl_t HTMLDOMTextNode_dispex_vtbl = {
.destructor = HTMLDOMNode_destructor,
.traverse = HTMLDOMNode_traverse,
.unlink = HTMLDOMNode_unlink
};
static const tid_t HTMLDOMTextNode_iface_tids[] = {
IHTMLDOMNode_tid,
IHTMLDOMNode2_tid,
......@@ -366,7 +371,7 @@ static const tid_t HTMLDOMTextNode_iface_tids[] = {
};
static dispex_static_data_t HTMLDOMTextNode_dispex = {
"Text",
NULL,
&HTMLDOMTextNode_dispex_vtbl,
DispHTMLDOMTextNode_tid,
HTMLDOMTextNode_iface_tids,
HTMLDOMNode_init_dispex_info
......
......@@ -123,7 +123,7 @@ static void detach_inner_window(HTMLInnerWindow *window)
detach_document_node(doc);
if(outer_window && outer_window->location.dispex.outer)
dispex_unlink(&outer_window->location.dispex);
dispex_props_unlink(&outer_window->location.dispex);
abort_window_bindings(window);
remove_target_tasks(window->task_magic);
......
......@@ -352,8 +352,10 @@ typedef struct {
- dynamic props: These props are generally allocated by external code (e.g. 'document.wine = 42' creates 'wine' dynamic prop on document)
*/
typedef struct {
/* Unlike delete_cycle_collectable, unlink is called before the destructor (if available). */
/* Used to implement Cycle Collection callbacks; note that the destructor is not optional!
Unlike delete_cycle_collectable, unlink is called before the destructor (if available). */
void (*destructor)(DispatchEx*);
void (*traverse)(DispatchEx*,nsCycleCollectionTraversalCallback*);
void (*unlink)(DispatchEx*);
/* Called when the object wants to handle DISPID_VALUE invocations */
......@@ -425,16 +427,28 @@ extern void (__cdecl *ccp_init)(ExternalCycleCollectionParticipant*,const CCObjC
extern void (__cdecl *describe_cc_node)(nsCycleCollectingAutoRefCnt*,const char*,nsCycleCollectionTraversalCallback*);
extern void (__cdecl *note_cc_edge)(nsISupports*,const char*,nsCycleCollectionTraversalCallback*);
extern ExternalCycleCollectionParticipant dispex_ccp;
static inline LONG dispex_ref_incr(DispatchEx *dispex)
{
return ccref_incr(&dispex->ccref, (nsISupports*)&dispex->IDispatchEx_iface);
}
static inline LONG dispex_ref_decr(DispatchEx *dispex)
{
return ccref_decr(&dispex->ccref, (nsISupports*)&dispex->IDispatchEx_iface, &dispex_ccp);
}
void init_dispatch(DispatchEx*,IUnknown*,dispex_static_data_t*,compat_mode_t);
void release_dispex(DispatchEx*);
BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
BOOL dispex_query_interface_no_cc(DispatchEx*,REFIID,void**);
void dispex_props_unlink(DispatchEx*);
HRESULT change_type(VARIANT*,VARIANT*,VARTYPE,IServiceProvider*);
HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**);
HRESULT get_dispids(tid_t,DWORD*,DISPID**);
HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*);
HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*);
void dispex_traverse(DispatchEx*,nsCycleCollectionTraversalCallback*);
void dispex_unlink(DispatchEx*);
void release_typelib(void);
HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**);
const void *dispex_get_vtbl(DispatchEx*);
......@@ -1072,7 +1086,7 @@ BOOL is_gecko_path(const char*);
void set_viewer_zoom(GeckoBrowser*,float);
float get_viewer_zoom(GeckoBrowser*);
void init_node_cc(void);
void init_dispex_cc(void);
HRESULT nsuri_to_url(LPCWSTR,BOOL,BSTR*);
......@@ -1219,11 +1233,14 @@ void HTMLDOMNode_Init(HTMLDocumentNode*,HTMLDOMNode*,nsIDOMNode*,dispex_static_d
void HTMLElement_Init(HTMLElement*,HTMLDocumentNode*,nsIDOMElement*,dispex_static_data_t*);
void EventTarget_Init(EventTarget*,IUnknown*,dispex_static_data_t*,compat_mode_t);
HRESULT EventTarget_QI(EventTarget*,REFIID,void**);
HRESULT EventTarget_QI_no_cc(EventTarget*,REFIID,void**);
void EventTarget_init_dispex_info(dispex_data_t*,compat_mode_t);
HRESULT HTMLDOMNode_QI(HTMLDOMNode*,REFIID,void**);
void HTMLDOMNode_destructor(HTMLDOMNode*);
void HTMLDOMNode_destructor(DispatchEx*);
void HTMLDOMNode_traverse(DispatchEx*,nsCycleCollectionTraversalCallback*);
void HTMLDOMNode_unlink(DispatchEx*);
void HTMLDOMNode_init_dispex_info(dispex_data_t*,compat_mode_t);
HRESULT HTMLElement_QI(HTMLDOMNode*,REFIID,void**);
......
......@@ -596,7 +596,7 @@ static BOOL init_xpcom(const PRUnichar *gre_path)
ERR("NS_GetComponentRegistrar failed: %08lx\n", nsres);
}
init_node_cc();
init_dispex_cc();
return TRUE;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment