From ca30d0374020752d3ac367fdffef88a5c1fe4a48 Mon Sep 17 00:00:00 2001 From: Andras Becsi Date: Fri, 25 Jul 2014 15:53:07 +0200 Subject: Add QQuick API for intercepting navigation requests Add missing navigationRequested API to be able to intercept navigation requests. This is useful for ignoring requests for example in kiosk-like applications that want to restrinct navigation to a specific url or domain, or want to disable specific types of navigation requests (e.g. reloading, clicking links, form submissions). Change-Id: Ie375e635a3c3566527972d05f5d99b39489c5ca8 Reviewed-by: Jocelyn Turcotte --- src/core/core_gyp_generator.pro | 2 + src/core/network_delegate_qt.cpp | 140 ++++++++++++++++++- src/core/network_delegate_qt.h | 38 +++-- src/core/web_contents_adapter_client.h | 16 +++ .../api/qquickwebenginenavigationrequest.cpp | 111 +++++++++++++++ .../api/qquickwebenginenavigationrequest_p.h | 85 ++++++++++++ src/webengine/api/qquickwebengineview.cpp | 10 ++ src/webengine/api/qquickwebengineview_p.h | 22 +++ src/webengine/api/qquickwebengineview_p_p.h | 1 + src/webengine/plugin/plugin.cpp | 2 + src/webengine/webengine.pro | 2 + src/webenginewidgets/api/qwebenginepage_p.h | 1 + tests/auto/quick/publicapi/tst_publicapi.cpp | 10 +- tests/auto/quick/qmltests/data/test2.html | 3 + .../qmltests/data/tst_navigationRequested.qml | 154 +++++++++++++++++++++ tests/auto/quick/qmltests/qmltests.pro | 1 + 16 files changed, 580 insertions(+), 18 deletions(-) create mode 100644 src/webengine/api/qquickwebenginenavigationrequest.cpp create mode 100644 src/webengine/api/qquickwebenginenavigationrequest_p.h create mode 100644 tests/auto/quick/qmltests/data/tst_navigationRequested.qml diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 27ee33e51..5e6d08214 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -55,6 +55,7 @@ SOURCES = \ javascript_dialog_controller.cpp \ javascript_dialog_manager_qt.cpp \ media_capture_devices_dispatcher.cpp \ + network_delegate_qt.cpp \ ozone_platform_eglfs.cpp \ process_main.cpp \ qrc_protocol_handler_qt.cpp \ @@ -99,6 +100,7 @@ HEADERS = \ javascript_dialog_controller.h \ javascript_dialog_manager_qt.h \ media_capture_devices_dispatcher.h \ + network_delegate_qt.h \ ozone_platform_eglfs.h \ process_main.h \ qrc_protocol_handler_qt.h \ diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index 27807c499..424d0e631 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -40,3 +40,141 @@ ****************************************************************************/ #include "network_delegate_qt.h" + +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_request_details.h" +#include "content/public/browser/resource_request_info.h" +#include "content/public/common/page_transition_types.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_request.h" +#include "type_conversion.h" +#include "web_contents_adapter_client.h" +#include "web_contents_view_qt.h" + +namespace { + +int pageTransitionToNavigationType(content::PageTransition transition) +{ + int32 qualifier = content::PageTransitionGetQualifier(transition); + + if (qualifier & content::PAGE_TRANSITION_FORWARD_BACK) + return WebContentsAdapterClient::BackForwardNavigation; + + content::PageTransition stippedTransition = content::PageTransitionStripQualifier(transition); + + switch (stippedTransition) { + case content::PAGE_TRANSITION_LINK: + return WebContentsAdapterClient::LinkClickedNavigation; + case content::PAGE_TRANSITION_TYPED: + return WebContentsAdapterClient::TypedNavigation; + case content::PAGE_TRANSITION_FORM_SUBMIT: + return WebContentsAdapterClient::FormSubmittedNavigation; + case content::PAGE_TRANSITION_RELOAD: + return WebContentsAdapterClient::ReloadNavigation; + default: + return WebContentsAdapterClient::OtherNavigation; + } +} + +} + +int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::CompletionCallback &callback, GURL *) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request); + int renderProcessId; + int renderViewId; + if (!info || !info->GetRenderViewForRequest(request, &renderProcessId, &renderViewId)) + // Abort the request if it has no associated render info / render view. + return net::ERR_ABORTED; + + ResourceType::Type resourceType = info->GetResourceType(); + // Only intercept MAIN_FRAME and SUB_FRAME. + if (!ResourceType::IsFrame(resourceType)) + return net::OK; + + // Track active requests since |callback| and |new_url| are valid + // only until OnURLRequestDestroyed is called for this request. + m_activeRequests.insert(request); + + int navigationType = pageTransitionToNavigationType(info->GetPageTransition()); + + RequestParams params = { + toQt(request->url()), + resourceType == ResourceType::MAIN_FRAME, + navigationType, + renderProcessId, + renderViewId + }; + + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&NetworkDelegateQt::NotifyNavigationRequestedOnUIThread, + base::Unretained(this), + request, + params, + callback) + ); + + // We'll run the callback after we notified the UI thread. + return net::ERR_IO_PENDING; +} + +void NetworkDelegateQt::OnURLRequestDestroyed(net::URLRequest* request) +{ + m_activeRequests.remove(request); +} + +void NetworkDelegateQt::CompleteURLRequestOnIOThread(net::URLRequest *request, + int navigationRequestAction, + const net::CompletionCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + if (!m_activeRequests.contains(request)) + return; + + int error = net::OK; + switch (navigationRequestAction) { + case WebContentsAdapterClient::AcceptRequest: + error = net::OK; + break; + case WebContentsAdapterClient::IgnoreRequest: + error = net::OK; + // We can cancel the request here since we are on the IO thread. + request->Cancel(); + break; + default: + error = net::ERR_FAILED; + Q_UNREACHABLE(); + } + callback.Run(error); +} + +void NetworkDelegateQt::NotifyNavigationRequestedOnUIThread(net::URLRequest *request, + RequestParams params, + const net::CompletionCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; + content::RenderViewHost *rvh = content::RenderViewHost::FromID(params.renderProcessId, params.renderViewId); + + if (rvh) { + content::WebContents *webContents = content::WebContents::FromRenderViewHost(rvh); + WebContentsAdapterClient *client = WebContentsViewQt::from(webContents->GetView())->client(); + client->navigationRequested(params.navigationType, params.url, navigationRequestAction, params.isMainFrameRequest); + } + + // Run the callback on the IO thread. + content::BrowserThread::PostTask( + content::BrowserThread::IO, + FROM_HERE, + base::Bind(&NetworkDelegateQt::CompleteURLRequestOnIOThread, + base::Unretained(this), + request, + navigationRequestAction, + callback) + ); +} diff --git a/src/core/network_delegate_qt.h b/src/core/network_delegate_qt.h index 9413addb3..d057b9915 100644 --- a/src/core/network_delegate_qt.h +++ b/src/core/network_delegate_qt.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -42,22 +42,20 @@ #define NETWORK_DELEGATE_QT_H #include "net/base/network_delegate.h" +#include "net/base/net_errors.h" -#include "qglobal.h" +#include +#include +#include // Needed for Q_DECL_OVERRIDE class NetworkDelegateQt : public net::NetworkDelegate { public: NetworkDelegateQt() {} virtual ~NetworkDelegateQt() {} - - private: - // net::NetworkDelegate implementation. - virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) Q_DECL_OVERRIDE - { - return net::OK; - } - +private: + // net::NetworkDelegate implementation + virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) Q_DECL_OVERRIDE; virtual int OnBeforeSendHeaders(net::URLRequest* request, const net::CompletionCallback& callback, net::HttpRequestHeaders* headers) Q_DECL_OVERRIDE { return net::OK; @@ -72,7 +70,7 @@ public: virtual void OnResponseStarted(net::URLRequest* request) Q_DECL_OVERRIDE { } virtual void OnRawBytesRead(const net::URLRequest& request, int bytes_read) Q_DECL_OVERRIDE { } virtual void OnCompleted(net::URLRequest* request, bool started) Q_DECL_OVERRIDE { } - virtual void OnURLRequestDestroyed(net::URLRequest* request) Q_DECL_OVERRIDE { } + virtual void OnURLRequestDestroyed(net::URLRequest* request) Q_DECL_OVERRIDE; virtual void OnPACScriptError(int line_number, const base::string16& error) Q_DECL_OVERRIDE { } virtual AuthRequiredResponse OnAuthRequired(net::URLRequest* request, const net::AuthChallengeInfo& auth_info, @@ -84,6 +82,24 @@ public: virtual bool OnCanThrottleRequest(const net::URLRequest& request) const Q_DECL_OVERRIDE { return false; } virtual int OnBeforeSocketStreamConnect(net::SocketStream* stream, const net::CompletionCallback& callback) Q_DECL_OVERRIDE { return net::OK; } virtual void OnRequestWaitStateChange(const net::URLRequest& request, RequestWaitState state) Q_DECL_OVERRIDE { } + + struct RequestParams { + QUrl url; + bool isMainFrameRequest; + int navigationType; + int renderProcessId; + int renderViewId; + }; + + void NotifyNavigationRequestedOnUIThread(net::URLRequest *request, + RequestParams params, + const net::CompletionCallback &callback); + + void CompleteURLRequestOnIOThread(net::URLRequest *request, + int navigationRequestAction, + const net::CompletionCallback &callback); + + QSet m_activeRequests; }; #endif // NETWORK_DELEGATE_QT_H diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index f8f729f60..2dffb8fb5 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -110,6 +110,21 @@ public: Save }; + enum NavigationRequestAction { + AcceptRequest, + // Make room in the valid range of the enum for extra actions exposed in Experimental. + IgnoreRequest = 0xFF + }; + + enum NavigationType { + LinkClickedNavigation, + TypedNavigation, + FormSubmittedNavigation, + BackForwardNavigation, + ReloadNavigation, + OtherNavigation + }; + enum JavaScriptConsoleMessageLevel { Info = 0, Warning, @@ -144,6 +159,7 @@ public: virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry) = 0; virtual void close() = 0; virtual bool contextMenuRequested(const WebEngineContextMenuData&) = 0; + virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) = 0; virtual void requestFullScreen(bool) = 0; virtual bool isFullScreen() const = 0; virtual void javascriptDialog(QSharedPointer) = 0; diff --git a/src/webengine/api/qquickwebenginenavigationrequest.cpp b/src/webengine/api/qquickwebenginenavigationrequest.cpp new file mode 100644 index 000000000..519170510 --- /dev/null +++ b/src/webengine/api/qquickwebenginenavigationrequest.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickwebenginenavigationrequest_p.h" + +#include "qquickwebengineview_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineNavigationRequestPrivate { +public: + QQuickWebEngineNavigationRequestPrivate(const QUrl& url, QQuickWebEngineView::NavigationType navigationType, bool mainFrame) + : url(url) + , action(QQuickWebEngineView::AcceptRequest) + , navigationType(navigationType) + , isMainFrame(mainFrame) + { + } + + ~QQuickWebEngineNavigationRequestPrivate() + { + } + + QUrl url; + QQuickWebEngineView::NavigationRequestAction action; + QQuickWebEngineView::NavigationType navigationType; + bool isMainFrame; +}; + +QQuickWebEngineNavigationRequest::QQuickWebEngineNavigationRequest(const QUrl& url, QQuickWebEngineView::NavigationType navigationType, bool mainFrame, QObject* parent) + : QObject(parent) + , d_ptr(new QQuickWebEngineNavigationRequestPrivate(url, navigationType, mainFrame)) +{ +} + +QQuickWebEngineNavigationRequest::~QQuickWebEngineNavigationRequest() +{ +} + +void QQuickWebEngineNavigationRequest::setAction(QQuickWebEngineView::NavigationRequestAction action) +{ + Q_D(QQuickWebEngineNavigationRequest); + if (d->action == action) + return; + + d->action = action; + emit actionChanged(); +} + +QUrl QQuickWebEngineNavigationRequest::url() const +{ + Q_D(const QQuickWebEngineNavigationRequest); + return d->url; +} + +QQuickWebEngineView::NavigationRequestAction QQuickWebEngineNavigationRequest::action() const +{ + Q_D(const QQuickWebEngineNavigationRequest); + return d->action; +} + +QQuickWebEngineView::NavigationType QQuickWebEngineNavigationRequest::navigationType() const +{ + Q_D(const QQuickWebEngineNavigationRequest); + return d->navigationType; +} + +bool QQuickWebEngineNavigationRequest::isMainFrame() const +{ + Q_D(const QQuickWebEngineNavigationRequest); + return d->isMainFrame; +} + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginenavigationrequest_p.h b/src/webengine/api/qquickwebenginenavigationrequest_p.h new file mode 100644 index 000000000..e8d94a56b --- /dev/null +++ b/src/webengine/api/qquickwebenginenavigationrequest_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINENAVIGATIONREQUEST_P_H +#define QQUICKWEBENGINENAVIGATIONREQUEST_P_H + +#include "qtwebengineglobal_p.h" +#include "qquickwebengineview_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineNavigationRequestPrivate; + +class Q_WEBENGINE_EXPORT QQuickWebEngineNavigationRequest : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl url READ url CONSTANT FINAL) + Q_PROPERTY(bool isMainFrame READ isMainFrame CONSTANT FINAL) + Q_PROPERTY(QQuickWebEngineView::NavigationRequestAction action READ action WRITE setAction NOTIFY actionChanged FINAL) + Q_PROPERTY(QQuickWebEngineView::NavigationType navigationType READ navigationType CONSTANT FINAL) + +public: + QQuickWebEngineNavigationRequest(const QUrl& url, QQuickWebEngineView::NavigationType navigationType, bool mainFrame, QObject* parent = 0); + ~QQuickWebEngineNavigationRequest(); + + QUrl url() const; + bool isMainFrame() const; + QQuickWebEngineView::NavigationRequestAction action() const; + + void setAction(QQuickWebEngineView::NavigationRequestAction action); + QQuickWebEngineView::NavigationType navigationType() const; + +Q_SIGNALS: + void actionChanged(); + +private: + Q_DECLARE_PRIVATE(QQuickWebEngineNavigationRequest) + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickWebEngineNavigationRequest) + +#endif // QQUICKWEBENGINENAVIGATIONREQUEST_P_H diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index a6a11c07d..f4881e8a5 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -45,6 +45,7 @@ #include "javascript_dialog_controller.h" #include "qquickwebenginehistory_p.h" #include "qquickwebengineloadrequest_p.h" +#include "qquickwebenginenavigationrequest_p.h" #include "qquickwebenginenewviewrequest_p.h" #include "render_widget_host_view_qt_delegate_quick.h" #include "render_widget_host_view_qt_delegate_quickwindow.h" @@ -194,6 +195,15 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu return true; } +void QQuickWebEngineViewPrivate::navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) +{ + Q_Q(QQuickWebEngineView); + QQuickWebEngineNavigationRequest navigationRequest(url, static_cast(navigationType), isMainFrame); + Q_EMIT q->navigationRequested(&navigationRequest); + + navigationRequestAction = navigationRequest.action(); +} + void QQuickWebEngineViewPrivate::javascriptDialog(QSharedPointer dialog) { ui()->showDialog(dialog); diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 12b9ee163..59349954f 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineViewExperimental; class QQuickWebEngineViewPrivate; class QQuickWebEngineLoadRequest; +class QQuickWebEngineNavigationRequest; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_OBJECT @@ -60,6 +61,8 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(bool canGoBack READ canGoBack NOTIFY loadingChanged) Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY loadingChanged) + Q_ENUMS(NavigationRequestAction); + Q_ENUMS(NavigationType); Q_ENUMS(LoadStatus); Q_ENUMS(ErrorDomain); Q_ENUMS(NewViewDestination); @@ -80,6 +83,24 @@ public: QQuickWebEngineViewExperimental *experimental() const; + // must match WebContentsAdapterClient::NavigationRequestAction + enum NavigationRequestAction { + AcceptRequest, + // Make room in the valid range of the enum so + // we can expose extra actions in experimental. + IgnoreRequest = 0xFF + }; + + // must match WebContentsAdapterClient::NavigationType + enum NavigationType { + LinkClickedNavigation, + TypedNavigation, + FormSubmittedNavigation, + BackForwardNavigation, + ReloadNavigation, + OtherNavigation + }; + enum LoadStatus { LoadStartedStatus, LoadStoppedStatus, @@ -124,6 +145,7 @@ Q_SIGNALS: void loadingChanged(QQuickWebEngineLoadRequest *loadRequest); void loadProgressChanged(); void linkHovered(const QUrl &hoveredUrl); + void navigationRequested(QQuickWebEngineNavigationRequest *request); void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); protected: diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 25b20a0e8..89d67bcd8 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -160,6 +160,7 @@ public: virtual void requestFullScreen(bool) Q_DECL_OVERRIDE; virtual bool isFullScreen() const Q_DECL_OVERRIDE; virtual bool contextMenuRequested(const WebEngineContextMenuData &) Q_DECL_OVERRIDE; + virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) Q_DECL_OVERRIDE; virtual void javascriptDialog(QSharedPointer) Q_DECL_OVERRIDE; virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE; virtual void didRunJavaScript(quint64, const QVariant&) Q_DECL_OVERRIDE; diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index 811f85dde..478a51f1a 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -44,6 +44,7 @@ #include "qtwebengineversion.h" #include "qquickwebengineview_p.h" #include "qquickwebengineloadrequest_p.h" +#include "qquickwebenginenavigationrequest_p.h" #include "qquickwebenginenewviewrequest_p.h" QT_BEGIN_NAMESPACE @@ -63,6 +64,7 @@ public: qmlRegisterType(uri, 0, 9, "WebEngineView"); qmlRegisterUncreatableType(uri, 0, 9, "WebEngineLoadRequest", QObject::tr("Cannot create separate instance of WebEngineLoadRequest")); + qmlRegisterUncreatableType(uri, 0, 9, "WebEngineNavigationRequest", QObject::tr("Cannot create separate instance of WebEngineNavigationRequest")); qmlRegisterUncreatableType(uri, 0, 9, "WebEngineNewViewRequest", QObject::tr("Cannot create separate instance of WebEngineNewViewRequest")); // The QML type loader relies on the minimum and maximum minor version of registered types diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index c379e2eda..6f2434700 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -15,6 +15,7 @@ INCLUDEPATH += $$PWD api ../core SOURCES = \ api/qquickwebenginehistory.cpp \ api/qquickwebengineloadrequest.cpp \ + api/qquickwebenginenavigationrequest.cpp \ api/qquickwebenginenewviewrequest.cpp \ api/qquickwebengineview.cpp \ api/qtwebengineglobal.cpp \ @@ -27,6 +28,7 @@ HEADERS = \ api/qtwebengineglobal_p.h \ api/qquickwebenginehistory_p.h \ api/qquickwebengineloadrequest_p.h \ + api/qquickwebenginenavigationrequest_p.h \ api/qquickwebenginenewviewrequest_p.h \ api/qquickwebengineview_p.h \ api/qquickwebengineview_p_p.h \ diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 90924bd8d..1a5e1ae3c 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -127,6 +127,7 @@ public: virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) Q_DECL_OVERRIDE; virtual void close() Q_DECL_OVERRIDE; virtual bool contextMenuRequested(const WebEngineContextMenuData &data) Q_DECL_OVERRIDE; + virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) Q_DECL_OVERRIDE { } virtual void requestFullScreen(bool) Q_DECL_OVERRIDE { } virtual bool isFullScreen() const Q_DECL_OVERRIDE { return false; } virtual void javascriptDialog(QSharedPointer) Q_DECL_OVERRIDE; diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index 57b6e9001..ad54bd12e 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -47,8 +47,7 @@ #include #include #include -// FIXME: Implement! -// #include +#include class tst_publicapi : public QObject { Q_OBJECT @@ -59,7 +58,7 @@ private Q_SLOTS: static QList typesToCheck = QList() << &QQuickWebEngineView::staticMetaObject << &QQuickWebEngineLoadRequest::staticMetaObject - // << &QQuickWebEngineNavigationRequest::staticMetaObject + << &QQuickWebEngineNavigationRequest::staticMetaObject ; static QList knownEnumNames = QList(); @@ -79,10 +78,10 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.FtpErrorDomain --> ErrorDomain" << "QQuickWebEngineView.DnsErrorDomain --> ErrorDomain" << "QQuickWebEngineView.LinkClickedNavigation --> NavigationType" + << "QQuickWebEngineView.TypedNavigation --> NavigationType" << "QQuickWebEngineView.FormSubmittedNavigation --> NavigationType" << "QQuickWebEngineView.BackForwardNavigation --> NavigationType" << "QQuickWebEngineView.ReloadNavigation --> NavigationType" - << "QQuickWebEngineView.FormResubmittedNavigation --> NavigationType" << "QQuickWebEngineView.OtherNavigation --> NavigationType" << "QQuickWebEngineView.NewViewInWindow --> NewViewDestination" << "QQuickWebEngineView.NewViewInTab --> NewViewDestination" @@ -118,8 +117,7 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineLoadRequest.errorDomain --> QQuickWebEngineView::ErrorDomain" << "QQuickWebEngineLoadRequest.errorCode --> int" << "QQuickWebEngineNavigationRequest.url --> QUrl" - << "QQuickWebEngineNavigationRequest.mouseButton --> int" - << "QQuickWebEngineNavigationRequest.keyboardModifiers --> int" + << "QQuickWebEngineNavigationRequest.isMainFrame --> bool" << "QQuickWebEngineNavigationRequest.action --> QQuickWebEngineView::NavigationRequestAction" << "QQuickWebEngineNavigationRequest.navigationType --> QQuickWebEngineView::NavigationType" << "QQuickWebEngineNavigationRequest.actionChanged() --> void" diff --git a/tests/auto/quick/qmltests/data/test2.html b/tests/auto/quick/qmltests/data/test2.html index 629c2a063..8e20d7e9e 100644 --- a/tests/auto/quick/qmltests/data/test2.html +++ b/tests/auto/quick/qmltests/data/test2.html @@ -2,5 +2,8 @@ Test page with huge link area +
+ +
diff --git a/tests/auto/quick/qmltests/data/tst_navigationRequested.qml b/tests/auto/quick/qmltests/data/tst_navigationRequested.qml new file mode 100644 index 000000000..aae3799bc --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_navigationRequested.qml @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 0.9 + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + + property bool shouldIgnoreLinkClicks: false + property bool shouldIgnoreSubFrameRequests: false + + QtObject { + id: attributes + property url mainUrl: "" + property url iframeUrl: "" + property bool linkClickedNavigationRequested: false + property bool linkClickedNavigationIgnored: false + + function clear() { + mainUrl = "" + iframeUrl = "" + linkClickedNavigationRequested = false + linkClickedNavigationIgnored = false + } + } + + SignalSpy { + id: navigationSpy + target: webEngineView + signalName: "navigationRequested" + } + + onNavigationRequested: { + if (request.isMainFrame) { + attributes.mainUrl = request.url + } else { + attributes.iframeUrl = request.url + if (shouldIgnoreSubFrameRequests) { + request.action = WebEngineView.IgnoreRequest + } + } + + if (request.navigationType === WebEngineView.LinkClickedNavigation) { + attributes.linkClickedNavigationRequested = true + if (shouldIgnoreLinkClicks) { + request.action = WebEngineView.IgnoreRequest + attributes.linkClickedNavigationIgnored = true + } + } + } + + TestCase { + name: "WebEngineViewNavigationRequested" + when: windowShown + + function init() { + attributes.clear() + navigationSpy.clear() + shouldIgnoreLinkClicks = false + shouldIgnoreSubFrameRequests = false + } + + function test_navigationRequested() { + // Test if we get notified about main frame and iframe loads + compare(navigationSpy.count, 0) + webEngineView.url = Qt.resolvedUrl("test2.html") + navigationSpy.wait() + compare(attributes.mainUrl, Qt.resolvedUrl("test2.html")) + navigationSpy.wait() + compare(attributes.iframeUrl, Qt.resolvedUrl("test1.html")) + compare(navigationSpy.count, 2) + verify(webEngineView.waitForLoadSucceeded()) + + // Test if we get notified about clicked links + mouseClick(webEngineView, 100, 100) + tryCompare(navigationSpy, "count", 3) + compare(attributes.mainUrl, Qt.resolvedUrl("test1.html")) + verify(attributes.linkClickedNavigationRequested) + verify(webEngineView.waitForLoadSucceeded()) + } + + function test_ignoreLinkClickedRequest() { + // Test if we can ignore clicked link requests + compare(navigationSpy.count, 0) + webEngineView.url = Qt.resolvedUrl("test2.html") + verify(webEngineView.waitForLoadSucceeded()) + + shouldIgnoreLinkClicks = true + mouseClick(webEngineView, 100, 100) + tryCompare(navigationSpy, "count", 3) + compare(attributes.mainUrl, Qt.resolvedUrl("test1.html")) + verify(attributes.linkClickedNavigationRequested) + verify(attributes.linkClickedNavigationIgnored) + // We ignored the main frame request, so we should + // get notified that the load has been stopped. + verify(webEngineView.waitForLoadStopped()) + verify(!webEngineView.loading) + } + + function test_ignoreSubFrameRequest() { + // Test if we can ignore sub frame requests + shouldIgnoreSubFrameRequests = true + webEngineView.url = Qt.resolvedUrl("test2.html") + tryCompare(navigationSpy, "count", 2) + compare(attributes.mainUrl, Qt.resolvedUrl("test2.html")) + compare(attributes.iframeUrl, Qt.resolvedUrl("test1.html")) + // We ignored the sub frame request, so + // the main frame load should still succeed. + verify(webEngineView.waitForLoadSucceeded()) + } + } +} diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index e6a68b950..b4514edc9 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -27,6 +27,7 @@ OTHER_FILES += \ $$PWD/data/tst_loadProgressSignal.qml \ $$PWD/data/tst_loadUrl.qml \ $$PWD/data/tst_navigationHistory.qml \ + $$PWD/data/tst_navigationRequested.qml \ $$PWD/data/tst_properties.qml \ $$PWD/data/tst_runJavaScript.qml \ $$PWD/data/tst_titleChanged.qml -- cgit v1.2.3