diff options
180 files changed, 8971 insertions, 2869 deletions
diff --git a/.gitignore b/.gitignore index 0e0da0ee3..53f5c6eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ moc_*.cpp .uic .rcc *.pyc +.pch +.obj diff --git a/.qmake.conf b/.qmake.conf index 6b6ee09e4..0a6b62d97 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ QMAKEPATH += $$PWD/tools/qmake load(qt_build_config) CONFIG += qt_example_installs -MODULE_VERSION = 5.4.2 +MODULE_VERSION = 5.5.0 diff --git a/examples/webengine/quicknanobrowser/ApplicationRoot.qml b/examples/webengine/quicknanobrowser/ApplicationRoot.qml new file mode 100644 index 000000000..56196efdc --- /dev/null +++ b/examples/webengine/quicknanobrowser/ApplicationRoot.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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.1 + +QtObject { + id: root + property Component browserWindowComponent: BrowserWindow { + applicationRoot: root + onClosing: destroy() + } + property Component browserDialogComponent: BrowserDialog { + onClosing: destroy() + } + function createWindow() { return browserWindowComponent.createObject(root) } + function createDialog() { return browserDialogComponent.createObject(root) } + function load(url) { + var browserWindow = createWindow() + browserWindow.currentWebView.url = url + } +} diff --git a/examples/webengine/quicknanobrowser/BrowserDialog.qml b/examples/webengine/quicknanobrowser/BrowserDialog.qml new file mode 100644 index 000000000..038a62f28 --- /dev/null +++ b/examples/webengine/quicknanobrowser/BrowserDialog.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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.1 +import QtQuick.Window 2.2 +import QtWebEngine 1.0 + +Window { + property alias currentWebView: webView + flags: Qt.Dialog + width: 800 + height: 600 + visible: true + onClosing: destroy() + WebEngineView { + id: webView + anchors.fill: parent + } +} diff --git a/examples/webengine/quicknanobrowser/quickwindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml index 610144dca..df13f99b9 100644 --- a/examples/webengine/quicknanobrowser/quickwindow.qml +++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml @@ -39,16 +39,18 @@ ****************************************************************************/ import QtQuick 2.1 -import QtWebEngine 1.0 +import QtWebEngine 1.1 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.0 import QtQuick.Layouts 1.0 import QtQuick.Window 2.1 import QtQuick.Controls.Private 1.0 +import QtQuick.Dialogs 1.2 +import Qt.labs.settings 1.0 ApplicationWindow { id: browserWindow - function load(url) { currentWebView.url = url } + property QtObject applicationRoot property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null width: 1300 @@ -61,6 +63,34 @@ ApplicationWindow { StyleItem { id: styleItem } property bool platformIsMac: styleItem.style == "mac" + Settings { + property alias autoLoadImages: loadImages.checked; + property alias javaScriptEnabled: javaScriptEnabled.checked; + property alias errorPageEnabled: errorPageEnabled.checked; + } + + WebEngineProfile { + id: defaultProfile + storageName: "Default" + httpCacheType: httpDiskCacheEnabled.checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache; + onDownloadRequested: { + downloadView.visible = true + downloadView.append(download) + download.accept() + } + } + + WebEngineProfile { + id: otrProfile + offTheRecord: true + } + + Action { + shortcut: "Ctrl+D" + onTriggered: { + downloadView.visible = !downloadView.visible + } + } Action { id: focus shortcut: "Ctrl+L" @@ -93,6 +123,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 @@ -138,6 +180,44 @@ ApplicationWindow { text: currentWebView && currentWebView.url onAccepted: currentWebView.url = utils.fromUserInput(text) } + ToolButton { + id: settingsMenuButton + menu: Menu { + MenuItem { + id: loadImages + text: "Autoload images" + checkable: true + checked: WebEngine.settings.autoLoadImages + onCheckedChanged: WebEngine.settings.autoLoadImages = checked + } + MenuItem { + id: javaScriptEnabled + text: "JavaScript On" + checkable: true + checked: WebEngine.settings.javascriptEnabled + onCheckedChanged: WebEngine.settings.javascriptEnabled = checked + } + MenuItem { + id: errorPageEnabled + text: "ErrorPage On" + checkable: true + checked: WebEngine.settings.errorPageEnabled + onCheckedChanged: WebEngine.settings.errorPageEnabled = checked + } + MenuItem { + id: offTheRecordEnabled + text: "Off The Record" + checkable: true + checked: false + } + MenuItem { + id: httpDiskCacheEnabled + text: "HTTP Disk Cache" + checkable: true + checked: (defaultProfile.httpCacheType == WebEngineProfile.DiskHttpCache) + } + } + } } ProgressBar { id: progressBar @@ -177,6 +257,7 @@ ApplicationWindow { WebEngineView { id: webEngineView focus: true + profile: offTheRecordEnabled.checked ? otrProfile : defaultProfile onLinkHovered: { if (hoveredUrl == "") @@ -186,10 +267,48 @@ ApplicationWindow { statusText.text = hoveredUrl } } + + onCertificateError: { + sslDialog.certError = error + sslDialog.text = "Certificate Error: " + error.description + sslDialog.visible = true + error.defer() + } + + onNewViewRequested: { + if (!request.userInitiated) + print("Warning: Blocked a popup window.") + else if (request.destination == WebEngineView.NewViewInTab) { + var tab = tabs.createEmptyTab() + request.openIn(tab.item) + } else if (request.destination == WebEngineView.NewViewInDialog) { + var dialog = applicationRoot.createDialog() + request.openIn(dialog.currentWebView) + } else { + var window = applicationRoot.createWindow() + request.openIn(window.currentWebView) + } + } } } } + MessageDialog { + id: sslDialog + + property var certError + standardButtons: StandardButton.Cancel | StandardButton.Ok + visible: false + title: "Do you want to accept this certificate?" + + onAccepted: certError.ignoreCertificateError() + onRejected: certError.rejectCertificate() + } + DownloadView { + id: downloadView + visible: false + anchors.fill: parent + } Rectangle { id: statusBubble color: "oldlace" diff --git a/examples/webengine/quicknanobrowser/DownloadView.qml b/examples/webengine/quicknanobrowser/DownloadView.qml new file mode 100644 index 000000000..763c02cd4 --- /dev/null +++ b/examples/webengine/quicknanobrowser/DownloadView.qml @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtWebEngine 1.0 +import QtQuick.Layouts 1.0 + +Rectangle { + id: downloadView + color: "lightgray" + + ListModel { + id: downloadModel + property var downloads: [] + } + + function append(download) { + downloadModel.append(download) + downloadModel.downloads.push(download) + } + + Component { + id: downloadItemDelegate + + Rectangle { + width: listView.width + height: childrenRect.height + anchors.margins: 10 + radius: 3 + color: "transparent" + border.color: "black" + Rectangle { + id: progressBar + + property real progress: downloadModel.downloads[index] + ? downloadModel.downloads[index].receivedBytes / downloadModel.downloads[index].totalBytes : 0 + + radius: 3 + color: width == listView.width ? "green" : "#2b74c7" + width: listView.width * progress + height: cancelButton.height + + Behavior on width { + SmoothedAnimation { duration: 100 } + } + } + Rectangle { + anchors { + left: parent.left + right: parent.right + leftMargin: 20 + } + Label { + id: label + text: path + anchors { + verticalCenter: cancelButton.verticalCenter + left: parent.left + right: cancelButton.left + } + } + Button { + id: cancelButton + anchors.right: parent.right + iconSource: "icons/process-stop.png" + onClicked: { + var download = downloadModel.downloads[index] + + download.cancel() + + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== download.id; + }); + downloadModel.remove(index) + } + } + } + } + + } + ListView { + id: listView + anchors { + topMargin: 10 + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: parent.width - 20 + spacing: 5 + + model: downloadModel + delegate: downloadItemDelegate + + Text { + visible: !listView.count + horizontalAlignment: Text.AlignHCenter + height: 30 + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.pixelSize: 20 + text: "No active downloads." + } + + Rectangle { + color: "gray" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: 30 + Button { + id: okButton + text: "OK" + anchors.centerIn: parent + onClicked: { + downloadView.visible = false + } + } + } + } +} diff --git a/examples/webengine/quicknanobrowser/main.cpp b/examples/webengine/quicknanobrowser/main.cpp index d5a4ade55..76cfa8397 100644 --- a/examples/webengine/quicknanobrowser/main.cpp +++ b/examples/webengine/quicknanobrowser/main.cpp @@ -39,7 +39,8 @@ ** ****************************************************************************/ -#include "quickwindow.h" +#include "utils.h" + #ifndef QT_NO_WIDGETS #include <QtWidgets/QApplication> typedef QApplication Application; @@ -47,15 +48,36 @@ typedef QApplication Application; #include <QtGui/QGuiApplication> typedef QGuiApplication Application; #endif +#include <QtQml/QQmlApplicationEngine> +#include <QtQml/QQmlContext> #include <QtWebEngine/qtwebengineglobal.h> +static QUrl startupUrl() +{ + QUrl ret; + QStringList args(qApp->arguments()); + args.takeFirst(); + Q_FOREACH (const QString& arg, args) { + if (arg.startsWith(QLatin1Char('-'))) + continue; + ret = Utils::fromUserInput(arg); + if (ret.isValid()) + return ret; + } + return QUrl(QStringLiteral("http://qt.io/")); +} + int main(int argc, char **argv) { Application app(argc, argv); QtWebEngine::initialize(); - ApplicationEngine appEngine; + QQmlApplicationEngine appEngine; + Utils utils; + appEngine.rootContext()->setContextProperty("utils", &utils); + appEngine.load(QUrl("qrc:/ApplicationRoot.qml")); + QMetaObject::invokeMethod(appEngine.rootObjects().first(), "load", Q_ARG(QVariant, startupUrl())); return app.exec(); } diff --git a/examples/webengine/quicknanobrowser/quicknanobrowser.pro b/examples/webengine/quicknanobrowser/quicknanobrowser.pro index 3628b817e..1447af927 100644 --- a/examples/webengine/quicknanobrowser/quicknanobrowser.pro +++ b/examples/webengine/quicknanobrowser/quicknanobrowser.pro @@ -1,12 +1,15 @@ +requires(contains(QT_CONFIG, accessibility)) + TEMPLATE = app TARGET = quicknanobrowser -HEADERS = quickwindow.h \ - util.h -SOURCES = quickwindow.cpp \ - main.cpp +HEADERS = utils.h +SOURCES = main.cpp -OTHER_FILES += quickwindow.qml +OTHER_FILES += ApplicationRoot.qml \ + BrowserDialog.qml \ + BrowserWindow.qml \ + DownloadView.qml RESOURCES += resources.qrc diff --git a/examples/webengine/quicknanobrowser/quickwindow.cpp b/examples/webengine/quicknanobrowser/quickwindow.cpp deleted file mode 100644 index ec7b6f94a..000000000 --- a/examples/webengine/quicknanobrowser/quickwindow.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "quickwindow.h" - -#include "util.h" - -#include <QFileInfo> -#include <QObject> -#include <QQmlContext> -#include <QQmlEngine> -#include <QUrl> - -class Utils : public QObject { - Q_OBJECT -public: - Utils(QObject* parent = 0) : QObject(parent) { } - Q_INVOKABLE static QUrl fromUserInput(const QString& userInput) { return urlFromUserInput(userInput); } -}; - -#include "quickwindow.moc" - -ApplicationEngine::ApplicationEngine() -{ - rootContext()->setContextProperty("utils", new Utils(this)); - load(QUrl("qrc:/quickwindow.qml")); - QMetaObject::invokeMethod(rootObjects().first(), "load", Q_ARG(QVariant, startupUrl())); -} diff --git a/examples/webengine/quicknanobrowser/resources.qrc b/examples/webengine/quicknanobrowser/resources.qrc index 549207726..28fd7b7dc 100644 --- a/examples/webengine/quicknanobrowser/resources.qrc +++ b/examples/webengine/quicknanobrowser/resources.qrc @@ -1,6 +1,9 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/"> - <file>quickwindow.qml</file> + <file>ApplicationRoot.qml</file> + <file>BrowserDialog.qml</file> + <file>BrowserWindow.qml</file> + <file>DownloadView.qml</file> </qresource> <qresource prefix="icons"> <file alias="go-next.png">icons/go-next.png</file> diff --git a/examples/webengine/quicknanobrowser/quickwindow.h b/examples/webengine/quicknanobrowser/utils.h index ed25a23b8..3cb3fec5d 100644 --- a/examples/webengine/quicknanobrowser/quickwindow.h +++ b/examples/webengine/quicknanobrowser/utils.h @@ -38,18 +38,24 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef UTILS_H +#define UTILS_H -#ifndef QUICKWINDOW_H -#define QUICKWINDOW_H +#include <QtCore/QFileInfo> +#include <QtCore/QUrl> -#include <QQmlApplicationEngine> - -class QWebEngineView; - -class ApplicationEngine : public QQmlApplicationEngine { +class Utils : public QObject { Q_OBJECT public: - ApplicationEngine(); + Q_INVOKABLE static QUrl fromUserInput(const QString& userInput); }; -#endif // QUICKWINDOW_H +inline QUrl Utils::fromUserInput(const QString& userInput) +{ + QFileInfo fileInfo(userInput); + if (fileInfo.exists()) + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + return QUrl::fromUserInput(userInput); +} + +#endif // UTILS_H diff --git a/examples/webenginewidgets/browser/browserapplication.cpp b/examples/webenginewidgets/browser/browserapplication.cpp index 44713901d..093ab7228 100644 --- a/examples/webenginewidgets/browser/browserapplication.cpp +++ b/examples/webenginewidgets/browser/browserapplication.cpp @@ -66,6 +66,7 @@ #include <QtNetwork/QNetworkProxy> #include <QtNetwork/QSslSocket> +#include <QWebEngineProfile> #include <QWebEngineSettings> #include <QtCore/QDebug> @@ -179,7 +180,7 @@ void BrowserApplication::quitBrowser() clean(); int tabCount = 0; for (int i = 0; i < m_mainWindows.count(); ++i) { - tabCount =+ m_mainWindows.at(i)->tabWidget()->count(); + tabCount += m_mainWindows.at(i)->tabWidget()->count(); } if (tabCount > 1) { @@ -230,6 +231,8 @@ void BrowserApplication::loadSettings() settings.beginGroup(QLatin1String("websettings")); QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); + QWebEngineProfile *defaultProfile = QWebEngineProfile::defaultProfile(); + QString standardFontFamily = defaultSettings->fontFamily(QWebEngineSettings::StandardFont); int standardFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFontSize); QFont standardFont = QFont(standardFontFamily, standardFontSize); @@ -255,6 +258,14 @@ void BrowserApplication::loadSettings() QUrl url = settings.value(QLatin1String("userStyleSheet")).toUrl(); defaultSettings->setUserStyleSheetUrl(url); #endif + defaultProfile->setHttpUserAgent(settings.value(QLatin1String("httpUserAgent")).toString()); + settings.endGroup(); + settings.beginGroup(QLatin1String("cookies")); + + QWebEngineProfile::PersistentCookiesPolicy persistentCookiesPolicy = QWebEngineProfile::PersistentCookiesPolicy(settings.value(QLatin1String("persistentCookiesPolicy")).toInt()); + defaultProfile->setPersistentCookiesPolicy(persistentCookiesPolicy); + QString pdataPath = settings.value(QLatin1String("persistentDataPath")).toString(); + defaultProfile->setPersistentStoragePath(pdataPath); settings.endGroup(); } diff --git a/examples/webenginewidgets/browser/browsermainwindow.cpp b/examples/webenginewidgets/browser/browsermainwindow.cpp index cce603cff..d09411abd 100644 --- a/examples/webenginewidgets/browser/browsermainwindow.cpp +++ b/examples/webenginewidgets/browser/browsermainwindow.cpp @@ -284,7 +284,7 @@ void BrowserMainWindow::setupMenu() fileMenu->addSeparator(); fileMenu->addAction(m_tabWidget->closeTabAction()); fileMenu->addSeparator(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) +#if defined(QWEBENGINE_SAVE_AS_FILE) fileMenu->addAction(tr("&Save As..."), this, SLOT(slotFileSaveAs()), QKeySequence(QKeySequence::Save)); fileMenu->addSeparator(); @@ -603,7 +603,7 @@ void BrowserMainWindow::slotSelectLineEdit() void BrowserMainWindow::slotFileSaveAs() { - BrowserApplication::downloadManager()->download(currentTab()->url(), true); + // not implemented yet. } void BrowserMainWindow::slotPreferences() @@ -940,10 +940,8 @@ void BrowserMainWindow::slotAboutToShowWindowMenu() m_windowMenu->addAction(m_tabWidget->nextTabAction()); m_windowMenu->addAction(m_tabWidget->previousTabAction()); m_windowMenu->addSeparator(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) m_windowMenu->addAction(tr("Downloads"), this, SLOT(slotDownloadManager()), QKeySequence(tr("Alt+Ctrl+L", "Download Manager"))); m_windowMenu->addSeparator(); -#endif QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows(); for (int i = 0; i < windows.count(); ++i) { diff --git a/examples/webenginewidgets/browser/downloaditem.ui b/examples/webenginewidgets/browser/downloaditem.ui index 4a0a0fd9a..b7f7deb72 100644 --- a/examples/webenginewidgets/browser/downloaditem.ui +++ b/examples/webenginewidgets/browser/downloaditem.ui @@ -82,16 +82,6 @@ </spacer> </item> <item> - <widget class="QPushButton" name="tryAgainButton" > - <property name="enabled" > - <bool>false</bool> - </property> - <property name="text" > - <string>Try Again</string> - </property> - </widget> - </item> - <item> <widget class="QPushButton" name="stopButton" > <property name="text" > <string>Stop</string> diff --git a/examples/webenginewidgets/browser/downloadmanager.cpp b/examples/webenginewidgets/browser/downloadmanager.cpp index 1ed27e642..3f2370959 100644 --- a/examples/webenginewidgets/browser/downloadmanager.cpp +++ b/examples/webenginewidgets/browser/downloadmanager.cpp @@ -58,48 +58,43 @@ #include <QtCore/QDebug> #include <QWebEngineSettings> +#include <QWebEngineDownloadItem> /*! - DownloadItem is a widget that is displayed in the download manager list. - It moves the data from the QNetworkReply into the QFile as well + DownloadWidget is a widget that is displayed in the download manager list. + It moves the data from the QWebEngineDownloadItem into the QFile as well as update the information/progressbar and report errors. */ -DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent) + +DownloadWidget::DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent) : QWidget(parent) - , m_reply(reply) - , m_requestFileName(requestFileName) , m_bytesReceived(0) + , m_download(download) { setupUi(this); QPalette p = downloadInfoLabel->palette(); p.setColor(QPalette::Text, Qt::darkGray); downloadInfoLabel->setPalette(p); progressBar->setMaximum(0); - tryAgainButton->hide(); connect(stopButton, SIGNAL(clicked()), this, SLOT(stop())); connect(openButton, SIGNAL(clicked()), this, SLOT(open())); - connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain())); + + if (download) { + m_file.setFile(download->path()); + m_url = download->url(); + } init(); } -void DownloadItem::init() +void DownloadWidget::init() { - if (!m_reply) - return; - - // attach to the m_reply - m_url = m_reply->url(); - m_reply->setParent(this); - connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead())); - connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(error(QNetworkReply::NetworkError))); - connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(downloadProgress(qint64,qint64))); - connect(m_reply, SIGNAL(metaDataChanged()), - this, SLOT(metaDataChanged())); - connect(m_reply, SIGNAL(finished()), - this, SLOT(finished())); + if (m_download) { + connect(m_download.data(), SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(downloadProgress(qint64,qint64))); + connect(m_download.data(), SIGNAL(finished()), + this, SLOT(finished())); + } // reset info downloadInfoLabel->clear(); @@ -108,139 +103,58 @@ void DownloadItem::init() // start timer for the download estimation m_downloadTime.start(); - - if (m_reply->error() != QNetworkReply::NoError) { - error(m_reply->error()); - finished(); - } } -void DownloadItem::getFileName() +bool DownloadWidget::getFileName(bool promptForFileName) { QSettings settings; settings.beginGroup(QLatin1String("downloadmanager")); QString defaultLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + if (m_file.absoluteDir().exists()) + defaultLocation = m_file.absolutePath(); QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString(); if (!downloadDirectory.isEmpty()) downloadDirectory += QLatin1Char('/'); - QString defaultFileName = saveFileName(downloadDirectory); + QString defaultFileName = QFileInfo(downloadDirectory, m_file.fileName()).absoluteFilePath(); QString fileName = defaultFileName; - if (m_requestFileName) { + if (promptForFileName) { fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName); if (fileName.isEmpty()) { - m_reply->close(); + if (m_download) + m_download->cancel(); fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName())); - return; + return false; } } - m_output.setFileName(fileName); - fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName()); - if (m_requestFileName) - downloadReadyRead(); -} + m_file.setFile(fileName); -QString DownloadItem::saveFileName(const QString &directory) const -{ - // Move this function into QNetworkReply to also get file name sent from the server - QString path = m_url.path(); - QFileInfo info(path); - QString baseName = info.completeBaseName(); - QString endName = info.suffix(); - - if (baseName.isEmpty()) { - baseName = QLatin1String("unnamed_download"); - qDebug() << "DownloadManager:: downloading unknown file:" << m_url; - } - QString name = directory + baseName + QLatin1Char('.') + endName; - if (QFile::exists(name)) { - // already exists, don't overwrite - int i = 1; - do { - name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName; - } while (QFile::exists(name)); - } - return name; -} + if (m_download && m_download->state() == QWebEngineDownloadItem::DownloadRequested) + m_download->setPath(m_file.absoluteFilePath()); + fileNameLabel->setText(m_file.fileName()); + return true; +} -void DownloadItem::stop() +void DownloadWidget::stop() { setUpdatesEnabled(false); stopButton->setEnabled(false); stopButton->hide(); - tryAgainButton->setEnabled(true); - tryAgainButton->show(); setUpdatesEnabled(true); - m_reply->abort(); -} - -void DownloadItem::open() -{ - QFileInfo info(m_output); - QUrl url = QUrl::fromLocalFile(info.absolutePath()); - QDesktopServices::openUrl(url); -} + if (m_download) + m_download->cancel(); -void DownloadItem::tryAgain() -{ - if (!tryAgainButton->isEnabled()) - return; - - tryAgainButton->setEnabled(false); - tryAgainButton->setVisible(false); - stopButton->setEnabled(true); - stopButton->setVisible(true); - progressBar->setVisible(true); - - QNetworkReply *r = BrowserApplication::networkAccessManager()->get(QNetworkRequest(m_url)); - if (m_reply) - m_reply->deleteLater(); - if (m_output.exists()) - m_output.remove(); - m_reply = r; - init(); emit statusChanged(); } -void DownloadItem::downloadReadyRead() -{ - if (m_requestFileName && m_output.fileName().isEmpty()) - return; - if (!m_output.isOpen()) { - // in case someone else has already put a file there - if (!m_requestFileName) - getFileName(); - if (!m_output.open(QIODevice::WriteOnly)) { - downloadInfoLabel->setText(tr("Error opening save file: %1") - .arg(m_output.errorString())); - stopButton->click(); - emit statusChanged(); - return; - } - emit statusChanged(); - } - if (-1 == m_output.write(m_reply->readAll())) { - downloadInfoLabel->setText(tr("Error saving: %1") - .arg(m_output.errorString())); - stopButton->click(); - } -} - -void DownloadItem::error(QNetworkReply::NetworkError) -{ - qDebug() << "DownloadItem::error" << m_reply->errorString() << m_url; - downloadInfoLabel->setText(tr("Network Error: %1").arg(m_reply->errorString())); - tryAgainButton->setEnabled(true); - tryAgainButton->setVisible(true); -} - -void DownloadItem::metaDataChanged() +void DownloadWidget::open() { - qDebug() << "DownloadItem::metaDataChanged: not handled."; + QUrl url = QUrl::fromLocalFile(m_file.absolutePath()); + QDesktopServices::openUrl(url); } -void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +void DownloadWidget::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { m_bytesReceived = bytesReceived; if (bytesTotal == -1) { @@ -253,13 +167,9 @@ void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) updateInfoLabel(); } -void DownloadItem::updateInfoLabel() +void DownloadWidget::updateInfoLabel() { - if (m_reply->error() == QNetworkReply::NoError) - return; - qint64 bytesTotal = progressBar->maximum(); - bool running = !downloadedSuccessfully(); // update info label double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed(); @@ -276,7 +186,7 @@ void DownloadItem::updateInfoLabel() timeRemaining = 1; QString info; - if (running) { + if (!downloadedSuccessfully()) { QString remaining; if (bytesTotal != 0) remaining = tr("- %4 %5 remaining") @@ -288,17 +198,17 @@ void DownloadItem::updateInfoLabel() .arg(dataString((int)speed)) .arg(remaining); } else { - if (m_bytesReceived == bytesTotal) - info = dataString(m_output.size()); - else + if (m_bytesReceived != bytesTotal) { info = tr("%1 of %2 - Stopped") .arg(dataString(m_bytesReceived)) .arg(dataString(bytesTotal)); + } else + info = dataString(m_bytesReceived); } downloadInfoLabel->setText(info); } -QString DownloadItem::dataString(int size) const +QString DownloadWidget::dataString(int size) const { QString unit; if (size < 1024) { @@ -313,28 +223,58 @@ QString DownloadItem::dataString(int size) const return QString(QLatin1String("%1 %2")).arg(size).arg(unit); } -bool DownloadItem::downloading() const +bool DownloadWidget::downloading() const { return (progressBar->isVisible()); } -bool DownloadItem::downloadedSuccessfully() const -{ - return (stopButton->isHidden() && tryAgainButton->isHidden()); -} +bool DownloadWidget::downloadedSuccessfully() const +{ + bool completed = m_download + && m_download->isFinished() + && m_download->state() == QWebEngineDownloadItem::DownloadCompleted; + return completed || !stopButton->isVisible(); +} + +void DownloadWidget::finished() +{ + if (m_download) { + QWebEngineDownloadItem::DownloadState state = m_download->state(); + QString message; + bool interrupted = false; + + switch (state) { + case QWebEngineDownloadItem::DownloadRequested: // Fall-through. + case QWebEngineDownloadItem::DownloadInProgress: + Q_UNREACHABLE(); + break; + case QWebEngineDownloadItem::DownloadCompleted: + break; + case QWebEngineDownloadItem::DownloadCancelled: + message = QStringLiteral("Download cancelled"); + interrupted = true; + break; + case QWebEngineDownloadItem::DownloadInterrupted: + message = QStringLiteral("Download interrupted"); + interrupted = true; + break; + } + + if (interrupted) { + downloadInfoLabel->setText(message); + return; + } + } -void DownloadItem::finished() -{ progressBar->hide(); stopButton->setEnabled(false); stopButton->hide(); - m_output.close(); updateInfoLabel(); emit statusChanged(); } /*! - DownloadManager is a Dialog that contains a list of DownloadItems + DownloadManager is a Dialog that contains a list of DownloadWidgets It is a basic download manager. It only downloads the file, doesn't do BitTorrent, extract zipped files or anything fancy. @@ -342,7 +282,6 @@ void DownloadItem::finished() DownloadManager::DownloadManager(QWidget *parent) : QDialog(parent) , m_autoSaver(new AutoSaver(this)) - , m_manager(BrowserApplication::networkAccessManager()) , m_iconProvider(0) , m_removePolicy(Never) { @@ -376,67 +315,51 @@ int DownloadManager::activeDownloads() const return count; } -void DownloadManager::download(const QNetworkRequest &request, bool requestFileName) +void DownloadManager::download(QWebEngineDownloadItem *download) { - if (request.url().isEmpty()) - return; - handleUnsupportedContent(m_manager->get(request), requestFileName); -} - -void DownloadManager::handleUnsupportedContent(QNetworkReply *reply, bool requestFileName) -{ - if (!reply || reply->url().isEmpty()) - return; - QVariant header = reply->header(QNetworkRequest::ContentLengthHeader); - bool ok; - int size = header.toInt(&ok); - if (ok && size == 0) - return; - - qDebug() << "DownloadManager::handleUnsupportedContent" << reply->url() << "requestFileName" << requestFileName; - DownloadItem *item = new DownloadItem(reply, requestFileName, this); - addItem(item); + DownloadWidget *widget = new DownloadWidget(download, this); + addItem(widget); } -void DownloadManager::addItem(DownloadItem *item) +void DownloadManager::addItem(DownloadWidget *widget) { - connect(item, SIGNAL(statusChanged()), this, SLOT(updateRow())); + connect(widget, SIGNAL(statusChanged()), this, SLOT(updateRow())); int row = m_downloads.count(); m_model->beginInsertRows(QModelIndex(), row, row); - m_downloads.append(item); + m_downloads.append(widget); m_model->endInsertRows(); updateItemCount(); if (row == 0) show(); - downloadsView->setIndexWidget(m_model->index(row, 0), item); + downloadsView->setIndexWidget(m_model->index(row, 0), widget); QIcon icon = style()->standardIcon(QStyle::SP_FileIcon); - item->fileIcon->setPixmap(icon.pixmap(48, 48)); - downloadsView->setRowHeight(row, item->sizeHint().height()); + widget->fileIcon->setPixmap(icon.pixmap(48, 48)); + downloadsView->setRowHeight(row, widget->sizeHint().height()); } void DownloadManager::updateRow() { - DownloadItem *item = qobject_cast<DownloadItem*>(sender()); - int row = m_downloads.indexOf(item); + DownloadWidget *widget = qobject_cast<DownloadWidget*>(sender()); + int row = m_downloads.indexOf(widget); if (-1 == row) return; if (!m_iconProvider) m_iconProvider = new QFileIconProvider(); - QIcon icon = m_iconProvider->icon(item->m_output.fileName()); + QIcon icon = m_iconProvider->icon(widget->m_file); if (icon.isNull()) icon = style()->standardIcon(QStyle::SP_FileIcon); - item->fileIcon->setPixmap(icon.pixmap(48, 48)); - downloadsView->setRowHeight(row, item->minimumSizeHint().height()); + widget->fileIcon->setPixmap(icon.pixmap(48, 48)); + downloadsView->setRowHeight(row, widget->minimumSizeHint().height()); bool remove = false; #if defined(QTWEBENGINE_PRIVATEBROWSING) QWebEngineSettings *globalSettings = QWebEngineSettings::globalSettings(); - if (!item->downloading() + if (!widget->downloading() && globalSettings->testAttribute(QWebEngineSettings::PrivateBrowsingEnabled)) remove = true; #endif - if (item->downloadedSuccessfully() + if (widget->downloadedSuccessfully() && removePolicy() == DownloadManager::SuccessFullDownload) { remove = true; } @@ -472,7 +395,7 @@ void DownloadManager::save() const for (int i = 0; i < m_downloads.count(); ++i) { QString key = QString(QLatin1String("download_%1_")).arg(i); settings.setValue(key + QLatin1String("url"), m_downloads[i]->m_url); - settings.setValue(key + QLatin1String("location"), QFileInfo(m_downloads[i]->m_output).filePath()); + settings.setValue(key + QLatin1String("location"), m_downloads[i]->m_file.filePath()); settings.setValue(key + QLatin1String("done"), m_downloads[i]->downloadedSuccessfully()); } int i = m_downloads.count(); @@ -504,17 +427,15 @@ void DownloadManager::load() QUrl url = settings.value(key + QLatin1String("url")).toUrl(); QString fileName = settings.value(key + QLatin1String("location")).toString(); bool done = settings.value(key + QLatin1String("done"), true).toBool(); - if (!url.isEmpty() && !fileName.isEmpty()) { - DownloadItem *item = new DownloadItem(0, this); - item->m_output.setFileName(fileName); - item->fileNameLabel->setText(QFileInfo(item->m_output.fileName()).fileName()); - item->m_url = url; - item->stopButton->setVisible(false); - item->stopButton->setEnabled(false); - item->tryAgainButton->setVisible(!done); - item->tryAgainButton->setEnabled(!done); - item->progressBar->setVisible(!done); - addItem(item); + if (done && !url.isEmpty() && !fileName.isEmpty()) { + DownloadWidget *widget = new DownloadWidget(0, this); + widget->m_file.setFile(fileName); + widget->fileNameLabel->setText(widget->m_file.fileName()); + widget->m_url = url; + widget->stopButton->setVisible(false); + widget->stopButton->setEnabled(false); + widget->progressBar->hide(); + addItem(widget); } key = QString(QLatin1String("download_%1_")).arg(++i); } @@ -568,8 +489,7 @@ bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent) int lastRow = row + count - 1; for (int i = lastRow; i >= row; --i) { - if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully() - || m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) { + if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully()) { beginRemoveRows(parent, i, i); m_downloadManager->m_downloads.takeAt(i)->deleteLater(); endRemoveRows(); diff --git a/examples/webenginewidgets/browser/downloadmanager.h b/examples/webenginewidgets/browser/downloadmanager.h index 072e99efd..b468054ab 100644 --- a/examples/webenginewidgets/browser/downloadmanager.h +++ b/examples/webenginewidgets/browser/downloadmanager.h @@ -45,12 +45,14 @@ #include "ui_downloads.h" #include "ui_downloaditem.h" -#include <QtNetwork/QNetworkReply> - -#include <QtCore/QFile> +#include <QtCore/QFileInfo> #include <QtCore/QTime> +#include <QtCore/QUrl> + +#include <QWebEngineDownloadItem> -class DownloadItem : public QWidget, public Ui_DownloadItem +class DownloadManager; +class DownloadWidget : public QWidget, public Ui_DownloadItem { Q_OBJECT @@ -58,37 +60,32 @@ signals: void statusChanged(); public: - DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0); + DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent = 0); bool downloading() const; bool downloadedSuccessfully() const; - QUrl m_url; - - QFile m_output; - QNetworkReply *m_reply; + void init(); + bool getFileName(bool promptForFileName = false); private slots: void stop(); - void tryAgain(); void open(); - void downloadReadyRead(); - void error(QNetworkReply::NetworkError code); void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void metaDataChanged(); void finished(); private: - void getFileName(); - void init(); + friend class DownloadManager; void updateInfoLabel(); QString dataString(int size) const; - QString saveFileName(const QString &directory) const; - - bool m_requestFileName; + QUrl m_url; + QFileInfo m_file; qint64 m_bytesReceived; QTime m_downloadTime; + bool m_stopped; + + QScopedPointer<QWebEngineDownloadItem> m_download; }; class AutoSaver; @@ -118,10 +115,7 @@ public: void setRemovePolicy(RemovePolicy policy); public slots: - void download(const QNetworkRequest &request, bool requestFileName = false); - inline void download(const QUrl &url, bool requestFileName = false) - { download(QNetworkRequest(url), requestFileName); } - void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false); + void download(QWebEngineDownloadItem *download); void cleanup(); private slots: @@ -129,15 +123,14 @@ private slots: void updateRow(); private: - void addItem(DownloadItem *item); + void addItem(DownloadWidget *item); void updateItemCount(); void load(); AutoSaver *m_autoSaver; DownloadModel *m_model; - QNetworkAccessManager *m_manager; QFileIconProvider *m_iconProvider; - QList<DownloadItem*> m_downloads; + QList<DownloadWidget*> m_downloads; RemovePolicy m_removePolicy; friend class DownloadModel; }; diff --git a/examples/webenginewidgets/browser/featurepermissionbar.cpp b/examples/webenginewidgets/browser/featurepermissionbar.cpp index 98f19ad1f..1b6d446cd 100644 --- a/examples/webenginewidgets/browser/featurepermissionbar.cpp +++ b/examples/webenginewidgets/browser/featurepermissionbar.cpp @@ -53,15 +53,17 @@ static QString textForPermissionType(QWebEnginePage::Feature type) { switch (type) { case QWebEnginePage::Notifications: - return QObject::tr("desktop notifications"); + return QObject::tr("use desktop notifications"); case QWebEnginePage::Geolocation: - return QObject::tr("your position"); + return QObject::tr("use your position"); case QWebEnginePage::MediaAudioCapture: - return QObject::tr("your microphone"); + return QObject::tr("use your microphone"); case QWebEnginePage::MediaVideoCapture: - return QObject::tr("your camera"); + return QObject::tr("use your camera"); case QWebEnginePage::MediaAudioVideoCapture: - return QObject::tr("your camera and microphone"); + return QObject::tr("use your camera and microphone"); + case QWebEnginePage::MouseLock: + return QObject::tr("lock your mouse"); default: Q_UNREACHABLE(); } @@ -80,12 +82,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); @@ -96,7 +99,7 @@ void FeaturePermissionBar::requestPermission(const QUrl &securityOrigin, QWebEng { m_securityOrigin = securityOrigin; m_feature = feature; - m_messageLabel->setText(tr("%1 wants to use %2.").arg(securityOrigin.host()).arg(textForPermissionType(feature))); + m_messageLabel->setText(tr("%1 wants to %2.").arg(securityOrigin.host()).arg(textForPermissionType(feature))); show(); // Ease in QPropertyAnimation *animation = new QPropertyAnimation(this); @@ -118,3 +121,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/settings.cpp b/examples/webenginewidgets/browser/settings.cpp index 835e7a9b5..753ef033d 100644 --- a/examples/webenginewidgets/browser/settings.cpp +++ b/examples/webenginewidgets/browser/settings.cpp @@ -58,9 +58,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent) { setupUi(this); - connect(exceptionsButton, SIGNAL(clicked()), this, SLOT(showExceptions())); connect(setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage())); - connect(cookiesButton, SIGNAL(clicked()), this, SLOT(showCookies())); connect(standardFontButton, SIGNAL(clicked()), this, SLOT(chooseFont())); connect(fixedFontButton, SIGNAL(clicked()), this, SLOT(chooseFixedFont())); @@ -89,6 +87,10 @@ void SettingsDialog::loadDefaults() #endif enableScrollAnimator->setChecked(defaultSettings->testAttribute(QWebEngineSettings::ScrollAnimatorEnabled)); + + persistentDataPath->setText(QWebEngineProfile::defaultProfile()->persistentStoragePath()); + sessionCookiesCombo->setCurrentIndex(QWebEngineProfile::defaultProfile()->persistentCookiesPolicy()); + httpUserAgent->setText(QWebEngineProfile::defaultProfile()->httpUserAgent()); } void SettingsDialog::loadFromSettings() @@ -137,47 +139,19 @@ void SettingsDialog::loadFromSettings() enablePlugins->setChecked(settings.value(QLatin1String("enablePlugins"), enablePlugins->isChecked()).toBool()); userStyleSheet->setText(settings.value(QLatin1String("userStyleSheet")).toUrl().toString()); enableScrollAnimator->setChecked(settings.value(QLatin1String("enableScrollAnimator"), enableScrollAnimator->isChecked()).toBool()); + httpUserAgent->setText(settings.value(QLatin1String("httpUserAgent"), httpUserAgent->text()).toString()); settings.endGroup(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) // Privacy settings.beginGroup(QLatin1String("cookies")); - QByteArray value = settings.value(QLatin1String("acceptCookies"), QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray(); - QMetaEnum acceptPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("AcceptPolicy")); - CookieJar::AcceptPolicy acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ? - CookieJar::AcceptOnlyFromSitesNavigatedTo : - static_cast<CookieJar::AcceptPolicy>(acceptPolicyEnum.keyToValue(value)); - switch (acceptCookies) { - case CookieJar::AcceptAlways: - acceptCombo->setCurrentIndex(0); - break; - case CookieJar::AcceptNever: - acceptCombo->setCurrentIndex(1); - break; - case CookieJar::AcceptOnlyFromSitesNavigatedTo: - acceptCombo->setCurrentIndex(2); - break; - } + int persistentCookiesPolicy = settings.value(QLatin1String("persistentCookiesPolicy"), sessionCookiesCombo->currentIndex()).toInt(); + sessionCookiesCombo->setCurrentIndex(persistentCookiesPolicy); + + QString pdataPath = settings.value(QLatin1String("persistentDataPath"), persistentDataPath->text()).toString(); + persistentDataPath->setText(pdataPath); - value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("Expire")).toByteArray(); - QMetaEnum keepPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("KeepPolicy")); - CookieJar::KeepPolicy keepCookies = keepPolicyEnum.keyToValue(value) == -1 ? - CookieJar::KeepUntilExpire : - static_cast<CookieJar::KeepPolicy>(keepPolicyEnum.keyToValue(value)); - switch (keepCookies) { - case CookieJar::KeepUntilExpire: - keepUntilCombo->setCurrentIndex(0); - break; - case CookieJar::KeepUntilExit: - keepUntilCombo->setCurrentIndex(1); - break; - case CookieJar::KeepUntilTimeLimit: - keepUntilCombo->setCurrentIndex(2); - break; - } settings.endGroup(); -#endif // Proxy settings.beginGroup(QLatin1String("proxy")); @@ -227,47 +201,19 @@ void SettingsDialog::saveToSettings() settings.setValue(QLatin1String("userStyleSheet"), QUrl::fromLocalFile(userStyleSheetString)); else settings.setValue(QLatin1String("userStyleSheet"), QUrl(userStyleSheetString)); + settings.setValue(QLatin1String("httpUserAgent"), httpUserAgent->text()); settings.endGroup(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) //Privacy settings.beginGroup(QLatin1String("cookies")); - CookieJar::KeepPolicy keepCookies; - switch (acceptCombo->currentIndex()) { - default: - case 0: - keepCookies = CookieJar::KeepUntilExpire; - break; - case 1: - keepCookies = CookieJar::KeepUntilExit; - break; - case 2: - keepCookies = CookieJar::KeepUntilTimeLimit; - break; - } - QMetaEnum acceptPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("AcceptPolicy")); - settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(keepCookies))); - - CookieJar::KeepPolicy keepPolicy; - switch (keepUntilCombo->currentIndex()) { - default: - case 0: - keepPolicy = CookieJar::KeepUntilExpire; - break; - case 1: - keepPolicy = CookieJar::KeepUntilExit; - break; - case 2: - keepPolicy = CookieJar::KeepUntilTimeLimit; - break; - } + int persistentCookiesPolicy = sessionCookiesCombo->currentIndex(); + settings.setValue(QLatin1String("persistentCookiesPolicy"), persistentCookiesPolicy); - QMetaEnum keepPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("KeepPolicy")); - settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(keepPolicy))); + QString pdataPath = persistentDataPath->text(); + settings.setValue(QLatin1String("persistentDataPath"), pdataPath); settings.endGroup(); -#endif // proxy settings.beginGroup(QLatin1String("proxy")); diff --git a/examples/webenginewidgets/browser/settings.ui b/examples/webenginewidgets/browser/settings.ui index 08374ca7a..7cafdae4b 100644 --- a/examples/webenginewidgets/browser/settings.ui +++ b/examples/webenginewidgets/browser/settings.ui @@ -1,7 +1,8 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>Settings</class> - <widget class="QDialog" name="Settings" > - <property name="geometry" > + <widget class="QDialog" name="Settings"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> @@ -9,64 +10,56 @@ <height>322</height> </rect> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>Settings</string> </property> - <layout class="QGridLayout" name="gridLayout" > - <item row="2" column="0" > - <widget class="QDialogButtonBox" name="buttonBox" > - <property name="orientation" > + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="standardButtons" > + <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> - <item row="1" column="0" > - <widget class="QTabWidget" name="tabWidget" > - <property name="currentIndex" > - <number>0</number> + <item row="1" column="0"> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>4</number> </property> - <widget class="QWidget" name="tab" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab"> + <attribute name="title"> <string>General</string> </attribute> - <layout class="QGridLayout" name="gridLayout_4" > - <item row="0" column="0" > - <widget class="QLabel" name="label_3" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> <string>Home:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" colspan="2" > - <widget class="QLineEdit" name="homeLineEdit" /> + <item row="0" column="1" colspan="2"> + <widget class="QLineEdit" name="homeLineEdit"/> </item> - <item row="1" column="1" > - <widget class="QPushButton" name="setHomeToCurrentPageButton" > - <property name="text" > + <item row="1" column="1"> + <widget class="QPushButton" name="setHomeToCurrentPageButton"> + <property name="text"> <string>Set to current page</string> </property> </widget> </item> - <item row="1" column="2" > - <spacer name="horizontalSpacer" > - <property name="orientation" > + <item row="1" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>280</width> <height>18</height> @@ -74,103 +67,103 @@ </property> </spacer> </item> - <item row="2" column="0" > - <widget class="QLabel" name="label_4" > - <property name="text" > + <item row="2" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> <string>Remove history items:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="2" column="1" colspan="2" > - <widget class="QComboBox" name="expireHistory" > + <item row="2" column="1" colspan="2"> + <widget class="QComboBox" name="expireHistory"> <item> - <property name="text" > + <property name="text"> <string>After one day</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After one week</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After two weeks</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After one month</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After one year</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>Manually</string> </property> </item> </widget> </item> - <item row="3" column="0" > - <widget class="QLabel" name="label_7" > - <property name="text" > + <item row="3" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> <string>Save downloads to:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="3" column="1" colspan="2" > - <widget class="QLineEdit" name="downloadsLocation" /> + <item row="3" column="1" colspan="2"> + <widget class="QLineEdit" name="downloadsLocation"/> </item> - <item row="4" column="0" > - <widget class="QLabel" name="label_8" > - <property name="text" > + <item row="4" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> <string>Open links from applications:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="4" column="1" colspan="2" > - <widget class="QComboBox" name="openLinksIn" > + <item row="4" column="1" colspan="2"> + <widget class="QComboBox" name="openLinksIn"> <item> - <property name="text" > + <property name="text"> <string>In a tab in the current window</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>In a new window</string> </property> </item> </widget> </item> <item row="5" column="1" colspan="2"> - <widget class="QCheckBox" name="enableScrollAnimator" > - <property name="text" > - <string>Enable Scroll Animator</string> + <widget class="QCheckBox" name="enableScrollAnimator"> + <property name="text"> + <string>Enable Scroll Animator</string> </property> - <property name="checked" > - <bool>true</bool> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> - <item row="6" column="1" colspan="2" > + <item row="6" column="1" colspan="2"> <spacer> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>391</width> <height>262</height> @@ -180,91 +173,83 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_3" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab_3"> + <attribute name="title"> <string>Appearance</string> </attribute> - <layout class="QGridLayout" name="gridLayout_3" > - <item row="0" column="0" > - <widget class="QLabel" name="label_5" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> <string>Standard font:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QLabel" name="standardLabel" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Expanding" > + <item row="0" column="1"> + <widget class="QLabel" name="standardLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="frameShape" > + <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> - <property name="text" > + <property name="text"> <string>Times 16</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="0" column="2" > - <widget class="QPushButton" name="standardFontButton" > - <property name="text" > + <item row="0" column="2"> + <widget class="QPushButton" name="standardFontButton"> + <property name="text"> <string>Select...</string> </property> </widget> </item> - <item row="1" column="0" > - <widget class="QLabel" name="label_6" > - <property name="text" > + <item row="1" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> <string>Fixed-width font:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="1" column="1" > - <widget class="QLabel" name="fixedLabel" > - <property name="frameShape" > + <item row="1" column="1"> + <widget class="QLabel" name="fixedLabel"> + <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> - <property name="text" > + <property name="text"> <string>Courier 13</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="1" column="2" > - <widget class="QPushButton" name="fixedFontButton" > - <property name="text" > + <item row="1" column="2"> + <widget class="QPushButton" name="fixedFontButton"> + <property name="text"> <string>Select...</string> </property> </widget> </item> - <item row="2" column="1" > - <spacer name="verticalSpacer" > - <property name="orientation" > + <item row="2" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>93</height> @@ -274,41 +259,33 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_2" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab_2"> + <attribute name="title"> <string>Privacy</string> </attribute> - <layout class="QVBoxLayout" name="verticalLayout_3" > + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QGroupBox" name="groupBox" > - <property name="title" > + <widget class="QGroupBox" name="groupBox"> + <property name="title"> <string>Web Content</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2" > + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QCheckBox" name="enablePlugins" > - <property name="text" > + <widget class="QCheckBox" name="enablePlugins"> + <property name="text"> <string>Enable Plugins</string> </property> - <property name="checked" > + <property name="checked"> <bool>true</bool> </property> </widget> </item> <item> - <widget class="QCheckBox" name="enableJavascript" > - <property name="text" > + <widget class="QCheckBox" name="enableJavascript"> + <property name="text"> <string>Enable Javascript</string> </property> - <property name="checked" > + <property name="checked"> <bool>true</bool> </property> </widget> @@ -317,186 +294,151 @@ </widget> </item> <item> - <widget class="QGroupBox" name="cookiesGroupBox" > - <property name="title" > + <widget class="QGroupBox" name="cookiesGroupBox"> + <property name="title"> <string>Cookies</string> </property> - <layout class="QGridLayout" > - <item row="0" column="0" > - <widget class="QLabel" name="label_2" > - <property name="text" > - <string>Accept Cookies:</string> + <layout class="QGridLayout"> + <property name="leftMargin"> + <number>9</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Persistent Cookie Policy</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QComboBox" name="acceptCombo" > + <item row="0" column="1"> + <widget class="QComboBox" name="sessionCookiesCombo"> <item> - <property name="text" > - <string>Always</string> + <property name="text"> + <string>Treat all cookies as session cookies</string> </property> </item> <item> - <property name="text" > - <string>Never</string> + <property name="text"> + <string>Allow persistent cookies</string> </property> </item> <item> - <property name="text" > - <string>Only from sites you navigate to</string> + <property name="text"> + <string>Treat all cookies as persistent cookies</string> </property> </item> </widget> </item> - <item row="0" column="2" > - <widget class="QPushButton" name="exceptionsButton" > - <property name="text" > - <string>Exceptions...</string> - </property> - </widget> - </item> - <item row="1" column="0" > - <widget class="QLabel" name="label" > - <property name="text" > - <string>Keep until:</string> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Persistent Data Path:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="1" column="1" > - <widget class="QComboBox" name="keepUntilCombo" > - <item> - <property name="text" > - <string>They expire</string> - </property> - </item> - <item> - <property name="text" > - <string>I exit the application</string> - </property> - </item> - <item> - <property name="text" > - <string>At most 90 days</string> - </property> - </item> - </widget> - </item> - <item row="1" column="2" > - <widget class="QPushButton" name="cookiesButton" > - <property name="text" > - <string>Cookies...</string> - </property> - </widget> + <item row="1" column="1"> + <widget class="QLineEdit" name="persistentDataPath"/> </item> </layout> </widget> </item> <item> - <spacer> - <property name="orientation" > + <spacer name="verticalSpacer_4"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> - <width>371</width> - <height>177</height> + <width>20</width> + <height>40</height> </size> </property> </spacer> </item> </layout> </widget> - <widget class="QWidget" name="tab_4" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab_4"> + <attribute name="title"> <string>Proxy</string> </attribute> - <layout class="QVBoxLayout" name="verticalLayout" > + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="proxySupport" > - <property name="title" > + <widget class="QGroupBox" name="proxySupport"> + <property name="title"> <string>Enable proxy</string> </property> - <property name="checkable" > + <property name="checkable"> <bool>true</bool> </property> - <layout class="QGridLayout" name="gridLayout_6" > - <item row="0" column="0" > - <widget class="QLabel" name="label_9" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> <string>Type:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" colspan="2" > - <widget class="QComboBox" name="proxyType" > + <item row="0" column="1" colspan="2"> + <widget class="QComboBox" name="proxyType"> <item> - <property name="text" > + <property name="text"> <string>Socks5</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>Http</string> </property> </item> </widget> </item> - <item row="1" column="0" > - <widget class="QLabel" name="label_10" > - <property name="text" > + <item row="1" column="0"> + <widget class="QLabel" name="label_10"> + <property name="text"> <string>Host:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="1" column="1" colspan="2" > - <widget class="QLineEdit" name="proxyHostName" /> + <item row="1" column="1" colspan="2"> + <widget class="QLineEdit" name="proxyHostName"/> </item> - <item row="2" column="0" > - <widget class="QLabel" name="label_11" > - <property name="text" > + <item row="2" column="0"> + <widget class="QLabel" name="label_11"> + <property name="text"> <string>Port:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="2" column="1" > - <widget class="QSpinBox" name="proxyPort" > - <property name="maximum" > + <item row="2" column="1"> + <widget class="QSpinBox" name="proxyPort"> + <property name="maximum"> <number>10000</number> </property> - <property name="value" > + <property name="value"> <number>1080</number> </property> </widget> </item> - <item row="2" column="2" > - <spacer name="horizontalSpacer_2" > - <property name="orientation" > + <item row="2" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>293</width> <height>20</height> @@ -504,42 +446,42 @@ </property> </spacer> </item> - <item row="3" column="0" > - <widget class="QLabel" name="label_12" > - <property name="text" > + <item row="3" column="0"> + <widget class="QLabel" name="label_12"> + <property name="text"> <string>User Name:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="3" column="1" colspan="2" > - <widget class="QLineEdit" name="proxyUserName" /> + <item row="3" column="1" colspan="2"> + <widget class="QLineEdit" name="proxyUserName"/> </item> - <item row="4" column="0" > - <widget class="QLabel" name="label_13" > - <property name="text" > + <item row="4" column="0"> + <widget class="QLabel" name="label_13"> + <property name="text"> <string>Password:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="4" column="1" colspan="2" > - <widget class="QLineEdit" name="proxyPassword" > - <property name="echoMode" > + <item row="4" column="1" colspan="2"> + <widget class="QLineEdit" name="proxyPassword"> + <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> - <item row="5" column="0" > - <spacer name="verticalSpacer_2" > - <property name="orientation" > + <item row="5" column="0"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>8</height> @@ -552,27 +494,27 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_5" > - <attribute name="title" > + <widget class="QWidget" name="tab_5"> + <attribute name="title"> <string>Advanced</string> </attribute> - <layout class="QGridLayout" name="gridLayout_2" > - <item row="0" column="0" > - <widget class="QLabel" name="label_14" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_14"> + <property name="text"> <string>Style Sheet:</string> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QLineEdit" name="userStyleSheet" /> + <item row="0" column="1"> + <widget class="QLineEdit" name="userStyleSheet"/> </item> - <item row="1" column="1" > - <spacer name="verticalSpacer_3" > - <property name="orientation" > + <item row="2" column="1"> + <spacer name="verticalSpacer_3"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>176</height> @@ -580,6 +522,16 @@ </property> </spacer> </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="httpUserAgent"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>HTTP User-Agent:</string> + </property> + </widget> + </item> </layout> </widget> </widget> @@ -594,11 +546,11 @@ <receiver>Settings</receiver> <slot>accept()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>248</x> <y>254</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>157</x> <y>274</y> </hint> @@ -610,11 +562,11 @@ <receiver>Settings</receiver> <slot>reject()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>316</x> <y>260</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>286</x> <y>274</y> </hint> diff --git a/examples/webenginewidgets/browser/tabwidget.cpp b/examples/webenginewidgets/browser/tabwidget.cpp index 74fb05b46..6f27b9391 100644 --- a/examples/webenginewidgets/browser/tabwidget.cpp +++ b/examples/webenginewidgets/browser/tabwidget.cpp @@ -43,12 +43,15 @@ #include "browserapplication.h" #include "browsermainwindow.h" +#include "downloadmanager.h" #include "history.h" #include "urllineedit.h" #include "webview.h" #include <QtCore/QMimeData> #include <QtGui/QClipboard> +#include <QtWebEngineWidgets/QWebEngineDownloadItem> +#include <QtWebEngineWidgets/QWebEngineProfile> #include <QtWidgets/QCompleter> #include <QtWidgets/QListView> #include <QtWidgets/QMenu> @@ -314,6 +317,8 @@ void TabWidget::currentChanged(int index) this, SIGNAL(linkHovered(const QString&))); disconnect(oldWebView, SIGNAL(loadProgress(int)), this, SIGNAL(loadProgress(int))); + disconnect(oldWebView->page()->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)), + this, SLOT(downloadRequested(QWebEngineDownloadItem*))); } #if defined(QWEBENGINEVIEW_STATUSBARMESSAGE) @@ -324,6 +329,8 @@ void TabWidget::currentChanged(int index) this, SIGNAL(linkHovered(const QString&))); connect(webView, SIGNAL(loadProgress(int)), this, SIGNAL(loadProgress(int))); + connect(webView->page()->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)), + this, SLOT(downloadRequested(QWebEngineDownloadItem*))); for (int i = 0; i < m_actions.count(); ++i) { WebActionMapper *mapper = m_actions[i]; @@ -772,6 +779,12 @@ bool TabWidget::restoreState(const QByteArray &state) return true; } +void TabWidget::downloadRequested(QWebEngineDownloadItem *download) +{ + BrowserApplication::downloadManager()->download(download); + download->accept(); +} + WebActionMapper::WebActionMapper(QAction *root, QWebEnginePage::WebAction webAction, QObject *parent) : QObject(parent) , m_currentParent(0) diff --git a/examples/webenginewidgets/browser/tabwidget.h b/examples/webenginewidgets/browser/tabwidget.h index 497a2c572..9f2e42d58 100644 --- a/examples/webenginewidgets/browser/tabwidget.h +++ b/examples/webenginewidgets/browser/tabwidget.h @@ -45,6 +45,11 @@ #include <QtWidgets/QTabBar> #include <QtWidgets/QShortcut> + +QT_BEGIN_NAMESPACE +class QWebEngineDownloadItem; +QT_END_NAMESPACE + /* Tab bar with a few more features such as a context menu and shortcuts */ @@ -197,6 +202,7 @@ private slots: void currentChanged(int index); void aboutToShowRecentTabsMenu(); void aboutToShowRecentTriggeredAction(QAction *action); + void downloadRequested(QWebEngineDownloadItem *download); void webViewLoadStarted(); void webViewIconChanged(); void webViewTitleChanged(const QString &title); diff --git a/examples/webenginewidgets/browser/webview.cpp b/examples/webenginewidgets/browser/webview.cpp index 5ea273e3a..3436dac67 100644 --- a/examples/webenginewidgets/browser/webview.cpp +++ b/examples/webenginewidgets/browser/webview.cpp @@ -52,6 +52,7 @@ #include <QtGui/QClipboard> #include <QtNetwork/QAuthenticator> +#include <QtNetwork/QNetworkReply> #include <QtWidgets/QMenu> #include <QtWidgets/QMessageBox> #include <QtGui/QMouseEvent> @@ -97,37 +98,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) { @@ -343,10 +322,6 @@ WebView::WebView(QWidget* parent) this, SIGNAL(urlChanged(QUrl))); connect(page(), SIGNAL(iconUrlChanged(QUrl)), this, SLOT(onIconUrlChanged(QUrl))); -#if defined(QWEBENGINEPAGE_DOWNLOADREQUESTED) - connect(page(), SIGNAL(downloadRequested(QNetworkRequest)), - this, SLOT(downloadRequested(QNetworkRequest))); -#endif connect(page(), &WebPage::featurePermissionRequested, this, &WebView::onFeaturePermissionRequested); #if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) page()->setForwardUnsupportedContent(true); @@ -494,8 +469,3 @@ void WebView::setStatusBarText(const QString &string) { m_statusBarText = string; } - -void WebView::downloadRequested(const QNetworkRequest &request) -{ - BrowserApplication::downloadManager()->download(request); -} diff --git a/examples/webenginewidgets/browser/webview.h b/examples/webenginewidgets/browser/webview.h index 2cedeb79b..bbe166e98 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); @@ -118,7 +116,6 @@ private slots: void setProgress(int progress); void loadFinished(bool success); void setStatusBarText(const QString &string); - void downloadRequested(const QNetworkRequest &request); void openLinkInNewTab(); void onFeaturePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature); void onIconUrlChanged(const QUrl &url); 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 f9c03801de86b5e9da2b915a9e490c2f2254fec +Subproject a43649f5fb0cd4b284b2b02a010a397e1ff48f8 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_accessibility_manager_qt.cpp b/src/core/browser_accessibility_manager_qt.cpp index 28d0dd7e3..0157c8602 100644 --- a/src/core/browser_accessibility_manager_qt.cpp +++ b/src/core/browser_accessibility_manager_qt.cpp @@ -43,6 +43,19 @@ using namespace blink; namespace content { +BrowserAccessibilityManager* BrowserAccessibilityManager::Create( + const ui::AXTreeUpdate& initial_tree, + BrowserAccessibilityDelegate* delegate, + BrowserAccessibilityFactory* factory) +{ +#ifndef QT_NO_ACCESSIBILITY + return new BrowserAccessibilityManagerQt(0, initial_tree, delegate); +#else + return 0; +#endif // QT_NO_ACCESSIBILITY +} + +#ifndef QT_NO_ACCESSIBILITY BrowserAccessibility *BrowserAccessibilityFactoryQt::Create() { return new BrowserAccessibilityQt(); @@ -95,23 +108,12 @@ void BrowserAccessibilityManagerQt::NotifyAccessibilityEvent(ui::AXEvent event_t break; case ui::AX_EVENT_LOAD_COMPLETE: break; - case ui::AX_EVENT_TEXT_CHANGED: { QAccessibleTextUpdateEvent event(iface, -1, QString(), QString()); QAccessible::updateAccessibility(&event); break; } - case ui::AX_EVENT_TEXT_INSERTED: { - QAccessibleTextInsertEvent event(iface, -1, QString()); - QAccessible::updateAccessibility(&event); - break; - } - case ui::AX_EVENT_TEXT_REMOVED: { - QAccessibleTextRemoveEvent event(iface, -1, QString()); - QAccessible::updateAccessibility(&event); - break; - } - case ui::AX_EVENT_SELECTED_TEXT_CHANGED: { + case ui::AX_EVENT_TEXT_SELECTION_CHANGED: { QAccessibleTextInterface *textIface = iface->textInterface(); if (textIface) { int start = 0; @@ -131,5 +133,6 @@ void BrowserAccessibilityManagerQt::NotifyAccessibilityEvent(ui::AXEvent event_t break; } } +#endif // QT_NO_ACCESSIBILITY } diff --git a/src/core/browser_accessibility_manager_qt.h b/src/core/browser_accessibility_manager_qt.h index 5d8498d01..49b3af3b2 100644 --- a/src/core/browser_accessibility_manager_qt.h +++ b/src/core/browser_accessibility_manager_qt.h @@ -38,6 +38,7 @@ #define BROWSER_ACCESSIBILITY_MANAGER_QT_H #include "content/browser/accessibility/browser_accessibility_manager.h" +#ifndef QT_NO_ACCESSIBILITY #include <QtCore/qobject.h> QT_BEGIN_NAMESPACE @@ -74,4 +75,5 @@ private: } +#endif // QT_NO_ACCESSIBILITY #endif diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index b5cd26f2f..9d7dbe8d8 100644 --- a/src/core/browser_accessibility_qt.cpp +++ b/src/core/browser_accessibility_qt.cpp @@ -38,6 +38,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef QT_NO_ACCESSIBILITY #include "browser_accessibility_qt.h" #include "third_party/WebKit/public/web/WebAXEnums.h" @@ -384,8 +385,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::NoRole; // FIXME case ui::AX_ROLE_MATH: return QAccessible::Equation; - case ui::AX_ROLE_MATH_ELEMENT: - return QAccessible::Equation; case ui::AX_ROLE_MATTE: return QAccessible::NoRole; // FIXME case ui::AX_ROLE_MENU: @@ -898,3 +897,5 @@ void BrowserAccessibilityQt::modelChange(QAccessibleTableModelChangeEvent *) } } // namespace content + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h index db190ffc4..6baab98b3 100644 --- a/src/core/browser_accessibility_qt.h +++ b/src/core/browser_accessibility_qt.h @@ -36,6 +36,7 @@ #ifndef BROWSER_ACCESSIBILITY_QT_H #define BROWSER_ACCESSIBILITY_QT_H +#ifndef QT_NO_ACCESSIBILITY #include <QtGui/qaccessible.h> #include "content/browser/accessibility/browser_accessibility.h" @@ -145,4 +146,5 @@ public: } +#endif // QT_NO_ACCESSIBILITY #endif diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp new file mode 100644 index 000000000..586d2c2ef --- /dev/null +++ b/src/core/browser_context_adapter.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** 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 "content/public/browser/browser_thread.h" +#include "browser_context_qt.h" +#include "content_client_qt.h" +#include "download_manager_delegate_qt.h" +#include "web_engine_context.h" +#include "web_engine_visited_links_manager.h" +#include "url_request_context_getter_qt.h" + +#include "net/proxy/proxy_service.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() % QLatin1String("/.") % QCoreApplication::applicationName(); + + location.append(QLatin1String("/QtWebEngine/") % name); + return location; +} +} + +BrowserContextAdapter::BrowserContextAdapter(bool offTheRecord) + : m_offTheRecord(offTheRecord) + , m_browserContext(new BrowserContextQt(this)) + , m_httpCacheType(DiskHttpCache) + , m_persistentCookiesPolicy(AllowPersistentCookies) + , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) + , m_client(0) + , m_httpCacheMaxSize(0) +{ +} + +BrowserContextAdapter::BrowserContextAdapter(const QString &storageName) + : m_name(storageName) + , m_offTheRecord(false) + , m_browserContext(new BrowserContextQt(this)) + , m_httpCacheType(DiskHttpCache) + , m_persistentCookiesPolicy(AllowPersistentCookies) + , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) + , m_httpCacheMaxSize(0) +{ +} + +BrowserContextAdapter::~BrowserContextAdapter() +{ + if (m_downloadManagerDelegate) + content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE, m_downloadManagerDelegate.take()); +} + +void BrowserContextAdapter::setStorageName(const QString &storageName) +{ + if (storageName == m_name) + return; + m_name = storageName; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateStorageSettings(); + m_visitedLinksManager.reset(); +} + +void BrowserContextAdapter::setOffTheRecord(bool offTheRecord) +{ + if (offTheRecord == m_offTheRecord) + return; + m_offTheRecord = offTheRecord; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateStorageSettings(); + m_visitedLinksManager.reset(); +} + +BrowserContextQt *BrowserContextAdapter::browserContext() +{ + return m_browserContext.data(); +} + +WebEngineVisitedLinksManager *BrowserContextAdapter::visitedLinksManager() +{ + if (!m_visitedLinksManager) + m_visitedLinksManager.reset(new WebEngineVisitedLinksManager(this)); + return m_visitedLinksManager.data(); +} + +DownloadManagerDelegateQt *BrowserContextAdapter::downloadManagerDelegate() +{ + if (!m_downloadManagerDelegate) + m_downloadManagerDelegate.reset(new DownloadManagerDelegateQt(this)); + return m_downloadManagerDelegate.data(); +} + +void BrowserContextAdapter::setClient(BrowserContextAdapterClient *adapterClient) +{ + m_client = adapterClient; +} + +void BrowserContextAdapter::cancelDownload(quint32 downloadId) +{ + downloadManagerDelegate()->cancelDownload(downloadId); +} + +BrowserContextAdapter* BrowserContextAdapter::defaultContext() +{ + return WebEngineContext::current()->defaultBrowserContext(); +} + +BrowserContextAdapter* BrowserContextAdapter::offTheRecordContext() +{ + return WebEngineContext::current()->offTheRecordBrowserContext(); +} + +QString BrowserContextAdapter::dataPath() const +{ + if (m_offTheRecord) + return QString(); + if (!m_dataPath.isEmpty()) + return m_dataPath; + if (!m_name.isNull()) + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation), m_name); + return QString(); +} + +void BrowserContextAdapter::setDataPath(const QString &path) +{ + if (m_dataPath == path) + return; + m_dataPath = path; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateStorageSettings(); + m_visitedLinksManager.reset(); +} + +QString BrowserContextAdapter::cachePath() const +{ + if (m_offTheRecord) + return QString(); + if (!m_cachePath.isEmpty()) + return m_cachePath; + if (!m_name.isNull()) + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation), m_name); + return QString(); +} + +void BrowserContextAdapter::setCachePath(const QString &path) +{ + if (m_cachePath == path) + return; + m_cachePath = path; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateHttpCache(); +} + +QString BrowserContextAdapter::cookiesPath() const +{ + if (m_offTheRecord) + return QString(); + QString basePath = dataPath(); + if (!basePath.isEmpty()) + return basePath % QLatin1String("/Coookies"); + return QString(); +} + +QString BrowserContextAdapter::httpCachePath() const +{ + if (m_offTheRecord) + return QString(); + QString basePath = cachePath(); + if (!basePath.isEmpty()) + return basePath % QLatin1String("/Cache"); + return QString(); +} + +QString BrowserContextAdapter::httpUserAgent() const +{ + if (m_httpUserAgent.isNull()) + return QString::fromStdString(ContentClientQt::getUserAgent()); + return m_httpUserAgent; +} + +void BrowserContextAdapter::setHttpUserAgent(const QString &userAgent) +{ + if (m_httpUserAgent == userAgent) + return; + m_httpUserAgent = userAgent; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateUserAgent(); +} + +BrowserContextAdapter::HttpCacheType BrowserContextAdapter::httpCacheType() const +{ + if (isOffTheRecord() || httpCachePath().isEmpty()) + return MemoryHttpCache; + return m_httpCacheType; +} + +void BrowserContextAdapter::setHttpCacheType(BrowserContextAdapter::HttpCacheType newhttpCacheType) +{ + BrowserContextAdapter::HttpCacheType oldCacheType = httpCacheType(); + m_httpCacheType = newhttpCacheType; + if (oldCacheType == httpCacheType()) + return; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateHttpCache(); +} + +BrowserContextAdapter::PersistentCookiesPolicy BrowserContextAdapter::persistentCookiesPolicy() const +{ + if (isOffTheRecord() || cookiesPath().isEmpty()) + return NoPersistentCookies; + return m_persistentCookiesPolicy; +} + +void BrowserContextAdapter::setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = persistentCookiesPolicy(); + m_persistentCookiesPolicy = newPersistentCookiesPolicy; + if (oldPolicy == persistentCookiesPolicy()) + return; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateCookieStore(); +} + +BrowserContextAdapter::VisitedLinksPolicy BrowserContextAdapter::visitedLinksPolicy() const +{ + if (isOffTheRecord() || m_visitedLinksPolicy == DoNotTrackVisitedLinks) + return DoNotTrackVisitedLinks; + if (dataPath().isEmpty()) + return TrackVisitedLinksInMemory; + return m_visitedLinksPolicy; +} + +bool BrowserContextAdapter::trackVisitedLinks() const +{ + switch (visitedLinksPolicy()) { + case DoNotTrackVisitedLinks: + return false; + default: + break; + } + return true; +} + +bool BrowserContextAdapter::persistVisitedLinks() const +{ + switch (visitedLinksPolicy()) { + case DoNotTrackVisitedLinks: + case TrackVisitedLinksInMemory: + return false; + default: + break; + } + return true; +} + +void BrowserContextAdapter::setVisitedLinksPolicy(BrowserContextAdapter::VisitedLinksPolicy visitedLinksPolicy) +{ + if (m_visitedLinksPolicy == visitedLinksPolicy) + return; + m_visitedLinksPolicy = visitedLinksPolicy; + m_visitedLinksManager.reset(); +} + +int BrowserContextAdapter::httpCacheMaxSize() const +{ + return m_httpCacheMaxSize; +} + +void BrowserContextAdapter::setHttpCacheMaxSize(int maxSize) +{ + if (m_httpCacheMaxSize == maxSize) + return; + m_httpCacheMaxSize = maxSize; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateHttpCache(); +} diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h new file mode 100644 index 000000000..1c12c465d --- /dev/null +++ b/src/core/browser_context_adapter.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 BrowserContextAdapterClient; +class BrowserContextQt; +class DownloadManagerDelegateQt; +class WebEngineVisitedLinksManager; + +class QWEBENGINE_EXPORT BrowserContextAdapter : public QSharedData +{ +public: + explicit BrowserContextAdapter(bool offTheRecord = false); + explicit BrowserContextAdapter(const QString &storagePrefix); + virtual ~BrowserContextAdapter(); + + static BrowserContextAdapter* defaultContext(); + static BrowserContextAdapter* offTheRecordContext(); + + WebEngineVisitedLinksManager *visitedLinksManager(); + DownloadManagerDelegateQt *downloadManagerDelegate(); + + BrowserContextAdapterClient* client() { return m_client; } + + void setClient(BrowserContextAdapterClient *adapterClient); + void cancelDownload(quint32 downloadId); + + BrowserContextQt *browserContext(); + + QString storageName() const { return m_name; } + void setStorageName(const QString &storageName); + + bool isOffTheRecord() const { return m_offTheRecord; } + void setOffTheRecord(bool offTheRecord); + + QString dataPath() const; + void setDataPath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpCachePath() const; + QString cookiesPath() const; + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + // KEEP IN SYNC with API or add mapping layer + enum HttpCacheType { + MemoryHttpCache = 0, + DiskHttpCache + }; + + enum PersistentCookiesPolicy { + NoPersistentCookies = 0, + AllowPersistentCookies, + ForcePersistentCookies + }; + + enum VisitedLinksPolicy { + DoNotTrackVisitedLinks = 0, + TrackVisitedLinksInMemory, + TrackVisitedLinksOnDisk, + }; + + HttpCacheType httpCacheType() const; + void setHttpCacheType(BrowserContextAdapter::HttpCacheType); + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy); + + VisitedLinksPolicy visitedLinksPolicy() const; + void setVisitedLinksPolicy(BrowserContextAdapter::VisitedLinksPolicy); + + int httpCacheMaxSize() const; + void setHttpCacheMaxSize(int maxSize); + + bool trackVisitedLinks() const; + bool persistVisitedLinks() const; + +private: + QString m_name; + bool m_offTheRecord; + QScopedPointer<BrowserContextQt> m_browserContext; + QScopedPointer<WebEngineVisitedLinksManager> m_visitedLinksManager; + QScopedPointer<DownloadManagerDelegateQt> m_downloadManagerDelegate; + QString m_dataPath; + QString m_cachePath; + QString m_httpUserAgent; + HttpCacheType m_httpCacheType; + PersistentCookiesPolicy m_persistentCookiesPolicy; + VisitedLinksPolicy m_visitedLinksPolicy; + BrowserContextAdapterClient *m_client; + int m_httpCacheMaxSize; + + Q_DISABLE_COPY(BrowserContextAdapter) +}; + +#endif // BROWSER_CONTEXT_ADAPTER_H diff --git a/src/core/browser_context_adapter_client.h b/src/core/browser_context_adapter_client.h new file mode 100644 index 000000000..a9e7eb726 --- /dev/null +++ b/src/core/browser_context_adapter_client.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 BROWSER_CONTEXT_ADAPTER_CLIENT_H +#define BROWSER_CONTEXT_ADAPTER_CLIENT_H + +#include "qtwebenginecoreglobal.h" +#include <QString> +#include <QUrl> + +class QWEBENGINE_EXPORT BrowserContextAdapterClient +{ +public: + // Keep in sync with content::DownloadItem::DownloadState + enum DownloadState { + // Download is actively progressing. + DownloadInProgress = 0, + // Download is completely finished. + DownloadCompleted, + // Download has been cancelled. + DownloadCancelled, + // This state indicates that the download has been interrupted. + DownloadInterrupted + }; + + struct DownloadItemInfo { + const quint32 id; + const QUrl url; + const int state; + const qint64 totalBytes; + const qint64 receivedBytes; + + QString path; + bool accepted; + }; + + virtual ~BrowserContextAdapterClient() { } + + virtual void downloadRequested(DownloadItemInfo &info) = 0; + virtual void downloadUpdated(const DownloadItemInfo &info) = 0; +}; + +#endif // BROWSER_CONTEXT_ADAPTER_CLIENT_H diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 44b6ca4ef..7fcbdee07 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -36,27 +36,21 @@ #include "browser_context_qt.h" +#include "browser_context_adapter.h" +#include "download_manager_delegate_qt.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" #include "resource_context_qt.h" #include "url_request_context_getter_qt.h" -#include "base/files/scoped_temp_dir.h" #include "base/time/time.h" #include "content/public/browser/browser_thread.h" #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)); } BrowserContextQt::~BrowserContextQt() @@ -67,29 +61,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 toFilePath(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 toFilePath(m_adapter->cachePath()); } bool BrowserContextQt::IsOffTheRecord() const { - return false; + return m_adapter->isOffTheRecord(); } net::URLRequestContextGetter *BrowserContextQt::GetRequestContext() @@ -119,12 +101,14 @@ net::URLRequestContextGetter *BrowserContextQt::GetMediaRequestContextForStorage content::ResourceContext *BrowserContextQt::GetResourceContext() { + if (!resourceContext) + resourceContext.reset(new ResourceContextQt(this)); return resourceContext.get(); } content::DownloadManagerDelegate *BrowserContextQt::GetDownloadManagerDelegate() { - return downloadManagerDelegate.get(); + return m_adapter->downloadManagerDelegate(); } content::BrowserPluginGuestManager *BrowserContextQt::GetGuestManager() @@ -132,7 +116,7 @@ content::BrowserPluginGuestManager *BrowserContextQt::GetGuestManager() return 0; } -quota::SpecialStoragePolicy *BrowserContextQt::GetSpecialStoragePolicy() +storage::SpecialStoragePolicy *BrowserContextQt::GetSpecialStoragePolicy() { QT_NOT_YET_IMPLEMENTED return 0; @@ -143,9 +127,14 @@ content::PushMessagingService *BrowserContextQt::GetPushMessagingService() return 0; } +content::SSLHostStateDelegate* BrowserContextQt::GetSSLHostStateDelegate() +{ + return 0; +} + net::URLRequestContextGetter *BrowserContextQt::CreateRequestContext(content::ProtocolHandlerMap *protocol_handlers) { - url_request_getter_ = new URLRequestContextGetterQt(GetPath(), GetCachePath(), protocol_handlers); - static_cast<ResourceContextQt*>(resourceContext.get())->set_url_request_context_getter(url_request_getter_.get()); + url_request_getter_ = new URLRequestContextGetterQt(m_adapter, protocol_handlers); + static_cast<ResourceContextQt*>(GetResourceContext())->set_url_request_context_getter(url_request_getter_.get()); return url_request_getter_.get(); } diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index 125c0fc46..ad46751a0 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -41,12 +41,16 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/resource_context.h" #include "net/url_request/url_request_context.h" -#include "download_manager_delegate_qt.h" + +#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE + +class BrowserContextAdapter; +class URLRequestContextGetterQt; class BrowserContextQt : public content::BrowserContext { public: - explicit BrowserContextQt(); + explicit BrowserContextQt(BrowserContextAdapter *); virtual ~BrowserContextQt(); @@ -62,14 +66,17 @@ public: virtual content::ResourceContext *GetResourceContext() Q_DECL_OVERRIDE; virtual content::DownloadManagerDelegate *GetDownloadManagerDelegate() Q_DECL_OVERRIDE; virtual content::BrowserPluginGuestManager* GetGuestManager() Q_DECL_OVERRIDE; - virtual quota::SpecialStoragePolicy *GetSpecialStoragePolicy() Q_DECL_OVERRIDE; + virtual storage::SpecialStoragePolicy *GetSpecialStoragePolicy() Q_DECL_OVERRIDE; virtual content::PushMessagingService* GetPushMessagingService() Q_DECL_OVERRIDE; + virtual content::SSLHostStateDelegate* GetSSLHostStateDelegate() Q_DECL_OVERRIDE; net::URLRequestContextGetter *CreateRequestContext(content::ProtocolHandlerMap *protocol_handlers); + BrowserContextAdapter* adapter() { return m_adapter; } private: scoped_ptr<content::ResourceContext> resourceContext; - scoped_refptr<net::URLRequestContextGetter> url_request_getter_; - scoped_ptr<DownloadManagerDelegateQt> downloadManagerDelegate; + scoped_refptr<URLRequestContextGetterQt> url_request_getter_; + BrowserContextAdapter *m_adapter; + friend class BrowserContextAdapter; DISALLOW_COPY_AND_ASSIGN(BrowserContextQt); }; diff --git a/src/core/certificate_error_controller.cpp b/src/core/certificate_error_controller.cpp index b5c705de3..365caed22 100644 --- a/src/core/certificate_error_controller.cpp +++ b/src/core/certificate_error_controller.cpp @@ -51,7 +51,7 @@ void CertificateErrorControllerPrivate::accept(bool accepted) CertificateErrorControllerPrivate::CertificateErrorControllerPrivate(int cert_error, const net::SSLInfo& ssl_info, const GURL &request_url, - ResourceType::Type resource_type, + content::ResourceType resource_type, bool _overridable, bool strict_enforcement, const base::Callback<void(bool)>& cb @@ -63,7 +63,7 @@ CertificateErrorControllerPrivate::CertificateErrorControllerPrivate(int cert_er , strictEnforcement(strict_enforcement) , callback(cb) { - if (ssl_info.cert) { + if (ssl_info.cert.get()) { validStart = toQt(ssl_info.cert->valid_start()); validExpiry = toQt(ssl_info.cert->valid_expiry()); } @@ -135,8 +135,6 @@ QString CertificateErrorController::errorString() const return getQStringForMessageId(IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION); case CertificateNoRevocationMechanism: return getQStringForMessageId(IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DETAILS); - case CertificateUnableToCheckRevocation: - return getQStringForMessageId(IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DETAILS); case CertificateRevoked: return getQStringForMessageId(IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION); case CertificateInvalid: @@ -149,6 +147,7 @@ QString CertificateErrorController::errorString() const return getQStringForMessageId(IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); case CertificateNameConstraintViolation: return getQStringForMessageId(IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION); + case CertificateUnableToCheckRevocation: // Deprecated in Chromium. default: break; } diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h index f1e7c5bd8..6d364fc9f 100644 --- a/src/core/certificate_error_controller.h +++ b/src/core/certificate_error_controller.h @@ -40,12 +40,13 @@ #include "qtwebenginecoreglobal.h" #include <QtCore/QDateTime> -#include <QtCore/QSharedData> #include <QtCore/QUrl> +QT_BEGIN_NAMESPACE + class CertificateErrorControllerPrivate; -class QWEBENGINE_EXPORT CertificateErrorController : public QSharedData { +class QWEBENGINE_EXPORT CertificateErrorController { public: CertificateErrorController(CertificateErrorControllerPrivate *p); ~CertificateErrorController(); @@ -107,4 +108,6 @@ private: CertificateErrorControllerPrivate* d; }; +QT_END_NAMESPACE + #endif // CERTIFICATE_ERROR_CONTROLLER_H diff --git a/src/core/certificate_error_controller_p.h b/src/core/certificate_error_controller_p.h index af0ce12aa..308131eb5 100644 --- a/src/core/certificate_error_controller_p.h +++ b/src/core/certificate_error_controller_p.h @@ -41,9 +41,11 @@ #include "certificate_error_controller.h" +QT_BEGIN_NAMESPACE + class CertificateErrorControllerPrivate { public: - CertificateErrorControllerPrivate(int cert_error, const net::SSLInfo& ssl_info, const GURL& request_url, ResourceType::Type resource_type, bool overridable, bool strict_enforcement, const base::Callback<void(bool)>& callback); + CertificateErrorControllerPrivate(int cert_error, const net::SSLInfo& ssl_info, const GURL& request_url, content::ResourceType resource_type, bool overridable, bool strict_enforcement, const base::Callback<void(bool)>& callback); void accept(bool accepted); @@ -54,7 +56,9 @@ public: CertificateErrorController::ResourceType resourceType; bool overridable; bool strictEnforcement; - const base::Callback<void(bool)>& callback; + const base::Callback<void(bool)> callback; }; +QT_END_NAMESPACE + #endif // CERTIFICATE_ERROR_CONTROLLER_P_H diff --git a/src/core/chrome_qt.gyp b/src/core/chrome_qt.gyp index 81ab2e881..703ce7525 100644 --- a/src/core/chrome_qt.gyp +++ b/src/core/chrome_qt.gyp @@ -21,8 +21,6 @@ '<(chromium_src_dir)/chrome/browser/media/desktop_media_list.h', '<(chromium_src_dir)/chrome/common/localized_error.cc', '<(chromium_src_dir)/chrome/common/localized_error.h', - '<(chromium_src_dir)/chrome/common/net/net_error_info.cc', - '<(chromium_src_dir)/chrome/common/net/net_error_info.h', ], }, { diff --git a/src/core/chromium_gpu_helper.cpp b/src/core/chromium_gpu_helper.cpp index 6287bd7c0..8ea8ad20d 100644 --- a/src/core/chromium_gpu_helper.cpp +++ b/src/core/chromium_gpu_helper.cpp @@ -96,7 +96,8 @@ gpu::gles2::MailboxManager *mailbox_manager() gpu::gles2::Texture* ConsumeTexture(gpu::gles2::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox) { - return mailboxManager->ConsumeTexture(target, mailbox); + Q_UNUSED(target); + return mailboxManager->ConsumeTexture(mailbox); } unsigned int service_id(gpu::gles2::Texture *tex) diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp index 9e97e3226..bb71d0d35 100644 --- a/src/core/chromium_overrides.cpp +++ b/src/core/chromium_overrides.cpp @@ -156,6 +156,7 @@ RenderText* RenderText::CreateNativeInstance() return 0; } +#if defined(OS_LINUX) PlatformFont* PlatformFont::CreateDefault() { QT_NOT_USED; @@ -173,6 +174,7 @@ PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string&, int) QT_NOT_USED; return 0; } +#endif } // namespace gfx diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp index 870c6ae2d..15d8e18dd 100644 --- a/src/core/clipboard_qt.cpp +++ b/src/core/clipboard_qt.cpp @@ -63,8 +63,6 @@ void ClipboardChangeObserver::trackChange(QClipboard::Mode mode) ++sequenceNumber[mode]; } -namespace ui { - namespace { const char kMimeTypeBitmap[] = "image/bmp"; @@ -83,6 +81,76 @@ QMimeData *getUncommittedData() } // namespace +namespace ui { + +// Factory function +Clipboard* Clipboard::Create() { + return new ClipboardQt; +} + +Clipboard::FormatType Clipboard::GetFormatType(const std::string& format_string) +{ + return FormatType::Deserialize(format_string); +} + +const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText)); + return type; +} + +const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() +{ + return GetPlainTextFormatType(); +} + +const Clipboard::FormatType& Clipboard::GetUrlFormatType() +{ + return GetPlainTextFormatType(); +} + +const Clipboard::FormatType& Clipboard::GetUrlWFormatType() +{ + return GetPlainTextWFormatType(); +} + +const Clipboard::FormatType& Clipboard::GetHtmlFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); + return type; +} + +const Clipboard::FormatType& Clipboard::GetRtfFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF)); + return type; +} + +const Clipboard::FormatType& Clipboard::GetBitmapFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap)); + return type; +} + +const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); + return type; +} + +const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomDataCopy)); + return type; +} + +const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() +{ + CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); + return type; +} + + Clipboard::FormatType::FormatType() { } @@ -111,15 +179,16 @@ bool Clipboard::FormatType::Equals(const FormatType& other) const return data_ == other.data_; } -Clipboard::Clipboard() +#if defined(OS_WIN) || defined(USE_AURA) +bool Clipboard::FormatType::operator<(const FormatType& other) const { + return data_.compare(other.data_) < 0; } +#endif -Clipboard::~Clipboard() -{ -} +} // namespace ui -void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) +void ClipboardQt::WriteObjects(ui::ClipboardType type, const ObjectMap& objects) { DCHECK(CalledOnValidThread()); DCHECK(IsSupportedClipboardType(type)); @@ -129,45 +198,45 @@ void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) // Commit the accumulated data. if (uncommittedData) - QGuiApplication::clipboard()->setMimeData(uncommittedData.take(), type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + QGuiApplication::clipboard()->setMimeData(uncommittedData.take(), type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); - if (type == CLIPBOARD_TYPE_COPY_PASTE) { + if (type == ui::CLIPBOARD_TYPE_COPY_PASTE) { ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT); if (text_iter != objects.end()) { // Copy text and SourceTag to the selection clipboard. ObjectMap::const_iterator next_iter = text_iter; - WriteObjects(CLIPBOARD_TYPE_SELECTION, ObjectMap(text_iter, ++next_iter)); + WriteObjects(ui::CLIPBOARD_TYPE_SELECTION, ObjectMap(text_iter, ++next_iter)); } } } -void Clipboard::WriteText(const char* text_data, size_t text_len) +void ClipboardQt::WriteText(const char* text_data, size_t text_len) { getUncommittedData()->setText(QString::fromUtf8(text_data, text_len)); } -void Clipboard::WriteHTML(const char* markup_data, size_t markup_len, const char* url_data, size_t url_len) +void ClipboardQt::WriteHTML(const char* markup_data, size_t markup_len, const char* url_data, size_t url_len) { getUncommittedData()->setHtml(QString::fromUtf8(markup_data, markup_len)); } -void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) +void ClipboardQt::WriteRTF(const char* rtf_data, size_t data_len) { getUncommittedData()->setData(QString::fromLatin1(kMimeTypeRTF), QByteArray(rtf_data, data_len)); } -void Clipboard::WriteWebSmartPaste() +void ClipboardQt::WriteWebSmartPaste() { getUncommittedData()->setData(QString::fromLatin1(kMimeTypeWebkitSmartPaste), QByteArray()); } -void Clipboard::WriteBitmap(const SkBitmap& bitmap) +void ClipboardQt::WriteBitmap(const SkBitmap& bitmap) { QImage image(reinterpret_cast<const uchar *>(bitmap.getPixels()), bitmap.width(), bitmap.height(), QImage::Format_ARGB32); getUncommittedData()->setImageData(image.copy()); } -void Clipboard::WriteBookmark(const char* title_data, size_t title_len, const char* url_data, size_t url_len) +void ClipboardQt::WriteBookmark(const char* title_data, size_t title_len, const char* url_data, size_t url_len) { // FIXME: Untested, seems to be used only for drag-n-drop. // Write as a mozilla url (UTF16: URL, newline, title). @@ -181,23 +250,23 @@ void Clipboard::WriteBookmark(const char* title_data, size_t title_len, const ch getUncommittedData()->setData(QString::fromLatin1(kMimeTypeMozillaURL), data); } -void Clipboard::WriteData(const FormatType& format, const char* data_data, size_t data_len) +void ClipboardQt::WriteData(const FormatType& format, const char* data_data, size_t data_len) { - getUncommittedData()->setData(QString::fromStdString(format.data_), QByteArray(data_data, data_len)); + getUncommittedData()->setData(QString::fromStdString(format.ToString()), QByteArray(data_data, data_len)); } -bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, ClipboardType type) const +bool ClipboardQt::IsFormatAvailable(const ui::Clipboard::FormatType& format, ui::ClipboardType type) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); - return mimeData->hasFormat(QString::fromStdString(format.data_)); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + return mimeData->hasFormat(QString::fromStdString(format.ToString())); } -void Clipboard::Clear(ClipboardType type) +void ClipboardQt::Clear(ui::ClipboardType type) { - QGuiApplication::clipboard()->clear(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + QGuiApplication::clipboard()->clear(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); } -void Clipboard::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16>* types, bool* contains_filenames) const +void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16>* types, bool* contains_filenames) const { if (!types || !contains_filenames) { NOTREACHED(); @@ -205,29 +274,29 @@ void Clipboard::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::str } types->clear(); - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); Q_FOREACH (const QString &mimeType, mimeData->formats()) types->push_back(toString16(mimeType)); *contains_filenames = false; const QByteArray customData = mimeData->data(QString::fromLatin1(kMimeTypeWebCustomDataCopy)); - ReadCustomDataTypes(customData.constData(), customData.size(), types); + ui::ReadCustomDataTypes(customData.constData(), customData.size(), types); } -void Clipboard::ReadText(ClipboardType type, base::string16* result) const +void ClipboardQt::ReadText(ui::ClipboardType type, base::string16* result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); *result = toString16(mimeData->text()); } -void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const +void ClipboardQt::ReadAsciiText(ui::ClipboardType type, std::string* result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); *result = mimeData->text().toStdString(); } -void Clipboard::ReadHTML(ClipboardType type, base::string16* markup, std::string* src_url, uint32* fragment_start, uint32* fragment_end) const +void ClipboardQt::ReadHTML(ui::ClipboardType type, base::string16* markup, std::string* src_url, uint32* fragment_start, uint32* fragment_end) const { markup->clear(); if (src_url) @@ -235,23 +304,23 @@ void Clipboard::ReadHTML(ClipboardType type, base::string16* markup, std::string *fragment_start = 0; *fragment_end = 0; - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); *markup = toString16(mimeData->html()); *fragment_end = static_cast<uint32>(markup->length()); } -void Clipboard::ReadRTF(ClipboardType type, std::string* result) const +void ClipboardQt::ReadRTF(ui::ClipboardType type, std::string* result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); const QByteArray byteArray = mimeData->data(QString::fromLatin1(kMimeTypeRTF)); *result = std::string(byteArray.constData(), byteArray.length()); } -SkBitmap Clipboard::ReadImage(ClipboardType type) const +SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const { // FIXME: Untested, pasting image data seems to only be supported through // FileReader.readAsDataURL in JavaScript and this isn't working down the pipe for some reason. - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); QImage image = qvariant_cast<QImage>(mimeData->imageData()); Q_ASSERT(image.format() == QImage::Format_ARGB32); @@ -265,97 +334,28 @@ SkBitmap Clipboard::ReadImage(ClipboardType type) const return copy; } -void Clipboard::ReadCustomData(ClipboardType clipboard_type, const base::string16& type, base::string16* result) const +void ClipboardQt::ReadCustomData(ui::ClipboardType clipboard_type, const base::string16& type, base::string16* result) const { - const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(clipboard_type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); + const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(clipboard_type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); const QByteArray customData = mimeData->data(QString::fromLatin1(kMimeTypeWebCustomDataCopy)); - ReadCustomDataForType(customData.constData(), customData.size(), type, result); + ui::ReadCustomDataForType(customData.constData(), customData.size(), type, result); } -void Clipboard::ReadBookmark(base::string16* title, std::string* url) const +void ClipboardQt::ReadBookmark(base::string16* title, std::string* url) const { NOTIMPLEMENTED(); } -void Clipboard::ReadData(const FormatType& format, std::string* result) const +void ClipboardQt::ReadData(const FormatType& format, std::string* result) const { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(); - const QByteArray byteArray = mimeData->data(QString::fromStdString(format.data_)); + const QByteArray byteArray = mimeData->data(QString::fromStdString(format.ToString())); *result = std::string(byteArray.constData(), byteArray.length()); } -uint64 Clipboard::GetSequenceNumber(ClipboardType type) -{ - return clipboardChangeObserver()->getSequenceNumber(type == CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); -} - -Clipboard::FormatType Clipboard::GetFormatType(const std::string& format_string) -{ - return FormatType::Deserialize(format_string); -} - -const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() -{ - return GetPlainTextFormatType(); -} - -const Clipboard::FormatType& Clipboard::GetUrlFormatType() -{ - return GetPlainTextFormatType(); -} - -const Clipboard::FormatType& Clipboard::GetUrlWFormatType() +uint64 ClipboardQt::GetSequenceNumber(ui::ClipboardType type) { - return GetPlainTextWFormatType(); + return clipboardChangeObserver()->getSequenceNumber(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); } -const Clipboard::FormatType& Clipboard::GetHtmlFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetRtfFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetBitmapFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomDataCopy)); - return type; -} - -const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() -{ - CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); - return type; -} - -#if defined(OS_WIN) || defined(USE_AURA) -bool Clipboard::FormatType::operator<(const FormatType& other) const -{ - return data_.compare(other.data_) < 0; -} -#endif -} // namespace ui diff --git a/src/core/clipboard_qt.h b/src/core/clipboard_qt.h index 87f2c2c2a..02db41c25 100644 --- a/src/core/clipboard_qt.h +++ b/src/core/clipboard_qt.h @@ -37,6 +37,8 @@ #ifndef CLIPBOARD_QT_H #define CLIPBOARD_QT_H +#include "ui/base/clipboard/clipboard.h" + #include <QClipboard> #include <QMap> #include <QObject> @@ -56,4 +58,34 @@ private: QMap<QClipboard::Mode, quint64> sequenceNumber; }; +class ClipboardQt : public ui::Clipboard { +public: + virtual uint64 GetSequenceNumber(ui::ClipboardType type) Q_DECL_OVERRIDE; + virtual bool IsFormatAvailable(const FormatType& format, ui::ClipboardType type) const Q_DECL_OVERRIDE; + virtual void Clear(ui::ClipboardType type) Q_DECL_OVERRIDE; + virtual void ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16>* types, bool* contains_filenames) const Q_DECL_OVERRIDE; + virtual void ReadText(ui::ClipboardType type, base::string16* result) const Q_DECL_OVERRIDE; + virtual void ReadAsciiText(ui::ClipboardType type, std::string* result) const Q_DECL_OVERRIDE; + virtual void ReadHTML(ui::ClipboardType type, + base::string16* markup, + std::string* src_url, + uint32* fragment_start, + uint32* fragment_end) const Q_DECL_OVERRIDE; + virtual void ReadRTF(ui::ClipboardType type, std::string* result) const Q_DECL_OVERRIDE; + virtual SkBitmap ReadImage(ui::ClipboardType type) const Q_DECL_OVERRIDE; + virtual void ReadCustomData(ui::ClipboardType clipboard_type, const base::string16& type, base::string16* result) const Q_DECL_OVERRIDE; + virtual void ReadBookmark(base::string16* title, std::string* url) const Q_DECL_OVERRIDE; + virtual void ReadData(const FormatType& format, std::string* result) const Q_DECL_OVERRIDE; + +protected: + virtual void WriteObjects(ui::ClipboardType type, const ObjectMap& objects) Q_DECL_OVERRIDE; + virtual void WriteText(const char* text_data, size_t text_len) Q_DECL_OVERRIDE; + virtual void WriteHTML(const char* markup_data, size_t markup_len, const char* url_data, size_t url_len) Q_DECL_OVERRIDE; + virtual void WriteRTF(const char* rtf_data, size_t data_len) Q_DECL_OVERRIDE; + virtual void WriteBookmark(const char* title_data, size_t title_len, const char* url_data, size_t url_len) Q_DECL_OVERRIDE; + virtual void WriteWebSmartPaste() Q_DECL_OVERRIDE; + virtual void WriteBitmap(const SkBitmap& bitmap) Q_DECL_OVERRIDE; + virtual void WriteData(const FormatType& format, const char* data_data, size_t data_len) Q_DECL_OVERRIDE; +}; + #endif diff --git a/src/core/common/qt_messages.h b/src/core/common/qt_messages.h index 315987cd3..5ae5fef7d 100644 --- a/src/core/common/qt_messages.h +++ b/src/core/common/qt_messages.h @@ -29,6 +29,8 @@ IPC_MESSAGE_ROUTED1(QtRenderViewObserver_FetchDocumentMarkup, IPC_MESSAGE_ROUTED1(QtRenderViewObserver_FetchDocumentInnerText, uint64 /* requestId */) +IPC_MESSAGE_ROUTED1(WebChannelIPCTransport_Message, std::vector<char> /*binaryJSON*/) + //----------------------------------------------------------------------------- // WebContents messages // These are messages sent from the renderer back to the browser process. @@ -42,3 +44,5 @@ IPC_MESSAGE_ROUTED2(QtRenderViewObserverHost_DidFetchDocumentInnerText, base::string16 /* innerText */) IPC_MESSAGE_ROUTED0(QtRenderViewObserverHost_DidFirstVisuallyNonEmptyLayout) + +IPC_MESSAGE_ROUTED1(WebChannelIPCTransportHost_SendMessage, std::vector<char> /*binaryJSON*/) diff --git a/src/core/config/desktop_linux.pri b/src/core/config/desktop_linux.pri index 57fb39f6e..500e04448 100644 --- a/src/core/config/desktop_linux.pri +++ b/src/core/config/desktop_linux.pri @@ -13,5 +13,7 @@ GYP_CONFIG += \ use_gnome_keyring=0 \ use_kerberos=0 \ use_pango=0 \ + host_clang=0 \ + clang=0 \ !contains(QT_CONFIG, pulseaudio): GYP_CONFIG += use_pulseaudio=0 diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 4948d1d8d..7251e2db0 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -55,17 +55,22 @@ #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" #include "access_token_store_qt.h" #include <QGuiApplication> +#include <QLocale> #include <QOpenGLContext> #include <qpa/qplatformnativeinterface.h> @@ -203,12 +208,10 @@ public: void PreMainMessageLoopRun() Q_DECL_OVERRIDE { - m_browserContext.reset(new BrowserContextQt()); } void PostMainMessageLoopRun() { - m_browserContext.reset(); } int PreCreateThreads() Q_DECL_OVERRIDE @@ -219,13 +222,7 @@ public: return 0; } - BrowserContextQt* browser_context() const { - return m_browserContext.get(); - } - private: - scoped_ptr<BrowserContextQt> m_browserContext; - DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt); }; @@ -246,7 +243,7 @@ public: m_handle = pni->nativeResourceForContext(QByteArrayLiteral("cglcontextobj"), qtContext); else if (platform == QLatin1String("qnx")) m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else if (platform == QLatin1String("eglfs")) + else if (platform == QLatin1String("eglfs") || platform == QLatin1String("wayland")) m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); else if (platform == QLatin1String("windows")) { if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) @@ -342,7 +339,7 @@ void ContentBrowserClientQt::ResourceDispatcherHostCreated() gfx::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup() { - if (!m_shareGroupQtQuick) + if (!m_shareGroupQtQuick.get()) m_shareGroupQtQuick = new ShareGroupQtQuick; return m_shareGroupQtQuick.get(); } @@ -352,7 +349,7 @@ content::MediaObserver *ContentBrowserClientQt::GetMediaObserver() return MediaCaptureDevicesDispatcher::GetInstance(); } -void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, const GURL &url, WebPreferences *web_prefs) +void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, const GURL &url, content::WebPreferences *web_prefs) { Q_UNUSED(url); if (content::WebContents *webContents = rvh->GetDelegate()->GetAsWebContents()) @@ -364,25 +361,9 @@ 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); -} - -void ContentBrowserClientQt::enableInspector(bool enable) -{ - if (enable && !m_devtools) { - m_devtools.reset(new DevToolsHttpHandlerDelegateQt(browser_context())); - } else if (!enable && m_devtools) { - m_devtools.reset(); - } + return static_cast<BrowserContextQt*>(browser_context)->CreateRequestContext(protocol_handlers); } content::QuotaPermissionContext *ContentBrowserClientQt::CreateQuotaPermissionContext() @@ -392,8 +373,9 @@ content::QuotaPermissionContext *ContentBrowserClientQt::CreateQuotaPermissionCo void ContentBrowserClientQt::AllowCertificateError(int render_process_id, int render_frame_id, int cert_error, const net::SSLInfo& ssl_info, const GURL& request_url, - ResourceType::Type resource_type, + content::ResourceType resource_type, bool overridable, bool strict_enforcement, + bool expired_previous_decision, const base::Callback<void(bool)>& callback, content::CertificateRequestResultType* result) { @@ -405,23 +387,60 @@ void ContentBrowserClientQt::AllowCertificateError(int render_process_id, int re if (content::WebContents *webContents = frameHost->GetRenderViewHost()->GetDelegate()->GetAsWebContents()) contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); - QExplicitlySharedDataPointer<CertificateErrorController> errorController(new CertificateErrorController(new CertificateErrorControllerPrivate(cert_error, ssl_info, request_url, resource_type, overridable, strict_enforcement, callback))); + QSharedPointer<CertificateErrorController> errorController(new CertificateErrorController(new CertificateErrorControllerPrivate(cert_error, ssl_info, request_url, resource_type, overridable, strict_enforcement, callback))); 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::RequestPermission(content::PermissionType permission, + content::WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + const base::Callback<void(bool)>& result_callback) { - Q_UNUSED(webContents); Q_UNUSED(bridge_id); - Q_UNUSED(requesting_frame); Q_UNUSED(user_gesture); - Q_UNUSED(cancel_callback); + WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(web_contents->GetDelegate()); + Q_ASSERT(contentsDelegate); + if (permission == content::PERMISSION_GEOLOCATION) + contentsDelegate->requestGeolocationPermission(requesting_frame, result_callback); + else + result_callback.Run(false); +} + + +void ContentBrowserClientQt::CancelPermissionRequest(content::PermissionType permission, + content::WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame) +{ + Q_UNUSED(bridge_id); + WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(web_contents->GetDelegate()); + Q_ASSERT(contentsDelegate); + if (permission == content::PERMISSION_GEOLOCATION) + contentsDelegate->cancelGeolocationPermissionRequest(requesting_frame); +} - // TODO: Add geolocation support - result_callback.Run(false); +blink::WebNotificationPermission ContentBrowserClientQt::CheckDesktopNotificationPermission(const GURL&, content::ResourceContext *, int ) +{ + return blink::WebNotificationPermission::WebNotificationPermissionDenied; +} + +content::LocationProvider *ContentBrowserClientQt::OverrideSystemLocationProvider() +{ +#ifdef QT_USE_POSITIONING + return new LocationProviderQt; +#else + return 0; // Leave it up to Chromium to figure something out. +#endif +} + +std::string ContentBrowserClientQt::GetApplicationLocale() +{ + return QLocale().bcp47Name().toStdString(); +} + +content::DevToolsManagerDelegate* ContentBrowserClientQt::GetDevToolsManagerDelegate() +{ + return new DevToolsManagerDelegateQt; } diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index f1ecf5825..42ee25907 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -40,6 +40,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/public/browser/content_browser_client.h" +#include "third_party/WebKit/public/platform/WebNotificationPermission.h" #include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE @@ -50,8 +51,10 @@ class URLRequestContextGetter; namespace content { class BrowserContext; class BrowserMainParts; +class DevToolsManagerDelegate; class RenderProcessHost; class RenderViewHostDelegateView; +class ResourceContext; class WebContentsViewPort; class WebContents; struct MainFunctionParams; @@ -63,7 +66,6 @@ class GLShareGroup; class BrowserContextQt; class BrowserMainPartsQt; -class DevToolsHttpHandlerDelegateQt; class ResourceDispatcherHostDelegateQt; class ShareGroupQtQuick; @@ -78,37 +80,42 @@ public: virtual void ResourceDispatcherHostCreated() Q_DECL_OVERRIDE; virtual gfx::GLShareGroup* GetInProcessGpuShareGroup() Q_DECL_OVERRIDE; virtual content::MediaObserver* GetMediaObserver() Q_DECL_OVERRIDE; - virtual void OverrideWebkitPrefs(content::RenderViewHost *, const GURL &, WebPreferences *) Q_DECL_OVERRIDE; - virtual content::AccessTokenStore *CreateAccessTokenStore() Q_DECL_OVERRIDE; + virtual content::AccessTokenStore* CreateAccessTokenStore() Q_DECL_OVERRIDE; virtual content::QuotaPermissionContext *CreateQuotaPermissionContext() Q_DECL_OVERRIDE; + virtual void OverrideWebkitPrefs(content::RenderViewHost *, const GURL &, content::WebPreferences *) Q_DECL_OVERRIDE; virtual void AllowCertificateError( int render_process_id, int render_frame_id, int cert_error, const net::SSLInfo& ssl_info, const GURL& request_url, - ResourceType::Type resource_type, + content::ResourceType resource_type, bool overridable, bool strict_enforcement, + bool expired_previous_decision, const base::Callback<void(bool)>& callback, content::CertificateRequestResultType* result) Q_DECL_OVERRIDE; - virtual void RequestGeolocationPermission( - content::WebContents *webContents, + virtual void RequestPermission( + content::PermissionType permission, + content::WebContents* web_contents, int bridge_id, - const GURL &requesting_frame, + const GURL& requesting_frame, bool user_gesture, - base::Callback<void(bool)> result_callback, - base::Closure *cancel_callback) Q_DECL_OVERRIDE; + const base::Callback<void(bool)>& result_callback) Q_DECL_OVERRIDE; + virtual void CancelPermissionRequest(content::PermissionType permission, + content::WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame) Q_DECL_OVERRIDE; + content::LocationProvider* OverrideSystemLocationProvider() Q_DECL_OVERRIDE; + content::DevToolsManagerDelegate *GetDevToolsManagerDelegate() Q_DECL_OVERRIDE; + virtual net::URLRequestContextGetter *CreateRequestContext(content::BrowserContext *browser_context, content::ProtocolHandlerMap *protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptorss) Q_DECL_OVERRIDE; - BrowserContextQt* browser_context(); + virtual blink::WebNotificationPermission CheckDesktopNotificationPermission(const GURL& source_origin, content::ResourceContext* context, int render_process_id) 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); + virtual std::string GetApplicationLocale() Q_DECL_OVERRIDE; private: BrowserMainPartsQt* m_browserMainParts; - scoped_ptr<DevToolsHttpHandlerDelegateQt> m_devtools; scoped_ptr<ResourceDispatcherHostDelegateQt> m_resourceDispatcherHostDelegate; scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick; }; diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index e41888976..a997e398c 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -52,6 +52,8 @@ #include "renderer/content_renderer_client_qt.h" #include "web_engine_library_info.h" +#include <QLocale> + static base::StringPiece PlatformResourceProvider(int key) { if (key == IDR_DIR_HEADER_HTML) { base::StringPiece html_data = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML); @@ -63,7 +65,7 @@ static base::StringPiece PlatformResourceProvider(int key) { void ContentMainDelegateQt::PreSandboxStartup() { net::NetModule::SetResourceProvider(PlatformResourceProvider); - ui::ResourceBundle::InitSharedInstanceWithLocale(l10n_util::GetApplicationLocale(std::string("en-US")), 0); + ui::ResourceBundle::InitSharedInstanceWithLocale(QLocale().name().toStdString(), 0, ui::ResourceBundle::LOAD_COMMON_RESOURCES); // Suppress info, warning and error messages per default. int logLevel = logging::LOG_FATAL; diff --git a/src/core/core_common.pri b/src/core/core_common.pri new file mode 100644 index 000000000..2e9ee4198 --- /dev/null +++ b/src/core/core_common.pri @@ -0,0 +1,8 @@ +# NOTE: The TARGET, QT, QT_PRIVATE variables are used in both core_module.pro and core_gyp_generator.pro +# gyp/ninja will take care of the compilation, qmake/make will finish with linking and install. + +TARGET = QtWebEngineCore +QT += qml quick webchannel +QT_PRIVATE += quick-private gui-private core-private + +qtHaveModule(positioning):QT += positioning diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 3817c334b..3980dcc5a 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -7,11 +7,7 @@ GYPINCLUDES += qtwebengine.gypi TEMPLATE = lib -# NOTE: The TARGET, QT, QT_PRIVATE variables must match those in core_module.pro. -# 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 +include(core_common.pri) # Defining keywords such as 'signal' clashes with the chromium code base. DEFINES += QT_NO_KEYWORDS \ @@ -35,6 +31,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 \ @@ -53,6 +50,7 @@ SOURCES = \ javascript_dialog_controller.cpp \ javascript_dialog_manager_qt.cpp \ media_capture_devices_dispatcher.cpp \ + native_web_keyboard_event_qt.cpp \ network_delegate_qt.cpp \ ozone_platform_eglfs.cpp \ process_main.cpp \ @@ -61,6 +59,7 @@ SOURCES = \ render_widget_host_view_qt.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/qt_render_view_observer.cpp \ + renderer/web_channel_ipc_transport.cpp \ resource_bundle_qt.cpp \ resource_context_qt.cpp \ resource_dispatcher_host_delegate_qt.cpp \ @@ -68,6 +67,7 @@ SOURCES = \ surface_factory_qt.cpp \ url_request_context_getter_qt.cpp \ url_request_qrc_job_qt.cpp \ + web_channel_ipc_transport_host.cpp \ web_contents_adapter.cpp \ web_contents_delegate_qt.cpp \ web_contents_view_qt.cpp \ @@ -83,6 +83,8 @@ HEADERS = \ access_token_store_qt.h \ browser_accessibility_manager_qt.h \ browser_accessibility_qt.h \ + browser_context_adapter.h \ + browser_context_adapter_client.h \ browser_context_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ @@ -112,12 +114,15 @@ HEADERS = \ render_widget_host_view_qt_delegate.h \ renderer/content_renderer_client_qt.h \ renderer/qt_render_view_observer.h \ + renderer/web_channel_ipc_transport.h \ resource_context_qt.h \ 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_channel_ipc_transport_host.h \ web_contents_adapter.h \ web_contents_adapter_client.h \ web_contents_adapter_p.h \ @@ -130,3 +135,9 @@ 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 +} diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 8e445bd3a..afa11d31f 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -1,9 +1,6 @@ MODULE = webenginecore -TARGET = QtWebEngineCore - -QT += qml quick -QT_PRIVATE += gui-private +include(core_common.pri) # 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 e12873c81..33ffbc66a 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::RenderPassId &id, const QList<QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > > &list) { - QSharedPointer<MailboxTexture> &texture = usedTextures[resourceId]; - if (!texture) - texture = candidateTextures.take(resourceId); - Q_ASSERT(texture); - return texture; + typedef QPair<cc::RenderPassId, 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::RenderPassId, 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,16 +469,23 @@ 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. + // to its dependencies through a RenderPassId reference in one or more RenderPassQuads. // The list is already ordered with intermediate RenderPasses placed before their // parent, with the last one in the list being the root RenderPass, the one // that we displayed to the user. @@ -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::RenderPassId, 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; @@ -537,7 +522,7 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour cc::QuadList::ConstBackToFrontIterator it = pass->quad_list.BackToFrontBegin(); cc::QuadList::ConstBackToFrontIterator end = pass->quad_list.BackToFrontEnd(); for (; it != end; ++it) { - cc::DrawQuad *quad = *it; + const cc::DrawQuad *quad = *it; if (currentLayerState != quad->shared_quad_state) { currentLayerState = quad->shared_quad_state; @@ -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..3ef984a09 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::RenderPassId, 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/desktop_screen_qt.cpp b/src/core/desktop_screen_qt.cpp index 34b02e379..1d9114260 100644 --- a/src/core/desktop_screen_qt.cpp +++ b/src/core/desktop_screen_qt.cpp @@ -36,13 +36,6 @@ #include "desktop_screen_qt.h" -bool DesktopScreenQt::IsDIPEnabled() -{ - // Currently only used by GetScaleFactorForNativeView for drag events. - // Short-circuit this until we can test any implementation properly in real code. - return false; -} - gfx::Point DesktopScreenQt::GetCursorScreenPoint() { Q_UNREACHABLE(); diff --git a/src/core/desktop_screen_qt.h b/src/core/desktop_screen_qt.h index ad57c1616..bf0c589f7 100644 --- a/src/core/desktop_screen_qt.h +++ b/src/core/desktop_screen_qt.h @@ -44,7 +44,6 @@ class DesktopScreenQt : public gfx::Screen { public: // Overridden from gfx::Screen: - virtual bool IsDIPEnabled() Q_DECL_OVERRIDE; virtual gfx::Point GetCursorScreenPoint() Q_DECL_OVERRIDE; virtual gfx::NativeWindow GetWindowUnderCursor() Q_DECL_OVERRIDE; virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) Q_DECL_OVERRIDE; diff --git a/src/core/dev_tools_http_handler_delegate_qt.cpp b/src/core/dev_tools_http_handler_delegate_qt.cpp index 4f8992dab..4b866a6bc 100644 --- a/src/core/dev_tools_http_handler_delegate_qt.cpp +++ b/src/core/dev_tools_http_handler_delegate_qt.cpp @@ -34,43 +34,159 @@ ** ****************************************************************************/ +// 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 "type_conversion.h" + #include <QByteArray> #include <QFile> #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/base/ip_endpoint.h" #include "net/socket/stream_listen_socket.h" -#include "net/socket/tcp_listen_socket.h" +#include "net/socket/tcp_server_socket.h" using namespace content; -DevToolsHttpHandlerDelegateQt::DevToolsHttpHandlerDelegateQt(BrowserContext* browser_context) - : m_browserContext(browser_context) +namespace { + +const char kTargetTypePage[] = "page"; +const char kTargetTypeServiceWorker[] = "service_worker"; +const char kTargetTypeOther[] = "other"; + +class TCPServerSocketFactory + : public DevToolsHttpHandler::ServerSocketFactory { +public: + TCPServerSocketFactory(const std::string& address, int port, int backlog) + : DevToolsHttpHandler::ServerSocketFactory(address, port, backlog) {} +private: + scoped_ptr<net::ServerSocket> Create() const override { + return scoped_ptr<net::ServerSocket>(new net::TCPServerSocket(NULL, net::NetLog::Source())); + } + DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory); +}; + +class Target : public content::DevToolsTarget { +public: + explicit Target(scoped_refptr<DevToolsAgentHost> agent_host); + + virtual std::string GetId() const override { return agent_host_->GetId(); } + virtual std::string GetParentId() const override { return std::string(); } + virtual std::string GetType() const override { + switch (agent_host_->GetType()) { + case DevToolsAgentHost::TYPE_WEB_CONTENTS: + return kTargetTypePage; + case DevToolsAgentHost::TYPE_SERVICE_WORKER: + return kTargetTypeServiceWorker; + default: + break; + } + return kTargetTypeOther; + } + virtual std::string GetTitle() const override { return agent_host_->GetTitle(); } + virtual std::string GetDescription() const override { return std::string(); } + virtual GURL GetURL() const override { return agent_host_->GetURL(); } + 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_; + GURL favicon_url_; + base::TimeTicks last_activity_time_; +}; + +Target::Target(scoped_refptr<DevToolsAgentHost> agent_host) + : agent_host_(agent_host) +{ + if (WebContents* web_contents = agent_host_->GetWebContents()) { + NavigationController& controller = web_contents->GetController(); + 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 { + return agent_host_->Activate(); +} + +bool Target::Close() const { + return agent_host_->Close(); +} + +} // namespace + +DevToolsHttpHandlerDelegateQt::DevToolsHttpHandlerDelegateQt() + : m_devtoolsHttpHandler(0) + , m_bindAddress(QLatin1String("127.0.0.1")) + , m_port(0) { - const int defaultPort = 1337; - int listeningPort = defaultPort; + const QString inspectorEnv = QString::fromUtf8(qgetenv("QTWEBENGINE_REMOTE_DEBUGGING")); const CommandLine &commandLine = *CommandLine::ForCurrentProcess(); + QString portStr; + if (commandLine.HasSwitch(switches::kRemoteDebuggingPort)) { - std::string portString = - commandLine.GetSwitchValueASCII(switches::kRemoteDebuggingPort); - int portInt = 0; - if (base::StringToInt(portString, &portInt) && portInt > 0 && portInt < 65535) - listeningPort = portInt; - } - m_devtoolsHttpHandler = DevToolsHttpHandler::Start(new net::TCPListenSocketFactory("0.0.0.0", listeningPort), std::string(), this, base::FilePath()); + portStr = QString::fromStdString(commandLine.GetSwitchValueASCII(switches::kRemoteDebuggingPort)); + } else if (!inspectorEnv.isEmpty()) { + int portColonPos = inspectorEnv.lastIndexOf(':'); + if (portColonPos != -1) { + portStr = inspectorEnv.mid(portColonPos + 1); + m_bindAddress = inspectorEnv.mid(0, portColonPos); + } else + portStr = inspectorEnv; + } else + return; + + bool ok = false; + m_port = portStr.toInt(&ok); + if (ok && m_port > 0 && m_port < 65535) { + scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory> factory(new TCPServerSocketFactory(m_bindAddress.toStdString(), m_port, 1)); + m_devtoolsHttpHandler = DevToolsHttpHandler::Start(factory.Pass(), std::string(), this, base::FilePath()); + } else + qWarning("Invalid port given for the inspector server \"%s\". Examples of valid input: \"12345\" or \"192.168.2.14:12345\" (with the address of one of this host's network interface).", qPrintable(portStr)); } DevToolsHttpHandlerDelegateQt::~DevToolsHttpHandlerDelegateQt() { - m_devtoolsHttpHandler->Stop(); + // Stop() takes care of deleting the DevToolsHttpHandler. + if (m_devtoolsHttpHandler) + m_devtoolsHttpHandler->Stop(); +} + +void DevToolsHttpHandlerDelegateQt::Initialized(const net::IPEndPoint& ip_address) +{ + if (ip_address.address().size()) { + QString addressAndPort = QString::fromStdString(ip_address.ToString()); + qWarning("Remote debugging server started successfully. Try pointing a Chromium-based browser to http://%s", qPrintable(addressAndPort)); + } else + qWarning("Couldn't start the inspector server on bind address \"%s\" and port \"%d\". In case of invalid input, try something like: \"12345\" or \"192.168.2.14:12345\" (with the address of one of this host's interface).", qPrintable(m_bindAddress), m_port); } std::string DevToolsHttpHandlerDelegateQt::GetDiscoveryPageHTML() @@ -95,22 +211,30 @@ base::FilePath DevToolsHttpHandlerDelegateQt::GetDebugFrontendDir() return base::FilePath(); } -std::string DevToolsHttpHandlerDelegateQt::GetPageThumbnailData(const GURL& url) +scoped_ptr<net::StreamListenSocket> DevToolsHttpHandlerDelegateQt::CreateSocketForTethering(net::StreamListenSocket::Delegate* delegate, std::string* name) { - return std::string(); + return scoped_ptr<net::StreamListenSocket>(); +} + +base::DictionaryValue* DevToolsManagerDelegateQt::HandleCommand(DevToolsAgentHost *, base::DictionaryValue *) { + return 0; } -scoped_ptr<DevToolsTarget> DevToolsHttpHandlerDelegateQt::CreateNewTarget(const GURL&) +std::string DevToolsManagerDelegateQt::GetPageThumbnailData(const GURL& url) { - return scoped_ptr<DevToolsTarget>(); + return std::string(); } -void DevToolsHttpHandlerDelegateQt::EnumerateTargets(TargetCallback callback) +scoped_ptr<DevToolsTarget> DevToolsManagerDelegateQt::CreateNewTarget(const GURL &) { - callback.Run(TargetList()); + return scoped_ptr<DevToolsTarget>(); } -scoped_ptr<net::StreamListenSocket> DevToolsHttpHandlerDelegateQt::CreateSocketForTethering(net::StreamListenSocket::Delegate* delegate, std::string* name) +void DevToolsManagerDelegateQt::EnumerateTargets(TargetCallback callback) { - return scoped_ptr<net::StreamListenSocket>(); + TargetList targets; + for (const auto& agent_host : DevToolsAgentHost::GetOrCreateAll()) { + targets.push_back(new Target(agent_host)); + } + callback.Run(targets); } diff --git a/src/core/dev_tools_http_handler_delegate_qt.h b/src/core/dev_tools_http_handler_delegate_qt.h index 06b690ae9..8a8a658a6 100644 --- a/src/core/dev_tools_http_handler_delegate_qt.h +++ b/src/core/dev_tools_http_handler_delegate_qt.h @@ -38,7 +38,9 @@ #define DEV_TOOLS_HTTP_HANDLER_DELEGATE_QT_H #include "content/public/browser/devtools_http_handler_delegate.h" +#include "content/public/browser/devtools_manager_delegate.h" +#include <QString> #include <QtCore/qcompilerdetection.h> // needed for Q_DECL_OVERRIDE namespace net { @@ -54,23 +56,32 @@ class RenderViewHost; class DevToolsHttpHandlerDelegateQt : public content::DevToolsHttpHandlerDelegate { public: - explicit DevToolsHttpHandlerDelegateQt(content::BrowserContext* browser_context); + DevToolsHttpHandlerDelegateQt(); virtual ~DevToolsHttpHandlerDelegateQt(); // content::DevToolsHttpHandlerDelegate Overrides + virtual void Initialized(const net::IPEndPoint &ip_address) Q_DECL_OVERRIDE; virtual std::string GetDiscoveryPageHTML() Q_DECL_OVERRIDE; virtual bool BundlesFrontendResources() Q_DECL_OVERRIDE; virtual base::FilePath GetDebugFrontendDir() Q_DECL_OVERRIDE; - virtual std::string GetPageThumbnailData(const GURL& url) Q_DECL_OVERRIDE; - virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(const GURL&) Q_DECL_OVERRIDE; // Requests the list of all inspectable targets. // The caller gets the ownership of the returned targets. - virtual void EnumerateTargets(TargetCallback callback) Q_DECL_OVERRIDE; - virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(net::StreamListenSocket::Delegate* delegate, std::string* name) Q_DECL_OVERRIDE; + virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(net::StreamListenSocket::Delegate *delegate, std::string *name) Q_DECL_OVERRIDE; private: - content::BrowserContext* m_browserContext; - content::DevToolsHttpHandler* m_devtoolsHttpHandler; + content::DevToolsHttpHandler *m_devtoolsHttpHandler; + QString m_bindAddress; + int m_port; +}; + +class DevToolsManagerDelegateQt : public content::DevToolsManagerDelegate { +public: + void Inspect(content::BrowserContext *browser_context, content::DevToolsAgentHost *agent_host) Q_DECL_OVERRIDE { } + void DevToolsAgentStateChanged(content::DevToolsAgentHost *agent_host, bool attached) Q_DECL_OVERRIDE { } + base::DictionaryValue *HandleCommand(content::DevToolsAgentHost *agent_host, base::DictionaryValue *command) Q_DECL_OVERRIDE; + scoped_ptr<content::DevToolsTarget> CreateNewTarget(const GURL &url) Q_DECL_OVERRIDE; + void EnumerateTargets(TargetCallback callback) Q_DECL_OVERRIDE; + std::string GetPageThumbnailData(const GURL &url) Q_DECL_OVERRIDE; }; #endif // DEV_TOOLS_HTTP_HANDLER_DELEGATE_QT_H diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index 3df03ffa3..3ef8cc9af 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -36,6 +36,7 @@ #include "download_manager_delegate_qt.h" +#include "content/public/browser/download_manager.h" #include "content/public/browser/download_item.h" #include "content/public/browser/save_page_type.h" #include "content/public/browser/web_contents.h" @@ -46,115 +47,26 @@ #include <QMap> #include <QStandardPaths> +#include "browser_context_adapter.h" +#include "browser_context_adapter_client.h" +#include "browser_context_qt.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" -// Helper class to track currently ongoing downloads to prevent file name -// clashes / overwriting of files. -class DownloadTargetHelper : public content::DownloadItem::Observer { -public: - DownloadTargetHelper() - : m_defaultDownloadDirectory(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) - { +ASSERT_ENUMS_MATCH(content::DownloadItem::IN_PROGRESS, BrowserContextAdapterClient::DownloadInProgress) +ASSERT_ENUMS_MATCH(content::DownloadItem::COMPLETE, BrowserContextAdapterClient::DownloadCompleted) +ASSERT_ENUMS_MATCH(content::DownloadItem::CANCELLED, BrowserContextAdapterClient::DownloadCancelled) +ASSERT_ENUMS_MATCH(content::DownloadItem::INTERRUPTED, BrowserContextAdapterClient::DownloadInterrupted) - } - virtual ~DownloadTargetHelper() {} - - bool determineDownloadTarget(content::DownloadItem *item, const content::DownloadTargetCallback &callback); - - virtual void OnDownloadUpdated(content::DownloadItem *download) Q_DECL_OVERRIDE; - virtual void OnDownloadDestroyed(content::DownloadItem *download) Q_DECL_OVERRIDE; -private: - bool isPathAvailable(const QString& path); - - QDir m_defaultDownloadDirectory; - QMap<content::DownloadItem*, QString> m_ongoingDownloads; -}; - -bool DownloadTargetHelper::isPathAvailable(const QString& path) -{ - return !m_ongoingDownloads.values().contains(path) && !QFile::exists(path); -} - -bool DownloadTargetHelper::determineDownloadTarget(content::DownloadItem *item, const content::DownloadTargetCallback &callback) -{ - std::string suggestedFilename = item->GetSuggestedFilename(); - - if (suggestedFilename.empty()) - suggestedFilename = item->GetTargetFilePath().AsUTF8Unsafe(); - - if (suggestedFilename.empty()) - suggestedFilename = item->GetURL().ExtractFileName(); - - if (suggestedFilename.empty()) - suggestedFilename = "qwe_download"; - - if (!m_defaultDownloadDirectory.exists() && !m_defaultDownloadDirectory.mkpath(m_defaultDownloadDirectory.absolutePath())) - return false; - - QString suggestedFilePath = m_defaultDownloadDirectory.absoluteFilePath(QString::fromStdString(suggestedFilename)); - if (!isPathAvailable(suggestedFilePath)) { - int i = 1; - for (; i < 99; i++) { - QFileInfo tmpFile(suggestedFilePath); - QString tmpFilePath = QString("%1%2%3(%4).%5").arg(tmpFile.absolutePath()).arg(QDir::separator()).arg(tmpFile.baseName()).arg(i).arg(tmpFile.completeSuffix()); - if (isPathAvailable(tmpFilePath)) { - suggestedFilePath = tmpFilePath; - break; - } - } - if (i >= 99) { - callback.Run(base::FilePath(), content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, base::FilePath()); - return false; - } - } - - m_ongoingDownloads.insert(item, suggestedFilePath); - item->AddObserver(this); - - base::FilePath filePathForCallback(toFilePathString(suggestedFilePath)); - callback.Run(filePathForCallback, content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, - content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, filePathForCallback.AddExtension(toFilePathString("download"))); - return true; -} - -void DownloadTargetHelper::OnDownloadUpdated(content::DownloadItem *download) -{ - switch (download->GetState()) { - case content::DownloadItem::COMPLETE: - case content::DownloadItem::CANCELLED: - case content::DownloadItem::INTERRUPTED: - download->RemoveObserver(this); - m_ongoingDownloads.remove(download); - break; - case content::DownloadItem::IN_PROGRESS: - default: - break; - } -} - -void DownloadTargetHelper::OnDownloadDestroyed(content::DownloadItem *download) -{ - download->RemoveObserver(this); - m_ongoingDownloads.remove(download); -} - -DownloadManagerDelegateQt::DownloadManagerDelegateQt() - : m_targetHelper(new DownloadTargetHelper()) +DownloadManagerDelegateQt::DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter) + : m_contextAdapter(contextAdapter) , m_currentId(0) { - + Q_ASSERT(m_contextAdapter); } DownloadManagerDelegateQt::~DownloadManagerDelegateQt() { - delete m_targetHelper; -} - - -void DownloadManagerDelegateQt::Shutdown() -{ - QT_NOT_YET_IMPLEMENTED } void DownloadManagerDelegateQt::GetNextId(const content::DownloadIdCallback& callback) @@ -162,24 +74,17 @@ void DownloadManagerDelegateQt::GetNextId(const content::DownloadIdCallback& cal callback.Run(++m_currentId); } -bool DownloadManagerDelegateQt::ShouldOpenFileBasedOnExtension(const base::FilePath& path) -{ - QT_NOT_YET_IMPLEMENTED - return false; -} - -bool DownloadManagerDelegateQt::ShouldCompleteDownload(content::DownloadItem* item, - const base::Closure& complete_callback) +void DownloadManagerDelegateQt::cancelDownload(const content::DownloadTargetCallback& callback) { - QT_NOT_YET_IMPLEMENTED - return true; + callback.Run(base::FilePath(), content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, base::FilePath()); } -bool DownloadManagerDelegateQt::ShouldOpenDownload(content::DownloadItem* item, - const content::DownloadOpenDelayedCallback& callback) +void DownloadManagerDelegateQt::cancelDownload(quint32 downloadId) { - QT_NOT_YET_IMPLEMENTED - return false; + content::DownloadManager* dlm = content::BrowserContext::GetDownloadManager(m_contextAdapter->browserContext()); + content::DownloadItem *download = dlm->GetDownload(downloadId); + if (download) + download->Cancel(/* user_cancel */ true); } bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* item, @@ -194,41 +99,63 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* i return true; } - // Let the target helper determine the download target path. - return m_targetHelper->determineDownloadTarget(item, callback); -} + std::string suggestedFilename = item->GetSuggestedFilename(); -bool DownloadManagerDelegateQt::GenerateFileHash() -{ - QT_NOT_YET_IMPLEMENTED - return false; -} + if (suggestedFilename.empty()) + suggestedFilename = item->GetTargetFilePath().AsUTF8Unsafe(); -void DownloadManagerDelegateQt::ChooseSavePath( - content::WebContents* web_contents, - const base::FilePath& suggested_path, - const base::FilePath::StringType& default_extension, - bool can_save_as_complete, - const content::SavePackagePathPickedCallback& callback) -{ - QT_NOT_YET_IMPLEMENTED -} + if (suggestedFilename.empty()) + suggestedFilename = item->GetURL().ExtractFileName(); -void DownloadManagerDelegateQt::OpenDownload(content::DownloadItem* download) -{ - QT_NOT_YET_IMPLEMENTED -} + if (suggestedFilename.empty()) + suggestedFilename = "qwe_download"; -void DownloadManagerDelegateQt::ShowDownloadInShell(content::DownloadItem* download) -{ - QT_NOT_YET_IMPLEMENTED -} + QDir defaultDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); -void DownloadManagerDelegateQt::CheckForFileExistence( - content::DownloadItem* download, - const content::CheckForFileExistenceCallback& callback) -{ - QT_NOT_YET_IMPLEMENTED + QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(QString::fromStdString(suggestedFilename))); + QString suggestedFilePath = suggestedFile.absoluteFilePath(); + QString tmpFileBase = QString("%1%2%3").arg(suggestedFile.absolutePath()).arg(QDir::separator()).arg(suggestedFile.baseName()); + + for (int i = 1; QFileInfo::exists(suggestedFilePath); ++i) { + suggestedFilePath = QString("%1(%2).%3").arg(tmpFileBase).arg(i).arg(suggestedFile.completeSuffix()); + if (i >= 99) { + suggestedFilePath = suggestedFile.absoluteFilePath(); + break; + } + } + + item->AddObserver(this); + if (m_contextAdapter->client()) { + BrowserContextAdapterClient::DownloadItemInfo info = { + item->GetId(), + toQt(item->GetURL()), + item->GetState(), + item->GetTotalBytes(), + item->GetReceivedBytes(), + suggestedFilePath, + false /* accepted */ + }; + m_contextAdapter->client()->downloadRequested(info); + + suggestedFile.setFile(info.path); + + if (info.accepted && !suggestedFile.absoluteDir().mkpath(suggestedFile.absolutePath())) { + qWarning("Creating download path failed, download cancelled: %s", suggestedFile.absolutePath().toUtf8().data()); + info.accepted = false; + } + + if (!info.accepted) { + cancelDownload(callback); + return true; + } + + base::FilePath filePathForCallback(toFilePathString(suggestedFile.absoluteFilePath())); + callback.Run(filePathForCallback, content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, + content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, filePathForCallback.AddExtension(toFilePathString("download"))); + } else + cancelDownload(callback); + + return true; } void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_context, @@ -242,4 +169,24 @@ void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_cont *skip_dir_check = true; } +void DownloadManagerDelegateQt::OnDownloadUpdated(content::DownloadItem *download) +{ + if (m_contextAdapter->client()) { + BrowserContextAdapterClient::DownloadItemInfo info = { + download->GetId(), + toQt(download->GetURL()), + download->GetState(), + download->GetTotalBytes(), + download->GetReceivedBytes(), + QString(), + true /* accepted */ + }; + m_contextAdapter->client()->downloadUpdated(info); + } +} +void DownloadManagerDelegateQt::OnDownloadDestroyed(content::DownloadItem *download) +{ + download->RemoveObserver(this); + download->Cancel(/* user_cancel */ false); +} diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index 4c838363f..007f2e580 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -39,7 +39,7 @@ #include "content/public/browser/download_manager_delegate.h" -#include <qglobal.h> +#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE namespace base { class FilePath; @@ -51,46 +51,38 @@ class DownloadItem; class WebContents; } -class DownloadTargetHelper; - -class DownloadManagerDelegateQt : public content::DownloadManagerDelegate +class BrowserContextAdapter; +class DownloadManagerDelegateInstance; +class DownloadManagerDelegateQt + : public content::DownloadManagerDelegate + , public content::DownloadItem::Observer { public: - DownloadManagerDelegateQt(); - virtual ~DownloadManagerDelegateQt(); - - void Shutdown() Q_DECL_OVERRIDE; + DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter); + ~DownloadManagerDelegateQt(); void GetNextId(const content::DownloadIdCallback& callback) Q_DECL_OVERRIDE; - bool ShouldOpenFileBasedOnExtension(const base::FilePath& path) Q_DECL_OVERRIDE; - bool ShouldCompleteDownload(content::DownloadItem* item, - const base::Closure& complete_callback) Q_DECL_OVERRIDE; - - bool ShouldOpenDownload(content::DownloadItem* item, - const content::DownloadOpenDelayedCallback& callback) Q_DECL_OVERRIDE; bool DetermineDownloadTarget(content::DownloadItem* item, const content::DownloadTargetCallback& callback) Q_DECL_OVERRIDE; - bool GenerateFileHash() Q_DECL_OVERRIDE; - void ChooseSavePath(content::WebContents* web_contents, - const base::FilePath& suggested_path, - const base::FilePath::StringType& default_extension, - bool can_save_as_complete, - const content::SavePackagePathPickedCallback& callback) Q_DECL_OVERRIDE; - - void OpenDownload(content::DownloadItem* download) Q_DECL_OVERRIDE; - void ShowDownloadInShell(content::DownloadItem* download) Q_DECL_OVERRIDE; - void CheckForFileExistence(content::DownloadItem* download, - const content::CheckForFileExistenceCallback& callback) Q_DECL_OVERRIDE; - void GetSaveDir(content::BrowserContext* browser_context, base::FilePath* website_save_dir, base::FilePath* download_save_dir, bool* skip_dir_check) Q_DECL_OVERRIDE; + void cancelDownload(quint32 downloadId); + + // Inherited from content::DownloadItem::Observer + void OnDownloadUpdated(content::DownloadItem *download) Q_DECL_OVERRIDE; + void OnDownloadDestroyed(content::DownloadItem *download) Q_DECL_OVERRIDE; + private: - DownloadTargetHelper* m_targetHelper; + void cancelDownload(const content::DownloadTargetCallback& callback); + BrowserContextAdapter *m_contextAdapter; + uint64 m_currentId; + + friend class DownloadManagerDelegateInstance; DISALLOW_COPY_AND_ASSIGN(DownloadManagerDelegateQt); }; 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/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index a8e964b4d..5d65a3391 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -254,14 +254,20 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content:: return; } - // The extension name that the stream is registered with. - std::string originalExtensionName; - // Resolve DesktopMediaID for the specified device id. - content::DesktopMediaID mediaId = - getDesktopStreamsRegistry()->RequestMediaForStreamId( - request.requested_video_device_id, request.render_process_id, - request.render_view_id, request.security_origin, - &originalExtensionName); + content::WebContents* const web_contents_for_stream = content::WebContents::FromRenderFrameHost( + content::RenderFrameHost::FromID(request.render_process_id, request.render_frame_id)); + content::RenderFrameHost* const main_frame = web_contents_for_stream ? web_contents_for_stream->GetMainFrame() : NULL; + + content::DesktopMediaID mediaId; + if (main_frame) { + // The extension name that the stream is registered with. + std::string originalExtensionName; + // Resolve DesktopMediaID for the specified device id. + mediaId = getDesktopStreamsRegistry()->RequestMediaForStreamId( + request.requested_video_device_id, main_frame->GetProcess()->GetID(), + main_frame->GetRoutingID(), request.security_origin, + &originalExtensionName); + } // Received invalid device id. if (mediaId.type == content::DesktopMediaID::TYPE_NONE) { @@ -391,37 +397,36 @@ DesktopStreamsRegistry *MediaCaptureDevicesDispatcher::getDesktopStreamsRegistry return m_desktopStreamsRegistry.get(); } -void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(int renderProcessId, int renderViewId, int pageRequestId, const GURL& securityOrigin - , const content::MediaStreamDevice &device, content::MediaRequestState state) +void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(int render_process_id, int render_frame_id, int page_request_id, const GURL& security_origin, content::MediaStreamType stream_type, content::MediaRequestState state) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind( &MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread, - base::Unretained(this), renderProcessId, renderViewId, - pageRequestId, device, state)); + base::Unretained(this), render_process_id, render_frame_id, + page_request_id, security_origin, stream_type, state)); } -void MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread(int renderProcessId, int renderViewId, int pageRequestId - , const content::MediaStreamDevice &device, content::MediaRequestState state) +void MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread(int render_process_id, int render_frame_id, int page_request_id + , const GURL& security_origin, content::MediaStreamType stream_type, content::MediaRequestState state) { // Track desktop capture sessions. Tracking is necessary to avoid unbalanced // session counts since not all requests will reach MEDIA_REQUEST_STATE_DONE, // but they will all reach MEDIA_REQUEST_STATE_CLOSING. - if (device.type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) { + if (stream_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) { if (state == content::MEDIA_REQUEST_STATE_DONE) { - DesktopCaptureSession session = { renderProcessId, renderViewId, - pageRequestId }; + DesktopCaptureSession session = { render_process_id, render_frame_id, + page_request_id }; m_desktopCaptureSessions.push_back(session); } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) { for (DesktopCaptureSessions::iterator it = m_desktopCaptureSessions.begin(); it != m_desktopCaptureSessions.end(); ++it) { - if (it->render_process_id == renderProcessId && - it->render_view_id == renderViewId && - it->page_request_id == pageRequestId) { + if (it->render_process_id == render_process_id && + it->render_view_id == render_frame_id && + it->page_request_id == page_request_id) { m_desktopCaptureSessions.erase(it); break; } @@ -437,9 +442,9 @@ void MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread(int render RequestsQueue &queue = rqs_it->second; for (RequestsQueue::iterator it = queue.begin(); it != queue.end(); ++it) { - if (it->request.render_process_id == renderProcessId && - it->request.render_view_id == renderViewId && - it->request.page_request_id == pageRequestId) { + if (it->request.render_process_id == render_process_id && + it->request.render_frame_id == render_frame_id && + it->request.page_request_id == page_request_id) { queue.erase(it); found = true; break; diff --git a/src/core/media_capture_devices_dispatcher.h b/src/core/media_capture_devices_dispatcher.h index 2c2988857..e0d6cff1d 100644 --- a/src/core/media_capture_devices_dispatcher.h +++ b/src/core/media_capture_devices_dispatcher.h @@ -75,12 +75,9 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver, // Overridden from content::MediaObserver: virtual void OnAudioCaptureDevicesChanged() Q_DECL_OVERRIDE { } virtual void OnVideoCaptureDevicesChanged() Q_DECL_OVERRIDE { } - virtual void OnMediaRequestStateChanged(int renderProcessId, int renderViewId, int pageRequestId, const GURL &securityOrigin, const content::MediaStreamDevice &device - , content::MediaRequestState state) Q_DECL_OVERRIDE; + virtual void OnMediaRequestStateChanged(int render_process_id, int render_frame_id, int page_request_id, const GURL& security_origin, content::MediaStreamType stream_type, content::MediaRequestState state) Q_DECL_OVERRIDE; virtual void OnCreatingAudioStream(int /*render_process_id*/, int /*render_frame_id*/) Q_DECL_OVERRIDE { } - virtual void OnAudioStreamPlaying(int /*render_process_id*/, int /*render_frame_id*/, int /*stream_id*/, const ReadPowerAndClipCallback& /*power_read_callback*/) Q_DECL_OVERRIDE { } - virtual void OnAudioStreamStopped(int /*render_process_id*/, int /*render_frame_id*/, int /*stream_id*/) Q_DECL_OVERRIDE { } DesktopStreamsRegistry *getDesktopStreamsRegistry(); @@ -112,8 +109,7 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver, void ProcessQueuedAccessRequest(content::WebContents *); // Called by the MediaObserver() functions, executed on UI thread. - void updateMediaRequestStateOnUIThread(int renderProcessId, int renderViewId, int pageRequestId, const content::MediaStreamDevice & - , content::MediaRequestState); + void updateMediaRequestStateOnUIThread(int render_process_id, int render_frame_id, int page_request_id, const GURL& security_origin, content::MediaStreamType stream_type, content::MediaRequestState state); RequestsQueues m_pendingRequests; diff --git a/src/core/native_web_keyboard_event_qt.cpp b/src/core/native_web_keyboard_event_qt.cpp new file mode 100644 index 000000000..072b4dd9d --- /dev/null +++ b/src/core/native_web_keyboard_event_qt.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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$ +** +****************************************************************************/ + +// Copyright (c) 2011 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 "content/public/browser/native_web_keyboard_event.h" +#include <QKeyEvent> + +namespace { + +// We need to copy |os_event| in NativeWebKeyboardEvent because it is +// queued in RenderWidgetHost and may be passed and used +// RenderViewHostDelegate::HandledKeybardEvent after the original aura +// event is destroyed. +gfx::NativeEvent CopyEvent(gfx::NativeEvent event) +{ + return event ? reinterpret_cast<gfx::NativeEvent>(new QKeyEvent(*reinterpret_cast<QKeyEvent*>(event))) : 0; +} + +void DestroyEvent(gfx::NativeEvent event) +{ + delete reinterpret_cast<QKeyEvent*>(event); +} + +} // namespace + +using blink::WebKeyboardEvent; + +namespace content { + +NativeWebKeyboardEvent::NativeWebKeyboardEvent() + : os_event(0), + skip_in_browser(false) +{ +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event) + : os_event(CopyEvent(native_event)), + skip_in_browser(false) +{ +} + +NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& other) + : WebKeyboardEvent(other), + os_event(CopyEvent(other.os_event)), + skip_in_browser(other.skip_in_browser) +{ +} + +NativeWebKeyboardEvent& NativeWebKeyboardEvent::operator=(const NativeWebKeyboardEvent& other) { + WebKeyboardEvent::operator=(other); + DestroyEvent(os_event); + os_event = CopyEvent(other.os_event); + skip_in_browser = other.skip_in_browser; + return *this; +} + +NativeWebKeyboardEvent::~NativeWebKeyboardEvent() { + DestroyEvent(os_event); +} + +} // namespace content diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index f14d2cb39..79af93e06 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -40,7 +40,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_request_details.h" #include "content/public/browser/resource_request_info.h" -#include "content/public/common/page_transition_types.h" +#include "ui/base/page_transition_types.h" #include "net/base/load_flags.h" #include "net/url_request/url_request.h" #include "type_conversion.h" @@ -49,23 +49,23 @@ namespace { -int pageTransitionToNavigationType(content::PageTransition transition) +int pageTransitionToNavigationType(ui::PageTransition transition) { - int32 qualifier = content::PageTransitionGetQualifier(transition); + int32 qualifier = ui::PageTransitionGetQualifier(transition); - if (qualifier & content::PAGE_TRANSITION_FORWARD_BACK) + if (qualifier & ui::PAGE_TRANSITION_FORWARD_BACK) return WebContentsAdapterClient::BackForwardNavigation; - content::PageTransition stippedTransition = content::PageTransitionStripQualifier(transition); + ui::PageTransition stippedTransition = ui::PageTransitionStripQualifier(transition); switch (stippedTransition) { - case content::PAGE_TRANSITION_LINK: + case ui::PAGE_TRANSITION_LINK: return WebContentsAdapterClient::LinkClickedNavigation; - case content::PAGE_TRANSITION_TYPED: + case ui::PAGE_TRANSITION_TYPED: return WebContentsAdapterClient::TypedNavigation; - case content::PAGE_TRANSITION_FORM_SUBMIT: + case ui::PAGE_TRANSITION_FORM_SUBMIT: return WebContentsAdapterClient::FormSubmittedNavigation; - case content::PAGE_TRANSITION_RELOAD: + case ui::PAGE_TRANSITION_RELOAD: return WebContentsAdapterClient::ReloadNavigation; default: return WebContentsAdapterClient::OtherNavigation; @@ -78,15 +78,14 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request); + if (!info) + return net::OK; + + content::ResourceType resourceType = info->GetResourceType(); int renderProcessId; int renderFrameId; - if (!info || !info->GetRenderFrameForRequest(request, &renderProcessId, &renderFrameId)) - // Abort the request if it has no associated render info / render view. - return net::ERR_ABORTED; - - ResourceType::Type resourceType = info->GetResourceType(); - // Only intercept MAIN_FRAME and SUB_FRAME. - if (!ResourceType::IsFrame(resourceType)) + // Only intercept MAIN_FRAME and SUB_FRAME with an associated render frame. + if (!content::IsResourceTypeFrame(resourceType) || !info->GetRenderFrameForRequest(request, &renderProcessId, &renderFrameId)) return net::OK; // Track active requests since |callback| and |new_url| are valid @@ -97,7 +96,7 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C RequestParams params = { toQt(request->url()), - resourceType == ResourceType::MAIN_FRAME, + info->IsMainFrame(), navigationType, renderProcessId, renderFrameId diff --git a/src/core/ozone_platform_eglfs.cpp b/src/core/ozone_platform_eglfs.cpp index b6b367aeb..8f1d9870f 100644 --- a/src/core/ozone_platform_eglfs.cpp +++ b/src/core/ozone_platform_eglfs.cpp @@ -36,6 +36,8 @@ #include "ozone_platform_eglfs.h" +#if defined(USE_OZONE) + #include "media/ozone/media_ozone_platform.h" #include "ui/events/ozone/device/device_manager.h" #include "ui/ozone/ozone_platform.h" @@ -43,7 +45,6 @@ #include "ui/ozone/public/gpu_platform_support.h" #include "ui/ozone/public/gpu_platform_support_host.h" -#if defined(USE_OZONE) namespace media { diff --git a/src/core/ozone_platform_eglfs.h b/src/core/ozone_platform_eglfs.h index 9d96688a5..a976d1c63 100644 --- a/src/core/ozone_platform_eglfs.h +++ b/src/core/ozone_platform_eglfs.h @@ -37,13 +37,13 @@ #ifndef UI_OZONE_PLATFORM_EGLFS_OZONE_PLATFORM_EGLFS_H_ #define UI_OZONE_PLATFORM_EGLFS_OZONE_PLATFORM_EGLFS_H_ +#if defined(USE_OZONE) + #include "ui/events/ozone/evdev/event_factory_evdev.h" #include "ui/ozone/ozone_platform.h" #include "surface_factory_qt.h" -#if defined(USE_OZONE) - namespace ui { class OzonePlatformEglfs : public OzonePlatform { diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index 17287669f..79eb6d45b 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -8,6 +8,7 @@ 'dependencies': [ '<(chromium_src_dir)/base/base.gyp:base', '<(chromium_src_dir)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '<(chromium_src_dir)/components/components.gyp:error_page_renderer', '<(chromium_src_dir)/components/components.gyp:visitedlink_browser', '<(chromium_src_dir)/components/components.gyp:visitedlink_renderer', '<(chromium_src_dir)/content/content.gyp:content', @@ -17,8 +18,7 @@ '<(chromium_src_dir)/content/content.gyp:content_gpu', '<(chromium_src_dir)/content/content.gyp:content_renderer', '<(chromium_src_dir)/content/content.gyp:content_utility', - '<(chromium_src_dir)/content/content.gyp:content_worker', - '<(chromium_src_dir)/content/content_resources.gyp:content_resources', + '<(chromium_src_dir)/content/app/resources/content_resources.gyp:content_resources', '<(chromium_src_dir)/ipc/ipc.gyp:ipc', '<(chromium_src_dir)/media/media.gyp:media', '<(chromium_src_dir)/net/net.gyp:net', @@ -102,7 +102,7 @@ }, }, # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - 'msvs_disabled_warnings': [ 4267, ], + 'msvs_disabled_warnings': [ 4267, 4996, ], }], # OS=="win" ['OS=="linux"', { 'dependencies': [ diff --git a/src/core/qtwebengine_extras.gypi b/src/core/qtwebengine_extras.gypi index f30c16401..b0e9bc697 100644 --- a/src/core/qtwebengine_extras.gypi +++ b/src/core/qtwebengine_extras.gypi @@ -15,6 +15,7 @@ ['exclude', 'clipboard/clipboard_util_win\\.(cc|h)$'], ['exclude', 'dragdrop/os_exchange_data_provider_aurax11\\.(cc|h)$'], ['exclude', 'dragdrop/os_exchange_data_provider_win\\.(cc|h)$'], + ['exclude', 'dragdrop/os_exchange_data_provider_mac\\.(mm|h)$'], ['exclude', 'resource/resource_bundle_android.cc$'], ['exclude', 'resource/resource_bundle_auralinux.cc$'], ['exclude', 'resource/resource_bundle_gtk.cc$'], @@ -26,6 +27,9 @@ ['exclude', 'browser/web_contents/web_contents_view_mac\\.(mm|h)$'], ['exclude', 'browser/web_contents/web_contents_view_win\\.(cc|h)$'], ['exclude', 'browser/renderer_host/gtk_im_context_wrapper\\.cc$'], + ['exclude', 'browser/renderer_host/native_web_keyboard_event_android.cc$'], + ['exclude', 'browser/renderer_host/native_web_keyboard_event_aura.cc$'], + ['exclude', 'browser/renderer_host/native_web_keyboard_event_mac.mm$'], ['exclude', 'browser/renderer_host/pepper/pepper_truetype_font_list_pango\\.cc$'], ['exclude', 'browser/renderer_host/render_widget_host_view_android\\.(cc|h)$'], ['exclude', 'browser/renderer_host/render_widget_host_view_aura\\.(cc|h)$'], diff --git a/src/core/qtwebenginecoreglobal.h b/src/core/qtwebenginecoreglobal.h index 9a222f43f..541406f87 100644 --- a/src/core/qtwebenginecoreglobal.h +++ b/src/core/qtwebenginecoreglobal.h @@ -57,4 +57,6 @@ # define QWEBENGINE_EXPORT #endif +#define ASSERT_ENUMS_MATCH(A, B) Q_STATIC_ASSERT_X(static_cast<int>(A) == static_cast<int>(B), "The enum values must match"); + #endif // QTWEBENGINECOREGLOBAL_H diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index c221e94e3..3741d8876 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -52,8 +52,6 @@ #include "content/browser/renderer_host/input/web_input_event_util.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/cursors/webcursor.h" -#include "content/common/gpu/gpu_messages.h" -#include "content/common/view_messages.h" #include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" @@ -62,7 +60,8 @@ #include "third_party/WebKit/public/platform/WebCursorInfo.h" #include "third_party/WebKit/public/web/WebCompositionUnderline.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" -#include "ui/events/gesture_detection/gesture_config_helper.h" +#include "ui/events/event.h" +#include "ui/events/gesture_detection/gesture_provider_config_helper.h" #include "ui/events/gesture_detection/motion_event.h" #include "ui/gfx/size_conversions.h" @@ -80,6 +79,22 @@ #include <QWindow> #include <QtGui/qaccessible.h> +static inline ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) { + ui::LatencyInfo latency_info; + // The latency number should only be added if the timestamp is valid. + if (event.timeStampSeconds) { + const int64 time_micros = static_cast<int64>( + event.timeStampSeconds * base::Time::kMicrosecondsPerSecond); + latency_info.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, + 0, + 0, + base::TimeTicks() + base::TimeDelta::FromMicroseconds(time_micros), + 1); + } + return latency_info; +} + static inline Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType) { switch (inputType) { @@ -128,8 +143,6 @@ static inline ui::GestureProvider::Config QtGestureProviderConfig() { ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig(); // Causes an assert in CreateWebGestureEventFromGestureEventData and we don't need them in Qt. config.gesture_begin_end_types_enabled = false; - // Swipe gestures aren't forwarded, we don't use them and they abort the gesture detection. - config.scale_gesture_detector_config.gesture_detector_config.swipe_enabled = config.gesture_detector_config.swipe_enabled = false; return config; } @@ -139,12 +152,37 @@ static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, const return lhs.state() < rhs.state(); } +static inline int flagsFromModifiers(Qt::KeyboardModifiers modifiers) +{ + int modifierFlags = ui::EF_NONE; +#if defined(Q_OS_OSX) + if (!qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + if ((modifiers & Qt::ControlModifier) != 0) + modifierFlags |= ui::EF_COMMAND_DOWN; + if ((modifiers & Qt::MetaModifier) != 0) + modifierFlags |= ui::EF_CONTROL_DOWN; + } else +#endif + { + if ((modifiers & Qt::ControlModifier) != 0) + modifierFlags |= ui::EF_CONTROL_DOWN; + if ((modifiers & Qt::MetaModifier) != 0) + modifierFlags |= ui::EF_COMMAND_DOWN; + } + if ((modifiers & Qt::ShiftModifier) != 0) + modifierFlags |= ui::EF_SHIFT_DOWN; + if ((modifiers & Qt::AltModifier) != 0) + modifierFlags |= ui::EF_ALT_DOWN; + return modifierFlags; +} + class MotionEventQt : public ui::MotionEvent { public: - MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, int index = -1) + MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, int index = -1) : touchPoints(touchPoints) , eventTime(eventTime) , action(action) + , flags(flagsFromModifiers(modifiers)) , index(index) { // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 @@ -160,7 +198,21 @@ public: virtual float GetY(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).pos().y(); } virtual float GetRawX(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).screenPos().x(); } virtual float GetRawY(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).screenPos().y(); } - virtual float GetTouchMajor(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).rect().height(); } + virtual float GetTouchMajor(size_t pointer_index) const Q_DECL_OVERRIDE + { + QRectF touchRect = touchPoints.at(pointer_index).rect(); + return std::max(touchRect.height(), touchRect.width()); + } + virtual float GetTouchMinor(size_t pointer_index) const Q_DECL_OVERRIDE + { + QRectF touchRect = touchPoints.at(pointer_index).rect(); + return std::min(touchRect.height(), touchRect.width()); + } + virtual float GetOrientation(size_t pointer_index) const Q_DECL_OVERRIDE + { + return 0; + } + virtual int GetFlags() const Q_DECL_OVERRIDE { return flags; } virtual float GetPressure(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).pressure(); } virtual base::TimeTicks GetEventTime() const Q_DECL_OVERRIDE { return eventTime; } @@ -172,16 +224,11 @@ public: virtual ToolType GetToolType(size_t pointer_index) const Q_DECL_OVERRIDE { return ui::MotionEvent::TOOL_TYPE_UNKNOWN; } virtual int GetButtonState() const Q_DECL_OVERRIDE { return 0; } - virtual scoped_ptr<MotionEvent> Cancel() const Q_DECL_OVERRIDE { Q_UNREACHABLE(); return scoped_ptr<MotionEvent>(); } - - virtual scoped_ptr<MotionEvent> Clone() const Q_DECL_OVERRIDE { - return scoped_ptr<MotionEvent>(new MotionEventQt(*this)); - } - private: QList<QTouchEvent::TouchPoint> touchPoints; base::TimeTicks eventTime; Action action; + int flags; int index; }; @@ -189,7 +236,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) @@ -198,15 +245,18 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget , m_initPending(false) { m_host->SetView(this); - +#ifndef QT_NO_ACCESSIBILITY QAccessible::installActivationObserver(this); if (QAccessible::isActive()) content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); +#endif // QT_NO_ACCESSIBILITY } RenderWidgetHostViewQt::~RenderWidgetHostViewQt() { +#ifndef QT_NO_ACCESSIBILITY QAccessible::removeActivationObserver(this); +#endif // QT_NO_ACCESSIBILITY } void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegate) @@ -263,6 +313,10 @@ void RenderWidgetHostViewQt::SetBounds(const gfx::Rect& screenRect) SetSize(screenRect.size()); } +gfx::Vector2dF RenderWidgetHostViewQt::GetLastScrollOffset() const { + return m_lastScrollOffset; +} + gfx::Size RenderWidgetHostViewQt::GetPhysicalBackingSize() const { if (!m_delegate || !m_delegate->window() || !m_delegate->window()->screen()) @@ -294,15 +348,16 @@ gfx::NativeViewAccessible RenderWidgetHostViewQt::GetNativeViewAccessible() return 0; } -void RenderWidgetHostViewQt::CreateBrowserAccessibilityManagerIfNeeded() +content::BrowserAccessibilityManager* RenderWidgetHostViewQt::CreateBrowserAccessibilityManager(content::BrowserAccessibilityDelegate* delegate) { - if (GetBrowserAccessibilityManager()) - return; - - SetBrowserAccessibilityManager(new content::BrowserAccessibilityManagerQt( +#ifndef QT_NO_ACCESSIBILITY + return new content::BrowserAccessibilityManagerQt( m_adapterClient->accessibilityParentObject(), content::BrowserAccessibilityManagerQt::GetEmptyDocument(), - this)); + delegate); +#else + return 0; +#endif // QT_NO_ACCESSIBILITY } // Set focus to the associated View component. @@ -352,17 +407,24 @@ gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const // Return value indicates whether the mouse is locked successfully or not. bool RenderWidgetHostViewQt::LockMouse() { - QT_NOT_USED - return false; + mouse_locked_ = true; + m_lockedMousePosition = QCursor::pos(); + m_delegate->lockMouse(); + qApp->setOverrideCursor(Qt::BlankCursor); + return true; } + void RenderWidgetHostViewQt::UnlockMouse() { - QT_NOT_USED + mouse_locked_ = false; + m_delegate->unlockMouse(); + qApp->restoreOverrideCursor(); + m_host->LostMouseLock(); } void RenderWidgetHostViewQt::WasShown() { - m_host->WasShown(); + m_host->WasShown(ui::LatencyInfo()); } void RenderWidgetHostViewQt::WasHidden() @@ -483,10 +545,13 @@ void RenderWidgetHostViewQt::SetIsLoading(bool) // We use WebContentsDelegateQt::LoadingStateChanged to notify about loading state. } -void RenderWidgetHostViewQt::TextInputStateChanged(const ViewHostMsg_TextInputState_Params& params) +void RenderWidgetHostViewQt::TextInputTypeChanged(ui::TextInputType type, ui::TextInputMode mode, bool can_compose_inline, int flags) { - m_currentInputType = params.type; - m_delegate->inputMethodStateChanged(static_cast<bool>(params.type)); + Q_UNUSED(mode); + Q_UNUSED(can_compose_inline); + Q_UNUSED(flags); + m_currentInputType = type; + m_delegate->inputMethodStateChanged(static_cast<bool>(type)); } void RenderWidgetHostViewQt::ImeCancelComposition() @@ -531,14 +596,12 @@ void RenderWidgetHostViewQt::SelectionBoundsChanged(const ViewHostMsg_SelectionB m_cursorRect = QRect(caretRect.x(), caretRect.y(), caretRect.width(), caretRect.height()); } -void RenderWidgetHostViewQt::ScrollOffsetChanged() -{ - // Not used. -} - -void RenderWidgetHostViewQt::CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& /* dst_size */, const base::Callback<void(bool, const SkBitmap&)>& callback, const SkBitmap::Config config) +void RenderWidgetHostViewQt::CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& dst_size, content::CopyFromCompositingSurfaceCallback& callback, const SkColorType color_type) { NOTIMPLEMENTED(); + Q_UNUSED(src_subrect); + Q_UNUSED(dst_size); + Q_UNUSED(color_type); callback.Run(false, SkBitmap()); } @@ -553,36 +616,6 @@ bool RenderWidgetHostViewQt::CanCopyToVideoFrame() const return false; } -void RenderWidgetHostViewQt::AcceleratedSurfaceInitialized(int host_id, int route_id) -{ -} - -void RenderWidgetHostViewQt::AcceleratedSurfaceBuffersSwapped(const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, int gpu_host_id) -{ - AcceleratedSurfaceMsg_BufferPresented_Params ack_params; - ack_params.sync_point = 0; - content::RenderWidgetHostImpl::AcknowledgeBufferPresent(params.route_id, gpu_host_id, ack_params); - content::RenderWidgetHostImpl::CompositorFrameDrawn(params.latency_info); -} - -void RenderWidgetHostViewQt::AcceleratedSurfacePostSubBuffer(const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, int gpu_host_id) -{ - AcceleratedSurfaceMsg_BufferPresented_Params ack_params; - ack_params.sync_point = 0; - content::RenderWidgetHostImpl::AcknowledgeBufferPresent(params.route_id, gpu_host_id, ack_params); - content::RenderWidgetHostImpl::CompositorFrameDrawn(params.latency_info); -} - -void RenderWidgetHostViewQt::AcceleratedSurfaceSuspend() -{ - QT_NOT_YET_IMPLEMENTED -} - -void RenderWidgetHostViewQt::AcceleratedSurfaceRelease() -{ - QT_NOT_YET_IMPLEMENTED -} - bool RenderWidgetHostViewQt::HasAcceleratedSurface(const gfx::Size&) { return false; @@ -590,18 +623,19 @@ bool RenderWidgetHostViewQt::HasAcceleratedSurface(const gfx::Size&) void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) { + m_lastScrollOffset = frame->metadata.root_scroll_offset; Q_ASSERT(!m_needsDelegatedFrameAck); 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(); @@ -633,7 +667,7 @@ gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow() gfx::GLSurfaceHandle RenderWidgetHostViewQt::GetCompositingSurface() { - return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT); + return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT); } void RenderWidgetHostViewQt::SelectionChanged(const base::string16 &text, size_t offset, const gfx::Range &range) @@ -643,9 +677,7 @@ void RenderWidgetHostViewQt::SelectionChanged(const base::string16 &text, size_t #if defined(USE_X11) // Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard. - ui::ScopedClipboardWriter clipboard_writer( - ui::Clipboard::GetForCurrentThread(), - ui::CLIPBOARD_TYPE_SELECTION); + ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_SELECTION); clipboard_writer.WriteText(text); #endif } @@ -661,7 +693,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. @@ -785,8 +817,8 @@ void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEve m_gestureProvider.OnTouchEventAck(eventConsumed); return; } - - m_host->ForwardTouchEvent(content::CreateWebTouchEventFromMotionEvent(motionEvent)); + blink::WebTouchEvent touchEvent = content::CreateWebTouchEventFromMotionEvent(motionEvent); + m_host->ForwardTouchEventWithLatencyInfo(touchEvent, CreateLatencyInfo(touchEvent)); } QList<QTouchEvent::TouchPoint> RenderWidgetHostViewQt::mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints) @@ -833,16 +865,32 @@ void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event) m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint(); } + if (IsMouseLocked()) { + webEvent.movementX = -(m_lockedMousePosition.x() - event->globalX()); + webEvent.movementY = -(m_lockedMousePosition.y() - event->globalY()); + QCursor::setPos(m_lockedMousePosition); + } + m_host->ForwardMouseEvent(webEvent); } void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) { + if (IsMouseLocked() && ev->key() == Qt::Key_Escape && ev->type() == QEvent::KeyRelease) + UnlockMouse(); + content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); - m_host->ForwardKeyboardEvent(webEvent); if (webEvent.type == blink::WebInputEvent::RawKeyDown && !ev->text().isEmpty()) { + // Blink won't consume the RawKeyDown, but rather the Char event in this case. + // Make sure to skip the former on the way back. The same os_event will be set on both of them. + webEvent.skip_in_browser = true; + m_host->ForwardKeyboardEvent(webEvent); + + webEvent.skip_in_browser = false; webEvent.type = blink::WebInputEvent::Char; m_host->ForwardKeyboardEvent(webEvent); + } else { + m_host->ForwardKeyboardEvent(webEvent); } } @@ -871,10 +919,12 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) QTextCharFormat textCharFormat = attribute.value.value<QTextFormat>().toCharFormat(); QColor qcolor = textCharFormat.underlineColor(); + QColor qBackgroundColor = textCharFormat.background().color(); blink::WebColor color = SkColorSetARGB(qcolor.alpha(), qcolor.red(), qcolor.green(), qcolor.blue()); + blink::WebColor backgroundColor = SkColorSetARGB(qBackgroundColor.alpha(), qBackgroundColor.red(), qBackgroundColor.green(), qBackgroundColor.blue()); int start = qMin(attribute.start, (attribute.start + attribute.length)); int end = qMax(attribute.start, (attribute.start + attribute.length)); - underlines.push_back(blink::WebCompositionUnderline(start, end, color, false)); + underlines.push_back(blink::WebCompositionUnderline(start, end, color, false, backgroundColor)); break; } case QInputMethodEvent::Cursor: @@ -905,54 +955,7 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) } } -void RenderWidgetHostViewQt::AccessibilitySetFocus(int acc_obj_id) -{ - if (!m_host) - return; - m_host->AccessibilitySetFocus(acc_obj_id); -} - -void RenderWidgetHostViewQt::AccessibilityDoDefaultAction(int acc_obj_id) -{ - if (!m_host) - return; - m_host->AccessibilityDoDefaultAction(acc_obj_id); -} - -void RenderWidgetHostViewQt::AccessibilityScrollToMakeVisible(int acc_obj_id, gfx::Rect subfocus) -{ - if (!m_host) - return; - m_host->AccessibilityScrollToMakeVisible(acc_obj_id, subfocus); -} - -void RenderWidgetHostViewQt::AccessibilityScrollToPoint(int acc_obj_id, gfx::Point point) -{ - if (!m_host) - return; - m_host->AccessibilityScrollToPoint(acc_obj_id, point); -} - -void RenderWidgetHostViewQt::AccessibilitySetTextSelection(int acc_obj_id, int start_offset, int end_offset) -{ - if (!m_host) - return; - m_host->AccessibilitySetTextSelection(acc_obj_id, start_offset, end_offset); -} - -bool RenderWidgetHostViewQt::AccessibilityViewHasFocus() const -{ - return HasFocus(); -} - -void RenderWidgetHostViewQt::AccessibilityFatalError() -{ - if (!m_host) - return; - m_host->AccessibilityFatalError(); - SetBrowserAccessibilityManager(NULL); -} - +#ifndef QT_NO_ACCESSIBILITY void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active) { if (active) @@ -960,6 +963,7 @@ void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active) else content::BrowserAccessibilityStateImpl::GetInstance()->DisableAccessibility(); } +#endif // QT_NO_ACCESSIBILITY void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) { @@ -981,7 +985,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(ev->touchPoints()); if (ev->type() == QEvent::TouchCancel) { - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::ACTION_CANCEL); + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::ACTION_CANCEL, ev->modifiers()); processMotionEvent(cancelEvent); return; } @@ -1014,7 +1018,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) continue; } - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, i); + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); processMotionEvent(motionEvent); } } @@ -1042,16 +1046,6 @@ void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) } } -QAccessibleInterface *RenderWidgetHostViewQt::GetQtAccessible() -{ - // Assume we have a screen reader doing stuff - CreateBrowserAccessibilityManagerIfNeeded(); - content::BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected(); - content::BrowserAccessibility *acc = GetBrowserAccessibilityManager()->GetRoot(); - content::BrowserAccessibilityQt *accQt = static_cast<content::BrowserAccessibilityQt*>(acc); - return accQt; -} - void RenderWidgetHostViewQt::didFirstVisuallyNonEmptyLayout() { m_didFirstVisuallyNonEmptyLayout = true; diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index d4a3ff248..93e7e75b4 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -44,12 +44,15 @@ #include "cc/resources/transferable_resource.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" +#include "content/common/gpu/gpu_messages.h" +#include "content/common/view_messages.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" #include <QMap> #include <QPoint> #include <QRect> #include <QtGlobal> #include <QtGui/qaccessible.h> +#include <QtGui/QTouchEvent> #include "delegated_frame_node.h" @@ -59,7 +62,6 @@ class QFocusEvent; class QHoverEvent; class QKeyEvent; class QMouseEvent; -class QTouchEvent; class QVariant; class QWheelEvent; class QAccessibleInterface; @@ -91,9 +93,10 @@ class RenderWidgetHostViewQt : public content::RenderWidgetHostViewBase , public ui::GestureProviderClient , public RenderWidgetHostViewQtDelegateClient - , public content::BrowserAccessibilityDelegate , public base::SupportsWeakPtr<RenderWidgetHostViewQt> +#ifndef QT_NO_ACCESSIBILITY , public QAccessible::ActivationObserver +#endif // QT_NO_ACCESSIBILITY { public: RenderWidgetHostViewQt(content::RenderWidgetHost* widget); @@ -108,6 +111,7 @@ public: virtual content::RenderWidgetHost* GetRenderWidgetHost() const Q_DECL_OVERRIDE; virtual void SetSize(const gfx::Size& size) Q_DECL_OVERRIDE; virtual void SetBounds(const gfx::Rect&) Q_DECL_OVERRIDE; + virtual gfx::Vector2dF GetLastScrollOffset() const Q_DECL_OVERRIDE; virtual gfx::Size GetPhysicalBackingSize() const Q_DECL_OVERRIDE; virtual gfx::NativeView GetNativeView() const Q_DECL_OVERRIDE; virtual gfx::NativeViewId GetNativeViewId() const Q_DECL_OVERRIDE; @@ -127,22 +131,16 @@ public: virtual void Blur() Q_DECL_OVERRIDE; virtual void UpdateCursor(const content::WebCursor&) Q_DECL_OVERRIDE; virtual void SetIsLoading(bool) Q_DECL_OVERRIDE; - virtual void TextInputStateChanged(const ViewHostMsg_TextInputState_Params& params) Q_DECL_OVERRIDE; + virtual void TextInputTypeChanged(ui::TextInputType type, ui::TextInputMode mode, bool can_compose_inline, int flags) Q_DECL_OVERRIDE; virtual void ImeCancelComposition() Q_DECL_OVERRIDE; virtual void ImeCompositionRangeChanged(const gfx::Range&, const std::vector<gfx::Rect>&) Q_DECL_OVERRIDE; virtual void RenderProcessGone(base::TerminationStatus, int) Q_DECL_OVERRIDE; virtual void Destroy() Q_DECL_OVERRIDE; virtual void SetTooltipText(const base::string16 &tooltip_text) Q_DECL_OVERRIDE; virtual void SelectionBoundsChanged(const ViewHostMsg_SelectionBounds_Params&) Q_DECL_OVERRIDE; - virtual void ScrollOffsetChanged() Q_DECL_OVERRIDE; - virtual void CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& /* dst_size */, const base::Callback<void(bool, const SkBitmap&)>& callback, const SkBitmap::Config config) Q_DECL_OVERRIDE; + virtual void CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& dst_size, content::CopyFromCompositingSurfaceCallback& callback, const SkColorType color_type) Q_DECL_OVERRIDE; virtual void CopyFromCompositingSurfaceToVideoFrame(const gfx::Rect& src_subrect, const scoped_refptr<media::VideoFrame>& target, const base::Callback<void(bool)>& callback) Q_DECL_OVERRIDE; virtual bool CanCopyToVideoFrame() const Q_DECL_OVERRIDE; - virtual void AcceleratedSurfaceInitialized(int host_id, int route_id) Q_DECL_OVERRIDE; - virtual void AcceleratedSurfaceBuffersSwapped(const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, int gpu_host_id) Q_DECL_OVERRIDE; - virtual void AcceleratedSurfacePostSubBuffer(const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, int gpu_host_id) Q_DECL_OVERRIDE; - virtual void AcceleratedSurfaceSuspend() Q_DECL_OVERRIDE; - virtual void AcceleratedSurfaceRelease() Q_DECL_OVERRIDE; virtual bool HasAcceleratedSurface(const gfx::Size&) Q_DECL_OVERRIDE; virtual void OnSwapCompositorFrame(uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) Q_DECL_OVERRIDE; virtual void GetScreenInfo(blink::WebScreenInfo* results) Q_DECL_OVERRIDE; @@ -173,7 +171,6 @@ public: void handleInputMethodEvent(QInputMethodEvent*); #if defined(OS_MACOSX) - virtual void SetTakesFocusOnlyOnMouseDown(bool flag) Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } virtual void SetActive(bool active) Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } virtual bool IsSpeaking() const Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED; return false; } virtual void SpeakSelection() Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } @@ -202,21 +199,10 @@ public: #endif // defined(OS_WIN) // Overridden from content::BrowserAccessibilityDelegate - virtual void AccessibilitySetFocus(int acc_obj_id) Q_DECL_OVERRIDE; - virtual void AccessibilityDoDefaultAction(int acc_obj_id) Q_DECL_OVERRIDE; - virtual void AccessibilityShowMenu(int acc_obj_id) Q_DECL_OVERRIDE { } - virtual void AccessibilityScrollToMakeVisible(int acc_obj_id, gfx::Rect subfocus) Q_DECL_OVERRIDE; - virtual void AccessibilityScrollToPoint(int acc_obj_id, gfx::Point point) Q_DECL_OVERRIDE; - virtual void AccessibilitySetTextSelection(int acc_obj_id, int start_offset, int end_offset) Q_DECL_OVERRIDE; - virtual bool AccessibilityViewHasFocus() const Q_DECL_OVERRIDE; - virtual gfx::Rect AccessibilityGetViewBounds() const Q_DECL_OVERRIDE { return GetViewBounds(); } - virtual gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds) const Q_DECL_OVERRIDE { return gfx::Point(); } - virtual void AccessibilityHitTest(const gfx::Point& point) Q_DECL_OVERRIDE { } - virtual void AccessibilityFatalError() Q_DECL_OVERRIDE; + virtual content::BrowserAccessibilityManager* CreateBrowserAccessibilityManager(content::BrowserAccessibilityDelegate* delegate) Q_DECL_OVERRIDE; +#ifndef QT_NO_ACCESSIBILITY virtual void accessibilityActiveChanged(bool active) Q_DECL_OVERRIDE; - - QAccessibleInterface *GetQtAccessible(); - +#endif // QT_NO_ACCESSIBILITY void didFirstVisuallyNonEmptyLayout(); private: @@ -226,7 +212,6 @@ private: float dpiScale() const; bool IsPopup() const; - void CreateBrowserAccessibilityManagerIfNeeded(); content::RenderWidgetHostImpl *m_host; ui::FilteredGestureProvider m_gestureProvider; @@ -235,7 +220,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; @@ -248,8 +233,11 @@ private: QRect m_cursorRect; size_t m_anchorPositionWithinSelection; size_t m_cursorPositionWithinSelection; + QPoint m_lockedMousePosition; bool m_initPending; + + gfx::Vector2dF m_lastScrollOffset; }; #endif // RENDER_WIDGET_HOST_VIEW_QT_H diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 3f6d9caac..018a914d8 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; @@ -74,10 +77,15 @@ public: virtual QRectF contentsRect() const = 0; virtual void setKeyboardFocus() = 0; virtual bool hasKeyboardFocus() = 0; + virtual void lockMouse() = 0; + virtual void unlockMouse() = 0; virtual void show() = 0; 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/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index bfc5c389f..f8970e7a0 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -38,6 +38,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/common/localized_error.h" +#include "components/error_page/common/error_page_params.h" #include "components/visitedlink/renderer/visitedlink_slave.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" @@ -47,8 +48,9 @@ #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/webui/jstemplate_builder.h" -#include "webkit/common/webpreferences.h" +#include "content/public/common/web_preferences.h" +#include "renderer/web_channel_ipc_transport.h" #include "renderer/qt_render_view_observer.h" #include "grit/renderer_resources.h" @@ -65,14 +67,17 @@ ContentRendererClientQt::~ContentRendererClientQt() void ContentRendererClientQt::RenderThreadStarted() { + content::RenderThread *renderThread = content::RenderThread::Get(); + renderThread->RegisterExtension(WebChannelIPCTransport::getV8Extension()); m_visitedLinkSlave.reset(new visitedlink::VisitedLinkSlave); - content::RenderThread::Get()->AddObserver(m_visitedLinkSlave.data()); + renderThread->AddObserver(m_visitedLinkSlave.data()); } void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view) { - // RenderViewObserver destroys itself with its RenderView. + // RenderViewObservers destroy themselves with their RenderView. new QtRenderViewObserver(render_view); + new WebChannelIPCTransport(render_view); } bool ContentRendererClientQt::HasErrorPage(int httpStatusCode, std::string *errorDomain) @@ -107,7 +112,7 @@ void ContentRendererClientQt::GetNavigationErrorStrings(content::RenderView* ren // NetErrorHelper::GetErrorStringsForDnsProbe, but that one is harder to untangle. LocalizedError::GetStrings(error.reason, error.domain.utf8(), error.unreachableURL, isPost , error.staleCopyInCache && !isPost, locale, renderView->GetAcceptLanguages() - , scoped_ptr<LocalizedError::ErrorPageParams>(), &errorStrings); + , scoped_ptr<error_page::ErrorPageParams>(), &errorStrings); resourceId = IDR_NET_ERROR_HTML; diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp new file mode 100644 index 000000000..0491a6103 --- /dev/null +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +// 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 "renderer/web_channel_ipc_transport.h" + +#include "common/qt_messages.h" + +#include "content/public/renderer/render_view.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "v8/include/v8.h" + +#include <QJsonDocument> + +static const char kWebChannelTransportExtensionName[] = "v8/WebChannelTransport"; + +static const char kWebChannelTransportApi[] = + "if (typeof(navigator) === 'undefined')" \ + " navigator = {};" \ + "if (typeof(navigator.qtWebChannelTransport) === 'undefined')" \ + " navigator.qtWebChannelTransport = {};" \ + "navigator.qtWebChannelTransport.send = function(message) {" \ + " native function NativeQtSendMessage();" \ + " NativeQtSendMessage(message);" \ + "};"; + +class WebChannelTransportExtension : public v8::Extension { +public: + static content::RenderView *GetRenderView(); + + WebChannelTransportExtension() : v8::Extension(kWebChannelTransportExtensionName, kWebChannelTransportApi) + { + } + + virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(v8::Isolate* isolate, v8::Handle<v8::String> name) Q_DECL_OVERRIDE; + + static void NativeQtSendMessage(const v8::FunctionCallbackInfo<v8::Value>& args) + { + content::RenderView *renderView = GetRenderView(); + if (!renderView || args.Length() != 1) + return; + v8::Handle<v8::Value> val = args[0]; + if (!val->IsString() && !val->IsStringObject()) + return; + v8::String::Utf8Value utf8(val->ToString()); + + QByteArray valueData(*utf8, utf8.length()); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(valueData, &error); + if (error.error != QJsonParseError::NoError) + qWarning("%s %d: Parsing error: %s",__FILE__, __LINE__, qPrintable(error.errorString())); + int size = 0; + const char *rawData = doc.rawData(&size); + renderView->Send(new WebChannelIPCTransportHost_SendMessage(renderView->GetRoutingID(), std::vector<char>(rawData, rawData + size))); + } +}; + +content::RenderView *WebChannelTransportExtension::GetRenderView() +{ + blink::WebLocalFrame *webframe = blink::WebLocalFrame::frameForCurrentContext(); + DCHECK(webframe) << "There should be an active frame since we just got a native function called."; + if (!webframe) + return 0; + + blink::WebView *webview = webframe->view(); + if (!webview) + return 0; // can happen during closing + + return content::RenderView::FromWebView(webview); +} + +v8::Handle<v8::FunctionTemplate> WebChannelTransportExtension::GetNativeFunctionTemplate(v8::Isolate *isolate, v8::Handle<v8::String> name) +{ + if (name->Equals(v8::String::NewFromUtf8(isolate, "NativeQtSendMessage"))) + return v8::FunctionTemplate::New(isolate, NativeQtSendMessage); + + return v8::Handle<v8::FunctionTemplate>(); +} + +WebChannelIPCTransport::WebChannelIPCTransport(content::RenderView *renderView) + : content::RenderViewObserver(renderView) +{ +} + +void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &binaryJSON) +{ + blink::WebView *webView = render_view()->GetWebView(); + if (!webView) + return; + + QJsonDocument doc = QJsonDocument::fromRawData(binaryJSON.data(), binaryJSON.size(), QJsonDocument::BypassValidation); + Q_ASSERT(doc.isObject()); + QByteArray json = doc.toJson(QJsonDocument::Compact); + + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handleScope(isolate); + blink::WebFrame *frame = webView->mainFrame(); + v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); + v8::Context::Scope contextScope(context); + + v8::Handle<v8::Object> global(context->Global()); + v8::Handle<v8::Value> navigatorValue(global->Get(v8::String::NewFromUtf8(isolate, "navigator"))); + if (!navigatorValue->IsObject()) + return; + v8::Handle<v8::Value> navigatorQtValue(navigatorValue->ToObject()->Get(v8::String::NewFromUtf8(isolate, "qtWebChannelTransport"))); + if (!navigatorQtValue->IsObject()) + return; + v8::Handle<v8::Value> onmessageCallbackValue(navigatorQtValue->ToObject()->Get(v8::String::NewFromUtf8(isolate, "onmessage"))); + if (!onmessageCallbackValue->IsFunction()) { + qWarning("onmessage is not a callable property of navigator.qtWebChannelTransport. Some things might not work as expected."); + return; + } + + v8::Handle<v8::Object> messageObject(v8::Object::New(isolate)); + messageObject->ForceSet(v8::String::NewFromUtf8(isolate, "data") + , v8::String::NewFromUtf8(isolate, json.constData(), v8::String::kNormalString, json.size()) + , v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); + + v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(onmessageCallbackValue); + const int argc = 1; + v8::Handle<v8::Value> argv[argc]; + argv[0] = messageObject; + frame->callFunctionEvenIfScriptDisabled(callback, navigatorQtValue->ToObject(), argc, argv); +} + +v8::Extension *WebChannelIPCTransport::getV8Extension() +{ + return new WebChannelTransportExtension; +} + +bool WebChannelIPCTransport::OnMessageReceived(const IPC::Message &message) +{ + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(WebChannelIPCTransport, message) + IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Message, dispatchWebChannelMessage) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} diff --git a/src/webengine/api/qquickwebenginesettings_p_p.h b/src/core/renderer/web_channel_ipc_transport.h index 8f3e95eea..29e819e95 100644 --- a/src/webengine/api/qquickwebenginesettings_p_p.h +++ b/src/core/renderer/web_channel_ipc_transport.h @@ -34,24 +34,26 @@ ** ****************************************************************************/ -#ifndef QQUICKWEBENGINESETTINGS_P_P_H -#define QQUICKWEBENGINESETTINGS_P_P_H +#ifndef NAVIGATOR_QT_EXTENSION_H +#define NAVIGATOR_QT_EXTENSION_H -#include "web_engine_settings.h" +#include "base/values.h" +#include "content/public/renderer/render_view_observer.h" +#include <QtCore/qcompilerdetection.h> -QT_BEGIN_NAMESPACE +namespace v8 { +class Extension; +} -class QQuickWebEngineSettingsPrivate : public WebEngineSettingsDelegate { +class WebChannelIPCTransport : public content::RenderViewObserver { public: - QQuickWebEngineSettingsPrivate(); - QQuickWebEngineSettingsPrivate(WebContentsAdapter *adapter); + static v8::Extension* getV8Extension(); - void apply() Q_DECL_OVERRIDE; - WebEngineSettings *fallbackSettings() const Q_DECL_OVERRIDE; + WebChannelIPCTransport(content::RenderView *); - QScopedPointer<WebEngineSettings> coreSettings; +private: + void dispatchWebChannelMessage(const std::vector<char> &binaryJSON); + virtual bool OnMessageReceived(const IPC::Message &message) Q_DECL_OVERRIDE; }; -QT_END_NAMESPACE - -#endif // QQUICKWEBENGINESETTINGS_P_P_H +#endif // NAVIGATOR_QT_EXTENSION_H diff --git a/src/core/resource_context_qt.h b/src/core/resource_context_qt.h index 490ef1789..e3f0292e7 100644 --- a/src/core/resource_context_qt.h +++ b/src/core/resource_context_qt.h @@ -60,9 +60,6 @@ public: virtual net::URLRequestContext* GetRequestContext() Q_DECL_OVERRIDE; - virtual bool AllowMicAccess(const GURL& origin) Q_DECL_OVERRIDE { return false; } - virtual bool AllowCameraAccess(const GURL& origin) Q_DECL_OVERRIDE { return false; } - void set_url_request_context_getter(net::URLRequestContextGetter* getter); private: 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/resources/repack_resources.gypi b/src/core/resources/repack_resources.gypi index 133813c60..b5d8c9d91 100644 --- a/src/core/resources/repack_resources.gypi +++ b/src/core/resources/repack_resources.gypi @@ -8,10 +8,10 @@ '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak', - '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources_100_percent.pak', - '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.pak', - '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_resources_100_percent.pak', - '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/webui_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/content/app/resources/content_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/resources/webui_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/chrome/renderer_resources_100_percent.pak', ], }, diff --git a/src/core/resources/resources.gyp b/src/core/resources/resources.gyp index 835a87cdf..5d4d83c05 100644 --- a/src/core/resources/resources.gyp +++ b/src/core/resources/resources.gyp @@ -14,8 +14,8 @@ 'qt_install_translations%': '', }, 'dependencies': [ - '<(chromium_src_dir)/webkit/webkit_resources.gyp:webkit_strings', - '<(chromium_src_dir)/webkit/webkit_resources.gyp:webkit_resources', + '<(chromium_src_dir)/content/app/strings/content_strings.gyp:content_strings', + '<(chromium_src_dir)/webkit/blink_resources.gyp:blink_resources', '<(chromium_src_dir)/content/browser/devtools/devtools_resources.gyp:devtools_resources', '../chrome_qt.gyp:chrome_resources', ], diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 9d9cdd675..6bb755abc 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -39,16 +39,17 @@ #include <QColor> #include <QDateTime> +#include <QDir> #include <QMatrix4x4> #include <QRect> #include <QString> #include <QUrl> #include "base/files/file_path.h" #include "base/time/time.h" +#include "content/public/common/file_chooser_file_info.h" #include "third_party/skia/include/utils/SkMatrix44.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/rect.h" -#include "ui/shell_dialogs/selected_file_info.h" #include "url/gurl.h" inline QString toQt(const base::string16 &string) @@ -135,10 +136,14 @@ 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) - return str.toStdWString(); + return QDir::toNativeSeparators(str).toStdWString(); #else return str.toStdString(); #endif @@ -150,13 +155,16 @@ 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) +inline content::FileChooserFileInfo fileListingHelper<content::FileChooserFileInfo>(const QString &file) { - base::FilePath fp(toFilePathString(file)); - return ui::SelectedFileInfo(fp, fp); + content::FileChooserFileInfo choose_file; + base::FilePath fp(toFilePath(file)); + choose_file.file_path = fp; + choose_file.display_name = fp.BaseName().value(); + return choose_file; } template <> diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 8ec600a85..d1f5aef5a 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -51,8 +51,8 @@ #include "net/http/http_network_session.h" #include "net/http/http_server_properties_impl.h" #include "net/proxy/proxy_service.h" -#include "net/ssl/default_server_bound_cert_store.h" -#include "net/ssl/server_bound_cert_service.h" +#include "net/ssl/channel_id_service.h" +#include "net/ssl/default_channel_id_store.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request_context.h" @@ -61,125 +61,229 @@ #include "net/url_request/ftp_protocol_handler.h" #include "net/ftp/ftp_network_layer.h" -#include "network_delegate_qt.h" +#include "browser_context_adapter.h" #include "content_client_qt.h" +#include "network_delegate_qt.h" #include "qrc_protocol_handler_qt.h" +#include "type_conversion.h" static const char kQrcSchemeQt[] = "qrc"; using content::BrowserThread; -URLRequestContextGetterQt::URLRequestContextGetterQt(const base::FilePath &dataPath, const base::FilePath &cachePath, content::ProtocolHandlerMap *protocolHandlers) +URLRequestContextGetterQt::URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers) : m_ignoreCertificateErrors(false) - , m_dataPath(dataPath) - , m_cachePath(cachePath) + , m_updateStorageSettings(false) + , m_updateCookieStore(false) + , m_updateHttpCache(false) + , m_browserContext(browserContext) { std::swap(m_protocolHandlers, *protocolHandlers); - // We must create the proxy config service on the UI loop on Linux because it - // must synchronously run on the glib message loop. This will be passed to - // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). -//#ifdef Q_OS_LINUX - m_proxyConfigService.reset(net::ProxyService::CreateSystemProxyConfigService(BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)->message_loop_proxy() - , BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE))); -//#endif + updateStorageSettings(); } net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() { if (!m_urlRequestContext) { - m_urlRequestContext.reset(new net::URLRequestContext()); - m_networkDelegate.reset(new NetworkDelegateQt); + m_networkDelegate.reset(new NetworkDelegateQt); m_urlRequestContext->set_network_delegate(m_networkDelegate.get()); - base::FilePath cookiesPath = m_dataPath.Append(FILE_PATH_LITERAL("Cookies")); - content::CookieStoreConfig cookieStoreConfig(cookiesPath, content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, NULL, NULL); - scoped_refptr<net::CookieStore> cookieStore = content::CreateCookieStore(cookieStoreConfig); + generateStorage(); + generateJobFactory(); + } + + return m_urlRequestContext.get(); +} + +void URLRequestContextGetterQt::updateStorageSettings() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (!m_proxyConfigService) { + // We must create the proxy config service on the UI loop on Linux because it + // must synchronously run on the glib message loop. This will be passed to + // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). + m_proxyConfigService.reset(net::ProxyService::CreateSystemProxyConfigService( + content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), + content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)) + ); + } + if (m_storage && !m_updateStorageSettings) { + m_updateStorageSettings = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateStorage, this)); + } +} + +void URLRequestContextGetterQt::generateStorage() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_proxyConfigService); + m_updateStorageSettings = false; + + m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get())); + + generateCookieStore(); + generateUserAgent(); + + m_storage->set_channel_id_service(new net::ChannelIDService( + new net::DefaultChannelIDStore(NULL), + base::WorkerPool::GetTaskRunner(true))); + + m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); + m_storage->set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver( + m_proxyConfigService.release(), 0, NULL)); + m_storage->set_ssl_config_service(new net::SSLConfigServiceDefaults); + m_storage->set_transport_security_state(new net::TransportSecurityState()); + + scoped_ptr<net::HostResolver> host_resolver(net::HostResolver::CreateDefaultResolver(NULL)); + m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get())); + m_storage->set_http_server_properties(scoped_ptr<net::HttpServerProperties>(new net::HttpServerPropertiesImpl)); + + // Give |m_storage| ownership at the end in case it's |mapped_host_resolver|. + m_storage->set_host_resolver(host_resolver.Pass()); + + generateHttpCache(); +} + +void URLRequestContextGetterQt::updateCookieStore() +{ + if (m_urlRequestContext && !m_updateCookieStore && !m_updateStorageSettings) { + m_updateCookieStore = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateCookieStore, this)); + } +} - m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get())); - m_storage->set_cookie_store(cookieStore.get()); - m_storage->set_server_bound_cert_service(new net::ServerBoundCertService( - new net::DefaultServerBoundCertStore(NULL), - base::WorkerPool::GetTaskRunner(true))); - m_storage->set_http_user_agent_settings( - new net::StaticHttpUserAgentSettings("en-us,en", ContentClientQt::getUserAgent())); +void URLRequestContextGetterQt::generateCookieStore() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_storage); + m_updateCookieStore = false; - scoped_ptr<net::HostResolver> host_resolver( - net::HostResolver::CreateDefaultResolver(NULL)); + // Unset it first to get a chance to destroy and flush the old cookie store before before opening a new on possibly the same file. + m_storage->set_cookie_store(0); - m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); + net::CookieStore* cookieStore = 0; + switch (m_browserContext->persistentCookiesPolicy()) { + case BrowserContextAdapter::NoPersistentCookies: + cookieStore = + content::CreateCookieStore(content::CookieStoreConfig( + base::FilePath(), + content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES, + NULL, NULL) + ); + break; + case BrowserContextAdapter::AllowPersistentCookies: + cookieStore = + content::CreateCookieStore(content::CookieStoreConfig( + toFilePath(m_browserContext->cookiesPath()), + content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, + NULL, NULL) + ); + break; + case BrowserContextAdapter::ForcePersistentCookies: + cookieStore = + content::CreateCookieStore(content::CookieStoreConfig( + toFilePath(m_browserContext->cookiesPath()), + content::CookieStoreConfig::RESTORED_SESSION_COOKIES, + NULL, NULL) + ); + break; + } + m_storage->set_cookie_store(cookieStore); +} - m_storage->set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver(m_proxyConfigService.release(), 0, NULL)); +void URLRequestContextGetterQt::updateUserAgent() +{ + if (m_urlRequestContext && !m_updateStorageSettings) + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateUserAgent, this)); +} - m_storage->set_ssl_config_service(new net::SSLConfigServiceDefaults); - m_storage->set_transport_security_state(new net::TransportSecurityState()); +void URLRequestContextGetterQt::generateUserAgent() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_storage); - m_storage->set_http_auth_handler_factory( - net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get())); - m_storage->set_http_server_properties(scoped_ptr<net::HttpServerProperties>(new net::HttpServerPropertiesImpl)); + m_storage->set_http_user_agent_settings( + new net::StaticHttpUserAgentSettings("en-us,en", m_browserContext->httpUserAgent().toStdString())); +} - base::FilePath cache_path = m_cachePath.Append(FILE_PATH_LITERAL("Cache")); - net::HttpCache::DefaultBackend* main_backend = +void URLRequestContextGetterQt::updateHttpCache() +{ + if (m_urlRequestContext && !m_updateHttpCache && !m_updateStorageSettings) { + m_updateHttpCache = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateHttpCache, this)); + } +} + +void URLRequestContextGetterQt::generateHttpCache() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_storage); + m_updateHttpCache = false; + + net::HttpCache::DefaultBackend* main_backend = 0; + switch (m_browserContext->httpCacheType()) { + case BrowserContextAdapter::MemoryHttpCache: + main_backend = + new net::HttpCache::DefaultBackend( + net::MEMORY_CACHE, + net::CACHE_BACKEND_DEFAULT, + base::FilePath(), + m_browserContext->httpCacheMaxSize(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE) + ); + break; + case BrowserContextAdapter::DiskHttpCache: + main_backend = new net::HttpCache::DefaultBackend( net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, - cache_path, - 0, - BrowserThread::GetMessageLoopProxyForThread( - BrowserThread::CACHE)); - - net::HttpNetworkSession::Params network_session_params; - network_session_params.transport_security_state = - m_urlRequestContext->transport_security_state(); - network_session_params.cert_verifier = - m_urlRequestContext->cert_verifier(); - network_session_params.server_bound_cert_service = - m_urlRequestContext->server_bound_cert_service(); - network_session_params.proxy_service = - m_urlRequestContext->proxy_service(); - network_session_params.ssl_config_service = - m_urlRequestContext->ssl_config_service(); - network_session_params.http_auth_handler_factory = - m_urlRequestContext->http_auth_handler_factory(); - network_session_params.network_delegate = - m_networkDelegate.get(); - network_session_params.http_server_properties = - m_urlRequestContext->http_server_properties(); - network_session_params.ignore_certificate_errors = - m_ignoreCertificateErrors; - - // Give |m_storage| ownership at the end in case it's |mapped_host_resolver|. - m_storage->set_host_resolver(host_resolver.Pass()); - network_session_params.host_resolver = - m_urlRequestContext->host_resolver(); - - net::HttpCache* main_cache = new net::HttpCache( - network_session_params, main_backend); - m_storage->set_http_transaction_factory(main_cache); - - - m_jobFactory.reset(new net::URLRequestJobFactoryImpl()); - - // Chromium has a few protocol handlers ready for us, only pick blob: and throw away the rest. - content::ProtocolHandlerMap::iterator it = m_protocolHandlers.find(url::kBlobScheme); - Q_ASSERT(it != m_protocolHandlers.end()); - m_jobFactory->SetProtocolHandler(it->first, it->second.release()); - m_protocolHandlers.clear(); - - m_jobFactory->SetProtocolHandler(url::kDataScheme, new net::DataProtocolHandler()); - m_jobFactory->SetProtocolHandler(url::kFileScheme, new net::FileProtocolHandler( - content::BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))); - m_jobFactory->SetProtocolHandler(kQrcSchemeQt, new QrcProtocolHandlerQt()); - m_jobFactory->SetProtocolHandler(url::kFtpScheme, new net::FtpProtocolHandler( - new net::FtpNetworkLayer(m_urlRequestContext->host_resolver()))); - m_urlRequestContext->set_job_factory(m_jobFactory.get()); + toFilePath(m_browserContext->httpCachePath()), + m_browserContext->httpCacheMaxSize(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE) + ); + break; } - return m_urlRequestContext.get(); + net::HttpNetworkSession::Params network_session_params; + network_session_params.transport_security_state = m_urlRequestContext->transport_security_state(); + network_session_params.cert_verifier = m_urlRequestContext->cert_verifier(); + network_session_params.channel_id_service = m_urlRequestContext->channel_id_service(); + network_session_params.proxy_service = m_urlRequestContext->proxy_service(); + network_session_params.ssl_config_service = m_urlRequestContext->ssl_config_service(); + network_session_params.http_auth_handler_factory = m_urlRequestContext->http_auth_handler_factory(); + network_session_params.network_delegate = m_networkDelegate.get(); + network_session_params.http_server_properties = m_urlRequestContext->http_server_properties(); + network_session_params.ignore_certificate_errors = m_ignoreCertificateErrors; + network_session_params.host_resolver = m_urlRequestContext->host_resolver(); + + m_storage->set_http_transaction_factory(new net::HttpCache(network_session_params, main_backend)); } +void URLRequestContextGetterQt::generateJobFactory() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(!m_jobFactory); + m_jobFactory.reset(new net::URLRequestJobFactoryImpl()); + + // Chromium has a few protocol handlers ready for us, only pick blob: and throw away the rest. + content::ProtocolHandlerMap::iterator it = m_protocolHandlers.find(url::kBlobScheme); + Q_ASSERT(it != m_protocolHandlers.end()); + m_jobFactory->SetProtocolHandler(it->first, it->second.release()); + m_protocolHandlers.clear(); + + m_jobFactory->SetProtocolHandler(url::kDataScheme, new net::DataProtocolHandler()); + m_jobFactory->SetProtocolHandler(url::kFileScheme, new net::FileProtocolHandler( + content::BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))); + m_jobFactory->SetProtocolHandler(kQrcSchemeQt, new QrcProtocolHandlerQt()); + m_jobFactory->SetProtocolHandler(url::kFtpScheme, + new net::FtpProtocolHandler(new net::FtpNetworkLayer(m_urlRequestContext->host_resolver()))); + + m_urlRequestContext->set_job_factory(m_jobFactory.get()); +} scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetterQt::GetNetworkTaskRunner() const { diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 6c9ac6d59..5f6048403 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -40,6 +40,7 @@ #include "net/url_request/url_request_context_getter.h" #include "base/files/file_path.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/single_thread_task_runner.h" #include "content/public/browser/content_browser_client.h" @@ -50,25 +51,41 @@ #include "qglobal.h" namespace net { -class HostResolver; class MappedHostResolver; class NetworkDelegate; class ProxyConfigService; } +class BrowserContextAdapter; + class URLRequestContextGetterQt : public net::URLRequestContextGetter { public: - explicit URLRequestContextGetterQt(const base::FilePath &, const base::FilePath &, content::ProtocolHandlerMap *protocolHandlers); + explicit URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers); virtual net::URLRequestContext *GetURLRequestContext() Q_DECL_OVERRIDE; virtual scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const Q_DECL_OVERRIDE; + // Called on the UI thread: + void updateStorageSettings(); + void updateUserAgent(); + void updateCookieStore(); + void updateHttpCache(); + private: virtual ~URLRequestContextGetterQt() {} + // Called on the IO thread: + void generateStorage(); + void generateCookieStore(); + void generateHttpCache(); + void generateUserAgent(); + void generateJobFactory(); + bool m_ignoreCertificateErrors; - base::FilePath m_dataPath; - base::FilePath m_cachePath; + volatile bool m_updateStorageSettings; + volatile bool m_updateCookieStore; + volatile bool m_updateHttpCache; + BrowserContextAdapter *m_browserContext; content::ProtocolHandlerMap m_protocolHandlers; scoped_ptr<net::ProxyConfigService> m_proxyConfigService; diff --git a/src/core/web_channel_ipc_transport_host.cpp b/src/core/web_channel_ipc_transport_host.cpp new file mode 100644 index 000000000..d940aeab7 --- /dev/null +++ b/src/core/web_channel_ipc_transport_host.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 "web_channel_ipc_transport_host.h" + +#include "base/strings/string16.h" + +#include "common/qt_messages.h" +#include "type_conversion.h" + +#include <QJsonDocument> +#include <QJsonObject> + +WebChannelIPCTransportHost::WebChannelIPCTransportHost(content::WebContents *contents, QObject *parent) + : QWebChannelAbstractTransport(parent) + , content::WebContentsObserver(contents) +{ +} + +WebChannelIPCTransportHost::~WebChannelIPCTransportHost() +{ +} + +void WebChannelIPCTransportHost::sendMessage(const QJsonObject &message) +{ + QJsonDocument doc(message); + int size = 0; + const char *rawData = doc.rawData(&size); + Send(new WebChannelIPCTransport_Message(routing_id(), std::vector<char>(rawData, rawData + size))); +} + +void WebChannelIPCTransportHost::onWebChannelMessage(const std::vector<char> &message) +{ + QJsonDocument doc = QJsonDocument::fromRawData(message.data(), message.size(), QJsonDocument::BypassValidation); + Q_ASSERT(doc.isObject()); + Q_EMIT messageReceived(doc.object(), this); +} + +bool WebChannelIPCTransportHost::OnMessageReceived(const IPC::Message &message) +{ + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(WebChannelIPCTransportHost, message) + IPC_MESSAGE_HANDLER(WebChannelIPCTransportHost_SendMessage, onWebChannelMessage) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} diff --git a/src/webenginewidgets/api/qwebenginesettings_p.h b/src/core/web_channel_ipc_transport_host.h index 830e8b360..d51ebba24 100644 --- a/src/webenginewidgets/api/qwebenginesettings_p.h +++ b/src/core/web_channel_ipc_transport_host.h @@ -34,31 +34,32 @@ ** ****************************************************************************/ -#ifndef QWEBENGINESETTINGS_P_H -#define QWEBENGINESETTINGS_P_H +#ifndef WEB_CHANNEL_IPC_TRANSPORT_H +#define WEB_CHANNEL_IPC_TRANSPORT_H -#include "web_engine_settings.h" -#include <QtCore/qcompilerdetection.h> -#include <QtCore/QScopedPointer> -QT_BEGIN_NAMESPACE +#include <QtWebChannel/QWebChannelAbstractTransport> +#include "content/public/browser/web_contents_observer.h" -class QWebEngineSettingsPrivate : public WebEngineSettingsDelegate { +#include "qtwebenginecoreglobal.h" +#include <QtCore/QObject> -public: - QWebEngineSettingsPrivate(); - void initDefaults(); - void apply() Q_DECL_OVERRIDE; - WebEngineSettings *fallbackSettings() const Q_DECL_OVERRIDE; +QT_FORWARD_DECLARE_CLASS(QString) - QScopedPointer<WebEngineSettings> coreSettings; +class WebChannelIPCTransportHost : public QWebChannelAbstractTransport + , public content::WebContentsObserver +{ +public: + WebChannelIPCTransportHost(content::WebContents *, QObject *parent = 0); + virtual ~WebChannelIPCTransportHost(); - // This should only contain things specific to WebEngineWidgets which we don't want exposed to the core layer. - // For instance, the icon database would most likely be implemented at that level. + // QWebChannelAbstractTransport + virtual void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE; +private: + bool OnMessageReceived(const IPC::Message& message) Q_DECL_OVERRIDE; + void onWebChannelMessage(const std::vector<char> &message); }; -QT_END_NAMESPACE - -#endif // QWEBENGINESETTINGS_P_H +#endif // WEB_CHANNEL_IPC_TRANSPORT_H diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 3f223f733..306de1a45 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -41,12 +41,15 @@ #include "web_contents_adapter.h" #include "web_contents_adapter_p.h" +#include "browser_accessibility_qt.h" +#include "browser_context_adapter.h" #include "browser_context_qt.h" #include "content_browser_client_qt.h" #include "javascript_dialog_manager_qt.h" #include "media_capture_devices_dispatcher.h" #include "qt_render_view_observer_host.h" #include "type_conversion.h" +#include "web_channel_ipc_transport_host.h" #include "web_contents_adapter_client.h" #include "web_contents_view_qt.h" #include "web_engine_context.h" @@ -65,9 +68,9 @@ #include "content/public/common/page_zoom.h" #include "content/public/common/renderer_preferences.h" #include "content/public/common/url_constants.h" +#include "content/public/common/web_preferences.h" #include "ui/shell_dialogs/selected_file_info.h" #include "third_party/WebKit/public/web/WebFindOptions.h" -#include "webkit/common/webpreferences.h" #include <QDir> #include <QGuiApplication> @@ -75,6 +78,7 @@ #include <QStyleHints> #include <QVariant> #include <QtGui/qaccessible.h> +#include <QtWebChannel/QWebChannel> static const int kTestWindowWidth = 800; static const int kTestWindowHeight = 600; @@ -175,9 +179,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 +225,7 @@ static void serializeNavigationHistory(const content::NavigationController &cont } } -void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::vector<content::NavigationEntry*> *entries) +static void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::vector<content::NavigationEntry*> *entries, content::BrowserContext *browserContext) { int version; input >> version; @@ -274,11 +277,11 @@ void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::ve content::Referrer(toGurl(referrerUrl), static_cast<blink::WebReferrerPolicy>(referrerPolicy)), // Use a transition type of reload so that we don't incorrectly // increase the typed count. - content::PAGE_TRANSITION_RELOAD, + ui::PAGE_TRANSITION_RELOAD, 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()))); @@ -292,9 +295,35 @@ void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::ve } } +namespace { +static QList<WebContentsAdapter *> recursive_guard_loading_adapters; + +class LoadRecursionGuard { + public: + static bool isGuarded(WebContentsAdapter *adapter) + { + return recursive_guard_loading_adapters.contains(adapter); + } + LoadRecursionGuard(WebContentsAdapter *adapter) + : m_adapter(adapter) + { + recursive_guard_loading_adapters.append(adapter); + } + + ~LoadRecursionGuard() { + recursive_guard_loading_adapters.removeOne(m_adapter); + } + + private: + WebContentsAdapter *m_adapter; +}; +} // Anonymous namespace + WebContentsAdapterPrivate::WebContentsAdapterPrivate() // This has to be the first thing we create, and the last we destroy. : engineContext(WebEngineContext::current()) + , webChannel(0) + , adapterClient(0) , nextRequestId(1) , lastFindRequestId(0) { @@ -308,13 +337,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); @@ -347,10 +376,13 @@ void WebContentsAdapter::initialize(WebContentsAdapterClient *adapterClient) { Q_D(WebContentsAdapter); d->adapterClient = adapterClient; + // We keep a reference to browserContextAdapter to keep it alive as long as we use it. + // This is needed in case the QML WebEngineProfile is garbage collected before the WebEnginePage. + d->browserContextAdapter = adapterClient->browserContextAdapter(); // Create our own if a WebContents wasn't provided at construction. if (!d->webContents) - d->webContents.reset(createBlankWebContents(adapterClient)); + d->webContents.reset(createBlankWebContents(adapterClient, d->browserContextAdapter->browserContext())); // This might replace any adapter that has been initialized with this WebEngineSettings. adapterClient->webEngineSettings()->setWebContentsAdapter(this); @@ -421,9 +453,22 @@ void WebContentsAdapter::reload() void WebContentsAdapter::load(const QUrl &url) { + // The situation can occur when relying on the editingFinished signal in QML to set the url + // of the WebView. + // When enter is pressed, onEditingFinished fires and the url of the webview is set, which + // calls into this and focuses the webview, taking the focus from the TextField/TextInput, + // which in turn leads to editingFinished firing again. This scenario would cause a crash + // down the line when unwinding as the first RenderWidgetHostViewQtDelegateQuick instance is + // a dangling pointer by that time. + + if (LoadRecursionGuard::isGuarded(this)) + return; + LoadRecursionGuard guard(this); + Q_UNUSED(guard); + Q_D(WebContentsAdapter); content::NavigationController::LoadURLParams params(toGurl(url)); - params.transition_type = content::PageTransitionFromInt(content::PAGE_TRANSITION_TYPED | content::PAGE_TRANSITION_FROM_ADDRESS_BAR); + params.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); d->webContents->GetController().LoadURLWithParams(params); d->webContents->Focus(); } @@ -623,17 +668,30 @@ qreal WebContentsAdapter::currentZoomFactor() const return content::ZoomLevelToZoomFactor(content::HostZoomMap::GetZoomLevel(d->webContents.get())); } -void WebContentsAdapter::enableInspector(bool enable) +BrowserContextQt* WebContentsAdapter::browserContext() { - ContentBrowserClientQt::Get()->enableInspector(enable); + Q_D(WebContentsAdapter); + return d->browserContextAdapter ? d->browserContextAdapter->browserContext() : d->webContents ? static_cast<BrowserContextQt*>(d->webContents->GetBrowserContext()) : 0; +} + +BrowserContextAdapter* WebContentsAdapter::browserContextAdapter() +{ + Q_D(WebContentsAdapter); + return d->browserContextAdapter ? d->browserContextAdapter.data() : d->webContents ? static_cast<BrowserContextQt*>(d->webContents->GetBrowserContext())->adapter() : 0; } +#ifndef QT_NO_ACCESSIBILITY QAccessibleInterface *WebContentsAdapter::browserAccessible() { Q_D(const WebContentsAdapter); - RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt*>(d->webContents->GetRenderWidgetHostView()); - return rwhv ? rwhv->GetQtAccessible() : Q_NULLPTR; + content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); + Q_ASSERT(rvh); + content::BrowserAccessibilityManager *manager = static_cast<content::RenderFrameHostImpl*>(rvh->GetMainFrame())->GetOrCreateBrowserAccessibilityManager(); + content::BrowserAccessibility *acc = manager->GetRoot(); + content::BrowserAccessibilityQt *accQt = static_cast<content::BrowserAccessibilityQt*>(acc); + return accQt; } +#endif // QT_NO_ACCESSIBILITY void WebContentsAdapter::runJavaScript(const QString &javaScript) { @@ -700,7 +758,7 @@ void WebContentsAdapter::stopFinding() d->webContents->StopFinding(content::STOP_FIND_ACTION_KEEP_SELECTION); } -void WebContentsAdapter::updateWebPreferences(const WebPreferences & webPreferences) +void WebContentsAdapter::updateWebPreferences(const content::WebPreferences & webPreferences) { Q_D(WebContentsAdapter); d->webContents->GetRenderViewHost()->UpdateWebkitPreferences(webPreferences); @@ -724,6 +782,26 @@ 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->geolocationPermissionReply(securityOrigin, allowed); +} + +void WebContentsAdapter::grantMouseLockPermission(bool granted) +{ + Q_D(WebContentsAdapter); + + if (granted) { + if (RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt *>(d->webContents->GetRenderWidgetHostView())) + rwhv->Focus(); + else + granted = false; + } + + d->webContents->GotResponseToLockMouseRequest(granted); +} + void WebContentsAdapter::dpiScaleChanged() { Q_D(WebContentsAdapter); @@ -734,6 +812,11 @@ void WebContentsAdapter::dpiScaleChanged() impl->NotifyScreenInfoChanged(); } +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Open, content::FileChooserParams::Open) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::OpenMultiple, content::FileChooserParams::OpenMultiple) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::UploadFolder, content::FileChooserParams::UploadFolder) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Save, content::FileChooserParams::Save) + void WebContentsAdapter::filesSelectedInChooser(const QStringList &fileList, WebContentsAdapterClient::FileChooserMode mode) { Q_D(WebContentsAdapter); @@ -743,5 +826,35 @@ void WebContentsAdapter::filesSelectedInChooser(const QStringList &fileList, Web if (mode == WebContentsAdapterClient::UploadFolder && !fileList.isEmpty() && QFileInfo(fileList.first()).isDir()) // Enumerate the directory files = listRecursively(QDir(fileList.first())); - rvh->FilesSelectedInChooser(toVector<ui::SelectedFileInfo>(files), static_cast<content::FileChooserParams::Mode>(mode)); + rvh->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(mode)); +} + +content::WebContents *WebContentsAdapter::webContents() const +{ + Q_D(const WebContentsAdapter); + return d->webContents.get(); +} + +QWebChannel *WebContentsAdapter::webChannel() const +{ + Q_D(const WebContentsAdapter); + return d->webChannel; +} + +void WebContentsAdapter::setWebChannel(QWebChannel *channel) +{ + Q_D(WebContentsAdapter); + if (d->webChannel == channel) + return; + if (!d->webChannelTransport.get()) + d->webChannelTransport.reset(new WebChannelIPCTransportHost(d->webContents.get())); + else + d->webChannel->disconnectFrom(d->webChannelTransport.get()); + + d->webChannel = channel; + if (!channel) { + d->webChannelTransport.reset(); + return; + } + channel->connectTo(d->webChannelTransport.get()); } diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 6bec50316..6ba7c4b0a 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -47,11 +47,16 @@ namespace content { class WebContents; +struct WebPreferences; } +class BrowserContextQt; +class MessagePassingInterface; class WebContentsAdapterPrivate; -struct WebPreferences; -QT_FORWARD_DECLARE_CLASS(QAccessibleInterface); +QT_BEGIN_NAMESPACE +class QAccessibleInterface; +class QWebChannel; +QT_END_NAMESPACE class QWEBENGINE_EXPORT WebContentsAdapter : public QSharedData { public: @@ -95,7 +100,6 @@ public: void serializeNavigationHistory(QDataStream &output); void setZoomFactor(qreal); qreal currentZoomFactor() const; - void enableInspector(bool); void filesSelectedInChooser(const QStringList &fileList, WebContentsAdapterClient::FileChooserMode); void runJavaScript(const QString &javaScript); quint64 runJavaScriptCallbackResult(const QString &javaScript); @@ -103,19 +107,28 @@ public: quint64 fetchDocumentInnerText(); quint64 findText(const QString &subString, bool caseSensitively, bool findBackward); void stopFinding(); - void updateWebPreferences(const WebPreferences &webPreferences); + void updateWebPreferences(const content::WebPreferences &webPreferences); void wasShown(); void wasHidden(); void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); + void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed); + void grantMouseLockPermission(bool granted); void dpiScaleChanged(); QAccessibleInterface *browserAccessible(); + BrowserContextQt* browserContext(); + BrowserContextAdapter* browserContextAdapter(); + QWebChannel *webChannel() const; + void setWebChannel(QWebChannel *); + + // meant to be used within WebEngineCore only + content::WebContents *webContents() const; 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..26d7a03ea 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -46,9 +46,11 @@ #include <QStringList> #include <QUrl> +QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QVariant) +QT_FORWARD_DECLARE_CLASS(CertificateErrorController) -class CertificateErrorController; +class BrowserContextAdapter; class JavaScriptDialogController; class RenderWidgetHostViewQt; class RenderWidgetHostViewQtDelegate; @@ -153,6 +155,7 @@ public: virtual void loadVisuallyCommitted() = 0; virtual void loadFinished(bool success, const QUrl &url, int errorCode = 0, const QString &errorDescription = QString()) = 0; virtual void focusContainer() = 0; + virtual void unhandledKeyEvent(QKeyEvent *event) = 0; virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry) = 0; virtual void close() = 0; virtual bool contextMenuRequested(const WebEngineContextMenuData&) = 0; @@ -168,13 +171,19 @@ public: virtual void passOnFocus(bool reverse) = 0; // returns the last QObject (QWidget/QQuickItem) based object in the accessibility // hierarchy before going into the BrowserAccessibility tree +#ifndef QT_NO_ACCESSIBILITY virtual QObject *accessibilityParentObject() = 0; +#endif // QT_NO_ACCESSIBILITY 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 void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual WebEngineSettings *webEngineSettings() const = 0; - virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController) = 0; + virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) = 0; + + virtual BrowserContextAdapter* browserContextAdapter() = 0; }; diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 28df0113a..dcdf97f2e 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -42,19 +42,27 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include <QExplicitlySharedDataPointer> + +class BrowserContextAdapter; class QtRenderViewObserverHost; +class WebChannelIPCTransportHost; class WebContentsAdapterClient; class WebContentsDelegateQt; class WebEngineContext; +QT_FORWARD_DECLARE_CLASS(QWebChannel) class WebContentsAdapterPrivate { public: WebContentsAdapterPrivate(); ~WebContentsAdapterPrivate(); scoped_refptr<WebEngineContext> engineContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> browserContextAdapter; scoped_ptr<content::WebContents> webContents; scoped_ptr<WebContentsDelegateQt> webContentsDelegate; scoped_ptr<QtRenderViewObserverHost> renderViewObserverHost; + scoped_ptr<WebChannelIPCTransportHost> webChannelTransport; + QWebChannel *webChannel; WebContentsAdapterClient *adapterClient; quint64 nextRequestId; int lastFindRequestId; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index c2cccfedb..03e03acc3 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" @@ -52,12 +53,13 @@ #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/favicon_url.h" #include "content/public/common/file_chooser_params.h" #include "content/public/common/frame_navigate_params.h" #include "content/public/common/url_constants.h" -#include "webkit/common/webpreferences.h" +#include "content/public/common/web_preferences.h" // Maps the LogSeverity defines in base/logging.h to the web engines message levels. static WebContentsAdapterClient::JavaScriptConsoleMessageLevel mapToJavascriptConsoleMessageLevel(int32 messageLevel) { @@ -83,7 +85,7 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents if (params.disposition != CURRENT_TAB) { WebContentsAdapter *targetAdapter = createWindow(0, params.disposition, gfx::Rect(), params.user_gesture); if (targetAdapter) - target = targetAdapter->d_func()->webContents.get(); + target = targetAdapter->webContents(); } content::NavigationController::LoadURLParams load_url_params(params.url); @@ -101,7 +103,7 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents return target; } -void WebContentsDelegateQt::NavigationStateChanged(const content::WebContents* source, unsigned changed_flags) +void WebContentsDelegateQt::NavigationStateChanged(const content::WebContents* source, content::InvalidateTypes changed_flags) { if (changed_flags & content::INVALIDATE_TYPE_URL) m_viewClient->urlChanged(toQt(source->GetVisibleURL())); @@ -129,21 +131,28 @@ void WebContentsDelegateQt::LoadProgressChanged(content::WebContents* source, do m_viewClient->loadProgressChanged(qRound(progress * 100)); } -void WebContentsDelegateQt::DidStartProvisionalLoadForFrame(int64 frame_id, int64 parent_frame_id, bool is_main_frame, const GURL &validated_url, bool isErrorPage, bool, content::RenderViewHost*) +void WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const content::NativeWebKeyboardEvent &event) { - if (isErrorPage) { - m_loadingErrorFrameList.append(frame_id); + Q_ASSERT(!event.skip_in_browser); + if (event.os_event) + m_viewClient->unhandledKeyEvent(reinterpret_cast<QKeyEvent *>(event.os_event)); +} + +void WebContentsDelegateQt::DidStartProvisionalLoadForFrame(content::RenderFrameHost* render_frame_host, const GURL& validated_url, bool is_error_page, bool is_iframe_srcdoc) +{ + if (is_error_page) { + m_loadingErrorFrameList.append(render_frame_host->GetRoutingID()); return; } - if (!is_main_frame) + if (render_frame_host->GetParent()) return; m_loadingErrorFrameList.clear(); m_viewClient->loadStarted(toQt(validated_url)); } -void WebContentsDelegateQt::DidCommitProvisionalLoadForFrame(int64 frame_id, const base::string16& frame_unique_name, bool is_main_frame, const GURL& url, content::PageTransition transition_type, content::RenderViewHost* render_view_host) +void WebContentsDelegateQt::DidCommitProvisionalLoadForFrame(content::RenderFrameHost* render_frame_host, const GURL& url, ui::PageTransition transition_type) { // Make sure that we don't set the findNext WebFindOptions on a new frame. m_lastSearchedString = QString(); @@ -152,32 +161,32 @@ void WebContentsDelegateQt::DidCommitProvisionalLoadForFrame(int64 frame_id, con m_viewClient->loadCommitted(); } -void WebContentsDelegateQt::DidFailProvisionalLoad(int64 frame_id, const base::string16& frame_unique_name, bool is_main_frame, const GURL& validated_url, int error_code, const base::string16& error_description, content::RenderViewHost* render_view_host) +void WebContentsDelegateQt::DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) { - DidFailLoad(frame_id, validated_url, is_main_frame, error_code, error_description, render_view_host); + DidFailLoad(render_frame_host, validated_url, error_code, error_description); } -void WebContentsDelegateQt::DidFailLoad(int64 frame_id, const GURL &validated_url, bool is_main_frame, int error_code, const base::string16 &error_description, content::RenderViewHost *rvh) +void WebContentsDelegateQt::DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) { - if (m_loadingErrorFrameList.removeOne(frame_id) || !is_main_frame) + if (m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID()) || render_frame_host->GetParent()) return; m_viewClient->loadFinished(false, toQt(validated_url), error_code, toQt(error_description)); m_viewClient->loadProgressChanged(0); } -void WebContentsDelegateQt::DidFinishLoad(int64 frame_id, const GURL &url, bool is_main_frame, content::RenderViewHost*) +void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) { - if (m_loadingErrorFrameList.removeOne(frame_id)) { - Q_ASSERT(url.is_valid() && url.spec() == content::kUnreachableWebDataURL); + if (m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID())) { + Q_ASSERT(validated_url.is_valid() && validated_url.spec() == content::kUnreachableWebDataURL); m_viewClient->iconChanged(QUrl()); return; } - if (!is_main_frame) + if (render_frame_host->GetParent()) return; - m_viewClient->loadFinished(true, toQt(url)); + m_viewClient->loadFinished(true, toQt(validated_url)); content::NavigationEntry *entry = web_contents()->GetController().GetActiveEntry(); if (!entry) @@ -222,8 +231,8 @@ bool WebContentsDelegateQt::IsFullscreenForTabOrPending(const content::WebConten return m_viewClient->isFullScreen(); } -Q_STATIC_ASSERT_X(static_cast<int>(WebContentsAdapterClient::Open) == static_cast<int>(content::FileChooserParams::Open), "Enums out of sync"); -Q_STATIC_ASSERT_X(static_cast<int>(WebContentsAdapterClient::Save) == static_cast<int>(content::FileChooserParams::Save), "Enums out of sync"); +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Open, content::FileChooserParams::Open) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Save, content::FileChooserParams::Save) void WebContentsDelegateQt::RunFileChooser(content::WebContents *web_contents, const content::FileChooserParams ¶ms) { @@ -259,22 +268,31 @@ void WebContentsDelegateQt::RequestMediaAccessPermission(content::WebContents *w MediaCaptureDevicesDispatcher::GetInstance()->processMediaAccessRequest(m_viewClient, web_contents, request, callback); } -void WebContentsDelegateQt::UpdateTargetURL(content::WebContents *source, int32 page_id, const GURL &url) +void WebContentsDelegateQt::UpdateTargetURL(content::WebContents* source, const GURL& url) { Q_UNUSED(source) - Q_UNUSED(page_id) m_viewClient->didUpdateTargetURL(toQt(url)); } -void WebContentsDelegateQt::DidNavigateAnyFrame(const content::LoadCommittedDetails &, const content::FrameNavigateParams ¶ms) +void WebContentsDelegateQt::DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) { - if (!params.should_update_history) + // VisistedLinksMaster asserts !IsOffTheRecord(). + if (!params.should_update_history || !m_viewClient->browserContextAdapter()->trackVisitedLinks()) return; - WebEngineContext::current()->visitedLinksManager()->addUrl(params.url); + m_viewClient->browserContextAdapter()->visitedLinksManager()->addUrl(params.url); } +void WebContentsDelegateQt::RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) +{ + Q_UNUSED(user_gesture); -void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *, WebPreferences *webPreferences) + if (last_unlocked_by_target) + web_contents->GotResponseToLockMouseRequest(true); + else + m_viewClient->runMouseLockPermissionRequest(toQt(web_contents->GetVisibleURL())); +} + +void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *, content::WebPreferences *webPreferences) { m_viewClient->webEngineSettings()->overrideWebPreferences(webPreferences); } @@ -296,7 +314,30 @@ WebContentsAdapter *WebContentsDelegateQt::createWindow(content::WebContents *ne return newAdapter; } -void WebContentsDelegateQt::allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController) +void WebContentsDelegateQt::allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) { m_viewClient->allowCertificateError(errorController); } + +void WebContentsDelegateQt::requestGeolocationPermission(const GURL &requestingFrameOrigin, const base::Callback<void (bool)> &resultCallback) +{ + QUrl url = toQt(requestingFrameOrigin); + bool newRequest = !m_geolocationPermissionRequests.contains(url); + m_geolocationPermissionRequests[url] = resultCallback; + if (newRequest) + m_viewClient->runGeolocationPermissionRequest(url); +} + +void WebContentsDelegateQt::cancelGeolocationPermissionRequest(const GURL &requestingFrameOrigin) +{ + m_geolocationPermissionRequests.remove(toQt(requestingFrameOrigin)); + // FIXME: Tell the API layer to cancel the permission request? +} + +void WebContentsDelegateQt::geolocationPermissionReply(const QUrl &origin, bool permission) +{ + if (m_geolocationPermissionRequests.contains(origin)) { + m_geolocationPermissionRequests[origin].Run(permission); + m_geolocationPermissionRequests.remove(origin); + } +} diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 2ab5fc8cd..f3b231798 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -40,20 +40,23 @@ #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> +QT_FORWARD_DECLARE_CLASS(CertificateErrorController) + namespace content { class BrowserContext; class SiteInstance; class RenderViewHost; class JavaScriptDialogManager; class WebContents; + struct WebPreferences; } -struct WebPreferences; class WebContentsAdapterClient; -class CertificateErrorController; class WebContentsDelegateQt : public content::WebContentsDelegate , public content::WebContentsObserver @@ -65,17 +68,13 @@ public: void setLastSearchedString(const QString &s) { m_lastSearchedString = s; } int lastReceivedFindReply() const { return m_lastReceivedFindReply; } + // WebContentsDelegate overrides virtual content::WebContents *OpenURLFromTab(content::WebContents *source, const content::OpenURLParams ¶ms) Q_DECL_OVERRIDE; - virtual void NavigationStateChanged(const content::WebContents* source, unsigned changed_flags) Q_DECL_OVERRIDE; + virtual void NavigationStateChanged(const content::WebContents* source, content::InvalidateTypes changed_flags) Q_DECL_OVERRIDE; virtual void AddNewContents(content::WebContents* source, content::WebContents* new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture, bool* was_blocked) Q_DECL_OVERRIDE; virtual void CloseContents(content::WebContents *source) Q_DECL_OVERRIDE; virtual void LoadProgressChanged(content::WebContents* source, double progress) Q_DECL_OVERRIDE; - virtual void DidStartProvisionalLoadForFrame(int64 frame_id, int64 parent_frame_id, bool is_main_frame, const GURL &validated_url, bool is_error_page, bool is_iframe_srcdoc, content::RenderViewHost *render_view_host) Q_DECL_OVERRIDE; - virtual void DidCommitProvisionalLoadForFrame(int64 frame_id, const base::string16& frame_unique_name, bool is_main_frame, const GURL& url, content::PageTransition transition_type, content::RenderViewHost* render_view_host) Q_DECL_OVERRIDE; - virtual void DidFailProvisionalLoad(int64 frame_id, const base::string16& frame_unique_name, bool is_main_frame, const GURL& validated_url, int error_code, const base::string16& error_description, content::RenderViewHost* render_view_host) Q_DECL_OVERRIDE; - virtual void DidFailLoad(int64 frame_id, const GURL &validated_url, bool is_main_frame, int error_code, const base::string16 &error_description, content::RenderViewHost *render_view_host) Q_DECL_OVERRIDE; - virtual void DidFinishLoad(int64 frame_id, const GURL &validated_url, bool is_main_frame, content::RenderViewHost *render_view_host) Q_DECL_OVERRIDE; - virtual void DidUpdateFaviconURL(const std::vector<content::FaviconURL>& candidates) Q_DECL_OVERRIDE; + virtual void HandleKeyboardEvent(content::WebContents *source, const content::NativeWebKeyboardEvent &event) Q_DECL_OVERRIDE; virtual content::JavaScriptDialogManager *GetJavaScriptDialogManager() Q_DECL_OVERRIDE; virtual void ToggleFullscreenModeForTab(content::WebContents* web_contents, bool enter_fullscreen) Q_DECL_OVERRIDE; virtual bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const Q_DECL_OVERRIDE; @@ -83,15 +82,29 @@ public: virtual bool AddMessageToConsole(content::WebContents* source, int32 level, const base::string16& message, int32 line_no, const base::string16& source_id) Q_DECL_OVERRIDE; virtual void FindReply(content::WebContents *source, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) Q_DECL_OVERRIDE; virtual void RequestMediaAccessPermission(content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) Q_DECL_OVERRIDE; - virtual void UpdateTargetURL(content::WebContents *source, int32 page_id, const GURL &url) Q_DECL_OVERRIDE; - virtual void DidNavigateAnyFrame(const content::LoadCommittedDetails&, const content::FrameNavigateParams& params) Q_DECL_OVERRIDE; + virtual void UpdateTargetURL(content::WebContents* source, const GURL& url) Q_DECL_OVERRIDE; + virtual void RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) Q_DECL_OVERRIDE; - void overrideWebPreferences(content::WebContents *, WebPreferences*); - void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &) ; + // WebContentsObserver overrides + virtual void DidStartProvisionalLoadForFrame(content::RenderFrameHost *render_frame_host, const GURL &validated_url, bool is_error_page, bool is_iframe_srcdoc) Q_DECL_OVERRIDE; + virtual void DidCommitProvisionalLoadForFrame(content::RenderFrameHost *render_frame_host, const GURL &url, ui::PageTransition transition_type) Q_DECL_OVERRIDE; + virtual void DidFailProvisionalLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url, int error_code, const base::string16 &error_description) Q_DECL_OVERRIDE; + virtual void DidFailLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url, int error_code, const base::string16 &error_description) Q_DECL_OVERRIDE; + virtual void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) Q_DECL_OVERRIDE; + virtual void DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) Q_DECL_OVERRIDE; + virtual void DidNavigateAnyFrame(content::RenderFrameHost *render_frame_host, const content::LoadCommittedDetails &details, const content::FrameNavigateParams ¶ms) Q_DECL_OVERRIDE; + + void overrideWebPreferences(content::WebContents *, content::WebPreferences*); + void allowCertificateError(const QSharedPointer<CertificateErrorController> &) ; + void requestGeolocationPermission(const GURL &requestingFrameOrigin, const base::Callback<void (bool)> &resultCallback); + void cancelGeolocationPermissionRequest(const GURL &requestingFrameOrigin); + void geolocationPermissionReply(const QUrl&, bool permission); private: WebContentsAdapter *createWindow(content::WebContents *new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); + QHash<QUrl, base::Callback<void (bool)> > m_geolocationPermissionRequests; + WebContentsAdapterClient *m_viewClient; QString m_lastSearchedString; int m_lastReceivedFindReply; diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 5909ee510..af5b6dd19 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -54,7 +54,7 @@ void WebContentsViewQt::initialize(WebContentsAdapterClient* client) static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())->setAdapterClient(client); } -content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(content::RenderWidgetHost* render_widget_host) +content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) { RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index d433718a7..5e8ff0f96 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -59,12 +59,13 @@ public: : m_webContents(webContents) , m_client(0) , m_factoryClient(0) + , m_allowOtherViews(false) { } void initialize(WebContentsAdapterClient* client); WebContentsAdapterClient *client() { return m_client; } - virtual content::RenderWidgetHostViewBase *CreateViewForWidget(content::RenderWidgetHost* render_widget_host) Q_DECL_OVERRIDE; + virtual content::RenderWidgetHostViewBase *CreateViewForWidget(content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) Q_DECL_OVERRIDE; virtual void CreateView(const gfx::Size& initial_size, gfx::NativeView context) Q_DECL_OVERRIDE; @@ -100,9 +101,6 @@ public: virtual gfx::Rect GetViewBounds() const Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED return gfx::Rect(); } - virtual void ShowPopupMenu(const gfx::Rect& bounds, int item_height, double item_font_size, int selected_item, - const std::vector<content::MenuItem>& items, bool right_aligned, bool allow_multiple_selection) Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } - virtual void StartDragging(const content::DropData& drop_data, blink::WebDragOperationsMask allowed_ops, const gfx::ImageSkia& image, const gfx::Vector2d& image_offset, const content::DragEventSourceInfo& event_info) Q_DECL_OVERRIDE; virtual void ShowContextMenu(content::RenderFrameHost *, const content::ContextMenuParams ¶ms) Q_DECL_OVERRIDE; @@ -110,9 +108,9 @@ public: virtual void TakeFocus(bool reverse) Q_DECL_OVERRIDE; #if defined(OS_MACOSX) - virtual void SetAllowOverlappingViews(bool overlapping) Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } + virtual void SetAllowOtherViews(bool allow) Q_DECL_OVERRIDE { m_allowOtherViews = allow; } + virtual bool GetAllowOtherViews() const Q_DECL_OVERRIDE { return m_allowOtherViews; } virtual void CloseTabAfterEventTracking() Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } - virtual bool GetAllowOverlappingViews() const Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED; return false; } virtual bool IsEventTracking() const Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED; return false; } virtual void SetOverlayView(WebContentsView* overlay, const gfx::Point& offset) { QT_NOT_YET_IMPLEMENTED } virtual void RemoveOverlayView() { QT_NOT_YET_IMPLEMENTED } @@ -122,6 +120,7 @@ private: content::WebContents *m_webContents; WebContentsAdapterClient *m_client; WebContentsAdapterClient *m_factoryClient; + bool m_allowOtherViews; }; #endif // WEB_CONTENTS_VIEW_QT_H diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 446f0e92c..df649606c 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -66,15 +66,17 @@ #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" +#include "dev_tools_http_handler_delegate_qt.h" #include "gl_context_qt.h" #include "media_capture_devices_dispatcher.h" #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> @@ -90,6 +92,46 @@ void destroyContext() sContext = 0; } +bool usingANGLE() +{ +#if defined(Q_OS_WIN) + return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES; +#else + return false; +#endif +} + +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() @@ -103,7 +145,7 @@ WebEngineContext::~WebEngineContext() scoped_refptr<WebEngineContext> WebEngineContext::current() { - if (!sContext) { + if (!sContext.get()) { sContext = new WebEngineContext(); // Make sure that we ramp down Chromium before QApplication destroys its X connection, etc. qAddPostRoutine(destroyContext); @@ -111,9 +153,18 @@ scoped_refptr<WebEngineContext> WebEngineContext::current() return sContext; } -WebEngineVisitedLinksManager *WebEngineContext::visitedLinksManager() +BrowserContextAdapter* WebEngineContext::defaultBrowserContext() +{ + if (!m_defaultBrowserContext) + m_defaultBrowserContext = new BrowserContextAdapter(QStringLiteral("Default")); + return m_defaultBrowserContext.data(); +} + +BrowserContextAdapter* WebEngineContext::offTheRecordBrowserContext() { - return m_visitedLinksManager.get(); + if (!m_offTheRecordBrowserContext) + m_offTheRecordBrowserContext = new BrowserContextAdapter(true); + return m_offTheRecordBrowserContext.data(); } #ifndef CHROMIUM_VERSION @@ -142,16 +193,6 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kEnableDelegatedRenderer); parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing); parsedCommandLine->AppendSwitch(switches::kInProcessGPU); - parsedCommandLine->AppendSwitch(switches::kDisableDesktopNotifications); - -#if defined(OS_WIN) - parsedCommandLine->AppendSwitch(switches::kDisableD3D11); - // ANGLE doesn't support multi-threading, doing texture upload from the GPU thread - // hasn't been causing problems yet but doing rendering there is conflicting with - // Qt's rendering of the scene graph. - parsedCommandLine->AppendSwitch(switches::kDisableExperimentalWebGL); - parsedCommandLine->AppendSwitch(switches::kDisableAccelerated2dCanvas); -#endif #if defined(QTWEBENGINE_MOBILE_SWITCHES) // Inspired from the Android port's default switches @@ -180,16 +221,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 (usingANGLE() || usingSoftwareDynamicGL() || usingQtQuick2DRenderer()) { + parsedCommandLine->AppendSwitch(switches::kDisableGpu); + } else { + const char *glType = 0; + 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); @@ -209,11 +254,9 @@ WebEngineContext::WebEngineContext() m_runLoop.reset(new base::RunLoop); m_runLoop->BeforeRun(); + m_devtools.reset(new DevToolsHttpHandlerDelegateQt); // Force the initialization of MediaCaptureDevicesDispatcher on the UI // 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..80ce65507 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -40,6 +40,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include <QExplicitlySharedDataPointer> + namespace base { class RunLoop; } @@ -49,15 +51,17 @@ class BrowserMainRunner; class ContentMainRunner; } +class BrowserContextAdapter; class ContentMainDelegateQt; +class DevToolsHttpHandlerDelegateQt; 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 +75,9 @@ private: #if defined(OS_ANDROID) scoped_ptr<SurfaceFactoryQt> m_surfaceFactory; #endif - scoped_ptr<WebEngineVisitedLinksManager> m_visitedLinksManager; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_defaultBrowserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_offTheRecordBrowserContext; + scoped_ptr<DevToolsHttpHandlerDelegateQt> m_devtools; }; #endif // WEB_ENGINE_CONTEXT_H diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 2d72dd5a2..110c9ae6a 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -38,7 +38,7 @@ #include "web_engine_library_info.h" #include "base/base_paths.h" -#include "base/file_util.h" +#include "base/files/file_util.h" #include "content/public/common/content_paths.h" #include "ui/base/ui_base_paths.h" #include "type_conversion.h" @@ -78,7 +78,7 @@ QString location(QLibraryInfo::LibraryLocation path) switch (path) { case QLibraryInfo::TranslationsPath: if (!webEnginePath.isEmpty()) - return webEnginePath % QDir::separator() % QLatin1String("translations"); + return webEnginePath % QLatin1String("/translations"); break; case QLibraryInfo::DataPath: if (!webEnginePath.isEmpty()) @@ -148,7 +148,7 @@ QString subProcessPath() % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME)); #else static QString processPath (location(QLibraryInfo::LibraryExecutablesPath) - % QDir::separator() % processBinary); + % QLatin1Char('/') % processBinary); #endif if (!initialized) { // Allow overriding at runtime for the time being. @@ -157,7 +157,7 @@ QString subProcessPath() processPath = QString::fromLatin1(fromEnv); if (!QFileInfo(processPath).exists()) { qWarning("QtWebEngineProcess not found at location %s. Trying fallback path...", qPrintable(processPath)); - processPath = QCoreApplication::applicationDirPath() % QDir::separator() % processBinary; + processPath = QCoreApplication::applicationDirPath() % QLatin1Char('/') % processBinary; } if (!QFileInfo(processPath).exists()) qFatal("QtWebEngineProcess not found at location %s. Try setting the QTWEBENGINEPROCESS_PATH environment variable.", qPrintable(processPath)); @@ -172,7 +172,7 @@ QString pluginsPath() #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) return getPath(frameworkBundle()) % QLatin1String("/Libraries"); #else - return location(QLibraryInfo::PluginsPath) % QDir::separator() % QLatin1String("qtwebengine"); + return location(QLibraryInfo::PluginsPath) % QLatin1String("/qtwebengine"); #endif } @@ -186,7 +186,7 @@ QString localesPath() } QString fallbackDir() { - static QString directory = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); + static QString directory = QDir::homePath() % QLatin1String("/.") % QCoreApplication::applicationName(); return directory; } diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 9b070d3b2..0aaa09814 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -38,7 +38,7 @@ #include "web_contents_adapter.h" #include "type_conversion.h" -#include "webkit/common/webpreferences.h" +#include "content/public/common/web_preferences.h" #include <QFont> #include <QTimer> @@ -67,7 +67,6 @@ private: WebEngineSettings *m_settings; }; -#include "web_engine_settings.moc" static inline bool isTouchScreenAvailable() { static bool initialized = false; @@ -85,19 +84,26 @@ static inline bool isTouchScreenAvailable() { } -WebEngineSettings::WebEngineSettings(WebEngineSettingsDelegate *delegate) +WebEngineSettings::WebEngineSettings(WebEngineSettings *_parentSettings) : m_adapter(0) - , m_delegate(delegate) , m_batchTimer(new BatchTimer(this)) + , parentSettings(_parentSettings) { - Q_ASSERT(delegate); + if (parentSettings) + parentSettings->childSettings.insert(this); } WebEngineSettings::~WebEngineSettings() { + if (parentSettings) + parentSettings->childSettings.remove(this); + // In QML the profile and its settings may be garbage collected before the page and its settings. + Q_FOREACH (WebEngineSettings *settings, childSettings) { + settings->parentSettings = 0; + } } -void WebEngineSettings::overrideWebPreferences(WebPreferences *prefs) +void WebEngineSettings::overrideWebPreferences(content::WebPreferences *prefs) { // Apply our settings on top of those. applySettingsToWebPreferences(prefs); @@ -105,100 +111,92 @@ void WebEngineSettings::overrideWebPreferences(WebPreferences *prefs) // as the host process already overides some of the default WebPreferences values // before we get here (e.g. number_of_cpu_cores). if (webPreferences.isNull()) - webPreferences.reset(new WebPreferences(*prefs)); + webPreferences.reset(new content::WebPreferences(*prefs)); } void WebEngineSettings::setAttribute(WebEngineSettings::Attribute attr, bool on) { m_attributes.insert(attr, on); - m_delegate->apply(); + scheduleApplyRecursively(); } bool WebEngineSettings::testAttribute(WebEngineSettings::Attribute attr) const { - WebEngineSettings *fallback = m_delegate->fallbackSettings(); - Q_ASSERT(fallback); - if (this == fallback) { + if (!parentSettings) { Q_ASSERT(m_attributes.contains(attr)); return m_attributes.value(attr); } - return m_attributes.value(attr, fallback->testAttribute(attr)); + return m_attributes.value(attr, parentSettings->testAttribute(attr)); } void WebEngineSettings::resetAttribute(WebEngineSettings::Attribute attr) { - if (this == m_delegate->fallbackSettings()) + if (!parentSettings) // FIXME: Set initial defaults. return; m_attributes.remove(attr); - m_delegate->apply(); + scheduleApplyRecursively(); } void WebEngineSettings::setFontFamily(WebEngineSettings::FontFamily which, const QString &family) { m_fontFamilies.insert(which, family); - m_delegate->apply(); + scheduleApplyRecursively(); } QString WebEngineSettings::fontFamily(WebEngineSettings::FontFamily which) { - WebEngineSettings *fallback = m_delegate->fallbackSettings(); - Q_ASSERT(fallback); - if (this == fallback) { + if (!parentSettings) { Q_ASSERT(m_fontFamilies.contains(which)); return m_fontFamilies.value(which); } - return m_fontFamilies.value(which, fallback->fontFamily(which)); + return m_fontFamilies.value(which, parentSettings->fontFamily(which)); } void WebEngineSettings::resetFontFamily(WebEngineSettings::FontFamily which) { - if (this == m_delegate->fallbackSettings()) + if (!parentSettings) // FIXME: Set initial defaults. return; m_fontFamilies.remove(which); - m_delegate->apply(); + scheduleApplyRecursively(); } void WebEngineSettings::setFontSize(WebEngineSettings::FontSize type, int size) { m_fontSizes.insert(type, size); - m_delegate->apply(); + scheduleApplyRecursively(); } int WebEngineSettings::fontSize(WebEngineSettings::FontSize type) const { - WebEngineSettings *fallback = m_delegate->fallbackSettings(); - Q_ASSERT(fallback); - if (this == fallback) { + if (!parentSettings) { Q_ASSERT(m_fontSizes.contains(type)); return m_fontSizes.value(type); } - return m_fontSizes.value(type, fallback->fontSize(type)); + return m_fontSizes.value(type, parentSettings->fontSize(type)); } void WebEngineSettings::resetFontSize(WebEngineSettings::FontSize type) { - if (this == m_delegate->fallbackSettings()) + if (!parentSettings) // FIXME: Set initial defaults. return; m_fontSizes.remove(type); - m_delegate->apply(); + scheduleApplyRecursively(); } void WebEngineSettings::setDefaultTextEncoding(const QString &encoding) { m_defaultEncoding = encoding; - m_delegate->apply(); + scheduleApplyRecursively(); } QString WebEngineSettings::defaultTextEncoding() const { - WebEngineSettings *fallback = m_delegate->fallbackSettings(); - Q_ASSERT(fallback); - if (this == fallback) + if (!parentSettings) return m_defaultEncoding; - return m_defaultEncoding.isEmpty()? fallback->defaultTextEncoding() : m_defaultEncoding; + return m_defaultEncoding.isEmpty()? parentSettings->defaultTextEncoding() : m_defaultEncoding; } -void WebEngineSettings::initDefaults() +void WebEngineSettings::initDefaults(bool offTheRecord) { // Initialize the default settings. m_attributes.insert(AutoLoadImages, true); @@ -206,7 +204,7 @@ void WebEngineSettings::initDefaults() m_attributes.insert(JavascriptCanOpenWindows, true); m_attributes.insert(JavascriptCanAccessClipboard, false); m_attributes.insert(LinksIncludedInFocusChain, true); - m_attributes.insert(LocalStorageEnabled, true); + m_attributes.insert(LocalStorageEnabled, !offTheRecord); m_attributes.insert(LocalContentCanAccessRemoteUrls, false); m_attributes.insert(XSSAuditingEnabled, false); m_attributes.insert(SpatialNavigationEnabled, false); @@ -258,7 +256,7 @@ void WebEngineSettings::doApply() m_adapter->updateWebPreferences(*webPreferences.data()); } -void WebEngineSettings::applySettingsToWebPreferences(WebPreferences *prefs) +void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *prefs) { // Override for now prefs->java_enabled = false; @@ -280,17 +278,36 @@ void WebEngineSettings::applySettingsToWebPreferences(WebPreferences *prefs) prefs->enable_error_page = testAttribute(ErrorPageEnabled); // Fonts settings. - prefs->standard_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily(StandardFont)); - prefs->fixed_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily(FixedFont)); - prefs->serif_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily(SerifFont)); - prefs->sans_serif_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily(SansSerifFont)); - prefs->cursive_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily(CursiveFont)); - prefs->fantasy_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily(FantasyFont)); + prefs->standard_font_family_map[content::kCommonScript] = toString16(fontFamily(StandardFont)); + prefs->fixed_font_family_map[content::kCommonScript] = toString16(fontFamily(FixedFont)); + prefs->serif_font_family_map[content::kCommonScript] = toString16(fontFamily(SerifFont)); + prefs->sans_serif_font_family_map[content::kCommonScript] = toString16(fontFamily(SansSerifFont)); + prefs->cursive_font_family_map[content::kCommonScript] = toString16(fontFamily(CursiveFont)); + prefs->fantasy_font_family_map[content::kCommonScript] = toString16(fontFamily(FantasyFont)); // FIXME: add pictograph? - // prefs.pictograph_font_family_map[webkit_glue::kCommonScript] = toString16(fontFamily()); + // prefs.pictograph_font_family_map[content::kCommonScript] = toString16(fontFamily()); prefs->default_font_size = fontSize(DefaultFontSize); prefs->default_fixed_font_size = fontSize(DefaultFixedFontSize); prefs->minimum_font_size = fontSize(MinimumFontSize); prefs->minimum_logical_font_size = fontSize(MinimumLogicalFontSize); prefs->default_encoding = defaultTextEncoding().toStdString(); } + +void WebEngineSettings::scheduleApplyRecursively() +{ + scheduleApply(); + Q_FOREACH (WebEngineSettings *settings, childSettings) { + settings->scheduleApply(); + } +} + +void WebEngineSettings::setParentSettings(WebEngineSettings *_parentSettings) +{ + if (parentSettings) + parentSettings->childSettings.remove(this); + parentSettings = _parentSettings; + if (parentSettings) + parentSettings->childSettings.insert(this); +} + +#include "web_engine_settings.moc" diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index c098f8ef4..8ee7d8871 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -43,19 +43,15 @@ #include <QScopedPointer> #include <QHash> #include <QUrl> +#include <QSet> class BatchTimer; class WebContentsAdapter; class WebEngineSettings; -struct WebPreferences; -class QWEBENGINE_EXPORT WebEngineSettingsDelegate { -public: - virtual ~WebEngineSettingsDelegate() {} - virtual void apply() = 0; - // Needs to be a valid pointer, the last available fallback (ex: global settings) should return itself. - virtual WebEngineSettings *fallbackSettings() const = 0; -}; +namespace content { +struct WebPreferences; +} class QWEBENGINE_EXPORT WebEngineSettings { public: @@ -95,10 +91,12 @@ public: DefaultFixedFontSize }; - WebEngineSettings(WebEngineSettingsDelegate*); - virtual ~WebEngineSettings(); + explicit WebEngineSettings(WebEngineSettings *parentSettings = 0); + ~WebEngineSettings(); - void overrideWebPreferences(WebPreferences *prefs); + void setParentSettings(WebEngineSettings *parentSettings); + + void overrideWebPreferences(content::WebPreferences *prefs); void setAttribute(Attribute, bool on); bool testAttribute(Attribute) const; @@ -115,23 +113,27 @@ public: void setDefaultTextEncoding(const QString &encoding); QString defaultTextEncoding() const; - void initDefaults(); + void initDefaults(bool offTheRecord = false); void scheduleApply(); + void scheduleApplyRecursively(); + private: void doApply(); - void applySettingsToWebPreferences(WebPreferences *); + void applySettingsToWebPreferences(content::WebPreferences *); void setWebContentsAdapter(WebContentsAdapter *adapter) { m_adapter = adapter; } WebContentsAdapter* m_adapter; - WebEngineSettingsDelegate* m_delegate; QHash<Attribute, bool> m_attributes; QHash<FontFamily, QString> m_fontFamilies; QHash<FontSize, int> m_fontSizes; QString m_defaultEncoding; - QScopedPointer<WebPreferences> webPreferences; + QScopedPointer<content::WebPreferences> webPreferences; QScopedPointer<BatchTimer> m_batchTimer; + WebEngineSettings *parentSettings; + QSet<WebEngineSettings *> childSettings; + friend class BatchTimer; friend class WebContentsAdapter; }; diff --git a/src/core/web_engine_visited_links_manager.cpp b/src/core/web_engine_visited_links_manager.cpp index 36467ca21..c5ed54f3e 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,12 +81,17 @@ void WebEngineVisitedLinksManager::deleteVisitedLinkDataForUrls(const QList<QUrl m_visitedLinkMaster->DeleteURLs(&iterator); } -WebEngineVisitedLinksManager::WebEngineVisitedLinksManager() +bool WebEngineVisitedLinksManager::containsUrl(const QUrl &url) const +{ + return m_visitedLinkMaster->IsVisited(toGurl(url)); +} + +WebEngineVisitedLinksManager::WebEngineVisitedLinksManager(BrowserContextAdapter *adapter) : m_delegate(new VisitedLinkDelegateQt) { - Q_ASSERT(ContentBrowserClientQt::Get() && ContentBrowserClientQt::Get()->browser_context()); - BrowserContextQt *browserContext = ContentBrowserClientQt::Get()->browser_context(); - m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(browserContext, m_delegate.data(), /* persist to disk = */true)); + Q_ASSERT(adapter && adapter->browserContext()); + BrowserContextQt *browserContext = adapter->browserContext(); + m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(browserContext, m_delegate.data(), adapter->persistVisitedLinks())); 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..dc2a4bff2 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,11 +58,13 @@ class QWEBENGINE_EXPORT WebEngineVisitedLinksManager { public: virtual~WebEngineVisitedLinksManager(); - WebEngineVisitedLinksManager(); + WebEngineVisitedLinksManager(BrowserContextAdapter*); void deleteAllVisitedLinkData(); void deleteVisitedLinkDataForUrls(const QList<QUrl> &); + bool containsUrl(const QUrl &) const; + private: void addUrl(const GURL &); friend class WebContentsDelegateQt; diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 36e96121c..eacb59011 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -64,6 +64,7 @@ #include "web_event_factory.h" #include "third_party/WebKit/Source/platform/WindowsKeyboardCodes.h" +#include <QCoreApplication> #include <QElapsedTimer> #include <QKeyEvent> #include <QMouseEvent> @@ -131,313 +132,320 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode, bool isKeypad) return VK_INSERT; // (2D) INS key case Qt::Key_Delete: return VK_DELETE; // (2E) DEL key + case Qt::Key_Shift: + return VK_SHIFT; // (10) SHIFT key + case Qt::Key_Control: + return VK_CONTROL; // (11) CTRL key + case Qt::Key_Menu: + case Qt::Key_Alt: + return VK_MENU; // (12) ALT key default: return 0; } - } else - - switch (keycode) { - case Qt::Key_Backspace: - return VK_BACK; // (08) BACKSPACE key - case Qt::Key_Backtab: - case Qt::Key_Tab: - return VK_TAB; // (09) TAB key - case Qt::Key_Clear: - return VK_CLEAR; // (0C) CLEAR key - case Qt::Key_Enter: - case Qt::Key_Return: - return VK_RETURN; // (0D) Return key - case Qt::Key_Shift: - return VK_SHIFT; // (10) SHIFT key - case Qt::Key_Control: - return VK_CONTROL; // (11) CTRL key - case Qt::Key_Menu: - case Qt::Key_Alt: - return VK_MENU; // (12) ALT key - - case Qt::Key_F1: - return VK_F1; - case Qt::Key_F2: - return VK_F2; - case Qt::Key_F3: - return VK_F3; - case Qt::Key_F4: - return VK_F4; - case Qt::Key_F5: - return VK_F5; - case Qt::Key_F6: - return VK_F6; - case Qt::Key_F7: - return VK_F7; - case Qt::Key_F8: - return VK_F8; - case Qt::Key_F9: - return VK_F9; - case Qt::Key_F10: - return VK_F10; - case Qt::Key_F11: - return VK_F11; - case Qt::Key_F12: - return VK_F12; - case Qt::Key_F13: - return VK_F13; - case Qt::Key_F14: - return VK_F14; - case Qt::Key_F15: - return VK_F15; - case Qt::Key_F16: - return VK_F16; - case Qt::Key_F17: - return VK_F17; - case Qt::Key_F18: - return VK_F18; - case Qt::Key_F19: - return VK_F19; - case Qt::Key_F20: - return VK_F20; - case Qt::Key_F21: - return VK_F21; - case Qt::Key_F22: - return VK_F22; - case Qt::Key_F23: - return VK_F23; - case Qt::Key_F24: - return VK_F24; - - case Qt::Key_Pause: - return VK_PAUSE; // (13) PAUSE key - case Qt::Key_CapsLock: - return VK_CAPITAL; // (14) CAPS LOCK key - case Qt::Key_Kana_Lock: - case Qt::Key_Kana_Shift: - return VK_KANA; // (15) Input Method Editor (IME) Kana mode - case Qt::Key_Hangul: - return VK_HANGUL; // VK_HANGUL (15) IME Hangul mode - // VK_JUNJA (17) IME Junja mode - // VK_FINAL (18) IME final mode - case Qt::Key_Hangul_Hanja: - return VK_HANJA; // (19) IME Hanja mode - case Qt::Key_Kanji: - return VK_KANJI; // (19) IME Kanji mode - case Qt::Key_Escape: - return VK_ESCAPE; // (1B) ESC key - // VK_CONVERT (1C) IME convert - // VK_NONCONVERT (1D) IME nonconvert - // VK_ACCEPT (1E) IME accept - // VK_MODECHANGE (1F) IME mode change request - case Qt::Key_Space: - return VK_SPACE; // (20) SPACEBAR - case Qt::Key_PageUp: - return VK_PRIOR; // (21) PAGE UP key - case Qt::Key_PageDown: - return VK_NEXT; // (22) PAGE DOWN key - case Qt::Key_End: - return VK_END; // (23) END key - case Qt::Key_Home: - return VK_HOME; // (24) HOME key - case Qt::Key_Left: - return VK_LEFT; // (25) LEFT ARROW key - case Qt::Key_Up: - return VK_UP; // (26) UP ARROW key - case Qt::Key_Right: - return VK_RIGHT; // (27) RIGHT ARROW key - case Qt::Key_Down: - return VK_DOWN; // (28) DOWN ARROW key - case Qt::Key_Select: - return VK_SELECT; // (29) SELECT key - case Qt::Key_Print: - return VK_SNAPSHOT; // (2A) PRINT key - case Qt::Key_Execute: - return VK_EXECUTE; // (2B) EXECUTE key - case Qt::Key_Insert: - return VK_INSERT; // (2D) INS key - case Qt::Key_Delete: - return VK_DELETE; // (2E) DEL key - case Qt::Key_Help: - return VK_HELP; // (2F) HELP key - case Qt::Key_0: - case Qt::Key_ParenLeft: - return VK_0; // (30) 0) key - case Qt::Key_1: - return VK_1; // (31) 1 ! key - case Qt::Key_2: - case Qt::Key_At: - return VK_2; // (32) 2 & key - case Qt::Key_3: - case Qt::Key_NumberSign: - return VK_3; // case '3': case '#'; - case Qt::Key_4: - case Qt::Key_Dollar: // (34) 4 key '$'; - return VK_4; - case Qt::Key_5: - case Qt::Key_Percent: - return VK_5; // (35) 5 key '%' - case Qt::Key_6: - case Qt::Key_AsciiCircum: - return VK_6; // (36) 6 key '^' - case Qt::Key_7: - case Qt::Key_Ampersand: - return VK_7; // (37) 7 key case '&' - case Qt::Key_8: - case Qt::Key_Asterisk: - return VK_8; // (38) 8 key '*' - case Qt::Key_9: - case Qt::Key_ParenRight: - return VK_9; // (39) 9 key '(' - case Qt::Key_A: - return VK_A; // (41) A key case 'a': case 'A': return 0x41; - case Qt::Key_B: - return VK_B; // (42) B key case 'b': case 'B': return 0x42; - case Qt::Key_C: - return VK_C; // (43) C key case 'c': case 'C': return 0x43; - case Qt::Key_D: - return VK_D; // (44) D key case 'd': case 'D': return 0x44; - case Qt::Key_E: - return VK_E; // (45) E key case 'e': case 'E': return 0x45; - case Qt::Key_F: - return VK_F; // (46) F key case 'f': case 'F': return 0x46; - case Qt::Key_G: - return VK_G; // (47) G key case 'g': case 'G': return 0x47; - case Qt::Key_H: - return VK_H; // (48) H key case 'h': case 'H': return 0x48; - case Qt::Key_I: - return VK_I; // (49) I key case 'i': case 'I': return 0x49; - case Qt::Key_J: - return VK_J; // (4A) J key case 'j': case 'J': return 0x4A; - case Qt::Key_K: - return VK_K; // (4B) K key case 'k': case 'K': return 0x4B; - case Qt::Key_L: - return VK_L; // (4C) L key case 'l': case 'L': return 0x4C; - case Qt::Key_M: - return VK_M; // (4D) M key case 'm': case 'M': return 0x4D; - case Qt::Key_N: - return VK_N; // (4E) N key case 'n': case 'N': return 0x4E; - case Qt::Key_O: - return VK_O; // (4F) O key case 'o': case 'O': return 0x4F; - case Qt::Key_P: - return VK_P; // (50) P key case 'p': case 'P': return 0x50; - case Qt::Key_Q: - return VK_Q; // (51) Q key case 'q': case 'Q': return 0x51; - case Qt::Key_R: - return VK_R; // (52) R key case 'r': case 'R': return 0x52; - case Qt::Key_S: - return VK_S; // (53) S key case 's': case 'S': return 0x53; - case Qt::Key_T: - return VK_T; // (54) T key case 't': case 'T': return 0x54; - case Qt::Key_U: - return VK_U; // (55) U key case 'u': case 'U': return 0x55; - case Qt::Key_V: - return VK_V; // (56) V key case 'v': case 'V': return 0x56; - case Qt::Key_W: - return VK_W; // (57) W key case 'w': case 'W': return 0x57; - case Qt::Key_X: - return VK_X; // (58) X key case 'x': case 'X': return 0x58; - case Qt::Key_Y: - return VK_Y; // (59) Y key case 'y': case 'Y': return 0x59; - case Qt::Key_Z: - return VK_Z; // (5A) Z key case 'z': case 'Z': return 0x5A; - case Qt::Key_Meta: - return VK_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard) - // case Qt::Key_Meta_R: FIXME: What to do here? - // return VK_RWIN; // (5C) Right Windows key (Natural keyboard) - // VK_APPS (5D) Applications key (Natural keyboard) - // VK_SLEEP (5F) Computer Sleep key - // VK_SEPARATOR (6C) Separator key - // VK_SUBTRACT (6D) Subtract key - // VK_DECIMAL (6E) Decimal key - // VK_DIVIDE (6F) Divide key - // handled by key code above - - case Qt::Key_NumLock: - return VK_NUMLOCK; // (90) NUM LOCK key - - case Qt::Key_ScrollLock: - return VK_SCROLL; // (91) SCROLL LOCK key - - // VK_LSHIFT (A0) Left SHIFT key - // VK_RSHIFT (A1) Right SHIFT key - // VK_LCONTROL (A2) Left CONTROL key - // VK_RCONTROL (A3) Right CONTROL key - // VK_LMENU (A4) Left MENU key - // VK_RMENU (A5) Right MENU key - // VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key - // VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key - // VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key - // VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key - // VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key - // VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key - // VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key - // VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key - // VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key - // VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key - // VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key - // VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key - // VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key - // VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key - // VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key - // VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key - // VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key - // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key - - // VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key - case Qt::Key_Semicolon: - case Qt::Key_Colon: - return VK_OEM_1; // case ';': case ':': return 0xBA; - // VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key - case Qt::Key_Plus: - case Qt::Key_Equal: - return VK_OEM_PLUS; // case '=': case '+': return 0xBB; - // VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key - case Qt::Key_Comma: - case Qt::Key_Less: - return VK_OEM_COMMA; // case ',': case '<': return 0xBC; - // VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key - case Qt::Key_Minus: - case Qt::Key_Underscore: - return VK_OEM_MINUS; // case '-': case '_': return 0xBD; - // VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key - case Qt::Key_Period: - case Qt::Key_Greater: - return VK_OEM_PERIOD; // case '.': case '>': return 0xBE; - // VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key - case Qt::Key_Slash: - case Qt::Key_Question: - return VK_OEM_2; // case '/': case '?': return 0xBF; - // VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key - case Qt::Key_AsciiTilde: - case Qt::Key_QuoteLeft: - return VK_OEM_3; // case '`': case '~': return 0xC0; - // VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key - case Qt::Key_BracketLeft: - case Qt::Key_BraceLeft: - return VK_OEM_4; // case '[': case '{': return 0xDB; - // VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key - case Qt::Key_Backslash: - case Qt::Key_Bar: - return VK_OEM_5; // case '\\': case '|': return 0xDC; - // VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key - case Qt::Key_BracketRight: - case Qt::Key_BraceRight: - return VK_OEM_6; // case ']': case '}': return 0xDD; - // VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key - case Qt::Key_QuoteDbl: - return VK_OEM_7; // case '\'': case '"': return 0xDE; - // VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. - // VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard - // VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key - // VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP - // VK_ATTN (F6) Attn key - // VK_CRSEL (F7) CrSel key - // VK_EXSEL (F8) ExSel key - // VK_EREOF (F9) Erase EOF key - // VK_PLAY (FA) Play key - // VK_ZOOM (FB) Zoom key - // VK_NONAME (FC) Reserved for future use - // VK_PA1 (FD) PA1 key - // VK_OEM_CLEAR (FE) Clear key - default: - return 0; + } else { + switch (keycode) { + case Qt::Key_Backspace: + return VK_BACK; // (08) BACKSPACE key + case Qt::Key_Backtab: + case Qt::Key_Tab: + return VK_TAB; // (09) TAB key + case Qt::Key_Clear: + return VK_CLEAR; // (0C) CLEAR key + case Qt::Key_Enter: + case Qt::Key_Return: + return VK_RETURN; // (0D) Return key + case Qt::Key_Shift: + return VK_SHIFT; // (10) SHIFT key + case Qt::Key_Control: + return VK_CONTROL; // (11) CTRL key + case Qt::Key_Menu: + case Qt::Key_Alt: + return VK_MENU; // (12) ALT key + + case Qt::Key_F1: + return VK_F1; + case Qt::Key_F2: + return VK_F2; + case Qt::Key_F3: + return VK_F3; + case Qt::Key_F4: + return VK_F4; + case Qt::Key_F5: + return VK_F5; + case Qt::Key_F6: + return VK_F6; + case Qt::Key_F7: + return VK_F7; + case Qt::Key_F8: + return VK_F8; + case Qt::Key_F9: + return VK_F9; + case Qt::Key_F10: + return VK_F10; + case Qt::Key_F11: + return VK_F11; + case Qt::Key_F12: + return VK_F12; + case Qt::Key_F13: + return VK_F13; + case Qt::Key_F14: + return VK_F14; + case Qt::Key_F15: + return VK_F15; + case Qt::Key_F16: + return VK_F16; + case Qt::Key_F17: + return VK_F17; + case Qt::Key_F18: + return VK_F18; + case Qt::Key_F19: + return VK_F19; + case Qt::Key_F20: + return VK_F20; + case Qt::Key_F21: + return VK_F21; + case Qt::Key_F22: + return VK_F22; + case Qt::Key_F23: + return VK_F23; + case Qt::Key_F24: + return VK_F24; + + case Qt::Key_Pause: + return VK_PAUSE; // (13) PAUSE key + case Qt::Key_CapsLock: + return VK_CAPITAL; // (14) CAPS LOCK key + case Qt::Key_Kana_Lock: + case Qt::Key_Kana_Shift: + return VK_KANA; // (15) Input Method Editor (IME) Kana mode + case Qt::Key_Hangul: + return VK_HANGUL; // VK_HANGUL (15) IME Hangul mode + // VK_JUNJA (17) IME Junja mode + // VK_FINAL (18) IME final mode + case Qt::Key_Hangul_Hanja: + return VK_HANJA; // (19) IME Hanja mode + case Qt::Key_Kanji: + return VK_KANJI; // (19) IME Kanji mode + case Qt::Key_Escape: + return VK_ESCAPE; // (1B) ESC key + // VK_CONVERT (1C) IME convert + // VK_NONCONVERT (1D) IME nonconvert + // VK_ACCEPT (1E) IME accept + // VK_MODECHANGE (1F) IME mode change request + case Qt::Key_Space: + return VK_SPACE; // (20) SPACEBAR + case Qt::Key_PageUp: + return VK_PRIOR; // (21) PAGE UP key + case Qt::Key_PageDown: + return VK_NEXT; // (22) PAGE DOWN key + case Qt::Key_End: + return VK_END; // (23) END key + case Qt::Key_Home: + return VK_HOME; // (24) HOME key + case Qt::Key_Left: + return VK_LEFT; // (25) LEFT ARROW key + case Qt::Key_Up: + return VK_UP; // (26) UP ARROW key + case Qt::Key_Right: + return VK_RIGHT; // (27) RIGHT ARROW key + case Qt::Key_Down: + return VK_DOWN; // (28) DOWN ARROW key + case Qt::Key_Select: + return VK_SELECT; // (29) SELECT key + case Qt::Key_Print: + return VK_SNAPSHOT; // (2A) PRINT key + case Qt::Key_Execute: + return VK_EXECUTE; // (2B) EXECUTE key + case Qt::Key_Insert: + return VK_INSERT; // (2D) INS key + case Qt::Key_Delete: + return VK_DELETE; // (2E) DEL key + case Qt::Key_Help: + return VK_HELP; // (2F) HELP key + case Qt::Key_0: + case Qt::Key_ParenLeft: + return VK_0; // (30) 0) key + case Qt::Key_1: + return VK_1; // (31) 1 ! key + case Qt::Key_2: + case Qt::Key_At: + return VK_2; // (32) 2 & key + case Qt::Key_3: + case Qt::Key_NumberSign: + return VK_3; // case '3': case '#'; + case Qt::Key_4: + case Qt::Key_Dollar: // (34) 4 key '$'; + return VK_4; + case Qt::Key_5: + case Qt::Key_Percent: + return VK_5; // (35) 5 key '%' + case Qt::Key_6: + case Qt::Key_AsciiCircum: + return VK_6; // (36) 6 key '^' + case Qt::Key_7: + case Qt::Key_Ampersand: + return VK_7; // (37) 7 key case '&' + case Qt::Key_8: + case Qt::Key_Asterisk: + return VK_8; // (38) 8 key '*' + case Qt::Key_9: + case Qt::Key_ParenRight: + return VK_9; // (39) 9 key '(' + case Qt::Key_A: + return VK_A; // (41) A key case 'a': case 'A': return 0x41; + case Qt::Key_B: + return VK_B; // (42) B key case 'b': case 'B': return 0x42; + case Qt::Key_C: + return VK_C; // (43) C key case 'c': case 'C': return 0x43; + case Qt::Key_D: + return VK_D; // (44) D key case 'd': case 'D': return 0x44; + case Qt::Key_E: + return VK_E; // (45) E key case 'e': case 'E': return 0x45; + case Qt::Key_F: + return VK_F; // (46) F key case 'f': case 'F': return 0x46; + case Qt::Key_G: + return VK_G; // (47) G key case 'g': case 'G': return 0x47; + case Qt::Key_H: + return VK_H; // (48) H key case 'h': case 'H': return 0x48; + case Qt::Key_I: + return VK_I; // (49) I key case 'i': case 'I': return 0x49; + case Qt::Key_J: + return VK_J; // (4A) J key case 'j': case 'J': return 0x4A; + case Qt::Key_K: + return VK_K; // (4B) K key case 'k': case 'K': return 0x4B; + case Qt::Key_L: + return VK_L; // (4C) L key case 'l': case 'L': return 0x4C; + case Qt::Key_M: + return VK_M; // (4D) M key case 'm': case 'M': return 0x4D; + case Qt::Key_N: + return VK_N; // (4E) N key case 'n': case 'N': return 0x4E; + case Qt::Key_O: + return VK_O; // (4F) O key case 'o': case 'O': return 0x4F; + case Qt::Key_P: + return VK_P; // (50) P key case 'p': case 'P': return 0x50; + case Qt::Key_Q: + return VK_Q; // (51) Q key case 'q': case 'Q': return 0x51; + case Qt::Key_R: + return VK_R; // (52) R key case 'r': case 'R': return 0x52; + case Qt::Key_S: + return VK_S; // (53) S key case 's': case 'S': return 0x53; + case Qt::Key_T: + return VK_T; // (54) T key case 't': case 'T': return 0x54; + case Qt::Key_U: + return VK_U; // (55) U key case 'u': case 'U': return 0x55; + case Qt::Key_V: + return VK_V; // (56) V key case 'v': case 'V': return 0x56; + case Qt::Key_W: + return VK_W; // (57) W key case 'w': case 'W': return 0x57; + case Qt::Key_X: + return VK_X; // (58) X key case 'x': case 'X': return 0x58; + case Qt::Key_Y: + return VK_Y; // (59) Y key case 'y': case 'Y': return 0x59; + case Qt::Key_Z: + return VK_Z; // (5A) Z key case 'z': case 'Z': return 0x5A; + case Qt::Key_Meta: + return VK_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard) + // case Qt::Key_Meta_R: FIXME: What to do here? + // return VK_RWIN; // (5C) Right Windows key (Natural keyboard) + // VK_APPS (5D) Applications key (Natural keyboard) + // VK_SLEEP (5F) Computer Sleep key + // VK_SEPARATOR (6C) Separator key + // VK_SUBTRACT (6D) Subtract key + // VK_DECIMAL (6E) Decimal key + // VK_DIVIDE (6F) Divide key + // handled by key code above + + case Qt::Key_NumLock: + return VK_NUMLOCK; // (90) NUM LOCK key + + case Qt::Key_ScrollLock: + return VK_SCROLL; // (91) SCROLL LOCK key + + // VK_LSHIFT (A0) Left SHIFT key + // VK_RSHIFT (A1) Right SHIFT key + // VK_LCONTROL (A2) Left CONTROL key + // VK_RCONTROL (A3) Right CONTROL key + // VK_LMENU (A4) Left MENU key + // VK_RMENU (A5) Right MENU key + // VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key + // VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key + // VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key + // VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key + // VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key + // VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key + // VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key + // VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key + // VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key + // VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key + // VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key + // VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key + // VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key + // VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key + // VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key + // VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key + // VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key + // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key + + // VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key + case Qt::Key_Semicolon: + case Qt::Key_Colon: + return VK_OEM_1; // case ';': case ':': return 0xBA; + // VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key + case Qt::Key_Plus: + case Qt::Key_Equal: + return VK_OEM_PLUS; // case '=': case '+': return 0xBB; + // VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key + case Qt::Key_Comma: + case Qt::Key_Less: + return VK_OEM_COMMA; // case ',': case '<': return 0xBC; + // VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key + case Qt::Key_Minus: + case Qt::Key_Underscore: + return VK_OEM_MINUS; // case '-': case '_': return 0xBD; + // VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key + case Qt::Key_Period: + case Qt::Key_Greater: + return VK_OEM_PERIOD; // case '.': case '>': return 0xBE; + // VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key + case Qt::Key_Slash: + case Qt::Key_Question: + return VK_OEM_2; // case '/': case '?': return 0xBF; + // VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key + case Qt::Key_AsciiTilde: + case Qt::Key_QuoteLeft: + return VK_OEM_3; // case '`': case '~': return 0xC0; + // VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key + case Qt::Key_BracketLeft: + case Qt::Key_BraceLeft: + return VK_OEM_4; // case '[': case '{': return 0xDB; + // VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key + case Qt::Key_Backslash: + case Qt::Key_Bar: + return VK_OEM_5; // case '\\': case '|': return 0xDC; + // VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key + case Qt::Key_BracketRight: + case Qt::Key_BraceRight: + return VK_OEM_6; // case ']': case '}': return 0xDD; + // VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key + case Qt::Key_QuoteDbl: + return VK_OEM_7; // case '\'': case '"': return 0xDE; + // VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. + // VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard + // VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key + // VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP + // VK_ATTN (F6) Attn key + // VK_CRSEL (F7) CrSel key + // VK_EXSEL (F8) ExSel key + // VK_EREOF (F9) Erase EOF key + // VK_PLAY (FA) Play key + // VK_ZOOM (FB) Zoom key + // VK_NONAME (FC) Reserved for future use + // VK_PA1 (FD) PA1 key + // VK_OEM_CLEAR (FE) Clear key + default: + return 0; + } } } @@ -478,14 +486,52 @@ static unsigned mouseButtonsModifiersForEvent(const T* event) return ret; } +// If only a modifier key is pressed, Qt only reports the key code. +// But Chromium also expects the modifier being set. +static inline WebInputEvent::Modifiers modifierForKeyCode(int key) +{ + switch (key) { + case Qt::Key_Shift: + return WebInputEvent::ShiftKey; + case Qt::Key_Alt: + return WebInputEvent::AltKey; +#if defined(Q_OS_OSX) + case Qt::Key_Control: + return (!qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) ? WebInputEvent::MetaKey : WebInputEvent::ControlKey; + case Qt::Key_Meta: + return (!qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) ? WebInputEvent::ControlKey : WebInputEvent::MetaKey; +#else + case Qt::Key_Control: + return WebInputEvent::ControlKey; + case Qt::Key_Meta: + return WebInputEvent::MetaKey; +#endif + default: + return static_cast<WebInputEvent::Modifiers>(0); + } +} + static inline WebInputEvent::Modifiers modifiersForEvent(const QInputEvent* event) { unsigned result = 0; Qt::KeyboardModifiers modifiers = event->modifiers(); +#if defined(Q_OS_OSX) + if (!qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + if (modifiers & Qt::ControlModifier) + result |= WebInputEvent::MetaKey; + if (modifiers & Qt::MetaModifier) + result |= WebInputEvent::ControlKey; + } else +#endif + { + if (modifiers & Qt::ControlModifier) + result |= WebInputEvent::ControlKey; + if (modifiers & Qt::MetaModifier) + result |= WebInputEvent::MetaKey; + } + if (modifiers & Qt::ShiftModifier) result |= WebInputEvent::ShiftKey; - if (modifiers & Qt::ControlModifier) - result |= WebInputEvent::ControlKey; if (modifiers & Qt::AltModifier) result |= WebInputEvent::AltKey; if (modifiers & Qt::MetaModifier) @@ -503,9 +549,12 @@ static inline WebInputEvent::Modifiers modifiersForEvent(const QInputEvent* even result |= mouseButtonsModifiersForEvent(static_cast<const QWheelEvent*>(event)); break; case QEvent::KeyPress: - case QEvent::KeyRelease: - if (static_cast<const QKeyEvent*>(event)->isAutoRepeat()) + case QEvent::KeyRelease: { + const QKeyEvent *keyEvent = static_cast<const QKeyEvent*>(event); + if (keyEvent->isAutoRepeat()) result |= WebInputEvent::IsAutoRepeat; + result |= modifierForKeyCode(keyEvent->key()); + } default: break; } @@ -612,7 +661,7 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev) { - content::NativeWebKeyboardEvent webKitEvent; + content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev)); webKitEvent.timeStampSeconds = currentTimeForEvent(ev); webKitEvent.modifiers = modifiersForEvent(ev); webKitEvent.type = webEventTypeForEvent(ev); diff --git a/src/webengine/api/qquickwebenginecertificateerror.cpp b/src/webengine/api/qquickwebenginecertificateerror.cpp new file mode 100644 index 000000000..37b92727a --- /dev/null +++ b/src/webengine/api/qquickwebenginecertificateerror.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** 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 <qquickwebenginecertificateerror_p.h> +#include "certificate_error_controller.h" +QT_BEGIN_NAMESPACE + +class QQuickWebEngineCertificateErrorPrivate { +public: + QQuickWebEngineCertificateErrorPrivate(const QSharedPointer<CertificateErrorController> &controller) + : weakRefCertErrorController(controller), + error(static_cast<QQuickWebEngineCertificateError::Error>(static_cast<int>(controller->error()))), + description(controller->errorString()), + overridable(controller->overridable()), + async(false) + { + } + + const QWeakPointer<CertificateErrorController> weakRefCertErrorController; + QQuickWebEngineCertificateError::Error error; + QString description; + bool overridable; + bool async; +}; + + + +/*! + \qmltype WebEngineCertificateError + \instantiates QQuickWebEngineCertificateError + \inqmlmodule QtWebEngine 1.1 + \since QtWebEngine 1.1 + + \brief A utility class for accepting or denying certificate exceptions when a certificate error occurs. + + This class contains information about a certificate error that happened and provides a way to accept or + deny a certificate exception. + + \sa WebEngineView::certificateError +*/ +QQuickWebEngineCertificateError::QQuickWebEngineCertificateError(const QSharedPointer<CertificateErrorController> &controller, QObject *parent) + : QObject(parent) + , d_ptr(new QQuickWebEngineCertificateErrorPrivate(controller)) +{ +} + +QQuickWebEngineCertificateError::~QQuickWebEngineCertificateError() +{ + rejectCertificate(); +} + + +/*! + \qmlmethod void WebEngineCertificateError::defer() + + This function should be called when there is a need to postpone the decision to ignore or not the certificate error. This is useful to + wait for user input. When called it will pause the url request until WebEngineCertificateError::ignoreCertificateError() or + WebEngineCertificateError::rejectCertificate() is called. + */ +void QQuickWebEngineCertificateError::defer() +{ + Q_D(QQuickWebEngineCertificateError); + d->async = true; +} +/*! + \qmlmethod void WebEngineCertificateError::ignoreCertificateError() + + The certificate error is ignored and the WebEngineView continues to load the requested url. + */ +void QQuickWebEngineCertificateError::ignoreCertificateError() +{ + Q_D(const QQuickWebEngineCertificateError); + + QSharedPointer<CertificateErrorController> strongRefCert = d->weakRefCertErrorController.toStrongRef(); + if (strongRefCert) + strongRefCert->accept(true); +} + +/*! + \qmlmethod void WebEngineCertificateError::rejectCertificate() + + The WebEngineView stops loading the requested url. + */ +void QQuickWebEngineCertificateError::rejectCertificate() +{ + Q_D(const QQuickWebEngineCertificateError); + + QSharedPointer<CertificateErrorController> strongRefCert = d->weakRefCertErrorController.toStrongRef(); + if (strongRefCert) + strongRefCert->accept(false); +} + +/*! + \qmlproperty url WebEngineCertificateError::url + \brief The URL of the certificate error. + */ +QUrl QQuickWebEngineCertificateError::url() const +{ + Q_D(const QQuickWebEngineCertificateError); + QSharedPointer<CertificateErrorController> strongRefCert = d->weakRefCertErrorController.toStrongRef(); + if (strongRefCert) + return strongRefCert->url(); + return QUrl(); +} + +/*! + \qmlproperty enumeration WebEngineCertificateError::error +*/ +QQuickWebEngineCertificateError::Error QQuickWebEngineCertificateError::error() const +{ + Q_D(const QQuickWebEngineCertificateError); + return d->error; +} + +/*! + \qmlproperty string WebEngineCertificateError::description +*/ +QString QQuickWebEngineCertificateError::description() const +{ + Q_D(const QQuickWebEngineCertificateError); + return d->description; +} + +/*! + \qmlproperty bool WebEngineCertificateError::overridable +*/ +bool QQuickWebEngineCertificateError::overridable() const +{ + Q_D(const QQuickWebEngineCertificateError); + return d->overridable; +} + +bool QQuickWebEngineCertificateError::deferred() const +{ + Q_D(const QQuickWebEngineCertificateError); + return d->async; +} + +QT_END_NAMESPACE + diff --git a/src/webengine/api/qquickwebenginecertificateerror_p.h b/src/webengine/api/qquickwebenginecertificateerror_p.h new file mode 100644 index 000000000..735cc8705 --- /dev/null +++ b/src/webengine/api/qquickwebenginecertificateerror_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 QQUICKWEBENGINECERTIFICATEERROR_P_H +#define QQUICKWEBENGINECERTIFICATEERROR_P_H + +#include <QObject> +#include "qquickwebengineview_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineCertificateErrorPrivate; +class CertificateErrorController; + +class Q_WEBENGINE_EXPORT QQuickWebEngineCertificateError : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl url READ url) + Q_PROPERTY(Error error READ error) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(bool overridable READ overridable) + Q_ENUMS(Error) + +public: + + // Keep this identical to CertificateErrorController::CertificateError, or add mapping layer. + enum Error { + SslPinnedKeyNotInCertificateChain = -150, + CertificateCommonNameInvalid = -200, + CertificateDateInvalid = -201, + CertificateAuthorityInvalid = -202, + CertificateContainsErrors = -203, + CertificateNoRevocationMechanism = -204, + CertificateUnableToCheckRevocation = -205, + CertificateRevoked = -206, + CertificateInvalid = -207, + CertificateWeakSignatureAlgorithm = -208, + CertificateNonUniqueName = -210, + CertificateWeakKey = -211, + CertificateNameConstraintViolation = -212, + }; + + QQuickWebEngineCertificateError(const QSharedPointer<CertificateErrorController> &controller, QObject *parent = 0); + ~QQuickWebEngineCertificateError(); + + Q_INVOKABLE void defer(); + Q_INVOKABLE void ignoreCertificateError(); + Q_INVOKABLE void rejectCertificate(); + QUrl url() const; + Error error() const; + QString description() const; + bool overridable() const; + bool deferred() const; + +private: + Q_DISABLE_COPY(QQuickWebEngineCertificateError) + Q_DECLARE_PRIVATE(QQuickWebEngineCertificateError) + QScopedPointer<QQuickWebEngineCertificateErrorPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickWebEngineCertificateError) + +#endif // QQUICKWEBENGINECERTIFICATEERROR_P_H diff --git a/src/webengine/api/qquickwebenginedownloaditem.cpp b/src/webengine/api/qquickwebenginedownloaditem.cpp new file mode 100644 index 000000000..6ee00d9a0 --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** 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 "qquickwebenginedownloaditem_p.h" +#include "qquickwebenginedownloaditem_p_p.h" + +QT_BEGIN_NAMESPACE + +static inline QQuickWebEngineDownloadItem::DownloadState toDownloadState(int state) { + switch (state) { + case BrowserContextAdapterClient::DownloadInProgress: + return QQuickWebEngineDownloadItem::DownloadInProgress; + case BrowserContextAdapterClient::DownloadCompleted: + return QQuickWebEngineDownloadItem::DownloadCompleted; + case BrowserContextAdapterClient::DownloadCancelled: + return QQuickWebEngineDownloadItem::DownloadCancelled; + case BrowserContextAdapterClient::DownloadInterrupted: + return QQuickWebEngineDownloadItem::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QQuickWebEngineDownloadItem::DownloadCancelled; + } +} + +QQuickWebEngineDownloadItemPrivate::QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfilePrivate *p) + : profile(p) + , downloadId(-1) + , downloadState(QQuickWebEngineDownloadItem::DownloadCancelled) +{ +} + +QQuickWebEngineDownloadItemPrivate::~QQuickWebEngineDownloadItemPrivate() +{ + profile->downloadDestroyed(downloadId); +} + +/*! + \qmltype WebEngineDownloadItem + \instantiates QQuickWebEngineDownloadItem + \inqmlmodule QtWebEngine 1.1 + \since QtWebEngine 1.1 + \brief A WebEngineDownloadItem provides information about a download. + + WebEngineDownloadItem stores the state of a download to be used to manage requested downloads. + + By default the download is rejected unless the user explicitly accepts it with + WebEngineDownloadItem::accept(). +*/ + +void QQuickWebEngineDownloadItemPrivate::update(const BrowserContextAdapterClient::DownloadItemInfo &info) +{ + Q_Q(QQuickWebEngineDownloadItem); + + updateState(toDownloadState(info.state)); + + if (info.receivedBytes != receivedBytes) { + receivedBytes = info.receivedBytes; + Q_EMIT q->receivedBytesChanged(); + } + + if (info.totalBytes != totalBytes) { + totalBytes = info.totalBytes; + Q_EMIT q->totalBytesChanged(); + } +} + +void QQuickWebEngineDownloadItemPrivate::updateState(QQuickWebEngineDownloadItem::DownloadState newState) +{ + Q_Q(QQuickWebEngineDownloadItem); + + if (downloadState != newState) { + downloadState = newState; + Q_EMIT q->stateChanged(); + } +} + +/*! + \qmlmethod void WebEngineDownloadItem::accept() + + Accepts the download request, which will start the download. + + \sa WebEngineDownloadItem::cancel() +*/ + +void QQuickWebEngineDownloadItem::accept() +{ + Q_D(QQuickWebEngineDownloadItem); + + if (d->downloadState != QQuickWebEngineDownloadItem::DownloadRequested) + return; + + d->updateState(QQuickWebEngineDownloadItem::DownloadInProgress); +} + +/*! + \qmlmethod void WebEngineDownloadItem::cancel() + + Cancels the download. +*/ + +void QQuickWebEngineDownloadItem::cancel() +{ + Q_D(QQuickWebEngineDownloadItem); + + QQuickWebEngineDownloadItem::DownloadState state = d->downloadState; + + if (state == QQuickWebEngineDownloadItem::DownloadCompleted + || state == QQuickWebEngineDownloadItem::DownloadCancelled) + return; + + d->updateState(QQuickWebEngineDownloadItem::DownloadCancelled); + + // We directly cancel the download if the user cancels before + // it even started, so no need to notify the profile here. + if (state == QQuickWebEngineDownloadItem::DownloadInProgress) + d->profile->cancelDownload(d->downloadId); +} + +/*! + \qmlproperty quint32 WebEngineDownloadItem::id + + The download item's id. +*/ + +quint32 QQuickWebEngineDownloadItem::id() const +{ + Q_D(const QQuickWebEngineDownloadItem); + return d->downloadId; +} + +/*! + \qmlproperty enumeration WebEngineDownloadItem::state + + This property describes the state in which the download is in. + + The state can be one of: + + \table + + \header + \li Constant + \li Description + + \row + \li DownloadRequested + \li The download has been requested, but has not been accepted yet. + + \row + \li DownloadInProgress + \li The download is in progress. + + \row + \li DownloadCompleted + \li The download completed successfully. + + \row + \li DownloadInterrupted + \li The download has been interrupted (by the server or because of lost connectivity). + + \endtable +*/ + +QQuickWebEngineDownloadItem::DownloadState QQuickWebEngineDownloadItem::state() const +{ + Q_D(const QQuickWebEngineDownloadItem); + return d->downloadState; +} + +/*! + \qmlproperty int WebEngineDownloadItem::totalBytes + + The download's total size in bytes. + + -1 means the total size is unknown. +*/ + +qint64 QQuickWebEngineDownloadItem::totalBytes() const +{ + Q_D(const QQuickWebEngineDownloadItem); + return d->totalBytes; +} + +/*! + \qmlproperty int WebEngineDownloadItem::receivedBytes + + The download's bytes that have been received so far. +*/ + +qint64 QQuickWebEngineDownloadItem::receivedBytes() const +{ + Q_D(const QQuickWebEngineDownloadItem); + return d->receivedBytes; +} + +/*! + \qmlproperty QString WebEngineDownloadItem::path + + The download item's full target path where it is being downloaded to. + + The path includes the file name. The default suggested path is the standard + download location and file name is deduced not to overwrite already existing files. + + The download path can only be set in the \c WebEngineProfile.onDownloadRequested + handler before the download is accepted. + + \sa WebEngineProfile::downloadRequested(WebEngineDownloadItem download), WebEngineDownloadItem::accept() +*/ + +QString QQuickWebEngineDownloadItem::path() const +{ + Q_D(const QQuickWebEngineDownloadItem); + return d->downloadPath; +} + +void QQuickWebEngineDownloadItem::setPath(QString path) +{ + Q_D(QQuickWebEngineDownloadItem); + if (d->downloadState != QQuickWebEngineDownloadItem::DownloadRequested) { + qWarning("Setting the download path is not allowed after the download has been accepted."); + return; + } + if (d->downloadPath != path) { + d->downloadPath = path; + Q_EMIT pathChanged(); + } +} + +QQuickWebEngineDownloadItem::QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +QQuickWebEngineDownloadItem::~QQuickWebEngineDownloadItem() +{ +} + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginedownloaditem_p.h b/src/webengine/api/qquickwebenginedownloaditem_p.h new file mode 100644 index 000000000..ea12c9c94 --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 QQUICKWEBENGINEDOWNLOADITEM_P_H +#define QQUICKWEBENGINEDOWNLOADITEM_P_H + +#include <private/qtwebengineglobal_p.h> +#include <QObject> +#include <QScopedPointer> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItemPrivate; +class QQuickWebEngineProfilePrivate; + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineDownloadItem: public QObject { + Q_OBJECT +public: + ~QQuickWebEngineDownloadItem(); + enum DownloadState { + DownloadRequested, + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUMS(DownloadState) + + Q_PROPERTY(quint32 id READ id() CONSTANT FINAL) + Q_PROPERTY(DownloadState state READ state NOTIFY stateChanged) + Q_PROPERTY(qint64 totalBytes READ totalBytes NOTIFY totalBytesChanged) + Q_PROPERTY(qint64 receivedBytes READ receivedBytes NOTIFY receivedBytesChanged) + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + + Q_INVOKABLE void accept(); + Q_INVOKABLE void cancel(); + + quint32 id() const; + DownloadState state() const; + qint64 totalBytes() const; + qint64 receivedBytes() const; + QString path() const; + void setPath(QString path); + +Q_SIGNALS: + void stateChanged(); + void receivedBytesChanged(); + void totalBytesChanged(); + void pathChanged(); + +private: + QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate*, QObject *parent = 0); + Q_DISABLE_COPY(QQuickWebEngineDownloadItem) + Q_DECLARE_PRIVATE(QQuickWebEngineDownloadItem) + friend class QQuickWebEngineProfilePrivate; + + QScopedPointer<QQuickWebEngineDownloadItemPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEDOWNLOADITEM_P_H diff --git a/src/webengine/api/qquickwebenginedownloaditem_p_p.h b/src/webengine/api/qquickwebenginedownloaditem_p_p.h new file mode 100644 index 000000000..0250a8faa --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem_p_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 QQUICKWEBENGINEDOWNLOADITEM_P_P_H +#define QQUICKWEBENGINEDOWNLOADITEM_P_P_H + +#include "qquickwebenginedownloaditem_p.h" +#include "qquickwebengineprofile_p_p.h" +#include <private/qtwebengineglobal_p.h> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItemPrivate { + QQuickWebEngineDownloadItem *q_ptr; + QQuickWebEngineProfilePrivate* profile; + friend class QQuickWebEngineProfilePrivate; +public: + Q_DECLARE_PUBLIC(QQuickWebEngineDownloadItem) + QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfilePrivate *p); + ~QQuickWebEngineDownloadItemPrivate(); + + quint32 downloadId; + QQuickWebEngineDownloadItem::DownloadState downloadState; + qint64 totalBytes; + qint64 receivedBytes; + QString downloadPath; + + void update(const BrowserContextAdapterClient::DownloadItemInfo &info); + void updateState(QQuickWebEngineDownloadItem::DownloadState newState); +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEDOWNLOADITEM_P_P_H diff --git a/src/webengine/api/qquickwebenginehistory.cpp b/src/webengine/api/qquickwebenginehistory.cpp index ffb857791..7924dbc5e 100644 --- a/src/webengine/api/qquickwebenginehistory.cpp +++ b/src/webengine/api/qquickwebenginehistory.cpp @@ -63,6 +63,8 @@ QQuickWebEngineBackHistoryListModelPrivate::QQuickWebEngineBackHistoryListModelP int QQuickWebEngineBackHistoryListModelPrivate::count() const { + if (!adapter()) + return -1; return adapter()->currentNavigationEntryIndex(); } @@ -79,6 +81,8 @@ QQuickWebEngineForwardHistoryListModelPrivate::QQuickWebEngineForwardHistoryList int QQuickWebEngineForwardHistoryListModelPrivate::count() const { + if (!adapter()) + return -1; return adapter()->navigationEntryCount() - adapter()->currentNavigationEntryIndex() - 1; } diff --git a/src/webengine/api/qquickwebenginenewviewrequest.cpp b/src/webengine/api/qquickwebenginenewviewrequest.cpp index f2a361f55..053fcd2f6 100644 --- a/src/webengine/api/qquickwebenginenewviewrequest.cpp +++ b/src/webengine/api/qquickwebenginenewviewrequest.cpp @@ -39,6 +39,18 @@ #include "qquickwebengineview_p_p.h" #include "web_contents_adapter.h" +/*! + \qmltype WebEngineNewViewRequest + \instantiates QQuickWebEngineNewViewRequest + \inqmlmodule QtWebEngine 1.1 + \since QtWebEngine 1.1 + + \brief A utility class for the WebEngineView::newViewRequested signal. + + This class contains information about the request of a page to open a new window. + + \sa WebEngineView::newViewRequested +*/ QQuickWebEngineNewViewRequest::QQuickWebEngineNewViewRequest() { } @@ -47,20 +59,48 @@ QQuickWebEngineNewViewRequest::~QQuickWebEngineNewViewRequest() { } +/*! + \qmlproperty WebEngineView::NewViewDestination WebEngineNewViewRequest::destination + \brief The type of view that is requested by the page. + */ QQuickWebEngineView::NewViewDestination QQuickWebEngineNewViewRequest::destination() const { return m_destination; } +/*! + \qmlproperty bool WebEngineNewViewRequest::isUserInitiated + \brief Whether this window request was directly triggered as the result of a keyboard or mouse event. + + Use this property to block possibly unwanted "popups". + */ bool QQuickWebEngineNewViewRequest::isUserInitiated() const { return m_isUserInitiated; } +/*! + \qmlmethod WebEngineNewViewRequest::openIn(WebEngineView view) + + Call this method to fulfill the request and determine which WebEngineView + should be used to contain the new page. Any state, history or loaded page + within \a view will be lost as result of this. + + \sa WebEngineView::newViewRequested + */ void QQuickWebEngineNewViewRequest::openIn(QQuickWebEngineView *view) { - if (view) { - view->d_func()->adoptWebContents(m_adapter.data()); - m_adapter.reset(); + if (!m_adapter) { + qWarning("Trying to open an empty request, it was either already used or was invalidated." + "\nYou must complete the request synchronously within the newViewRequested signal handler." + " If a view hasn't been adopted before returning, the request will be invalidated."); + return; + } + + if (!view) { + qWarning("Trying to open a WebEngineNewViewRequest in an invalid WebEngineView."); + return; } + view->d_func()->adoptWebContents(m_adapter.data()); + m_adapter.reset(); } diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp new file mode 100644 index 000000000..5905fb3d9 --- /dev/null +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -0,0 +1,410 @@ +/**************************************************************************** +** +** 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 "qquickwebengineprofile_p.h" + +#include "qquickwebenginedownloaditem_p.h" +#include "qquickwebenginedownloaditem_p_p.h" +#include "qquickwebengineprofile_p_p.h" +#include "qquickwebenginesettings_p.h" + +#include <QQmlEngine> + +#include "browser_context_adapter.h" +#include "web_engine_settings.h" + +QT_BEGIN_NAMESPACE + +QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext) + : m_settings(new QQuickWebEngineSettings()) + , m_browserContext(browserContext) +{ + if (ownsContext) + m_browserContextRef = browserContext; + + m_browserContext->setClient(this); + m_settings->d_ptr->initDefaults(browserContext->isOffTheRecord()); +} + +QQuickWebEngineProfilePrivate::~QQuickWebEngineProfilePrivate() +{ + m_browserContext->setClient(0); + + Q_FOREACH (QQuickWebEngineDownloadItem* download, m_ongoingDownloads) { + if (download) + download->cancel(); + } + + m_ongoingDownloads.clear(); +} + +void QQuickWebEngineProfilePrivate::cancelDownload(quint32 downloadId) +{ + m_browserContext->cancelDownload(downloadId); +} + +void QQuickWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) +{ + m_ongoingDownloads.remove(downloadId); +} + +void QQuickWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info) +{ + Q_Q(QQuickWebEngineProfile); + + Q_ASSERT(!m_ongoingDownloads.contains(info.id)); + QQuickWebEngineDownloadItemPrivate *itemPrivate = new QQuickWebEngineDownloadItemPrivate(this); + itemPrivate->downloadId = info.id; + itemPrivate->downloadState = QQuickWebEngineDownloadItem::DownloadRequested; + itemPrivate->downloadPath = info.path; + + QQuickWebEngineDownloadItem *download = new QQuickWebEngineDownloadItem(itemPrivate, q); + + m_ongoingDownloads.insert(info.id, download); + + QQmlEngine::setObjectOwnership(download, QQmlEngine::JavaScriptOwnership); + Q_EMIT q->downloadRequested(download); + + QQuickWebEngineDownloadItem::DownloadState state = download->state(); + info.path = download->path(); + info.accepted = state != QQuickWebEngineDownloadItem::DownloadCancelled + && state != QQuickWebEngineDownloadItem::DownloadRequested; +} + +void QQuickWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info) +{ + if (!m_ongoingDownloads.contains(info.id)) + return; + + Q_Q(QQuickWebEngineProfile); + + QQuickWebEngineDownloadItem* download = m_ongoingDownloads.value(info.id).data(); + + if (!download) { + downloadDestroyed(info.id); + return; + } + + download->d_func()->update(info); + + if (info.state != BrowserContextAdapterClient::DownloadInProgress) { + Q_EMIT q->downloadFinished(download); + m_ongoingDownloads.remove(info.id); + } +} + +/*! + \qmltype WebEngineProfile + \instantiates QQuickWebEngineProfile + \inqmlmodule QtWebEngine 1.1 + \since QtWebEngine 1.1 + \brief A WebEngineProfile contains common settings for multiple WebEngineView. + + WebEngineProfile contains settings and history shared by all WebEngineView that belong + to the profile. + + A default profile is built-in that all web pages not specifically created with another profile + belongs to. +*/ + +/*! + \qmlsignal WebEngineProfile::downloadRequested(WebEngineDownloadItem download) + + This signal is emitted whenever a download has been triggered. + The \a download argument holds the state of the download. + The \a download has to be explicitly accepted with WebEngineDownloadItem::accept(), + else the download will be cancelled by default. +*/ + +/*! + \qmlsignal WebEngineProfile::downloadFinished(WebEngineDownloadItem download) + + This signal is emitted whenever a download finishes downloading. + This can be due to the download finishing successfully, being cancelled or + interrupted by lost connectivity for example. + The \a download argument holds the state of the finished download instance. +*/ + +QQuickWebEngineProfile::QQuickWebEngineProfile() + : d_ptr(new QQuickWebEngineProfilePrivate(new BrowserContextAdapter(false), true)) +{ + d_ptr->q_ptr = this; +} + +QQuickWebEngineProfile::QQuickWebEngineProfile(QQuickWebEngineProfilePrivate *privatePtr) + : d_ptr(privatePtr) +{ + d_ptr->q_ptr = this; +} + +QQuickWebEngineProfile::~QQuickWebEngineProfile() +{ +} + +/*! + \qmlproperty QString WebEngineProfile::storageName + + The storage name is used to give each profile that uses the disk separate subdirectories for persistent data and cache. +*/ + +QString QQuickWebEngineProfile::storageName() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->storageName(); +} + +void QQuickWebEngineProfile::setStorageName(const QString &name) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->storageName() == name) + return; + BrowserContextAdapter::HttpCacheType oldCacheType = d->browserContext()->httpCacheType(); + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = d->browserContext()->persistentCookiesPolicy(); + d->browserContext()->setStorageName(name); + emit storageNameChanged(); + emit persistentStoragePathChanged(); + emit cachePathChanged(); + if (d->browserContext()->httpCacheType() != oldCacheType) + emit httpCacheTypeChanged(); + if (d->browserContext()->persistentCookiesPolicy() != oldPolicy) + emit persistentCookiesPolicyChanged(); +} + +/*! + \qmlproperty bool WebEngineProfile::offTheRecord + + An offTheRecord profile forces cookies and HTTP cache to be in memory, but also force + all other normally persistent data to be stored in memory. +*/ +bool QQuickWebEngineProfile::isOffTheRecord() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->isOffTheRecord(); +} + +void QQuickWebEngineProfile::setOffTheRecord(bool offTheRecord) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->isOffTheRecord() == offTheRecord) + return; + BrowserContextAdapter::HttpCacheType oldCacheType = d->browserContext()->httpCacheType(); + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = d->browserContext()->persistentCookiesPolicy(); + d->browserContext()->setOffTheRecord(offTheRecord); + emit offTheRecordChanged(); + if (d->browserContext()->httpCacheType() != oldCacheType) + emit httpCacheTypeChanged(); + if (d->browserContext()->persistentCookiesPolicy() != oldPolicy) + emit persistentCookiesPolicyChanged(); +} + +/*! + \qmlproperty QString WebEngineProfile::persistentStoragePath + + The persistent storage path is where persistent data for the browser and web content is stored. + Persistent data includes persistent cookies, HTML5 local storage and visited links. + + By default this is below QStandardPaths::writableLocation(QStandardPaths::DataLocation) in a storageName specific directory. +*/ +QString QQuickWebEngineProfile::persistentStoragePath() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->dataPath(); +} + +void QQuickWebEngineProfile::setPersistentStoragePath(const QString &path) +{ + Q_D(QQuickWebEngineProfile); + if (persistentStoragePath() == path) + return; + d->browserContext()->setDataPath(path); + emit persistentStoragePathChanged(); +} + +/*! + \qmlproperty QString WebEngineProfile::cachePath + + By default this is below QStandardPaths::writableLocation(QStandardPaths::CacheLocation) in a storageName specific directory. +*/ +QString QQuickWebEngineProfile::cachePath() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->cachePath(); +} + +void QQuickWebEngineProfile::setCachePath(const QString &path) +{ + Q_D(QQuickWebEngineProfile); + if (cachePath() == path) + return; + d->browserContext()->setCachePath(path); + emit cachePathChanged(); +} + +/*! + \qmlproperty QString WebEngineProfile::httpUserAgent + + The user-agent string send with HTTP to identify the browser. +*/ +QString QQuickWebEngineProfile::httpUserAgent() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->httpUserAgent(); +} + +void QQuickWebEngineProfile::setHttpUserAgent(const QString &userAgent) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->httpUserAgent() == userAgent) + return; + d->browserContext()->setHttpUserAgent(userAgent); + emit httpUserAgentChanged(); +} + + +/*! + \qmlproperty enumeration WebEngineProfile::httpCacheType + + The type of the HTTP cache. + + \table + + \header + \li Constant + \li Description + + \row + \li MemoryHttpCache + \li Use a in-memory cache. This is the only setting possible if offTheRecord is set or no cachePath is available. + + \row + \li DiskHttpCache + \li DiskHttpCache Use a disk cache. This is the default. + + \endtable +*/ + +QQuickWebEngineProfile::HttpCacheType QQuickWebEngineProfile::httpCacheType() const +{ + const Q_D(QQuickWebEngineProfile); + return QQuickWebEngineProfile::HttpCacheType(d->browserContext()->httpCacheType()); +} + +void QQuickWebEngineProfile::setHttpCacheType(QQuickWebEngineProfile::HttpCacheType httpCacheType) +{ + Q_D(QQuickWebEngineProfile); + BrowserContextAdapter::HttpCacheType oldCacheType = d->browserContext()->httpCacheType(); + d->browserContext()->setHttpCacheType(BrowserContextAdapter::HttpCacheType(httpCacheType)); + if (d->browserContext()->httpCacheType() != oldCacheType) + emit httpCacheTypeChanged(); +} + +/*! + \qmlproperty enumeration WebEngineProfile::persistentCookiesPolicy + + The policy of cookie persistency. + + \table + + \header + \li Constant + \li Description + + \row + \li NoPersistentCookies + \li Both session and persistent cookies are stored in memory. This is the only setting possible if offTheRecord is set or no persistentStoragePath is available. + + \row + \li AllowPersistentCookies + \li Cookies marked persistent are save and restored from disk, session cookies are only stored to disk for crash recovery. This is the default setting. + + \row + \li ForcePersistentCookies + \li Both session and persistent cookies are save and restored from disk. + + \endtable +*/ + +QQuickWebEngineProfile::PersistentCookiesPolicy QQuickWebEngineProfile::persistentCookiesPolicy() const +{ + const Q_D(QQuickWebEngineProfile); + return QQuickWebEngineProfile::PersistentCookiesPolicy(d->browserContext()->persistentCookiesPolicy()); +} + +void QQuickWebEngineProfile::setPersistentCookiesPolicy(QQuickWebEngineProfile::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + Q_D(QQuickWebEngineProfile); + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = d->browserContext()->persistentCookiesPolicy(); + d->browserContext()->setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy(newPersistentCookiesPolicy)); + if (d->browserContext()->persistentCookiesPolicy() != oldPolicy) + emit persistentCookiesPolicyChanged(); +} + +/*! + \qmlproperty int WebEngineProfile::httpCacheMaximumSize + + The maximum size of the HTTP cache. If 0 it means the size will be controlled automatically by QtWebEngine. + The default value is 0. + + \sa httpCacheType +*/ +int QQuickWebEngineProfile::httpCacheMaximumSize() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->httpCacheMaxSize(); +} + +void QQuickWebEngineProfile::setHttpCacheMaximumSize(int maximumSize) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->httpCacheMaxSize() == maximumSize) + return; + d->browserContext()->setHttpCacheMaxSize(maximumSize); + emit httpCacheMaximumSizeChanged(); +} + +QQuickWebEngineProfile *QQuickWebEngineProfile::defaultProfile() +{ + static QQuickWebEngineProfile profile(new QQuickWebEngineProfilePrivate(BrowserContextAdapter::defaultContext(), false)); + return &profile; +} + +QQuickWebEngineSettings *QQuickWebEngineProfile::settings() const +{ + const Q_D(QQuickWebEngineProfile); + return d->settings(); +} + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h new file mode 100644 index 000000000..f3e0f5c33 --- /dev/null +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 QQUICKWEBENGINEPROFILE_P_H +#define QQUICKWEBENGINEPROFILE_P_H + +#include <private/qtwebengineglobal_p.h> + +#include <QObject> +#include <QScopedPointer> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItem; +class QQuickWebEngineProfilePrivate; +class QQuickWebEngineSettings; + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineProfile : public QObject { + Q_OBJECT + Q_ENUMS(HttpCacheType); + Q_ENUMS(PersistentCookiesPolicy); + Q_PROPERTY(QString storageName READ storageName WRITE setStorageName NOTIFY storageNameChanged FINAL) + Q_PROPERTY(bool offTheRecord READ isOffTheRecord WRITE setOffTheRecord NOTIFY offTheRecordChanged FINAL) + Q_PROPERTY(QString persistentStoragePath READ persistentStoragePath WRITE setPersistentStoragePath NOTIFY persistentStoragePathChanged FINAL) + Q_PROPERTY(QString cachePath READ cachePath WRITE setCachePath NOTIFY cachePathChanged FINAL) + Q_PROPERTY(QString httpUserAgent READ httpUserAgent WRITE setHttpUserAgent NOTIFY httpUserAgentChanged FINAL) + Q_PROPERTY(HttpCacheType httpCacheType READ httpCacheType WRITE setHttpCacheType NOTIFY httpCacheTypeChanged FINAL) + Q_PROPERTY(PersistentCookiesPolicy persistentCookiesPolicy READ persistentCookiesPolicy WRITE setPersistentCookiesPolicy NOTIFY persistentCookiesPolicyChanged FINAL) + Q_PROPERTY(int httpCacheMaximumSize READ httpCacheMaximumSize WRITE setHttpCacheMaximumSize NOTIFY httpCacheMaximumSizeChanged FINAL) +public: + QQuickWebEngineProfile(); + ~QQuickWebEngineProfile(); + + enum HttpCacheType { + MemoryHttpCache, + DiskHttpCache + }; + + enum PersistentCookiesPolicy { + NoPersistentCookies, + AllowPersistentCookies, + ForcePersistentCookies + }; + + QString storageName() const; + void setStorageName(const QString &name); + + bool isOffTheRecord() const; + void setOffTheRecord(bool offTheRecord); + + QString persistentStoragePath() const; + void setPersistentStoragePath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + HttpCacheType httpCacheType() const; + void setHttpCacheType(QQuickWebEngineProfile::HttpCacheType); + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(QQuickWebEngineProfile::PersistentCookiesPolicy); + + int httpCacheMaximumSize() const; + void setHttpCacheMaximumSize(int maxSize); + + static QQuickWebEngineProfile *defaultProfile(); + +signals: + void storageNameChanged(); + void offTheRecordChanged(); + void persistentStoragePathChanged(); + void cachePathChanged(); + void httpUserAgentChanged(); + void httpCacheTypeChanged(); + void persistentCookiesPolicyChanged(); + void httpCacheMaximumSizeChanged(); + + void downloadRequested(QQuickWebEngineDownloadItem *download); + void downloadFinished(QQuickWebEngineDownloadItem *download); + +private: + Q_DECLARE_PRIVATE(QQuickWebEngineProfile) + QQuickWebEngineProfile(QQuickWebEngineProfilePrivate *); + QQuickWebEngineSettings *settings() const; + + friend class QQuickWebEngineSettings; + friend class QQuickWebEngineSingleton; + friend class QQuickWebEngineViewPrivate; + QScopedPointer<QQuickWebEngineProfilePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEPROFILE_P_H diff --git a/src/webengine/api/qquickwebengineprofile_p_p.h b/src/webengine/api/qquickwebengineprofile_p_p.h new file mode 100644 index 000000000..6b6026abb --- /dev/null +++ b/src/webengine/api/qquickwebengineprofile_p_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 QQUICKWEBENGINEPROFILE_P_P_H +#define QQUICKWEBENGINEPROFILE_P_P_H + +class BrowserContextAdapter; + +#include "browser_context_adapter_client.h" +#include "qquickwebengineprofile_p.h" + +#include <QExplicitlySharedDataPointer> +#include <QMap> +#include <QPointer> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItem; +class QQuickWebEngineSettings; + +class QQuickWebEngineProfilePrivate : public BrowserContextAdapterClient { +public: + Q_DECLARE_PUBLIC(QQuickWebEngineProfile) + QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext); + ~QQuickWebEngineProfilePrivate(); + + BrowserContextAdapter *browserContext() const { return m_browserContext; } + QQuickWebEngineSettings *settings() const { return m_settings.data(); } + + void cancelDownload(quint32 downloadId); + void downloadDestroyed(quint32 downloadId); + + void downloadRequested(DownloadItemInfo &info) Q_DECL_OVERRIDE; + void downloadUpdated(const DownloadItemInfo &info) Q_DECL_OVERRIDE; + +private: + friend class QQuickWebEngineViewPrivate; + QQuickWebEngineProfile *q_ptr; + QScopedPointer<QQuickWebEngineSettings> m_settings; + BrowserContextAdapter *m_browserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_browserContextRef; + QMap<quint32, QPointer<QQuickWebEngineDownloadItem> > m_ongoingDownloads; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEPROFILE_P_P_H diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp index 743d22d81..f4c9a656d 100644 --- a/src/webengine/api/qquickwebenginesettings.cpp +++ b/src/webengine/api/qquickwebenginesettings.cpp @@ -35,238 +35,184 @@ ****************************************************************************/ #include "qquickwebenginesettings_p.h" -#include "qquickwebenginesettings_p_p.h" + +#include "qquickwebengineprofile_p.h" +#include "web_engine_settings.h" #include <QtCore/QList> QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC(QList<QQuickWebEngineSettingsPrivate*>, allSettings) - -QQuickWebEngineSettingsPrivate::QQuickWebEngineSettingsPrivate() - : coreSettings(new WebEngineSettings(this)) -{ - allSettings->append(this); -} - -void QQuickWebEngineSettingsPrivate::apply() -{ - coreSettings->scheduleApply(); - QQuickWebEngineSettingsPrivate *globals = QQuickWebEngineSettings::globalSettings()->d_func(); - Q_ASSERT((this == globals) != (allSettings->contains(this))); - if (this == globals) - Q_FOREACH (QQuickWebEngineSettingsPrivate *settings, *allSettings) - settings->coreSettings->scheduleApply(); -} - -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; -} +QQuickWebEngineSettings::QQuickWebEngineSettings(QQuickWebEngineSettings *parentSettings) + : d_ptr(new WebEngineSettings(parentSettings ? parentSettings->d_ptr.data() : 0)) +{ } QQuickWebEngineSettings::~QQuickWebEngineSettings() -{ - allSettings->removeAll(this->d_func()); -} +{ } bool QQuickWebEngineSettings::autoLoadImages() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::AutoLoadImages); + return d_ptr->testAttribute(WebEngineSettings::AutoLoadImages); } bool QQuickWebEngineSettings::javascriptEnabled() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::JavascriptEnabled); + return d_ptr->testAttribute(WebEngineSettings::JavascriptEnabled); } bool QQuickWebEngineSettings::javascriptCanOpenWindows() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanOpenWindows); + return d_ptr->testAttribute(WebEngineSettings::JavascriptCanOpenWindows); } bool QQuickWebEngineSettings::javascriptCanAccessClipboard() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard); + return d_ptr->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard); } bool QQuickWebEngineSettings::linksIncludedInFocusChain() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::LinksIncludedInFocusChain); + return d_ptr->testAttribute(WebEngineSettings::LinksIncludedInFocusChain); } bool QQuickWebEngineSettings::localStorageEnabled() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::LocalStorageEnabled); + return d_ptr->testAttribute(WebEngineSettings::LocalStorageEnabled); } bool QQuickWebEngineSettings::localContentCanAccessRemoteUrls() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls); + return d_ptr->testAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls); } bool QQuickWebEngineSettings::spatialNavigationEnabled() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::SpatialNavigationEnabled); + return d_ptr->testAttribute(WebEngineSettings::SpatialNavigationEnabled); } bool QQuickWebEngineSettings::localContentCanAccessFileUrls() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls); + return d_ptr->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls); } bool QQuickWebEngineSettings::hyperlinkAuditingEnabled() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::HyperlinkAuditingEnabled); + return d_ptr->testAttribute(WebEngineSettings::HyperlinkAuditingEnabled); } bool QQuickWebEngineSettings::errorPageEnabled() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->testAttribute(WebEngineSettings::ErrorPageEnabled); + return d_ptr->testAttribute(WebEngineSettings::ErrorPageEnabled); } QString QQuickWebEngineSettings::defaultTextEncoding() const { - Q_D(const QQuickWebEngineSettings); - return d->coreSettings->defaultTextEncoding(); + return d_ptr->defaultTextEncoding(); } void QQuickWebEngineSettings::setAutoLoadImages(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::AutoLoadImages); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::AutoLoadImages); // Set unconditionally as it sets the override for the current settings while the current setting // 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); + d_ptr->setAttribute(WebEngineSettings::AutoLoadImages, on); + if (wasOn != on) + Q_EMIT autoLoadImagesChanged(); } void QQuickWebEngineSettings::setJavascriptEnabled(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptEnabled); - d->coreSettings->setAttribute(WebEngineSettings::JavascriptEnabled, on); - if (wasOn ^ on) - Q_EMIT javascriptEnabledChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::JavascriptEnabled); + d_ptr->setAttribute(WebEngineSettings::JavascriptEnabled, on); + if (wasOn != on) + Q_EMIT javascriptEnabledChanged(); } void QQuickWebEngineSettings::setJavascriptCanOpenWindows(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanOpenWindows); - d->coreSettings->setAttribute(WebEngineSettings::JavascriptCanOpenWindows, on); - if (wasOn ^ on) - Q_EMIT javascriptCanOpenWindowsChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::JavascriptCanOpenWindows); + d_ptr->setAttribute(WebEngineSettings::JavascriptCanOpenWindows, on); + if (wasOn != on) + Q_EMIT javascriptCanOpenWindowsChanged(); } void QQuickWebEngineSettings::setJavascriptCanAccessClipboard(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard); - d->coreSettings->setAttribute(WebEngineSettings::JavascriptCanAccessClipboard, on); - if (wasOn ^ on) - Q_EMIT javascriptCanAccessClipboardChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard); + d_ptr->setAttribute(WebEngineSettings::JavascriptCanAccessClipboard, on); + if (wasOn != on) + Q_EMIT javascriptCanAccessClipboardChanged(); } void QQuickWebEngineSettings::setLinksIncludedInFocusChain(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LinksIncludedInFocusChain); - d->coreSettings->setAttribute(WebEngineSettings::LinksIncludedInFocusChain, on); - if (wasOn ^ on) - Q_EMIT linksIncludedInFocusChainChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::LinksIncludedInFocusChain); + d_ptr->setAttribute(WebEngineSettings::LinksIncludedInFocusChain, on); + if (wasOn != on) + Q_EMIT linksIncludedInFocusChainChanged(); } void QQuickWebEngineSettings::setLocalStorageEnabled(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalStorageEnabled); - d->coreSettings->setAttribute(WebEngineSettings::LocalStorageEnabled, on); - if (wasOn ^ on) - Q_EMIT localStorageEnabledChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::LocalStorageEnabled); + d_ptr->setAttribute(WebEngineSettings::LocalStorageEnabled, on); + if (wasOn != on) + Q_EMIT localStorageEnabledChanged(); } void QQuickWebEngineSettings::setLocalContentCanAccessRemoteUrls(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls); - d->coreSettings->setAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls, on); - if (wasOn ^ on) - Q_EMIT localContentCanAccessRemoteUrlsChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls); + d_ptr->setAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls, on); + if (wasOn != on) + Q_EMIT localContentCanAccessRemoteUrlsChanged(); } void QQuickWebEngineSettings::setSpatialNavigationEnabled(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::SpatialNavigationEnabled); - d->coreSettings->setAttribute(WebEngineSettings::SpatialNavigationEnabled, on); - if (wasOn ^ on) - Q_EMIT spatialNavigationEnabledChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::SpatialNavigationEnabled); + d_ptr->setAttribute(WebEngineSettings::SpatialNavigationEnabled, on); + if (wasOn != on) + Q_EMIT spatialNavigationEnabledChanged(); } void QQuickWebEngineSettings::setLocalContentCanAccessFileUrls(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls); - d->coreSettings->setAttribute(WebEngineSettings::LocalContentCanAccessFileUrls, on); - if (wasOn ^ on) - Q_EMIT localContentCanAccessFileUrlsChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls); + d_ptr->setAttribute(WebEngineSettings::LocalContentCanAccessFileUrls, on); + if (wasOn != on) + Q_EMIT localContentCanAccessFileUrlsChanged(); } void QQuickWebEngineSettings::setHyperlinkAuditingEnabled(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::HyperlinkAuditingEnabled); - d->coreSettings->setAttribute(WebEngineSettings::HyperlinkAuditingEnabled, on); - if (wasOn ^ on) - Q_EMIT hyperlinkAuditingEnabledChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::HyperlinkAuditingEnabled); + d_ptr->setAttribute(WebEngineSettings::HyperlinkAuditingEnabled, on); + if (wasOn != on) + Q_EMIT hyperlinkAuditingEnabledChanged(); } void QQuickWebEngineSettings::setErrorPageEnabled(bool on) { - Q_D(QQuickWebEngineSettings); - bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::ErrorPageEnabled); - d->coreSettings->setAttribute(WebEngineSettings::ErrorPageEnabled, on); - if (wasOn ^ on) - Q_EMIT errorPageEnabledChanged(on); + bool wasOn = d_ptr->testAttribute(WebEngineSettings::ErrorPageEnabled); + d_ptr->setAttribute(WebEngineSettings::ErrorPageEnabled, on); + if (wasOn != on) + Q_EMIT errorPageEnabledChanged(); } void QQuickWebEngineSettings::setDefaultTextEncoding(QString encoding) { - Q_D(QQuickWebEngineSettings); - const QString oldDefaultTextEncoding = d->coreSettings->defaultTextEncoding(); - d->coreSettings->setDefaultTextEncoding(encoding); + const QString oldDefaultTextEncoding = d_ptr->defaultTextEncoding(); + d_ptr->setDefaultTextEncoding(encoding); if (oldDefaultTextEncoding.compare(encoding)) - Q_EMIT defaultTextEncodingChanged(encoding); + Q_EMIT defaultTextEncodingChanged(); } -QQuickWebEngineSettings::QQuickWebEngineSettings() - : d_ptr(new QQuickWebEngineSettingsPrivate) +void QQuickWebEngineSettings::setParentSettings(QQuickWebEngineSettings *parentSettings) { + d_ptr->setParentSettings(parentSettings->d_ptr.data()); + d_ptr->scheduleApplyRecursively(); } QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index 4a7c2f834..6e8bfa219 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -41,9 +41,9 @@ #include <QObject> #include <QScopedPointer> -QT_BEGIN_NAMESPACE +class WebEngineSettings; -class QQuickWebEngineSettingsPrivate; +QT_BEGIN_NAMESPACE class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_OBJECT @@ -61,8 +61,6 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_PROPERTY(QString defaultTextEncoding READ defaultTextEncoding WRITE setDefaultTextEncoding NOTIFY defaultTextEncodingChanged) public: - static QQuickWebEngineSettings *globalSettings(); - ~QQuickWebEngineSettings(); bool autoLoadImages() const; @@ -92,26 +90,28 @@ 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(); + explicit QQuickWebEngineSettings(QQuickWebEngineSettings *parentSettings = 0); Q_DISABLE_COPY(QQuickWebEngineSettings) - Q_DECLARE_PRIVATE(QQuickWebEngineSettings) + friend class QQuickWebEngineProfilePrivate; friend class QQuickWebEngineViewPrivate; - QScopedPointer<QQuickWebEngineSettingsPrivate> d_ptr; + void setParentSettings(QQuickWebEngineSettings *parentSettings); + + QScopedPointer<WebEngineSettings> d_ptr; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginesingleton.cpp b/src/webengine/api/qquickwebenginesingleton.cpp index bf4951f3b..4f1bd32f2 100644 --- a/src/webengine/api/qquickwebenginesingleton.cpp +++ b/src/webengine/api/qquickwebenginesingleton.cpp @@ -37,12 +37,18 @@ #include "qquickwebenginesingleton_p.h" #include "qquickwebenginesettings_p.h" +#include "qquickwebengineprofile_p.h" QT_BEGIN_NAMESPACE QQuickWebEngineSettings *QQuickWebEngineSingleton::settings() const { - return QQuickWebEngineSettings::globalSettings(); + return defaultProfile()->settings(); +} + +QQuickWebEngineProfile *QQuickWebEngineSingleton::defaultProfile() const +{ + return QQuickWebEngineProfile::defaultProfile(); } QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginesingleton_p.h b/src/webengine/api/qquickwebenginesingleton_p.h index 23205e2df..f983d0ffb 100644 --- a/src/webengine/api/qquickwebenginesingleton_p.h +++ b/src/webengine/api/qquickwebenginesingleton_p.h @@ -41,14 +41,16 @@ #include <qtwebengineglobal_p.h> QT_BEGIN_NAMESPACE +class QQuickWebEngineProfile; class QQuickWebEngineSettings; - class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSingleton : public QObject { Q_OBJECT Q_PROPERTY(QQuickWebEngineSettings* settings READ settings CONSTANT FINAL) + Q_PROPERTY(QQuickWebEngineProfile* defaultProfile READ defaultProfile CONSTANT FINAL REVISION 1) public: QQuickWebEngineSettings *settings() const; + QQuickWebEngineProfile *defaultProfile() const; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 3497c16ad..a47defb7c 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -37,14 +37,17 @@ #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" +#include "qquickwebenginecertificateerror_p.h" #include "qquickwebengineloadrequest_p.h" #include "qquickwebenginenavigationrequest_p.h" #include "qquickwebenginenewviewrequest_p.h" +#include "qquickwebengineprofile_p.h" +#include "qquickwebengineprofile_p_p.h" #include "qquickwebenginesettings_p.h" -#include "qquickwebenginesettings_p_p.h" #include "render_widget_host_view_qt_delegate_quick.h" #include "render_widget_host_view_qt_delegate_quickwindow.h" #include "ui_delegates_manager.h" @@ -58,29 +61,34 @@ #include <QQmlContext> #include <QQmlEngine> #include <QQmlProperty> +#include <QQmlWebChannel> #include <QScreen> #include <QStringBuilder> #include <QUrl> +#ifndef QT_NO_ACCESSIBILITY #include <private/qquickaccessibleattached_p.h> +#endif // QT_NO_ACCESSIBILITY QT_BEGIN_NAMESPACE +#ifndef QT_NO_ACCESSIBILITY static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object) { if (QQuickWebEngineView *v = qobject_cast<QQuickWebEngineView*>(object)) return new QQuickWebEngineViewAccessible(v); return 0; } +#endif // QT_NO_ACCESSIBILITY QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() - : adapter(new WebContentsAdapter) + : adapter(0) , e(new QQuickWebEngineViewExperimental(this)) , v(new QQuickWebEngineViewport(this)) , m_history(new QQuickWebEngineHistory(this)) - , m_settings(new QQuickWebEngineSettings) + , m_profile(QQuickWebEngineProfile::defaultProfile()) + , m_settings(new QQuickWebEngineSettings(m_profile->settings())) , contextMenuExtraItems(0) , loadProgress(0) - , inspectable(false) , m_isFullScreen(false) , isLoading(false) , devicePixelRatio(QGuiApplication::primaryScreen()->devicePixelRatio()) @@ -102,7 +110,9 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() // 1x, 2x, 3x etc assets that fit an integral number of pixels. setDevicePixelRatio(qMax(1, qRound(webPixelRatio))); } +#ifndef QT_NO_ACCESSIBILITY QAccessible::installFactory(&webAccessibleFactory); +#endif // QT_NO_ACCESSIBILITY } QQuickWebEngineViewPrivate::~QQuickWebEngineViewPrivate() @@ -211,10 +221,21 @@ void QQuickWebEngineViewPrivate::javascriptDialog(QSharedPointer<JavaScriptDialo ui()->showDialog(dialog); } -void QQuickWebEngineViewPrivate::allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController) +void QQuickWebEngineViewPrivate::allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) { - // ### Implement a way to export this to QML - Q_UNUSED(errorController); + Q_Q(QQuickWebEngineView); + + m_certificateErrorController = errorController; + QQuickWebEngineCertificateError *quickController = new QQuickWebEngineCertificateError(errorController); + QQmlEngine::setObjectOwnership(quickController, QQmlEngine::JavaScriptOwnership); + Q_EMIT q->certificateError(quickController); + if (!quickController->deferred()) + quickController->rejectCertificate(); +} + +void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url) +{ + Q_EMIT e->featurePermissionRequested(url, QQuickWebEngineViewExperimental::Geolocation); } void QQuickWebEngineViewPrivate::runFileChooser(FileChooserMode mode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) @@ -333,8 +354,16 @@ void QQuickWebEngineViewPrivate::focusContainer() q->forceActiveFocus(); } +void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event) +{ + Q_Q(QQuickWebEngineView); + if (q->parentItem()) + q->window()->sendEvent(q->parentItem(), event); +} + void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &) { + Q_Q(QQuickWebEngineView); QQuickWebEngineNewViewRequest request; // This increases the ref-count of newWebContents and will tell Chromium // to start loading it and possibly return it to its parent page window.open(). @@ -343,9 +372,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 +387,7 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebConten Q_UNREACHABLE(); } - emit e->newViewRequested(&request); + Q_EMIT q->newViewRequested(&request); } void QQuickWebEngineViewPrivate::close() @@ -387,23 +418,39 @@ 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); } +void QQuickWebEngineViewPrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) +{ + + Q_UNUSED(securityOrigin); + + // TODO: Add mouse lock support + adapter->grantMouseLockPermission(false); +} + +#ifndef QT_NO_ACCESSIBILITY QObject *QQuickWebEngineViewPrivate::accessibilityParentObject() { Q_Q(QQuickWebEngineView); return q; } +#endif // QT_NO_ACCESSIBILITY + +BrowserContextAdapter *QQuickWebEngineViewPrivate::browserContextAdapter() +{ + return m_profile->d_ptr->browserContext(); +} WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const { - return m_settings->d_func()->coreSettings.data(); + return m_settings->d_ptr.data(); } void QQuickWebEngineViewPrivate::setDevicePixelRatio(qreal devicePixelRatio) @@ -414,6 +461,7 @@ void QQuickWebEngineViewPrivate::setDevicePixelRatio(qreal devicePixelRatio) m_dpiScale = devicePixelRatio / screen->devicePixelRatio(); } +#ifndef QT_NO_ACCESSIBILITY QQuickWebEngineViewAccessible::QQuickWebEngineViewAccessible(QQuickWebEngineView *o) : QAccessibleObject(o) {} @@ -460,6 +508,7 @@ QAccessible::State QQuickWebEngineViewAccessible::state() const QAccessible::State s; return s; } +#endif // QT_NO_ACCESSIBILITY void QQuickWebEngineViewPrivate::adoptWebContents(WebContentsAdapter *webContents) { @@ -470,6 +519,11 @@ void QQuickWebEngineViewPrivate::adoptWebContents(WebContentsAdapter *webContent return; } + if (browserContextAdapter() != webContents->browserContextAdapter()) { + qWarning("Can not adopt content from a different WebEngineProfile."); + return; + } + Q_Q(QQuickWebEngineView); // This throws away the WebContentsAdapter that has been used until now. // All its states, particularly the loading URL, are replaced by the adopted WebContentsAdapter. @@ -493,22 +547,33 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) { Q_D(QQuickWebEngineView); d->e->q_ptr = d->q_ptr = this; - d->adapter->initialize(d); this->setActiveFocusOnTab(true); this->setFlag(QQuickItem::ItemIsFocusScope); +#ifndef QT_NO_ACCESSIBILITY QQuickAccessibleAttached *accessible = QQuickAccessibleAttached::qmlAttachedProperties(this); accessible->setRole(QAccessible::Grouping); +#endif // QT_NO_ACCESSIBILITY } QQuickWebEngineView::~QQuickWebEngineView() { } +void QQuickWebEngineViewPrivate::ensureContentsAdapter() +{ + if (!adapter) { + adapter = new WebContentsAdapter(); + adapter->initialize(this); + if (explicitUrl.isValid()) + adapter->load(explicitUrl); + } +} + QUrl QQuickWebEngineView::url() const { Q_D(const QQuickWebEngineView); - return d->explicitUrl.isValid() ? d->explicitUrl : d->adapter->activeUrl(); + return d->explicitUrl.isValid() ? d->explicitUrl : (d->adapter ? d->adapter->activeUrl() : QUrl()); } void QQuickWebEngineView::setUrl(const QUrl& url) @@ -518,7 +583,10 @@ void QQuickWebEngineView::setUrl(const QUrl& url) Q_D(QQuickWebEngineView); d->explicitUrl = url; - d->adapter->load(url); + if (d->adapter) + d->adapter->load(url); + if (!qmlEngine(this)) + d->ensureContentsAdapter(); } QUrl QQuickWebEngineView::icon() const @@ -530,33 +598,93 @@ QUrl QQuickWebEngineView::icon() const void QQuickWebEngineView::loadHtml(const QString &html, const QUrl &baseUrl) { Q_D(QQuickWebEngineView); - d->adapter->setContent(html.toUtf8(), QStringLiteral("text/html;charset=UTF-8"), baseUrl); + d->explicitUrl = QUrl(); + if (!qmlEngine(this)) + d->ensureContentsAdapter(); + if (d->adapter) + d->adapter->setContent(html.toUtf8(), QStringLiteral("text/html;charset=UTF-8"), baseUrl); } void QQuickWebEngineView::goBack() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->navigateToOffset(-1); } void QQuickWebEngineView::goForward() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->navigateToOffset(1); } void QQuickWebEngineView::reload() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->reload(); } void QQuickWebEngineView::stop() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->stop(); } +void QQuickWebEngineView::setZoomFactor(qreal arg) +{ + Q_D(QQuickWebEngineView); + if (!d->adapter) + return; + qreal oldFactor = d->adapter->currentZoomFactor(); + d->adapter->setZoomFactor(arg); + if (qFuzzyCompare(oldFactor, d->adapter->currentZoomFactor())) + return; + + emit zoomFactorChanged(arg); +} + +QQuickWebEngineProfile *QQuickWebEngineView::profile() const +{ + Q_D(const QQuickWebEngineView); + return d->m_profile; +} + +void QQuickWebEngineView::setProfile(QQuickWebEngineProfile *profile) +{ + Q_D(QQuickWebEngineView); + d->setProfile(profile); +} + +QQuickWebEngineSettings *QQuickWebEngineView::settings() const +{ + Q_D(const QQuickWebEngineView); + return d->m_settings.data(); +} + +void QQuickWebEngineViewPrivate::setProfile(QQuickWebEngineProfile *profile) +{ + if (profile == m_profile) + return; + m_profile = profile; + m_settings->setParentSettings(profile->settings()); + + if (adapter && adapter->browserContext() != browserContextAdapter()->browserContext()) { + // When the profile changes we need to create a new WebContentAdapter and reload the active URL. + QUrl activeUrl = adapter->activeUrl(); + adapter = 0; + ensureContentsAdapter(); + if (!explicitUrl.isValid() && activeUrl.isValid()) + adapter->load(activeUrl); + } +} + void QQuickWebEngineViewPrivate::didRunJavaScript(quint64 requestId, const QVariant &result) { Q_Q(QQuickWebEngineView); @@ -589,24 +717,32 @@ int QQuickWebEngineView::loadProgress() const QString QQuickWebEngineView::title() const { Q_D(const QQuickWebEngineView); + if (!d->adapter) + return QString(); return d->adapter->pageTitle(); } bool QQuickWebEngineView::canGoBack() const { Q_D(const QQuickWebEngineView); + if (!d->adapter) + return false; return d->adapter->canGoBack(); } bool QQuickWebEngineView::canGoForward() const { Q_D(const QQuickWebEngineView); + if (!d->adapter) + return false; return d->adapter->canGoForward(); } void QQuickWebEngineView::runJavaScript(const QString &script, const QJSValue &callback) { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; if (!callback.isUndefined()) { quint64 requestId = d_ptr->adapter->runJavaScriptCallbackResult(script); d->m_callbacks.insert(requestId, callback); @@ -620,17 +756,12 @@ QQuickWebEngineViewExperimental *QQuickWebEngineView::experimental() const return d->e.data(); } -bool QQuickWebEngineViewExperimental::inspectable() const +qreal QQuickWebEngineView::zoomFactor() const { Q_D(const QQuickWebEngineView); - return d->inspectable; -} - -void QQuickWebEngineViewExperimental::setInspectable(bool enable) -{ - Q_D(QQuickWebEngineView); - d->inspectable = enable; - d->adapter->enableInspector(enable); + if (!d->adapter) + return 1.0; + return d->adapter->currentZoomFactor(); } void QQuickWebEngineViewExperimental::setIsFullScreen(bool fullscreen) @@ -657,24 +788,22 @@ QQmlComponent *QQuickWebEngineViewExperimental::extraContextMenuEntriesComponent return d_ptr->contextMenuExtraItems; } -QQuickWebEngineSettings *QQuickWebEngineViewExperimental::settings() const -{ - return d_ptr->m_settings.data(); -} - void QQuickWebEngineViewExperimental::findText(const QString &subString, FindFlags options, const QJSValue &callback) { + Q_D(QQuickWebEngineView); + if (!d->adapter) + return; if (subString.isEmpty()) { - d_ptr->adapter->stopFinding(); + d->adapter->stopFinding(); if (!callback.isUndefined()) { QJSValueList args; args.append(QJSValue(0)); const_cast<QJSValue&>(callback).call(args); } } else { - quint64 requestId = d_ptr->adapter->findText(subString, options & FindCaseSensitively, options & FindBackward); + quint64 requestId = d->adapter->findText(subString, options & FindCaseSensitively, options & FindBackward); if (!callback.isUndefined()) - d_ptr->m_callbacks.insert(requestId, callback); + d->m_callbacks.insert(requestId, callback); } } @@ -683,29 +812,54 @@ QQuickWebEngineHistory *QQuickWebEngineViewExperimental::navigationHistory() con return d_ptr->m_history.data(); } +QQmlWebChannel *QQuickWebEngineViewExperimental::webChannel() const +{ + d_ptr->ensureContentsAdapter(); + QQmlWebChannel *qmlWebChannel = qobject_cast<QQmlWebChannel *>(d_ptr->adapter->webChannel()); + Q_ASSERT(!d_ptr->adapter->webChannel() || qmlWebChannel); + if (!qmlWebChannel) { + qmlWebChannel = new QQmlWebChannel; + d_ptr->adapter->setWebChannel(qmlWebChannel); + } + return qmlWebChannel; +} + +void QQuickWebEngineViewExperimental::setWebChannel(QQmlWebChannel *webChannel) +{ + d_ptr->adapter->setWebChannel(webChannel); +} + void QQuickWebEngineViewExperimental::grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineViewExperimental::Feature feature, bool granted) { - if (!granted && feature >= MediaAudioDevices && feature <= MediaAudioVideoDevices) { + if (!d_ptr->adapter) + return; + 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(); } } void QQuickWebEngineViewExperimental::goBackTo(int index) { + if (!d_ptr->adapter) + return; int count = d_ptr->adapter->currentNavigationEntryIndex(); if (index < 0 || index >= count) return; @@ -715,6 +869,8 @@ void QQuickWebEngineViewExperimental::goBackTo(int index) void QQuickWebEngineViewExperimental::goForwardTo(int index) { + if (!d_ptr->adapter) + return; int count = d_ptr->adapter->navigationEntryCount() - d_ptr->adapter->currentNavigationEntryIndex() - 1; if (index < 0 || index >= count) return; @@ -734,7 +890,7 @@ void QQuickWebEngineView::geometryChanged(const QRectF &newGeometry, const QRect void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &value) { Q_D(QQuickWebEngineView); - if (change == ItemSceneChange || change == ItemVisibleHasChanged) { + if (d->adapter && (change == ItemSceneChange || change == ItemVisibleHasChanged)) { if (window() && isVisible()) d->adapter->wasShown(); else @@ -743,6 +899,13 @@ void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &va QQuickItem::itemChange(change, value); } +void QQuickWebEngineView::componentComplete() +{ + Q_D(QQuickWebEngineView); + QQuickItem::componentComplete(); + d->ensureContentsAdapter(); +} + QQuickWebEngineViewExperimental::QQuickWebEngineViewExperimental(QQuickWebEngineViewPrivate *viewPrivate) : q_ptr(0) , d_ptr(viewPrivate) @@ -774,6 +937,8 @@ void QQuickWebEngineViewport::setDevicePixelRatio(qreal devicePixelRatio) if (d->devicePixelRatio == devicePixelRatio) return; d->setDevicePixelRatio(devicePixelRatio); + if (!d->adapter) + return; d->adapter->dpiScaleChanged(); Q_EMIT devicePixelRatioChanged(); } diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 22713ee22..56a1b47ab 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -42,10 +42,14 @@ QT_BEGIN_NAMESPACE -class QQuickWebEngineViewExperimental; -class QQuickWebEngineViewPrivate; +class QQuickWebEngineCertificateError; class QQuickWebEngineLoadRequest; class QQuickWebEngineNavigationRequest; +class QQuickWebEngineNewViewRequest; +class QQuickWebEngineProfile; +class QQuickWebEngineSettings; +class QQuickWebEngineViewExperimental; +class QQuickWebEngineViewPrivate; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_OBJECT @@ -56,6 +60,9 @@ 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 REVISION 1) + Q_PROPERTY(QQuickWebEngineProfile *profile READ profile WRITE setProfile FINAL REVISION 1) + Q_PROPERTY(QQuickWebEngineSettings *settings READ settings REVISION 1) Q_ENUMS(NavigationRequestAction); Q_ENUMS(NavigationType); Q_ENUMS(LoadStatus); @@ -75,6 +82,8 @@ public: QString title() const; bool canGoBack() const; bool canGoForward() const; + qreal zoomFactor() const; + void setZoomFactor(qreal arg); QQuickWebEngineViewExperimental *experimental() const; @@ -116,7 +125,8 @@ public: enum NewViewDestination { NewViewInWindow, NewViewInTab, - NewViewInDialog + NewViewInDialog, + NewViewInBackgroundTab }; // must match WebContentsAdapterClient::JavaScriptConsoleMessageLevel @@ -126,6 +136,14 @@ public: ErrorMessageLevel }; + // QmlParserStatus + virtual void componentComplete() Q_DECL_OVERRIDE; + + QQuickWebEngineProfile *profile() const; + void setProfile(QQuickWebEngineProfile *); + + QQuickWebEngineSettings *settings() const; + public Q_SLOTS: void runJavaScript(const QString&, const QJSValue & = QJSValue()); void loadHtml(const QString &html, const QUrl &baseUrl = QUrl()); @@ -143,6 +161,9 @@ Q_SIGNALS: void linkHovered(const QUrl &hoveredUrl); void navigationRequested(QQuickWebEngineNavigationRequest *request); void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); + Q_REVISION(1) void certificateError(QQuickWebEngineCertificateError *error); + Q_REVISION(1) void newViewRequested(QQuickWebEngineNewViewRequest *request); + Q_REVISION(1) void zoomFactorChanged(qreal arg); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); @@ -155,7 +176,9 @@ private: friend class QQuickWebEngineViewExperimental; friend class QQuickWebEngineViewExperimentalExtension; friend class QQuickWebEngineNewViewRequest; +#ifndef QT_NO_ACCESSIBILITY friend class QQuickWebEngineViewAccessible; +#endif // QT_NO_ACCESSIBILITY }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 6662f1f02..d7785092f 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -51,11 +51,11 @@ class UIDelegatesManager; QT_BEGIN_NAMESPACE class QQuickWebEngineHistory; -class QQuickWebEngineNewViewRequest; class QQuickWebEngineView; class QQmlComponent; class QQmlContext; class QQuickWebEngineSettings; +class QQmlWebChannel; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewport : public QObject { Q_OBJECT @@ -79,18 +79,18 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewExperimental : public QObjec Q_OBJECT Q_PROPERTY(QQuickWebEngineViewport *viewport READ viewport) Q_PROPERTY(QQmlComponent *extraContextMenuEntriesComponent READ extraContextMenuEntriesComponent WRITE setExtraContextMenuEntriesComponent NOTIFY extraContextMenuEntriesComponentChanged) - Q_PROPERTY(bool inspectable READ inspectable WRITE setInspectable) Q_PROPERTY(bool isFullScreen READ isFullScreen WRITE setIsFullScreen NOTIFY isFullScreenChanged) Q_PROPERTY(QQuickWebEngineHistory *navigationHistory READ navigationHistory CONSTANT FINAL) - Q_PROPERTY(QQuickWebEngineSettings *settings READ settings) + Q_PROPERTY(QQmlWebChannel *webChannel READ webChannel WRITE setWebChannel) Q_ENUMS(Feature) Q_FLAGS(FindFlags) public: enum Feature { - MediaAudioDevices, - MediaVideoDevices, - MediaAudioVideoDevices + MediaAudioCapture, + MediaVideoCapture, + MediaAudioVideoCapture, + Geolocation }; enum FindFlag { @@ -99,8 +99,6 @@ public: }; Q_DECLARE_FLAGS(FindFlags, FindFlag) - bool inspectable() const; - void setInspectable(bool); void setIsFullScreen(bool fullscreen); bool isFullScreen() const; QQuickWebEngineViewport *viewport() const; @@ -108,6 +106,8 @@ public: QQmlComponent *extraContextMenuEntriesComponent() const; QQuickWebEngineHistory *navigationHistory() const; QQuickWebEngineSettings *settings() const; + QQmlWebChannel *webChannel() const; + void setWebChannel(QQmlWebChannel *); public Q_SLOTS: void goBackTo(int index); @@ -116,7 +116,6 @@ public Q_SLOTS: void grantFeaturePermission(const QUrl &securityOrigin, Feature, bool granted); Q_SIGNALS: - void newViewRequested(QQuickWebEngineNewViewRequest *request); void fullScreenRequested(bool fullScreen); void isFullScreenChanged(); void extraContextMenuEntriesComponentChanged(); @@ -159,6 +158,7 @@ public: virtual void loadVisuallyCommitted() Q_DECL_OVERRIDE; virtual void loadFinished(bool success, const QUrl &url, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE; virtual void focusContainer() Q_DECL_OVERRIDE; + virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE; virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &) Q_DECL_OVERRIDE; virtual void close() Q_DECL_OVERRIDE; virtual void requestFullScreen(bool) Q_DECL_OVERRIDE; @@ -175,33 +175,43 @@ public: virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; virtual void authenticationRequired(const QUrl&, const QString&, bool, const QString&, QString*, QString*) Q_DECL_OVERRIDE { } virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) Q_DECL_OVERRIDE; + virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; +#ifndef QT_NO_ACCESSIBILITY virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; +#endif // QT_NO_ACCESSIBILITY virtual WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; - virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController); + virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController); + virtual void runGeolocationPermissionRequest(QUrl const&) Q_DECL_OVERRIDE; + + virtual BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal); void adoptWebContents(WebContentsAdapter *webContents); + void setProfile(QQuickWebEngineProfile *profile); + void ensureContentsAdapter(); QExplicitlySharedDataPointer<WebContentsAdapter> adapter; QScopedPointer<QQuickWebEngineViewExperimental> e; QScopedPointer<QQuickWebEngineViewport> v; QScopedPointer<QQuickWebEngineHistory> m_history; + QQuickWebEngineProfile *m_profile; QScopedPointer<QQuickWebEngineSettings> m_settings; QQmlComponent *contextMenuExtraItems; QUrl explicitUrl; QUrl icon; int loadProgress; - bool inspectable; bool m_isFullScreen; bool isLoading; qreal devicePixelRatio; QMap<quint64, QJSValue> m_callbacks; + QSharedPointer<CertificateErrorController> m_certificateErrorController; private: QScopedPointer<UIDelegatesManager> m_uIDelegatesManager; qreal m_dpiScale; }; +#ifndef QT_NO_ACCESSIBILITY class QQuickWebEngineViewAccessible : public QAccessibleObject { public: @@ -217,7 +227,7 @@ public: private: QQuickWebEngineView *engineView() const { return static_cast<QQuickWebEngineView*>(object()); } }; - +#endif // QT_NO_ACCESSIBILITY QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickWebEngineViewExperimental) diff --git a/src/webengine/doc/qtwebengine.qdocconf b/src/webengine/doc/qtwebengine.qdocconf index e5abeafd6..ad6898440 100644 --- a/src/webengine/doc/qtwebengine.qdocconf +++ b/src/webengine/doc/qtwebengine.qdocconf @@ -33,7 +33,7 @@ depends += qtcore qtgui qtquick qtquickcontrols qtdoc headerdirs += . ../api sourcedirs += . ../api -exampledirs += ../../../examples/webengine +exampledirs += ../../../examples/webengine . navigation.landingpage = "Qt WebEngine" navigation.qmltypespage = "Qt WebEngine QML Types" diff --git a/src/webengine/doc/snippets/qtwebengine_webengineview_newviewrequested.qml b/src/webengine/doc/snippets/qtwebengine_webengineview_newviewrequested.qml new file mode 100644 index 000000000..6c5497145 --- /dev/null +++ b/src/webengine/doc/snippets/qtwebengine_webengineview_newviewrequested.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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.0 +import QtQuick.Window 2.1 +import QtWebEngine 1.1 + +//! [0] +QtObject { + id: windowParent + // Create the initial browsing windows and open the startup page. + Component.onCompleted: { + var firstWindow = windowComponent.createObject(windowParent) + firstWindow.webView.loadHtml('<input type="button" value="Click!" onclick="window.open("http://qt.io")">') + } + + property Component windowComponent: Window { + // Destroy on close to release the Window's QML resources. + // Because it was created with a parent, it won't be garbage-collected. + onClosing: destroy() + visible: true + + property WebEngineView webView: webView_ + WebEngineView { + id: webView_ + anchors.fill: parent + + // Handle the signal. Dynamically create the window and + // use its WebEngineView as the destination of our request. + onNewViewRequested: { + var newWindow = windowComponent.createObject(windowParent) + request.openIn(newWindow.webView) + } + } + } +} +//! [0] diff --git a/src/webengine/doc/src/qquickwebengineview_lgpl.qdoc b/src/webengine/doc/src/qquickwebengineview_lgpl.qdoc index 379c45e1c..24341d745 100644 --- a/src/webengine/doc/src/qquickwebengineview_lgpl.qdoc +++ b/src/webengine/doc/src/qquickwebengineview_lgpl.qdoc @@ -258,6 +258,26 @@ */ /*! + \qmlsignal WebEngineView::newViewRequested(request) + + This signal is emitted when a page load is requested to happen in a separate + WebEngineView. This can either be because the current page requested it explicitly + through a JavaScript call to window.open, or because the user clicked on a link + while holding Shift, Ctrl or a built-in combination that triggers the page to open + in a new window. + + If this signal isn't handled the requested load will fail. + + An example implementation: + + \snippet snippets/qtwebengine_webengineview_newviewrequested.qml 0 + + The corresponding handler is onNewViewRequested. + + \sa WebEngineNewViewRequest, WebEngineView::NewViewDestination, {WebEngine Quick Nano Browser} +*/ + +/*! \qmlproperty enumeration WebEngineView::ErrorDomain This enumeration details various high-level error types. @@ -328,3 +348,20 @@ \endtable */ + +/*! + \qmlproperty enumeration WebEngineView::NewViewDestination + + This enumeration details the format in which a new view request should be opened. + + \value WebEngineView::NewViewInWindow + The page expects to be opened in a separate Window. + \value WebEngineView::NewViewInTab + The page expects to be opened in a tab of the same window. + \value WebEngineView::NewViewInDialog + The page expects to be opened in a Window without any tab, tool or URL bar. + \value WebEngineView::NewViewInBackgroundTab + The page expects to be opened in a tab of the same window, without hiding the currently visible WebEngineView. + + \sa WebEngineNewViewRequest::destination +*/ diff --git a/src/webengine/plugin/experimental/plugin.cpp b/src/webengine/plugin/experimental/plugin.cpp index 883ebc598..4d00a4d3d 100644 --- a/src/webengine/plugin/experimental/plugin.cpp +++ b/src/webengine/plugin/experimental/plugin.cpp @@ -37,18 +37,11 @@ #include <QtQml/qqmlextensionplugin.h> #include "qquickwebenginehistory_p.h" -#include "qquickwebenginesettings_p.h" -#include "qquickwebenginesingleton_p.h" #include "qquickwebengineview_p.h" #include "qquickwebengineview_p_p.h" QT_BEGIN_NAMESPACE -static QObject *webEngineSingletonProvider(QQmlEngine *, QJSEngine *) -{ - return new QQuickWebEngineSingleton; -} - class QQuickWebEngineViewExperimentalExtension : public QObject { Q_OBJECT Q_PROPERTY(QQuickWebEngineViewExperimental* experimental READ experimental CONSTANT FINAL) @@ -78,9 +71,9 @@ public: QObject::tr("Cannot create a separate instance of NavigationHistory")); qmlRegisterUncreatableType<QQuickWebEngineHistoryListModel>(uri, 1, 0, "NavigationHistoryListModel", QObject::tr("Cannot create a separate instance of NavigationHistory")); - qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 0, "WebEngineSettings", - QObject::tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 0, "WebEngine", webEngineSingletonProvider); + + // Use the latest revision of QQuickWebEngineView when importing QtWebEngine.experimental 1.0 + qmlRegisterRevision<QQuickWebEngineView, 1>(uri, 1, 0); } }; diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index 60e401301..b6ac8407c 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -36,17 +36,23 @@ #include <QtQml/qqmlextensionplugin.h> +#include "qquickwebenginecertificateerror_p.h" +#include "qquickwebenginedownloaditem_p.h" #include "qquickwebengineloadrequest_p.h" #include "qquickwebenginenavigationrequest_p.h" #include "qquickwebenginenewviewrequest_p.h" +#include "qquickwebengineprofile_p.h" +#include "qquickwebenginesettings_p.h" +#include "qquickwebenginesingleton_p.h" #include "qquickwebengineview_p.h" #include "qtwebengineversion.h" QT_BEGIN_NAMESPACE -class QQuickWebEngineVersionBumper : public QObject { - Q_OBJECT -}; +static QObject *webEngineSingletonProvider(QQmlEngine *, QJSEngine *) +{ + return new QQuickWebEngineSingleton; +} class QtWebEnginePlugin : public QQmlExtensionPlugin { @@ -59,8 +65,16 @@ public: qmlRegisterType<QQuickWebEngineView>(uri, 1, 0, "WebEngineView"); qmlRegisterUncreatableType<QQuickWebEngineLoadRequest>(uri, 1, 0, "WebEngineLoadRequest", QObject::tr("Cannot create separate instance of WebEngineLoadRequest")); - qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 0, "WebEngineNewViewRequest", QObject::tr("Cannot create separate instance of WebEngineNewViewRequest")); qmlRegisterUncreatableType<QQuickWebEngineNavigationRequest>(uri, 1, 0, "WebEngineNavigationRequest", QObject::tr("Cannot create separate instance of WebEngineNavigationRequest")); + + qmlRegisterType<QQuickWebEngineView, 1>(uri, 1, 1, "WebEngineView"); + qmlRegisterType<QQuickWebEngineProfile>(uri, 1, 1, "WebEngineProfile"); + qmlRegisterUncreatableType<QQuickWebEngineCertificateError>(uri, 1, 1, "WebEngineCertificateError", QObject::tr("Cannot create separate instance of WebEngineCertificateError")); + qmlRegisterUncreatableType<QQuickWebEngineDownloadItem>(uri, 1, 1, "WebEngineDownloadItem", + QObject::tr("Cannot create a separate instance of WebEngineDownloadItem")); + qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 1, "WebEngineNewViewRequest", QObject::tr("Cannot create separate instance of WebEngineNewViewRequest")); + qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 1, "WebEngineSettings", QObject::tr("Cannot create a separate instance of WebEngineSettings")); + qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 1, "WebEngine", webEngineSingletonProvider); } }; 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 7c04cb8c0..663232eda 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) @@ -103,6 +105,16 @@ bool RenderWidgetHostViewQtDelegateQuick::hasKeyboardFocus() return hasFocus(); } +void RenderWidgetHostViewQtDelegateQuick::lockMouse() +{ + grabMouse(); +} + +void RenderWidgetHostViewQtDelegateQuick::unlockMouse() +{ + ungrabMouse(); +} + void RenderWidgetHostViewQtDelegateQuick::show() { setVisible(true); @@ -123,6 +135,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..305c14957 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -53,10 +53,15 @@ public: virtual QRectF contentsRect() const Q_DECL_OVERRIDE; virtual void setKeyboardFocus() Q_DECL_OVERRIDE; virtual bool hasKeyboardFocus() Q_DECL_OVERRIDE; + virtual void lockMouse() Q_DECL_OVERRIDE; + virtual void unlockMouse() Q_DECL_OVERRIDE; virtual void show() Q_DECL_OVERRIDE; 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..d3e81e497 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -56,10 +56,15 @@ public: virtual QRectF contentsRect() const Q_DECL_OVERRIDE; virtual void setKeyboardFocus() Q_DECL_OVERRIDE {} virtual bool hasKeyboardFocus() Q_DECL_OVERRIDE { return false; } + virtual void lockMouse() Q_DECL_OVERRIDE {} + virtual void unlockMouse() Q_DECL_OVERRIDE {} virtual void show() Q_DECL_OVERRIDE; 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/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 9e7af3fad..a8abcfff5 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -345,7 +345,7 @@ public: FilePickerController(WebContentsAdapterClient::FileChooserMode, const QExplicitlySharedDataPointer<WebContentsAdapter> &, QObject * = 0); public Q_SLOTS: - void accepted(const QJSValue &files); + void accepted(const QVariant &files); void rejected(); private: @@ -362,14 +362,11 @@ FilePickerController::FilePickerController(WebContentsAdapterClient::FileChooser { } -void FilePickerController::accepted(const QJSValue &filesValue) +void FilePickerController::accepted(const QVariant &files) { QStringList stringList; - int length = filesValue.property(QStringLiteral("length")).toInt(); - for (int i = 0; i < length; i++) { - stringList.append(QUrl(filesValue.property(i).toString()).toLocalFile()); - } - + Q_FOREACH (const QUrl &url, files.value<QList<QUrl> >()) + stringList.append(url.toLocalFile()); m_adapter->filesSelectedInChooser(stringList, m_mode); } @@ -418,7 +415,7 @@ void UIDelegatesManager::showFilePicker(WebContentsAdapterClient::FileChooserMod CHECK_QML_SIGNAL_PROPERTY(filesPickedSignal, filePickerComponent->url()); QQmlProperty rejectSignal(filePicker, QStringLiteral("onRejected")); CHECK_QML_SIGNAL_PROPERTY(rejectSignal, filePickerComponent->url()); - static int acceptedIndex = controller->metaObject()->indexOfSlot("accepted(QJSValue)"); + static int acceptedIndex = controller->metaObject()->indexOfSlot("accepted(QVariant)"); QObject::connect(filePicker, filesPickedSignal.method(), controller, controller->metaObject()->method(acceptedIndex)); static int rejectedIndex = controller->metaObject()->indexOfSlot("rejected()"); QObject::connect(filePicker, rejectSignal.method(), controller, controller->metaObject()->method(rejectedIndex)); diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 4c4606690..8a6d06c10 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -4,17 +4,20 @@ TARGET = QtWebEngine 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 INCLUDEPATH += $$PWD api ../core SOURCES = \ + api/qquickwebenginecertificateerror.cpp \ + api/qquickwebenginedownloaditem.cpp \ api/qquickwebenginehistory.cpp \ api/qquickwebengineloadrequest.cpp \ api/qquickwebenginenavigationrequest.cpp \ api/qquickwebenginenewviewrequest.cpp \ + api/qquickwebengineprofile.cpp \ api/qquickwebenginesettings.cpp \ api/qquickwebenginesingleton.cpp \ api/qquickwebengineview.cpp \ @@ -26,12 +29,16 @@ SOURCES = \ HEADERS = \ api/qtwebengineglobal.h \ api/qtwebengineglobal_p.h \ + api/qquickwebenginecertificateerror_p.h \ + api/qquickwebenginedownloaditem_p.h \ + api/qquickwebenginedownloaditem_p_p.h \ api/qquickwebenginehistory_p.h \ api/qquickwebengineloadrequest_p.h \ api/qquickwebenginenavigationrequest_p.h \ api/qquickwebenginenewviewrequest_p.h \ + api/qquickwebengineprofile_p.h \ + api/qquickwebengineprofile_p_p.h \ api/qquickwebenginesettings_p.h \ - api/qquickwebenginesettings_p_p.h \ api/qquickwebenginesingleton_p.h \ api/qquickwebengineview_p.h \ api/qquickwebengineview_p_p.h \ diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp new file mode 100644 index 000000000..9bfe1f9fd --- /dev/null +++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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 "qwebenginedownloaditem.h" + +#include "qwebenginedownloaditem_p.h" +#include "qwebengineprofile_p.h" + +QT_BEGIN_NAMESPACE + +static inline QWebEngineDownloadItem::DownloadState toDownloadState(int state) +{ + switch (state) { + case BrowserContextAdapterClient::DownloadInProgress: + return QWebEngineDownloadItem::DownloadInProgress; + case BrowserContextAdapterClient::DownloadCompleted: + return QWebEngineDownloadItem::DownloadCompleted; + case BrowserContextAdapterClient::DownloadCancelled: + return QWebEngineDownloadItem::DownloadCancelled; + case BrowserContextAdapterClient::DownloadInterrupted: + return QWebEngineDownloadItem::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QWebEngineDownloadItem::DownloadCancelled; + } +} + +/*! + \class QWebEngineDownloadItem + \brief The QWebEngineDownloadItem class provides information about a download. + + \since 5.5 + + \inmodule QtWebEngineWidgets + + QWebEngineDownloadItem stores the state of a download to be used to manage requested downloads. +*/ + +QWebEngineDownloadItemPrivate::QWebEngineDownloadItemPrivate(QWebEngineProfilePrivate *p, const QUrl &url) + : profile(p) + , downloadFinished(false) + , downloadId(-1) + , downloadState(QWebEngineDownloadItem::DownloadCancelled) + , downloadUrl(url) + , totalBytes(-1) + , receivedBytes(0) +{ +} + +QWebEngineDownloadItemPrivate::~QWebEngineDownloadItemPrivate() +{ + profile->downloadDestroyed(downloadId); +} + +void QWebEngineDownloadItemPrivate::update(const BrowserContextAdapterClient::DownloadItemInfo &info) +{ + Q_Q(QWebEngineDownloadItem); + + Q_ASSERT(downloadState != QWebEngineDownloadItem::DownloadRequested); + + if (toDownloadState(info.state) != downloadState) { + downloadState = toDownloadState(info.state); + Q_EMIT q->stateChanged(downloadState); + } + + if (info.receivedBytes != receivedBytes || info.totalBytes != totalBytes) { + receivedBytes = info.receivedBytes; + totalBytes = info.totalBytes; + Q_EMIT q->downloadProgress(receivedBytes, totalBytes); + } + + downloadFinished = downloadState != QWebEngineDownloadItem::DownloadInProgress; + + if (downloadFinished) + Q_EMIT q->finished(); +} + +/*! + Accepts the current download request, which will start the download. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadItem::accept() +{ + Q_D(QWebEngineDownloadItem); + + if (d->downloadState != QWebEngineDownloadItem::DownloadRequested) + return; + + d->downloadState = QWebEngineDownloadItem::DownloadInProgress; + Q_EMIT stateChanged(d->downloadState); +} + +/*! + Cancels the current download. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadItem::cancel() +{ + Q_D(QWebEngineDownloadItem); + + QWebEngineDownloadItem::DownloadState state = d->downloadState; + + if (state == QWebEngineDownloadItem::DownloadCompleted + || state == QWebEngineDownloadItem::DownloadCancelled) + return; + + d->downloadState = QWebEngineDownloadItem::DownloadCancelled; + Q_EMIT stateChanged(d->downloadState); + + // We directly cancel the download request if the user cancels + // before it even started, so no need to notify the profile here. + if (state == QWebEngineDownloadItem::DownloadInProgress) + d->profile->cancelDownload(d->downloadId); +} + +/*! + Returns the download item's id. +*/ + +quint32 QWebEngineDownloadItem::id() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadId; +} + +/*! + \fn QWebEngineDownloadItem::finished() + + This signal is emitted whenever the download finishes. + + \sa state(), isFinished() +*/ + +/*! + \fn QWebEngineDownloadItem::stateChanged(DownloadState state) + + This signal is emitted whenever the download's \a state changes. + + \sa state(), QWebEngineDownloadItem::DownloadState +*/ + +/*! + \fn QWebEngineDownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) + + This signal is emitted whenever the download's \a bytesReceived or + \a bytesTotal changes. + + \sa totalBytes(), receivedBytes() +*/ + +/*! + \enum QWebEngineDownloadItem::DownloadState + + This enum describes the state in which the download is in. + + \value DownloadRequested The download has been requested, but has not been accepted yet. + \value DownloadInProgress The download is in progress. + \value DownloadCompleted The download completed successfully. + \value DownloadCancelled The download has been cancelled. + \value DownloadInterrupted The download has been interrupted (by the server or because of lost connectivity). +*/ + +/*! + Returns the download item's current state. + + \sa QWebEngineDownloadItem::DownloadState +*/ + +QWebEngineDownloadItem::DownloadState QWebEngineDownloadItem::state() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadState; +} + +/*! + Returns the download's total size in bytes. + + -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadItem::totalBytes() +{ + Q_D(QWebEngineDownloadItem); + return d->totalBytes; +} + +/*! + Returns the download's bytes that have been received so far. + + -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadItem::receivedBytes() +{ + Q_D(QWebEngineDownloadItem); + return d->receivedBytes; +} + +/*! + Returns the download's origin url. +*/ + +QUrl QWebEngineDownloadItem::url() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadUrl; +} + +/*! + Returns the download's full target path where it is being downloaded to. + + The path includes the file name. The default suggested path is the standard download location + and file name is deduced not to overwrite already existing files. +*/ + +QString QWebEngineDownloadItem::path() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadPath; +} + +/*! + Sets the download's full target path, where the file should be downloaded to. + + The \a path should also include the file name. The download path can only be set in response + to the QWebEngineProfile::downloadRequested() signal before the download is accepted. + Past that point this function has no effect on the download item's state. +*/ +void QWebEngineDownloadItem::setPath(QString path) +{ + Q_D(QWebEngineDownloadItem); + if (d->downloadState != QWebEngineDownloadItem::DownloadRequested) { + qWarning("Setting the download path is not allowed after the download has been accepted."); + return; + } + + d->downloadPath = path; +} + +/*! + Returns whether this download is finished (not in progress). + + \sa finished(), state(), +*/ + +bool QWebEngineDownloadItem::isFinished() +{ + Q_D(QWebEngineDownloadItem); + return d->downloadFinished; +} + +QWebEngineDownloadItem::QWebEngineDownloadItem(QWebEngineDownloadItemPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineDownloadItem::~QWebEngineDownloadItem() +{ +} + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h new file mode 100644 index 000000000..1051d686c --- /dev/null +++ b/src/webenginewidgets/api/qwebenginedownloaditem.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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 QWEBENGINEDOWNLOADITEM_H +#define QWEBENGINEDOWNLOADITEM_H + +#include "qtwebenginewidgetsglobal.h" + +#include <QObject> + +QT_BEGIN_NAMESPACE + +class QWebEngineDownloadItemPrivate; +class QWebEngineProfilePrivate; + +class QWEBENGINEWIDGETS_EXPORT QWebEngineDownloadItem : public QObject +{ + Q_OBJECT +public: + ~QWebEngineDownloadItem(); + + enum DownloadState { + DownloadRequested, + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUMS(DownloadState) + + quint32 id(); + DownloadState state(); + qint64 totalBytes(); + qint64 receivedBytes(); + QUrl url(); + QString path(); + void setPath(QString path); + bool isFinished(); + +public Q_SLOTS: + void accept(); + void cancel(); + +Q_SIGNALS: + void finished(); + void stateChanged(DownloadState state); + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + +private: + Q_DISABLE_COPY(QWebEngineDownloadItem) + Q_DECLARE_PRIVATE(QWebEngineDownloadItem) + + friend class QWebEngineProfilePrivate; + + QWebEngineDownloadItem(QWebEngineDownloadItemPrivate*, QObject *parent = 0); + QScopedPointer<QWebEngineDownloadItemPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADITEM_H diff --git a/src/webenginewidgets/api/qwebenginedownloaditem_p.h b/src/webenginewidgets/api/qwebenginedownloaditem_p.h new file mode 100644 index 000000000..a7e5b36e6 --- /dev/null +++ b/src/webenginewidgets/api/qwebenginedownloaditem_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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 QWEBENGINEDOWNLOADITEM_P_H +#define QWEBENGINEDOWNLOADITEM_P_H + +#include "qtwebenginewidgetsglobal.h" + +#include "qwebenginedownloaditem_p.h" +#include "qwebengineprofile_p.h" +#include <QString> + +QT_BEGIN_NAMESPACE + +class QWebEngineDownloadItemPrivate { + QWebEngineDownloadItem *q_ptr; + QWebEngineProfilePrivate* profile; + friend class QWebEngineProfilePrivate; +public: + Q_DECLARE_PUBLIC(QWebEngineDownloadItem) + QWebEngineDownloadItemPrivate(QWebEngineProfilePrivate *p, const QUrl &url); + ~QWebEngineDownloadItemPrivate(); + + bool downloadFinished; + quint32 downloadId; + QWebEngineDownloadItem::DownloadState downloadState; + QString downloadPath; + const QUrl downloadUrl; + + qint64 totalBytes; + qint64 receivedBytes; + + void update(const BrowserContextAdapterClient::DownloadItemInfo &info); +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADITEM_P_H + diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 72b16f28b..a59165e8b 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -23,12 +23,14 @@ #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" #include "qwebenginehistory_p.h" +#include "qwebengineprofile.h" +#include "qwebengineprofile_p.h" #include "qwebenginesettings.h" -#include "qwebenginesettings_p.h" #include "qwebengineview.h" #include "qwebengineview_p.h" #include "render_widget_host_view_qt_delegate_widget.h" @@ -166,10 +168,11 @@ void CallbackDirectory::CallbackSharedDataPointer::doDeref() } } -QWebEnginePagePrivate::QWebEnginePagePrivate() +QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) : adapter(new WebContentsAdapter) , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this))) - , settings(new QWebEngineSettings) + , profile(_profile ? _profile : QWebEngineProfile::defaultProfile()) + , settings(new QWebEngineSettings(profile->settings())) , view(0) , isLoading(false) { @@ -267,6 +270,12 @@ void QWebEnginePagePrivate::focusContainer() view->setFocus(); } +void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) +{ + if (view && view->parentWidget()) + QGuiApplication::sendEvent(view->parentWidget(), event); +} + void QWebEnginePagePrivate::adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) { Q_Q(QWebEnginePage); @@ -342,10 +351,24 @@ 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); +} + +void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock); +} + +#ifndef QT_NO_ACCESSIBILITY QObject *QWebEnginePagePrivate::accessibilityParentObject() { return view; } +#endif // QT_NO_ACCESSIBILITY void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const { @@ -410,9 +433,31 @@ void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) } } +BrowserContextAdapter *QWebEnginePagePrivate::browserContextAdapter() +{ + return profile->d_ptr->browserContext(); +} + QWebEnginePage::QWebEnginePage(QObject* parent) : QObject(parent) - , d_ptr(new QWebEnginePagePrivate) + , d_ptr(new QWebEnginePagePrivate()) +{ + Q_D(QWebEnginePage); + d->q_ptr = this; + d->adapter->initialize(d); +} + +/*! + Constructs an empty QWebEnginePage in the QWebEngineProfile \a profile with parent \a parent. + + If the profile is not the default profile the caller must ensure the profile is alive for as + long as the page is. + + \since 5.5 +*/ +QWebEnginePage::QWebEnginePage(QWebEngineProfile *profile, QObject* parent) + : QObject(parent) + , d_ptr(new QWebEnginePagePrivate(profile)) { Q_D(QWebEnginePage); d->q_ptr = this; @@ -448,6 +493,16 @@ QWidget *QWebEnginePage::view() const return d->view; } +/*! + Returns the QWebEngineProfile the page belongs to. + \since 5.5 +*/ +QWebEngineProfile *QWebEnginePage::profile() const +{ + Q_D(const QWebEnginePage); + return d->profile; +} + bool QWebEnginePage::hasSelection() const { return !selectedText().isEmpty(); @@ -624,6 +679,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); @@ -654,7 +716,7 @@ void QWebEnginePagePrivate::javascriptDialog(QSharedPointer<JavaScriptDialogCont controller->reject(); } -void QWebEnginePagePrivate::allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &controller) +void QWebEnginePagePrivate::allowCertificateError(const QSharedPointer<CertificateErrorController> &controller) { Q_Q(QWebEnginePage); bool accepted = false; @@ -743,6 +805,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 +825,16 @@ 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; + case MouseLock: + if (policy == PermissionGrantedByUser) + d->adapter->grantMouseLockPermission(true); + else + d->adapter->grantMouseLockPermission(false); break; default: break; @@ -782,7 +856,7 @@ void QWebEnginePagePrivate::runFileChooser(WebContentsAdapterClient::FileChooser WebEngineSettings *QWebEnginePagePrivate::webEngineSettings() const { - return settings->d_func()->coreSettings.data(); + return settings->d_func(); } void QWebEnginePage::load(const QUrl& url) @@ -883,8 +957,8 @@ QWebEnginePage *QWebEnginePage::createWindow(WebWindowType type) return 0; } -Q_STATIC_ASSERT_X(static_cast<int>(WebContentsAdapterClient::Open) == static_cast<int>(QWebEnginePage::FileSelectOpen), "Enums out of sync"); -Q_STATIC_ASSERT_X(static_cast<int>(WebContentsAdapterClient::OpenMultiple) == static_cast<int>(QWebEnginePage::FileSelectOpenMultiple), "Enums out of sync"); +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Open, QWebEnginePage::FileSelectOpen) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::OpenMultiple, QWebEnginePage::FileSelectOpenMultiple) QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) { @@ -945,6 +1019,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..a194df831 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -50,8 +50,9 @@ QT_BEGIN_NAMESPACE class QMenu; class QWebEngineHistory; class QWebEnginePage; -class QWebEngineSettings; class QWebEnginePagePrivate; +class QWebEngineProfile; +class QWebEngineSettings; namespace QtWebEnginePrivate { @@ -136,14 +137,25 @@ public: PermissionDeniedByUser }; + // must match WebContentsAdapterClient::NavigationType + enum NavigationType { + NavigationTypeLinkClicked, + NavigationTypeTyped, + NavigationTypeFormSubmitted, + NavigationTypeBackForward, + NavigationTypeReload, + NavigationTypeOther + }; + enum Feature { #ifndef Q_QDOC Notifications = 0, - Geolocation = 1, #endif + Geolocation = 1, MediaAudioCapture = 2, MediaVideoCapture, - MediaAudioVideoCapture + MediaAudioVideoCapture, + MouseLock }; // Ex-QWebFrame enum @@ -161,6 +173,7 @@ public: }; explicit QWebEnginePage(QObject *parent = 0); + QWebEnginePage(QWebEngineProfile *profile, QObject *parent = 0); ~QWebEnginePage(); QWebEngineHistory *history() const; @@ -170,6 +183,8 @@ public: bool hasSelection() const; QString selectedText() const; + QWebEngineProfile *profile() const; + #ifndef QT_NO_ACTION QAction *action(WebAction action) const; #endif @@ -248,6 +263,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); @@ -258,7 +274,9 @@ private: friend class QWebEngineView; friend class QWebEngineViewPrivate; +#ifndef QT_NO_ACCESSIBILITY friend class QWebEngineViewAccessible; +#endif // QT_NO_ACCESSIBILITY }; diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 54129229f..6c6520414 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -49,6 +49,7 @@ class WebContentsAdapter; QT_BEGIN_NAMESPACE class QWebEngineHistory; class QWebEnginePage; +class QWebEngineProfile; class QWebEngineSettings; class QWebEngineView; @@ -101,7 +102,7 @@ public: Q_DECLARE_PUBLIC(QWebEnginePage) QWebEnginePage *q_ptr; - QWebEnginePagePrivate(); + QWebEnginePagePrivate(QWebEngineProfile *profile = 0); ~QWebEnginePagePrivate(); virtual RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) Q_DECL_OVERRIDE; @@ -119,10 +120,11 @@ public: virtual void loadVisuallyCommitted() Q_DECL_OVERRIDE { } virtual void loadFinished(bool success, const QUrl &url, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE; virtual void focusContainer() Q_DECL_OVERRIDE; + virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE; virtual void adoptNewWindow(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,9 +137,15 @@ 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 void runMouseLockPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; +#ifndef QT_NO_ACCESSIBILITY virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; +#endif // QT_NO_ACCESSIBILITY virtual WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; - virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &controller) Q_DECL_OVERRIDE; + virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &controller) Q_DECL_OVERRIDE; + + virtual BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; void updateAction(QWebEnginePage::WebAction) const; void updateNavigationActions(); @@ -148,6 +156,7 @@ public: QExplicitlySharedDataPointer<WebContentsAdapter> adapter; QWebEngineHistory *history; + QWebEngineProfile *profile; QWebEngineSettings *settings; QWebEngineView *view; QSize viewportSize; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp new file mode 100644 index 000000000..afe0774c0 --- /dev/null +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -0,0 +1,456 @@ +/**************************************************************************** +** +** 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 "qwebengineprofile.h" + +#include "qwebenginedownloaditem.h" +#include "qwebenginedownloaditem_p.h" +#include "qwebenginepage.h" +#include "qwebengineprofile_p.h" +#include "qwebenginesettings.h" + +#include "browser_context_adapter.h" +#include "web_engine_visited_links_manager.h" +#include "web_engine_settings.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineProfile + \brief The QWebEngineProfile class provides a web-engine profile shared by multiple pages. + \since 5.5 + + \inmodule QtWebEngineWidgets + + QWebEngineProfile contains settings and history shared by all QWebEnginePages that belong + to the profile. + + A default profile is built-in that all web pages not specifically created with another profile + belongs to. +*/ + +/*! + \enum QWebEngineProfile::HttpCacheType + + This enum describes the HTTP cache types QtWebEngine can be configured to use. + + \value MemoryHttpCache Use a in-memory cache. This is the only setting possible if off-the-record is set or no cache path is available. + \value DiskHttpCache Use a disk cache. This is the default. +*/ + +/*! + \enum QWebEngineProfile::PersistentCookiesPolicy + + This enum describes policy for cookie persistency. + + \value NoPersistentCookies Both session and persistent cookies are stored in memory. This is the only setting possible if off-the-record is set or no persistent data path is available. + \value AllowPersistentCookies Cookies marked persistent are save and restored from disk, session cookies are only stored to disk for crash recovery. This is the default setting. + \value ForcePersistentCookies Both session and persistent cookies are save and restored from disk. +*/ + +/*! + \fn QWebEngineProfile::downloadRequested(QWebEngineDownloadItem *download) + + \since 5.5 + + This signal is emitted whenever a download has been triggered. + The \a download argument holds the state of the download. + The \a download either has to be explicitly accepted with + QWebEngineDownloadItem::accept(), else the download will be + cancelled by default. + The download item is parented by the profile, but if not accepted + will be deleted immediately after the signal emission. + This signal can not be used with a queued connection. + + \sa QWebEngineDownloadItem +*/ + +QWebEngineProfilePrivate::QWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext) + : m_settings(new QWebEngineSettings()) + , m_browserContext(browserContext) +{ + if (ownsContext) + m_browserContextRef = browserContext; + + m_browserContext->setClient(this); + m_settings->d_ptr->initDefaults(browserContext->isOffTheRecord()); +} + +QWebEngineProfilePrivate::~QWebEngineProfilePrivate() +{ + delete m_settings; + m_settings = 0; + m_browserContext->setClient(0); + + Q_FOREACH (QWebEngineDownloadItem* download, m_ongoingDownloads) { + if (download) + download->cancel(); + } + + m_ongoingDownloads.clear(); +} + +void QWebEngineProfilePrivate::cancelDownload(quint32 downloadId) +{ + m_browserContext->cancelDownload(downloadId); +} + +void QWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) +{ + m_ongoingDownloads.remove(downloadId); +} + +void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info) +{ + Q_Q(QWebEngineProfile); + + Q_ASSERT(!m_ongoingDownloads.contains(info.id)); + QWebEngineDownloadItemPrivate *itemPrivate = new QWebEngineDownloadItemPrivate(this, info.url); + itemPrivate->downloadId = info.id; + itemPrivate->downloadState = QWebEngineDownloadItem::DownloadRequested; + itemPrivate->downloadPath = info.path; + + QWebEngineDownloadItem *download = new QWebEngineDownloadItem(itemPrivate, q); + + m_ongoingDownloads.insert(info.id, download); + + Q_EMIT q->downloadRequested(download); + + QWebEngineDownloadItem::DownloadState state = download->state(); + + info.path = download->path(); + info.accepted = state != QWebEngineDownloadItem::DownloadCancelled; + + if (state == QWebEngineDownloadItem::DownloadRequested) { + // Delete unaccepted downloads. + info.accepted = false; + m_ongoingDownloads.remove(info.id); + delete download; + } +} + +void QWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info) +{ + if (!m_ongoingDownloads.contains(info.id)) + return; + + QWebEngineDownloadItem* download = m_ongoingDownloads.value(info.id).data(); + + if (!download) { + downloadDestroyed(info.id); + return; + } + + download->d_func()->update(info); + + if (download->isFinished()) + m_ongoingDownloads.remove(info.id); +} + +/*! + Constructs a new off-the-record profile. + + An off-the-record profile leaves no record on the local machine, and has no persistent data or cache. + Thus, the HTTP cache can only be in memory and the cookies only be non-persistent, trying to change + these settings will have no effect. + + \sa isOffTheRecord() +*/ +QWebEngineProfile::QWebEngineProfile(QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(true), true)) +{ + d_ptr->q_ptr = this; +} + +/*! + Constructs a new profile with storage name \a storageName. + + The storage name must be unique. + + A disk-based QWebEngineProfile should be destroyed on or before application exit, otherwise the cache + and persistent data may not be fully flushed to disk. + + \sa storageName() +*/ +QWebEngineProfile::QWebEngineProfile(const QString &storageName, QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(storageName), true)) +{ + d_ptr->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineProfile::QWebEngineProfile(QWebEngineProfilePrivate *privatePtr) + : d_ptr(privatePtr) +{ + d_ptr->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineProfile::~QWebEngineProfile() +{ +} + +/*! + Returns the storage name for the profile. + + The storage name is used to give each profile that uses the disk separate subdirectories for persistent data and cache. +*/ +QString QWebEngineProfile::storageName() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->storageName(); +} + +/*! + Returns true if this is an off-the-record profile that leaves no record on the computer. + + This will force cookies and HTTP cache to be in memory, but also force all other normally + persistent data to be stored in memory. +*/ +bool QWebEngineProfile::isOffTheRecord() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->isOffTheRecord(); +} + +/*! + Returns the path used to store persistent data for the browser and web content. + + Persistent data includes persistent cookies, HTML5 local storage and visited links. + + By default this is below QStandardPaths::writableLocation(QStandardPaths::DataLocation) in a storage name specific directory. + + \sa setPersistentStoragePath(), storageName(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::persistentStoragePath() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->dataPath(); +} + +/*! + Overrides the default path used to store persistent web engine data. + + If set to the null string, the default path is restored. + + \sa persistentStoragePath() +*/ +void QWebEngineProfile::setPersistentStoragePath(const QString &path) +{ + const Q_D(QWebEngineProfile); + d->browserContext()->setDataPath(path); +} + +/*! + Returns the path used for caches. + + By default this is below QStandardPaths::writableLocation(QStandardPaths::CacheLocation) in a storage name specific directory. + + \sa setCachePath(), storageName(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::cachePath() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->cachePath(); +} + +/*! + Overrides the default path used for disk caches. + + If set to the null string, the default path is restored. + + \sa cachePath() +*/ +void QWebEngineProfile::setCachePath(const QString &path) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setCachePath(path); +} + +/*! + Returns the user-agent string send with HTTP to identify the browser. + + \sa setHttpUserAgent() +*/ +QString QWebEngineProfile::httpUserAgent() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->httpUserAgent(); +} + +/*! + Overrides the default user-agent string, setting it to \a userAgent. + + \sa httpUserAgent() +*/ +void QWebEngineProfile::setHttpUserAgent(const QString &userAgent) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpUserAgent(userAgent); +} + +/*! + Returns the type of HTTP cache used. + + If the profile is off-the-record MemoryHttpCache is returned. + + \sa setHttpCacheType(), cachePath() +*/ +QWebEngineProfile::HttpCacheType QWebEngineProfile::httpCacheType() const +{ + const Q_D(QWebEngineProfile); + return QWebEngineProfile::HttpCacheType(d->browserContext()->httpCacheType()); +} + +/*! + Sets the HTTP cache type to \a httpCacheType. + + \sa httpCacheType(), setCachePath() +*/ +void QWebEngineProfile::setHttpCacheType(QWebEngineProfile::HttpCacheType httpCacheType) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpCacheType(BrowserContextAdapter::HttpCacheType(httpCacheType)); +} + +/*! + Returns the current policy for persistent cookies. + + If the profile is off-the-record NoPersistentCookies is returned. + + \sa setPersistentCookiesPolicy() +*/ +QWebEngineProfile::PersistentCookiesPolicy QWebEngineProfile::persistentCookiesPolicy() const +{ + const Q_D(QWebEngineProfile); + return QWebEngineProfile::PersistentCookiesPolicy(d->browserContext()->persistentCookiesPolicy()); +} + +/*! + Sets the policy for persistent cookies to \a newPersistentCookiesPolicy. + + \sa persistentCookiesPolicy() +*/ +void QWebEngineProfile::setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy(newPersistentCookiesPolicy)); +} + +/*! + Returns the maximum size of the HTTP size. + + Will return 0 if the size is automatically controlled by QtWebEngine. + + \sa setHttpCacheMaximumSize(), httpCacheType() +*/ +int QWebEngineProfile::httpCacheMaximumSize() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->httpCacheMaxSize(); +} + +/*! + Sets the maximum size of the HTTP cache to \a maxSize. + + Setting it to 0 means the size will be controlled automatically by QtWebEngine. + + \sa httpCacheMaximumSize(), setHttpCacheType() +*/ +void QWebEngineProfile::setHttpCacheMaximumSize(int maxSize) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpCacheMaxSize(maxSize); +} + +/*! + Clears all links from the visited links database. + + \sa clearVisitedLinks() +*/ +void QWebEngineProfile::clearAllVisitedLinks() +{ + Q_D(QWebEngineProfile); + d->browserContext()->visitedLinksManager()->deleteAllVisitedLinkData(); +} + +/*! + Clears the links in \a urls from the visited links database. + + \sa clearAllVisitedLinks() +*/ +void QWebEngineProfile::clearVisitedLinks(const QList<QUrl> &urls) +{ + Q_D(QWebEngineProfile); + d->browserContext()->visitedLinksManager()->deleteVisitedLinkDataForUrls(urls); +} + +/*! + Returns true if \a url is considered a visited link by this profile. +*/ +bool QWebEngineProfile::visitedLinksContainsUrl(const QUrl &url) const +{ + Q_D(const QWebEngineProfile); + return d->browserContext()->visitedLinksManager()->containsUrl(url); +} + +/*! + Returns the default profile. + + The default profile uses the storage name "Default". + + \sa storageName() +*/ +QWebEngineProfile *QWebEngineProfile::defaultProfile() +{ + static QWebEngineProfile profile(new QWebEngineProfilePrivate(BrowserContextAdapter::defaultContext(), false)); + return &profile; +} + +/*! + Returns the default settings for all pages in this profile. +*/ +QWebEngineSettings *QWebEngineProfile::settings() const +{ + const Q_D(QWebEngineProfile); + return d->settings(); +} + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h new file mode 100644 index 000000000..0908862e9 --- /dev/null +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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 QWEBENGINEPROFILE_H +#define QWEBENGINEPROFILE_H + +#include "qtwebenginewidgetsglobal.h" + +#include <QObject> +#include <QScopedPointer> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QObject; +class QUrl; +class QWebEngineDownloadItem; +class QWebEnginePage; +class QWebEnginePagePrivate; +class QWebEngineProfilePrivate; +class QWebEngineSettings; + +class QWEBENGINEWIDGETS_EXPORT QWebEngineProfile : public QObject { + Q_OBJECT +public: + explicit QWebEngineProfile(QObject *parent = 0); + explicit QWebEngineProfile(const QString &name, QObject *parent = 0); + virtual ~QWebEngineProfile(); + + enum HttpCacheType { + MemoryHttpCache, + DiskHttpCache + }; + + enum PersistentCookiesPolicy { + NoPersistentCookies, + AllowPersistentCookies, + ForcePersistentCookies + }; + + QString storageName() const; + bool isOffTheRecord() const; + + QString persistentStoragePath() const; + void setPersistentStoragePath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + HttpCacheType httpCacheType() const; + void setHttpCacheType(QWebEngineProfile::HttpCacheType); + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy); + + int httpCacheMaximumSize() const; + void setHttpCacheMaximumSize(int maxSize); + + void clearAllVisitedLinks(); + void clearVisitedLinks(const QList<QUrl> &urls); + bool visitedLinksContainsUrl(const QUrl &url) const; + + QWebEngineSettings *settings() const; + + static QWebEngineProfile *defaultProfile(); + +Q_SIGNALS: + void downloadRequested(QWebEngineDownloadItem *download); + +private: + Q_DECLARE_PRIVATE(QWebEngineProfile); + QWebEngineProfile(QWebEngineProfilePrivate *); + + friend class QWebEnginePagePrivate; + QScopedPointer<QWebEngineProfilePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPROFILE_H diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h new file mode 100644 index 000000000..7c3d2a5e7 --- /dev/null +++ b/src/webenginewidgets/api/qwebengineprofile_p.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 QWEBENGINEPROFILE_P_H +#define QWEBENGINEPROFILE_P_H + +#include "browser_context_adapter_client.h" +#include "qwebengineprofile.h" +#include <QMap> +#include <QPointer> + +class BrowserContextAdapter; + +QT_BEGIN_NAMESPACE + +class QWebEngineSettings; + +class QWebEngineProfilePrivate : public BrowserContextAdapterClient { +public: + Q_DECLARE_PUBLIC(QWebEngineProfile) + QWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext); + ~QWebEngineProfilePrivate(); + + BrowserContextAdapter *browserContext() const { return m_browserContext; } + QWebEngineSettings *settings() const { return m_settings; } + + void cancelDownload(quint32 downloadId); + void downloadDestroyed(quint32 downloadId); + + void downloadRequested(DownloadItemInfo &info) Q_DECL_OVERRIDE; + void downloadUpdated(const DownloadItemInfo &info) Q_DECL_OVERRIDE; + +private: + QWebEngineProfile *q_ptr; + QWebEngineSettings *m_settings; + BrowserContextAdapter *m_browserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_browserContextRef; + QMap<quint32, QPointer<QWebEngineDownloadItem> > m_ongoingDownloads; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPROFILE_P_H diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index 729a09f56..e126a7e64 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -35,13 +35,14 @@ ****************************************************************************/ #include "qwebenginesettings.h" -#include "qwebenginesettings_p.h" -#include <QDebug> +#include "qwebengineprofile.h" +#include "web_engine_settings.h" -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE -static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::WebAttribute attribute) { +static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::WebAttribute attribute) +{ switch (attribute) { case QWebEngineSettings::AutoLoadImages: return WebEngineSettings::AutoLoadImages; @@ -74,144 +75,110 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web } } -Q_GLOBAL_STATIC(QList<QWebEngineSettingsPrivate*>, allSettings); - -QWebEngineSettingsPrivate::QWebEngineSettingsPrivate() - : coreSettings(new WebEngineSettings(this)) +QWebEngineSettings::QWebEngineSettings(QWebEngineSettings *parentSettings) + : d_ptr(new WebEngineSettings(parentSettings ? parentSettings->d_func() : 0)) { + Q_D(QWebEngineSettings); + d->scheduleApplyRecursively(); } -void QWebEngineSettingsPrivate::apply() +QWebEngineSettings::~QWebEngineSettings() { - coreSettings->scheduleApply(); - QWebEngineSettingsPrivate *globals = QWebEngineSettings::globalSettings()->d_func(); - Q_ASSERT((this == globals) != (allSettings->contains(this))); - if (this == globals) { - Q_FOREACH (QWebEngineSettingsPrivate *settings, *allSettings) - settings->coreSettings->scheduleApply(); - } } -void QWebEngineSettingsPrivate::initDefaults() +#if QT_DEPRECATED_SINCE(5, 5) +QWebEngineSettings *QWebEngineSettings::globalSettings() { - coreSettings->initDefaults(); -} - -WebEngineSettings *QWebEngineSettingsPrivate::fallbackSettings() const { - return QWebEngineSettings::globalSettings()->d_func()->coreSettings.data(); + return defaultSettings(); } +#endif -QWebEngineSettings *QWebEngineSettings::globalSettings() +QWebEngineSettings *QWebEngineSettings::defaultSettings() { - 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 QWebEngineProfile::defaultProfile()->settings(); } -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::StandardFont) == static_cast<int>(QWebEngineSettings::StandardFont), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::FixedFont) == static_cast<int>(QWebEngineSettings::FixedFont), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::SerifFont) == static_cast<int>(QWebEngineSettings::SerifFont), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::SansSerifFont) == static_cast<int>(QWebEngineSettings::SansSerifFont), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::CursiveFont) == static_cast<int>(QWebEngineSettings::CursiveFont), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::FantasyFont) == static_cast<int>(QWebEngineSettings::FantasyFont), "The enum values must match"); +ASSERT_ENUMS_MATCH(WebEngineSettings::StandardFont, QWebEngineSettings::StandardFont) +ASSERT_ENUMS_MATCH(WebEngineSettings::FixedFont, QWebEngineSettings::FixedFont) +ASSERT_ENUMS_MATCH(WebEngineSettings::SerifFont, QWebEngineSettings::SerifFont) +ASSERT_ENUMS_MATCH(WebEngineSettings::SansSerifFont, QWebEngineSettings::SansSerifFont) +ASSERT_ENUMS_MATCH(WebEngineSettings::CursiveFont, QWebEngineSettings::CursiveFont) +ASSERT_ENUMS_MATCH(WebEngineSettings::FantasyFont, QWebEngineSettings::FantasyFont) void QWebEngineSettings::setFontFamily(QWebEngineSettings::FontFamily which, const QString &family) { Q_D(QWebEngineSettings); - d->coreSettings->setFontFamily(static_cast<WebEngineSettings::FontFamily>(which), family); + d->setFontFamily(static_cast<WebEngineSettings::FontFamily>(which), family); } QString QWebEngineSettings::fontFamily(QWebEngineSettings::FontFamily which) const { - Q_D(const QWebEngineSettings); - return d->coreSettings->fontFamily(static_cast<WebEngineSettings::FontFamily>(which)); + return d_ptr->fontFamily(static_cast<WebEngineSettings::FontFamily>(which)); } void QWebEngineSettings::resetFontFamily(QWebEngineSettings::FontFamily which) { - Q_D(QWebEngineSettings); - d->coreSettings->resetFontFamily(static_cast<WebEngineSettings::FontFamily>(which)); + d_ptr->resetFontFamily(static_cast<WebEngineSettings::FontFamily>(which)); } -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::DefaultFixedFontSize) == static_cast<int>(QWebEngineSettings::DefaultFixedFontSize), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::DefaultFontSize) == static_cast<int>(QWebEngineSettings::DefaultFontSize), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::MinimumFontSize) == static_cast<int>(QWebEngineSettings::MinimumFontSize), "The enum values must match"); -Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::MinimumLogicalFontSize) == static_cast<int>(QWebEngineSettings::MinimumLogicalFontSize), "The enum values must match"); +ASSERT_ENUMS_MATCH(WebEngineSettings::DefaultFixedFontSize, QWebEngineSettings::DefaultFixedFontSize) +ASSERT_ENUMS_MATCH(WebEngineSettings::DefaultFontSize, QWebEngineSettings::DefaultFontSize) +ASSERT_ENUMS_MATCH(WebEngineSettings::MinimumFontSize, QWebEngineSettings::MinimumFontSize) +ASSERT_ENUMS_MATCH(WebEngineSettings::MinimumLogicalFontSize, QWebEngineSettings::MinimumLogicalFontSize) void QWebEngineSettings::setFontSize(QWebEngineSettings::FontSize type, int size) { - Q_D(const QWebEngineSettings); - d->coreSettings->setFontSize(static_cast<WebEngineSettings::FontSize>(type), size); + Q_D(QWebEngineSettings); + d->setFontSize(static_cast<WebEngineSettings::FontSize>(type), size); } int QWebEngineSettings::fontSize(QWebEngineSettings::FontSize type) const { Q_D(const QWebEngineSettings); - return d->coreSettings->fontSize(static_cast<WebEngineSettings::FontSize>(type)); + return d->fontSize(static_cast<WebEngineSettings::FontSize>(type)); } void QWebEngineSettings::resetFontSize(QWebEngineSettings::FontSize type) { Q_D(QWebEngineSettings); - d->coreSettings->resetFontSize(static_cast<WebEngineSettings::FontSize>(type)); -} - - -QWebEngineSettings::QWebEngineSettings() - : d_ptr(new QWebEngineSettingsPrivate) -{ - Q_D(QWebEngineSettings); - allSettings->append(d); - d->coreSettings->scheduleApply(); + d->resetFontSize(static_cast<WebEngineSettings::FontSize>(type)); } -QWebEngineSettings::~QWebEngineSettings() -{ - Q_D(QWebEngineSettings); - allSettings->removeAll(d); -} - void QWebEngineSettings::setDefaultTextEncoding(const QString &encoding) { Q_D(QWebEngineSettings); - d->coreSettings->setDefaultTextEncoding(encoding); + d->setDefaultTextEncoding(encoding); } QString QWebEngineSettings::defaultTextEncoding() const { Q_D(const QWebEngineSettings); - return d->coreSettings->defaultTextEncoding(); + return d->defaultTextEncoding(); } void QWebEngineSettings::setAttribute(QWebEngineSettings::WebAttribute attr, bool on) { Q_D(QWebEngineSettings); WebEngineSettings::Attribute webEngineAttribute = toWebEngineAttribute(attr); - if (webEngineAttribute != WebEngineSettings::UnsupportedInCoreSettings) - return d->coreSettings->setAttribute(webEngineAttribute, on); - qDebug() << Q_FUNC_INFO << "Missing support for:" << attr; + Q_ASSERT(webEngineAttribute != WebEngineSettings::UnsupportedInCoreSettings); + d->setAttribute(webEngineAttribute, on); } bool QWebEngineSettings::testAttribute(QWebEngineSettings::WebAttribute attr) const { Q_D(const QWebEngineSettings); WebEngineSettings::Attribute webEngineAttribute = toWebEngineAttribute(attr); - if (webEngineAttribute != WebEngineSettings::UnsupportedInCoreSettings) - return d->coreSettings->testAttribute(webEngineAttribute); - - - - qDebug() << Q_FUNC_INFO << "Missing support for:" << attr; - return false; + Q_ASSERT(webEngineAttribute != WebEngineSettings::UnsupportedInCoreSettings); + return d->testAttribute(webEngineAttribute); } void QWebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) { - setAttribute(attr, globalSettings()->testAttribute(attr)); + Q_D(QWebEngineSettings); + WebEngineSettings::Attribute webEngineAttribute = toWebEngineAttribute(attr); + Q_ASSERT(webEngineAttribute != WebEngineSettings::UnsupportedInCoreSettings); + d->resetAttribute(webEngineAttribute); } + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index d9f57a935..48cc3107c 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -25,12 +25,13 @@ #include <QtCore/qscopedpointer.h> #include <QtCore/qstring.h> +class WebEngineSettings; + QT_BEGIN_NAMESPACE class QIcon; class QPixmap; class QUrl; -class QWebEngineSettingsPrivate; class QWEBENGINEWIDGETS_EXPORT QWebEngineSettings { public: @@ -65,7 +66,10 @@ public: DefaultFixedFontSize }; +#if QT_DEPRECATED_SINCE(5, 5) static QWebEngineSettings *globalSettings(); +#endif + static QWebEngineSettings *defaultSettings(); void setFontFamily(FontFamily which, const QString &family); QString fontFamily(FontFamily which) const; @@ -84,12 +88,15 @@ public: private: Q_DISABLE_COPY(QWebEngineSettings) - Q_DECLARE_PRIVATE(QWebEngineSettings); + typedef WebEngineSettings QWebEngineSettingsPrivate; + QWebEngineSettingsPrivate* d_func() { return d_ptr.data(); } + const QWebEngineSettingsPrivate* d_func() const { return d_ptr.data(); } QScopedPointer<QWebEngineSettingsPrivate> d_ptr; friend class QWebEnginePagePrivate; + friend class QWebEngineProfilePrivate; - QWebEngineSettings(); ~QWebEngineSettings(); + explicit QWebEngineSettings(QWebEngineSettings *parentSettings = 0); }; QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 8d2198998..63ac40571 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -85,19 +85,22 @@ void QWebEngineViewPrivate::bind(QWebEngineView *view, QWebEnginePage *page) } } - +#ifndef QT_NO_ACCESSIBILITY static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object) { if (QWebEngineView *v = qobject_cast<QWebEngineView*>(object)) return new QWebEngineViewAccessible(v); return Q_NULLPTR; } +#endif // QT_NO_ACCESSIBILITY QWebEngineViewPrivate::QWebEngineViewPrivate() : page(0) , m_pendingContextMenuEvent(false) { +#ifndef QT_NO_ACCESSIBILITY QAccessible::installFactory(&webAccessibleFactory); +#endif // QT_NO_ACCESSIBILITY } QWebEngineView::QWebEngineView(QWidget *parent) @@ -274,6 +277,7 @@ void QWebEngineView::contextMenuEvent(QContextMenuEvent *event) menu->popup(event->globalPos()); } +#ifndef QT_NO_ACCESSIBILITY int QWebEngineViewAccessible::childCount() const { if (view() && child(0)) @@ -294,6 +298,7 @@ int QWebEngineViewAccessible::indexOfChild(const QAccessibleInterface *c) const return 0; return -1; } +#endif // QT_NO_ACCESSIBILITY QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index 9db971f79..e0cc3f4ee 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -59,6 +59,7 @@ public: bool m_pendingContextMenuEvent; }; +#ifndef QT_NO_ACCESSIBILITY class QWebEngineViewAccessible : public QAccessibleWidget { public: @@ -72,7 +73,7 @@ public: private: QWebEngineView *view() const { return static_cast<QWebEngineView*>(object()); } }; - +#endif // QT_NO_ACCESSIBILITY QT_END_NAMESPACE diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index e89b10ab8..e23fc6f7c 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -147,10 +147,26 @@ */ /*! + \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. + \value Geolocation Access to location hardware or service \value MediaAudioCapture Audio capture devices such a microphones \value MediaVideoCapture Video devices, e.g. cameras \value MediaAudioVideoCapture Both Audio and Video capture devices. @@ -209,6 +225,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..3880e4197 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; @@ -119,6 +121,16 @@ bool RenderWidgetHostViewQtDelegateWidget::hasKeyboardFocus() return hasFocus(); } +void RenderWidgetHostViewQtDelegateWidget::lockMouse() +{ + grabMouse(); +} + +void RenderWidgetHostViewQtDelegateWidget::unlockMouse() +{ + releaseMouse(); +} + void RenderWidgetHostViewQtDelegateWidget::show() { // Check if we're attached to a QWebEngineView, we don't @@ -143,6 +155,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..8fc189124 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -61,10 +61,15 @@ public: virtual QRectF contentsRect() const Q_DECL_OVERRIDE; virtual void setKeyboardFocus() Q_DECL_OVERRIDE; virtual bool hasKeyboardFocus() Q_DECL_OVERRIDE; + virtual void lockMouse() Q_DECL_OVERRIDE; + virtual void unlockMouse() Q_DECL_OVERRIDE; virtual void show() Q_DECL_OVERRIDE; 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 4da888baa..82908bfd0 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -4,7 +4,7 @@ TARGET = QtWebEngineWidgets 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 @@ -13,20 +13,25 @@ INCLUDEPATH += $$PWD api ../core ../webengine/api SOURCES = \ api/qtwebenginewidgetsglobal.cpp \ api/qwebenginecertificateerror.cpp \ + api/qwebenginedownloaditem.cpp \ api/qwebenginehistory.cpp \ api/qwebenginepage.cpp \ + api/qwebengineprofile.cpp \ api/qwebenginesettings.cpp \ - api/qwebengineview.cpp\ + api/qwebengineview.cpp \ render_widget_host_view_qt_delegate_widget.cpp HEADERS = \ api/qtwebenginewidgetsglobal.h \ + api/qwebenginedownloaditem.h \ + api/qwebenginedownloaditem_p.h \ api/qwebenginecertificateerror.h \ api/qwebenginehistory.h \ api/qwebenginepage.h \ api/qwebenginepage_p.h \ + api/qwebengineprofile.h \ + api/qwebengineprofile_p.h \ api/qwebenginesettings.h \ - api/qwebenginesettings_p.h \ api/qwebengineview.h \ api/qwebengineview_p.h \ render_widget_host_view_qt_delegate_widget.h diff --git a/sync.profile b/sync.profile index 1e9519fe3..774941d56 100644 --- a/sync.profile +++ b/sync.profile @@ -21,4 +21,5 @@ "qtxmlpatterns" => "", # FIXME: take examples out into their own module to avoid a potential circular dependency later ? "qtquickcontrols" => "", + "qtwebchannel" => "", ); diff --git a/tests/auto/quick/inspectorserver/inspectorserver.pro b/tests/auto/quick/inspectorserver/inspectorserver.pro new file mode 100644 index 000000000..1a2c2f053 --- /dev/null +++ b/tests/auto/quick/inspectorserver/inspectorserver.pro @@ -0,0 +1,4 @@ +include(../tests.pri) +QT += webengine +QT_PRIVATE += webengine-private +DEFINES += IMPORT_DIR=\"\\\"$${ROOT_BUILD_DIR}$${QMAKE_DIR_SEP}imports\\\"\" diff --git a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp new file mode 100644 index 000000000..827f1a3c5 --- /dev/null +++ b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QScopedPointer> +#include <QtQml/QQmlEngine> +#include <QtTest/QtTest> +#include <private/qquickwebengineview_p.h> + +#define INSPECTOR_SERVER_PORT "23654" +static const QUrl s_inspectorServerHttpBaseUrl("http://localhost:" INSPECTOR_SERVER_PORT); + +class tst_InspectorServer : public QObject { + Q_OBJECT +public: + tst_InspectorServer(); + +private Q_SLOTS: + void init(); + void cleanup(); + + void testPageList(); + void testRemoteDebuggingMessage(); + void openRemoteDebuggingSession(); +private: + void prepareWebViewComponent(); + inline QQuickWebEngineView* newWebView(); + inline QQuickWebEngineView* webView() const; + QJsonArray fetchPageList() const; + QScopedPointer<QQuickWebEngineView> m_webView; + QScopedPointer<QQmlComponent> m_component; +}; + +tst_InspectorServer::tst_InspectorServer() +{ + qputenv("QTWEBENGINE_REMOTE_DEBUGGING", INSPECTOR_SERVER_PORT); + QtWebEngine::initialize(); + prepareWebViewComponent(); +} + +void tst_InspectorServer::prepareWebViewComponent() +{ + static QQmlEngine* engine = new QQmlEngine(this); + engine->addImportPath(QString::fromUtf8(IMPORT_DIR)); + + m_component.reset(new QQmlComponent(engine, this)); + + m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n" + "import QtWebEngine 1.0\n" + "WebEngineView { }") + , QUrl()); +} + +QQuickWebEngineView* tst_InspectorServer::newWebView() +{ + QObject* viewInstance = m_component->create(); + + return qobject_cast<QQuickWebEngineView*>(viewInstance); +} + +void tst_InspectorServer::init() +{ + m_webView.reset(newWebView()); +} + +void tst_InspectorServer::cleanup() +{ + m_webView.reset(); +} + +inline QQuickWebEngineView* tst_InspectorServer::webView() const +{ + return m_webView.data(); +} + +QJsonArray tst_InspectorServer::fetchPageList() const +{ + QNetworkAccessManager qnam; + QScopedPointer<QNetworkReply> reply(qnam.get(QNetworkRequest(s_inspectorServerHttpBaseUrl.resolved(QUrl("json/list"))))); + QSignalSpy(reply.data(), SIGNAL(finished())).wait(); + return QJsonDocument::fromJson(reply->readAll()).array(); +} + +void tst_InspectorServer::testPageList() +{ + const QUrl testPageUrl = QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "/html/basic_page.html")); + QSignalSpy loadSpy(webView(), SIGNAL(loadingChanged(QQuickWebEngineLoadRequest*))); + webView()->setUrl(testPageUrl); + QTRY_VERIFY(loadSpy.size() && !webView()->isLoading()); + + // Our page has developerExtrasEnabled and should be the only one in the list. + QJsonArray pageList = fetchPageList(); + QCOMPARE(pageList.size(), 1); + QCOMPARE(testPageUrl.toString(), pageList.at(0).toObject().value("url").toString()); +} + +void tst_InspectorServer::testRemoteDebuggingMessage() +{ + QJsonArray pageList = fetchPageList(); + QCOMPARE(pageList.size(), 1); + QVERIFY(pageList.at(0).toObject().contains("webSocketDebuggerUrl")); + + // Test sending a raw remote debugging message through our web socket server. + // For this specific message see: http://code.google.com/chrome/devtools/docs/protocol/tot/runtime.html#command-evaluate + QLatin1String jsExpression("2 + 2"); + QLatin1String jsExpressionResult("4"); + QScopedPointer<QQuickWebEngineView> webSocketQueryWebView(newWebView()); + webSocketQueryWebView->loadHtml(QString( + "<script type=\"text/javascript\">\n" + "var socket = new WebSocket('%1');\n" + "socket.onmessage = function(message) {\n" + "var response = JSON.parse(message.data);\n" + "if (response.id === 1)\n" + "document.title = response.result.result.value;\n" + "}\n" + "socket.onopen = function() {\n" + "socket.send('{\"id\": 1, \"method\": \"Runtime.evaluate\", \"params\": {\"expression\": \"%2\" } }');\n" + "}\n" + "</script>") + .arg(pageList.at(0).toObject().value("webSocketDebuggerUrl").toString()) + .arg(jsExpression)); + + QTRY_COMPARE(webSocketQueryWebView->title(), jsExpressionResult); +} + +void tst_InspectorServer::openRemoteDebuggingSession() +{ + QJsonArray pageList = fetchPageList(); + QCOMPARE(pageList.size(), 1); + QVERIFY(pageList.at(0).toObject().contains("devtoolsFrontendUrl")); + + QScopedPointer<QQuickWebEngineView> inspectorWebView(newWebView()); + inspectorWebView->setUrl(s_inspectorServerHttpBaseUrl.resolved(QUrl(pageList.at(0).toObject().value("devtoolsFrontendUrl").toString()))); + + // To test the whole pipeline this exploits a behavior of the inspector front-end which won't provide any title unless the + // debugging session was established correctly through web socket. + // So this test case will fail if: + // - The page list didn't return a valid inspector URL + // - Or the front-end couldn't be loaded through the inspector HTTP server + // - Or the web socket connection couldn't be established between the front-end and the page through the inspector server + QTRY_VERIFY(inspectorWebView->title().startsWith("Developer Tools -")); +} + +QTEST_MAIN(tst_InspectorServer) + +#include "tst_inspectorserver.moc" diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index f7cffb8b1..4b143d2bd 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -46,8 +46,12 @@ #include <QMetaType> #include <QtTest/QtTest> #include <private/qquickwebengineview_p.h> +#include <private/qquickwebenginecertificateerror_p.h> +#include <private/qquickwebenginedownloaditem_p.h> #include <private/qquickwebengineloadrequest_p.h> #include <private/qquickwebenginenavigationrequest_p.h> +#include <private/qquickwebenginenewviewrequest_p.h> +#include <private/qquickwebengineprofile_p.h> class tst_publicapi : public QObject { Q_OBJECT @@ -57,8 +61,12 @@ private Q_SLOTS: static QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>() << &QQuickWebEngineView::staticMetaObject + << &QQuickWebEngineCertificateError::staticMetaObject + << &QQuickWebEngineDownloadItem::staticMetaObject << &QQuickWebEngineLoadRequest::staticMetaObject << &QQuickWebEngineNavigationRequest::staticMetaObject + << &QQuickWebEngineNewViewRequest::staticMetaObject + << &QQuickWebEngineProfile::staticMetaObject ; static QList<const char *> knownEnumNames = QList<const char *>(); @@ -74,6 +82,19 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.LoadStoppedStatus --> LoadStatus" << "QQuickWebEngineView.LoadSucceededStatus --> LoadStatus" << "QQuickWebEngineView.LoadFailedStatus --> LoadStatus" + << "QQuickWebEngineCertificateError.SslPinnedKeyNotInCertificateChain --> Error" + << "QQuickWebEngineCertificateError.CertificateCommonNameInvalid --> Error" + << "QQuickWebEngineCertificateError.CertificateDateInvalid --> Error" + << "QQuickWebEngineCertificateError.CertificateAuthorityInvalid --> Error" + << "QQuickWebEngineCertificateError.CertificateContainsErrors --> Error" + << "QQuickWebEngineCertificateError.CertificateNoRevocationMechanism --> Error" + << "QQuickWebEngineCertificateError.CertificateUnableToCheckRevocation --> Error" + << "QQuickWebEngineCertificateError.CertificateRevoked --> Error" + << "QQuickWebEngineCertificateError.CertificateInvalid --> Error" + << "QQuickWebEngineCertificateError.CertificateWeakSignatureAlgorithm --> Error" + << "QQuickWebEngineCertificateError.CertificateNonUniqueName --> Error" + << "QQuickWebEngineCertificateError.CertificateWeakKey --> Error" + << "QQuickWebEngineCertificateError.CertificateNameConstraintViolation --> Error" << "QQuickWebEngineView.NoErrorDomain --> ErrorDomain" << "QQuickWebEngineView.InternalErrorDomain --> ErrorDomain" << "QQuickWebEngineView.ConnectionErrorDomain --> ErrorDomain" @@ -90,6 +111,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" @@ -103,6 +125,7 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.titleChanged() --> void" << "QQuickWebEngineView.navigationHistoryChanged() --> void" << "QQuickWebEngineView.loadingChanged(QQuickWebEngineLoadRequest*) --> void" + << "QQuickWebEngineView.certificateError(QQuickWebEngineCertificateError*) --> void" << "QQuickWebEngineView.loadProgressChanged() --> void" << "QQuickWebEngineView.javaScriptConsoleMessage(JavaScriptConsoleMessageLevel,QString,int,QString) --> void" << "QQuickWebEngineView.urlChanged() --> void" @@ -117,6 +140,22 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.goForward() --> void" << "QQuickWebEngineView.stop() --> void" << "QQuickWebEngineView.reload() --> void" + << "QQuickWebEngineView.zoomFactor --> double" + << "QQuickWebEngineView.zoomFactorChanged(double) --> void" + << "QQuickWebEngineView.profile --> QQuickWebEngineProfile*" + << "QQuickWebEngineView.newViewRequested(QQuickWebEngineNewViewRequest*) --> void" + << "QQuickWebEngineDownloadItem.id --> uint" + << "QQuickWebEngineDownloadItem.state --> DownloadState" + << "QQuickWebEngineDownloadItem.progress --> int" + << "QQuickWebEngineDownloadItem.path --> QString" + << "QQuickWebEngineDownloadItem.DownloadInProgress --> DownloadState" + << "QQuickWebEngineDownloadItem.DownloadCompleted --> DownloadState" + << "QQuickWebEngineDownloadItem.DownloadCancelled --> DownloadState" + << "QQuickWebEngineDownloadItem.DownloadInterrupted --> DownloadState" + << "QQuickWebEngineDownloadItem.stateChanged() --> void" + << "QQuickWebEngineDownloadItem.progressChanged() --> void" + << "QQuickWebEngineDownloadItem.pathChanged() --> void" + << "QQuickWebEngineDownloadItem.cancel() --> void" << "QQuickWebEngineLoadRequest.url --> QUrl" << "QQuickWebEngineLoadRequest.status --> QQuickWebEngineView::LoadStatus" << "QQuickWebEngineLoadRequest.errorString --> QString" @@ -127,6 +166,39 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineNavigationRequest.action --> QQuickWebEngineView::NavigationRequestAction" << "QQuickWebEngineNavigationRequest.navigationType --> QQuickWebEngineView::NavigationType" << "QQuickWebEngineNavigationRequest.actionChanged() --> void" + << "QQuickWebEngineNewViewRequest.destination --> QQuickWebEngineView::NewViewDestination" + << "QQuickWebEngineNewViewRequest.userInitiated --> bool" + << "QQuickWebEngineNewViewRequest.openIn(QQuickWebEngineView*) --> void" + << "QQuickWebEngineProfile.MemoryHttpCache --> HttpCacheType" + << "QQuickWebEngineProfile.DiskHttpCache --> HttpCacheType" + << "QQuickWebEngineProfile.NoPersistentCookies --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.AllowPersistentCookies --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.ForcePersistentCookies --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.storageName --> QString" + << "QQuickWebEngineProfile.offTheRecord --> bool" + << "QQuickWebEngineProfile.persistentStoragePath --> QString" + << "QQuickWebEngineProfile.cachePath --> QString" + << "QQuickWebEngineProfile.httpUserAgent --> QString" + << "QQuickWebEngineProfile.httpCacheType --> HttpCacheType" + << "QQuickWebEngineProfile.persistentCookiesPolicy --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.httpCacheMaxSize --> int" + << "QQuickWebEngineProfile.storageNameChanged() --> void" + << "QQuickWebEngineProfile.offTheRecordChanged() --> void" + << "QQuickWebEngineProfile.persistentStoragePathChanged() --> void" + << "QQuickWebEngineProfile.cachePathChanged() --> void" + << "QQuickWebEngineProfile.httpUserAgentChanged() --> void" + << "QQuickWebEngineProfile.httpCacheTypeChanged() --> void" + << "QQuickWebEngineProfile.persistentCookiesPolicyChanged() --> void" + << "QQuickWebEngineProfile.httpCacheMaxSizeChanged() --> void" + << "QQuickWebEngineCertificateError.ignoreCertificateError() --> void" + << "QQuickWebEngineCertificateError.rejectCertificate() --> void" + << "QQuickWebEngineCertificateError.defer() --> void" + << "QQuickWebEngineCertificateError.url --> QUrl" + << "QQuickWebEngineCertificateError.error --> Error" + << "QQuickWebEngineCertificateError.description --> QString" + << "QQuickWebEngineCertificateError.overridable --> bool" + << "QQuickWebEngineProfile.downloadStarted(QQuickWebEngineDownloadItem*) --> void" + << "QQuickWebEngineProfile.downloadFinished(QQuickWebEngineDownloadItem*) --> void" ; static bool isCheckedEnum(const QByteArray &typeName) diff --git a/tests/auto/quick/qmltests/data/keyboardModifierMapping.html b/tests/auto/quick/qmltests/data/keyboardModifierMapping.html new file mode 100644 index 000000000..b6d291207 --- /dev/null +++ b/tests/auto/quick/qmltests/data/keyboardModifierMapping.html @@ -0,0 +1,36 @@ +<html> +<body> +<kbd>Alt</kbd> is <span id="alt_state">no</span><br> +<kbd>Ctrl</kbd> is <span id="ctrl_state">no</span><br> +<kbd>Meta</kbd> is <span id="meta_state">no</span><br> +last keycode: <span id="last_keycode">none</span><br> + +<script> + +document.body.onkeydown = function(e) { + if (e.altKey) + alt_state.textContent = 'pressed' + if (e.ctrlKey) + ctrl_state.textContent = 'pressed' + if (e.metaKey) + meta_state.textContent = 'pressed' + last_keycode.textContent = e.keyCode +}; +document.body.onkeyup = function(e) { + if (e.altKey) + alt_state.textContent = 'released' + if (e.ctrlKey) + ctrl_state.textContent = 'released' + if (e.metaKey) + meta_state.textContent = 'released' + last_keycode.textContent = e.keyCode +}; + +function getPressedModifiers() { + return "alt:" + alt_state.textContent + " ctrl:" + ctrl_state.textContent + " meta:" + meta_state.textContent +} + +</script> +</body> +</html> + diff --git a/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml b/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml new file mode 100644 index 000000000..ddf025281 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 1.0 + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + + SignalSpy { + id: spy + target: webEngineView + signalName: "titleChanged" + } + + TestCase { + name: "WebEngineViewKeyboardModifierMapping" + + when: false + Timer { + running: parent.windowShown + repeat: false + interval: 1 + onTriggered: parent.when = true + } + + function test_keyboardModifierMapping() { + webEngineView.url = Qt.resolvedUrl("keyboardModifierMapping.html") + waitForLoadSucceeded(); + var callbackCalled = false; + + // Alt + keyPress(Qt.Key_Alt); + runJavaScript("getPressedModifiers()", function(result) { + compare(result, "alt:pressed ctrl:no meta:no"); + callbackCalled = true; + }); + wait(100); + verify(callbackCalled); + keyRelease(Qt.Key_Alt) + callbackCalled = false; + + // Ctrl + // On mac Qt automatically translates Meta to Ctrl and vice versa. + // However, if sending the events manually no mapping is being done, + // so we have to do this here manually. + // For testing we assume that the flag Qt::AA_MacDontSwapCtrlAndMeta is NOT set. + keyPress(Qt.platform.os == "osx" ? Qt.Key_Meta : Qt.Key_Control); + runJavaScript("getPressedModifiers()", function(result) { + compare(result, "alt:released ctrl:pressed meta:no"); + callbackCalled = true; + }); + wait(100); + verify(callbackCalled); + keyRelease(Qt.platform.os == "osx" ? Qt.Key_Meta : Qt.Key_Control); + callbackCalled = false; + + // Meta (Command on Mac) + keyPress(Qt.platform.os == "osx" ? Qt.Key_Control : Qt.Key_Meta); + runJavaScript("getPressedModifiers()", function(result) { + compare(result, "alt:released ctrl:released meta:pressed"); + callbackCalled = true; + }); + wait(100); + verify(callbackCalled); + keyRelease(Qt.platform.os == "osx" ? Qt.Key_Control : Qt.Key_Meta); + callbackCalled = false; + + runJavaScript("getPressedModifiers()", function(result) { + compare(result, "alt:released ctrl:released meta:released"); + callbackCalled = true; + }); + wait(100); + verify(callbackCalled); + callbackCalled = false; + } + } +} diff --git a/tests/quicktestbrowser/util.h b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml index bad41d6a7..f9b95ac19 100644 --- a/tests/quicktestbrowser/util.h +++ b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtWebEngine module of the Qt Toolkit. +** This file is part of the Qt Quick Controls module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -38,36 +38,53 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef UTIL_H -#define UTIL_H -#include <QtCore/QCoreApplication> -#include <QtCore/QFileInfo> -#include <QtCore/QUrl> -#include <QtCore/QStringList> +import QtQuick 2.3 +import QtTest 1.0 +import QtWebEngine 1.0 -QUrl urlFromUserInput(const QString& userInput) -{ - QFileInfo fileInfo(userInput); - if (fileInfo.exists()) - return QUrl(fileInfo.absoluteFilePath()); - return QUrl::fromUserInput(userInput); -} - -QUrl startupUrl() -{ - QUrl ret; - QStringList args(qApp->arguments()); - args.takeFirst(); - Q_FOREACH (const QString& arg, args) { - if (arg.startsWith(QLatin1Char('-'))) - continue; - ret = urlFromUserInput(arg); - if (ret.isValid()) - return ret; +Item { +width: 300 +height: 400 + TextInput { + id: textInput + anchors { + top: parent.top + left: parent.left + right: parent.right + } + focus: true + text: Qt.resolvedUrl("test1.html") + onEditingFinished: webEngineView.url = text } - return QUrl(QStringLiteral("http://qt-project.org/")); -} + TestWebEngineView { + id: webEngineView + anchors { + top: textInput.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } -#endif // UTIL_H + TestCase { + name: "WebEngineViewLoadRecursionCrash" + when:windowShown + + function test_QTBUG_42929() { + textInput.forceActiveFocus() + keyClick(Qt.Key_Return) + verify(webEngineView.waitForLoadSucceeded()) + textInput.text = "about:blank" + textInput.forceActiveFocus() + keyClick(Qt.Key_Return) + verify(webEngineView.waitForLoadSucceeded()) + textInput.text = Qt.resolvedUrl("test4.html") + textInput.forceActiveFocus() + // Don't crash now + keyClick(Qt.Key_Return) + verify(webEngineView.waitForLoadSucceeded()) + } + } + } +} diff --git a/examples/webengine/quicknanobrowser/util.h b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml index bc1cf8beb..8d5fd5375 100644 --- a/examples/webengine/quicknanobrowser/util.h +++ b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 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. +** This file is part of the Qt Quick Controls module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -38,36 +38,58 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef UTIL_H -#define UTIL_H -#include <QtCore/QCoreApplication> -#include <QtCore/QFileInfo> -#include <QtCore/QUrl> -#include <QtCore/QStringList> +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 1.0 -QUrl urlFromUserInput(const QString& userInput) -{ - QFileInfo fileInfo(userInput); - if (fileInfo.exists()) - return QUrl(fileInfo.absoluteFilePath()); - return QUrl::fromUserInput(userInput); -} +Item { + id: parentItem + width: 400 + height: 300 + + property var pressEvents: [] + property var releaseEvents: [] + Keys.onPressed: pressEvents.push(event.key) + Keys.onReleased: releaseEvents.push(event.key) -QUrl startupUrl() -{ - QUrl ret; - QStringList args(qApp->arguments()); - args.takeFirst(); - Q_FOREACH (const QString& arg, args) { - if (arg.startsWith(QLatin1Char('-'))) - continue; - ret = urlFromUserInput(arg); - if (ret.isValid()) - return ret; + TestWebEngineView { + id: webEngineView + anchors.fill: parent + focus: true } - return QUrl(QStringLiteral("http://qt.io/")); -} + TestCase { + name: "WebEngineViewUnhandledKeyEventPropagation" + + when: false + Timer { + running: parent.windowShown + repeat: false + interval: 1 + onTriggered: parent.when = true + } + function test_keyboardModifierMapping() { + webEngineView.loadHtml("<input type='text'/>") + webEngineView.waitForLoadSucceeded() + webEngineView.runJavaScript("document.body.firstChild.focus()") -#endif // UTIL_H + keyPress(Qt.Key_A) + keyRelease(Qt.Key_A) + keyPress(Qt.Key_Left) + keyRelease(Qt.Key_Left) + keyPress(Qt.Key_Left) + keyRelease(Qt.Key_Left) + + for (var i = 0; i < 20 && parentItem.releaseEvents.length < 3; i++) + wait(100) + + compare(parentItem.pressEvents.length, 1) + compare(parentItem.pressEvents[0], Qt.Key_Left) + compare(parentItem.releaseEvents.length, 3) + compare(parentItem.releaseEvents[0], Qt.Key_A) + compare(parentItem.releaseEvents[1], Qt.Key_Left) + compare(parentItem.releaseEvents[2], Qt.Key_Left) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_webchannel.qml b/tests/auto/quick/qmltests/data/tst_webchannel.qml new file mode 100644 index 000000000..1abb191e1 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_webchannel.qml @@ -0,0 +1,114 @@ +/********************************************************************* +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 1.0 +import QtWebEngine.experimental 1.0 + +import QtWebChannel 1.0 + +Item { + id: test + signal barCalled(var arg) + signal clientInitializedCalled(var arg) + + QtObject { + id: testObject + WebChannel.id: "testObject" + + property var foo: 42 + + function clientInitialized(arg) + { + clientInitializedCalled(arg); + } + + function bar(arg) { + barCalled(arg); + } + + signal runTest(var foo) + } + + TestWebEngineView { + id: webView + experimental.webChannel.registeredObjects: [testObject] + } + + SignalSpy { + id: initializedSpy + target: test + signalName: "clientInitializedCalled" + } + + SignalSpy { + id: barSpy + target: test + signalName: "barCalled" + } + + TestCase { + name: "WebViewWebChannel" + property url testUrl: Qt.resolvedUrl("./webchannel-test.html") + + function init() { + initializedSpy.clear(); + barSpy.clear(); + } + + function test_basic() { + webView.url = testUrl; + verify(webView.waitForLoadSucceeded()); + + initializedSpy.wait(); + compare(initializedSpy.signalArguments.length, 1); + compare(initializedSpy.signalArguments[0][0], 42); + + var newValue = "roundtrip"; + testObject.runTest(newValue); + barSpy.wait(); + compare(barSpy.signalArguments.length, 1); + compare(barSpy.signalArguments[0][0], newValue); + + compare(testObject.foo, newValue); + } + } +} diff --git a/tests/auto/quick/qmltests/data/webchannel-test.html b/tests/auto/quick/qmltests/data/webchannel-test.html new file mode 100644 index 000000000..940821209 --- /dev/null +++ b/tests/auto/quick/qmltests/data/webchannel-test.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> + <script type="text/javascript"> + //BEGIN SETUP + var channel = new QWebChannel(navigator.qtWebChannelTransport, function(channel) { + window.testObject = channel.objects.testObject; + testObject.runTest.connect(function(foo) { + testObject.foo = foo; + testObject.bar(foo); + }); + testObject.clientInitialized(testObject.foo); + }); + //END SETUP + </script> + </head> + <body> + </body> +</html> diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index b40ef3b8c..6789b714b 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -16,6 +16,8 @@ OTHER_FILES += \ $$PWD/data/test1.html \ $$PWD/data/test2.html \ $$PWD/data/test3.html \ + $$PWD/data/test4.html \ + $$PWD/data/keyboardModifierMapping.html \ $$PWD/data/tst_desktopBehaviorLoadHtml.qml \ $$PWD/data/tst_favIconLoad.qml \ $$PWD/data/tst_linkHovered.qml \ @@ -23,12 +25,15 @@ OTHER_FILES += \ $$PWD/data/tst_loadHtml.qml \ $$PWD/data/tst_loadProgress.qml \ $$PWD/data/tst_loadProgressSignal.qml \ + $$PWD/data/tst_loadRecursionCrash.qml \ $$PWD/data/tst_loadUrl.qml \ $$PWD/data/tst_navigationHistory.qml \ $$PWD/data/tst_navigationRequested.qml \ $$PWD/data/tst_properties.qml \ $$PWD/data/tst_runJavaScript.qml \ - $$PWD/data/tst_titleChanged.qml + $$PWD/data/tst_titleChanged.qml \ + $$PWD/data/tst_keyboardModifierMapping.qml \ + load(qt_build_paths) DEFINES += QUICK_TEST_SOURCE_DIR=\"\\\"$$PWD$${QMAKE_DIR_SEP}data\\\"\" diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 5c9bb72b5..71bc61b9e 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs SUBDIRS += \ + inspectorserver \ publicapi \ qmltests \ qquickwebengineview \ 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/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 3893397cd..83f65f9d0 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -50,6 +50,7 @@ private Q_SLOTS: void reusePage(); void microFocusCoordinates(); void focusInputTypes(); + void unhandledKeyEventPropagation(); void horizontalScrollbarTest(); void crashTests(); @@ -321,6 +322,49 @@ void tst_QWebEngineView::focusInputTypes() #endif } +class KeyEventRecordingWidget : public QWidget { +public: + QList<QKeyEvent> pressEvents; + QList<QKeyEvent> releaseEvents; + void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE { pressEvents << *e; } + void keyReleaseEvent(QKeyEvent *e) Q_DECL_OVERRIDE { releaseEvents << *e; } +}; + +void tst_QWebEngineView::unhandledKeyEventPropagation() +{ + KeyEventRecordingWidget parentWidget; + QWebEngineView webView(&parentWidget); + parentWidget.show(); + QTest::qWaitForWindowExposed(&webView); + + QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool))); + webView.setHtml("<input type='text'/>"); + QTRY_COMPARE(loadSpy.count(), 1); + + evaluateJavaScriptSync(webView.page(), "document.body.firstChild.focus()"); + + QTest::sendKeyEvent(QTest::Press, parentWidget.windowHandle(), Qt::Key_A, 'a', Qt::NoModifier); + QTest::sendKeyEvent(QTest::Release, parentWidget.windowHandle(), Qt::Key_A, 'a', Qt::NoModifier); + QTest::sendKeyEvent(QTest::Press, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier); + QTest::sendKeyEvent(QTest::Release, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier); + QTest::sendKeyEvent(QTest::Press, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier); + QTest::sendKeyEvent(QTest::Release, parentWidget.windowHandle(), Qt::Key_Left, QString(), Qt::NoModifier); + + // All this happens asychronously, wait for the last release event to know when we're done. + for (int i = 0; i < 20 && parentWidget.releaseEvents.size() < 3; ++i) + QTest::qWait(100); + + // The page will consume the 'a' and the first left key presses, the second left won't be + // used since the cursor will already be at the left end of the text input. + // Key releases will all come back unconsumed. + QCOMPARE(parentWidget.pressEvents.size(), 1); + QCOMPARE(parentWidget.pressEvents[0].key(), (int)Qt::Key_Left); + QCOMPARE(parentWidget.releaseEvents.size(), 3); + QCOMPARE(parentWidget.releaseEvents[0].key(), (int)Qt::Key_A); + QCOMPARE(parentWidget.releaseEvents[1].key(), (int)Qt::Key_Left); + QCOMPARE(parentWidget.releaseEvents[2].key(), (int)Qt::Key_Left); +} + void tst_QWebEngineView::horizontalScrollbarTest() { #if !defined(QWEBENGINEPAGE_SCROLL) diff --git a/tests/quicktestbrowser/ApplicationRoot.qml b/tests/quicktestbrowser/ApplicationRoot.qml new file mode 100644 index 000000000..56196efdc --- /dev/null +++ b/tests/quicktestbrowser/ApplicationRoot.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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.1 + +QtObject { + id: root + property Component browserWindowComponent: BrowserWindow { + applicationRoot: root + onClosing: destroy() + } + property Component browserDialogComponent: BrowserDialog { + onClosing: destroy() + } + function createWindow() { return browserWindowComponent.createObject(root) } + function createDialog() { return browserDialogComponent.createObject(root) } + function load(url) { + var browserWindow = createWindow() + browserWindow.currentWebView.url = url + } +} diff --git a/tests/quicktestbrowser/BrowserDialog.qml b/tests/quicktestbrowser/BrowserDialog.qml new file mode 100644 index 000000000..038a62f28 --- /dev/null +++ b/tests/quicktestbrowser/BrowserDialog.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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.1 +import QtQuick.Window 2.2 +import QtWebEngine 1.0 + +Window { + property alias currentWebView: webView + flags: Qt.Dialog + width: 800 + height: 600 + visible: true + onClosing: destroy() + WebEngineView { + id: webView + anchors.fill: parent + } +} diff --git a/tests/quicktestbrowser/quickwindow.qml b/tests/quicktestbrowser/BrowserWindow.qml index 6a5ef3187..d438075d8 100644 --- a/tests/quicktestbrowser/quickwindow.qml +++ b/tests/quicktestbrowser/BrowserWindow.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.1 -import QtWebEngine 1.0 +import QtWebEngine 1.1 import QtWebEngine.experimental 1.0 import QtQuick.Controls 1.0 @@ -48,11 +48,11 @@ import QtQuick.Layouts 1.0 import QtQuick.Window 2.1 import QtQuick.Controls.Private 1.0 import Qt.labs.settings 1.0 - +import QtQuick.Dialogs 1.2 ApplicationWindow { id: browserWindow - function load(url) { currentWebView.url = url } + property QtObject applicationRoot property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item.webView : null property bool isFullScreen: visibility == Window.FullScreen @@ -73,6 +73,22 @@ ApplicationWindow { property alias errorPageEnabled: errorPageEnabled.checked; } + WebEngineProfile { + id: testProfile + storageName: "Test" + httpCacheType: httpDiskCacheEnabled.checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache; + onDownloadRequested: { + downloadView.visible = true + downloadView.append(download) + download.accept() + } + } + + WebEngineProfile { + id: otrProfile + offTheRecord: true + } + // Make sure the Qt.WindowFullscreenButtonHint is set on Mac. Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint @@ -81,6 +97,12 @@ ApplicationWindow { StyleItem { id: styleItem } property bool platformIsMac: styleItem.style == "mac" + Action { + shortcut: "Ctrl+D" + onTriggered: { + downloadView.visible = !downloadView.visible + } + } Action { id: focus @@ -122,6 +144,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 @@ -223,6 +257,18 @@ ApplicationWindow { checked: WebEngine.settings.errorPageEnabled onCheckedChanged: WebEngine.settings.errorPageEnabled = checked } + MenuItem { + id: offTheRecordEnabled + text: "Off The Record" + checkable: true + checked: false + } + MenuItem { + id: httpDiskCacheEnabled + text: "HTTP Disk Cache" + checkable: true + checked: (testProfile.httpCacheType == WebEngineProfile.DiskHttpCache) + } } } } @@ -260,20 +306,6 @@ ApplicationWindow { Component.onCompleted: createEmptyTab() Component { - id: dialogComponent - Window { - property Item webView: _webView - width: 800 - height: 600 - visible: true - WebEngineView { - id: _webView - anchors.fill: parent - } - } - } - - Component { id: tabComponent Item { property alias webView: webEngineView @@ -300,6 +332,7 @@ ApplicationWindow { WebEngineView { id: webEngineView + profile: offTheRecordEnabled.checked ? otrProfile : testProfile anchors { fill: parent @@ -323,6 +356,28 @@ ApplicationWindow { } ] + onCertificateError: { + sslDialog.certError = error + sslDialog.text = "Certificate Error: " + error.description + sslDialog.visible = true + error.defer() + } + + onNewViewRequested: { + if (!request.userInitiated) + print("Warning: Blocked a popup window.") + else if (request.destination == WebEngineView.NewViewInTab) { + var tab = tabs.createEmptyTab() + request.openIn(tab.item.webView) + } else if (request.destination == WebEngineView.NewViewInDialog) { + var dialog = applicationRoot.createDialog() + request.openIn(dialog.currentWebView) + } else { + var window = applicationRoot.createWindow() + request.openIn(window.currentWebView) + } + } + experimental { isFullScreen: webEngineView.state == "FullScreen" && browserWindow.isFullScreen onFullScreenRequested: { @@ -335,21 +390,6 @@ ApplicationWindow { } } - onNewViewRequested: { - if (!request.userInitiated) - print("Warning: Blocked a popup window.") - else if (request.destination == WebEngineView.NewViewInTab) { - var tab = tabs.createEmptyTab() - request.openIn(tab.item.webView) - } else if (request.destination == WebEngineView.NewViewInDialog) { - var dialog = dialogComponent.createObject() - request.openIn(dialog.webView) - } else { - var component = Qt.createComponent("quickwindow.qml") - var window = component.createObject() - request.openIn(window.currentWebView) - } - } onFeaturePermissionRequested: { permBar.securityOrigin = securityOrigin; permBar.requestedFeature = feature; @@ -399,4 +439,36 @@ ApplicationWindow { } } } + + MessageDialog { + id: sslDialog + + property var certError + + standardButtons: StandardButton.Cancel | StandardButton.Ok + visible: false + title: "Do you want to accept this certificate?" + + onAccepted: certError.ignoreCertificateError() + onRejected: certError.rejectCertificate() + } + + DownloadView { + id: downloadView + visible: false + anchors.fill: parent + } + + 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/ButtonWithMenu.qml b/tests/quicktestbrowser/ButtonWithMenu.qml index 8058b958a..10f5dbbc3 100644 --- a/tests/quicktestbrowser/ButtonWithMenu.qml +++ b/tests/quicktestbrowser/ButtonWithMenu.qml @@ -47,7 +47,7 @@ ToolButton { id: root property Menu longPressMenu function showMenu() { - longPressMenu.__popup(0, root.height, 0) + longPressMenu.__popup(Qt.rect(0, root.height, 0, 0), 0) } Binding { diff --git a/tests/quicktestbrowser/DownloadView.qml b/tests/quicktestbrowser/DownloadView.qml new file mode 100644 index 000000000..3367dfc71 --- /dev/null +++ b/tests/quicktestbrowser/DownloadView.qml @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtWebEngine 1.0 +import QtWebEngine.experimental 1.0 +import QtQuick.Layouts 1.0 + +Rectangle { + id: downloadView + color: "lightgray" + + ListModel { + id: downloadModel + property var downloads: [] + } + + function append(download) { + downloadModel.append(download) + downloadModel.downloads.push(download) + } + + Component { + id: downloadItemDelegate + + Rectangle { + width: listView.width + height: childrenRect.height + anchors.margins: 10 + radius: 3 + color: "transparent" + border.color: "black" + Rectangle { + id: progressBar + + property real progress: downloadModel.downloads[index] + ? downloadModel.downloads[index].receivedBytes / downloadModel.downloads[index].totalBytes : 0 + + radius: 3 + color: width == listView.width ? "green" : "#2b74c7" + width: listView.width * progress + height: cancelButton.height + + Behavior on width { + SmoothedAnimation { duration: 100 } + } + } + Rectangle { + anchors { + left: parent.left + right: parent.right + leftMargin: 20 + } + Label { + id: label + text: path + anchors { + verticalCenter: cancelButton.verticalCenter + left: parent.left + right: cancelButton.left + } + } + Button { + id: cancelButton + anchors.right: parent.right + iconSource: "icons/process-stop.png" + onClicked: { + var download = downloadModel.downloads[index] + + download.cancel() + + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== download.id; + }); + downloadModel.remove(index) + } + } + } + } + + } + ListView { + id: listView + anchors { + topMargin: 10 + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: parent.width - 20 + spacing: 5 + + model: downloadModel + delegate: downloadItemDelegate + + Text { + visible: !listView.count + horizontalAlignment: Text.AlignHCenter + height: 30 + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.pixelSize: 20 + text: "No active downloads." + } + + Rectangle { + color: "gray" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: 30 + Button { + id: okButton + text: "OK" + anchors.centerIn: parent + onClicked: { + downloadView.visible = false + } + } + } + } +} 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/main.cpp b/tests/quicktestbrowser/main.cpp index d8fe01aa1..2d5271176 100644 --- a/tests/quicktestbrowser/main.cpp +++ b/tests/quicktestbrowser/main.cpp @@ -39,7 +39,8 @@ ** ****************************************************************************/ -#include "quickwindow.h" +#include "utils.h" + #ifndef QT_NO_WIDGETS #include <QtWidgets/QApplication> typedef QApplication Application; @@ -47,15 +48,39 @@ typedef QApplication Application; #include <QtGui/QGuiApplication> typedef QGuiApplication Application; #endif -#include <qtwebengineglobal.h> +#include <QtQml/QQmlApplicationEngine> +#include <QtQml/QQmlContext> +#include <QtWebEngine/qtwebengineglobal.h> + +static QUrl startupUrl() +{ + QUrl ret; + QStringList args(qApp->arguments()); + args.takeFirst(); + Q_FOREACH (const QString& arg, args) { + if (arg.startsWith(QLatin1Char('-'))) + continue; + ret = Utils::fromUserInput(arg); + if (ret.isValid()) + return ret; + } + return QUrl(QStringLiteral("http://qt.io/")); +} int main(int argc, char **argv) { Application app(argc, argv); + // Enable dev tools by default for the test browser + if (qgetenv("QTWEBENGINE_REMOTE_DEBUGGING").isNull()) + qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "1337"); QtWebEngine::initialize(); - ApplicationEngine appEngine; + QQmlApplicationEngine appEngine; + Utils utils; + appEngine.rootContext()->setContextProperty("utils", &utils); + appEngine.load(QUrl("qrc:/ApplicationRoot.qml")); + QMetaObject::invokeMethod(appEngine.rootObjects().first(), "load", Q_ARG(QVariant, startupUrl())); return app.exec(); } diff --git a/tests/quicktestbrowser/quicktestbrowser.pro b/tests/quicktestbrowser/quicktestbrowser.pro index ac8fe74b3..b285c5e62 100644 --- a/tests/quicktestbrowser/quicktestbrowser.pro +++ b/tests/quicktestbrowser/quicktestbrowser.pro @@ -1,17 +1,20 @@ +requires(contains(QT_CONFIG, accessibility)) + TEMPLATE = app TARGET = quicktestbrowser macx: CONFIG -= app_bundle -HEADERS = quickwindow.h \ - util.h -SOURCES = quickwindow.cpp \ - main.cpp +HEADERS = utils.h +SOURCES = main.cpp -OTHER_FILES += ButtonWithMenu.qml \ +OTHER_FILES += ApplicationRoot.qml \ + BrowserDialog.qml \ + BrowserWindow.qml \ + ButtonWithMenu.qml \ ContextMenuExtras.qml \ - FeaturePermissionBar.qml \ - quickwindow.qml + DownloadView.qml \ + FeaturePermissionBar.qml RESOURCES += resources.qrc diff --git a/tests/quicktestbrowser/quickwindow.cpp b/tests/quicktestbrowser/quickwindow.cpp deleted file mode 100644 index ec7b6f94a..000000000 --- a/tests/quicktestbrowser/quickwindow.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "quickwindow.h" - -#include "util.h" - -#include <QFileInfo> -#include <QObject> -#include <QQmlContext> -#include <QQmlEngine> -#include <QUrl> - -class Utils : public QObject { - Q_OBJECT -public: - Utils(QObject* parent = 0) : QObject(parent) { } - Q_INVOKABLE static QUrl fromUserInput(const QString& userInput) { return urlFromUserInput(userInput); } -}; - -#include "quickwindow.moc" - -ApplicationEngine::ApplicationEngine() -{ - rootContext()->setContextProperty("utils", new Utils(this)); - load(QUrl("qrc:/quickwindow.qml")); - QMetaObject::invokeMethod(rootObjects().first(), "load", Q_ARG(QVariant, startupUrl())); -} diff --git a/tests/quicktestbrowser/resources.qrc b/tests/quicktestbrowser/resources.qrc index cdc3d2304..80f1d1543 100644 --- a/tests/quicktestbrowser/resources.qrc +++ b/tests/quicktestbrowser/resources.qrc @@ -1,9 +1,13 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/"> - <file>quickwindow.qml</file> + <file>ApplicationRoot.qml</file> + <file>BrowserDialog.qml</file> + <file>BrowserWindow.qml</file> <file>ContextMenuExtras.qml</file> <file>FeaturePermissionBar.qml</file> <file>ButtonWithMenu.qml</file> + <file>DownloadView.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/quickwindow.h b/tests/quicktestbrowser/utils.h index ed25a23b8..3cb3fec5d 100644 --- a/tests/quicktestbrowser/quickwindow.h +++ b/tests/quicktestbrowser/utils.h @@ -38,18 +38,24 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef UTILS_H +#define UTILS_H -#ifndef QUICKWINDOW_H -#define QUICKWINDOW_H +#include <QtCore/QFileInfo> +#include <QtCore/QUrl> -#include <QQmlApplicationEngine> - -class QWebEngineView; - -class ApplicationEngine : public QQmlApplicationEngine { +class Utils : public QObject { Q_OBJECT public: - ApplicationEngine(); + Q_INVOKABLE static QUrl fromUserInput(const QString& userInput); }; -#endif // QUICKWINDOW_H +inline QUrl Utils::fromUserInput(const QString& userInput) +{ + QFileInfo fileInfo(userInput); + if (fileInfo.exists()) + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + return QUrl::fromUserInput(userInput); +} + +#endif // UTILS_H diff --git a/tests/tests.pro b/tests/tests.pro index f6dec7a55..2922e5076 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,5 +1,3 @@ TEMPLATE = subdirs -isPlatformSupported() { - SUBDIRS += auto quicktestbrowser -} +SUBDIRS += auto quicktestbrowser diff --git a/tools/buildscripts/repack_locales.py b/tools/buildscripts/repack_locales.py index 389e9b1fd..da3164b4d 100755 --- a/tools/buildscripts/repack_locales.py +++ b/tools/buildscripts/repack_locales.py @@ -85,16 +85,16 @@ def calc_inputs(locale): inputs = [] if OS != 'ios': - #e.g. '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_strings_da.pak' - inputs.append(os.path.join(SHARE_INT_DIR, 'webkit', - 'webkit_strings_%s.pak' % locale)) + #e.g. '<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.pak' + inputs.append(os.path.join(SHARE_INT_DIR, 'content', 'app', 'strings', + 'content_strings_%s.pak' % locale)) - #e.g. '<(SHARED_INTERMEDIATE_DIR)/ui/ui_strings_da.pak', - inputs.append(os.path.join(SHARE_INT_DIR, 'ui', 'ui_strings', + #e.g. '<(SHARED_INTERMEDIATE_DIR)/ui/strings/ui_strings_da.pak', + inputs.append(os.path.join(SHARE_INT_DIR, 'ui', 'strings', 'ui_strings_%s.pak' % locale)) - #e.g. '<(SHARED_INTERMEDIATE_DIR)/ui/app_locale_settings_da.pak', - inputs.append(os.path.join(SHARE_INT_DIR, 'ui', 'app_locale_settings', + #e.g. '<(SHARED_INTERMEDIATE_DIR)/ui/strings/app_locale_settings_da.pak', + inputs.append(os.path.join(SHARE_INT_DIR, 'ui', 'strings', 'app_locale_settings_%s.pak' % locale)) # Used for localized error messages and error pages diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index 4c2547d57..2e2261cb9 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -1,4 +1,8 @@ defineTest(isPlatformSupported) { + !win32-msvc2013: !contains(QT_CONFIG, c++11) { + skipBuild("C++11 support is required in order to build chromium.") + return(false) + } static { skipBuild("Static builds of QtWebEngine aren't supported.") return(false) @@ -20,16 +24,16 @@ defineTest(isPlatformSupported) { defineTest(isPythonVersionSupported) { python_major_version = $$system('python -c "import sys; print sys.version_info.major"') python_minor_version = $$system('python -c "import sys; print sys.version_info.minor"') - greaterThan(python_major_version, 1): greaterThan(python_minor_version, 6): return(true) - skipBuild("Using Python version "$$python_major_version"."$$python_minor_version", but at least Python version 2.7 is required to build Qt WebEngine.") + lessThan(python_major_version, 3): greaterThan(python_major_version, 1): greaterThan(python_minor_version, 6): return(true) + skipBuild("Using Python version "$$python_major_version"."$$python_minor_version", but Python version 2 (2.7 or later) is required to build Qt WebEngine.") return(false) } defineTest(isGCCVersionSupported) { - # The below will work for gcc 4.6 and up and also match gcc 5 - greaterThan(QT_GCC_MINOR_VERSION, 5):return(true) + # The below will work for gcc 4.7 and up and also match gcc 5 + greaterThan(QT_GCC_MINOR_VERSION, 6):return(true) greaterThan(QT_GCC_MAJOR_VERSION, 4):return(true) - skipBuild("Using gcc version "$$QT_GCC_MAJOR_VERSION"."$$QT_GCC_MINOR_VERSION", but at least gcc version 4.6 is required to build Qt WebEngine.") + skipBuild("Using gcc version "$$QT_GCC_MAJOR_VERSION"."$$QT_GCC_MINOR_VERSION", but at least gcc version 4.7 is required to build Qt WebEngine.") return(false) } @@ -73,7 +77,7 @@ defineReplace(findMocables) { for (file, input): \ infiles += $$absolute_path($$file, $$_PRO_FILE_PWD_) mocables = $$system("python $$QTWEBENGINE_ROOT/tools/buildscripts/find-mocables $$infiles") - mocables = $$replace(mocables, $$_PRO_FILE_PWD_/, '') + mocables = $$replace(mocables, $$re_escape($${_PRO_FILE_PWD_}/), '') return($$mocables) } @@ -87,8 +91,10 @@ defineReplace(findIncludedMocFiles) { defineReplace(mocOutput) { out = $$1 # The order is important, since the output of the second replace would end up accidentaly transformed by the first one - out = $$replace(out, ^(.*)($$join(QMAKE_EXT_CPP,|)), $${QMAKE_CPP_MOD_MOC}\\1$${QMAKE_EXT_CPP_MOC}) - out = $$replace(out, ^(.*)($$join(QMAKE_EXT_H,|)), $${QMAKE_H_MOD_MOC}\\1$${first(QMAKE_EXT_CPP)}) + for(ext, $$list($${QMAKE_EXT_CPP})): \ + out = $$replace(out, ^(.*)($$re_escape($${ext})), $${QMAKE_CPP_MOD_MOC}\\1$${QMAKE_EXT_CPP_MOC}) + for(ext, $$list($${QMAKE_EXT_H})): \ + out = $$replace(out, ^(.*)($$re_escape($${ext})), $${QMAKE_H_MOD_MOC}\\1$${first(QMAKE_EXT_CPP)}) return($$out) } @@ -139,7 +145,7 @@ defineReplace(findOrBuildNinja) { win32: out = $$system_path($${out}.exe) # If we did not find ninja, then we bootstrap it. - !exists($$out): system("python $$dirname(out)/bootstrap.py") + !exists($$out): system("cd $$dirname(out) && python configure.py --bootstrap") } return($$out) } diff --git a/tools/scripts/init-repository.py b/tools/scripts/init-repository.py index 3425649ff..7c33ff01d 100755 --- a/tools/scripts/init-repository.py +++ b/tools/scripts/init-repository.py @@ -98,7 +98,7 @@ def updateLastChange(): def initUpstreamSubmodules(): ninja_url = 'https://github.com/martine/ninja.git' chromium_url = 'https://chromium.googlesource.com/chromium/src.git' - ninja_shasum = '7103c32646df958b0287c65b1c660bf528a191d6' + ninja_shasum = 'refs/tags/' + resolver.currentNinjaVersion() chromium_ref = 'refs/tags/' + resolver.currentVersion() os.chdir(qtwebengine_root) diff --git a/tools/scripts/take_snapshot.py b/tools/scripts/take_snapshot.py index 3696b9a7a..4a468d113 100755 --- a/tools/scripts/take_snapshot.py +++ b/tools/scripts/take_snapshot.py @@ -61,6 +61,7 @@ def isInGitBlacklist(file_path): False if ( '.gitignore' in file_path or '.gitmodules' in file_path + or '.gitattributes' in file_path or '.DEPS' in file_path ): return True @@ -102,19 +103,22 @@ def isInChromiumBlacklist(file_path): not 'media/desktop_media_list.h' in file_path and not 'media/desktop_streams_registry.cc' in file_path and not 'media/desktop_streams_registry.h' in file_path and - not 'net/net_error_info' in file_path and not 'common/localized_error' in file_path and not file_path.endswith('cf_resources.rc') and not file_path.endswith('version.py') and not file_path.endswith('.grd') and not file_path.endswith('.grdp') and - not file_path.endswith('.json')) + not file_path.endswith('.json') and + not file_path.endswith('chrome_version.rc.version')) or file_path.startswith('chrome_frame') or file_path.startswith('chromeos') or file_path.startswith('cloud_print') or (file_path.startswith('components') and not file_path.startswith('components/tracing') and - not file_path.startswith('components/visitedlink')) + not file_path.startswith('components/visitedlink') and + not file_path.startswith('components/error_page') and + not file_path.endswith('.grdp') and + not 'components_strings' in file_path) or file_path.startswith('content/public/android/java') or file_path.startswith('content/shell') or file_path.startswith('courgette') @@ -157,9 +161,11 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/cros_dbus_cplusplus') or file_path.startswith('third_party/cros_system_api') or file_path.startswith('third_party/cygwin') + or file_path.startswith('third_party/cython') or file_path.startswith('third_party/elfutils') or file_path.startswith('third_party/eyesfree') or file_path.startswith('third_party/findbugs') + or file_path.startswith('third_party/google_input_tools') or file_path.startswith('third_party/gperf') or file_path.startswith('third_party/gnu_binutils') or file_path.startswith('third_party/gtk+') @@ -173,6 +179,7 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/instrumented_libraries') or file_path.startswith('third_party/jarjar') or file_path.startswith('third_party/jsr-305/src') + or file_path.startswith('third_party/junit') or file_path.startswith('third_party/libphonenumber') or file_path.startswith('third_party/libaddressinput') or file_path.startswith('third_party/libc++') @@ -182,6 +189,7 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/markdown') or file_path.startswith('third_party/mingw-w64') or file_path.startswith('third_party/nacl_sdk_binaries') + or file_path.startswith('third_party/polymer') or file_path.startswith('third_party/pdfsqueeze') or file_path.startswith('third_party/pefile') or file_path.startswith('third_party/perl') @@ -248,7 +256,7 @@ def clearDirectory(directory): os.chdir(directory) print 'clearing the directory:' + directory for direntry in os.listdir(directory): - if not direntry == '.git': + if not direntry == '.git' and os.path.isdir(direntry): print 'clearing:' + direntry shutil.rmtree(direntry) os.chdir(currentDir) @@ -304,6 +312,12 @@ if not commandNotFound: if commandNotFound or dos2unixVersion < StrictVersion('6.0.6'): raise Exception("You need dos2unix version 6.0.6 minimum.") +os.chdir(third_party) +ignore_case_setting = subprocess.Popen(['git', 'config', '--get', 'core.ignorecase'], stdout=subprocess.PIPE).communicate()[0] +if 'true' in ignore_case_setting: + raise Exception("Your 3rdparty repository is configured to ignore case. " + "A snapshot created with these settings would cause problems on case sensitive file systems.") + clearDirectory(third_party) exportNinja() diff --git a/tools/scripts/version_resolver.py b/tools/scripts/version_resolver.py index 2430555d9..d0ae1824e 100644 --- a/tools/scripts/version_resolver.py +++ b/tools/scripts/version_resolver.py @@ -51,8 +51,9 @@ import json import urllib2 import git_submodule as GitSubmodule -chromium_version = '37.0.2062.103' -chromium_branch = '2062' +chromium_version = '40.0.2214.28' +chromium_branch = '2214' +ninja_version = 'v1.5.3' json_url = 'http://omahaproxy.appspot.com/all.json' @@ -73,6 +74,9 @@ sys.path.append(os.path.join(qtwebengine_root, 'tools', 'scripts')) def currentVersion(): return chromium_version +def currentNinjaVersion(): + return ninja_version + def readReleaseChannels(): response = urllib2.urlopen(json_url) raw_json = response.read().strip() |