From: Gabriel Ivăncescu gabrielopcode@gmail.com
Note that native still sends a synchronous readyState notification during SuperNavigate (which we don't yet).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/mshtml_private.h | 3 +- dlls/mshtml/mutation.c | 9 ++++ dlls/mshtml/task.c | 11 +++-- dlls/mshtml/tests/events.c | 90 +++++++++++++++++++++++++++++++++++- dlls/mshtml/xmlhttprequest.c | 2 +- 5 files changed, 107 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index f3d621c5f90..c3a5bf7f191 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1460,11 +1460,12 @@ typedef struct { struct list *pending_xhr_events_tail; struct wine_rb_tree session_storage_map; void *blocking_xhr; + unsigned tasks_locked; } thread_data_t;
thread_data_t *get_thread_data(BOOL); HWND get_thread_hwnd(void); -void unblock_tasks_and_timers(thread_data_t*); +void unblock_tasks_and_timers(thread_data_t*,BOOL); int session_storage_map_cmp(const void*,const struct wine_rb_entry*); void destroy_session_storage(thread_data_t*);
diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index c5ce26b97bb..a9bec58f544 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -272,8 +272,14 @@ static void call_explorer_69(HTMLDocumentObj *doc)
static void parse_complete(HTMLDocumentObj *doc) { + thread_data_t *thread_data; + TRACE("(%p)\n", doc);
+ if(!(thread_data = get_thread_data(TRUE))) + return; + thread_data->tasks_locked++; + if(doc->nscontainer->usermode == EDITMODE) init_editor(doc->doc_node);
@@ -287,6 +293,9 @@ static void parse_complete(HTMLDocumentObj *doc) IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->window->base.IHTMLWindow2_iface, 0);
/* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */ + + if(!--thread_data->tasks_locked) + unblock_tasks_and_timers(thread_data, TRUE); }
static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2) diff --git a/dlls/mshtml/task.c b/dlls/mshtml/task.c index 49f76d101a9..711b9336b3e 100644 --- a/dlls/mshtml/task.c +++ b/dlls/mshtml/task.c @@ -310,7 +310,7 @@ static LRESULT process_timer(void) thread_data = get_thread_data(FALSE); assert(thread_data != NULL);
- if(list_empty(&thread_data->timer_list) || thread_data->blocking_xhr) { + if(list_empty(&thread_data->timer_list) || thread_data->tasks_locked || thread_data->blocking_xhr) { KillTimer(thread_data->thread_hwnd, TIMER_ID); return 0; } @@ -345,7 +345,7 @@ static LRESULT process_timer(void) call_timer_disp(disp, timer_type);
IDispatch_Release(disp); - }while(!list_empty(&thread_data->timer_list) && !thread_data->blocking_xhr); + }while(!list_empty(&thread_data->timer_list) && !thread_data->tasks_locked && !thread_data->blocking_xhr);
KillTimer(thread_data->thread_hwnd, TIMER_ID); return 0; @@ -364,6 +364,9 @@ static LRESULT WINAPI hidden_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa while(1) { struct list *head = list_head(&thread_data->task_list);
+ if(thread_data->tasks_locked) + break; + if(head) { task_t *task = LIST_ENTRY(head, task_t, entry); list_remove(&task->entry); @@ -479,9 +482,9 @@ ULONGLONG get_time_stamp(void) return (((ULONGLONG)time.dwHighDateTime << 32) + time.dwLowDateTime) / 10000 - time_epoch; }
-void unblock_tasks_and_timers(thread_data_t *thread_data) +void unblock_tasks_and_timers(thread_data_t *thread_data, BOOL include_task_list) { - if(!list_empty(&thread_data->event_task_list)) + if(!list_empty(&thread_data->event_task_list) || (include_task_list && !list_empty(&thread_data->task_list))) PostMessageW(thread_data->thread_hwnd, WM_PROCESSTASK, 0, 0);
if(!thread_data->blocking_xhr && !list_empty(&thread_data->timer_list)) { diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 2cf63f06dd3..0dd51ec6e14 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -133,6 +133,7 @@ static IOleDocumentView *view; static BOOL is_ie9plus; static int document_mode; static unsigned in_fire_event; +static DWORD main_thread_id;
typedef struct { LONG x; @@ -6196,6 +6197,7 @@ static HRESULT QueryInterface(REFIID riid, void **ppv) }
static IHTMLDocument2 *notif_doc; +static unsigned in_nav_notif_test, nav_notif_test_depth; static BOOL doc_complete;
static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, @@ -6222,9 +6224,14 @@ static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID) { - if(dispID == DISPID_READYSTATE){ + HRESULT hres; + + ok(GetCurrentThreadId() == main_thread_id, "OnChanged called on different thread\n"); + + if(dispID == DISPID_READYSTATE) { BSTR state; - HRESULT hres; + + ok(nav_notif_test_depth < 2, "nav_notif_test_depth = %u\n", nav_notif_test_depth);
hres = IHTMLDocument2_get_readyState(notif_doc, &state); ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); @@ -6235,6 +6242,44 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D SysFreeString(state); }
+ if(dispID == 1005) { + IHTMLPrivateWindow *priv_window; + IHTMLWindow2 *window; + BSTR bstr, bstr2; + VARIANT v; + + ok(!nav_notif_test_depth, "nav_notif_test_depth = %u\n", nav_notif_test_depth); + + if(in_nav_notif_test != 1) + return S_OK; + in_nav_notif_test++; + nav_notif_test_depth++; + + hres = IHTMLDocument2_get_parentWindow(notif_doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + ok(window != NULL, "window == NULL\n"); + + V_VT(&v) = VT_EMPTY; + bstr = SysAllocString(L"about:blank"); + bstr2 = SysAllocString(L""); + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_SuperNavigate(priv_window, bstr, bstr2, NULL, NULL, &v, &v, 0); + ok(hres == S_OK, "SuperNavigate failed: %08lx\n", hres); + IHTMLPrivateWindow_Release(priv_window); + IHTMLWindow2_Release(window); + SysFreeString(bstr2); + SysFreeString(bstr); + + ok(nav_notif_test_depth == 1, "nav_notif_test_depth = %u\n", nav_notif_test_depth); + pump_msgs(NULL); + pump_msgs(NULL); + pump_msgs(NULL); + ok(nav_notif_test_depth == 1, "nav_notif_test_depth = %u\n", nav_notif_test_depth); + ok(!doc_complete, "doc_complete = TRUE\n"); + nav_notif_test_depth--; + } + return S_OK; }
@@ -7445,6 +7490,45 @@ static void test_sync_xhr_events(const char *doc_str) IHTMLDocument2_Release(doc[1]); }
+static void test_navigation_during_notif(void) +{ + IPersistMoniker *persist; + IHTMLDocument2 *doc; + IMoniker *mon; + HRESULT hres; + BSTR url; + MSG msg; + + if(!(doc = create_document())) + return; + + notif_doc = doc; + doc_complete = FALSE; + set_client_site(doc, TRUE); + do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); + + url = SysAllocString(L"about:setting"); + hres = CreateURLMoniker(NULL, url, &mon); + SysFreeString(url); + ok(hres == S_OK, "CreateUrlMoniker failed: %08lx\n", hres); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IPersistMoniker, (void**)&persist); + ok(hres == S_OK, "Could not get IPersistMoniker iface: %08lx\n", hres); + + hres = IPersistMoniker_Load(persist, FALSE, mon, NULL, 0); + ok(hres == S_OK, "Load failed: %08lx\n", hres); + IPersistMoniker_Release(persist); + IMoniker_Release(mon); + + in_nav_notif_test = 1; + while(in_nav_notif_test != 2 && !doc_complete && GetMessageA(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + ok(!nav_notif_test_depth, "nav_notif_test_depth = %u\n", nav_notif_test_depth); + in_nav_notif_test = 0; +} + static BOOL check_ie(void) { IHTMLDocument2 *doc; @@ -7475,6 +7559,7 @@ static BOOL check_ie(void) START_TEST(events) { CoInitialize(NULL); + main_thread_id = GetCurrentThreadId();
if(check_ie()) { container_hwnd = create_container_window(); @@ -7516,6 +7601,7 @@ START_TEST(events) test_storage_events(empty_doc_ie9_str); test_sync_xhr_events(empty_doc_ie9_str); } + test_navigation_during_notif();
/* Test this last since it doesn't close the view properly. */ test_document_close(); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index fffc9fab51b..f7eff984d87 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -306,7 +306,7 @@ static nsresult sync_xhr_send(HTMLXMLHttpRequest *xhr, nsIVariant *nsbody) window->base.outer_window->readystate_locked--;
if(!--window->blocking_depth) - unblock_tasks_and_timers(thread_data); + unblock_tasks_and_timers(thread_data, FALSE);
/* Process any pending events now since they were part of the blocked send() above */ synthesize_pending_events(xhr);