This implements some events related to document/window load and unload / visibility changes. The latter is related in that native partially implements it, and only sends it when it is minimized or restored from being minimized, not on navigation or anything else.
The main issue for me is the visibilitychange patch. Since we don't control the container hwnd, and it can even be in another process, there is no way to be notified cleanly when it changes its minimization state. We can't subclass it either, as the tests show, it's not subclassed.
I implemented it now using an internal timer that polls for that, since it was the least invasive and works in all cases, including other process hwnd. Hooks wouldn't be able to do that, and are also more invasive IMO. I'm hoping for better ideas, though.
-- v5: mshtml: Implement pagehide event. mshtml: Implement unload event. mshtml: Dispatch beforeunload event to the window. mshtml: Implement pageshow event. mshtml: Store the nsevent listener descs in a table. mshtml: Add visibilitychange event stub. mshtml: Dispatch Gecko events to the window if there's no node. mshtml: Do not register Gecko load event handler twice. mshtml: Allow EVENT_BIND_TO_TARGET to bind to the window.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f2c862c5b0a..e669afb7483 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -3683,10 +3683,7 @@ HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, nsIDOMNode *nsnode, ev
if(event_info[eid].flags & EVENT_DEFAULTLISTENER) { nsnode = NULL; - }else if(event_info[eid].flags & EVENT_BIND_TO_TARGET) { - if(!nsnode) - nsnode = doc->node.nsnode; - }else { + }else if(!(event_info[eid].flags & EVENT_BIND_TO_TARGET)) { return S_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/nsevents.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index a8e3d503921..65de8c8c2e3 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -482,4 +482,7 @@ void init_nsevents(HTMLDocumentNode *doc) init_event(target, L"load", &listener->load_listener.nsIDOMEventListener_iface, TRUE);
nsIDOMEventTarget_Release(target); + + /* handle_load already takes care of dispatching the load event */ + doc->event_vector[EVENTID_LOAD] = TRUE; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
The window itself is not a DOM node, so this is perfectly normal to fail here. In fact, we weren't dispatching any gecko events sent to the window.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/nsevents.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 65de8c8c2e3..305a017d978 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -287,8 +287,8 @@ static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent * nsEventListener *This = impl_from_nsIDOMEventListener(iface); HTMLDocumentNode *doc = This->This->doc; nsIDOMEventTarget *event_target; + EventTarget *target; nsIDOMNode *nsnode; - HTMLDOMNode *node; DOMEvent *event; nsresult nsres; HRESULT hres; @@ -309,18 +309,22 @@ static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent * nsres = nsIDOMEventTarget_QueryInterface(event_target, &IID_nsIDOMNode, (void**)&nsnode); nsIDOMEventTarget_Release(event_target); if(NS_FAILED(nsres)) { - ERR("Could not get nsIDOMNode: %08lx\n", nsres); - return NS_OK; + if(!doc->window) + return S_OK; + target = &doc->window->event_target; + IHTMLWindow2_AddRef(&doc->window->base.IHTMLWindow2_iface); + }else { + HTMLDOMNode *node; + hres = get_node(nsnode, TRUE, &node); + nsIDOMNode_Release(nsnode); + if(FAILED(hres)) + return NS_OK; + target = &node->event_target; }
- hres = get_node(nsnode, TRUE, &node); - nsIDOMNode_Release(nsnode); - if(FAILED(hres)) - return NS_OK; - hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); if(FAILED(hres)) { - node_release(node); + IEventTarget_Release(&target->IEventTarget_iface); return NS_OK; }
@@ -330,15 +334,15 @@ static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent *
hres = create_document_event(doc, event->event_id == EVENTID_FOCUS ? EVENTID_FOCUSIN : EVENTID_FOCUSOUT, &focus_event); if(SUCCEEDED(hres)) { - dispatch_event(&node->event_target, focus_event); + dispatch_event(target, focus_event); IDOMEvent_Release(&focus_event->IDOMEvent_iface); } }
- dispatch_event(&node->event_target, event); + dispatch_event(target, event);
IDOMEvent_Release(&event->IDOMEvent_iface); - node_release(node); + IEventTarget_Release(&target->IEventTarget_iface); return NS_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 2 + dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/tests/blank_ie10.html | 3 ++ dlls/mshtml/tests/documentmode.js | 5 ++ dlls/mshtml/tests/events.c | 85 +++++++++++++++++++++++++++++-- dlls/mshtml/tests/rsrc.rc | 3 ++ 6 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 dlls/mshtml/tests/blank_ie10.html
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index e669afb7483..3f02f455bbf 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -206,6 +206,8 @@ static const event_info_t event_info[] = { EVENT_BIND_TO_TARGET}, {L"unload", EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD, EVENT_FIXME}, + {L"visibilitychange", EVENT_TYPE_EVENT, DISPID_EVPROP_VISIBILITYCHANGE, + EVENT_FIXME | EVENT_BUBBLES},
/* EVENTID_LAST special entry */ {NULL, EVENT_TYPE_EVENT, 0, 0} diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index f78c4a0f188..97baf9eed7b 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -63,6 +63,7 @@ typedef enum { EVENTID_SUBMIT, EVENTID_TIMEOUT, EVENTID_UNLOAD, + EVENTID_VISIBILITYCHANGE, EVENTID_LAST } eventid_t;
diff --git a/dlls/mshtml/tests/blank_ie10.html b/dlls/mshtml/tests/blank_ie10.html new file mode 100644 index 00000000000..64e6dfaa172 --- /dev/null +++ b/dlls/mshtml/tests/blank_ie10.html @@ -0,0 +1,3 @@ +<html> +<head><meta http-equiv="x-ua-compatible" content="IE=10" /></head> +</html> diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 6b74094110f..6a1a2783062 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,6 +19,11 @@ var compat_version; var tests = [];
+if(window.addEventListener) { + document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); +} + + sync_test("builtin_toString", function() { var tags = [ [ "abbr", "Phrase" ], diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index dcd7160a67d..6d9543db96b 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -97,6 +97,7 @@ DEFINE_EXPECT(submit_onclick_attached_check_cancel); DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); +DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1406,6 +1407,30 @@ static HRESULT WINAPI iframe_onreadystatechange(IDispatchEx *iface, DISPID id, L
EVENT_HANDLER_FUNC_OBJ(iframe_onreadystatechange);
+static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + IDispatchEx *dispex; + HRESULT hres; + BSTR bstr; + + CHECK_EXPECT(visibilitychange); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + + hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + bstr = SysAllocString(L"toString"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &id); + todo_wine + ok(hres == S_OK, "GetDispID("toString") failed: %08lx\n", hres); + SysFreeString(bstr); + + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onvisibilitychange); + static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -2387,6 +2412,54 @@ static void test_focus(IHTMLDocument2 *doc) IHTMLElement4_Release(div); }
+static void test_visibilitychange(IHTMLDocument2 *doc) +{ + if(!winetest_interactive) { + ShowWindow(container_hwnd, SW_SHOW); + pump_msgs(NULL); + } + add_event_listener((IUnknown*)doc, L"visibilitychange", (IDispatch*)&onvisibilitychange_obj, VARIANT_TRUE); + + ShowWindow(container_hwnd, SW_HIDE); + pump_msgs(NULL); + + ShowWindow(container_hwnd, SW_SHOW); + pump_msgs(NULL); + + if(document_mode < 10) { + ShowWindow(container_hwnd, SW_MINIMIZE); + pump_msgs(NULL); + + ShowWindow(container_hwnd, SW_RESTORE); + pump_msgs(NULL); + }else { + /* FIXME: currently not implemented in Wine, so we can't wait for it */ + BOOL *expect = broken(1) ? &called_visibilitychange : NULL; + + SET_EXPECT(visibilitychange); + ShowWindow(container_hwnd, SW_MINIMIZE); + pump_msgs(expect); + todo_wine + CHECK_CALLED(visibilitychange); + + SET_EXPECT(visibilitychange); + ShowWindow(container_hwnd, SW_RESTORE); + pump_msgs(expect); + todo_wine + CHECK_CALLED(visibilitychange); + } + + navigate(doc, document_mode < 10 ? L"blank_ie10.html" : L"blank.html"); + + if(document_mode >= 9) + add_event_listener((IUnknown*)doc, L"visibilitychange", (IDispatch*)&onvisibilitychange_obj, VARIANT_TRUE); + + if(!winetest_interactive) { + ShowWindow(container_hwnd, SW_HIDE); + pump_msgs(NULL); + } +} + static void test_submit(IHTMLDocument2 *doc) { IHTMLElement *elem, *submit; @@ -5091,6 +5164,10 @@ static IHTMLDocument2 *create_document_with_origin(const char *str) return doc; }
+static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProcA(hwnd, msg, wParam, lParam); +}
typedef void (*testfunc_t)(IHTMLDocument2*);
@@ -5154,6 +5231,7 @@ static void run_test_impl(const char *str, const WCHAR *res, testfunc_t test) ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); ok(window != NULL, "window == NULL\n");
+ ok((WNDPROC)GetWindowLongPtrA(container_hwnd, GWLP_WNDPROC) == wnd_proc, "container_hwnd is subclassed\n"); test(doc);
IHTMLWindow2_Release(window); @@ -5176,11 +5254,6 @@ static void run_test_from_res(const WCHAR *res, testfunc_t test) return run_test_impl(NULL, res, test); }
-static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - return DefWindowProcA(hwnd, msg, wParam, lParam); -} - static HWND create_container_window(void) { static const CHAR szHTMLDocumentTest[] = "HTMLDocumentTest"; @@ -5496,6 +5569,8 @@ START_TEST(events) if(is_ie9plus) { run_test_from_res(L"doc_with_prop.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); + run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); + run_test_from_res(L"blank_ie10.html", test_visibilitychange); run_test(empty_doc_ie9_str, test_create_event); }
diff --git a/dlls/mshtml/tests/rsrc.rc b/dlls/mshtml/tests/rsrc.rc index 9bff32a78e9..01b2838be8b 100644 --- a/dlls/mshtml/tests/rsrc.rc +++ b/dlls/mshtml/tests/rsrc.rc @@ -73,6 +73,9 @@ blank2.html HTML "blank.html" /* @makedep: blank.html */ 123 HTML "blank.html"
+/* @makedep: blank_ie10.html */ +blank_ie10.html HTML "blank_ie10.html" + /* @makedep: doc_with_prop.html */ doc_with_prop.html HTML "doc_with_prop.html"
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Rather than hardcoding them individually, so that it's all in one place when adding new ones.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/nsevents.c | 79 +++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 32 deletions(-)
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 305a017d978..d70fea67ca4 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -37,16 +37,45 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
+#define EVENTLISTENER_VTBL(handler) \ + { \ + nsDOMEventListener_QueryInterface, \ + nsDOMEventListener_AddRef, \ + nsDOMEventListener_Release, \ + handler, \ + } +static nsresult NSAPI nsDOMEventListener_QueryInterface(nsIDOMEventListener*,nsIIDRef,void**); +static nsrefcnt NSAPI nsDOMEventListener_AddRef(nsIDOMEventListener*); +static nsrefcnt NSAPI nsDOMEventListener_Release(nsIDOMEventListener*); + typedef struct { nsIDOMEventListener nsIDOMEventListener_iface; nsDocumentEventListener *This; } nsEventListener;
+static nsresult NSAPI handle_blur(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_focus(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_keypress(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*); + +enum doc_event_listener_flags { + BUBBLES = 0x0001, + OVERRIDE = 0x0002, +}; + +static const struct { + eventid_t id; + enum doc_event_listener_flags flags; + nsIDOMEventListenerVtbl vtbl; +} doc_event_listeners[] = { + { EVENTID_BLUR, 0, EVENTLISTENER_VTBL(handle_blur) }, + { EVENTID_FOCUS, 0, EVENTLISTENER_VTBL(handle_focus) }, + { EVENTID_KEYPRESS, BUBBLES, EVENTLISTENER_VTBL(handle_keypress) }, + { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, +}; + struct nsDocumentEventListener { - nsEventListener blur_listener; - nsEventListener focus_listener; - nsEventListener keypress_listener; - nsEventListener load_listener; + nsEventListener listener[ARRAY_SIZE(doc_event_listeners)]; nsEventListener htmlevent_listener;
LONG ref; @@ -346,18 +375,6 @@ static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent * return NS_OK; }
-#define EVENTLISTENER_VTBL(handler) \ - { \ - nsDOMEventListener_QueryInterface, \ - nsDOMEventListener_AddRef, \ - nsDOMEventListener_Release, \ - handler, \ - } - -static const nsIDOMEventListenerVtbl blur_vtbl = EVENTLISTENER_VTBL(handle_blur); -static const nsIDOMEventListenerVtbl focus_vtbl = EVENTLISTENER_VTBL(handle_focus); -static const nsIDOMEventListenerVtbl keypress_vtbl = EVENTLISTENER_VTBL(handle_keypress); -static const nsIDOMEventListenerVtbl load_vtbl = EVENTLISTENER_VTBL(handle_load); static const nsIDOMEventListenerVtbl htmlevent_vtbl = EVENTLISTENER_VTBL(handle_htmlevent);
static void init_event(nsIDOMEventTarget *target, const PRUnichar *type, @@ -438,16 +455,15 @@ void detach_nsevent(HTMLDocumentNode *doc, const WCHAR *type) void release_nsevents(HTMLDocumentNode *doc) { nsDocumentEventListener *listener = doc->nsevent_listener; + unsigned i;
TRACE("%p %p\n", doc, doc->nsevent_listener);
if(!listener) return;
- detach_nslistener(doc, L"blur", &listener->blur_listener, TRUE); - detach_nslistener(doc, L"focus", &listener->focus_listener, TRUE); - detach_nslistener(doc, L"keypress", &listener->keypress_listener, FALSE); - detach_nslistener(doc, L"load", &listener->load_listener, TRUE); + for(i = 0; i < ARRAY_SIZE(doc_event_listeners); i++) + detach_nslistener(doc, get_event_name(doc_event_listeners[i].id), &listener->listener[i], !(doc_event_listeners[i].flags & BUBBLES));
listener->doc = NULL; release_listener(listener); @@ -458,6 +474,7 @@ void init_nsevents(HTMLDocumentNode *doc) { nsDocumentEventListener *listener; nsIDOMEventTarget *target; + unsigned i;
listener = heap_alloc(sizeof(nsDocumentEventListener)); if(!listener) @@ -468,11 +485,9 @@ void init_nsevents(HTMLDocumentNode *doc) listener->ref = 1; listener->doc = doc;
- init_listener(&listener->blur_listener, listener, &blur_vtbl); - init_listener(&listener->focus_listener, listener, &focus_vtbl); - init_listener(&listener->keypress_listener, listener, &keypress_vtbl); - init_listener(&listener->load_listener, listener, &load_vtbl); - init_listener(&listener->htmlevent_listener, listener, &htmlevent_vtbl); + for(i = 0; i < ARRAY_SIZE(doc_event_listeners); i++) + init_listener(&listener->listener[i], listener, &doc_event_listeners[i].vtbl); + init_listener(&listener->htmlevent_listener, listener, &htmlevent_vtbl);
doc->nsevent_listener = listener;
@@ -480,13 +495,13 @@ void init_nsevents(HTMLDocumentNode *doc) if(!target) return;
- init_event(target, L"blur", &listener->blur_listener.nsIDOMEventListener_iface, TRUE); - init_event(target, L"focus", &listener->focus_listener.nsIDOMEventListener_iface, TRUE); - init_event(target, L"keypress", &listener->keypress_listener.nsIDOMEventListener_iface, FALSE); - init_event(target, L"load", &listener->load_listener.nsIDOMEventListener_iface, TRUE); + for(i = 0; i < ARRAY_SIZE(doc_event_listeners); i++) { + init_event(target, get_event_name(doc_event_listeners[i].id), &listener->listener[i].nsIDOMEventListener_iface, + !(doc_event_listeners[i].flags & BUBBLES));
- nsIDOMEventTarget_Release(target); + if(doc_event_listeners[i].flags & OVERRIDE) + doc->event_vector[doc_event_listeners[i].id] = TRUE; + }
- /* handle_load already takes care of dispatching the load event */ - doc->event_vector[EVENTID_LOAD] = TRUE; + nsIDOMEventTarget_Release(target); }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 120 +++++++++++++++++++++++++++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/mshtml_private_iface.idl | 14 ++++ dlls/mshtml/nsevents.c | 22 +++++ dlls/mshtml/tests/documentmode.js | 17 ++++ 6 files changed, 175 insertions(+)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 3f02f455bbf..c8fca5d4936 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -68,6 +68,7 @@ typedef enum { EVENT_TYPE_MOUSE, EVENT_TYPE_FOCUS, EVENT_TYPE_UIEVENT, + EVENT_TYPE_PAGETRANSITION, EVENT_TYPE_MESSAGE, EVENT_TYPE_PROGRESS, EVENT_TYPE_STORAGE, @@ -82,6 +83,7 @@ static const WCHAR *event_types[] = { L"MouseEvent", L"Event", /* FIXME */ L"UIEvent", + L"Event", /* FIXME */ L"MessageEvent", L"ProgressEvent", L"StorageEvent", @@ -182,6 +184,8 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"msthumbnailclick", EVENT_TYPE_MOUSE, DISPID_EVPROP_ONMSTHUMBNAILCLICK, EVENT_FIXME}, + {L"pageshow", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGESHOW, + 0}, {L"paste", EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE, EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"progress", EVENT_TYPE_PROGRESS, DISPID_EVPROP_PROGRESS, @@ -2209,6 +2213,98 @@ static void DOMKeyboardEvent_destroy(DOMEvent *event) nsIDOMKeyEvent_Release(This->nsevent); }
+typedef struct { + DOMEvent event; + IWinePageTransitionEvent IWinePageTransitionEvent_iface; +} DOMPageTransitionEvent; + +static inline DOMPageTransitionEvent *impl_from_IWinePageTransitionEvent(IWinePageTransitionEvent *iface) +{ + return CONTAINING_RECORD(iface, DOMPageTransitionEvent, IWinePageTransitionEvent_iface); +} + +static HRESULT WINAPI DOMPageTransitionEvent_QueryInterface(IWinePageTransitionEvent *iface, REFIID riid, void **ppv) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDOMEvent_QueryInterface(&This->event.IDOMEvent_iface, riid, ppv); +} + +static ULONG WINAPI DOMPageTransitionEvent_AddRef(IWinePageTransitionEvent *iface) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDOMEvent_AddRef(&This->event.IDOMEvent_iface); +} + +static ULONG WINAPI DOMPageTransitionEvent_Release(IWinePageTransitionEvent *iface) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDOMEvent_Release(&This->event.IDOMEvent_iface); +} + +static HRESULT WINAPI DOMPageTransitionEvent_GetTypeInfoCount(IWinePageTransitionEvent *iface, UINT *pctinfo) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_GetTypeInfoCount(&This->event.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI DOMPageTransitionEvent_GetTypeInfo(IWinePageTransitionEvent *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_GetTypeInfo(&This->event.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI DOMPageTransitionEvent_GetIDsOfNames(IWinePageTransitionEvent *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_GetIDsOfNames(&This->event.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI DOMPageTransitionEvent_Invoke(IWinePageTransitionEvent *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_Invoke(&This->event.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI DOMPageTransitionEvent_get_persisted(IWinePageTransitionEvent *iface, VARIANT_BOOL *p) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + + FIXME("(%p)->(%p): always returning FALSE\n", This, p); + + *p = VARIANT_FALSE; + return S_OK; +} + +static const IWinePageTransitionEventVtbl DOMPageTransitionEventVtbl = { + DOMPageTransitionEvent_QueryInterface, + DOMPageTransitionEvent_AddRef, + DOMPageTransitionEvent_Release, + DOMPageTransitionEvent_GetTypeInfoCount, + DOMPageTransitionEvent_GetTypeInfo, + DOMPageTransitionEvent_GetIDsOfNames, + DOMPageTransitionEvent_Invoke, + DOMPageTransitionEvent_get_persisted +}; + +static DOMPageTransitionEvent *DOMPageTransitionEvent_from_DOMEvent(DOMEvent *event) +{ + return CONTAINING_RECORD(event, DOMPageTransitionEvent, event); +} + +static void *DOMPageTransitionEvent_query_interface(DOMEvent *event, REFIID riid) +{ + DOMPageTransitionEvent *page_transition_event = DOMPageTransitionEvent_from_DOMEvent(event); + if(IsEqualGUID(&IID_IWinePageTransitionEvent, riid)) + return &page_transition_event->IWinePageTransitionEvent_iface; + return NULL; +} + typedef struct { DOMEvent event; IDOMCustomEvent IDOMCustomEvent_iface; @@ -2837,6 +2933,20 @@ static dispex_static_data_t DOMKeyboardEvent_dispex = { DOMKeyboardEvent_iface_tids };
+static void DOMPageTransitionEvent_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode >= COMPAT_MODE_IE11) + dispex_info_add_interface(info, IWinePageTransitionEvent_tid, NULL); +} + +dispex_static_data_t DOMPageTransitionEvent_dispex = { + L"PageTransitionEvent", + NULL, + DispDOMEvent_tid, + DOMEvent_iface_tids, + DOMPageTransitionEvent_init_dispex_info +}; + static const tid_t DOMCustomEvent_iface_tids[] = { IDOMEvent_tid, IDOMCustomEvent_tid, @@ -2961,6 +3071,15 @@ static DOMEvent *keyboard_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_ return &keyboard_event->ui_event.event; }
+static DOMEvent *page_transition_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +{ + DOMPageTransitionEvent *page_transition_event = event_ctor(sizeof(DOMCustomEvent), &DOMPageTransitionEvent_dispex, + DOMPageTransitionEvent_query_interface, NULL, nsevent, event_id, compat_mode); + if(!page_transition_event) return NULL; + page_transition_event->IWinePageTransitionEvent_iface.lpVtbl = &DOMPageTransitionEventVtbl; + return &page_transition_event->event; +} + static DOMEvent *custom_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) { DOMCustomEvent *custom_event = event_ctor(sizeof(DOMCustomEvent), &DOMCustomEvent_dispex, @@ -3015,6 +3134,7 @@ static const struct { [EVENT_TYPE_CLIPBOARD] = { NULL, generic_event_ctor }, [EVENT_TYPE_FOCUS] = { NULL, generic_event_ctor }, [EVENT_TYPE_DRAG] = { NULL, generic_event_ctor }, + [EVENT_TYPE_PAGETRANSITION] = { NULL, page_transition_event_ctor }, [EVENT_TYPE_CUSTOM] = { &IID_nsIDOMCustomEvent, custom_event_ctor }, [EVENT_TYPE_PROGRESS] = { &IID_nsIDOMProgressEvent, progress_event_ctor }, [EVENT_TYPE_MESSAGE] = { NULL, message_event_ctor }, diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 97baf9eed7b..e49c47d6988 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -51,6 +51,7 @@ typedef enum { EVENTID_MOUSEUP, EVENTID_MOUSEWHEEL, EVENTID_MSTHUMBNAILCLICK, + EVENTID_PAGESHOW, EVENTID_PASTE, EVENTID_PROGRESS, EVENTID_READYSTATECHANGE, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e3971258b13..7e7dd358c8d 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -288,6 +288,7 @@ typedef struct EventTarget EventTarget; XIID(IWineHTMLElementPrivate) \ XIID(IWineHTMLWindowPrivate) \ XIID(IWineHTMLWindowCompatPrivate) \ + XIID(IWinePageTransitionEvent) \ XIID(IWineXMLHttpRequestPrivate) \ XIID(IWineMSHTMLConsole) \ XIID(IWineMSHTMLMediaQueryList) diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index fc023473cc9..8e4a64bda39 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -162,6 +162,20 @@ interface IWineDOMTokenList : IDispatch HRESULT toString([retval, out] BSTR *String); }
+[ + odl, + oleautomation, + dual, + hidden, + uuid(25508c5d-6a54-6888-8f41-75ff3ae8706b) +] +interface IWinePageTransitionEvent : IDispatch +{ + [propget, id(1)] + HRESULT persisted([retval, out] VARIANT_BOOL *ret); +} + + const long DISPID_IWINEXMLHTTPREQUESTPRIVATE_RESPONSE = 1; const long DISPID_IWINEXMLHTTPREQUESTPRIVATE_RESPONSETYPE = 2; const long DISPID_IWINEXMLHTTPREQUESTPRIVATE_UPLOAD = 3; diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index d70fea67ca4..0b76ebec5c3 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -56,6 +56,7 @@ typedef struct { static nsresult NSAPI handle_blur(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_focus(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_keypress(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_pageshow(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*);
enum doc_event_listener_flags { @@ -71,6 +72,7 @@ static const struct { { EVENTID_BLUR, 0, EVENTLISTENER_VTBL(handle_blur) }, { EVENTID_FOCUS, 0, EVENTLISTENER_VTBL(handle_focus) }, { EVENTID_KEYPRESS, BUBBLES, EVENTLISTENER_VTBL(handle_keypress) }, + { EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), }, { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, };
@@ -208,6 +210,26 @@ static nsresult NSAPI handle_keypress(nsIDOMEventListener *iface, return NS_OK; }
+static nsresult NSAPI handle_pageshow(nsIDOMEventListener *iface, nsIDOMEvent *nsevent) +{ + nsEventListener *This = impl_from_nsIDOMEventListener(iface); + HTMLDocumentNode *doc = This->This->doc; + HTMLInnerWindow *window; + DOMEvent *event; + HRESULT hres; + + if(!doc || !(window = doc->window) || !doc->dom_document || doc->document_mode < COMPAT_MODE_IE11) + return NS_OK; + + hres = create_document_event(doc, EVENTID_PAGESHOW, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + + return NS_OK; +} + static void handle_docobj_load(HTMLDocumentObj *doc) { IOleCommandTarget *olecmd = NULL; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 6a1a2783062..ca942501381 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,10 +19,27 @@ var compat_version; var tests = [];
+var pageshow_fired = false; if(window.addEventListener) { + window.addEventListener("pageshow", function(e) { + pageshow_fired = true; + + var r = Object.prototype.toString.call(e); + todo_wine. + ok(r === "[object PageTransitionEvent]", "pageshow toString = " + r); + ok("persisted" in e, "'persisted' not in pageshow event"); + ok(document.readyState === "complete", "pageshow readyState = " + document.readyState); + }, true); + document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); }
+sync_test("page transition events", function() { + if(document.documentMode < 11) + ok(pageshow_fired === false, "pageshow fired"); + else + ok(pageshow_fired === true, "pageshow not fired"); +});
sync_test("builtin_toString", function() { var tags = [
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/nsevents.c | 23 +++++++ dlls/mshtml/tests/documentmode.js | 5 ++ dlls/mshtml/tests/events.c | 103 ++++++++++++++++++++++++++++++ dlls/mshtml/tests/iframe.html | 4 ++ dlls/mshtml/tests/rsrc.rc | 3 + 5 files changed, 138 insertions(+) create mode 100644 dlls/mshtml/tests/iframe.html
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 0b76ebec5c3..7002a2cc71d 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -58,6 +58,7 @@ static nsresult NSAPI handle_focus(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_keypress(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_pageshow(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_beforeunload(nsIDOMEventListener*,nsIDOMEvent*);
enum doc_event_listener_flags { BUBBLES = 0x0001, @@ -74,6 +75,7 @@ static const struct { { EVENTID_KEYPRESS, BUBBLES, EVENTLISTENER_VTBL(handle_keypress) }, { EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), }, { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, + { EVENTID_BEFOREUNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_beforeunload), }, };
struct nsDocumentEventListener { @@ -333,6 +335,27 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event return NS_OK; }
+static nsresult NSAPI handle_beforeunload(nsIDOMEventListener *iface, nsIDOMEvent *nsevent) +{ + nsEventListener *This = impl_from_nsIDOMEventListener(iface); + HTMLDocumentNode *doc = This->This->doc; + HTMLInnerWindow *window; + DOMEvent *event; + HRESULT hres; + + if(!doc || !(window = doc->window)) + return NS_OK; + + /* Gecko dispatches this to the document, but IE dispatches it to the window */ + hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + + return NS_OK; +} + static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent *nsevent) { nsEventListener *This = impl_from_nsIDOMEventListener(iface); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ca942501381..246974fb82e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -20,6 +20,8 @@ var compat_version; var tests = [];
var pageshow_fired = false; +window.onbeforeunload = function() { ok(false, "beforeunload fired"); }; + if(window.addEventListener) { window.addEventListener("pageshow", function(e) { pageshow_fired = true; @@ -32,6 +34,9 @@ if(window.addEventListener) { }, true);
document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); + document.addEventListener("beforeunload", function() { ok(false, "beforeunload fired on document"); }); +}else { + document.attachEvent("onbeforeunload", function() { ok(false, "beforeunload fired on document"); }); }
sync_test("page transition events", function() { diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 6d9543db96b..e12f4f666a2 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -98,6 +98,8 @@ DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); DEFINE_EXPECT(visibilitychange); +DEFINE_EXPECT(onbeforeunload); +DEFINE_EXPECT(iframe_onbeforeunload); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1431,6 +1433,27 @@ static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lci
EVENT_HANDLER_FUNC_OBJ(onvisibilitychange);
+static HRESULT WINAPI onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(onbeforeunload); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onbeforeunload); + +static HRESULT WINAPI iframe_onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_onbeforeunload); + ok(called_onbeforeunload, "beforeunload not fired on parent window before iframe\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(iframe_onbeforeunload); + static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -2460,6 +2483,85 @@ static void test_visibilitychange(IHTMLDocument2 *doc) } }
+static void test_unload_event(IHTMLDocument2 *doc) +{ + IHTMLDocument2 *child_doc; + IHTMLFrameBase2 *iframe; + IHTMLDocument6 *doc6; + IHTMLElement2 *elem; + IHTMLWindow2 *child; + HRESULT hres; + VARIANT v; + BSTR bstr; + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&onbeforeunload_obj; + hres = IHTMLWindow2_put_onbeforeunload(window, v); + ok(hres == S_OK, "put_onbeforeunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(window, &v); + ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onbeforeunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v)); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6 iface: %08lx\n", hres); + bstr = SysAllocString(L"ifr"); + hres = IHTMLDocument6_getElementById(doc6, bstr, &elem); + ok(hres == S_OK, "getElementById failed: %08lx\n", hres); + IHTMLDocument6_Release(doc6); + SysFreeString(bstr); + + hres = IHTMLElement2_QueryInterface(elem, &IID_IHTMLFrameBase2, (void**)&iframe); + ok(hres == S_OK, "Could not get IHTMLFrameBase2 iface: %08lx\n", hres); + IHTMLElement2_Release(elem); + hres = IHTMLFrameBase2_get_contentWindow(iframe, &child); + ok(hres == S_OK, "get_contentWindow failed: %08lx\n", hres); + IHTMLFrameBase2_Release(iframe); + + hres = IHTMLWindow2_get_document(child, &child_doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&iframe_onbeforeunload_obj; + hres = IHTMLWindow2_put_onbeforeunload(child, v); + ok(hres == S_OK, "put_onbeforeunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(child, &v); + ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onbeforeunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&iframe_onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v)); + + add_event_listener((IUnknown*)doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE); + add_event_listener((IUnknown*)child_doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE); + IHTMLDocument2_Release(child_doc); + IHTMLWindow2_Release(child); + + SET_EXPECT(onbeforeunload); + SET_EXPECT(iframe_onbeforeunload); + navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_onbeforeunload); + CHECK_CALLED(onbeforeunload); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(window, &v); + ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_NULL, "V_VT(onbeforeunload) = %d\n", V_VT(&v)); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&onbeforeunload_obj; + hres = IHTMLWindow2_put_onbeforeunload(window, v); + ok(hres == S_OK, "put_onbeforeunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(window, &v); + ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onbeforeunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v)); +} + static void test_submit(IHTMLDocument2 *doc) { IHTMLElement *elem, *submit; @@ -5571,6 +5673,7 @@ START_TEST(events) run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); run_test_from_res(L"blank_ie10.html", test_visibilitychange); + run_test_from_res(L"iframe.html", test_unload_event); run_test(empty_doc_ie9_str, test_create_event); }
diff --git a/dlls/mshtml/tests/iframe.html b/dlls/mshtml/tests/iframe.html new file mode 100644 index 00000000000..ec08a0eb19a --- /dev/null +++ b/dlls/mshtml/tests/iframe.html @@ -0,0 +1,4 @@ +<html> +<head><meta http-equiv="x-ua-compatible" content="IE=11" /></head> +<body><iframe src="about:blank" id="ifr"></iframe></body> +</html> diff --git a/dlls/mshtml/tests/rsrc.rc b/dlls/mshtml/tests/rsrc.rc index 01b2838be8b..e60e37198de 100644 --- a/dlls/mshtml/tests/rsrc.rc +++ b/dlls/mshtml/tests/rsrc.rc @@ -82,6 +82,9 @@ doc_with_prop.html HTML "doc_with_prop.html" /* @makedep: doc_with_prop_ie9.html */ doc_with_prop_ie9.html HTML "doc_with_prop_ie9.html"
+/* @makedep: iframe.html */ +iframe.html HTML "iframe.html" + /* For res: protocol test: */
/* @makedep: jstest.html */
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 2 +- dlls/mshtml/mshtml_private.h | 3 +- dlls/mshtml/nsevents.c | 23 +++++++++ dlls/mshtml/tests/documentmode.js | 12 +++++ dlls/mshtml/tests/events.c | 78 +++++++++++++++++++++++++++++++ dlls/mshtml/tests/script.c | 22 +++++++++ dlls/mshtml/view.c | 33 +++++++++++++ 7 files changed, 171 insertions(+), 2 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index c8fca5d4936..7b82d823bd9 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -209,7 +209,7 @@ static const event_info_t event_info[] = { {L"timeout", EVENT_TYPE_PROGRESS, DISPID_EVPROP_TIMEOUT, EVENT_BIND_TO_TARGET}, {L"unload", EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD, - EVENT_FIXME}, + EVENT_BIND_TO_TARGET}, {L"visibilitychange", EVENT_TYPE_EVENT, DISPID_EVPROP_VISIBILITYCHANGE, EVENT_FIXME | EVENT_BUBBLES},
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7e7dd358c8d..d9e2d93d220 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -924,7 +924,8 @@ struct HTMLDocumentNode {
nsIDOMDocument *dom_document; nsIDOMHTMLDocument *html_document; - BOOL content_ready; + BOOL content_ready : 1; + BOOL unload_sent : 1;
IHTMLDOMImplementation *dom_implementation; IHTMLNamespaceCollection *namespaces; diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 7002a2cc71d..edc90563dd9 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -59,6 +59,7 @@ static nsresult NSAPI handle_keypress(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_pageshow(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_beforeunload(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_unload(nsIDOMEventListener*,nsIDOMEvent*);
enum doc_event_listener_flags { BUBBLES = 0x0001, @@ -76,6 +77,7 @@ static const struct { { EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), }, { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, { EVENTID_BEFOREUNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_beforeunload), }, + { EVENTID_UNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_unload) }, };
struct nsDocumentEventListener { @@ -356,6 +358,27 @@ static nsresult NSAPI handle_beforeunload(nsIDOMEventListener *iface, nsIDOMEven return NS_OK; }
+static nsresult NSAPI handle_unload(nsIDOMEventListener *iface, nsIDOMEvent *nsevent) +{ + nsEventListener *This = impl_from_nsIDOMEventListener(iface); + HTMLDocumentNode *doc = This->This->doc; + HTMLInnerWindow *window; + DOMEvent *event; + HRESULT hres; + + if(!doc || !(window = doc->window) || doc->unload_sent) + return NS_OK; + doc->unload_sent = TRUE; + + hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + + return NS_OK; +} + static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent *nsevent) { nsEventListener *This = impl_from_nsIDOMEventListener(iface); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 246974fb82e..0669073771c 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -20,7 +20,12 @@ var compat_version; var tests = [];
var pageshow_fired = false; +document.doc_unload_events_called = false; window.onbeforeunload = function() { ok(false, "beforeunload fired"); }; +window.onunload = function() { + document.doc_unload_events_called = true; + ok(document.readyState === "complete", "unload readyState = " + document.readyState); +};
if(window.addEventListener) { window.addEventListener("pageshow", function(e) { @@ -35,8 +40,10 @@ if(window.addEventListener) {
document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); document.addEventListener("beforeunload", function() { ok(false, "beforeunload fired on document"); }); + document.addEventListener("unload", function() { ok(false, "unload fired on document"); }); }else { document.attachEvent("onbeforeunload", function() { ok(false, "beforeunload fired on document"); }); + document.attachEvent("onunload", function() { ok(false, "unload fired on document"); }); }
sync_test("page transition events", function() { @@ -44,6 +51,11 @@ sync_test("page transition events", function() { ok(pageshow_fired === false, "pageshow fired"); else ok(pageshow_fired === true, "pageshow not fired"); + + if(document.body.addEventListener) + document.body.addEventListener("unload", function() { ok(false, "unload fired on document.body"); }); + else + document.body.attachEvent("onunload", function() { ok(false, "unload fired on document.body"); }); });
sync_test("builtin_toString", function() { diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index e12f4f666a2..4e7238e119c 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -100,6 +100,8 @@ DEFINE_EXPECT(iframe_onload); DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(onbeforeunload); DEFINE_EXPECT(iframe_onbeforeunload); +DEFINE_EXPECT(onunload); +DEFINE_EXPECT(iframe_onunload); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1448,12 +1450,39 @@ static HRESULT WINAPI iframe_onbeforeunload(IDispatchEx *iface, DISPID id, LCID { CHECK_EXPECT(iframe_onbeforeunload); ok(called_onbeforeunload, "beforeunload not fired on parent window before iframe\n"); + ok(!called_onunload, "unload fired on parent window before beforeunload on iframe\n"); + ok(!called_iframe_onunload, "unload fired before beforeunload on iframe\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; }
EVENT_HANDLER_FUNC_OBJ(iframe_onbeforeunload);
+static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(onunload); + if(expect_iframe_onunload) { + ok(called_onbeforeunload, "beforeunload not fired before unload\n"); + ok(called_iframe_onbeforeunload, "beforeunload not fired on iframe before unload\n"); + } + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onunload); + +static HRESULT WINAPI iframe_onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_onunload); + ok(called_onunload, "unload not fired on parent window before iframe\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(iframe_onunload); + static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -2494,6 +2523,17 @@ static void test_unload_event(IHTMLDocument2 *doc) VARIANT v; BSTR bstr;
+ V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&onunload_obj; + hres = IHTMLWindow2_put_onunload(window, v); + ok(hres == S_OK, "put_onunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onunload(window, &v); + ok(hres == S_OK, "get_onunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v)); + V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = (IDispatch*)&onbeforeunload_obj; hres = IHTMLWindow2_put_onbeforeunload(window, v); @@ -2523,6 +2563,17 @@ static void test_unload_event(IHTMLDocument2 *doc) hres = IHTMLWindow2_get_document(child, &child_doc); ok(hres == S_OK, "get_document failed: %08lx\n", hres);
+ V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&iframe_onunload_obj; + hres = IHTMLWindow2_put_onunload(child, v); + ok(hres == S_OK, "put_onunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onunload(child, &v); + ok(hres == S_OK, "get_onunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&iframe_onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v)); + V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = (IDispatch*)&iframe_onbeforeunload_obj; hres = IHTMLWindow2_put_onbeforeunload(child, v); @@ -2536,12 +2587,18 @@ static void test_unload_event(IHTMLDocument2 *doc)
add_event_listener((IUnknown*)doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE); add_event_listener((IUnknown*)child_doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE); + add_event_listener((IUnknown*)doc, L"unload", (IDispatch*)&nocall_obj, VARIANT_TRUE); + add_event_listener((IUnknown*)child_doc, L"unload", (IDispatch*)&nocall_obj, VARIANT_TRUE); IHTMLDocument2_Release(child_doc); IHTMLWindow2_Release(child);
SET_EXPECT(onbeforeunload); SET_EXPECT(iframe_onbeforeunload); + SET_EXPECT(onunload); + SET_EXPECT(iframe_onunload); navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_onunload); + CHECK_CALLED(onunload); CHECK_CALLED(iframe_onbeforeunload); CHECK_CALLED(onbeforeunload);
@@ -2550,6 +2607,17 @@ static void test_unload_event(IHTMLDocument2 *doc) ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); ok(V_VT(&v) == VT_NULL, "V_VT(onbeforeunload) = %d\n", V_VT(&v));
+ V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&onunload_obj; + hres = IHTMLWindow2_put_onunload(window, v); + ok(hres == S_OK, "put_onunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onunload(window, &v); + ok(hres == S_OK, "get_onunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v)); + V_VT(&v) = VT_DISPATCH; V_DISPATCH(&v) = (IDispatch*)&onbeforeunload_obj; hres = IHTMLWindow2_put_onbeforeunload(window, v); @@ -2560,6 +2628,16 @@ static void test_unload_event(IHTMLDocument2 *doc) ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); ok(V_VT(&v) == VT_DISPATCH, "V_VT(onbeforeunload) = %d\n", V_VT(&v)); ok(V_DISPATCH(&v) == (IDispatch*)&onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v)); + + IOleDocumentView_Show(view, FALSE); + + SET_EXPECT(onunload); + IOleDocumentView_CloseView(view, 0); + CHECK_CALLED(onunload); + + IOleDocumentView_SetInPlaceSite(view, NULL); + IOleDocumentView_Release(view); + view = NULL; }
static void test_submit(IHTMLDocument2 *doc) diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index e71f178e51a..d7d7e7361c3 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -3892,8 +3892,10 @@ static void test_simple_script(void)
static void run_from_moniker(IMoniker *mon) { + DISPID dispid = DISPID_UNKNOWN; IPersistMoniker *persist; IHTMLDocument2 *doc; + BSTR bstr; MSG msg; HRESULT hres;
@@ -3921,8 +3923,28 @@ static void run_from_moniker(IMoniker *mon)
CHECK_CALLED(external_success);
+ /* check prop set by events fired during document unload */ + bstr = SysAllocString(L"doc_unload_events_called"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + SysFreeString(bstr); + if(hres == DISP_E_UNKNOWNNAME) + dispid = DISPID_UNKNOWN; + else + ok(hres == S_OK, "GetIDsOfNames failed %08lx\n", hres); + free_registered_streams(); set_client_site(doc, FALSE); + + if(dispid != DISPID_UNKNOWN) { + DISPPARAMS dp = { 0 }; + UINT argerr; + VARIANT v; + + hres = IHTMLDocument2_Invoke(doc, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v, NULL, &argerr); + ok(hres == S_OK, "Invoke failed %08lx\n", hres); + ok(V_VT(&v) == VT_BOOL, "V_VT(doc_unload_events_called) = %d\n", V_VT(&v)); + ok(V_BOOL(&v) == VARIANT_TRUE, "doc_unload_events_called is not true\n"); + } IHTMLDocument2_Release(doc); }
diff --git a/dlls/mshtml/view.c b/dlls/mshtml/view.c index 04b35e43039..b54b1d6967b 100644 --- a/dlls/mshtml/view.c +++ b/dlls/mshtml/view.c @@ -31,6 +31,7 @@ #include "wine/debug.h"
#include "mshtml_private.h" +#include "htmlevent.h"
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
@@ -407,6 +408,37 @@ HRESULT call_set_active_object(IOleInPlaceUIWindow *window, IOleInPlaceActiveObj return IOleInPlaceUIWindow_SetActiveObject(window, act_obj, act_obj ? html_documentW : NULL); }
+static void send_unload_events_impl(HTMLInnerWindow *window) +{ + HTMLOuterWindow *child; + DOMEvent *event; + HRESULT hres; + + if(!window) + return; + + if(window->doc) { + window->doc->unload_sent = TRUE; + + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + } + + LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) + send_unload_events_impl(child->base.inner_window); +} + +static void send_unload_events(HTMLDocumentObj *doc) +{ + if(!doc->doc_node || !doc->window || !doc->doc_node->content_ready || doc->doc_node->unload_sent) + return; + + send_unload_events_impl(doc->window->base.inner_window); +} + /********************************************************** * IOleDocumentView implementation */ @@ -670,6 +702,7 @@ static HRESULT WINAPI OleDocumentView_CloseView(IOleDocumentView *iface, DWORD d if(dwReserved) WARN("dwReserved = %ld\n", dwReserved);
+ send_unload_events(This); IOleDocumentView_Show(iface, FALSE); return S_OK; }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 2 ++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/nsevents.c | 22 ++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 17 +++++++++++++- dlls/mshtml/tests/events.c | 37 ++++++++++++++++++++++++++++++- dlls/mshtml/view.c | 14 ++++++++++-- 6 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 7b82d823bd9..01a385130b1 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -184,6 +184,8 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"msthumbnailclick", EVENT_TYPE_MOUSE, DISPID_EVPROP_ONMSTHUMBNAILCLICK, EVENT_FIXME}, + {L"pagehide", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGEHIDE, + 0}, {L"pageshow", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGESHOW, 0}, {L"paste", EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE, diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index e49c47d6988..a6d1f734a40 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -51,6 +51,7 @@ typedef enum { EVENTID_MOUSEUP, EVENTID_MOUSEWHEEL, EVENTID_MSTHUMBNAILCLICK, + EVENTID_PAGEHIDE, EVENTID_PAGESHOW, EVENTID_PASTE, EVENTID_PROGRESS, diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index edc90563dd9..0248737b012 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -57,6 +57,7 @@ static nsresult NSAPI handle_blur(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_focus(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_keypress(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_pageshow(nsIDOMEventListener*,nsIDOMEvent*); +static nsresult NSAPI handle_pagehide(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_beforeunload(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_unload(nsIDOMEventListener*,nsIDOMEvent*); @@ -75,6 +76,7 @@ static const struct { { EVENTID_FOCUS, 0, EVENTLISTENER_VTBL(handle_focus) }, { EVENTID_KEYPRESS, BUBBLES, EVENTLISTENER_VTBL(handle_keypress) }, { EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), }, + { EVENTID_PAGEHIDE, OVERRIDE, EVENTLISTENER_VTBL(handle_pagehide), }, { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, { EVENTID_BEFOREUNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_beforeunload), }, { EVENTID_UNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_unload) }, @@ -234,6 +236,26 @@ static nsresult NSAPI handle_pageshow(nsIDOMEventListener *iface, nsIDOMEvent *n return NS_OK; }
+static nsresult NSAPI handle_pagehide(nsIDOMEventListener *iface, nsIDOMEvent *nsevent) +{ + nsEventListener *This = impl_from_nsIDOMEventListener(iface); + HTMLDocumentNode *doc = This->This->doc; + HTMLInnerWindow *window; + DOMEvent *event; + HRESULT hres; + + if(!doc || !(window = doc->window) || !doc->dom_document || doc->document_mode < COMPAT_MODE_IE11 || doc->unload_sent) + return NS_OK; + + hres = create_document_event(doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + + return NS_OK; +} + static void handle_docobj_load(HTMLDocumentObj *doc) { IOleCommandTarget *olecmd = NULL; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0669073771c..33d60f7e835 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,12 +19,16 @@ var compat_version; var tests = [];
-var pageshow_fired = false; +var pageshow_fired = false, pagehide_fired = false; document.doc_unload_events_called = false; window.onbeforeunload = function() { ok(false, "beforeunload fired"); }; window.onunload = function() { document.doc_unload_events_called = true; ok(document.readyState === "complete", "unload readyState = " + document.readyState); + if(document.documentMode < 11) + ok(pagehide_fired === false, "pagehide fired before unload"); + else + ok(pagehide_fired === true, "pagehide not fired before unload"); };
if(window.addEventListener) { @@ -38,6 +42,16 @@ if(window.addEventListener) { ok(document.readyState === "complete", "pageshow readyState = " + document.readyState); }, true);
+ window.addEventListener("pagehide", function(e) { + pagehide_fired = true; + ok(document.documentMode >= 11, "pagehide fired"); + + var r = Object.prototype.toString.call(e); + todo_wine. + ok(r === "[object PageTransitionEvent]", "pagehide toString = " + r); + ok("persisted" in e, "'persisted' not in pagehide event"); + }, true); + document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); document.addEventListener("beforeunload", function() { ok(false, "beforeunload fired on document"); }); document.addEventListener("unload", function() { ok(false, "unload fired on document"); }); @@ -51,6 +65,7 @@ sync_test("page transition events", function() { ok(pageshow_fired === false, "pageshow fired"); else ok(pageshow_fired === true, "pageshow not fired"); + ok(pagehide_fired === false, "pagehide fired");
if(document.body.addEventListener) document.body.addEventListener("unload", function() { ok(false, "unload fired on document.body"); }); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 4e7238e119c..643993bc475 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -101,7 +101,9 @@ DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(onbeforeunload); DEFINE_EXPECT(iframe_onbeforeunload); DEFINE_EXPECT(onunload); +DEFINE_EXPECT(pagehide); DEFINE_EXPECT(iframe_onunload); +DEFINE_EXPECT(iframe_pagehide); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1458,6 +1460,17 @@ static HRESULT WINAPI iframe_onbeforeunload(IDispatchEx *iface, DISPID id, LCID
EVENT_HANDLER_FUNC_OBJ(iframe_onbeforeunload);
+static HRESULT WINAPI pagehide(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(pagehide); + ok(!called_onunload, "unload fired before pagehide\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(pagehide); + static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -1465,18 +1478,34 @@ static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wF if(expect_iframe_onunload) { ok(called_onbeforeunload, "beforeunload not fired before unload\n"); ok(called_iframe_onbeforeunload, "beforeunload not fired on iframe before unload\n"); - } + ok(called_pagehide, "pagehide not fired before unload\n"); + }else + ok(!called_pagehide, "pagehide fired before unload in quirks mode\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; }
EVENT_HANDLER_FUNC_OBJ(onunload);
+static HRESULT WINAPI iframe_pagehide(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_pagehide); + ok(called_pagehide, "pagehide not fired on parent window before iframe\n"); + ok(called_onunload, "unload not fired on parent window before pagehide on iframe\n"); + ok(!called_iframe_onunload, "unload fired before pagehide on iframe\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(iframe_pagehide); + static HRESULT WINAPI iframe_onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { CHECK_EXPECT(iframe_onunload); ok(called_onunload, "unload not fired on parent window before iframe\n"); + ok(called_iframe_pagehide, "pagehide not fired before unload on iframe\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; } @@ -2585,6 +2614,8 @@ static void test_unload_event(IHTMLDocument2 *doc) ok(V_VT(&v) == VT_DISPATCH, "V_VT(onbeforeunload) = %d\n", V_VT(&v)); ok(V_DISPATCH(&v) == (IDispatch*)&iframe_onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v));
+ add_event_listener((IUnknown*)window, L"pagehide", (IDispatch*)&pagehide_obj, VARIANT_TRUE); + add_event_listener((IUnknown*)child, L"pagehide", (IDispatch*)&iframe_pagehide_obj, VARIANT_TRUE); add_event_listener((IUnknown*)doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE); add_event_listener((IUnknown*)child_doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE); add_event_listener((IUnknown*)doc, L"unload", (IDispatch*)&nocall_obj, VARIANT_TRUE); @@ -2595,9 +2626,13 @@ static void test_unload_event(IHTMLDocument2 *doc) SET_EXPECT(onbeforeunload); SET_EXPECT(iframe_onbeforeunload); SET_EXPECT(onunload); + SET_EXPECT(pagehide); SET_EXPECT(iframe_onunload); + SET_EXPECT(iframe_pagehide); navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_pagehide); CHECK_CALLED(iframe_onunload); + CHECK_CALLED(pagehide); CHECK_CALLED(onunload); CHECK_CALLED(iframe_onbeforeunload); CHECK_CALLED(onbeforeunload); diff --git a/dlls/mshtml/view.c b/dlls/mshtml/view.c index b54b1d6967b..063f7afab9d 100644 --- a/dlls/mshtml/view.c +++ b/dlls/mshtml/view.c @@ -417,9 +417,19 @@ static void send_unload_events_impl(HTMLInnerWindow *window) if(!window) return;
- if(window->doc) { + if(window->doc && !window->doc->unload_sent) { window->doc->unload_sent = TRUE;
+ /* Native sends pagehide events prior to unload on the same window + before it moves on to the next window, so they're interleaved. */ + if(window->doc->document_mode >= COMPAT_MODE_IE11) { + hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + } + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event); @@ -433,7 +443,7 @@ static void send_unload_events_impl(HTMLInnerWindow *window)
static void send_unload_events(HTMLDocumentObj *doc) { - if(!doc->doc_node || !doc->window || !doc->doc_node->content_ready || doc->doc_node->unload_sent) + if(!doc->doc_node || !doc->window || !doc->doc_node->content_ready) return;
send_unload_events_impl(doc->window->base.inner_window);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=126380
Your paranoid android.
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:351: Test failed: expected Exec_SETTITLE htmldoc.c:2938: Test failed: unexpected call Exec_SETTITLE