From 25c5082f90e181beb83258ed7d8542822220233b Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 12 Jul 2012 14:25:43 +0200 Subject: [PATCH] mshtml: Create inner window early in binding process and use it to store current binding callback. --- dlls/mshtml/binding.h | 2 +- dlls/mshtml/htmlwindow.c | 114 ++++++++++++++++++++++------------- dlls/mshtml/mshtml_private.h | 9 +-- dlls/mshtml/navigate.c | 79 ++++++++++-------------- dlls/mshtml/nsio.c | 7 ++- dlls/mshtml/persist.c | 10 +-- 6 files changed, 120 insertions(+), 101 deletions(-) diff --git a/dlls/mshtml/binding.h b/dlls/mshtml/binding.h index 7e3b6d370fc..2970849e981 100644 --- a/dlls/mshtml/binding.h +++ b/dlls/mshtml/binding.h @@ -111,7 +111,7 @@ HRESULT super_navigate(HTMLOuterWindow*,IUri*,const WCHAR*,BYTE*,DWORD) DECLSPEC HRESULT navigate_new_window(HTMLOuterWindow*,IUri*,const WCHAR*,IHTMLWindow2**) DECLSPEC_HIDDEN; HRESULT create_channelbsc(IMoniker*,const WCHAR*,BYTE*,DWORD,nsChannelBSC**) DECLSPEC_HIDDEN; -HRESULT channelbsc_load_stream(nsChannelBSC*,IStream*) DECLSPEC_HIDDEN; +HRESULT channelbsc_load_stream(HTMLInnerWindow*,IStream*) DECLSPEC_HIDDEN; void channelbsc_set_channel(nsChannelBSC*,nsChannel*,nsIStreamListener*,nsISupports*) DECLSPEC_HIDDEN; IUri *nsuri_get_uri(nsWineURI*) DECLSPEC_HIDDEN; HRESULT create_relative_uri(HTMLOuterWindow*,const WCHAR*,IUri**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index d448614287f..0ced93d89d2 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -197,8 +197,13 @@ static ULONG WINAPI HTMLWindow2_AddRef(IHTMLWindow2 *iface) static void release_outer_window(HTMLOuterWindow *This) { + 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_window_bscallback(This, NULL); set_current_mon(This, NULL); detach_inner_window(This); release_children(This); @@ -228,9 +233,14 @@ static void release_inner_window(HTMLInnerWindow *This) { unsigned i; + TRACE("%p\n", This); + + abort_window_bindings(This); release_script_hosts(This); - htmldoc_release(&This->doc->basedoc); + if(This->doc) + htmldoc_release(&This->doc->basedoc); + release_dispex(&This->dispex); for(i=0; i < This->global_prop_cnt; i++) @@ -2596,7 +2606,7 @@ static void *alloc_window(size_t size) return window; } -static HRESULT create_inner_window(HTMLOuterWindow *outer_window, HTMLDocumentNode *doc_node, HTMLInnerWindow **ret) +static HRESULT create_inner_window(HTMLOuterWindow *outer_window, HTMLInnerWindow **ret) { HTMLInnerWindow *window; @@ -2610,9 +2620,6 @@ static HRESULT create_inner_window(HTMLOuterWindow *outer_window, HTMLDocumentNo window->base.outer_window = outer_window; window->base.inner_window = window; - htmldoc_addref(&doc_node->basedoc); - window->doc = doc_node; - init_dispex(&window->dispex, (IUnknown*)&window->base.IHTMLWindow2_iface, &HTMLWindow_dispex); *ret = window; @@ -2651,7 +2658,9 @@ HRESULT HTMLOuterWindow_Create(HTMLDocumentObj *doc_obj, nsIDOMWindow *nswindow, window->scriptmode = parent ? parent->scriptmode : SCRIPTMODE_GECKO; window->readystate = READYSTATE_UNINITIALIZED; - hres = update_window_doc(window); + hres = create_pending_window(window, NULL); + if(SUCCEEDED(hres)) + hres = update_window_doc(window->pending_window); if(FAILED(hres)) { IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); return hres; @@ -2675,54 +2684,54 @@ HRESULT HTMLOuterWindow_Create(HTMLDocumentObj *doc_obj, nsIDOMWindow *nswindow, list_add_tail(&parent->children, &window->sibling_entry); } + TRACE("%p inner_window %p\n", window, window->base.inner_window); + *ret = window; return S_OK; } -static HRESULT window_set_docnode(HTMLOuterWindow *window, HTMLDocumentNode *doc_node) +HRESULT create_pending_window(HTMLOuterWindow *outer_window, nsChannelBSC *channelbsc) { - HTMLInnerWindow *inner_window; + HTMLInnerWindow *pending_window; HRESULT hres; - hres = create_inner_window(window, doc_node, &inner_window); + hres = create_inner_window(outer_window, &pending_window); if(FAILED(hres)) return hres; - detach_inner_window(window); - window->base.inner_window = inner_window; + if(channelbsc) { + IBindStatusCallback_AddRef(&channelbsc->bsc.IBindStatusCallback_iface); + pending_window->bscallback = channelbsc; - if(window->doc_obj && window->doc_obj->basedoc.window == window) { - if(window->doc_obj->basedoc.doc_node) - htmldoc_release(&window->doc_obj->basedoc.doc_node->basedoc); - window->doc_obj->basedoc.doc_node = doc_node; - if(doc_node) - htmldoc_addref(&doc_node->basedoc); + channelbsc->window = outer_window; } - if(doc_node && window->doc_obj && window->doc_obj->usermode == EDITMODE) { - nsAString mode_str; - nsresult nsres; - - static const PRUnichar onW[] = {'o','n',0}; - - nsAString_Init(&mode_str, onW); - nsres = nsIDOMHTMLDocument_SetDesignMode(doc_node->nsdoc, &mode_str); - nsAString_Finish(&mode_str); - if(NS_FAILED(nsres)) - ERR("SetDesignMode failed: %08x\n", nsres); + if(outer_window->pending_window) { + abort_window_bindings(outer_window->pending_window); + outer_window->pending_window->base.outer_window = NULL; + IHTMLWindow2_Release(&outer_window->pending_window->base.IHTMLWindow2_iface); } + outer_window->pending_window = pending_window; return S_OK; } -HRESULT update_window_doc(HTMLOuterWindow *window) +HRESULT update_window_doc(HTMLInnerWindow *window) { + HTMLOuterWindow *outer_window = window->base.outer_window; nsIDOMHTMLDocument *nshtmldoc; nsIDOMDocument *nsdoc; nsresult nsres; HRESULT hres; - nsres = nsIDOMWindow_GetDocument(window->nswindow, &nsdoc); + assert(!window->doc); + + if(!outer_window) { + ERR("NULL outer window\n"); + return E_UNEXPECTED; + } + + nsres = nsIDOMWindow_GetDocument(outer_window->nswindow, &nsdoc); if(NS_FAILED(nsres) || !nsdoc) { ERR("GetDocument failed: %08x\n", nsres); return E_FAIL; @@ -2735,21 +2744,40 @@ HRESULT update_window_doc(HTMLOuterWindow *window) return E_FAIL; } - if(!window->base.inner_window || window->base.inner_window->doc->nsdoc != nshtmldoc) { - HTMLDocumentNode *doc; + hres = create_doc_from_nsdoc(nshtmldoc, outer_window->doc_obj, outer_window, &window->doc); + nsIDOMHTMLDocument_Release(nshtmldoc); + if(FAILED(hres)) + return hres; - hres = create_doc_from_nsdoc(nshtmldoc, window->doc_obj, window, &doc); - if(SUCCEEDED(hres)) { - hres = window_set_docnode(window, doc); - htmldoc_release(&doc->basedoc); - }else { - ERR("create_doc_from_nsdoc failed: %08x\n", hres); - } - }else { - hres = S_OK; + if(outer_window->doc_obj->usermode == EDITMODE) { + nsAString mode_str; + nsresult nsres; + + static const PRUnichar onW[] = {'o','n',0}; + + nsAString_Init(&mode_str, onW); + nsres = nsIDOMHTMLDocument_SetDesignMode(window->doc->nsdoc, &mode_str); + nsAString_Finish(&mode_str); + if(NS_FAILED(nsres)) + ERR("SetDesignMode failed: %08x\n", nsres); + } + + if(window != outer_window->pending_window) { + ERR("not current pending window\n"); + return S_OK; + } + + detach_inner_window(outer_window); + outer_window->base.inner_window = window; + outer_window->pending_window = NULL; + + if(outer_window->doc_obj && (outer_window->doc_obj->basedoc.window == outer_window || !outer_window->doc_obj->basedoc.window)) { + if(outer_window->doc_obj->basedoc.doc_node) + htmldoc_release(&outer_window->doc_obj->basedoc.doc_node->basedoc); + outer_window->doc_obj->basedoc.doc_node = window->doc; + htmldoc_addref(&window->doc->basedoc); } - nsIDOMHTMLDocument_Release(nshtmldoc); return hres; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index b63ad53a98b..f0dde6ceab7 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -326,7 +326,7 @@ struct HTMLOuterWindow { HTMLFrameBase *frame_element; READYSTATE readystate; - nsChannelBSC *bscallback; + HTMLInnerWindow *pending_window; IMoniker *mon; IUri *uri; BSTR url; @@ -361,6 +361,7 @@ struct HTMLInnerWindow { DWORD global_prop_cnt; DWORD global_prop_size; + nsChannelBSC *bscallback; struct list bindings; }; @@ -665,7 +666,7 @@ HRESULT create_doc_from_nsdoc(nsIDOMHTMLDocument*,HTMLDocumentObj*,HTMLOuterWind HRESULT create_document_fragment(nsIDOMNode*,HTMLDocumentNode*,HTMLDocumentNode**) DECLSPEC_HIDDEN; HRESULT HTMLOuterWindow_Create(HTMLDocumentObj*,nsIDOMWindow*,HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; -HRESULT update_window_doc(HTMLOuterWindow*) DECLSPEC_HIDDEN; +HRESULT update_window_doc(HTMLInnerWindow*) DECLSPEC_HIDDEN; HTMLOuterWindow *nswindow_to_window(const nsIDOMWindow*) DECLSPEC_HIDDEN; void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**) DECLSPEC_HIDDEN; @@ -750,11 +751,11 @@ void get_editor_controller(NSContainer*) DECLSPEC_HIDDEN; nsresult get_nsinterface(nsISupports*,REFIID,void**) DECLSPEC_HIDDEN; nsIWritableVariant *create_nsvariant(void) DECLSPEC_HIDDEN; -void set_window_bscallback(HTMLOuterWindow*,nsChannelBSC*) DECLSPEC_HIDDEN; +HRESULT create_pending_window(HTMLOuterWindow*,nsChannelBSC*) DECLSPEC_HIDDEN; void set_current_mon(HTMLOuterWindow*,IMoniker*) DECLSPEC_HIDDEN; void set_current_uri(HTMLOuterWindow*,IUri*) DECLSPEC_HIDDEN; HRESULT start_binding(HTMLOuterWindow*,HTMLInnerWindow*,BSCallback*,IBindCtx*) DECLSPEC_HIDDEN; -HRESULT async_start_doc_binding(HTMLOuterWindow*,nsChannelBSC*) DECLSPEC_HIDDEN; +HRESULT async_start_doc_binding(HTMLOuterWindow*,HTMLInnerWindow*) DECLSPEC_HIDDEN; void abort_window_bindings(HTMLInnerWindow*) DECLSPEC_HIDDEN; void set_download_state(HTMLDocumentObj*,int) DECLSPEC_HIDDEN; void call_docview_84(HTMLDocumentObj*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index c07fd9069c3..1fe4f9d8424 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -725,8 +725,6 @@ HRESULT start_binding(HTMLOuterWindow *window, HTMLInnerWindow *inner_window, BS TRACE("(%p %p %p %p)\n", window, inner_window, bscallback, bctx); bscallback->window = inner_window; - if(!inner_window && window) - bscallback->window = window->base.inner_window; /* NOTE: IE7 calls IsSystemMoniker here*/ @@ -995,12 +993,7 @@ static HRESULT on_start_nsrequest(nsChannelBSC *This) } if(This->window) { - list_remove(&This->bsc.entry); - list_init(&This->bsc.entry); - update_window_doc(This->window); - if(This->window->base.inner_window != This->bsc.window) - This->bsc.window = This->window->base.inner_window; - list_add_head(&This->bsc.window->bindings, &This->bsc.entry); + update_window_doc(This->bsc.window); if(This->window->readystate != READYSTATE_LOADING) set_ready_state(This->window, READYSTATE_LOADING); } @@ -1331,6 +1324,7 @@ static HRESULT async_stop_request(nsChannelBSC *This) IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface); task->bsc = This; + push_task(&task->header, stop_request_proc, stop_request_task_destr, This->window->doc_obj->basedoc.task_magic); return S_OK; } @@ -1650,59 +1644,40 @@ HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, return S_OK; } -void set_window_bscallback(HTMLOuterWindow *window, nsChannelBSC *callback) -{ - if(window->bscallback) { - if(window->bscallback->bsc.binding) - IBinding_Abort(window->bscallback->bsc.binding); - window->bscallback->bsc.window = NULL; - window->bscallback->window = NULL; - IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface); - } - - window->bscallback = callback; - - if(callback) { - callback->window = window; - IBindStatusCallback_AddRef(&callback->bsc.IBindStatusCallback_iface); - callback->bsc.window = window->base.inner_window; - } -} - typedef struct { task_t header; HTMLOuterWindow *window; - nsChannelBSC *bscallback; + HTMLInnerWindow *pending_window; } start_doc_binding_task_t; static void start_doc_binding_proc(task_t *_task) { start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task; - start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL); + start_binding(task->window, task->pending_window, &task->pending_window->bscallback->bsc, NULL); } static void start_doc_binding_task_destr(task_t *_task) { start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task; - IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface); + IHTMLWindow2_Release(&task->pending_window->base.IHTMLWindow2_iface); heap_free(task); } -HRESULT async_start_doc_binding(HTMLOuterWindow *window, nsChannelBSC *bscallback) +HRESULT async_start_doc_binding(HTMLOuterWindow *window, HTMLInnerWindow *pending_window) { start_doc_binding_task_t *task; - TRACE("%p\n", bscallback); + TRACE("%p\n", pending_window); task = heap_alloc(sizeof(start_doc_binding_task_t)); if(!task) return E_OUTOFMEMORY; task->window = window; - task->bscallback = bscallback; - IBindStatusCallback_AddRef(&bscallback->bsc.IBindStatusCallback_iface); + task->pending_window = pending_window; + IHTMLWindow2_AddRef(&pending_window->base.IHTMLWindow2_iface); push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, window->task_magic); return S_OK; @@ -1710,28 +1685,40 @@ HRESULT async_start_doc_binding(HTMLOuterWindow *window, nsChannelBSC *bscallbac void abort_window_bindings(HTMLInnerWindow *window) { - BSCallback *iter, *next; + BSCallback *iter; + + while(!list_empty(&window->bindings)) { + iter = LIST_ENTRY(window->bindings.next, BSCallback, entry); - LIST_FOR_EACH_ENTRY_SAFE(iter, next, &window->bindings, BSCallback, entry) { TRACE("Aborting %p\n", iter); + IBindStatusCallback_AddRef(&iter->IBindStatusCallback_iface); + if(iter->window && iter->window->doc) remove_target_tasks(iter->window->doc->basedoc.task_magic); if(iter->binding) IBinding_Abort(iter->binding); - else { - list_remove(&iter->entry); - list_init(&iter->entry); + else iter->vtbl->stop_binding(iter, E_ABORT); - } iter->window = NULL; + list_remove(&iter->entry); + list_init(&iter->entry); + + IBindStatusCallback_Release(&iter->IBindStatusCallback_iface); + } + + if(window->bscallback) { + window->bscallback->window = NULL; + IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface); + window->bscallback = NULL; } } -HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream) +HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IStream *stream) { + nsChannelBSC *bscallback = pending_window->bscallback; HRESULT hres = S_OK; if(!bscallback->nschannel) { @@ -1743,7 +1730,7 @@ HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream) if(!bscallback->nschannel->content_type) return E_OUTOFMEMORY; - list_add_head(&bscallback->bsc.window->bindings, &bscallback->bsc.entry); + bscallback->bsc.window = pending_window; if(stream) hres = read_stream_data(bscallback, stream); if(SUCCEEDED(hres)) @@ -1839,14 +1826,14 @@ static void navigate_proc(task_t *_task) hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, NULL, task->bscallback, TRUE); if(SUCCEEDED(hres)) - start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL); + start_binding(task->window, task->window->pending_window, &task->bscallback->bsc, NULL); } static void navigate_task_destr(task_t *_task) { navigate_task_t *task = (navigate_task_t*)_task; - IUnknown_Release((IUnknown*)task->bscallback); + IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface); IMoniker_Release(task->mon); heap_free(task); } @@ -1946,7 +1933,7 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, const WCHAR *headers, task = heap_alloc(sizeof(*task)); if(!task) { - IUnknown_Release((IUnknown*)bsc); + IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface); IMoniker_Release(mon); return E_OUTOFMEMORY; } @@ -1963,7 +1950,7 @@ HRESULT super_navigate(HTMLOuterWindow *window, IUri *uri, const WCHAR *headers, }else { navigate_javascript_task_t *task; - IUnknown_Release((IUnknown*)bsc); + IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface); IMoniker_Release(mon); task = heap_alloc(sizeof(*task)); diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c index e177390df85..0a8a1240261 100644 --- a/dlls/mshtml/nsio.c +++ b/dlls/mshtml/nsio.c @@ -1016,9 +1016,12 @@ static nsresult async_open(nsChannel *This, HTMLOuterWindow *window, BOOL is_doc channelbsc_set_channel(bscallback, This, listener, context); if(is_doc_channel) { - set_window_bscallback(window, bscallback); - async_start_doc_binding(window, bscallback); + hres = create_pending_window(window, bscallback); + if(SUCCEEDED(hres)) + async_start_doc_binding(window, window->pending_window); IUnknown_Release((IUnknown*)bscallback); + if(FAILED(hres)) + return NS_ERROR_UNEXPECTED; }else { start_binding_task_t *task = heap_alloc(sizeof(start_binding_task_t)); diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c index cb148c42998..6f62c1b7f6b 100644 --- a/dlls/mshtml/persist.c +++ b/dlls/mshtml/persist.c @@ -370,9 +370,9 @@ HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, nsChannel hres = load_nsuri(This->window, nsuri, bscallback, 0/*LOAD_INITIAL_DOCUMENT_URI*/); nsISupports_Release((nsISupports*)nsuri); /* FIXME */ if(SUCCEEDED(hres)) - set_window_bscallback(This->window, bscallback); + hres = create_pending_window(This->window, bscallback); if(bscallback != async_bsc) - IUnknown_Release((IUnknown*)bscallback); + IUnknown_Release(&bscallback->bsc.IBindStatusCallback_iface); } if(FAILED(hres)) { @@ -538,7 +538,7 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva if(FAILED(hres)) return hres; - return start_binding(This->window, NULL, (BSCallback*)This->window->bscallback, pibc); + return start_binding(This->window, This->window->pending_window, (BSCallback*)This->window->pending_window->bscallback, pibc); } static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName, @@ -810,7 +810,7 @@ static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM if(FAILED(hres)) return hres; - return channelbsc_load_stream(This->window->bscallback, pStm); + return channelbsc_load_stream(This->window->pending_window, pStm); } static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm, @@ -869,7 +869,7 @@ static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface) if(FAILED(hres)) return hres; - return channelbsc_load_stream(This->window->bscallback, NULL); + return channelbsc_load_stream(This->window->pending_window, NULL); } static const IPersistStreamInitVtbl PersistStreamInitVtbl = {