From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlwindow.c | 170 ++++++++++++++++++++++++----------- dlls/mshtml/mshtml_private.h | 3 +- dlls/mshtml/nsembed.c | 1 + dlls/mshtml/persist.c | 3 +- 4 files changed, 125 insertions(+), 52 deletions(-)
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index ff9c5622ec7..55a2488155e 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -45,6 +45,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
+static ExternalCycleCollectionParticipant window_ccp; + static int window_map_compare(const void *key, const struct wine_rb_entry *entry) { HTMLOuterWindow *window = WINE_RB_ENTRY_VALUE(entry, HTMLOuterWindow, entry); @@ -198,9 +200,12 @@ static HRESULT WINAPI HTMLWindow2_QueryInterface(IHTMLWindow2 *iface, REFIID rii *ppv = NULL; FIXME("(%p)->(IID_IMarshal %p)\n", This, ppv); return E_NOINTERFACE; - }else if(dispex_query_interface(&This->inner_window->event_target.dispex, riid, ppv)) { - assert(!*ppv); - return E_NOINTERFACE; + }else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) { + *ppv = &window_ccp; + return S_OK; + }else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) { + *ppv = &This->IHTMLWindow2_iface; + return S_OK; }else { return EventTarget_QI(&This->inner_window->event_target, riid, ppv); } @@ -212,47 +217,13 @@ static HRESULT WINAPI HTMLWindow2_QueryInterface(IHTMLWindow2 *iface, REFIID rii static ULONG WINAPI HTMLWindow2_AddRef(IHTMLWindow2 *iface) { HTMLWindow *This = impl_from_IHTMLWindow2(iface); - LONG ref = InterlockedIncrement(&This->ref); + LONG ref = ccref_incr(&This->ccref, (nsISupports*)&This->IHTMLWindow2_iface);
TRACE("(%p) ref=%ld\n", This, ref);
return ref; }
-static void release_outer_window(HTMLOuterWindow *This) -{ - if(This->browser) { - list_remove(&This->browser_entry); - This->browser = NULL; - } - - if(This->pending_window) { - abort_window_bindings(This->pending_window); - This->pending_window->base.outer_window = NULL; - IHTMLWindow2_Release(&This->pending_window->base.IHTMLWindow2_iface); - } - - remove_target_tasks(This->task_magic); - set_current_mon(This, NULL, 0); - set_current_uri(This, NULL); - if(This->base.inner_window) - detach_inner_window(This->base.inner_window); - - if(This->location) - IHTMLLocation_Release(&This->location->IHTMLLocation_iface); - - if(This->frame_element) - This->frame_element->content_window = NULL; - - if(This->nswindow) - nsIDOMWindow_Release(This->nswindow); - if(This->window_proxy) - mozIDOMWindowProxy_Release(This->window_proxy); - - wine_rb_remove(&window_map, &This->entry); - free(This); -} - static void release_inner_window(HTMLInnerWindow *This) { unsigned i; @@ -318,20 +289,10 @@ static void release_inner_window(HTMLInnerWindow *This) static ULONG WINAPI HTMLWindow2_Release(IHTMLWindow2 *iface) { HTMLWindow *This = impl_from_IHTMLWindow2(iface); - LONG ref = InterlockedDecrement(&This->ref); + LONG ref = ccref_decr(&This->ccref, (nsISupports*)&This->IHTMLWindow2_iface, &window_ccp);
TRACE("(%p) ref=%ld\n", This, ref);
- if(!ref) { - if (This->console) - IWineMSHTMLConsole_Release(This->console); - - if(is_outer_window(This)) - release_outer_window(This->outer_window); - else - release_inner_window(This->inner_window); - } - return ref; }
@@ -4036,6 +3997,115 @@ static dispex_static_data_t HTMLWindow_dispex = { HTMLWindow_init_dispex_info };
+static nsresult NSAPI window_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) +{ + HTMLWindow *This = impl_from_IHTMLWindow2(p); + HTMLOuterWindow *window; + + if(!is_outer_window(This)) { + /* FIXME: Traverse inner window and its dispex */ + return NS_OK; + } + window = This->outer_window; + + describe_cc_node(&window->base.ccref, "OuterWindow", cb); + + if(window->base.console) + note_cc_edge((nsISupports*)window->base.console, "console", cb); + if(window->pending_window) + note_cc_edge((nsISupports*)&window->pending_window->base.IHTMLWindow2_iface, "pending_window", cb); + if(window->base.inner_window) + note_cc_edge((nsISupports*)&window->base.inner_window->base.IHTMLWindow2_iface, "inner_window", cb); + if(window->location) + note_cc_edge((nsISupports*)&window->location->IHTMLLocation_iface, "location", cb); + if(window->nswindow) + note_cc_edge((nsISupports*)window->nswindow, "nswindow", cb); + if(window->window_proxy) + note_cc_edge((nsISupports*)window->window_proxy, "window_proxy", cb); + return NS_OK; +} + +static nsresult NSAPI window_unlink(void *p) +{ + HTMLWindow *This = impl_from_IHTMLWindow2(p); + HTMLOuterWindow *window; + + if(This->console) { + IWineMSHTMLConsole *console = This->console; + This->console = NULL; + IWineMSHTMLConsole_Release(console); + } + + if(!is_outer_window(This)) { + /* FIXME: Unlink inner window and its dispex */ + return NS_OK; + } + window = This->outer_window; + + remove_target_tasks(window->task_magic); + if(window->browser) { + list_remove(&window->browser_entry); + window->browser = NULL; + } + if(window->pending_window) { + HTMLInnerWindow *pending_window = window->pending_window; + abort_window_bindings(pending_window); + pending_window->base.outer_window = NULL; + window->pending_window = NULL; + IHTMLWindow2_Release(&pending_window->base.IHTMLWindow2_iface); + } + + set_current_mon(window, NULL, 0); + set_current_uri(window, NULL); + if(window->base.inner_window) + detach_inner_window(window->base.inner_window); + if(window->location) { + HTMLLocation *location = window->location; + window->location = NULL; + IHTMLLocation_Release(&location->IHTMLLocation_iface); + } + if(window->frame_element) { + window->frame_element->content_window = NULL; + window->frame_element = NULL; + } + if(window->nswindow) { + nsIDOMWindow *nswindow = window->nswindow; + window->nswindow = NULL; + nsIDOMWindow_Release(nswindow); + } + if(window->window_proxy) { + mozIDOMWindowProxy *window_proxy = window->window_proxy; + window->window_proxy = NULL; + mozIDOMWindowProxy_Release(window_proxy); + + wine_rb_remove(&window_map, &window->entry); + } + return NS_OK; +} + +static void NSAPI window_delete_cycle_collectable(void *p) +{ + HTMLWindow *This = impl_from_IHTMLWindow2(p); + window_unlink(p); + + if(!is_outer_window(This)) { + release_inner_window(This->inner_window); + return; + } + + free(This->outer_window); +} + +void init_window_cc(void) +{ + static const CCObjCallback ccp_callback = { + window_traverse, + window_unlink, + window_delete_cycle_collectable + }; + ccp_init(&window_ccp, &ccp_callback); +} + static void *alloc_window(size_t size) { HTMLWindow *window; @@ -4058,7 +4128,7 @@ static void *alloc_window(size_t size) window->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl; window->IWineHTMLWindowPrivate_iface.lpVtbl = &WineHTMLWindowPrivateVtbl; window->IWineHTMLWindowCompatPrivate_iface.lpVtbl = &WineHTMLWindowCompatPrivateVtbl; - window->ref = 1; + ccref_init(&window->ccref, 1);
return window; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7987f964ef9..3a05528d97c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -526,7 +526,7 @@ struct HTMLWindow {
IWineMSHTMLConsole *console;
- LONG ref; + nsCycleCollectingAutoRefCnt ccref;
HTMLInnerWindow *inner_window; HTMLOuterWindow *outer_window; @@ -1047,6 +1047,7 @@ BOOL is_gecko_path(const char*); void set_viewer_zoom(GeckoBrowser*,float); float get_viewer_zoom(GeckoBrowser*);
+void init_window_cc(void); void init_node_cc(void);
HRESULT nsuri_to_url(LPCWSTR,BOOL,BSTR*); diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index 95c07c90390..3e300d4e3e8 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -596,6 +596,7 @@ static BOOL init_xpcom(const PRUnichar *gre_path) ERR("NS_GetComponentRegistrar failed: %08lx\n", nsres); }
+ init_window_cc(); init_node_cc();
return TRUE; diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index b1ec172f912..4c3996471b3 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -474,7 +474,8 @@ static void notif_readystate(HTMLOuterWindow *window)
static void notif_readystate_proc(event_task_t *task) { - notif_readystate(task->window->base.outer_window); + if(task->window->base.outer_window) + notif_readystate(task->window->base.outer_window); }
static void notif_readystate_destr(event_task_t *task)