From 93f9eed62db271ae4b8896f48df72a956f3ce7be Mon Sep 17 00:00:00 2001
From: Viktor Engelmann <Viktor.Engelmann@qt.io>
Date: Mon, 13 Mar 2017 14:30:02 +0100
Subject: [PATCH] Store Target URL in WebContentsDelegateQt::WebContentsCreated

When opening a new window, for example by using the JavaScript
method window.open('...'), the requested url is not stored
in the content::WebContents object we get in
WebContentsDelegateQt::createWindow (at this point, it should
at least be stored as pending request in the WebContents'
NavigationController, but it is not).

Because of this, the QQuickWebEngineNewViewRequest object
in QQuickWebEngineViewPrivate::adoptNewWindow never contained
the url. We have access to the target url in
WebContentsDelegateQt::WebContentsCreated, so now we store
it there in a new property m_initialTargetUrl, from where
WebContentsDelegateQt::createWindow takes it and passes it
to WebContentsAdapter::adoptNewWindow as a new parameter.

[ChangeLog][WebEngine] Fix WebEngineNewViewRequest::requestedUrl being empty when opening window from JavaScript

Task-number: QTBUG-57675
Change-Id: I7e2c7866899baade17ce2517e6be8b2b2709699e
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
---
 src/core/web_contents_adapter_client.h         |  2 +-
 src/core/web_contents_delegate_qt.cpp          |  7 ++++++-
 src/core/web_contents_delegate_qt.h            |  2 ++
 src/webengine/api/qquickwebengineview.cpp      |  5 ++---
 src/webengine/api/qquickwebengineview_p_p.h    |  2 +-
 src/webenginewidgets/api/qwebenginepage.cpp    |  3 ++-
 src/webenginewidgets/api/qwebenginepage_p.h    |  2 +-
 .../quick/qmltests/data/tst_newViewRequest.qml | 18 ++++++++++++------
 8 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index d4b2974fc..055cefa6f 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -330,7 +330,7 @@ public:
     virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) = 0;
     virtual void focusContainer() = 0;
     virtual void unhandledKeyEvent(QKeyEvent *event) = 0;
-    virtual void adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry) = 0;
+    virtual void adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry, const QUrl &targetUrl) = 0;
     virtual bool isBeingAdopted() = 0;
     virtual void close() = 0;
     virtual void windowCloseRejected() = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 6c5b63960..86366abaa 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -282,6 +282,11 @@ void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::Favic
     m_faviconManager->update(faviconCandidates);
 }
 
+void WebContentsDelegateQt::WebContentsCreated(content::WebContents* /*source_contents*/, int /*opener_render_process_id*/, int /*opener_render_frame_id*/, const std::string& /*frame_name*/, const GURL& target_url, content::WebContents* new_contents)
+{
+    this->m_initialTargetUrl = toQt(target_url);
+}
+
 content::ColorChooser *WebContentsDelegateQt::OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<content::ColorSuggestion> &suggestion)
 {
     Q_UNUSED(suggestion);
@@ -422,7 +427,7 @@ QWeakPointer<WebContentsAdapter> WebContentsDelegateQt::createWindow(content::We
 {
     QSharedPointer<WebContentsAdapter> newAdapter = QSharedPointer<WebContentsAdapter>::create(new_contents);
 
-    m_viewClient->adoptNewWindow(newAdapter, static_cast<WebContentsAdapterClient::WindowOpenDisposition>(disposition), user_gesture, toQt(initial_pos));
+    m_viewClient->adoptNewWindow(newAdapter, static_cast<WebContentsAdapterClient::WindowOpenDisposition>(disposition), user_gesture, toQt(initial_pos), m_initialTargetUrl);
 
     // If the client didn't reference the adapter, it will be deleted now, and the weak pointer zeroed.
     return newAdapter;
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 2e294a841..913bf356c 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -104,6 +104,7 @@ public:
     void LoadProgressChanged(content::WebContents* source, double progress) override;
     void HandleKeyboardEvent(content::WebContents *source, const content::NativeWebKeyboardEvent &event) override;
     content::ColorChooser *OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<content::ColorSuggestion> &suggestion) override;
+    void WebContentsCreated(content::WebContents* source_contents, int opener_render_process_id, int opener_render_frame_id, const std::string& frame_name, const GURL& target_url, content::WebContents* new_contents) override;
     content::JavaScriptDialogManager *GetJavaScriptDialogManager(content::WebContents *source) override;
     void EnterFullscreenModeForTab(content::WebContents* web_contents, const GURL& origin) override;
     void ExitFullscreenModeForTab(content::WebContents*) override;
@@ -156,6 +157,7 @@ private:
     QScopedPointer<FaviconManager> m_faviconManager;
     SavePageInfo m_savePageInfo;
     QSharedPointer<FilePickerController> m_filePickerController;
+    QUrl m_initialTargetUrl;
 };
 
 } // namespace QtWebEngineCore
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index be86f5daf..cd734f971 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -586,7 +586,7 @@ void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event)
         q->window()->sendEvent(q->parentItem(), event);
 }
 
-void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &)
+void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &, const QUrl &targetUrl)
 {
     Q_Q(QQuickWebEngineView);
     QQuickWebEngineNewViewRequest request;
@@ -594,8 +594,7 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapte
     // to start loading it and possibly return it to its parent page window.open().
     request.m_adapter = newWebContents;
     request.m_isUserInitiated = userGesture;
-    if (newWebContents)
-        request.m_requestedUrl = newWebContents->requestedUrl();
+    request.m_requestedUrl = targetUrl;
 
     switch (disposition) {
     case WebContentsAdapterClient::NewForegroundTabDisposition:
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 2ecd70d78..64c63f31a 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -107,7 +107,7 @@ public:
     virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE;
     virtual void focusContainer() Q_DECL_OVERRIDE;
     virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
-    virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &) Q_DECL_OVERRIDE;
+    virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &, const QUrl &targetUrl) Q_DECL_OVERRIDE;
     virtual bool isBeingAdopted() Q_DECL_OVERRIDE;
     virtual void close() Q_DECL_OVERRIDE;
     virtual void windowCloseRejected() Q_DECL_OVERRIDE;
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 09d05a438..416b3a5a2 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -401,10 +401,11 @@ void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event)
         QGuiApplication::sendEvent(view->parentWidget(), event);
 }
 
-void QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry)
+void QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry, const QUrl &targetUrl)
 {
     Q_Q(QWebEnginePage);
     Q_UNUSED(userGesture);
+    Q_UNUSED(targetUrl);
 
     QWebEnginePage *newPage = q->createWindow(toWindowType(disposition));
     if (!newPage)
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index c7b805c45..0a1fcd34e 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -100,7 +100,7 @@ public:
     virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE;
     virtual void focusContainer() Q_DECL_OVERRIDE;
     virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
-    virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) Q_DECL_OVERRIDE;
+    virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry, const QUrl &targetUrl) Q_DECL_OVERRIDE;
     void adoptNewWindowImpl(QWebEnginePage *newPage,
             const QSharedPointer<QtWebEngineCore::WebContentsAdapter> &newWebContents,
             const QRect &initialGeometry);
diff --git a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml
index 7a04d5f5b..4becbb620 100644
--- a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml
+++ b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml
@@ -28,7 +28,7 @@
 
 import QtQuick 2.0
 import QtTest 1.0
-import QtWebEngine 1.2
+import QtWebEngine 1.5
 
 TestWebEngineView {
     id: webEngineView
@@ -47,7 +47,8 @@ TestWebEngineView {
     onNewViewRequested: {
         newViewRequest = {
             "destination": request.destination,
-            "userInitiated": request.userInitiated
+            "userInitiated": request.userInitiated,
+            "requestedUrl": request.requestedUrl
         };
 
         dialog = Qt.createQmlObject(
@@ -81,6 +82,8 @@ TestWebEngineView {
         }
 
         function test_jsWindowOpen() {
+            var url = 'data:text/html,%3Chtml%3E%3Cbody%3ETest+Page%3C%2Fbody%3E%3C%2Fhtml%3E';
+
             // Open an empty page in a new tab
             webEngineView.loadHtml(
                 "<html><head><script>" +
@@ -95,28 +98,30 @@ TestWebEngineView {
 
             verify(dialog.webEngineView.waitForLoadSucceeded());
             compare(dialog.webEngineView.url, "");
+            compare(newViewRequest.requestedUrl, 'about:blank');
             newViewRequestedSpy.clear();
             dialog.destroy();
 
-            // Open an empty page in a new dialog
+            // Open a page in a new dialog
             webEngineView.loadHtml(
                 "<html><head><script>" +
-                "   function popup() { window.open('', '_blank', 'width=200,height=100'); }" +
+                "   function popup() { window.open('" + url + "', '_blank', 'width=200,height=100'); }" +
                 "</script></head>" +
                 "<body onload='popup()'></body></html>");
             verify(webEngineView.waitForLoadSucceeded());
             tryCompare(newViewRequestedSpy, "count", 1);
 
             compare(newViewRequest.destination, WebEngineView.NewViewInDialog);
+            compare(newViewRequest.requestedUrl, url);
             verify(!newViewRequest.userInitiated);
             verify(dialog.webEngineView.waitForLoadSucceeded());
             newViewRequestedSpy.clear();
             dialog.destroy();
 
-            // Open an empty page in a new dialog by user
+            // Open a page in a new dialog by user
             webEngineView.loadHtml(
                 "<html><head><script>" +
-                "   function popup() { window.open('', '_blank', 'width=200,height=100'); }" +
+                "   function popup() { window.open('" + url + "', '_blank', 'width=200,height=100'); }" +
                 "</script></head>" +
                 "<body onload=\"document.getElementById('popupButton').focus();\">" +
                 "   <button id='popupButton' onclick='popup()'>Pop Up!</button>" +
@@ -124,6 +129,7 @@ TestWebEngineView {
             verify(webEngineView.waitForLoadSucceeded());
             verifyElementHasFocus("popupButton");
             keyPress(Qt.Key_Enter);
+            compare(newViewRequest.requestedUrl, url);
             tryCompare(newViewRequestedSpy, "count", 1);
 
             compare(newViewRequest.destination, WebEngineView.NewViewInDialog);
-- 
GitLab