Jacek Caban : mshtml: Block load event until dynamically created script elements that are part of the document are loaded.
Alexandre Julliard
julliard at winehq.org
Thu Mar 25 16:49:23 CDT 2021
Module: wine
Branch: master
Commit: e5da8dbfb78c0f19b22af4f4406ad837b43b9f2e
URL: https://source.winehq.org/git/wine.git/?a=commit;h=e5da8dbfb78c0f19b22af4f4406ad837b43b9f2e
Author: Jacek Caban <jacek at codeweavers.com>
Date: Thu Mar 25 19:28:36 2021 +0100
mshtml: Block load event until dynamically created script elements that are part of the document are loaded.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/mshtml/binding.h | 1 +
dlls/mshtml/nsio.c | 18 ++++++++++++++++
dlls/mshtml/script.c | 42 ++++++++++++++++++++++++++++++++++++
dlls/mshtml/tests/asyncscriptload.js | 16 ++++++++++++++
4 files changed, 77 insertions(+)
diff --git a/dlls/mshtml/binding.h b/dlls/mshtml/binding.h
index 3d1ea6ecc8d..26a337fe470 100644
--- a/dlls/mshtml/binding.h
+++ b/dlls/mshtml/binding.h
@@ -154,6 +154,7 @@ HRESULT create_channelbsc(IMoniker*,const WCHAR*,BYTE*,DWORD,BOOL,nsChannelBSC**
HRESULT channelbsc_load_stream(HTMLInnerWindow*,IMoniker*,IStream*) DECLSPEC_HIDDEN;
void channelbsc_set_channel(nsChannelBSC*,nsChannel*,nsIStreamListener*,nsISupports*) DECLSPEC_HIDDEN;
IUri *nsuri_get_uri(nsWineURI*) DECLSPEC_HIDDEN;
+nsresult create_onload_blocker_request(nsIRequest**) DECLSPEC_HIDDEN;
HRESULT read_stream(BSCallback*,IStream*,void*,DWORD,DWORD*) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c
index 1ffc6325725..ea8eae2007d 100644
--- a/dlls/mshtml/nsio.c
+++ b/dlls/mshtml/nsio.c
@@ -3980,3 +3980,21 @@ void release_nsio(void)
nsio = NULL;
}
}
+
+nsresult create_onload_blocker_request(nsIRequest **ret)
+{
+ nsIChannel *channel;
+ nsACString spec;
+ nsresult nsres;
+
+ nsACString_InitDepend(&spec, "about:wine-script-onload-blocker");
+ nsres = nsIIOService_NewChannel(nsio, &spec, NULL, NULL, &channel);
+ nsACString_Finish(&spec);
+ if(NS_FAILED(nsres)) {
+ ERR("Failed to create channel: %08x\n", nsres);
+ return nsres;
+ }
+
+ *ret = (nsIRequest *)channel;
+ return NS_OK;
+}
diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c
index c52c62f56d9..ec739c4777f 100644
--- a/dlls/mshtml/script.c
+++ b/dlls/mshtml/script.c
@@ -822,6 +822,8 @@ typedef struct {
BSCallback bsc;
HTMLScriptElement *script_elem;
+ nsILoadGroup *load_group;
+ nsIRequest *request;
DWORD scheme;
DWORD size;
@@ -945,6 +947,13 @@ static void ScriptBSC_destroy(BSCallback *bsc)
This->script_elem = NULL;
}
+ if(This->request) {
+ ERR("Unfinished request\n");
+ nsIRequest_Release(This->request);
+ }
+ if(This->load_group)
+ nsILoadGroup_Release(This->load_group);
+
heap_free(This->buf);
heap_free(This);
}
@@ -957,9 +966,19 @@ static HRESULT ScriptBSC_init_bindinfo(BSCallback *bsc)
static HRESULT ScriptBSC_start_binding(BSCallback *bsc)
{
ScriptBSC *This = impl_from_BSCallback(bsc);
+ nsresult nsres;
This->script_elem->binding = &This->bsc;
+ if(This->load_group) {
+ nsres = create_onload_blocker_request(&This->request);
+ if(NS_SUCCEEDED(nsres)) {
+ nsres = nsILoadGroup_AddRequest(This->load_group, This->request, NULL);
+ if(NS_FAILED(nsres))
+ ERR("AddRequest failed: %08x\n", nsres);
+ }
+ }
+
/* FIXME: We should find a better to decide if 'loading' state is supposed to be used by the protocol. */
if(This->scheme == URL_SCHEME_HTTPS || This->scheme == URL_SCHEME_HTTP)
set_script_elem_readystate(This->script_elem, READYSTATE_LOADING);
@@ -970,6 +989,7 @@ static HRESULT ScriptBSC_start_binding(BSCallback *bsc)
static HRESULT ScriptBSC_stop_binding(BSCallback *bsc, HRESULT result)
{
ScriptBSC *This = impl_from_BSCallback(bsc);
+ nsresult nsres;
if(SUCCEEDED(result) && !This->script_elem)
result = E_UNEXPECTED;
@@ -989,6 +1009,14 @@ static HRESULT ScriptBSC_stop_binding(BSCallback *bsc, HRESULT result)
This->size = 0;
}
+ if(This->request) {
+ nsres = nsILoadGroup_RemoveRequest(This->load_group, This->request, NULL, NS_OK);
+ if(NS_FAILED(nsres))
+ ERR("RemoveRequest failed: %08x\n", nsres);
+ nsIRequest_Release(This->request);
+ This->request = NULL;
+ }
+
IHTMLScriptElement_Release(&This->script_elem->IHTMLScriptElement_iface);
This->script_elem = NULL;
return S_OK;
@@ -1099,6 +1127,20 @@ HRESULT load_script(HTMLScriptElement *script_elem, const WCHAR *src, BOOL async
IHTMLScriptElement_AddRef(&script_elem->IHTMLScriptElement_iface);
bsc->script_elem = script_elem;
+ if(window->bscallback && window->bscallback->nschannel &&
+ window->bscallback->nschannel->load_group) {
+ cpp_bool contains;
+ nsresult nsres;
+
+ nsres = nsIDOMNode_Contains(script_elem->element.node.doc->node.nsnode,
+ script_elem->element.node.nsnode, &contains);
+ if(NS_SUCCEEDED(nsres) && contains) {
+ TRACE("script %p will block load event\n", script_elem);
+ bsc->load_group = window->bscallback->nschannel->load_group;
+ nsILoadGroup_AddRef(bsc->load_group);
+ }
+ }
+
hres = start_binding(window, &bsc->bsc, NULL);
IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
diff --git a/dlls/mshtml/tests/asyncscriptload.js b/dlls/mshtml/tests/asyncscriptload.js
index 6dc333afdf4..207df133e91 100644
--- a/dlls/mshtml/tests/asyncscriptload.js
+++ b/dlls/mshtml/tests/asyncscriptload.js
@@ -90,3 +90,19 @@ async_test("append_script", function() {
elem.src = "jsstream.php?simple";
external.writeStream("simple", " ");
});
+
+function unexpected_load(e) {
+ ok(false, "onload event before executing script");
+}
+
+guard(function() {
+ var elem = document.createElement("script");
+ document.head.appendChild(elem);
+ elem.src = "jsstream.php?blockload";
+
+ window.addEventListener("load", unexpected_load, true);
+
+ setTimeout(guard(function() {
+ external.writeStream("blockload", "window.removeEventListener('load', unexpected_load, true);");
+ }), 100);
+})();
More information about the wine-cvs
mailing list