diff options
65 files changed, 1590 insertions, 573 deletions
diff --git a/examples/webengine/quicknanobrowser/quickwindow.qml b/examples/webengine/quicknanobrowser/quickwindow.qml index 610144dca..b954629fb 100644 --- a/examples/webengine/quicknanobrowser/quickwindow.qml +++ b/examples/webengine/quicknanobrowser/quickwindow.qml @@ -93,6 +93,18 @@ ApplicationWindow { tabs.removeTab(tabs.currentIndex) } } + Action { + shortcut: "Ctrl+0" + onTriggered: currentWebView.zoomFactor = 1.0; + } + Action { + shortcut: "Ctrl+-" + onTriggered: currentWebView.zoomFactor -= 0.1; + } + Action { + shortcut: "Ctrl+=" + onTriggered: currentWebView.zoomFactor += 0.1; + } toolBar: ToolBar { id: navigationBar diff --git a/examples/webengine/quicknanobrowser/util.h b/examples/webengine/quicknanobrowser/util.h index bc1cf8beb..ca0f5f1d5 100644 --- a/examples/webengine/quicknanobrowser/util.h +++ b/examples/webengine/quicknanobrowser/util.h @@ -50,7 +50,7 @@ QUrl urlFromUserInput(const QString& userInput) { QFileInfo fileInfo(userInput); if (fileInfo.exists()) - return QUrl(fileInfo.absoluteFilePath()); + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); return QUrl::fromUserInput(userInput); } diff --git a/examples/webenginewidgets/browser/featurepermissionbar.cpp b/examples/webenginewidgets/browser/featurepermissionbar.cpp index 98f19ad1f..a47cbcd9e 100644 --- a/examples/webenginewidgets/browser/featurepermissionbar.cpp +++ b/examples/webenginewidgets/browser/featurepermissionbar.cpp @@ -80,12 +80,13 @@ FeaturePermissionBar::FeaturePermissionBar(QWidget *view) l->addStretch(); QPushButton *allowButton = new QPushButton(tr("Allow"), this); QPushButton *denyButton = new QPushButton(tr("Deny"), this); + QPushButton *discardButton = new QPushButton(QIcon(QStringLiteral(":closetab.png")), QString(), this); connect(allowButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionGranted); connect(denyButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionDenied); - QPushButton *discardButton = new QPushButton(QIcon(QStringLiteral(":closetab.png")), QString(), this); - connect(discardButton, &QPushButton::clicked, this, &QObject::deleteLater); + connect(discardButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionUnknown); connect(allowButton, &QPushButton::clicked, this, &QObject::deleteLater); connect(denyButton, &QPushButton::clicked, this, &QObject::deleteLater); + connect(discardButton, &QPushButton::clicked, this, &QObject::deleteLater); l->addWidget(denyButton); l->addWidget(allowButton); l->addWidget(discardButton); @@ -118,3 +119,8 @@ void FeaturePermissionBar::permissionGranted() { emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionGrantedByUser); } + +void FeaturePermissionBar::permissionUnknown() +{ + emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionUnknown); +} diff --git a/examples/webenginewidgets/browser/featurepermissionbar.h b/examples/webenginewidgets/browser/featurepermissionbar.h index 92ca04773..cee5a25b0 100644 --- a/examples/webenginewidgets/browser/featurepermissionbar.h +++ b/examples/webenginewidgets/browser/featurepermissionbar.h @@ -63,6 +63,7 @@ signals: private slots: void permissionDenied(); void permissionGranted(); + void permissionUnknown(); private: QWebEnginePage::Feature m_feature; diff --git a/examples/webenginewidgets/browser/webview.cpp b/examples/webenginewidgets/browser/webview.cpp index 5ea273e3a..9b42f2ab2 100644 --- a/examples/webenginewidgets/browser/webview.cpp +++ b/examples/webenginewidgets/browser/webview.cpp @@ -97,37 +97,15 @@ BrowserMainWindow *WebPage::mainWindow() return BrowserApplication::instance()->mainWindow(); } -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) -bool WebPage::acceptNavigationRequest(QWebEngineFrame *frame, const QNetworkRequest &request, NavigationType type) +bool WebPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) { - // ctrl open in new tab - // ctrl-shift open in new tab and select - // ctrl-alt open in new window - if (type == QWebEnginePage::NavigationTypeLinkClicked - && (m_keyboardModifiers & Qt::ControlModifier - || m_pressedButtons == Qt::MidButton)) { - bool newWindow = (m_keyboardModifiers & Qt::AltModifier); - WebView *webView; - if (newWindow) { - BrowserApplication::instance()->newMainWindow(); - BrowserMainWindow *newMainWindow = BrowserApplication::instance()->mainWindow(); - webView = newMainWindow->currentTab(); - newMainWindow->raise(); - newMainWindow->activateWindow(); - webView->setFocus(); - } else { - bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier); - webView = mainWindow()->tabWidget()->newTab(selectNewTab); - } - webView->load(request); - m_keyboardModifiers = Qt::NoModifier; - m_pressedButtons = Qt::NoButton; - return false; + Q_UNUSED(type); + if (isMainFrame) { + m_loadingUrl = url; + emit loadingUrl(m_loadingUrl); } - m_loadingUrl = request.url(); - emit loadingUrl(m_loadingUrl); + return true; } -#endif bool WebPage::certificateError(const QWebEngineCertificateError &error) { diff --git a/examples/webenginewidgets/browser/webview.h b/examples/webenginewidgets/browser/webview.h index 2cedeb79b..5ed674f6a 100644 --- a/examples/webenginewidgets/browser/webview.h +++ b/examples/webenginewidgets/browser/webview.h @@ -65,9 +65,7 @@ public: BrowserMainWindow *mainWindow(); protected: -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) - bool acceptNavigationRequest(QWebEngineFrame *frame, const QNetworkRequest &request, NavigationType type); -#endif + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type); #if !defined(QT_NO_UITOOLS) QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); diff --git a/qtwebengine.pro b/qtwebengine.pro index 366446c7a..5156e4620 100644 --- a/qtwebengine.pro +++ b/qtwebengine.pro @@ -1,8 +1,2 @@ load(qt_build_config) - -# As long as we are a module separate from the rest of Qt, we want to unconditionally build examples. -# Once part of Qt 5, this should be removed and we should respect the Qt wide configuration. -QTWEBENGINE_BUILD_PARTS = $$QT_BUILD_PARTS -QTWEBENGINE_BUILD_PARTS *= examples - load(qt_parts) diff --git a/src/3rdparty b/src/3rdparty -Subproject 577cd47e54bb88c81b7a5b5a6d658d8d61b2c74 +Subproject 66388297cf2ca42049fb099237134ec33465e2f diff --git a/src/core/access_token_store_qt.cpp b/src/core/access_token_store_qt.cpp index 85a91c3f7..791d628ba 100644 --- a/src/core/access_token_store_qt.cpp +++ b/src/core/access_token_store_qt.cpp @@ -34,11 +34,27 @@ ** ****************************************************************************/ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #include "access_token_store_qt.h" -#include <QDebug> +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/browser_thread.h" + +#include "browser_context_qt.h" +#include "browser_context_adapter.h" +#include "content_browser_client_qt.h" +#include "web_engine_context.h" + +using content::AccessTokenStore; +using content::BrowserThread; AccessTokenStoreQt::AccessTokenStoreQt() + : m_systemRequestContext(0) { } @@ -48,9 +64,23 @@ AccessTokenStoreQt::~AccessTokenStoreQt() void AccessTokenStoreQt::LoadAccessTokens(const LoadAccessTokensCallbackType& callback) { + BrowserThread::PostTaskAndReply(BrowserThread::UI, FROM_HERE + , base::Bind(&AccessTokenStoreQt::performWorkOnUIThread, this) + , base::Bind(&AccessTokenStoreQt::respondOnOriginatingThread, this, callback)); +} + +void AccessTokenStoreQt::performWorkOnUIThread() +{ + m_systemRequestContext = WebEngineContext::current()->defaultBrowserContext()->browserContext()->GetRequestContext(); } -void AccessTokenStoreQt::SaveAccessToken(const GURL& server_url, const base::string16& access_token) +void AccessTokenStoreQt::respondOnOriginatingThread(const LoadAccessTokensCallbackType& callback) { + callback.Run(m_accessTokenSet, m_systemRequestContext); + m_systemRequestContext = 0; } +void AccessTokenStoreQt::SaveAccessToken(const GURL& serverUrl, const base::string16& accessToken) +{ + m_accessTokenSet[serverUrl] = accessToken; +} diff --git a/src/core/access_token_store_qt.h b/src/core/access_token_store_qt.h index 2a76681f0..9493da774 100644 --- a/src/core/access_token_store_qt.h +++ b/src/core/access_token_store_qt.h @@ -37,20 +37,33 @@ #ifndef ACCESS_TOKEN_STORE_QT_H #define ACCESS_TOKEN_STORE_QT_H +#include "base/memory/ref_counted.h" #include "content/public/browser/access_token_store.h" -#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE +#include <QtCore/qcompilerdetection.h> +#include <QtCore/QFile> +#include <QtCore/QScopedPointer> -class AccessTokenStoreQt : public content::AccessTokenStore -{ +namespace net { +class URLRequestContextGetter; +} + +class AccessTokenStoreQt : public content::AccessTokenStore { public: AccessTokenStoreQt(); ~AccessTokenStoreQt(); - virtual void LoadAccessTokens(const LoadAccessTokensCallbackType& callback) Q_DECL_OVERRIDE; - virtual void SaveAccessToken(const GURL& server_url, const base::string16& access_token) Q_DECL_OVERRIDE; + virtual void LoadAccessTokens(const LoadAccessTokensCallbackType& request) Q_DECL_OVERRIDE; + virtual void SaveAccessToken(const GURL& serverUrl, const base::string16& accessToken) Q_DECL_OVERRIDE; private: + void performWorkOnUIThread(); + void respondOnOriginatingThread(const LoadAccessTokensCallbackType& callback); + + + net::URLRequestContextGetter *m_systemRequestContext; + AccessTokenSet m_accessTokenSet; + DISALLOW_COPY_AND_ASSIGN(AccessTokenStoreQt); }; diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp new file mode 100644 index 000000000..ccb6a385d --- /dev/null +++ b/src/core/browser_context_adapter.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "browser_context_adapter.h" + +#include "browser_context_qt.h" +#include "web_engine_context.h" +#include "web_engine_visited_links_manager.h" + +#include <QCoreApplication> +#include <QDir> +#include <QString> +#include <QStringBuilder> +#include <QStandardPaths> + +namespace { +inline QString buildLocationFromStandardPath(const QString &standardPath, const QString &name) { + QString location = standardPath; + if (location.isEmpty()) + location = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); + + location.append(QDir::separator() % QLatin1String("QtWebEngine") % QDir::separator() % name); + return location; +} +} + +BrowserContextAdapter::BrowserContextAdapter(const QString &name, bool offTheRecord) + : m_name(name) + , m_offTheRecord(offTheRecord) + , m_browserContext(new BrowserContextQt(this)) + , m_visitedLinksManager(new WebEngineVisitedLinksManager(this)) +{ +} + +BrowserContextAdapter::~BrowserContextAdapter() +{ +} + +BrowserContextQt *BrowserContextAdapter::browserContext() +{ + return m_browserContext.data(); +} + +WebEngineVisitedLinksManager *BrowserContextAdapter::visitedLinksManager() +{ + return m_visitedLinksManager.data(); +} + +BrowserContextAdapter* BrowserContextAdapter::defaultContext() +{ + return WebEngineContext::current()->defaultBrowserContext(); +} + +BrowserContextAdapter* BrowserContextAdapter::offTheRecordContext() +{ + return WebEngineContext::current()->offTheRecordBrowserContext(); +} + +QString BrowserContextAdapter::dataPath() const +{ + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation), m_name); +} + +QString BrowserContextAdapter::cachePath() const +{ + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation), m_name); +} diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h new file mode 100644 index 000000000..e4e046c8e --- /dev/null +++ b/src/core/browser_context_adapter.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BROWSER_CONTEXT_ADAPTER_H +#define BROWSER_CONTEXT_ADAPTER_H + +#include "qtwebenginecoreglobal.h" + +#include <QScopedPointer> +#include <QSharedData> +#include <QString> + +class BrowserContextQt; +class WebEngineVisitedLinksManager; + +// Make a QSharedData if we need to open arbitrary BrowserContextAdapter beyond the defaults. +class QWEBENGINE_EXPORT BrowserContextAdapter // : public QSharedData +{ +public: + virtual ~BrowserContextAdapter(); + + static BrowserContextAdapter* defaultContext(); + static BrowserContextAdapter* offTheRecordContext(); + + WebEngineVisitedLinksManager *visitedLinksManager(); + + BrowserContextQt *browserContext(); + bool isOffTheRecord() const { return m_offTheRecord; } + QString dataPath() const; + QString cachePath() const; + +protected: + BrowserContextAdapter(const QString &name, bool offTheRecord = false); + +private: + const QString m_name; + bool m_offTheRecord; + QScopedPointer<BrowserContextQt> m_browserContext; + QScopedPointer<WebEngineVisitedLinksManager> m_visitedLinksManager; + friend class WebEngineContext; + + Q_DISABLE_COPY(BrowserContextAdapter) +}; + +#endif // BROWSER_CONTEXT_ADAPTER_H diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 44b6ca4ef..8dc4a3da2 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -36,6 +36,7 @@ #include "browser_context_qt.h" +#include "browser_context_adapter.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" #include "resource_context_qt.h" @@ -47,14 +48,8 @@ #include "content/public/browser/storage_partition.h" #include "net/proxy/proxy_config_service.h" -#include <QByteArray> -#include <QCoreApplication> -#include <QDir> -#include <QStandardPaths> -#include <QString> -#include <QStringBuilder> - -BrowserContextQt::BrowserContextQt() +BrowserContextQt::BrowserContextQt(BrowserContextAdapter *adapter) + : m_adapter(adapter) { resourceContext.reset(new ResourceContextQt(this)); } @@ -67,29 +62,17 @@ BrowserContextQt::~BrowserContextQt() base::FilePath BrowserContextQt::GetPath() const { - QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - if (dataLocation.isEmpty()) - dataLocation = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); - - dataLocation.append(QDir::separator() % QLatin1String("QtWebEngine")); - dataLocation.append(QDir::separator() % QLatin1String("Default")); - return base::FilePath(toFilePathString(dataLocation)); + return base::FilePath(toFilePathString(m_adapter->dataPath())); } base::FilePath BrowserContextQt::GetCachePath() const { - QString cacheLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - if (cacheLocation.isEmpty()) - cacheLocation = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); - - cacheLocation.append(QDir::separator() % QLatin1String("QtWebEngine")); - cacheLocation.append(QDir::separator() % QLatin1String("Default")); - return base::FilePath(toFilePathString(cacheLocation)); + return base::FilePath(toFilePathString(m_adapter->cachePath())); } bool BrowserContextQt::IsOffTheRecord() const { - return false; + return m_adapter->isOffTheRecord(); } net::URLRequestContextGetter *BrowserContextQt::GetRequestContext() diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index 125c0fc46..634db6f3f 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -43,10 +43,12 @@ #include "net/url_request/url_request_context.h" #include "download_manager_delegate_qt.h" +class BrowserContextAdapter; + class BrowserContextQt : public content::BrowserContext { public: - explicit BrowserContextQt(); + explicit BrowserContextQt(BrowserContextAdapter *); virtual ~BrowserContextQt(); @@ -70,6 +72,7 @@ private: scoped_ptr<content::ResourceContext> resourceContext; scoped_refptr<net::URLRequestContextGetter> url_request_getter_; scoped_ptr<DownloadManagerDelegateQt> downloadManagerDelegate; + BrowserContextAdapter *m_adapter; DISALLOW_COPY_AND_ASSIGN(BrowserContextQt); }; diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index ee403298b..1c0c75bad 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -54,11 +54,15 @@ #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_share_group.h" +#include "access_token_store_qt.h" #include "browser_context_qt.h" #include "certificate_error_controller.h" #include "certificate_error_controller_p.h" #include "desktop_screen_qt.h" #include "dev_tools_http_handler_delegate_qt.h" +#ifdef QT_USE_POSITIONING +#include "location_provider_qt.h" +#endif #include "media_capture_devices_dispatcher.h" #include "resource_dispatcher_host_delegate_qt.h" #include "web_contents_delegate_qt.h" @@ -202,12 +206,10 @@ public: void PreMainMessageLoopRun() Q_DECL_OVERRIDE { - m_browserContext.reset(new BrowserContextQt()); } void PostMainMessageLoopRun() { - m_browserContext.reset(); } int PreCreateThreads() Q_DECL_OVERRIDE @@ -218,13 +220,7 @@ public: return 0; } - BrowserContextQt* browser_context() const { - return m_browserContext.get(); - } - private: - scoped_ptr<BrowserContextQt> m_browserContext; - DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt); }; @@ -353,22 +349,15 @@ content::AccessTokenStore *ContentBrowserClientQt::CreateAccessTokenStore() return new AccessTokenStoreQt; } -BrowserContextQt* ContentBrowserClientQt::browser_context() { - Q_ASSERT(m_browserMainParts); - return static_cast<BrowserMainPartsQt*>(m_browserMainParts)->browser_context(); -} - -net::URLRequestContextGetter* ContentBrowserClientQt::CreateRequestContext(content::BrowserContext* content_browser_context, content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) +net::URLRequestContextGetter* ContentBrowserClientQt::CreateRequestContext(content::BrowserContext* browser_context, content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) { - if (content_browser_context != browser_context()) - fprintf(stderr, "Warning: off the record browser context not implemented !\n"); - return static_cast<BrowserContextQt*>(browser_context())->CreateRequestContext(protocol_handlers); + return static_cast<BrowserContextQt*>(browser_context)->CreateRequestContext(protocol_handlers); } -void ContentBrowserClientQt::enableInspector(bool enable) +void ContentBrowserClientQt::enableInspector(bool enable, content::BrowserContext* browser_context) { if (enable && !m_devtools) { - m_devtools.reset(new DevToolsHttpHandlerDelegateQt(browser_context())); + m_devtools.reset(new DevToolsHttpHandlerDelegateQt(browser_context)); } else if (!enable && m_devtools) { m_devtools.reset(); } @@ -393,19 +382,18 @@ void ContentBrowserClientQt::AllowCertificateError(int render_process_id, int re contentsDelegate->allowCertificateError(errorController); } -void ContentBrowserClientQt::RequestGeolocationPermission(content::WebContents *webContents, - int bridge_id, - const GURL &requesting_frame, - bool user_gesture, - base::Callback<void(bool)> result_callback, - base::Closure *cancel_callback) +void ContentBrowserClientQt::RequestGeolocationPermission(content::WebContents *webContents, int /*bridgeId*/, const GURL &requestingFrameOrigin, bool /*userGesture*/, base::Callback<void (bool)> resultCallback, base::Closure *cancelCallback) +{ + WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); + Q_ASSERT(contentsDelegate); + contentsDelegate->requestGeolocationPermission(requestingFrameOrigin, resultCallback, cancelCallback); +} + +content::LocationProvider *ContentBrowserClientQt::OverrideSystemLocationProvider() { - Q_UNUSED(webContents); - Q_UNUSED(bridge_id); - Q_UNUSED(requesting_frame); - Q_UNUSED(user_gesture); - Q_UNUSED(cancel_callback); - - // TODO: Add geolocation support - result_callback.Run(false); +#ifdef QT_USE_POSITIONING + return new LocationProviderQt; +#else + return 0; // Leave it up to Chromium to figure something out. +#endif } diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index 4f216030c..879546994 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -78,8 +78,8 @@ public: virtual void ResourceDispatcherHostCreated() Q_DECL_OVERRIDE; virtual gfx::GLShareGroup* GetInProcessGpuShareGroup() Q_DECL_OVERRIDE; virtual content::MediaObserver* GetMediaObserver() Q_DECL_OVERRIDE; + virtual content::AccessTokenStore* CreateAccessTokenStore() Q_DECL_OVERRIDE; virtual void OverrideWebkitPrefs(content::RenderViewHost *, const GURL &, WebPreferences *) Q_DECL_OVERRIDE; - virtual content::AccessTokenStore *CreateAccessTokenStore() Q_DECL_OVERRIDE; virtual void AllowCertificateError( int render_process_id, int render_frame_id, @@ -91,19 +91,14 @@ public: bool strict_enforcement, const base::Callback<void(bool)>& callback, content::CertificateRequestResultType* result) Q_DECL_OVERRIDE; - virtual void RequestGeolocationPermission( - content::WebContents *webContents, - int bridge_id, - const GURL &requesting_frame, - bool user_gesture, - base::Callback<void(bool)> result_callback, - base::Closure *cancel_callback) Q_DECL_OVERRIDE; + void RequestGeolocationPermission(content::WebContents* web_contents, int, const GURL& requesting_frame + , bool, base::Callback<void(bool)> resultCallback + , base::Closure* cancelCallback) Q_DECL_OVERRIDE; + content::LocationProvider* OverrideSystemLocationProvider() Q_DECL_OVERRIDE; - BrowserContextQt* browser_context(); + virtual net::URLRequestContextGetter *CreateRequestContext(content::BrowserContext *browser_context, content::ProtocolHandlerMap *protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptorss) Q_DECL_OVERRIDE; - virtual net::URLRequestContextGetter *CreateRequestContext(content::BrowserContext *content_browser_context, content::ProtocolHandlerMap *protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptorss) Q_DECL_OVERRIDE; - - void enableInspector(bool); + void enableInspector(bool enable, content::BrowserContext *browser_context); private: BrowserMainPartsQt* m_browserMainParts; diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 38aba3a76..4514475ec 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -11,7 +11,7 @@ TEMPLATE = lib # gyp/ninja will take care of the compilation, qmake/make will finish with linking and install. TARGET = QtWebEngineCore QT += qml quick -QT_PRIVATE += gui-private +QT_PRIVATE += quick-private gui-private core-private # Defining keywords such as 'signal' clashes with the chromium code base. DEFINES += QT_NO_KEYWORDS \ @@ -36,6 +36,7 @@ SOURCES = \ access_token_store_qt.cpp \ browser_accessibility_manager_qt.cpp \ browser_accessibility_qt.cpp \ + browser_context_adapter.cpp \ browser_context_qt.cpp \ certificate_error_controller.cpp \ chromium_gpu_helper.cpp \ @@ -84,6 +85,7 @@ HEADERS = \ access_token_store_qt.h \ browser_accessibility_manager_qt.h \ browser_accessibility_qt.h \ + browser_context_adapter.h \ browser_context_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ @@ -117,6 +119,7 @@ HEADERS = \ resource_dispatcher_host_delegate_qt.h \ stream_video_node.h \ surface_factory_qt.h \ + type_conversion.h \ url_request_context_getter_qt.h \ url_request_qrc_job_qt.h \ web_contents_adapter.h \ @@ -131,3 +134,10 @@ HEADERS = \ web_engine_visited_links_manager.h \ web_event_factory.h \ yuv_video_node.h + +qtHaveModule(positioning) { + SOURCES += location_provider_qt.cpp + HEADERS += location_provider_qt.h + DEFINES += QT_USE_POSITIONING=1 + QT += positioning +} diff --git a/src/core/core_module.pro b/src/core/core_module.pro index ceb248372..1a7b0878f 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -3,8 +3,9 @@ TARGET = QtWebEngineCore CMAKE_MODULE_TESTS = "-" +qtHaveModule(positioning):QT += positioning QT += qml quick -QT_PRIVATE += gui-private +QT_PRIVATE += quick-private gui-private core-private # Needed to set a CFBundleIdentifier QMAKE_INFO_PLIST = Info_mac.plist diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index 1a393a0c7..0a24333db 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -55,6 +55,7 @@ #include "base/bind.h" #include "cc/output/delegated_frame_data.h" #include "cc/quads/checkerboard_draw_quad.h" +#include "cc/quads/debug_border_draw_quad.h" #include "cc/quads/draw_quad.h" #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/solid_color_draw_quad.h" @@ -62,80 +63,60 @@ #include "cc/quads/texture_draw_quad.h" #include "cc/quads/tile_draw_quad.h" #include "cc/quads/yuv_video_draw_quad.h" +#include "content/common/host_shared_bitmap_manager.h" #include <QOpenGLContext> -#include <QOpenGLFramebufferObject> #include <QOpenGLFunctions> -#include <QSGAbstractRenderer> -#include <QSGEngine> #include <QSGSimpleRectNode> #include <QSGSimpleTextureNode> #include <QSGTexture> +#include <private/qsgadaptationlayer_p.h> #if !defined(QT_NO_EGL) #include <EGL/egl.h> #include <EGL/eglext.h> #endif -class RenderPassTexture : public QSGTexture, protected QOpenGLFunctions -{ -public: - RenderPassTexture(const cc::RenderPass::Id &id); - - const cc::RenderPass::Id &id() const { return m_id; } - void bind(); - - int textureId() const { return m_fbo ? m_fbo->texture() : 0; } - QSize textureSize() const { return m_rect.size(); } - bool hasAlphaChannel() const { return m_format != GL_RGB; } - bool hasMipmaps() const { return false; } - - void setRect(const QRect &rect) { m_rect = rect; } - void setFormat(GLenum format) { m_format = format; } - QSGNode *rootNode() { return m_rootNode.data(); } - - void grab(); - -private: - cc::RenderPass::Id m_id; - QRect m_rect; - GLenum m_format; - - QScopedPointer<QSGEngine> m_sgEngine; - QScopedPointer<QSGRootNode> m_rootNode; - QScopedPointer<QSGAbstractRenderer> m_renderer; - QScopedPointer<QOpenGLFramebufferObject> m_fbo; -}; - class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { public: - MailboxTexture(const cc::TransferableResource &resource); + MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize); virtual int textureId() const Q_DECL_OVERRIDE { return m_textureId; } - void setTextureSize(const QSize& size) { m_textureSize = size; } virtual QSize textureSize() const Q_DECL_OVERRIDE { return m_textureSize; } virtual bool hasAlphaChannel() const Q_DECL_OVERRIDE { return m_hasAlpha; } void setHasAlphaChannel(bool hasAlpha) { m_hasAlpha = hasAlpha; } virtual bool hasMipmaps() const Q_DECL_OVERRIDE { return false; } virtual void bind() Q_DECL_OVERRIDE; - bool needsToFetch() const { return !m_textureId; } - cc::TransferableResource &resource() { return m_resource; } - cc::ReturnedResource returnResource(); + gpu::MailboxHolder &mailboxHolder() { return m_mailboxHolder; } void fetchTexture(gpu::gles2::MailboxManager *mailboxManager); void setTarget(GLenum target); - void incImportCount() { ++m_importCount; } private: - cc::TransferableResource m_resource; + gpu::MailboxHolder m_mailboxHolder; int m_textureId; QSize m_textureSize; bool m_hasAlpha; GLenum m_target; - int m_importCount; #ifdef Q_OS_QNX EGLStreamData m_eglStreamData; #endif }; +class ResourceHolder { +public: + ResourceHolder(const cc::TransferableResource &resource); + QSharedPointer<QSGTexture> initTexture(bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); + QSGTexture *texture() const { return m_texture.data(); } + cc::TransferableResource &transferableResource() { return m_resource; } + cc::ReturnedResource returnResource(); + void incImportCount() { ++m_importCount; } + bool needsToFetch() const { return !m_resource.is_software && m_texture && !m_texture.data()->textureId(); } + +private: + QWeakPointer<QSGTexture> m_texture; + cc::TransferableResource m_resource; + int m_importCount; +}; + class RectClipNode : public QSGClipNode { public: @@ -144,23 +125,13 @@ private: QSGGeometry m_geometry; }; -static inline QSharedPointer<RenderPassTexture> findRenderPassTexture(const cc::RenderPass::Id &id, const QList<QSharedPointer<RenderPassTexture> > &list) -{ - Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, list) - if (texture->id() == id) - return texture; - return QSharedPointer<RenderPassTexture>(); -} - -static inline QSharedPointer<MailboxTexture> &findMailboxTexture(unsigned resourceId - , QHash<unsigned, QSharedPointer<MailboxTexture> > &usedTextures - , QHash<unsigned, QSharedPointer<MailboxTexture> > &candidateTextures) +static inline QSharedPointer<QSGLayer> findRenderPassLayer(const cc::RenderPass::Id &id, const QList<QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > > &list) { - QSharedPointer<MailboxTexture> &texture = usedTextures[resourceId]; - if (!texture) - texture = candidateTextures.take(resourceId); - Q_ASSERT(texture); - return texture; + typedef QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > Pair; + Q_FOREACH (const Pair &pair, list) + if (pair.first == id) + return pair.second; + return QSharedPointer<QSGLayer>(); } static QSGNode *buildRenderPassChain(QSGNode *chainParent) @@ -294,59 +265,20 @@ static void deleteChromiumSync(gfx::TransferableFence *sync) Q_ASSERT(!*sync); } -RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id) - : QSGTexture() - , m_id(id) - , m_format(GL_RGBA) - , m_sgEngine(new QSGEngine) - , m_rootNode(new QSGRootNode) -{ - initializeOpenGLFunctions(); -} - -void RenderPassTexture::bind() -{ - glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); - updateBindOptions(); -} - -void RenderPassTexture::grab() -{ - if (!m_renderer) { - m_sgEngine->initialize(QOpenGLContext::currentContext()); - m_renderer.reset(m_sgEngine->createRenderer()); - m_renderer->setRootNode(m_rootNode.data()); - } - - if (!m_fbo || m_fbo->size() != m_rect.size() || m_fbo->format().internalTextureFormat() != m_format) - { - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setInternalTextureFormat(m_format); - - m_fbo.reset(new QOpenGLFramebufferObject(m_rect.size(), format)); - glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); - updateBindOptions(true); - } - - m_renderer->setDeviceRect(m_rect.size()); - m_renderer->setViewportRect(m_rect.size()); - QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height()); - m_renderer->setProjectionMatrixToRect(mirrored); - m_renderer->setClearColor(Qt::transparent); - - m_renderer->renderScene(m_fbo->handle()); -} - -MailboxTexture::MailboxTexture(const cc::TransferableResource &resource) - : m_resource(resource) +MailboxTexture::MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize) + : m_mailboxHolder(mailboxHolder) , m_textureId(0) - , m_textureSize(toQt(resource.size)) + , m_textureSize(textureSize) , m_hasAlpha(false) , m_target(GL_TEXTURE_2D) - , m_importCount(1) { initializeOpenGLFunctions(); + + // Assume that resources without a size will be used with a full source rect. + // Setting a size of 1x1 will let any texture node compute a normalized source + // rect of (0, 0) to (1, 1) while an empty texture size would set (0, 0) on all corners. + if (m_textureSize.isEmpty()) + m_textureSize = QSize(1, 1); } void MailboxTexture::bind() @@ -373,7 +305,55 @@ void MailboxTexture::setTarget(GLenum target) m_target = target; } -cc::ReturnedResource MailboxTexture::returnResource() +void MailboxTexture::fetchTexture(gpu::gles2::MailboxManager *mailboxManager) +{ + gpu::gles2::Texture *tex = ConsumeTexture(mailboxManager, m_target, m_mailboxHolder.mailbox); + + // The texture might already have been deleted (e.g. when navigating away from a page). + if (tex) { + m_textureId = service_id(tex); +#ifdef Q_OS_QNX + if (m_target == GL_TEXTURE_EXTERNAL_OES) { + m_eglStreamData = eglstream_connect_consumer(tex); + } +#endif + } +} + +ResourceHolder::ResourceHolder(const cc::TransferableResource &resource) + : m_resource(resource) + , m_importCount(1) +{ +} + +QSharedPointer<QSGTexture> ResourceHolder::initTexture(bool quadNeedsBlending, RenderWidgetHostViewQtDelegate *apiDelegate) +{ + QSharedPointer<QSGTexture> texture = m_texture.toStrongRef(); + if (!texture) { + if (m_resource.is_software) { + Q_ASSERT(apiDelegate); + scoped_ptr<cc::SharedBitmap> sharedBitmap = content::HostSharedBitmapManager::current()->GetSharedBitmapFromId(m_resource.size, m_resource.mailbox_holder.mailbox); + // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending + // to draw it but Chromium keeps this information in the quads. + // The input format is currently always Format_ARGB32_Premultiplied, so assume that all + // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion + // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to + // return false. + QImage::Format format = quadNeedsBlending ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + QImage image(sharedBitmap->pixels(), m_resource.size.width(), m_resource.size.height(), format); + texture.reset(apiDelegate->createTextureFromImage(image.copy())); + } else { + texture.reset(new MailboxTexture(m_resource.mailbox_holder, toQt(m_resource.size))); + static_cast<MailboxTexture *>(texture.data())->setHasAlphaChannel(quadNeedsBlending); + } + m_texture = texture; + } + // All quads using a resource should request the same blending state. + Q_ASSERT(texture->hasAlphaChannel() || !quadNeedsBlending); + return texture; +} + +cc::ReturnedResource ResourceHolder::returnResource() { cc::ReturnedResource returned; // The ResourceProvider ensures that the resource isn't used by the parent compositor's GL @@ -389,20 +369,6 @@ cc::ReturnedResource MailboxTexture::returnResource() return returned; } -void MailboxTexture::fetchTexture(gpu::gles2::MailboxManager *mailboxManager) -{ - gpu::gles2::Texture *tex = ConsumeTexture(mailboxManager, m_target, m_resource.mailbox_holder.mailbox); - - // The texture might already have been deleted (e.g. when navigating away from a page). - if (tex) { - m_textureId = service_id(tex); -#ifdef Q_OS_QNX - if (m_target == GL_TEXTURE_EXTERNAL_OES) { - m_eglStreamData = eglstream_connect_consumer(tex); - } -#endif - } -} RectClipNode::RectClipNode(const QRectF &rect) : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) @@ -429,9 +395,12 @@ void DelegatedFrameNode::preprocess() // We can now wait for the Chromium GPU thread to produce textures that will be // rendered on our quads and fetch the IDs from the mailboxes we were given. QList<MailboxTexture *> mailboxesToFetch; - Q_FOREACH (const QSharedPointer<MailboxTexture> &mailboxTexture, m_data->mailboxTextures.values()) - if (mailboxTexture->needsToFetch()) - mailboxesToFetch.append(mailboxTexture.data()); + typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator ResourceHolderIterator; + ResourceHolderIterator end = m_chromiumCompositorData->resourceHolders.constEnd(); + for (ResourceHolderIterator it = m_chromiumCompositorData->resourceHolders.constBegin(); it != end ; ++it) { + if ((*it)->needsToFetch()) + mailboxesToFetch.append(static_cast<MailboxTexture *>((*it)->texture())); + } if (!mailboxesToFetch.isEmpty()) { QMap<uint32, gfx::TransferableFence> transferredFences; @@ -442,7 +411,7 @@ void DelegatedFrameNode::preprocess() Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { m_numPendingSyncPoints++; - AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->resource().mailbox_holder.sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); + AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->mailboxHolder().sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); } m_mailboxesFetchedWaitCond.wait(&m_mutex); @@ -452,7 +421,7 @@ void DelegatedFrameNode::preprocess() // Tell GL to wait until Chromium is done generating resource textures on the GPU thread // for each mailbox. We can safely start referencing those textures onto geometries afterward. Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { - gfx::TransferableFence fence = transferredFences.take(mailboxTexture->resource().mailbox_holder.sync_point); + gfx::TransferableFence fence = transferredFences.take(mailboxTexture->mailboxHolder().sync_point); waitChromiumSync(&fence); deleteChromiumSync(&fence); } @@ -464,14 +433,19 @@ void DelegatedFrameNode::preprocess() } // Then render any intermediate RenderPass in order. - Q_FOREACH (const QSharedPointer<RenderPassTexture> &renderPass, m_renderPassTextures) - renderPass->grab(); + typedef QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > Pair; + Q_FOREACH (const Pair &pair, m_sgObjects.renderPassLayers) { + // The layer is non-live, request a one-time update here. + pair.second->scheduleUpdate(); + // Proceed with the actual update. + pair.second->updateTexture(); + } } -void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResourceArray *resourcesToRelease) +void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate) { - m_data = data; - cc::DelegatedFrameData* frameData = m_data->frameData.get(); + m_chromiumCompositorData = chromiumCompositorData; + cc::DelegatedFrameData* frameData = m_chromiumCompositorData->frameData.get(); if (!frameData) return; @@ -479,14 +453,15 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - matrix.scale(1 / m_data->frameDevicePixelRatio, 1 / m_data->frameDevicePixelRatio); + matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, 1 / m_chromiumCompositorData->frameDevicePixelRatio); setMatrix(matrix); - // Keep the old texture lists around to find the ones we can re-use. - QList<QSharedPointer<RenderPassTexture> > oldRenderPassTextures; - m_renderPassTextures.swap(oldRenderPassTextures); - QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextureCandidates; - m_data->mailboxTextures.swap(mailboxTextureCandidates); + // Keep the old objects in scope to hold a ref on layers, resources and textures + // that we can re-use. Destroy the remaining objects before returning. + SGObjects previousSGObjects; + qSwap(m_sgObjects, previousSGObjects); + QHash<unsigned, QSharedPointer<ResourceHolder> > resourceCandidates; + qSwap(m_chromiumCompositorData->resourceHolders, resourceCandidates); // A frame's resource_list only contains the new resources to be added to the scene. Quads can // still reference resources that were added in previous frames. Add them to the list of @@ -494,14 +469,21 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour // to the producing child compositor. for (unsigned i = 0; i < frameData->resource_list.size(); ++i) { const cc::TransferableResource &res = frameData->resource_list.at(i); - if (QSharedPointer<MailboxTexture> texture = mailboxTextureCandidates.value(res.id)) - texture->incImportCount(); + if (QSharedPointer<ResourceHolder> resource = resourceCandidates.value(res.id)) + resource->incImportCount(); else - mailboxTextureCandidates[res.id] = QSharedPointer<MailboxTexture>(new MailboxTexture(res)); + resourceCandidates[res.id] = QSharedPointer<ResourceHolder>(new ResourceHolder(res)); } frameData->resource_list.clear(); + // There is currently no way to know which and how quads changed since the last frame. + // We have to reconstruct the node chain with their geometries on every update. + // Intermediate render pass node chains are going to be destroyed when previousSGObjects + // goes out of scope together with any QSGLayer that could reference them. + while (QSGNode *oldChain = firstChild()) + delete oldChain; + // The RenderPasses list is actually a tree where a parent RenderPass is connected // to its dependencies through a RenderPass::Id reference in one or more RenderPassQuads. // The list is already ordered with intermediate RenderPasses placed before their @@ -515,21 +497,24 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour QSGNode *renderPassParent = 0; if (pass != rootRenderPass) { - QSharedPointer<RenderPassTexture> rpTexture = findRenderPassTexture(pass->id, oldRenderPassTextures); - if (!rpTexture) - rpTexture = QSharedPointer<RenderPassTexture>(new RenderPassTexture(pass->id)); - m_renderPassTextures.append(rpTexture); - rpTexture->setRect(toQt(pass->output_rect)); - rpTexture->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); - renderPassParent = rpTexture->rootNode(); + QSharedPointer<QSGLayer> rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers); + if (!rpLayer) { + rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); + // Avoid any premature texture update since we need to wait + // for the GPU thread to produce the dependent resources first. + rpLayer->setLive(false); + } + QSharedPointer<QSGRootNode> rootNode(new QSGRootNode); + rpLayer->setRect(toQt(pass->output_rect)); + rpLayer->setSize(toQt(pass->output_rect.size())); + rpLayer->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); + rpLayer->setItem(rootNode.data()); + m_sgObjects.renderPassLayers.append(QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> >(pass->id, rpLayer)); + m_sgObjects.renderPassRootNodes.append(rootNode); + renderPassParent = rootNode.data(); } else renderPassParent = this; - // There is currently no way to know which and how quads changed since the last frame. - // We have to reconstruct the node chain with their geometries on every update. - while (QSGNode *oldChain = renderPassParent->firstChild()) - delete oldChain; - QSGNode *renderPassChain = buildRenderPassChain(renderPassParent); const cc::SharedQuadState *currentLayerState = 0; QSGNode *currentLayerChain = 0; @@ -555,37 +540,28 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour break; } case cc::DrawQuad::RENDER_PASS: { const cc::RenderPassDrawQuad *renderPassQuad = cc::RenderPassDrawQuad::MaterialCast(quad); - QSGTexture *texture = findRenderPassTexture(renderPassQuad->render_pass_id, m_renderPassTextures).data(); + QSGTexture *layer = findRenderPassLayer(renderPassQuad->render_pass_id, m_sgObjects.renderPassLayers).data(); // cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes. - if (!texture) + if (!layer) continue; - QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; - textureNode->setRect(toQt(quad->rect)); - textureNode->setTexture(texture); - currentLayerChain->appendChildNode(textureNode); + // Only QSGImageNode currently supports QSGLayer textures. + QSGImageNode *imageNode = apiDelegate->createImageNode(); + imageNode->setTargetRect(toQt(quad->rect)); + imageNode->setInnerTargetRect(toQt(quad->rect)); + imageNode->setTexture(layer); + imageNode->update(); + currentLayerChain->appendChildNode(imageNode); break; } case cc::DrawQuad::TEXTURE_CONTENT: { const cc::TextureDrawQuad *tquad = cc::TextureDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &texture = findMailboxTexture(tquad->resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - - // FIXME: TransferableResource::size isn't always set properly for TextureDrawQuads, use the size of its DrawQuad::rect instead. - texture->setTextureSize(toQt(quad->rect.size())); - - // TransferableResource::format seems to always be GL_BGRA even though it might not - // contain any pixel with alpha < 1.0. The information about if they need blending - // for the contents itself is actually stored in quads. - // Tell the scene graph to enable blending for a texture only when at least one quad asks for it. - // Do not rely on DrawQuad::ShouldDrawWithBlending() since the shared_quad_state->opacity - // case will be handled by QtQuick by fetching this information from QSGOpacityNodes. - if (!quad->visible_rect.IsEmpty() && !quad->opaque_rect.Contains(quad->visible_rect)) - texture->setHasAlphaChannel(true); + ResourceHolder *resource = findAndHoldResource(tquad->resource_id, resourceCandidates); QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; textureNode->setTextureCoordinatesTransform(tquad->flipped ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform); textureNode->setRect(toQt(quad->rect)); - textureNode->setFiltering(texture->resource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); - textureNode->setTexture(texture.data()); + textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); + textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); currentLayerChain->appendChildNode(textureNode); break; } case cc::DrawQuad::SOLID_COLOR: { @@ -601,46 +577,67 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour rectangleNode->setColor(toQt(scquad->color)); currentLayerChain->appendChildNode(rectangleNode); break; + } case cc::DrawQuad::DEBUG_BORDER: { + const cc::DebugBorderDrawQuad *dbquad = cc::DebugBorderDrawQuad::MaterialCast(quad); + QSGGeometryNode *geometryNode = new QSGGeometryNode; + + QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); + geometry->setDrawingMode(GL_LINE_LOOP); + geometry->setLineWidth(dbquad->width); + // QSGGeometry::updateRectGeometry would actually set the corners in the following order: + // top-left, bottom-left, top-right, bottom-right, leading to a nice criss cross, instead + // of having a closed loop. + const gfx::Rect &r(dbquad->rect); + geometry->vertexDataAsPoint2D()[0].set(r.x(), r.y()); + geometry->vertexDataAsPoint2D()[1].set(r.x() + r.width(), r.y()); + geometry->vertexDataAsPoint2D()[2].set(r.x() + r.width(), r.y() + r.height()); + geometry->vertexDataAsPoint2D()[3].set(r.x(), r.y() + r.height()); + geometryNode->setGeometry(geometry); + + QSGFlatColorMaterial *material = new QSGFlatColorMaterial; + material->setColor(toQt(dbquad->color)); + geometryNode->setMaterial(material); + + geometryNode->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); + currentLayerChain->appendChildNode(geometryNode); + break; } case cc::DrawQuad::TILED_CONTENT: { const cc::TileDrawQuad *tquad = cc::TileDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &texture = findMailboxTexture(tquad->resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - - if (!quad->visible_rect.IsEmpty() && !quad->opaque_rect.Contains(quad->visible_rect)) - texture->setHasAlphaChannel(true); + ResourceHolder *resource = findAndHoldResource(tquad->resource_id, resourceCandidates); QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; textureNode->setRect(toQt(quad->rect)); - textureNode->setFiltering(texture->resource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); - textureNode->setTexture(texture.data()); - - // FIXME: Find out if we can implement a QSGSimpleTextureNode::setSourceRect instead of this hack. - // This has to be done at the end since many QSGSimpleTextureNode methods would overwrite this. - QSGGeometry::updateTexturedRectGeometry(textureNode->geometry(), textureNode->rect(), textureNode->texture()->convertToNormalizedSourceRect(toQt(tquad->tex_coord_rect))); + textureNode->setSourceRect(toQt(tquad->tex_coord_rect)); + textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); + textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); currentLayerChain->appendChildNode(textureNode); break; } case cc::DrawQuad::YUV_VIDEO_CONTENT: { const cc::YUVVideoDrawQuad *vquad = cc::YUVVideoDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &yTexture = findMailboxTexture(vquad->y_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - QSharedPointer<MailboxTexture> &uTexture = findMailboxTexture(vquad->u_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - QSharedPointer<MailboxTexture> &vTexture = findMailboxTexture(vquad->v_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - - // Do not use a reference for this one, it might be null. - QSharedPointer<MailboxTexture> aTexture; + ResourceHolder *yResource = findAndHoldResource(vquad->y_plane_resource_id, resourceCandidates); + ResourceHolder *uResource = findAndHoldResource(vquad->u_plane_resource_id, resourceCandidates); + ResourceHolder *vResource = findAndHoldResource(vquad->v_plane_resource_id, resourceCandidates); + ResourceHolder *aResource = 0; // This currently requires --enable-vp8-alpha-playback and needs a video with alpha data to be triggered. if (vquad->a_plane_resource_id) - aTexture = findMailboxTexture(vquad->a_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); + aResource = findAndHoldResource(vquad->a_plane_resource_id, resourceCandidates); - YUVVideoNode *videoNode = new YUVVideoNode(yTexture.data(), uTexture.data(), vTexture.data(), aTexture.data(), toQt(vquad->tex_coord_rect)); + YUVVideoNode *videoNode = new YUVVideoNode( + initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), + initAndHoldTexture(uResource, quad->ShouldDrawWithBlending()), + initAndHoldTexture(vResource, quad->ShouldDrawWithBlending()), + aResource ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) : 0, toQt(vquad->tex_coord_rect)); videoNode->setRect(toQt(quad->rect)); currentLayerChain->appendChildNode(videoNode); break; #ifdef GL_OES_EGL_image_external } case cc::DrawQuad::STREAM_VIDEO_CONTENT: { const cc::StreamVideoDrawQuad *squad = cc::StreamVideoDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &texture = findMailboxTexture(squad->resource_id, m_data->mailboxTextures, mailboxTextureCandidates); + ResourceHolder *resource = findAndHoldResource(squad->resource_id, resourceCandidates); + MailboxTexture *texture = static_cast<MailboxTexture *>(initAndHoldTexture(resource, quad->ShouldDrawWithBlending())); texture->setTarget(GL_TEXTURE_EXTERNAL_OES); // since this is not default TEXTURE_2D type - StreamVideoNode *svideoNode = new StreamVideoNode(texture.data()); + StreamVideoNode *svideoNode = new StreamVideoNode(texture); svideoNode->setRect(toQt(squad->rect)); svideoNode->setTextureMatrix(toQt(squad->matrix.matrix())); currentLayerChain->appendChildNode(svideoNode); @@ -653,8 +650,30 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour } // Send resources of remaining candidates back to the child compositors so that they can be freed or reused. - Q_FOREACH (const QSharedPointer<MailboxTexture> &mailboxTexture, mailboxTextureCandidates.values()) - resourcesToRelease->push_back(mailboxTexture->returnResource()); + typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator ResourceHolderIterator; + ResourceHolderIterator end = resourceCandidates.constEnd(); + for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it) + resourcesToRelease->push_back((*it)->returnResource()); +} + +ResourceHolder *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +{ + // ResourceHolders must survive when the scene graph destroys our node branch + QSharedPointer<ResourceHolder> &resource = m_chromiumCompositorData->resourceHolders[resourceId]; + if (!resource) + resource = candidates.take(resourceId); + Q_ASSERT(resource); + return resource.data(); +} + +QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate) +{ + // QSGTextures must be destroyed in the scene graph thread as part of the QSGNode tree, + // so we can't store them with the ResourceHolder in m_chromiumCompositorData. + // Hold them through a QSharedPointer solely on the root DelegatedFrameNode of the web view + // and access them through a QWeakPointer from the resource holder to find them later. + m_sgObjects.textureStrongRefs.append(resource->initTexture(quadIsAllOpaque, apiDelegate)); + return m_sgObjects.textureStrongRefs.last().data(); } void DelegatedFrameNode::fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch) diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index a031a464f..b866c94b4 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -38,6 +38,7 @@ #define DELEGATED_FRAME_NODE_H #include "base/memory/scoped_ptr.h" +#include "cc/quads/render_pass.h" #include "cc/resources/transferable_resource.h" #include <QMutex> #include <QSGNode> @@ -46,20 +47,25 @@ #include <QWaitCondition> #include "chromium_gpu_helper.h" +#include "render_widget_host_view_qt_delegate.h" + +QT_BEGIN_NAMESPACE +class QSGLayer; +QT_END_NAMESPACE namespace cc { class DelegatedFrameData; } class MailboxTexture; -class RenderPassTexture; +class ResourceHolder; // Separating this data allows another DelegatedFrameNode to reconstruct the QSGNode tree from the mailbox textures // and render pass information. -class DelegatedFrameNodeData : public QSharedData { +class ChromiumCompositorData : public QSharedData { public: - DelegatedFrameNodeData() : frameDevicePixelRatio(1) { } - QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextures; + ChromiumCompositorData() : frameDevicePixelRatio(1) { } + QHash<unsigned, QSharedPointer<ResourceHolder> > resourceHolders; scoped_ptr<cc::DelegatedFrameData> frameData; qreal frameDevicePixelRatio; }; @@ -69,20 +75,27 @@ public: DelegatedFrameNode(); ~DelegatedFrameNode(); void preprocess(); - void commit(DelegatedFrameNodeData* data, cc::ReturnedResourceArray *resourcesToRelease); + void commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate); private: - QExplicitlySharedDataPointer<DelegatedFrameNodeData> m_data; - QList<QSharedPointer<RenderPassTexture> > m_renderPassTextures; - int m_numPendingSyncPoints; - QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; - QWaitCondition m_mailboxesFetchedWaitCond; - QMutex m_mutex; - // Making those callbacks static bypasses base::Bind's ref-counting requirement // of the this pointer when the callback is a method. static void fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch); static void syncPointRetired(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch); + + ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); + QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); + + QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; + struct SGObjects { + QList<QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > > renderPassLayers; + QList<QSharedPointer<QSGRootNode> > renderPassRootNodes; + QList<QSharedPointer<QSGTexture> > textureStrongRefs; + } m_sgObjects; + int m_numPendingSyncPoints; + QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; + QWaitCondition m_mailboxesFetchedWaitCond; + QMutex m_mutex; }; #endif // DELEGATED_FRAME_NODE_H diff --git a/src/core/dev_tools_http_handler_delegate_qt.cpp b/src/core/dev_tools_http_handler_delegate_qt.cpp index 4f8992dab..1bb8ec1f1 100644 --- a/src/core/dev_tools_http_handler_delegate_qt.cpp +++ b/src/core/dev_tools_http_handler_delegate_qt.cpp @@ -34,6 +34,10 @@ ** ****************************************************************************/ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #include "dev_tools_http_handler_delegate_qt.h" #include <QByteArray> @@ -42,16 +46,90 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_http_handler.h" #include "content/public/browser/devtools_target.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_delegate.h" #include "content/public/common/content_switches.h" #include "net/socket/stream_listen_socket.h" #include "net/socket/tcp_listen_socket.h" using namespace content; +namespace { + +const char kTargetTypePage[] = "page"; + +class Target : public content::DevToolsTarget { +public: + explicit Target(WebContents* web_contents); + + virtual std::string GetId() const OVERRIDE { return id_; } + virtual std::string GetParentId() const OVERRIDE { return std::string(); } + virtual std::string GetType() const OVERRIDE { return kTargetTypePage; } + virtual std::string GetTitle() const OVERRIDE { return title_; } + virtual std::string GetDescription() const OVERRIDE { return std::string(); } + virtual GURL GetURL() const OVERRIDE { return url_; } + virtual GURL GetFaviconURL() const OVERRIDE { return favicon_url_; } + virtual base::TimeTicks GetLastActivityTime() const OVERRIDE { + return last_activity_time_; + } + virtual bool IsAttached() const OVERRIDE { + return agent_host_->IsAttached(); + } + virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE { + return agent_host_; + } + virtual bool Activate() const OVERRIDE; + virtual bool Close() const OVERRIDE; + +private: + scoped_refptr<DevToolsAgentHost> agent_host_; + std::string id_; + std::string title_; + GURL url_; + GURL favicon_url_; + base::TimeTicks last_activity_time_; +}; + +Target::Target(WebContents* web_contents) { + agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost()); + id_ = agent_host_->GetId(); + title_ = base::UTF16ToUTF8(web_contents->GetTitle()); + url_ = web_contents->GetURL(); + content::NavigationController& controller = web_contents->GetController(); + content::NavigationEntry* entry = controller.GetActiveEntry(); + if (entry != NULL && entry->GetURL().is_valid()) + favicon_url_ = entry->GetFavicon().url; + last_activity_time_ = web_contents->GetLastActiveTime(); +} + +bool Target::Activate() const { + RenderViewHost* rvh = agent_host_->GetRenderViewHost(); + if (!rvh) + return false; + WebContents* web_contents = WebContents::FromRenderViewHost(rvh); + if (!web_contents) + return false; + web_contents->GetDelegate()->ActivateContents(web_contents); + return true; +} + +bool Target::Close() const { + RenderViewHost* rvh = agent_host_->GetRenderViewHost(); + if (!rvh) + return false; + rvh->ClosePage(); + return true; +} + +} // namespace + DevToolsHttpHandlerDelegateQt::DevToolsHttpHandlerDelegateQt(BrowserContext* browser_context) : m_browserContext(browser_context) { @@ -107,7 +185,14 @@ scoped_ptr<DevToolsTarget> DevToolsHttpHandlerDelegateQt::CreateNewTarget(const void DevToolsHttpHandlerDelegateQt::EnumerateTargets(TargetCallback callback) { - callback.Run(TargetList()); + TargetList targets; + std::vector<RenderViewHost*> rvh_list = content::DevToolsAgentHost::GetValidRenderViewHosts(); + for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin(); it != rvh_list.end(); ++it) { + WebContents* web_contents = WebContents::FromRenderViewHost(*it); + if (web_contents) + targets.push_back(new Target(web_contents)); + } + callback.Run(targets); } scoped_ptr<net::StreamListenSocket> DevToolsHttpHandlerDelegateQt::CreateSocketForTethering(net::StreamListenSocket::Delegate* delegate, std::string* name) diff --git a/src/core/location_provider_qt.cpp b/src/core/location_provider_qt.cpp new file mode 100644 index 000000000..cdc9f1a44 --- /dev/null +++ b/src/core/location_provider_qt.cpp @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "location_provider_qt.h" + +#include <math.h> + +#include "type_conversion.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QThread> +#include <QtPositioning/QGeoPositionInfoSource> + +#include "base/message_loop/message_loop.h" +#include "base/bind.h" +#include "content/browser/geolocation/geolocation_provider_impl.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/geolocation_provider.h" + +using content::BrowserThread; + +class QtPositioningHelper : public QObject { + Q_OBJECT +public: + QtPositioningHelper(LocationProviderQt *provider); + ~QtPositioningHelper(); + + bool start(bool highAccuracy); + void stop(); + void refresh(); + +private Q_SLOTS: + void updatePosition(const QGeoPositionInfo &); + void error(QGeoPositionInfoSource::Error positioningError); + void timeout(); + +private: + LocationProviderQt *m_locationProvider; + QGeoPositionInfoSource *m_positionInfoSource; + + void postToLocationProvider(const base::Closure &task); +}; + +QtPositioningHelper::QtPositioningHelper(LocationProviderQt *provider) + : m_locationProvider(provider) + , m_positionInfoSource(0) +{ + Q_ASSERT(provider); +} + +QtPositioningHelper::~QtPositioningHelper() +{ + m_locationProvider->m_positioningHelper = 0; +} + +bool QtPositioningHelper::start(bool highAccuracy) +{ + DCHECK_CURRENTLY_ON(BrowserThread::UI); + Q_UNUSED(highAccuracy); + // FIXME: go through availableSources until one supports QGeoPositionInfoSource::SatellitePositioningMethods + // for the highAccuracy case. + m_positionInfoSource = QGeoPositionInfoSource::createDefaultSource(this); + if (!m_positionInfoSource) + return false; + + connect(m_positionInfoSource, &QGeoPositionInfoSource::positionUpdated, this, &QtPositioningHelper::updatePosition); + // disambiguate the error getter and the signal in QGeoPositionInfoSource. + connect(m_positionInfoSource, static_cast<void (QGeoPositionInfoSource::*)(QGeoPositionInfoSource::Error)>(&QGeoPositionInfoSource::error) + , this, &QtPositioningHelper::error); + connect(m_positionInfoSource, &QGeoPositionInfoSource::updateTimeout, this, &QtPositioningHelper::timeout); + + m_positionInfoSource->startUpdates(); + return true; +} + +void QtPositioningHelper::stop() +{ + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!m_positionInfoSource) + return; + m_positionInfoSource->stopUpdates(); +} + +void QtPositioningHelper::refresh() +{ + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!m_positionInfoSource) + return; + m_positionInfoSource->stopUpdates(); +} + +void QtPositioningHelper::updatePosition(const QGeoPositionInfo &pos) +{ + if (!pos.isValid()) + return; + Q_ASSERT(m_positionInfoSource->error() == QGeoPositionInfoSource::NoError); + content::Geoposition newPos; + newPos.error_code = content::Geoposition::ERROR_CODE_NONE; + newPos.error_message.clear(); + + newPos.timestamp = toTime(pos.timestamp()); + newPos.latitude = pos.coordinate().latitude(); + newPos.longitude = pos.coordinate().longitude(); + + const double altitude = pos.coordinate().altitude(); + if (!qIsNaN(altitude)) + newPos.altitude = altitude; + + // Chromium's geoposition needs a valid (as in >=0.) accuracy field. + // try and get an accuracy estimate from QGeoPositionInfo. + // If we don't have any accuracy info, 100m seems a pesimistic enough default. + if (!pos.hasAttribute(QGeoPositionInfo::VerticalAccuracy) && !pos.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) + newPos.accuracy = 100; + else { + const double vAccuracy = pos.hasAttribute(QGeoPositionInfo::VerticalAccuracy) ? pos.attribute(QGeoPositionInfo::VerticalAccuracy) : 0; + const double hAccuracy = pos.hasAttribute(QGeoPositionInfo::HorizontalAccuracy) ? pos.attribute(QGeoPositionInfo::HorizontalAccuracy) : 0; + newPos.accuracy = sqrt(vAccuracy * vAccuracy + hAccuracy * hAccuracy); + } + + // And now the "nice to have" fields (-1 means invalid). + newPos.speed = pos.hasAttribute(QGeoPositionInfo::GroundSpeed) ? pos.attribute(QGeoPositionInfo::GroundSpeed) : -1; + newPos.heading = pos.hasAttribute(QGeoPositionInfo::Direction) ? pos.attribute(QGeoPositionInfo::Direction) : -1; + + postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos)); +} + +void QtPositioningHelper::error(QGeoPositionInfoSource::Error positioningError) +{ + Q_ASSERT(positioningError != QGeoPositionInfoSource::NoError); + content::Geoposition newPos; + switch (positioningError) { + case QGeoPositionInfoSource::AccessError: + newPos.error_code = content::Geoposition::ERROR_CODE_PERMISSION_DENIED; + break; + case QGeoPositionInfoSource::ClosedError: + case QGeoPositionInfoSource::UnknownSourceError: // position unavailable is as good as it gets in Geoposition + default: + newPos.error_code = content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; + break; + } + postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos)); +} + +void QtPositioningHelper::timeout() +{ + content::Geoposition newPos; + // content::Geoposition::ERROR_CODE_TIMEOUT is not handled properly in the renderer process, and the timeout + // argument used in JS never comes all the way to the browser process. + // Let's just treat it like any other error where the position is unavailable. + newPos.error_code = content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; + postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos)); +} + +inline void QtPositioningHelper::postToLocationProvider(const base::Closure &task) +{ + LocationProviderQt::messageLoop()->PostTask(FROM_HERE, task); +} + +#include "location_provider_qt.moc" + +LocationProviderQt::LocationProviderQt() + : m_positioningHelper(0) +{ +} + +LocationProviderQt::~LocationProviderQt() +{ + m_positioningHelper->deleteLater(); +} + +bool LocationProviderQt::StartProvider(bool highAccuracy) +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + QThread *guiThread = qApp->thread(); + if (!m_positioningHelper) { + m_positioningHelper = new QtPositioningHelper(this); + m_positioningHelper->moveToThread(guiThread); + } + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(base::IgnoreResult(&QtPositioningHelper::start) + , base::Unretained(m_positioningHelper), highAccuracy)); + return true; +} + +void LocationProviderQt::StopProvider() +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + if (m_positioningHelper) + BrowserThread::PostTask(BrowserThread::UI,FROM_HERE, base::Bind(&QtPositioningHelper::stop + , base::Unretained(m_positioningHelper))); +} + +void LocationProviderQt::RequestRefresh() +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + if (m_positioningHelper) + BrowserThread::PostTask(BrowserThread::UI,FROM_HERE, base::Bind(&QtPositioningHelper::refresh + , base::Unretained(m_positioningHelper))); +} + +void LocationProviderQt::OnPermissionGranted() +{ + RequestRefresh(); +} + +void LocationProviderQt::updatePosition(const content::Geoposition &position) +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + m_lastKnownPosition = position; + NotifyCallback(position); +} + +base::MessageLoop *LocationProviderQt::messageLoop() +{ + return static_cast<content::GeolocationProviderImpl*>(content::GeolocationProvider::GetInstance())->message_loop(); +} diff --git a/src/core/location_provider_qt.h b/src/core/location_provider_qt.h new file mode 100644 index 000000000..c3e462092 --- /dev/null +++ b/src/core/location_provider_qt.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LOCATION_PROVIDER_QT_H +#define LOCATION_PROVIDER_QT_H + +#include <QtCore/qcompilerdetection.h> + +#include "content/browser/geolocation/location_provider_base.h" +#include "content/public/common/geoposition.h" + +QT_FORWARD_DECLARE_CLASS(QThread) +class QtPositioningHelper; + +namespace base { +class MessageLoop; +} + +class LocationProviderQt : public content::LocationProviderBase +{ +public: + LocationProviderQt(); + virtual ~LocationProviderQt(); + + // LocationProviderBase + virtual bool StartProvider(bool highAccuracy) Q_DECL_OVERRIDE; + virtual void StopProvider() Q_DECL_OVERRIDE; + virtual void GetPosition(content::Geoposition *position) Q_DECL_OVERRIDE { *position = m_lastKnownPosition; } + virtual void RequestRefresh() Q_DECL_OVERRIDE; + virtual void OnPermissionGranted() Q_DECL_OVERRIDE; + +private: + friend class QtPositioningHelper; + + static base::MessageLoop *messageLoop(); + void updatePosition(const content::Geoposition &); + + content::Geoposition m_lastKnownPosition; + QtPositioningHelper *m_positioningHelper; +}; +//#define QT_USE_POSITIONING 1 + +#endif // LOCATION_PROVIDER_QT_H diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index c221e94e3..fec9caabc 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -189,7 +189,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget : m_host(content::RenderWidgetHostImpl::From(widget)) , m_gestureProvider(QtGestureProviderConfig(), this) , m_sendMotionActionDown(false) - , m_frameNodeData(new DelegatedFrameNodeData) + , m_chromiumCompositorData(new ChromiumCompositorData) , m_needsDelegatedFrameAck(false) , m_didFirstVisuallyNonEmptyLayout(false) , m_adapterClient(0) @@ -594,14 +594,14 @@ void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32 output_surface_id, sco m_needsDelegatedFrameAck = true; m_pendingOutputSurfaceId = output_surface_id; Q_ASSERT(frame->delegated_frame_data); - Q_ASSERT(!m_frameNodeData->frameData || m_frameNodeData->frameData->resource_list.empty()); - m_frameNodeData->frameData = frame->delegated_frame_data.Pass(); - m_frameNodeData->frameDevicePixelRatio = frame->metadata.device_scale_factor; + Q_ASSERT(!m_chromiumCompositorData->frameData || m_chromiumCompositorData->frameData->resource_list.empty()); + m_chromiumCompositorData->frameData = frame->delegated_frame_data.Pass(); + m_chromiumCompositorData->frameDevicePixelRatio = frame->metadata.device_scale_factor; // Support experimental.viewport.devicePixelRatio, see GetScreenInfo implementation below. float dpiScale = this->dpiScale(); if (dpiScale != 0 && dpiScale != 1) - m_frameNodeData->frameDevicePixelRatio /= dpiScale; + m_chromiumCompositorData->frameDevicePixelRatio /= dpiScale; m_delegate->update(); @@ -661,7 +661,7 @@ QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) if (!frameNode) frameNode = new DelegatedFrameNode; - frameNode->commit(m_frameNodeData.data(), &m_resourcesToRelease); + frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_delegate.get()); // This is possibly called from the Qt render thread, post the ack back to the UI // to tell the child compositors to release resources and trigger a new frame. diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index d4a3ff248..fdb43dcae 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -235,7 +235,7 @@ private: QMap<int, int> m_touchIdMapping; scoped_ptr<RenderWidgetHostViewQtDelegate> m_delegate; - QExplicitlySharedDataPointer<DelegatedFrameNodeData> m_frameNodeData; + QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; cc::ReturnedResourceArray m_resourcesToRelease; bool m_needsDelegatedFrameAck; bool m_didFirstVisuallyNonEmptyLayout; diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 3f6d9caac..0fb3d1d5f 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -46,7 +46,10 @@ QT_BEGIN_NAMESPACE class QCursor; class QEvent; class QPainter; +class QSGImageNode; +class QSGLayer; class QSGNode; +class QSGTexture; class QVariant; class QWindow; class QInputMethodEvent; @@ -78,6 +81,9 @@ public: virtual void hide() = 0; virtual bool isVisible() const = 0; virtual QWindow* window() const = 0; + virtual QSGTexture *createTextureFromImage(const QImage &) = 0; + virtual QSGLayer *createLayer() = 0; + virtual QSGImageNode *createImageNode() = 0; virtual void update() = 0; virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; diff --git a/src/core/resources/devtools_discovery_page.html b/src/core/resources/devtools_discovery_page.html index 79463cc16..7aac74932 100644 --- a/src/core/resources/devtools_discovery_page.html +++ b/src/core/resources/devtools_discovery_page.html @@ -1,18 +1,55 @@ -<!-- -Copyright (c) 2013 BlackBerry Limited. All rights reserved. ---> <html> <head> -<title>QtWebEngine remote debugging</title> +<title>QtWebEngine Remote Debugging</title> <style> +body { + background-color: rgb(245, 245, 245); + font-family: Helvetica, Arial, sans-serif; + text-shadow: rgba(255, 255, 255, 0.496094) 0px 1px 0px; +} + +#caption { + color: black; + font-size: 16px; + margin-top: 30px; + margin-bottom: 0px; + margin-left: 70px; + height: 20px; + text-align: left; +} + +#items { + margin-left: 60px; + margin-right: 60px; + -webkit-box-orient: horizontal; + -webkit-box-lines: multiple; +} + +.frontend_ref { + color: black; + text-decoration: initial; +} + +.text { + background: no-repeat 0; + background-size: 16px; + font-size: 12px; + margin: 4px 0px 0px 4px; + overflow: hidden; + padding: 2px 0px 0px 20px; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; +} </style> <script> + function onLoad() { - var tabs_list_request = new XMLHttpRequest(); - tabs_list_request.open('GET', '/json/list?t=' + new Date().getTime(), true); - tabs_list_request.onreadystatechange = onReady; - tabs_list_request.send(); + var tabsListRequest = new XMLHttpRequest(); + tabsListRequest.open('GET', '/json/list', true); + tabsListRequest.onreadystatechange = onReady; + tabsListRequest.send(); } function onReady() { @@ -24,23 +61,35 @@ function onReady() { } } +function overrideFrontendUrl(item) { + if (window.location.hash) { + var overridden_url = window.location.hash.substr(1); + var ws_suffix = item.webSocketDebuggerUrl.replace('ws://', 'ws='); + if (overridden_url.indexOf('?') == -1) + return overridden_url + '?' + ws_suffix; + else + return overridden_url + '&' + ws_suffix; + } + return item.devtoolsFrontendUrl; +} + function appendItem(item_object) { var frontend_ref; if (item_object.devtoolsFrontendUrl) { frontend_ref = document.createElement('a'); - frontend_ref.href = item_object.devtoolsFrontendUrl; + frontend_ref.href = overrideFrontendUrl(item_object); frontend_ref.title = item_object.title; } else { frontend_ref = document.createElement('div'); - frontend_ref.title = 'The tab already has active debugging session'; + frontend_ref.title = 'The tab already has an active debug session'; } + frontend_ref.className = 'frontend_ref'; var text = document.createElement('div'); - if (item_object.title) - text.innerText = item_object.title; - else - text.innerText = '(untitled tab)'; - text.style.cssText = 'background-image:url(' + item_object.faviconUrl + ')'; + text.className = 'text'; + text.innerText = item_object.description || item_object.title; + text.style.cssText = 'background-image:url(' + + item_object.faviconUrl + ')'; frontend_ref.appendChild(text); var item = document.createElement('p'); @@ -51,7 +100,9 @@ function appendItem(item_object) { </script> </head> <body onload='onLoad()'> - <div id='caption'>Inspectable WebContents</div> - <div id='items'></div> + <div id='caption'>Inspectable pages</div> + <div id='items'> + </div> + <hr> </body> </html> diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 9d9cdd675..f88e5dd21 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -135,6 +135,10 @@ inline QDateTime toQt(base::Time time) return QDateTime::fromMSecsSinceEpoch(time.ToJavaTime()); } +inline base::Time toTime(const QDateTime &dateTime) { + return base::Time::FromInternalValue(dateTime.toMSecsSinceEpoch()); +} + inline base::FilePath::StringType toFilePathString(const QString &str) { #if defined(OS_WIN) @@ -150,7 +154,7 @@ inline base::FilePath toFilePath(const QString &str) } template <typename T> -inline T fileListingHelper(const QString &) {qFatal("Specialization missing for %s.", Q_FUNC_INFO);} +inline T fileListingHelper(const QString &) {qFatal("Specialization missing for %s.", Q_FUNC_INFO); return T(); } template <> inline ui::SelectedFileInfo fileListingHelper<ui::SelectedFileInfo>(const QString &file) diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 3f223f733..678b558c1 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -41,6 +41,7 @@ #include "web_contents_adapter.h" #include "web_contents_adapter_p.h" +#include "browser_context_adapter.h" #include "browser_context_qt.h" #include "content_browser_client_qt.h" #include "javascript_dialog_manager_qt.h" @@ -175,9 +176,8 @@ static QStringList listRecursively(const QDir& dir) { return ret; } -static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient) +static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient, content::BrowserContext *browserContext) { - content::BrowserContext* browserContext = ContentBrowserClientQt::Get()->browser_context(); content::WebContents::CreateParams create_params(browserContext, NULL); create_params.routing_id = MSG_ROUTING_NONE; create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight); @@ -222,7 +222,7 @@ static void serializeNavigationHistory(const content::NavigationController &cont } } -void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::vector<content::NavigationEntry*> *entries) +void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::vector<content::NavigationEntry*> *entries, content::BrowserContext *browserContext) { int version; input >> version; @@ -278,7 +278,7 @@ void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::ve false, // The extra headers are not sync'ed across sessions. std::string(), - ContentBrowserClientQt::Get()->browser_context()); + browserContext); entry->SetTitle(toString16(title)); entry->SetPageState(content::PageState::CreateFromEncodedData(std::string(pageState.data(), pageState.size()))); @@ -308,13 +308,13 @@ QExplicitlySharedDataPointer<WebContentsAdapter> WebContentsAdapter::createFromS { int currentIndex; std::vector<content::NavigationEntry*> entries; - deserializeNavigationHistory(input, ¤tIndex, &entries); + deserializeNavigationHistory(input, ¤tIndex, &entries, adapterClient->browserContextAdapter()->browserContext()); if (currentIndex == -1) return QExplicitlySharedDataPointer<WebContentsAdapter>(); // Unlike WebCore, Chromium only supports Restoring to a new WebContents instance. - content::WebContents* newWebContents = createBlankWebContents(adapterClient); + content::WebContents* newWebContents = createBlankWebContents(adapterClient, adapterClient->browserContextAdapter()->browserContext()); content::NavigationController &controller = newWebContents->GetController(); controller.Restore(currentIndex, content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries); @@ -350,7 +350,7 @@ void WebContentsAdapter::initialize(WebContentsAdapterClient *adapterClient) // Create our own if a WebContents wasn't provided at construction. if (!d->webContents) - d->webContents.reset(createBlankWebContents(adapterClient)); + d->webContents.reset(createBlankWebContents(adapterClient, adapterClient->browserContextAdapter()->browserContext())); // This might replace any adapter that has been initialized with this WebEngineSettings. adapterClient->webEngineSettings()->setWebContentsAdapter(this); @@ -625,7 +625,13 @@ qreal WebContentsAdapter::currentZoomFactor() const void WebContentsAdapter::enableInspector(bool enable) { - ContentBrowserClientQt::Get()->enableInspector(enable); + ContentBrowserClientQt::Get()->enableInspector(enable, browserContext()); +} + +BrowserContextQt* WebContentsAdapter::browserContext() +{ + Q_D(WebContentsAdapter); + return static_cast<BrowserContextQt*>(d->webContents->GetBrowserContext()); } QAccessibleInterface *WebContentsAdapter::browserAccessible() @@ -724,6 +730,12 @@ void WebContentsAdapter::grantMediaAccessPermission(const QUrl &securityOrigin, MediaCaptureDevicesDispatcher::GetInstance()->handleMediaAccessPermissionResponse(d->webContents.get(), securityOrigin, flags); } +void WebContentsAdapter::runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed) +{ + Q_D(WebContentsAdapter); + d->webContentsDelegate->m_lastGeolocationRequestCallbacks.first.Run(allowed); +} + void WebContentsAdapter::dpiScaleChanged() { Q_D(WebContentsAdapter); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 6bec50316..18542d039 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -48,6 +48,7 @@ namespace content { class WebContents; } +class BrowserContextQt; class WebContentsAdapterPrivate; struct WebPreferences; @@ -108,14 +109,17 @@ public: void wasShown(); void wasHidden(); void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); + void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed); void dpiScaleChanged(); QAccessibleInterface *browserAccessible(); + BrowserContextQt* browserContext(); private: Q_DISABLE_COPY(WebContentsAdapter); Q_DECLARE_PRIVATE(WebContentsAdapter); QScopedPointer<WebContentsAdapterPrivate> d_ptr; + friend class WebContentsDelegateQt; }; #endif // WEB_CONTENTS_ADAPTER_H diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 8fd401fe4..df2039ba6 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -48,6 +48,7 @@ QT_FORWARD_DECLARE_CLASS(QVariant) +class BrowserContextAdapter; class CertificateErrorController; class JavaScriptDialogController; class RenderWidgetHostViewQt; @@ -171,11 +172,14 @@ public: virtual QObject *accessibilityParentObject() = 0; virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) = 0; virtual void authenticationRequired(const QUrl &requestUrl, const QString &realm, bool isProxy, const QString &challengingHost, QString *outUser, QString *outPassword) = 0; + virtual void runGeolocationPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) = 0; virtual WebEngineSettings *webEngineSettings() const = 0; virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController) = 0; + virtual BrowserContextAdapter* browserContextAdapter() = 0; + }; #endif // WEB_CONTENTS_ADAPTER_CLIENT_H diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index c2cccfedb..46830f865 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -40,6 +40,7 @@ #include "web_contents_delegate_qt.h" +#include "browser_context_adapter.h" #include "media_capture_devices_dispatcher.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" @@ -270,7 +271,7 @@ void WebContentsDelegateQt::DidNavigateAnyFrame(const content::LoadCommittedDeta { if (!params.should_update_history) return; - WebEngineContext::current()->visitedLinksManager()->addUrl(params.url); + m_viewClient->browserContextAdapter()->visitedLinksManager()->addUrl(params.url); } @@ -300,3 +301,9 @@ void WebContentsDelegateQt::allowCertificateError(const QExplicitlySharedDataPoi { m_viewClient->allowCertificateError(errorController); } + +void WebContentsDelegateQt::requestGeolocationPermission(const GURL &requestingFrameOrigin, base::Callback<void (bool)> resultCallback, base::Closure *cancelCallback) +{ + m_lastGeolocationRequestCallbacks = qMakePair(resultCallback, cancelCallback); + m_viewClient->runGeolocationPermissionRequest(toQt(requestingFrameOrigin)); +} diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 2ab5fc8cd..29a548f47 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -40,6 +40,8 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" +#include "base/callback.h" + #include "javascript_dialog_manager_qt.h" #include <QtCore/qcompilerdetection.h> @@ -88,7 +90,9 @@ public: void overrideWebPreferences(content::WebContents *, WebPreferences*); void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &) ; + void requestGeolocationPermission(const GURL &requestingFrameOrigin, base::Callback<void (bool)> resultCallback, base::Closure *cancelCallback); + QPair<base::Callback<void (bool)>, base::Closure*> m_lastGeolocationRequestCallbacks; private: WebContentsAdapter *createWindow(content::WebContents *new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index ac9a921e7..b17ee124c 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -65,6 +65,7 @@ #include "content/public/app/startup_helper_win.h" #endif // OS_WIN +#include "browser_context_adapter.h" #include "content_browser_client_qt.h" #include "content_client_qt.h" #include "content_main_delegate_qt.h" @@ -73,7 +74,7 @@ #include "type_conversion.h" #include "surface_factory_qt.h" #include "web_engine_library_info.h" -#include "web_engine_visited_links_manager.h" +#include <QFileInfo> #include <QGuiApplication> #include <QOpenGLContext> #include <QStringList> @@ -89,6 +90,37 @@ void destroyContext() sContext = 0; } +bool usingSoftwareDynamicGL() +{ +#if defined(Q_OS_WIN) + HMODULE handle = static_cast<HMODULE>(QOpenGLContext::openGLModuleHandle()); + wchar_t path[MAX_PATH]; + DWORD size = GetModuleFileName(handle, path, MAX_PATH); + QFileInfo openGLModule(QString::fromWCharArray(path, size)); + return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); +#else + return false; +#endif +} + +bool usingQtQuick2DRenderer() +{ + const QStringList args = QGuiApplication::arguments(); + QString device; + for (int index = 0; index < args.count(); ++index) { + if (args.at(index).startsWith(QLatin1String("--device="))) { + device = args.at(index).mid(9); + break; + } + } + + if (device.isEmpty()) + device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE")); + + // This assumes that the plugin is installed and is going to be used by QtQuick. + return device == QLatin1String("softwarecontext"); +} + } // namespace WebEngineContext::~WebEngineContext() @@ -107,9 +139,18 @@ scoped_refptr<WebEngineContext> WebEngineContext::current() return sContext; } -WebEngineVisitedLinksManager *WebEngineContext::visitedLinksManager() +BrowserContextAdapter* WebEngineContext::defaultBrowserContext() { - return m_visitedLinksManager.get(); + if (!m_defaultBrowserContext) + m_defaultBrowserContext.reset(new BrowserContextAdapter(QStringLiteral("Default"), false)); + return m_defaultBrowserContext.get(); +} + +BrowserContextAdapter* WebEngineContext::offTheRecordBrowserContext() +{ + if (!m_offTheRecordBrowserContext) + m_offTheRecordBrowserContext.reset(new BrowserContextAdapter(QStringLiteral("OTR"), true)); + return m_offTheRecordBrowserContext.get(); } #ifndef CHROMIUM_VERSION @@ -176,16 +217,20 @@ WebEngineContext::WebEngineContext() GLContextHelper::initialize(); - const char *glType; - switch (QOpenGLContext::currentContext()->openGLModuleType()) { - case QOpenGLContext::LibGL: - glType = gfx::kGLImplementationDesktopName; - break; - case QOpenGLContext::LibGLES: - glType = gfx::kGLImplementationEGLName; - break; + if (usingSoftwareDynamicGL() || usingQtQuick2DRenderer()) { + parsedCommandLine->AppendSwitch(switches::kDisableGpu); + } else { + const char *glType; + switch (QOpenGLContext::openGLModuleType()) { + case QOpenGLContext::LibGL: + glType = gfx::kGLImplementationDesktopName; + break; + case QOpenGLContext::LibGLES: + glType = gfx::kGLImplementationEGLName; + break; + } + parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); } - parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); content::UtilityProcessHostImpl::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); @@ -208,7 +253,4 @@ WebEngineContext::WebEngineContext() // thread to avoid a thread check assertion in its constructor when it // first gets referenced on the IO thread. MediaCaptureDevicesDispatcher::GetInstance(); - - // Ensure we have a VisitedLinksMaster instance up and running - m_visitedLinksManager.reset(new WebEngineVisitedLinksManager); } diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index d1cd9a7a5..0b3ad8678 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -49,15 +49,16 @@ class BrowserMainRunner; class ContentMainRunner; } +class BrowserContextAdapter; class ContentMainDelegateQt; class SurfaceFactoryQt; -class WebEngineVisitedLinksManager; class WebEngineContext : public base::RefCounted<WebEngineContext> { public: static scoped_refptr<WebEngineContext> current(); - WebEngineVisitedLinksManager *visitedLinksManager(); + BrowserContextAdapter *defaultBrowserContext(); + BrowserContextAdapter *offTheRecordBrowserContext(); private: friend class base::RefCounted<WebEngineContext>; @@ -71,7 +72,8 @@ private: #if defined(OS_ANDROID) scoped_ptr<SurfaceFactoryQt> m_surfaceFactory; #endif - scoped_ptr<WebEngineVisitedLinksManager> m_visitedLinksManager; + scoped_ptr<BrowserContextAdapter> m_defaultBrowserContext; + scoped_ptr<BrowserContextAdapter> m_offTheRecordBrowserContext; }; #endif // WEB_ENGINE_CONTEXT_H diff --git a/src/core/web_engine_visited_links_manager.cpp b/src/core/web_engine_visited_links_manager.cpp index 36467ca21..a2f6dbf9f 100644 --- a/src/core/web_engine_visited_links_manager.cpp +++ b/src/core/web_engine_visited_links_manager.cpp @@ -36,8 +36,9 @@ #include "web_engine_visited_links_manager.h" -#include "content_browser_client_qt.h" +#include "browser_context_adapter.h" #include "browser_context_qt.h" +#include "content_browser_client_qt.h" #include "type_conversion.h" #include "base/memory/scoped_ptr.h" @@ -80,11 +81,11 @@ void WebEngineVisitedLinksManager::deleteVisitedLinkDataForUrls(const QList<QUrl m_visitedLinkMaster->DeleteURLs(&iterator); } -WebEngineVisitedLinksManager::WebEngineVisitedLinksManager() +WebEngineVisitedLinksManager::WebEngineVisitedLinksManager(BrowserContextAdapter *adapter) : m_delegate(new VisitedLinkDelegateQt) { - Q_ASSERT(ContentBrowserClientQt::Get() && ContentBrowserClientQt::Get()->browser_context()); - BrowserContextQt *browserContext = ContentBrowserClientQt::Get()->browser_context(); + Q_ASSERT(adapter && adapter->browserContext()); + BrowserContextQt *browserContext = adapter->browserContext(); m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(browserContext, m_delegate.data(), /* persist to disk = */true)); m_visitedLinkMaster->Init(); } diff --git a/src/core/web_engine_visited_links_manager.h b/src/core/web_engine_visited_links_manager.h index aa44dd9cf..5b0286c51 100644 --- a/src/core/web_engine_visited_links_manager.h +++ b/src/core/web_engine_visited_links_manager.h @@ -49,6 +49,7 @@ namespace visitedlink { class VisitedLinkMaster; } +class BrowserContextAdapter; class VisitedLinkDelegateQt; class GURL; @@ -57,7 +58,7 @@ class QWEBENGINE_EXPORT WebEngineVisitedLinksManager { public: virtual~WebEngineVisitedLinksManager(); - WebEngineVisitedLinksManager(); + WebEngineVisitedLinksManager(BrowserContextAdapter*); void deleteAllVisitedLinkData(); void deleteVisitedLinkDataForUrls(const QList<QUrl> &); diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp index 743d22d81..e46b1a80d 100644 --- a/src/webengine/api/qquickwebenginesettings.cpp +++ b/src/webengine/api/qquickwebenginesettings.cpp @@ -43,6 +43,20 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QList<QQuickWebEngineSettingsPrivate*>, allSettings) +class QQuickWebEngineGlobalSettings { + QQuickWebEngineSettings globalSettings; +public: + QQuickWebEngineGlobalSettings() { + // globalSettings shouldn't be in that list. + allSettings->removeAll(globalSettings.d_func()); + globalSettings.d_func()->coreSettings->initDefaults(); + } + + QQuickWebEngineSettings *data() { return &globalSettings; } +}; + +Q_GLOBAL_STATIC(QQuickWebEngineGlobalSettings, globalInstance) + QQuickWebEngineSettingsPrivate::QQuickWebEngineSettingsPrivate() : coreSettings(new WebEngineSettings(this)) { @@ -64,16 +78,9 @@ WebEngineSettings *QQuickWebEngineSettingsPrivate::fallbackSettings() const return QQuickWebEngineSettings::globalSettings()->d_func()->coreSettings.data(); } - QQuickWebEngineSettings *QQuickWebEngineSettings::globalSettings() { - static QQuickWebEngineSettings *globals = 0; - if (!globals) { - globals = new QQuickWebEngineSettings; - allSettings->removeAll(globals->d_func()); - globals->d_func()->coreSettings->initDefaults(); - } - return globals; + return globalInstance()->data(); } QQuickWebEngineSettings::~QQuickWebEngineSettings() @@ -161,7 +168,7 @@ void QQuickWebEngineSettings::setAutoLoadImages(bool on) // could be from the fallback and is prone to changing later on. d->coreSettings->setAttribute(WebEngineSettings::AutoLoadImages, on); if (wasOn ^ on) - Q_EMIT autoLoadImagesChanged(on); + Q_EMIT autoLoadImagesChanged(); } void QQuickWebEngineSettings::setJavascriptEnabled(bool on) @@ -170,7 +177,7 @@ void QQuickWebEngineSettings::setJavascriptEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptEnabled); d->coreSettings->setAttribute(WebEngineSettings::JavascriptEnabled, on); if (wasOn ^ on) - Q_EMIT javascriptEnabledChanged(on); + Q_EMIT javascriptEnabledChanged(); } void QQuickWebEngineSettings::setJavascriptCanOpenWindows(bool on) @@ -179,7 +186,7 @@ void QQuickWebEngineSettings::setJavascriptCanOpenWindows(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanOpenWindows); d->coreSettings->setAttribute(WebEngineSettings::JavascriptCanOpenWindows, on); if (wasOn ^ on) - Q_EMIT javascriptCanOpenWindowsChanged(on); + Q_EMIT javascriptCanOpenWindowsChanged(); } void QQuickWebEngineSettings::setJavascriptCanAccessClipboard(bool on) @@ -188,7 +195,7 @@ void QQuickWebEngineSettings::setJavascriptCanAccessClipboard(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard); d->coreSettings->setAttribute(WebEngineSettings::JavascriptCanAccessClipboard, on); if (wasOn ^ on) - Q_EMIT javascriptCanAccessClipboardChanged(on); + Q_EMIT javascriptCanAccessClipboardChanged(); } void QQuickWebEngineSettings::setLinksIncludedInFocusChain(bool on) @@ -197,7 +204,7 @@ void QQuickWebEngineSettings::setLinksIncludedInFocusChain(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LinksIncludedInFocusChain); d->coreSettings->setAttribute(WebEngineSettings::LinksIncludedInFocusChain, on); if (wasOn ^ on) - Q_EMIT linksIncludedInFocusChainChanged(on); + Q_EMIT linksIncludedInFocusChainChanged(); } void QQuickWebEngineSettings::setLocalStorageEnabled(bool on) @@ -206,7 +213,7 @@ void QQuickWebEngineSettings::setLocalStorageEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalStorageEnabled); d->coreSettings->setAttribute(WebEngineSettings::LocalStorageEnabled, on); if (wasOn ^ on) - Q_EMIT localStorageEnabledChanged(on); + Q_EMIT localStorageEnabledChanged(); } void QQuickWebEngineSettings::setLocalContentCanAccessRemoteUrls(bool on) @@ -215,7 +222,7 @@ void QQuickWebEngineSettings::setLocalContentCanAccessRemoteUrls(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls); d->coreSettings->setAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls, on); if (wasOn ^ on) - Q_EMIT localContentCanAccessRemoteUrlsChanged(on); + Q_EMIT localContentCanAccessRemoteUrlsChanged(); } @@ -225,7 +232,7 @@ void QQuickWebEngineSettings::setSpatialNavigationEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::SpatialNavigationEnabled); d->coreSettings->setAttribute(WebEngineSettings::SpatialNavigationEnabled, on); if (wasOn ^ on) - Q_EMIT spatialNavigationEnabledChanged(on); + Q_EMIT spatialNavigationEnabledChanged(); } void QQuickWebEngineSettings::setLocalContentCanAccessFileUrls(bool on) @@ -234,7 +241,7 @@ void QQuickWebEngineSettings::setLocalContentCanAccessFileUrls(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls); d->coreSettings->setAttribute(WebEngineSettings::LocalContentCanAccessFileUrls, on); if (wasOn ^ on) - Q_EMIT localContentCanAccessFileUrlsChanged(on); + Q_EMIT localContentCanAccessFileUrlsChanged(); } void QQuickWebEngineSettings::setHyperlinkAuditingEnabled(bool on) @@ -243,7 +250,7 @@ void QQuickWebEngineSettings::setHyperlinkAuditingEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::HyperlinkAuditingEnabled); d->coreSettings->setAttribute(WebEngineSettings::HyperlinkAuditingEnabled, on); if (wasOn ^ on) - Q_EMIT hyperlinkAuditingEnabledChanged(on); + Q_EMIT hyperlinkAuditingEnabledChanged(); } void QQuickWebEngineSettings::setErrorPageEnabled(bool on) @@ -252,7 +259,7 @@ void QQuickWebEngineSettings::setErrorPageEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::ErrorPageEnabled); d->coreSettings->setAttribute(WebEngineSettings::ErrorPageEnabled, on); if (wasOn ^ on) - Q_EMIT errorPageEnabledChanged(on); + Q_EMIT errorPageEnabledChanged(); } void QQuickWebEngineSettings::setDefaultTextEncoding(QString encoding) @@ -261,7 +268,7 @@ void QQuickWebEngineSettings::setDefaultTextEncoding(QString encoding) const QString oldDefaultTextEncoding = d->coreSettings->defaultTextEncoding(); d->coreSettings->setDefaultTextEncoding(encoding); if (oldDefaultTextEncoding.compare(encoding)) - Q_EMIT defaultTextEncodingChanged(encoding); + Q_EMIT defaultTextEncodingChanged(); } QQuickWebEngineSettings::QQuickWebEngineSettings() diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index 4a7c2f834..040a5f5fb 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineSettingsPrivate; +class QQuickWebEngineGlobalSettings; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_OBJECT @@ -92,24 +93,25 @@ public: void setDefaultTextEncoding(QString encoding); signals: - void autoLoadImagesChanged(bool on); - void javascriptEnabledChanged(bool on); - void javascriptCanOpenWindowsChanged(bool on); - void javascriptCanAccessClipboardChanged(bool on); - void linksIncludedInFocusChainChanged(bool on); - void localStorageEnabledChanged(bool on); - void localContentCanAccessRemoteUrlsChanged(bool on); - void spatialNavigationEnabledChanged(bool on); - void localContentCanAccessFileUrlsChanged(bool on); - void hyperlinkAuditingEnabledChanged(bool on); - void errorPageEnabledChanged(bool on); - void defaultTextEncodingChanged(QString encoding); + void autoLoadImagesChanged(); + void javascriptEnabledChanged(); + void javascriptCanOpenWindowsChanged(); + void javascriptCanAccessClipboardChanged(); + void linksIncludedInFocusChainChanged(); + void localStorageEnabledChanged(); + void localContentCanAccessRemoteUrlsChanged(); + void spatialNavigationEnabledChanged(); + void localContentCanAccessFileUrlsChanged(); + void hyperlinkAuditingEnabledChanged(); + void errorPageEnabledChanged(); + void defaultTextEncodingChanged(); private: QQuickWebEngineSettings(); Q_DISABLE_COPY(QQuickWebEngineSettings) Q_DECLARE_PRIVATE(QQuickWebEngineSettings) friend class QQuickWebEngineViewPrivate; + friend class QQuickWebEngineGlobalSettings; QScopedPointer<QQuickWebEngineSettingsPrivate> d_ptr; }; diff --git a/src/webengine/api/qquickwebenginesettings_p_p.h b/src/webengine/api/qquickwebenginesettings_p_p.h index 8f3e95eea..05a163b92 100644 --- a/src/webengine/api/qquickwebenginesettings_p_p.h +++ b/src/webengine/api/qquickwebenginesettings_p_p.h @@ -44,7 +44,6 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineSettingsPrivate : public WebEngineSettingsDelegate { public: QQuickWebEngineSettingsPrivate(); - QQuickWebEngineSettingsPrivate(WebContentsAdapter *adapter); void apply() Q_DECL_OVERRIDE; WebEngineSettings *fallbackSettings() const Q_DECL_OVERRIDE; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index ad850e84e..dccbb5b9f 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -37,6 +37,7 @@ #include "qquickwebengineview_p.h" #include "qquickwebengineview_p_p.h" +#include "browser_context_adapter.h" #include "certificate_error_controller.h" #include "javascript_dialog_controller.h" #include "qquickwebenginehistory_p.h" @@ -217,6 +218,11 @@ void QQuickWebEngineViewPrivate::allowCertificateError(const QExplicitlySharedDa Q_UNUSED(errorController); } +void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url) +{ + Q_EMIT e->featurePermissionRequested(url, QQuickWebEngineViewExperimental::Geolocation); +} + void QQuickWebEngineViewPrivate::runFileChooser(FileChooserMode mode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) { ui()->showFilePicker(mode, defaultFileName, acceptedMimeTypes, adapter); @@ -343,9 +349,11 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebConten switch (disposition) { case WebContentsAdapterClient::NewForegroundTabDisposition: - case WebContentsAdapterClient::NewBackgroundTabDisposition: request.m_destination = QQuickWebEngineView::NewViewInTab; break; + case WebContentsAdapterClient::NewBackgroundTabDisposition: + request.m_destination = QQuickWebEngineView::NewViewInBackgroundTab; + break; case WebContentsAdapterClient::NewPopupDisposition: request.m_destination = QQuickWebEngineView::NewViewInDialog; break; @@ -356,7 +364,7 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebConten Q_UNREACHABLE(); } - emit e->newViewRequested(&request); + Q_EMIT e->newViewRequested(&request); } void QQuickWebEngineViewPrivate::close() @@ -387,11 +395,11 @@ void QQuickWebEngineViewPrivate::runMediaAccessPermissionRequest(const QUrl &sec return; QQuickWebEngineViewExperimental::Feature feature; if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QQuickWebEngineViewExperimental::MediaAudioVideoDevices; + feature = QQuickWebEngineViewExperimental::MediaAudioVideoCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) - feature = QQuickWebEngineViewExperimental::MediaAudioDevices; + feature = QQuickWebEngineViewExperimental::MediaAudioCapture; else // WebContentsAdapterClient::MediaVideoCapture - feature = QQuickWebEngineViewExperimental::MediaVideoDevices; + feature = QQuickWebEngineViewExperimental::MediaVideoCapture; Q_EMIT e->featurePermissionRequested(securityOrigin, feature); } @@ -401,6 +409,11 @@ QObject *QQuickWebEngineViewPrivate::accessibilityParentObject() return q; } +BrowserContextAdapter *QQuickWebEngineViewPrivate::browserContextAdapter() +{ + return BrowserContextAdapter::defaultContext(); +} + WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const { return m_settings->d_func()->coreSettings.data(); @@ -557,6 +570,17 @@ void QQuickWebEngineView::stop() d->adapter->stop(); } +void QQuickWebEngineView::setZoomFactor(qreal arg) +{ + Q_D(QQuickWebEngineView); + qreal oldFactor = d->adapter->currentZoomFactor(); + d->adapter->setZoomFactor(arg); + if (qFuzzyCompare(oldFactor, d->adapter->currentZoomFactor())) + return; + + emit zoomFactorChanged(arg); +} + void QQuickWebEngineViewPrivate::didRunJavaScript(quint64 requestId, const QVariant &result) { Q_Q(QQuickWebEngineView); @@ -620,6 +644,12 @@ QQuickWebEngineViewExperimental *QQuickWebEngineView::experimental() const return d->e.data(); } +qreal QQuickWebEngineView::zoomFactor() const +{ + Q_D(const QQuickWebEngineView); + return d->adapter->currentZoomFactor(); +} + bool QQuickWebEngineViewExperimental::inspectable() const { Q_D(const QQuickWebEngineView); @@ -685,22 +715,26 @@ QQuickWebEngineHistory *QQuickWebEngineViewExperimental::navigationHistory() con void QQuickWebEngineViewExperimental::grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineViewExperimental::Feature feature, bool granted) { - if (!granted && feature >= MediaAudioDevices && feature <= MediaAudioVideoDevices) { + if (!granted && feature >= MediaAudioCapture && feature <= MediaAudioVideoCapture) { d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone); return; } switch (feature) { - case MediaAudioDevices: + case MediaAudioCapture: d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaAudioCapture); break; - case MediaVideoDevices: + case MediaVideoCapture: d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaVideoCapture); break; - case MediaAudioVideoDevices: - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaAudioCapture - | WebContentsAdapterClient::MediaVideoCapture)); + case MediaAudioVideoCapture: + d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaAudioCapture | WebContentsAdapterClient::MediaVideoCapture)); + break; + case Geolocation: + d_ptr->adapter->runGeolocationRequestCallback(securityOrigin, granted); break; + default: + Q_UNREACHABLE(); } } diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 22713ee22..9f6493022 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -56,6 +56,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(bool canGoBack READ canGoBack NOTIFY urlChanged) Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY urlChanged) + Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged) Q_ENUMS(NavigationRequestAction); Q_ENUMS(NavigationType); Q_ENUMS(LoadStatus); @@ -75,6 +76,7 @@ public: QString title() const; bool canGoBack() const; bool canGoForward() const; + qreal zoomFactor() const; QQuickWebEngineViewExperimental *experimental() const; @@ -116,7 +118,8 @@ public: enum NewViewDestination { NewViewInWindow, NewViewInTab, - NewViewInDialog + NewViewInDialog, + NewViewInBackgroundTab }; // must match WebContentsAdapterClient::JavaScriptConsoleMessageLevel @@ -133,6 +136,7 @@ public Q_SLOTS: void goForward(); void reload(); void stop(); + void setZoomFactor(qreal arg); Q_SIGNALS: void titleChanged(); @@ -143,6 +147,7 @@ Q_SIGNALS: void linkHovered(const QUrl &hoveredUrl); void navigationRequested(QQuickWebEngineNavigationRequest *request); void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); + void zoomFactorChanged(qreal arg); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 6662f1f02..46388bfbb 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -88,9 +88,10 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewExperimental : public QObjec public: enum Feature { - MediaAudioDevices, - MediaVideoDevices, - MediaAudioVideoDevices + MediaAudioCapture, + MediaVideoCapture, + MediaAudioVideoCapture, + Geolocation }; enum FindFlag { @@ -178,6 +179,9 @@ public: virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; virtual WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController); + virtual void runGeolocationPermissionRequest(QUrl const&) Q_DECL_OVERRIDE; + + virtual BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal); void adoptWebContents(WebContentsAdapter *webContents); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index a2f60d4ef..209b5fbea 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -43,6 +43,8 @@ #include <QQuickWindow> #include <QVariant> #include <QWindow> +#include <private/qquickwindow_p.h> +#include <private/qsgcontext_p.h> RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup) : m_client(client) @@ -123,6 +125,23 @@ QWindow* RenderWidgetHostViewQtDelegateQuick::window() const return QQuickItem::window(); } +QSGTexture *RenderWidgetHostViewQtDelegateQuick::createTextureFromImage(const QImage &image) +{ + return QQuickItem::window()->createTextureFromImage(image, QQuickWindow::TextureCanUseAtlas); +} + +QSGLayer *RenderWidgetHostViewQtDelegateQuick::createLayer() +{ + QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context; + return renderContext->sceneGraphContext()->createLayer(renderContext); +} + +QSGImageNode *RenderWidgetHostViewQtDelegateQuick::createImageNode() +{ + QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context; + return renderContext->sceneGraphContext()->createImageNode(); +} + void RenderWidgetHostViewQtDelegateQuick::update() { QQuickItem::update(); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index ddc581289..112d97377 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -57,6 +57,9 @@ public: virtual void hide() Q_DECL_OVERRIDE; virtual bool isVisible() const Q_DECL_OVERRIDE; virtual QWindow* window() const Q_DECL_OVERRIDE; + virtual QSGTexture *createTextureFromImage(const QImage &) Q_DECL_OVERRIDE; + virtual QSGLayer *createLayer() Q_DECL_OVERRIDE; + virtual QSGImageNode *createImageNode() Q_DECL_OVERRIDE; virtual void update() Q_DECL_OVERRIDE; virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp index da8d3d806..6a0e416e0 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -95,6 +95,21 @@ QWindow *RenderWidgetHostViewQtDelegateQuickWindow::window() const return const_cast<RenderWidgetHostViewQtDelegateQuickWindow*>(this); } +QSGTexture *RenderWidgetHostViewQtDelegateQuickWindow::createTextureFromImage(const QImage &image) +{ + return m_realDelegate->createTextureFromImage(image); +} + +QSGLayer *RenderWidgetHostViewQtDelegateQuickWindow::createLayer() +{ + return m_realDelegate->createLayer(); +} + +QSGImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createImageNode() +{ + return m_realDelegate->createImageNode(); +} + void RenderWidgetHostViewQtDelegateQuickWindow::update() { QQuickWindow::update(); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index eeab4a79a..e6c793143 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -60,6 +60,9 @@ public: virtual void hide() Q_DECL_OVERRIDE; virtual bool isVisible() const Q_DECL_OVERRIDE; virtual QWindow* window() const Q_DECL_OVERRIDE; + virtual QSGTexture *createTextureFromImage(const QImage &) Q_DECL_OVERRIDE; + virtual QSGLayer *createLayer() Q_DECL_OVERRIDE; + virtual QSGImageNode *createImageNode() Q_DECL_OVERRIDE; virtual void update() Q_DECL_OVERRIDE; virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 6f48e9d49..128ae043d 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -6,7 +6,7 @@ CMAKE_MODULE_TESTS = "-" DEFINES += QT_BUILD_WEBENGINE_LIB QT += qml quick -QT_PRIVATE += webenginecore quick-private +QT_PRIVATE += webenginecore quick-private gui-private core-private QMAKE_DOCS = $$PWD/doc/qtwebengine.qdocconf diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 72b16f28b..3f5fd53b5 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -23,6 +23,7 @@ #include "qwebenginepage.h" #include "qwebenginepage_p.h" +#include "browser_context_adapter.h" #include "certificate_error_controller.h" #include "javascript_dialog_controller.h" #include "qwebenginehistory.h" @@ -342,6 +343,12 @@ void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &security Q_EMIT q->featurePermissionRequested(securityOrigin, requestedFeature); } +void QWebEnginePagePrivate::runGeolocationPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::Geolocation); +} + QObject *QWebEnginePagePrivate::accessibilityParentObject() { return view; @@ -410,6 +417,11 @@ void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) } } +BrowserContextAdapter *QWebEnginePagePrivate::browserContextAdapter() +{ + return BrowserContextAdapter::defaultContext(); +} + QWebEnginePage::QWebEnginePage(QObject* parent) : QObject(parent) , d_ptr(new QWebEnginePagePrivate) @@ -624,6 +636,13 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData return true; } +void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) +{ + Q_Q(QWebEnginePage); + bool accepted = q->acceptNavigationRequest(url, static_cast<QWebEnginePage::NavigationType>(navigationType), isMainFrame); + navigationRequestAction = accepted ? WebContentsAdapterClient::AcceptRequest : WebContentsAdapterClient::IgnoreRequest; +} + void QWebEnginePagePrivate::javascriptDialog(QSharedPointer<JavaScriptDialogController> controller) { Q_Q(QWebEnginePage); @@ -743,6 +762,8 @@ QMenu *QWebEnginePage::createStandardContextMenu() void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy) { Q_D(QWebEnginePage); + if (policy == PermissionUnknown) + return; WebContentsAdapterClient::MediaRequestFlags flags = WebContentsAdapterClient::MediaNone; switch (feature) { case MediaAudioVideoCapture: @@ -761,6 +782,10 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine } d->adapter->grantMediaAccessPermission(securityOrigin, flags); } + d->adapter->grantMediaAccessPermission(securityOrigin, flags); + break; + case QWebEnginePage::Geolocation: + d->adapter->runGeolocationRequestCallback(securityOrigin, (policy == PermissionGrantedByUser) ? true : false); break; default: break; @@ -945,6 +970,14 @@ bool QWebEnginePage::certificateError(const QWebEngineCertificateError &) return false; } +bool QWebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) +{ + Q_UNUSED(url); + Q_UNUSED(type); + Q_UNUSED(isMainFrame); + return true; +} + QT_END_NAMESPACE #include "moc_qwebenginepage.cpp" diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 7856b8243..afb62ceda 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -136,6 +136,16 @@ public: PermissionDeniedByUser }; + // must match WebContentsAdapterClient::NavigationType + enum NavigationType { + NavigationTypeLinkClicked, + NavigationTypeTyped, + NavigationTypeFormSubmitted, + NavigationTypeBackForward, + NavigationTypeReload, + NavigationTypeOther + }; + enum Feature { #ifndef Q_QDOC Notifications = 0, @@ -248,6 +258,7 @@ protected: virtual bool javaScriptPrompt(const QUrl &securityOrigin, const QString& msg, const QString& defaultValue, QString* result); virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID); virtual bool certificateError(const QWebEngineCertificateError &certificateError); + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); private: Q_DECLARE_PRIVATE(QWebEnginePage); diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 54129229f..23d577c94 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -122,7 +122,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, const QUrl &, int &, bool) 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<JavaScriptDialogController>) Q_DECL_OVERRIDE; @@ -135,10 +135,13 @@ public: virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; virtual void authenticationRequired(const QUrl &requestUrl, const QString &realm, bool isProxy, const QString &challengingHost, QString *outUser, QString *outPassword) Q_DECL_OVERRIDE; virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) Q_DECL_OVERRIDE; + virtual void runGeolocationPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; virtual WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &controller) Q_DECL_OVERRIDE; + virtual BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; + void updateAction(QWebEnginePage::WebAction) const; void updateNavigationActions(); void _q_webActionTriggered(bool checked); diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index 729a09f56..3a0f4fced 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -39,7 +39,7 @@ #include <QDebug> -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::WebAttribute attribute) { switch (attribute) { @@ -74,7 +74,21 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web } } -Q_GLOBAL_STATIC(QList<QWebEngineSettingsPrivate*>, allSettings); +Q_GLOBAL_STATIC(QList<QWebEngineSettingsPrivate*>, allSettings) + +class QWebEngineGlobalSettings { + QWebEngineSettings globalSettings; +public: + QWebEngineGlobalSettings() { + // globalSettings shouldn't be in that list. + allSettings->removeAll(globalSettings.d_func()); + globalSettings.d_func()->coreSettings->initDefaults(); + } + + QWebEngineSettings *data() { return &globalSettings; } +}; + +Q_GLOBAL_STATIC(QWebEngineGlobalSettings, globalInstance) QWebEngineSettingsPrivate::QWebEngineSettingsPrivate() : coreSettings(new WebEngineSettings(this)) @@ -92,25 +106,13 @@ void QWebEngineSettingsPrivate::apply() } } -void QWebEngineSettingsPrivate::initDefaults() -{ - coreSettings->initDefaults(); -} - WebEngineSettings *QWebEngineSettingsPrivate::fallbackSettings() const { return QWebEngineSettings::globalSettings()->d_func()->coreSettings.data(); } QWebEngineSettings *QWebEngineSettings::globalSettings() { - static QWebEngineSettings* globalSettings = 0; - if (!globalSettings) { - globalSettings = new QWebEngineSettings; - // globalSettings shouldn't be in that list. - allSettings->removeAll(globalSettings->d_func()); - globalSettings->d_func()->initDefaults(); - } - return globalSettings; + return globalInstance()->data(); } Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::StandardFont) == static_cast<int>(QWebEngineSettings::StandardFont), "The enum values must match"); @@ -215,3 +217,5 @@ void QWebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) { setAttribute(attr, globalSettings()->testAttribute(attr)); } + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index d9f57a935..29825f5a4 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -31,6 +31,7 @@ class QIcon; class QPixmap; class QUrl; class QWebEngineSettingsPrivate; +class QWebEngineGlobalSettings; class QWEBENGINEWIDGETS_EXPORT QWebEngineSettings { public: @@ -87,6 +88,7 @@ private: Q_DECLARE_PRIVATE(QWebEngineSettings); QScopedPointer<QWebEngineSettingsPrivate> d_ptr; friend class QWebEnginePagePrivate; + friend class QWebEngineGlobalSettings; QWebEngineSettings(); ~QWebEngineSettings(); diff --git a/src/webenginewidgets/api/qwebenginesettings_p.h b/src/webenginewidgets/api/qwebenginesettings_p.h index 830e8b360..12464fa02 100644 --- a/src/webenginewidgets/api/qwebenginesettings_p.h +++ b/src/webenginewidgets/api/qwebenginesettings_p.h @@ -48,7 +48,6 @@ class QWebEngineSettingsPrivate : public WebEngineSettingsDelegate { public: QWebEngineSettingsPrivate(); - void initDefaults(); void apply() Q_DECL_OVERRIDE; WebEngineSettings *fallbackSettings() const Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index e89b10ab8..af435d170 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -147,6 +147,21 @@ */ /*! + \enum QWebEnginePage::NavigationType + + This enum describes the type of a navigation request. + + \value NavigationTypeLinkClicked The navigation request resulted from a clicked link. + \value NavigationTypeTyped The navigation request resulted from an explicitly loaded url. + \value NavigationTypeFormSubmitted The navigation request resulted from a form submission. + \value NavigationTypeBackForward The navigation request resulted from a back/forward action. + \value NavigationTypeReload The navigation request resulted from a reload action. + \value NavigationTypeOther The navigation request was triggered by other means not covered by the above. + + \sa acceptNavigationRequest() +*/ + +/*! \enum QWebEnginePage::Feature This enum describes the platform feature access categories that the user may be asked to grant or deny access to. @@ -209,6 +224,15 @@ */ /*! + \fn bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) + This function is called whenever there is a request to navigate to a specified \a url by means of the specified navigation type \atype. + The \a isMainFrame argument marks if the request corresponds to the main frame, or a sub frame. + If the request is accepted Chromium will continue to load the page, else the request will be ignored. + The default implementation accepts the navigation request. +*/ + + +/*! \fn void QWebEnginePage::javaScriptAlert(const QUrl &securityOrigin, const QString& msg) This function is called whenever a JavaScript program running in a frame affiliated with \a securityOrigin calls the alert() function with the message \a msg. diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index c4a32d685..e49259a59 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -44,9 +44,11 @@ #include <QOpenGLContext> #include <QResizeEvent> #include <QSGAbstractRenderer> -#include <QSGEngine> #include <QSGNode> #include <QWindow> +#include <private/qsgcontext_p.h> +#include <private/qsgengine_p.h> + static const int MaxTooltipLength = 1024; @@ -143,6 +145,22 @@ QWindow* RenderWidgetHostViewQtDelegateWidget::window() const return root ? root->windowHandle() : 0; } +QSGTexture *RenderWidgetHostViewQtDelegateWidget::createTextureFromImage(const QImage &image) +{ + return m_sgEngine->createTextureFromImage(image, QSGEngine::TextureCanUseAtlas); +} + +QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer() +{ + QSGEnginePrivate *enginePrivate = QSGEnginePrivate::get(m_sgEngine.data()); + return enginePrivate->sgContext->createLayer(enginePrivate->sgRenderContext.data()); +} + +QSGImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode() +{ + return QSGEnginePrivate::get(m_sgEngine.data())->sgContext->createImageNode(); +} + void RenderWidgetHostViewQtDelegateWidget::update() { #if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0)) diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index 0b553d8eb..670e22f31 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -65,6 +65,9 @@ public: virtual void hide() Q_DECL_OVERRIDE; virtual bool isVisible() const Q_DECL_OVERRIDE; virtual QWindow* window() const Q_DECL_OVERRIDE; + virtual QSGTexture *createTextureFromImage(const QImage &) Q_DECL_OVERRIDE; + virtual QSGLayer *createLayer() Q_DECL_OVERRIDE; + virtual QSGImageNode *createImageNode() Q_DECL_OVERRIDE; virtual void update() Q_DECL_OVERRIDE; virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 71240cbaf..296b62475 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -6,7 +6,7 @@ CMAKE_MODULE_TESTS = "-" DEFINES += QT_BUILD_WEBENGINEWIDGETS_LIB QT += webengine widgets network quick -QT_PRIVATE += webenginecore +QT_PRIVATE += webenginecore quick-private gui-private core-private QMAKE_DOCS = $$PWD/doc/qtwebenginewidgets.qdocconf diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index f7cffb8b1..abb8d3d7b 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -90,6 +90,7 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.NewViewInWindow --> NewViewDestination" << "QQuickWebEngineView.NewViewInTab --> NewViewDestination" << "QQuickWebEngineView.NewViewInDialog --> NewViewDestination" + << "QQuickWebEngineView.NewViewInBackgroundTab --> NewViewDestination" << "QQuickWebEngineView.InfoMessageLevel --> JavaScriptConsoleMessageLevel" << "QQuickWebEngineView.WarningMessageLevel --> JavaScriptConsoleMessageLevel" << "QQuickWebEngineView.ErrorMessageLevel --> JavaScriptConsoleMessageLevel" diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 6fb46057d..85939a686 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -107,11 +107,11 @@ private Q_SLOTS: void contextMenuCopy(); void contextMenuPopulatedOnce(); void acceptNavigationRequest(); + void acceptNavigationRequestNavigationType(); void geolocationRequestJS(); void loadFinished(); void actionStates(); void popupFormSubmission(); - void acceptNavigationRequestWithNewWindow(); void userStyleSheet(); void userStyleSheetFromLocalFileUrl(); void userStyleSheetFromQrcUrl(); @@ -133,8 +133,6 @@ private Q_SLOTS: void textEditing(); void backActionUpdate(); void frameAt(); - void requestCache(); - void loadCachedPage(); void protectBindingsRuntimeObjectsFromCollector(); void localURLSchemes(); void testOptionalJSObjects(); @@ -240,7 +238,6 @@ void tst_QWebEnginePage::cleanupTestCase() cleanupFiles(); // Be nice } -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) class NavigationRequestOverride : public QWebEnginePage { public: @@ -248,21 +245,18 @@ public: bool m_acceptNavigationRequest; protected: - virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, QWebEnginePage::NavigationType type) { - Q_UNUSED(frame); - Q_UNUSED(request); + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) + { + Q_UNUSED(url); Q_UNUSED(type); + Q_UNUSED(isMainFrame); return m_acceptNavigationRequest; } }; -#endif void tst_QWebEnginePage::acceptNavigationRequest() { -#if !defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) - QSKIP("QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST"); -#else QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false); @@ -278,11 +272,10 @@ void tst_QWebEnginePage::acceptNavigationRequest() evaluateJavaScriptSync(m_view->page(), "tstform.submit();"); QTRY_COMPARE(loadSpy.count(), 2); - QCOMPARE(m_view->page()->toPlainText(), QString("foo?")); + QCOMPARE(toPlainTextSync(m_view->page()), QString("foo?")); // Restore default page m_view->setPage(0); -#endif } #if defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) @@ -439,23 +432,22 @@ public: connect(this, SIGNAL(geometryChangeRequested(QRect)), this, SLOT(slotGeometryChangeRequested(QRect))); } -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) struct Navigation { - QWebEngineFrame *frame; - QNetworkRequest request; NavigationType type; + QUrl url; + bool isMainFrame; }; QList<Navigation> navigations; - virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, NavigationType type) { + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) + { Navigation n; - n.frame = frame; - n.request = request; + n.url = url; n.type = type; + n.isMainFrame = isMainFrame; navigations.append(n); return true; } -#endif QList<TestPage*> createdWindows; virtual QWebEnginePage* createWindow(WebWindowType) { @@ -471,6 +463,42 @@ private Q_SLOTS: } }; +void tst_QWebEnginePage::acceptNavigationRequestNavigationType() +{ + + TestPage page; + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + + page.load(QUrl("qrc:///resources/script.html")); + QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(page.navigations.count(), 1); + + page.load(QUrl("qrc:///resources/content.html")); + QTRY_COMPARE(loadSpy.count(), 2); + QTRY_COMPARE(page.navigations.count(), 2); + + page.triggerAction(QWebEnginePage::Stop); + QVERIFY(page.history()->canGoBack()); + page.triggerAction(QWebEnginePage::Back); + + QTRY_COMPARE(loadSpy.count(), 3); + QTRY_COMPARE(page.navigations.count(), 3); + + page.triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(loadSpy.count(), 4); + QTRY_COMPARE(page.navigations.count(), 4); + + QList<QWebEnginePage::NavigationType> expectedList; + expectedList << QWebEnginePage::NavigationTypeTyped + << QWebEnginePage::NavigationTypeTyped + << QWebEnginePage::NavigationTypeBackForward + << QWebEnginePage::NavigationTypeReload; + QVERIFY(expectedList.count() == page.navigations.count()); + for (int i = 0; i < expectedList.count(); ++i) { + QCOMPARE(page.navigations[i].type, expectedList[i]); + } +} + void tst_QWebEnginePage::popupFormSubmission() { TestPage page; @@ -491,38 +519,6 @@ void tst_QWebEnginePage::popupFormSubmission() QVERIFY(url.contains("?foo=bar")); } -void tst_QWebEnginePage::acceptNavigationRequestWithNewWindow() -{ -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else - TestPage* page = new TestPage(m_view); - page->settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, true); - m_page = page; - m_view->setPage(m_page); - - m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QFocusEvent fe(QEvent::FocusIn); - m_page->event(&fe); - - QVERIFY(m_page->focusNextPrevChild(/*next*/ true)); - - QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - m_page->event(&keyEnter); - - QCOMPARE(page->navigations.count(), 2); - - TestPage::Navigation n = page->navigations.at(1); - QVERIFY(!n.frame); - QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached")); - QVERIFY(n.type == QWebEnginePage::NavigationTypeLinkClicked); - - QCOMPARE(page->createdWindows.count(), 1); -#endif -} - class TestNetworkManager : public QNetworkAccessManager { public: @@ -1606,72 +1602,6 @@ void tst_QWebEnginePage::textEditing() #endif } -void tst_QWebEnginePage::requestCache() -{ -#if !defined(ACCEPTNAVIGATIONREQUEST) - QSKIP("ACCEPTNAVIGATIONREQUEST"); -#else - TestPage page; - QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); - - page.setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(page.navigations.count(), 1); - - page.setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>")); - QTRY_COMPARE(loadSpy.count(), 2); - QTRY_COMPARE(page.navigations.count(), 2); - - page.triggerAction(QWebEnginePage::Stop); - QVERIFY(page.history()->canGoBack()); - page.triggerAction(QWebEnginePage::Back); - - QTRY_COMPARE(loadSpy.count(), 3); - QTRY_COMPARE(page.navigations.count(), 3); - QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferNetwork); - QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferNetwork); - QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferCache); -#endif -} - -void tst_QWebEnginePage::loadCachedPage() -{ -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else - TestPage page; - QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); - page.settings()->setMaximumPagesInCache(3); - - page.load(QUrl("data:text/html,This is first page")); - - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(page.navigations.count(), 1); - - QUrl firstPageUrl = page.url(); - page.load(QUrl("data:text/html,This is second page")); - - QTRY_COMPARE(loadSpy.count(), 2); - QTRY_COMPARE(page.navigations.count(), 2); - - page.triggerAction(QWebEnginePage::Stop); - QVERIFY(page.history()->canGoBack()); - - QSignalSpy urlSpy(&page, SIGNAL(urlChanged(QUrl))); - QVERIFY(urlSpy.isValid()); - - page.triggerAction(QWebEnginePage::Back); - ::waitForSignal(&page, SIGNAL(urlChanged(QUrl))); - QCOMPARE(urlSpy.size(), 1); - - QList<QVariant> arguments1 = urlSpy.takeFirst(); - QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl); -#endif -} - void tst_QWebEnginePage::backActionUpdate() { QWebEngineView view; diff --git a/tests/quicktestbrowser/FeaturePermissionBar.qml b/tests/quicktestbrowser/FeaturePermissionBar.qml index dd2e0f714..68ad43195 100644 --- a/tests/quicktestbrowser/FeaturePermissionBar.qml +++ b/tests/quicktestbrowser/FeaturePermissionBar.qml @@ -69,12 +69,14 @@ Rectangle { Layout.fillWidth: true function textForFeature(feature) { - if (feature === WebEngineViewExperimental.MediaAudioDevices) + if (feature === WebEngineViewExperimental.MediaAudioCapture) return "your microphone" - if (feature === WebEngineViewExperimental.MediaVideoDevices) + if (feature === WebEngineViewExperimental.MediaVideoCapture) return "your camera" - if (feature === WebEngineViewExperimental.MediaAudioVideoDevices) + if (feature === WebEngineViewExperimental.MediaAudioVideoCapture) return "your camera and microphone" + if (feature === WebEngineViewExperimental.Geolocation) + return "your position" } } diff --git a/tests/quicktestbrowser/ZoomController.qml b/tests/quicktestbrowser/ZoomController.qml new file mode 100644 index 000000000..a714ed2a9 --- /dev/null +++ b/tests/quicktestbrowser/ZoomController.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** 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:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 + +Rectangle { + property alias zoomFactor: slider.value ; + function zoomIn() { + visible = true + visibilityTimer.restart() + zoomFactor = zoomFactor + 0.25; + } + function zoomOut() { + visible = true + visibilityTimer.restart() + zoomFactor = zoomFactor - 0.25; + } + function reset() { zoomFactor = 1.0 } + + width: 220 + height: 30 + color: palette.window + visible: false + radius: 4 + + SystemPalette { + id: palette + } + Timer { + id: visibilityTimer + interval: 3000 + repeat: false + onTriggered: zoomController.visible = false + } + + RowLayout { + anchors.margins: 4 + anchors.fill: parent + ToolButton { + id: plusButton + text: '+' + onClicked: zoomIn() + } + ToolButton { + text: '\u2014' + id: minusButton + onClicked: zoomOut() + } + Slider { + id: slider + maximumValue: 5.0 + minimumValue: 0.25 + Layout.fillWidth: true; + stepSize: 0.05 + value: 1 + onValueChanged: visibilityTimer.restart() + } + Button { + text: "Reset" + onClicked: reset() + } + } +} diff --git a/tests/quicktestbrowser/quickwindow.qml b/tests/quicktestbrowser/quickwindow.qml index 6a5ef3187..b1be6db3e 100644 --- a/tests/quicktestbrowser/quickwindow.qml +++ b/tests/quicktestbrowser/quickwindow.qml @@ -122,6 +122,18 @@ ApplicationWindow { browserWindow.showNormal() } } + Action { + shortcut: "Ctrl+0" + onTriggered: zoomController.reset() + } + Action { + shortcut: "Ctrl+-" + onTriggered: zoomController.zoomOut() + } + Action { + shortcut: "Ctrl+=" + onTriggered: zoomController.zoomIn() + } Menu { id: backHistoryMenu @@ -342,7 +354,7 @@ ApplicationWindow { var tab = tabs.createEmptyTab() request.openIn(tab.item.webView) } else if (request.destination == WebEngineView.NewViewInDialog) { - var dialog = dialogComponent.createObject() + var dialog = dialogComponent.createObject(webEngineView) request.openIn(dialog.webView) } else { var component = Qt.createComponent("quickwindow.qml") @@ -399,4 +411,16 @@ ApplicationWindow { } } } + ZoomController { + id: zoomController + y: parent.mapFromItem(currentWebView, 0 , 0).y - 4 + anchors.right: parent.right + width: (parent.width > 800) ? parent.width * 0.25 : 220 + anchors.rightMargin: (parent.width > 400) ? 100 : 0 + } + Binding { + target: currentWebView + property: "zoomFactor" + value: zoomController.zoomFactor + } } diff --git a/tests/quicktestbrowser/resources.qrc b/tests/quicktestbrowser/resources.qrc index cdc3d2304..4880b3d65 100644 --- a/tests/quicktestbrowser/resources.qrc +++ b/tests/quicktestbrowser/resources.qrc @@ -4,6 +4,7 @@ <file>ContextMenuExtras.qml</file> <file>FeaturePermissionBar.qml</file> <file>ButtonWithMenu.qml</file> + <file>ZoomController.qml</file> </qresource> <qresource prefix="icons"> <!-- To the risk of this breaking more often, do not duplicate the resources since this application won't be deployed --> diff --git a/tests/quicktestbrowser/util.h b/tests/quicktestbrowser/util.h index bad41d6a7..85db8c25b 100644 --- a/tests/quicktestbrowser/util.h +++ b/tests/quicktestbrowser/util.h @@ -50,7 +50,7 @@ QUrl urlFromUserInput(const QString& userInput) { QFileInfo fileInfo(userInput); if (fileInfo.exists()) - return QUrl(fileInfo.absoluteFilePath()); + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); return QUrl::fromUserInput(userInput); } |