Patch status: *should* be fixed in qtwebengine-6.8.2 Somewhat annoying issue for qutebrowser users[1][2] resulting in hints not always being usable on some google-based sites (e.g. youtube). Note: as of the writing of this, [3] hasn't been merged upstream (yet) and so the final version of this patch may differ. Was added here early to avoid revbumping qtwebengine post-6.8.1 release, final version will likely land in 6.8.2 instead. [1] https://github.com/qutebrowser/qutebrowser/issues/8197 [2] https://bugreports.qt.io/browse/QTBUG-131156 [3] https://codereview.qt-project.org/c/qt/qtwebengine/+/604899 --- a/src/core/renderer_host/user_resource_controller_host.cpp +++ b/src/core/renderer_host/user_resource_controller_host.cpp @@ -43,8 +43,7 @@ void UserResourceControllerHost::WebContentsObserverHelper::RenderFrameCreated(content::RenderFrameHost *renderFrameHost) { - content::WebContents *contents = web_contents(); auto &remote = m_controllerHost->GetUserResourceControllerRenderFrame(renderFrameHost); - const QList scripts = m_controllerHost->m_perContentsScripts.value(contents); - for (const UserScript &script : scripts) + const auto scripts = m_controllerHost->m_perContentsScripts.constFind(web_contents()); + for (const UserScript &script : *scripts) remote->AddScript(script.data()); } @@ -57,4 +56,10 @@ remote->ClearScripts(); } + if (newHost) { + auto &remote = m_controllerHost->GetUserResourceControllerRenderFrame(newHost); + const auto scripts = m_controllerHost->m_perContentsScripts.constFind(web_contents()); + for (const UserScript &script : *scripts) + remote->AddScript(script.data()); + } } --- a/src/core/renderer_host/web_channel_ipc_transport_host.cpp +++ b/src/core/renderer_host/web_channel_ipc_transport_host.cpp @@ -108,4 +108,14 @@ } +void WebChannelIPCTransportHost::RenderFrameHostChanged(content::RenderFrameHost *oldHost, content::RenderFrameHost *newHost) +{ + if (oldHost) { + if (oldHost->IsRenderFrameLive()) + GetWebChannelIPCTransportRemote(oldHost)->ResetWorldId(); + } + if (newHost) // this might set it again, but that is harmless + setWorldId(newHost, m_worldId); +} + void WebChannelIPCTransportHost::RenderFrameDeleted(content::RenderFrameHost *rfh) { --- a/src/core/renderer_host/web_channel_ipc_transport_host.h +++ b/src/core/renderer_host/web_channel_ipc_transport_host.h @@ -46,4 +46,5 @@ // WebContentsObserver void RenderFrameCreated(content::RenderFrameHost *frame) override; + void RenderFrameHostChanged(content::RenderFrameHost *oldHost, content::RenderFrameHost *newHost) override; void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override; --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -70,4 +70,5 @@ void webChannelWithExistingQtObject(); void navigation(); + void navigation2(); void webChannelWithBadString(); void webChannelWithJavaScriptDisabled(); @@ -578,4 +579,79 @@ } +void tst_QWebEngineScript::navigation2() +{ + QWebEngineProfile profile("navigation2"); + QWebEnginePage page(&profile, nullptr); + QWebChannel channel; + page.setWebChannel(&channel); + QWebEngineScript s1; + s1.setInjectionPoint(QWebEngineScript::DocumentCreation); + // Check webchannel is installed before DocumentCreation scripts are run + // onload shouldn't have run, and neither should wasready + s1.setWorldId(QWebEngineScript::MainWorld); + s1.setSourceCode("document.passCreation = 0;" \ + "if (typeof qt !== undefined) document.passCreation++;" \ + "if (document.onloadran) document.passCreation++;" \ + "if (document.wasready) document.passCreation++;"); + page.scripts().insert(s1); + QWebEngineScript s2; + s2.setInjectionPoint(QWebEngineScript::DocumentReady); + // onload shouldn't have run + s2.setWorldId(QWebEngineScript::MainWorld); + s2.setSourceCode("document.passReady = 0;" \ + "if (typeof qt !== undefined) document.passReady++;" \ + "if (document.passCreation > 0) document.passReady++;" \ + "if (document.passDeferred > 0) document.passReady++;" \ + "if (document.onloadran) document.passReady++;" \ + "if (document.wasready) document.passReady++;"); + page.scripts().insert(s2); + QWebEngineScript s3; + s3.setInjectionPoint(QWebEngineScript::Deferred); + // all should have run + s3.setWorldId(QWebEngineScript::MainWorld); + s3.setSourceCode("document.passDeferred = 0;" \ + "if (typeof qt !== undefined) document.passDeferred++;" \ + "if (document.passCreation > 0) document.passDeferred++;" \ + "if (document.passReady > 0) document.passDeferred++;" \ + "if (document.onloadran) document.passDeferred++;" \ + "if (document.wasready) document.passDeferred++;"); + page.scripts().insert(s3); + + + QString html("" \ + "

hello world

"); + page.setHtml(html, QUrl("about:blank")); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passCreation", QWebEngineScript::MainWorld), + QVariant(1)); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passReady", QWebEngineScript::MainWorld), + QVariant(3)); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passDeferred", QWebEngineScript::MainWorld), + QVariant(5)); + + QString url2 = QStringLiteral("chrome://gpu/"); + page.setUrl(url2); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passCreation", QWebEngineScript::MainWorld), + QVariant(1)); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passReady", QWebEngineScript::MainWorld), + QVariant(2)); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passDeferred", QWebEngineScript::MainWorld), + QVariant(3)); + + QString url3 = QStringLiteral("qrc:/resources/test_iframe_main.html"); + page.setUrl(url3); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passCreation", QWebEngineScript::MainWorld), + QVariant(1)); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passReady", QWebEngineScript::MainWorld), + QVariant(2)); + QTRY_COMPARE(evaluateJavaScriptSyncInWorld(&page, "document.passDeferred", QWebEngineScript::MainWorld), + QVariant(3)); +} + // Try to set TestObject::text to an invalid UTF-16 string. //