diff options
209 files changed, 7247 insertions, 1111 deletions
diff --git a/.gitignore b/.gitignore index b66341f8f..67a9d4d04 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ src/3rdparty_upstream/ninja src/3rdparty_upstream/chromium src/core/Debug src/core/Release +src/core/api/Release +src/core/api/Debug src/core/core_generated.gyp src/core/gypfiles src/core/qmake_extras.gypi diff --git a/.qmake.conf b/.qmake.conf index 513fe9a0e..fe1cde075 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.5.1 +MODULE_VERSION = 5.6.0 diff --git a/examples/webengine/quicknanobrowser/ApplicationRoot.qml b/examples/webengine/quicknanobrowser/ApplicationRoot.qml index b409696be..91d1551a7 100644 --- a/examples/webengine/quicknanobrowser/ApplicationRoot.qml +++ b/examples/webengine/quicknanobrowser/ApplicationRoot.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.1 -import QtWebEngine 1.1 +import QtWebEngine 1.2 QtObject { id: root diff --git a/examples/webengine/quicknanobrowser/BrowserDialog.qml b/examples/webengine/quicknanobrowser/BrowserDialog.qml index 6202d02f7..0577bf642 100644 --- a/examples/webengine/quicknanobrowser/BrowserDialog.qml +++ b/examples/webengine/quicknanobrowser/BrowserDialog.qml @@ -40,7 +40,7 @@ import QtQuick 2.1 import QtQuick.Window 2.2 -import QtWebEngine 1.1 +import QtWebEngine 1.2 Window { property alias currentWebView: webView diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml index c4c0270a4..bdee68d17 100644 --- a/examples/webengine/quicknanobrowser/BrowserWindow.qml +++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml @@ -38,8 +38,8 @@ ** ****************************************************************************/ -import QtQuick 2.1 -import QtWebEngine 1.1 +import QtQuick 2.2 +import QtWebEngine 1.2 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.0 import QtQuick.Layouts 1.0 @@ -82,6 +82,7 @@ ApplicationWindow { property alias autoLoadImages: loadImages.checked; property alias javaScriptEnabled: javaScriptEnabled.checked; property alias errorPageEnabled: errorPageEnabled.checked; + property alias pluginsEnabled: pluginsEnabled.checked; } Action { @@ -99,14 +100,14 @@ ApplicationWindow { } } Action { - shortcut: "Ctrl+R" + shortcut: StandardKey.Refresh onTriggered: { if (currentWebView) currentWebView.reload() } } Action { - shortcut: "Ctrl+T" + shortcut: StandardKey.AddTab onTriggered: { tabs.createEmptyTab(currentWebView.profile) tabs.currentIndex = tabs.count - 1 @@ -115,7 +116,7 @@ ApplicationWindow { } } Action { - shortcut: "Ctrl+W" + shortcut: StandardKey.Close onTriggered: { if (tabs.count == 1) browserWindow.close() @@ -135,14 +136,51 @@ ApplicationWindow { onTriggered: currentWebView.zoomFactor = 1.0; } Action { - shortcut: "Ctrl+-" + shortcut: StandardKey.ZoomOut onTriggered: currentWebView.zoomFactor -= 0.1; } Action { - shortcut: "Ctrl+=" + shortcut: StandardKey.ZoomIn onTriggered: currentWebView.zoomFactor += 0.1; } + Action { + shortcut: StandardKey.Copy + onTriggered: currentWebView.triggerWebAction(WebEngineView.Copy) + } + Action { + shortcut: StandardKey.Cut + onTriggered: currentWebView.triggerWebAction(WebEngineView.Cut) + } + Action { + shortcut: StandardKey.Paste + onTriggered: currentWebView.triggerWebAction(WebEngineView.Paste) + } + Action { + shortcut: "Shift+"+StandardKey.Paste + onTriggered: currentWebView.triggerWebAction(WebEngineView.PasteAndMatchStyle) + } + Action { + shortcut: StandardKey.SelectAll + onTriggered: currentWebView.triggerWebAction(WebEngineView.SelectAll) + } + Action { + shortcut: StandardKey.Undo + onTriggered: currentWebView.triggerWebAction(WebEngineView.Undo) + } + Action { + shortcut: StandardKey.Redo + onTriggered: currentWebView.triggerWebAction(WebEngineView.Redo) + } + Action { + shortcut: StandardKey.Back + onTriggered: currentWebView.triggerWebAction(WebEngineView.Back) + } + Action { + shortcut: StandardKey.Forward + onTriggered: currentWebView.triggerWebAction(WebEngineView.Forward) + } + toolBar: ToolBar { id: navigationBar RowLayout { @@ -230,6 +268,12 @@ ApplicationWindow { checked: WebEngine.settings.errorPageEnabled } MenuItem { + id: pluginsEnabled + text: "Plugins On" + checkable: true + checked: true + } + MenuItem { id: offTheRecordEnabled text: "Off The Record" checkable: true @@ -312,6 +356,7 @@ ApplicationWindow { settings.autoLoadImages: appSettings.autoLoadImages settings.javascriptEnabled: appSettings.javaScriptEnabled settings.errorPageEnabled: appSettings.errorPageEnabled + settings.pluginsEnabled: appSettings.pluginsEnabled onCertificateError: { error.defer() diff --git a/examples/webengine/quicknanobrowser/DownloadView.qml b/examples/webengine/quicknanobrowser/DownloadView.qml index 9a5cdd28f..c17a8bd60 100644 --- a/examples/webengine/quicknanobrowser/DownloadView.qml +++ b/examples/webengine/quicknanobrowser/DownloadView.qml @@ -41,7 +41,7 @@ import QtQuick 2.1 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.0 -import QtWebEngine 1.0 +import QtWebEngine 1.2 import QtQuick.Layouts 1.0 Rectangle { diff --git a/examples/webenginewidgets/browser/browserapplication.cpp b/examples/webenginewidgets/browser/browserapplication.cpp index ca28b2d0b..5fb8aad4c 100644 --- a/examples/webenginewidgets/browser/browserapplication.cpp +++ b/examples/webenginewidgets/browser/browserapplication.cpp @@ -283,14 +283,13 @@ void BrowserApplication::loadSettings() defaultSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, settings.value(QLatin1String("enableJavascript"), true).toBool()); defaultSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, settings.value(QLatin1String("enableScrollAnimator"), true).toBool()); -#if defined(QTWEBENGINE_PLUGINS) defaultSettings->setAttribute(QWebEngineSettings::PluginsEnabled, settings.value(QLatin1String("enablePlugins"), true).toBool()); -#endif QString css = settings.value(QLatin1String("userStyleSheet")).toString(); setUserStyleSheet(defaultProfile, css, mainWindow()); defaultProfile->setHttpUserAgent(settings.value(QLatin1String("httpUserAgent")).toString()); + defaultProfile->setHttpAcceptLanguage(settings.value(QLatin1String("httpAcceptLanguage")).toString()); settings.endGroup(); settings.beginGroup(QLatin1String("cookies")); diff --git a/examples/webenginewidgets/browser/settings.cpp b/examples/webenginewidgets/browser/settings.cpp index 7ed5f707b..ee8c719b4 100644 --- a/examples/webenginewidgets/browser/settings.cpp +++ b/examples/webenginewidgets/browser/settings.cpp @@ -50,6 +50,7 @@ #include "networkaccessmanager.h" #include "webview.h" +#include <QtCore/QLocale> #include <QtCore/QSettings> #include <QtWidgets/QtWidgets> #include <QtWebEngineWidgets/QtWebEngineWidgets> @@ -66,6 +67,21 @@ SettingsDialog::SettingsDialog(QWidget *parent) loadFromSettings(); } +static QString defaultAcceptLanguage() +{ + const QStringList langs = QLocale().uiLanguages(); + if (langs.isEmpty()) + return QString(); + QString str = langs.first(); + const float qstep = 1.0f / float(langs.count()); + float q = 1.0f - qstep; + for (int i = 1; i < langs.count(); ++i) { + str += QStringLiteral(", ") + langs.at(i) + QStringLiteral(";q=") + QString::number(q, 'f', 2); + q -= qstep; + } + return str; +} + void SettingsDialog::loadDefaults() { QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); @@ -82,15 +98,14 @@ void SettingsDialog::loadDefaults() downloadsLocation->setText(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); enableJavascript->setChecked(defaultSettings->testAttribute(QWebEngineSettings::JavascriptEnabled)); -#if defined(QTWEBENGINE_PLUGINS) enablePlugins->setChecked(defaultSettings->testAttribute(QWebEngineSettings::PluginsEnabled)); -#endif enableScrollAnimator->setChecked(defaultSettings->testAttribute(QWebEngineSettings::ScrollAnimatorEnabled)); persistentDataPath->setText(QWebEngineProfile::defaultProfile()->persistentStoragePath()); sessionCookiesCombo->setCurrentIndex(QWebEngineProfile::defaultProfile()->persistentCookiesPolicy()); httpUserAgent->setText(QWebEngineProfile::defaultProfile()->httpUserAgent()); + httpAcceptLanguage->setText(defaultAcceptLanguage()); } void SettingsDialog::loadFromSettings() @@ -140,6 +155,7 @@ void SettingsDialog::loadFromSettings() userStyleSheet->setPlainText(settings.value(QLatin1String("userStyleSheet")).toString()); enableScrollAnimator->setChecked(settings.value(QLatin1String("enableScrollAnimator"), enableScrollAnimator->isChecked()).toBool()); httpUserAgent->setText(settings.value(QLatin1String("httpUserAgent"), httpUserAgent->text()).toString()); + httpAcceptLanguage->setText(settings.value(QLatin1String("httpAcceptLanguage"), httpAcceptLanguage->text()).toString()); settings.endGroup(); // Privacy @@ -198,6 +214,7 @@ void SettingsDialog::saveToSettings() settings.setValue(QLatin1String("enableScrollAnimator"), enableScrollAnimator->isChecked()); settings.setValue(QLatin1String("userStyleSheet"), userStyleSheet->toPlainText()); settings.setValue(QLatin1String("httpUserAgent"), httpUserAgent->text()); + settings.setValue(QLatin1String("httpAcceptLanguage"), httpAcceptLanguage->text()); settings.endGroup(); //Privacy @@ -271,6 +288,16 @@ void SettingsDialog::chooseFixedFont() } } +void SettingsDialog::on_httpUserAgent_editingFinished() +{ + QWebEngineProfile::defaultProfile()->setHttpUserAgent(httpUserAgent->text()); +} + +void SettingsDialog::on_httpAcceptLanguage_editingFinished() +{ + QWebEngineProfile::defaultProfile()->setHttpAcceptLanguage(httpAcceptLanguage->text()); +} + void SettingsDialog::setHomeToCurrentPage() { BrowserMainWindow *mw = static_cast<BrowserMainWindow*>(parent()); diff --git a/examples/webenginewidgets/browser/settings.h b/examples/webenginewidgets/browser/settings.h index 6def66928..3a50dd29f 100644 --- a/examples/webenginewidgets/browser/settings.h +++ b/examples/webenginewidgets/browser/settings.h @@ -65,6 +65,9 @@ private slots: void chooseFont(); void chooseFixedFont(); + void on_httpUserAgent_editingFinished(); + void on_httpAcceptLanguage_editingFinished(); + private: QFont standardFont; QFont fixedFont; diff --git a/examples/webenginewidgets/browser/settings.ui b/examples/webenginewidgets/browser/settings.ui index 11bdee4d3..38a7af344 100644 --- a/examples/webenginewidgets/browser/settings.ui +++ b/examples/webenginewidgets/browser/settings.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>657</width> - <height>322</height> + <height>336</height> </rect> </property> <property name="windowTitle"> @@ -499,19 +499,29 @@ <string>Advanced</string> </attribute> <layout class="QGridLayout" name="gridLayout_2"> - <item row="2" column="1"> - <widget class="QTextEdit" name="userStyleSheet"/> + <item row="0" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>HTTP User-Agent:</string> + </property> + </widget> </item> <item row="0" column="1"> <widget class="QLineEdit" name="httpUserAgent"/> </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_15"> + <item row="1" column="0"> + <widget class="QLabel" name="label_16"> <property name="text"> - <string>HTTP User-Agent:</string> + <string>HTTP Accept-&Language:</string> + </property> + <property name="buddy"> + <cstring>httpAcceptLanguage</cstring> </property> </widget> </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="httpAcceptLanguage"/> + </item> <item row="2" column="0"> <widget class="QLabel" name="label_14"> <property name="text"> @@ -519,7 +529,10 @@ </property> </widget> </item> - <item row="4" column="1"> + <item row="2" column="1"> + <widget class="QTextEdit" name="userStyleSheet"/> + </item> + <item row="3" column="1"> <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/examples/webenginewidgets/browser/webview.cpp b/examples/webenginewidgets/browser/webview.cpp index 99986642e..7705e7ab4 100644 --- a/examples/webenginewidgets/browser/webview.cpp +++ b/examples/webenginewidgets/browser/webview.cpp @@ -72,7 +72,6 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent) : QWebEnginePage(profile, parent) , m_keyboardModifiers(Qt::NoModifier) , m_pressedButtons(Qt::NoButton) - , m_openInNewTab(false) { #if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) setNetworkAccessManager(BrowserApplication::networkAccessManager()); @@ -175,8 +174,7 @@ private: QWebEnginePage *WebPage::createWindow(QWebEnginePage::WebWindowType type) { - if (m_openInNewTab || type == QWebEnginePage::WebBrowserTab) { - m_openInNewTab = false; + if (type == QWebEnginePage::WebBrowserTab) { return mainWindow()->tabWidget()->newTab()->page(); } else if (type == QWebEnginePage::WebBrowserWindow) { BrowserApplication::instance()->newMainWindow(); @@ -304,6 +302,23 @@ void WebPage::proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator } } +void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int /*lineNumber*/, const QString& sourceID) +{ + QUrl url; + url.setUrl(sourceID); + switch (level) { + case InfoMessageLevel: + // Ignore these, they can still be found in the inspector. + break; + case WarningMessageLevel: + qInfo() << "JavaScript WARNING:" << url.host() << message; + break; + case ErrorMessageLevel: + qInfo() << "JavaScript ERROR:" << url.host() << message; + break; + } +} + WebView::WebView(QWidget* parent) : QWebEngineView(parent) , m_progress(0) @@ -338,24 +353,17 @@ void WebView::setPage(WebPage *_page) void WebView::contextMenuEvent(QContextMenuEvent *event) { -#if defined(QWEBENGINEPAGE_HITTESTCONTENT) - QWebEngineHitTestResult r = page()->hitTestContent(event->pos()); - if (!r.linkUrl().isEmpty()) { - QMenu menu(this); - menu.addAction(pageAction(QWebEnginePage::OpenLinkInNewWindow)); - menu.addAction(tr("Open in New Tab"), this, SLOT(openLinkInNewTab())); - menu.addSeparator(); - menu.addAction(pageAction(QWebEnginePage::DownloadLinkToDisk)); - // Add link to bookmarks... - menu.addSeparator(); - menu.addAction(pageAction(QWebEnginePage::CopyLinkToClipboard)); - if (page()->settings()->testAttribute(QWebEngineSettings::DeveloperExtrasEnabled)) - menu.addAction(pageAction(QWebEnginePage::InspectElement)); - menu.exec(mapToGlobal(event->pos())); - return; + QMenu *menu = page()->createStandardContextMenu(); + const QList<QAction*> actions = menu->actions(); + QList<QAction*>::const_iterator it = qFind(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::OpenLinkInThisWindow)); + if (it != actions.cend()) { + (*it)->setText(tr("Open Link in This Window")); + ++it; + menu->insertAction(*it, page()->action(QWebEnginePage::OpenLinkInNewWindow)); + menu->insertAction(*it, page()->action(QWebEnginePage::OpenLinkInNewTab)); } -#endif - QWebEngineView::contextMenuEvent(event); + + menu->popup(event->globalPos()); } void WebView::wheelEvent(QWheelEvent *event) @@ -374,10 +382,7 @@ void WebView::wheelEvent(QWheelEvent *event) void WebView::openLinkInNewTab() { -#if defined(QWEBENGINEPAGE_WEBACTION_OPENLINKINNEWWINDOW) - m_page->m_openInNewTab = true; - pageAction(QWebEnginePage::OpenLinkInNewWindow)->trigger(); -#endif + pageAction(QWebEnginePage::OpenLinkInNewTab)->trigger(); } void WebView::onFeaturePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature) diff --git a/examples/webenginewidgets/browser/webview.h b/examples/webenginewidgets/browser/webview.h index a147d780a..cb78fdd8a 100644 --- a/examples/webenginewidgets/browser/webview.h +++ b/examples/webenginewidgets/browser/webview.h @@ -71,6 +71,7 @@ protected: QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); #endif virtual bool certificateError(const QWebEngineCertificateError &error) Q_DECL_OVERRIDE; + virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; private slots: #if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) @@ -85,7 +86,6 @@ private: // set the webview mousepressedevent Qt::KeyboardModifiers m_keyboardModifiers; Qt::MouseButtons m_pressedButtons; - bool m_openInNewTab; QUrl m_loadingUrl; }; diff --git a/src/3rdparty b/src/3rdparty -Subproject 85827b2c3db3c4cb6308ce8a4c2069c0e403cd9 +Subproject 154d7a3611197845352b3e1d3ebeaf429d37e65 diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro new file mode 100644 index 000000000..d72b27229 --- /dev/null +++ b/src/core/api/core_api.pro @@ -0,0 +1,44 @@ +TARGET = qtwebenginecoreapi +DESTDIR = $$OUT_PWD/$$getConfigDir() + +TEMPLATE = lib + +CONFIG += staticlib c++11 +QT += network + +# Don't create .prl file for this intermediate library because +# their contents get used when linking against them, breaking +# "-Wl,-whole-archive -lqtwebenginecoreapi --Wl,-no-whole-archive" +CONFIG -= create_prl + +# Copy this logic from qt_module.prf so that the intermediate library can be +# created to the same rules as the final module linking in core_module.pro. +!host_build:if(win32|mac):!macx-xcode { + contains(QT_CONFIG, debug_and_release):CONFIG += debug_and_release + contains(QT_CONFIG, build_all):CONFIG += build_all +} + +DEFINES += \ + BUILDING_CHROMIUM \ + NOMINMAX + +CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() +INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core \ + $$CHROMIUM_SRC_DIR + +linux-g++*: QMAKE_CXXFLAGS += -Wno-unused-parameter + +HEADERS = \ + qwebenginecallback.h \ + qwebenginecallback_p.h \ + qtwebenginecoreglobal.h \ + qtwebenginecoreglobal_p.h \ + qwebenginecookiestoreclient.h \ + qwebenginecookiestoreclient_p.h \ + qwebengineurlrequestinterceptor.h \ + qwebengineurlrequestinfo.h \ + qwebengineurlrequestinfo_p.h + +SOURCES = \ + qwebenginecookiestoreclient.cpp \ + qwebengineurlrequestinfo.cpp diff --git a/src/core/api/qtwebenginecoreglobal.h b/src/core/api/qtwebenginecoreglobal.h new file mode 100644 index 000000000..16daaab7d --- /dev/null +++ b/src/core/api/qtwebenginecoreglobal.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QTWEBENGINECOREGLOBAL_H +#define QTWEBENGINECOREGLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(BUILDING_CHROMIUM) +# define QWEBENGINE_EXPORT Q_DECL_EXPORT +#else +# define QWEBENGINE_EXPORT Q_DECL_IMPORT +#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/qtwebenginecoreglobal.h b/src/core/api/qtwebenginecoreglobal_p.h index d09497ce8..e93ca9c2c 100644 --- a/src/core/qtwebenginecoreglobal.h +++ b/src/core/api/qtwebenginecoreglobal_p.h @@ -34,10 +34,21 @@ ** ****************************************************************************/ -#ifndef QTWEBENGINECOREGLOBAL_H -#define QTWEBENGINECOREGLOBAL_H +#ifndef QTWEBENGINECOREGLOBAL_P_H +#define QTWEBENGINECOREGLOBAL_P_H -#include <QtCore/qglobal.h> +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtwebenginecoreglobal.h" #ifdef QT_WEBENGINE_LOGGING #define QT_NOT_YET_IMPLEMENTED fprintf(stderr, "function %s not implemented! - %s:%d\n", __func__, __FILE__, __LINE__); @@ -47,16 +58,6 @@ #define QT_NOT_USED Q_UNREACHABLE(); // This will assert in debug. #endif -#ifndef QT_STATIC -# if defined(BUILDING_CHROMIUM) -# define QWEBENGINE_EXPORT Q_DECL_EXPORT -# else -# define QWEBENGINE_EXPORT Q_DECL_IMPORT -# endif -#else -# 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"); +#define QWEBENGINE_PRIVATE_EXPORT QWEBENGINE_EXPORT -#endif // QTWEBENGINECOREGLOBAL_H +#endif // QTWEBENGINECOREGLOBAL_P_H diff --git a/src/core/api/qwebenginecallback.h b/src/core/api/qwebenginecallback.h new file mode 100644 index 000000000..ddee20d06 --- /dev/null +++ b/src/core/api/qwebenginecallback.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENGINECALLBACK_H +#define QWEBENGINECALLBACK_H + +#include "qtwebenginecoreglobal.h" + +#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE +#include <QtCore/qshareddata.h> +#include <QtCore/qstring.h> +#include <QtCore/qvariant.h> + +namespace QtWebEngineCore { +class CallbackDirectory; +} + +QT_BEGIN_NAMESPACE + +namespace QtWebEnginePrivate { + +template <typename T> +class QWebEngineCallbackPrivateBase : public QSharedData { +public: + QWebEngineCallbackPrivateBase() {} + virtual ~QWebEngineCallbackPrivateBase() {} + virtual void operator()(T) = 0; +}; + +template <typename T, typename F> +class QWebEngineCallbackPrivate : public QWebEngineCallbackPrivateBase<T> { +public: + QWebEngineCallbackPrivate(F callable) + : m_callable(callable) + {} + virtual void operator()(T value) Q_DECL_OVERRIDE { m_callable(value); } +private: + F m_callable; +}; + +} // namespace QtWebEnginePrivate + +template <typename T> +class QWebEngineCallback { +public: + template <typename F> + QWebEngineCallback(F f) + : d(new QtWebEnginePrivate::QWebEngineCallbackPrivate<T, F>(f)) + { } + QWebEngineCallback() { } + operator bool() const { return d; } +private: + friend class QtWebEngineCore::CallbackDirectory; + QExplicitlySharedDataPointer<QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> > d; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINECALLBACK_H diff --git a/src/core/api/qwebenginecallback_p.h b/src/core/api/qwebenginecallback_p.h new file mode 100644 index 000000000..44d9ceb14 --- /dev/null +++ b/src/core/api/qwebenginecallback_p.h @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENGINECALLBACK_P_H +#define QWEBENGINECALLBACK_P_H + +#include "qtwebenginecoreglobal_p.h" +#include "qwebenginecallback.h" + +#include <QByteArray> +#include <QHash> +#include <QSharedData> +#include <QString> +#include <QVariant> +#include <type_traits> + +#define FOR_EACH_TYPE(F) \ + F(bool) \ + F(int) \ + F(const QString &) \ + F(const QByteArray &) \ + F(const QVariant &) + +namespace QtWebEngineCore { + +class CallbackDirectory { + template<typename T> + void invokeInternal(quint64 callbackId, T result); + template<typename T> + void invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *callback); + +public: + ~CallbackDirectory() + { + // "Cancel" pending callbacks by calling them with an invalid value. + // This guarantees that each callback is called exactly once. + for (CallbackSharedDataPointerBase * const sharedPtrBase: m_callbackMap) { + Q_ASSERT(sharedPtrBase); + sharedPtrBase->invokeEmpty(); + delete sharedPtrBase; + } + } + + enum ReservedCallbackIds { + NoCallbackId = 0, + DeleteCookieCallbackId, + DeleteSessionCookiesCallbackId, + DeleteAllCookiesCallbackId, + GetAllCookiesCallbackId, + + // Place reserved id's before this. + ReservedCallbackIdsEnd + }; + + template<typename T> + void registerCallback(quint64 callbackId, const QWebEngineCallback<T> &callback); + + template<typename T> + void invokeEmpty(const QWebEngineCallback<T> &callback); + +#define DEFINE_INVOKE_FOR_TYPE(Type) \ + void invoke(quint64 callbackId, Type result) { \ + invokeInternal<Type>(callbackId, std::forward<Type>(result)); \ + } + FOR_EACH_TYPE(DEFINE_INVOKE_FOR_TYPE) +#undef DEFINE_INVOKE_FOR_TYPE + +private: + struct CallbackSharedDataPointerBase { + virtual ~CallbackSharedDataPointerBase() { } + virtual void invokeEmpty() = 0; + virtual void doRef() = 0; + virtual void doDeref() = 0; + virtual operator bool () const = 0; + }; + + template <typename T> + struct CallbackSharedDataPointer : public CallbackSharedDataPointerBase { + CallbackDirectory* parent; + QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *callback; + + ~CallbackSharedDataPointer() { doDeref(); } + CallbackSharedDataPointer() : parent(0), callback(0) { } + CallbackSharedDataPointer(const CallbackSharedDataPointer<T> &other) + : parent(other.parent), callback(other.callback) { doRef(); } + CallbackSharedDataPointer(CallbackDirectory *p, QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *c) + : parent(p), callback(c) { Q_ASSERT(callback); doRef(); } + + void invokeEmpty() override; + operator bool () const override { return callback; } + + private: + void doRef() override; + void doDeref() override; + }; + + QHash<quint64, CallbackSharedDataPointerBase*> m_callbackMap; +}; + +template<typename T> +inline +void CallbackDirectory::registerCallback(quint64 callbackId, const QWebEngineCallback<T> &callback) +{ + if (!callback.d) + return; + m_callbackMap.insert(callbackId, new CallbackSharedDataPointer<T>(this, callback.d.data())); +} + +template<typename T> +inline +void CallbackDirectory::invokeInternal(quint64 callbackId, T result) +{ + CallbackSharedDataPointerBase * const sharedPtrBase = m_callbackMap.take(callbackId); + if (!sharedPtrBase) + return; + + auto ptr = static_cast<CallbackSharedDataPointer<T> *>(sharedPtrBase); + Q_ASSERT(ptr); + (*ptr->callback)(std::forward<T>(result)); + delete ptr; +} + +template<typename T> +inline +void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> *callback) +{ + Q_ASSERT(callback); + using NoRefT = typename std::remove_reference<T>::type; + using NoConstNoRefT = typename std::remove_const<NoRefT>::type; + NoConstNoRefT t; + (*callback)(t); +} + +template<> +inline +void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<bool> *callback) +{ + Q_ASSERT(callback); + (*callback)(false); +} + +template<> +inline +void CallbackDirectory::invokeEmptyInternal(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<int> *callback) +{ + Q_ASSERT(callback); + (*callback)(0); +} + +template<typename T> +inline +void CallbackDirectory::invokeEmpty(const QWebEngineCallback<T> &callback) +{ + if (!callback.d) + return; + + invokeEmptyInternal(callback.d.data()); +} + +template <typename T> +inline +void CallbackDirectory::CallbackSharedDataPointer<T>::doRef() +{ + if (!callback) + return; + + callback->ref.ref(); +} + +template <typename T> +inline +void CallbackDirectory::CallbackSharedDataPointer<T>::doDeref() +{ + if (!callback) + return; + if (!callback->ref.deref()) + delete callback; +} + +template <typename T> +inline +void CallbackDirectory::CallbackSharedDataPointer<T>::invokeEmpty() +{ + if (!callback) + return; + + Q_ASSERT(parent); + parent->invokeEmptyInternal(callback); +} + +} // namespace QtWebEngineCore + +#endif // QWEBENGINECALLBACK_P_H diff --git a/src/core/api/qwebenginecookiestoreclient.cpp b/src/core/api/qwebenginecookiestoreclient.cpp new file mode 100644 index 000000000..f4770927e --- /dev/null +++ b/src/core/api/qwebenginecookiestoreclient.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "qwebenginecookiestoreclient.h" +#include "qwebenginecookiestoreclient_p.h" + +#include <QByteArray> +#include <QUrl> + +QT_BEGIN_NAMESPACE + +using namespace QtWebEngineCore; + +QWebEngineCookieStoreClientPrivate::QWebEngineCookieStoreClientPrivate(QWebEngineCookieStoreClient* q) + : m_nextCallbackId(CallbackDirectory::ReservedCallbackIdsEnd) + , m_deleteSessionCookiesPending(false) + , m_deleteAllCookiesPending(false) + , m_getAllCookiesPending(false) + , delegate(0) + , q_ptr(q) +{ +} + +QWebEngineCookieStoreClientPrivate::~QWebEngineCookieStoreClientPrivate() +{ + +} + +void QWebEngineCookieStoreClientPrivate::processPendingUserCookies() +{ + Q_ASSERT(delegate); + Q_ASSERT(delegate->hasCookieMonster()); + + if (m_getAllCookiesPending) { + m_getAllCookiesPending = false; + delegate->getAllCookies(CallbackDirectory::GetAllCookiesCallbackId); + } + + if (m_deleteAllCookiesPending) { + m_deleteAllCookiesPending = false; + delegate->deleteAllCookies(CallbackDirectory::DeleteAllCookiesCallbackId); + } + + if (m_deleteSessionCookiesPending) { + m_deleteSessionCookiesPending = false; + delegate->deleteSessionCookies(CallbackDirectory::DeleteSessionCookiesCallbackId); + } + + if (m_pendingUserCookies.isEmpty()) + return; + + Q_FOREACH (const auto &cookieData, m_pendingUserCookies) { + if (cookieData.callbackId == CallbackDirectory::DeleteCookieCallbackId) + delegate->deleteCookie(cookieData.cookie, cookieData.origin); + else + delegate->setCookie(cookieData.callbackId, cookieData.cookie, cookieData.origin); + } + + m_pendingUserCookies.clear(); +} + +void QWebEngineCookieStoreClientPrivate::setCookie(const QWebEngineCallback<bool> &callback, const QNetworkCookie &cookie, const QUrl &origin) +{ + const quint64 currentCallbackId = callback ? m_nextCallbackId++ : static_cast<quint64>(CallbackDirectory::NoCallbackId); + + if (currentCallbackId != CallbackDirectory::NoCallbackId) + callbackDirectory.registerCallback(currentCallbackId, callback); + + if (!delegate || !delegate->hasCookieMonster()) { + m_pendingUserCookies.append(CookieData{ currentCallbackId, cookie, origin }); + return; + } + + delegate->setCookie(currentCallbackId, cookie, origin); +} + +void QWebEngineCookieStoreClientPrivate::deleteCookie(const QNetworkCookie &cookie, const QUrl &url) +{ + if (!delegate || !delegate->hasCookieMonster()) { + m_pendingUserCookies.append(CookieData{ CallbackDirectory::DeleteCookieCallbackId, cookie, url }); + return; + } + + delegate->deleteCookie(cookie, url); +} + +void QWebEngineCookieStoreClientPrivate::deleteSessionCookies() +{ + if (!delegate || !delegate->hasCookieMonster()) { + m_deleteSessionCookiesPending = true; + return; + } + + delegate->deleteSessionCookies(CallbackDirectory::DeleteSessionCookiesCallbackId); +} + +void QWebEngineCookieStoreClientPrivate::deleteAllCookies() +{ + if (!delegate || !delegate->hasCookieMonster()) { + m_deleteAllCookiesPending = true; + m_deleteSessionCookiesPending = false; + return; + } + + delegate->deleteAllCookies(CallbackDirectory::DeleteAllCookiesCallbackId); +} + +void QWebEngineCookieStoreClientPrivate::getAllCookies() +{ + if (!delegate || !delegate->hasCookieMonster()) { + m_getAllCookiesPending = true; + return; + } + + delegate->getAllCookies(CallbackDirectory::GetAllCookiesCallbackId); +} + +void QWebEngineCookieStoreClientPrivate::onGetAllCallbackResult(qint64 callbackId, const QByteArray &cookieList) +{ + callbackDirectory.invoke(callbackId, cookieList); +} +void QWebEngineCookieStoreClientPrivate::onSetCallbackResult(qint64 callbackId, bool success) +{ + callbackDirectory.invoke(callbackId, success); +} + +void QWebEngineCookieStoreClientPrivate::onDeleteCallbackResult(qint64 callbackId, int numCookies) +{ + callbackDirectory.invoke(callbackId, numCookies); +} + +void QWebEngineCookieStoreClientPrivate::onCookieChanged(const QNetworkCookie &cookie, bool removed) +{ + Q_Q(QWebEngineCookieStoreClient); + if (removed) + Q_EMIT q->cookieRemoved(cookie); + else + Q_EMIT q->cookieAdded(cookie); +} + +QWebEngineCookieStoreClient::QWebEngineCookieStoreClient(QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineCookieStoreClientPrivate(this)) +{ + +} + +QWebEngineCookieStoreClient::~QWebEngineCookieStoreClient() +{ + +} + +void QWebEngineCookieStoreClient::setCookieWithCallback(const QNetworkCookie &cookie, const QWebEngineCallback<bool> &resultCallback, const QUrl &origin) +{ + Q_D(QWebEngineCookieStoreClient); + d->setCookie(resultCallback, cookie, origin); +} + +void QWebEngineCookieStoreClient::setCookie(const QNetworkCookie &cookie, const QUrl &origin) +{ + setCookieWithCallback(cookie, QWebEngineCallback<bool>(), origin); +} + +void QWebEngineCookieStoreClient::deleteCookie(const QNetworkCookie &cookie, const QUrl &origin) +{ + Q_D(QWebEngineCookieStoreClient); + d->deleteCookie(cookie, origin); +} + +void QWebEngineCookieStoreClient::getAllCookies(const QWebEngineCallback<const QByteArray&> &resultCallback) +{ + Q_D(QWebEngineCookieStoreClient); + if (d->m_getAllCookiesPending) { + d->callbackDirectory.invokeEmpty(resultCallback); + return; + } + d->callbackDirectory.registerCallback(CallbackDirectory::GetAllCookiesCallbackId, resultCallback); + d->getAllCookies(); +} + +void QWebEngineCookieStoreClient::deleteSessionCookiesWithCallback(const QWebEngineCallback<int> &resultCallback) +{ + Q_D(QWebEngineCookieStoreClient); + if (d->m_deleteAllCookiesPending || d->m_deleteSessionCookiesPending) { + d->callbackDirectory.invokeEmpty(resultCallback); + return; + } + d->callbackDirectory.registerCallback(CallbackDirectory::DeleteSessionCookiesCallbackId, resultCallback); + d->deleteSessionCookies(); +} + +void QWebEngineCookieStoreClient::deleteAllCookiesWithCallback(const QWebEngineCallback<int> &resultCallback) +{ + Q_D(QWebEngineCookieStoreClient); + if (d->m_deleteAllCookiesPending) { + d->callbackDirectory.invokeEmpty(resultCallback); + return; + } + d->callbackDirectory.registerCallback(CallbackDirectory::DeleteAllCookiesCallbackId, resultCallback); + d->deleteAllCookies(); +} + +void QWebEngineCookieStoreClient::deleteSessionCookies() +{ + deleteSessionCookiesWithCallback(QWebEngineCallback<int>()); +} + +void QWebEngineCookieStoreClient::deleteAllCookies() +{ + deleteAllCookiesWithCallback(QWebEngineCallback<int>()); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginecookiestoreclient.h b/src/core/api/qwebenginecookiestoreclient.h new file mode 100644 index 000000000..929584c86 --- /dev/null +++ b/src/core/api/qwebenginecookiestoreclient.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENGINECOOKIESTORECLIENT_H +#define QWEBENGINECOOKIESTORECLIENT_H + +#include "qtwebenginecoreglobal.h" +#include "qwebenginecallback.h" + +#include <QtCore/qobject.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qurl.h> +#include <QtNetwork/qnetworkcookie.h> + +namespace QtWebEngineCore { +class CookieMonsterDelegateQt; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineCookieStoreClientPrivate; +class QWEBENGINE_EXPORT QWebEngineCookieStoreClient : public QObject { + Q_OBJECT +public: + explicit QWebEngineCookieStoreClient(QObject *parent = 0); + virtual ~QWebEngineCookieStoreClient(); + +#ifdef Q_QDOC + void setCookieWithCallback(const QNetworkCookie &cookie, FunctorOrLambda resultCallback, const QUrl &origin = QUrl()); + void deleteSessionCookiesWithCallback(FunctorOrLambda resultCallback); + void deleteAllCookiesWithCallback(FunctorOrLambda resultCallback); + void getAllCookies(FunctorOrLambda resultCallback); +#else + void setCookieWithCallback(const QNetworkCookie &cookie, const QWebEngineCallback<bool> &resultCallback, const QUrl &origin = QUrl()); + void deleteSessionCookiesWithCallback(const QWebEngineCallback<int> &resultCallback); + void deleteAllCookiesWithCallback(const QWebEngineCallback<int> &resultCallback); + void getAllCookies(const QWebEngineCallback<const QByteArray&> &resultCallback); +#endif + void setCookie(const QNetworkCookie &cookie, const QUrl &origin = QUrl()); + void deleteCookie(const QNetworkCookie &cookie, const QUrl &origin = QUrl()); + void deleteSessionCookies(); + void deleteAllCookies(); + +Q_SIGNALS: + void cookieAdded(const QNetworkCookie &cookie); + void cookieRemoved(const QNetworkCookie &cookie); + +private: + friend class QtWebEngineCore::CookieMonsterDelegateQt; + + Q_DECLARE_PRIVATE(QWebEngineCookieStoreClient) + QScopedPointer<QWebEngineCookieStoreClientPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINECOOKIESTORECLIENT_H diff --git a/src/core/api/qwebenginecookiestoreclient_p.h b/src/core/api/qwebenginecookiestoreclient_p.h new file mode 100644 index 000000000..ba7914d94 --- /dev/null +++ b/src/core/api/qwebenginecookiestoreclient_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENGINECOOKIESTORECLIENT_P_H +#define QWEBENGINECOOKIESTORECLIENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtwebenginecoreglobal_p.h" + +#include "cookie_monster_delegate_qt.h" +#include "qwebenginecallback_p.h" +#include "qwebenginecookiestoreclient.h" + +#include <QList> +#include <QMap> +#include <QNetworkCookie> +#include <QUrl> + +QT_BEGIN_NAMESPACE + +class QWEBENGINE_PRIVATE_EXPORT QWebEngineCookieStoreClientPrivate { + struct CookieData { + quint64 callbackId; + QNetworkCookie cookie; + QUrl origin; + }; + +public: + Q_DECLARE_PUBLIC(QWebEngineCookieStoreClient) + QtWebEngineCore::CallbackDirectory callbackDirectory; + QList<CookieData> m_pendingUserCookies; + quint64 m_nextCallbackId; + bool m_deleteSessionCookiesPending; + bool m_deleteAllCookiesPending; + bool m_getAllCookiesPending; + + QtWebEngineCore::CookieMonsterDelegateQt *delegate; + QWebEngineCookieStoreClient *q_ptr; + + QWebEngineCookieStoreClientPrivate(QWebEngineCookieStoreClient *q); + ~QWebEngineCookieStoreClientPrivate(); + + void processPendingUserCookies(); + void setCookie(const QWebEngineCallback<bool> &callback, const QNetworkCookie &cookie, const QUrl &origin); + void deleteCookie(const QNetworkCookie &cookie, const QUrl &url); + void deleteSessionCookies(); + void deleteAllCookies(); + void getAllCookies(); + + void onGetAllCallbackResult(qint64 callbackId, const QByteArray &cookieList); + void onSetCallbackResult(qint64 callbackId, bool success); + void onDeleteCallbackResult(qint64 callbackId, int numCookies); + void onCookieChanged(const QNetworkCookie &cookie, bool removed); +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINECOOKIESTORECLIENT_P_H diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp new file mode 100644 index 000000000..e97b0c7b9 --- /dev/null +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "qwebengineurlrequestinfo.h" +#include "qwebengineurlrequestinfo_p.h" + +#include "content/public/common/resource_type.h" + +#include "web_contents_adapter_client.h" + +QT_BEGIN_NAMESPACE + +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMainFrame, content::RESOURCE_TYPE_MAIN_FRAME) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSubFrame, content::RESOURCE_TYPE_SUB_FRAME) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeStylesheet, content::RESOURCE_TYPE_STYLESHEET) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeScript, content::RESOURCE_TYPE_SCRIPT) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeImage, content::RESOURCE_TYPE_IMAGE) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFontResource, content::RESOURCE_TYPE_FONT_RESOURCE) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSubResource, content::RESOURCE_TYPE_SUB_RESOURCE) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeObject, content::RESOURCE_TYPE_OBJECT) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMedia, content::RESOURCE_TYPE_MEDIA) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeWorker, content::RESOURCE_TYPE_WORKER) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSharedWorker, content::RESOURCE_TYPE_SHARED_WORKER) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePrefetch, content::RESOURCE_TYPE_PREFETCH) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFavicon, content::RESOURCE_TYPE_FAVICON) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeXhr, content::RESOURCE_TYPE_XHR) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePing, content::RESOURCE_TYPE_PING) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker, content::RESOURCE_TYPE_SERVICE_WORKER) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeUnknown, content::RESOURCE_TYPE_LAST_TYPE) + +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::LinkNavigation, QWebEngineUrlRequestInfo::NavigationTypeLink) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::TypedNavigation, QWebEngineUrlRequestInfo::NavigationTypeTyped) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::FormSubmittedNavigation, QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::BackForwardNavigation, QWebEngineUrlRequestInfo::NavigationTypeBackForward) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::ReloadNavigation, QWebEngineUrlRequestInfo::NavigationTypeReload) +ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, QWebEngineUrlRequestInfo::NavigationTypeOther) + +QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource, QWebEngineUrlRequestInfo::NavigationType navigation, const QUrl &u, const QByteArray &m) + : resourceType(resource) + , navigationType(navigation) + , shouldBlockRequest(false) + , url(u) + , method(m) +{ +} + +QWebEngineUrlRequestInfo::~QWebEngineUrlRequestInfo() +{ + +} + +QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p) + : d_ptr(p) +{ + d_ptr->q_ptr = this; +} + +QWebEngineUrlRequestInfo::ResourceType QWebEngineUrlRequestInfo::resourceType() const +{ + Q_D(const QWebEngineUrlRequestInfo); + return d->resourceType; +} + +QWebEngineUrlRequestInfo::NavigationType QWebEngineUrlRequestInfo::navigationType() const +{ + Q_D(const QWebEngineUrlRequestInfo); + return d->navigationType; +} + +const QUrl &QWebEngineUrlRequestInfo::url() const +{ + Q_D(const QWebEngineUrlRequestInfo); + return d->url; +} + +const QByteArray &QWebEngineUrlRequestInfo::method() const +{ + Q_D(const QWebEngineUrlRequestInfo); + return d->method; +} + +void QWebEngineUrlRequestInfo::redirectTo(const QUrl &url) +{ + Q_D(QWebEngineUrlRequestInfo); + d->url = url; +} + +void QWebEngineUrlRequestInfo::blockRequest(bool shouldBlock) +{ + Q_D(QWebEngineUrlRequestInfo); + d->shouldBlockRequest = shouldBlock; +} + +void QWebEngineUrlRequestInfo::setExtraHeader(const QByteArray &name, const QByteArray &value) +{ + Q_D(QWebEngineUrlRequestInfo); + d->extraHeaders.insert(name, value); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h new file mode 100644 index 000000000..dd1e57ebd --- /dev/null +++ b/src/core/api/qwebengineurlrequestinfo.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENGINEURLREQUESTINFO_H +#define QWEBENGINEURLREQUESTINFO_H + +#include "qtwebenginecoreglobal.h" + +#include <QtCore/qscopedpointer.h> +#include <QtCore/qurl.h> + +namespace QtWebEngineCore { +class NetworkDelegateQt; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineUrlRequestInfoPrivate; + +class QWEBENGINE_EXPORT QWebEngineUrlRequestInfo { +public: + enum ResourceType { + ResourceTypeMainFrame = 0, // top level page + ResourceTypeSubFrame, // frame or iframe + ResourceTypeStylesheet, // a CSS stylesheet + ResourceTypeScript, // an external script + ResourceTypeImage, // an image (jpg/gif/png/etc) + ResourceTypeFontResource, // a font + ResourceTypeSubResource, // an "other" subresource. + ResourceTypeObject, // an object (or embed) tag for a plugin, + // or a resource that a plugin requested. + ResourceTypeMedia, // a media resource. + ResourceTypeWorker, // the main resource of a dedicated worker. + ResourceTypeSharedWorker, // the main resource of a shared worker. + ResourceTypePrefetch, // an explicitly requested prefetch + ResourceTypeFavicon, // a favicon + ResourceTypeXhr, // a XMLHttpRequest + ResourceTypePing, // a ping request for <a ping> + ResourceTypeServiceWorker, // the main resource of a service worker. + ResourceTypeUnknown + }; + + enum NavigationType { + NavigationTypeLink, + NavigationTypeTyped, + NavigationTypeFormSubmitted, + NavigationTypeBackForward, + NavigationTypeReload, + NavigationTypeOther + }; + + ResourceType resourceType() const; + NavigationType navigationType() const; + + const QUrl &url() const; + const QByteArray &method() const; + + void blockRequest(bool shouldBlock); + void redirectTo(const QUrl &url); + void setExtraHeader(const QByteArray &name, const QByteArray &value); + +private: + friend class QtWebEngineCore::NetworkDelegateQt; + Q_DISABLE_COPY(QWebEngineUrlRequestInfo) + Q_DECLARE_PRIVATE(QWebEngineUrlRequestInfo) + + QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p); + ~QWebEngineUrlRequestInfo(); + QScopedPointer<QWebEngineUrlRequestInfoPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEURLREQUESTINFO_H diff --git a/src/core/api/qwebengineurlrequestinfo_p.h b/src/core/api/qwebengineurlrequestinfo_p.h new file mode 100644 index 000000000..b6a304a03 --- /dev/null +++ b/src/core/api/qwebengineurlrequestinfo_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENGINEURLREQUESTINFO_P_H +#define QWEBENGINEURLREQUESTINFO_P_H + +#include "qtwebenginecoreglobal_p.h" + +#include "qwebengineurlrequestinfo.h" + +#include <QByteArray> +#include <QHash> +#include <QUrl> + +namespace net { +class URLRequest; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineUrlRequestInfoPrivate +{ + Q_DECLARE_PUBLIC(QWebEngineUrlRequestInfo) +public: + QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource + , QWebEngineUrlRequestInfo::NavigationType navigation + , const QUrl &u + , const QByteArray &m); + + QWebEngineUrlRequestInfo::ResourceType resourceType; + QWebEngineUrlRequestInfo::NavigationType navigationType; + bool shouldBlockRequest; + + QUrl url; + const QByteArray method; + QHash<QByteArray, QByteArray> extraHeaders; + + QWebEngineUrlRequestInfo *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEURLREQUESTINFO_P_H diff --git a/src/core/api/qwebengineurlrequestinterceptor.h b/src/core/api/qwebengineurlrequestinterceptor.h new file mode 100644 index 000000000..3eac74bb6 --- /dev/null +++ b/src/core/api/qwebengineurlrequestinterceptor.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QWEBENINGEURLREQUESTINTERCEPTOR_H +#define QWEBENINGEURLREQUESTINTERCEPTOR_H + +#include "qtwebenginecoreglobal.h" +#include "qwebengineurlrequestinfo.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qhash.h> +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + +class QWEBENGINE_EXPORT QWebEngineUrlRequestInterceptor : public QObject +{ + Q_OBJECT +public: + explicit QWebEngineUrlRequestInterceptor(QObject *p = 0) + : QObject (p) + { + } + virtual ~QWebEngineUrlRequestInterceptor() + { + } + + virtual bool interceptRequest(QWebEngineUrlRequestInfo &info) = 0; +}; + +QT_END_NAMESPACE + +#endif // QWEBENINGEURLREQUESTINTERCEPTOR_H diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index 7cd5ac21f..9d4fdfe00 100644 --- a/src/core/browser_accessibility_qt.cpp +++ b/src/core/browser_accessibility_qt.cpp @@ -46,7 +46,7 @@ #include "ui/accessibility/ax_node_data.h" #include "browser_accessibility_manager_qt.h" -#include "qtwebenginecoreglobal.h" +#include "qtwebenginecoreglobal_p.h" #include "type_conversion.h" using namespace blink; @@ -59,82 +59,6 @@ BrowserAccessibilityQt::BrowserAccessibilityQt() QAccessible::registerAccessibleInterface(this); } -// This function is taken from chromium/content/browser/accessibility/browser_accessibility_win.cc -// see also http://www.w3.org/TR/html-aapi -void BrowserAccessibilityQt::OnDataChanged() -{ - BrowserAccessibility::OnDataChanged(); - - // The calculation of the accessible name of an element has been - // standardized in the HTML to Platform Accessibility APIs Implementation - // Guide (http://www.w3.org/TR/html-aapi/). In order to return the - // appropriate accessible name on Windows, we need to apply some logic - // to the fields we get from WebKit. - // - // TODO(dmazzoni): move most of this logic into WebKit. - // - // WebKit gives us: - // - // name: the default name, e.g. inner text - // title ui element: a reference to a <label> element on the same - // page that labels this node. - // description: accessible labels that override the default name: - // aria-label or aria-labelledby or aria-describedby - // help: the value of the "title" attribute - // - // On Windows, the logic we apply lets some fields take precedence and - // always returns the primary name in "name" and the secondary name, - // if any, in "description". - - int title_elem_id = GetIntAttribute( - ui::AX_ATTR_TITLE_UI_ELEMENT); - std::string help = GetStringAttribute(ui::AX_ATTR_HELP); - std::string description = GetStringAttribute( - ui::AX_ATTR_DESCRIPTION); - - // WebKit annoyingly puts the title in the description if there's no other - // description, which just confuses the rest of the logic. Put it back. - // Now "help" is always the value of the "title" attribute, if present. - std::string title_attr; - if (GetHtmlAttribute("title", &title_attr) && - description == title_attr && - help.empty()) { - help = description; - description.clear(); - } - - // Now implement the main logic: the descripion should become the name if - // it's nonempty, and the help should become the description if - // there's no description - or the name if there's no name or description. - if (!description.empty()) { - set_name(description); - description.clear(); - } - if (!help.empty() && description.empty()) { - description = help; - help.clear(); - } - if (!description.empty() && name().empty() && !title_elem_id) { - set_name(description); - description.clear(); - } - - // If it's a text field, also consider the placeholder. - std::string placeholder; - if (GetRole() == ui::AX_ROLE_TEXT_FIELD && - HasState(ui::AX_STATE_FOCUSABLE) && - GetHtmlAttribute("placeholder", &placeholder)) { - if (name().empty() && !title_elem_id) { - set_name(placeholder); - } else if (description.empty()) { - description = placeholder; - } - } - - SetStringAttribute(ui::AX_ATTR_DESCRIPTION, description); - SetStringAttribute(ui::AX_ATTR_HELP, help); -} - bool BrowserAccessibilityQt::isValid() const { return true; @@ -227,7 +151,7 @@ QString BrowserAccessibilityQt::text(QAccessible::Text t) const { switch (t) { case QAccessible::Name: - return toQt(name()); + return toQt(GetStringAttribute(ui::AX_ATTR_NAME)); case QAccessible::Description: return toQt(GetStringAttribute(ui::AX_ATTR_DESCRIPTION)); case QAccessible::Help: @@ -277,10 +201,10 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::Document; // returning Application here makes Qt return the top level app object case ui::AX_ROLE_ARTICLE: return QAccessible::Section; - case ui::AX_ROLE_BROWSER: - return QAccessible::Document; // FIXME case ui::AX_ROLE_BANNER: return QAccessible::Section; + case ui::AX_ROLE_BLOCKQUOTE: + return QAccessible::Section; case ui::AX_ROLE_BUSY_INDICATOR: return QAccessible::Animation; // FIXME case ui::AX_ROLE_BUTTON: @@ -325,10 +249,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::Section; case ui::AX_ROLE_DOCUMENT: return QAccessible::Document; - case ui::AX_ROLE_DRAWER: - return QAccessible::Client; // FIXME - case ui::AX_ROLE_EDITABLE_TEXT: - return QAccessible::EditableText; case ui::AX_ROLE_EMBEDDED_OBJECT: return QAccessible::Grouping; // FIXME case ui::AX_ROLE_FOOTER: @@ -339,14 +259,8 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::Table; case ui::AX_ROLE_GROUP: return QAccessible::Grouping; - case ui::AX_ROLE_GROW_AREA: - return QAccessible::Grip; case ui::AX_ROLE_HEADING: return QAccessible::Heading; - case ui::AX_ROLE_HELP_TAG: - return QAccessible::HelpBalloon; // FIXME - case ui::AX_ROLE_HORIZONTAL_RULE: - return QAccessible::Separator; case ui::AX_ROLE_IFRAME: return QAccessible::Grouping; case ui::AX_ROLE_IGNORED: @@ -357,8 +271,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::Graphic; case ui::AX_ROLE_IMAGE_MAP_LINK: return QAccessible::Link; - case ui::AX_ROLE_INCREMENTOR: - return QAccessible::NoRole; // FIXME case ui::AX_ROLE_INLINE_TEXT_BOX: return QAccessible::EditableText; case ui::AX_ROLE_LABEL_TEXT: @@ -387,8 +299,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::NoRole; // FIXME case ui::AX_ROLE_MATH: return QAccessible::Equation; - case ui::AX_ROLE_MATTE: - return QAccessible::NoRole; // FIXME case ui::AX_ROLE_MENU: return QAccessible::PopupMenu; case ui::AX_ROLE_MENU_BAR: @@ -413,6 +323,8 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::Paragraph; case ui::AX_ROLE_POP_UP_BUTTON: return QAccessible::ComboBox; + case ui::AX_ROLE_PRE: + return QAccessible::Section; case ui::AX_ROLE_PRESENTATIONAL: return QAccessible::NoRole; // FIXME case ui::AX_ROLE_PROGRESS_INDICATOR: @@ -429,8 +341,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::RowHeader; case ui::AX_ROLE_RULER: return QAccessible::NoRole; // FIXME - case ui::AX_ROLE_RULER_MARKER: - return QAccessible::NoRole; // FIXME case ui::AX_ROLE_SCROLL_AREA: return QAccessible::Client; // FIXME case ui::AX_ROLE_SCROLL_BAR: @@ -439,8 +349,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::NoRole; // FIXME case ui::AX_ROLE_SEARCH: return QAccessible::Section; - case ui::AX_ROLE_SHEET: - return QAccessible::NoRole; // FIXME case ui::AX_ROLE_SLIDER: return QAccessible::Slider; case ui::AX_ROLE_SLIDER_THUMB: @@ -451,16 +359,12 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::NoRole; // FIXME case ui::AX_ROLE_SPLITTER: return QAccessible::Splitter; - case ui::AX_ROLE_SPLIT_GROUP: - return QAccessible::Splitter; case ui::AX_ROLE_STATIC_TEXT: return QAccessible::StaticText; case ui::AX_ROLE_STATUS: return QAccessible::StatusBar; case ui::AX_ROLE_SVG_ROOT: return QAccessible::Graphic; - case ui::AX_ROLE_SYSTEM_WIDE: - return QAccessible::NoRole; // FIXME case ui::AX_ROLE_TABLE: return QAccessible::Table; case ui::AX_ROLE_TABLE_HEADER_CONTAINER: @@ -473,8 +377,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::PageTabList; case ui::AX_ROLE_TAB_PANEL: return QAccessible::PageTab; - case ui::AX_ROLE_TEXT_AREA: - return QAccessible::EditableText; case ui::AX_ROLE_TEXT_FIELD: return QAccessible::EditableText; case ui::AX_ROLE_TIMER: @@ -493,8 +395,6 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::Tree; case ui::AX_ROLE_TREE_ITEM: return QAccessible::TreeItem; - case ui::AX_ROLE_VALUE_INDICATOR: - return QAccessible::Client; // FIXME case ui::AX_ROLE_WINDOW: return QAccessible::Window; } diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h index 7d58f515e..d4f8ac0a5 100644 --- a/src/core/browser_accessibility_qt.h +++ b/src/core/browser_accessibility_qt.h @@ -55,9 +55,6 @@ class BrowserAccessibilityQt public: BrowserAccessibilityQt(); - // BrowserAccessibility - virtual void OnDataChanged() Q_DECL_OVERRIDE; - // QAccessibleInterface virtual bool isValid() const Q_DECL_OVERRIDE; virtual QObject *object() const Q_DECL_OVERRIDE; diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp index fa51575e3..14f3b1c6c 100644 --- a/src/core/browser_context_adapter.cpp +++ b/src/core/browser_context_adapter.cpp @@ -40,6 +40,7 @@ #include "browser_context_qt.h" #include "content_client_qt.h" #include "download_manager_delegate_qt.h" +#include "permission_manager_qt.h" #include "web_engine_context.h" #include "web_engine_visited_links_manager.h" #include "url_request_context_getter_qt.h" @@ -132,6 +133,28 @@ DownloadManagerDelegateQt *BrowserContextAdapter::downloadManagerDelegate() return m_downloadManagerDelegate.data(); } +QWebEngineCookieStoreClient *BrowserContextAdapter::cookieStoreClient() +{ + return m_cookieStoreClient.data(); +} + +void BrowserContextAdapter::setCookieStoreClient(QWebEngineCookieStoreClient *client) +{ + m_cookieStoreClient = client; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateStorageSettings(); +} + +QWebEngineUrlRequestInterceptor *BrowserContextAdapter::requestInterceptor() +{ + return m_requestInterceptor.data(); +} + +void BrowserContextAdapter::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + m_requestInterceptor = interceptor; +} + void BrowserContextAdapter::addClient(BrowserContextAdapterClient *adapterClient) { m_clients.append(adapterClient); @@ -340,4 +363,19 @@ UserScriptControllerHost *BrowserContextAdapter::userScriptController() return m_userScriptController.data(); } +void BrowserContextAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, bool reply) +{ + static_cast<PermissionManagerQt*>(browserContext()->GetPermissionManager())->permissionRequestReply(origin, type, reply); +} + +QString BrowserContextAdapter::httpAcceptLanguage() const +{ + return m_httpAcceptLanguage; +} + +void BrowserContextAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage) +{ + m_httpAcceptLanguage = httpAcceptLanguage; +} + } // namespace QtWebEngineCore diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h index 42787bc23..d58d8a4be 100644 --- a/src/core/browser_context_adapter.h +++ b/src/core/browser_context_adapter.h @@ -40,11 +40,15 @@ #include "qtwebenginecoreglobal.h" #include <QList> +#include <QPointer> #include <QScopedPointer> #include <QSharedData> #include <QString> #include <QVector> +#include "api/qwebenginecookiestoreclient.h" +#include "api/qwebengineurlrequestinterceptor.h" + QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { @@ -69,6 +73,12 @@ public: WebEngineVisitedLinksManager *visitedLinksManager(); DownloadManagerDelegateQt *downloadManagerDelegate(); + QWebEngineCookieStoreClient *cookieStoreClient(); + void setCookieStoreClient(QWebEngineCookieStoreClient *client); + + QWebEngineUrlRequestInterceptor* requestInterceptor(); + void setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); + QList<BrowserContextAdapterClient*> clients() { return m_clients; } void addClient(BrowserContextAdapterClient *adapterClient); void removeClient(BrowserContextAdapterClient *adapterClient); @@ -113,6 +123,13 @@ public: TrackVisitedLinksOnDisk, }; + enum PermissionType { + UnsupportedPermission = 0, + GeolocationPermission = 1, +// Reserved: +// NotificationPermission = 2, + }; + HttpCacheType httpCacheType() const; void setHttpCacheType(BrowserContextAdapter::HttpCacheType); @@ -132,6 +149,11 @@ public: void updateCustomUrlSchemeHandlers(); UserScriptControllerHost *userScriptController(); + void permissionRequestReply(const QUrl &origin, PermissionType type, bool reply); + + QString httpAcceptLanguage() const; + void setHttpAcceptLanguage(const QString &httpAcceptLanguage); + private: QString m_name; bool m_offTheRecord; @@ -139,11 +161,14 @@ private: QScopedPointer<WebEngineVisitedLinksManager> m_visitedLinksManager; QScopedPointer<DownloadManagerDelegateQt> m_downloadManagerDelegate; QScopedPointer<UserScriptControllerHost> m_userScriptController; + QPointer<QWebEngineCookieStoreClient> m_cookieStoreClient; + QPointer<QWebEngineUrlRequestInterceptor> m_requestInterceptor; QString m_dataPath; QString m_cachePath; QString m_httpUserAgent; HttpCacheType m_httpCacheType; + QString m_httpAcceptLanguage; PersistentCookiesPolicy m_persistentCookiesPolicy; VisitedLinksPolicy m_visitedLinksPolicy; QVector<CustomUrlSchemeHandler*> m_customUrlSchemeHandlers; diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 7f285b1e5..28486cced 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -38,9 +38,10 @@ #include "browser_context_adapter.h" #include "download_manager_delegate_qt.h" -#include "type_conversion.h" -#include "qtwebenginecoreglobal.h" +#include "permission_manager_qt.h" +#include "qtwebenginecoreglobal_p.h" #include "resource_context_qt.h" +#include "type_conversion.h" #include "url_request_context_getter_qt.h" #include "base/time/time.h" @@ -134,6 +135,18 @@ content::SSLHostStateDelegate* BrowserContextQt::GetSSLHostStateDelegate() return 0; } +scoped_ptr<content::ZoomLevelDelegate> BrowserContextQt::CreateZoomLevelDelegate(const base::FilePath&) +{ + return nullptr; +} + +content::PermissionManager *BrowserContextQt::GetPermissionManager() +{ + if (!permissionManager) + permissionManager.reset(new PermissionManagerQt(m_adapter)); + return permissionManager.get(); +} + net::URLRequestContextGetter *BrowserContextQt::CreateRequestContext(content::ProtocolHandlerMap *protocol_handlers) { url_request_getter_ = new URLRequestContextGetterQt(m_adapter, protocol_handlers); diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index af36b55ab..eccd684a3 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -47,6 +47,7 @@ namespace QtWebEngineCore { class BrowserContextAdapter; +class PermissionManagerQt; class URLRequestContextGetterQt; class BrowserContextQt : public content::BrowserContext @@ -72,13 +73,17 @@ public: virtual content::PushMessagingService* GetPushMessagingService() Q_DECL_OVERRIDE; virtual content::SSLHostStateDelegate* GetSSLHostStateDelegate() Q_DECL_OVERRIDE; net::URLRequestContextGetter *CreateRequestContext(content::ProtocolHandlerMap *protocol_handlers); + virtual scoped_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(const base::FilePath& partition_path) Q_DECL_OVERRIDE; + virtual content::PermissionManager *GetPermissionManager() Q_DECL_OVERRIDE; + + BrowserContextAdapter *adapter() { return m_adapter; } - BrowserContextAdapter* adapter() { return m_adapter; } private: friend class ContentBrowserClientQt; friend class WebContentsAdapter; scoped_ptr<content::ResourceContext> resourceContext; scoped_refptr<URLRequestContextGetterQt> url_request_getter_; + scoped_ptr<PermissionManagerQt> permissionManager; BrowserContextAdapter *m_adapter; friend class BrowserContextAdapter; diff --git a/src/core/chrome_qt.gyp b/src/core/chrome_qt.gyp index 703ce7525..0f30b7a04 100644 --- a/src/core/chrome_qt.gyp +++ b/src/core/chrome_qt.gyp @@ -19,6 +19,8 @@ '<(chromium_src_dir)/chrome/browser/media/desktop_streams_registry.cc', '<(chromium_src_dir)/chrome/browser/media/desktop_streams_registry.h', '<(chromium_src_dir)/chrome/browser/media/desktop_media_list.h', + '<(chromium_src_dir)/chrome/common/chrome_switches.cc', + '<(chromium_src_dir)/chrome/common/chrome_switches.h', '<(chromium_src_dir)/chrome/common/localized_error.cc', '<(chromium_src_dir)/chrome/common/localized_error.h', ], diff --git a/src/core/chromium_gpu_helper.cpp b/src/core/chromium_gpu_helper.cpp index ef574eccd..9dfc498ad 100644 --- a/src/core/chromium_gpu_helper.cpp +++ b/src/core/chromium_gpu_helper.cpp @@ -43,18 +43,18 @@ // Including gpu/command_buffer headers before content/gpu headers makes sure that // guards are defined to prevent duplicate definition errors with forward declared // GL typedefs cascading through content header includes. +#include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/texture_manager.h" #include "content/common/gpu/gpu_channel_manager.h" -#include "content/common/gpu/sync_point_manager.h" #include "content/gpu/gpu_child_thread.h" #ifdef Q_OS_QNX #include "content/common/gpu/stream_texture_qnx.h" #endif -static void addSyncPointCallbackDelegate(content::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback) +static void addSyncPointCallbackDelegate(gpu::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback) { syncPointManager->AddSyncPointCallback(sync_point, callback); } @@ -78,13 +78,13 @@ base::MessageLoop *gpu_message_loop() return content::GpuChildThread::instance()->message_loop(); } -content::SyncPointManager *sync_point_manager() +gpu::SyncPointManager *sync_point_manager() { content::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->ChannelManager(); return gpuChannelManager->sync_point_manager(); } -void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, content::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback) +void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, gpu::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback) { // We need to set our callback from the GPU thread, where the SyncPointManager lives. gpuMessageLoop->PostTask(FROM_HERE, base::Bind(&addSyncPointCallbackDelegate, make_scoped_refptr(syncPointManager), sync_point, callback)); diff --git a/src/core/chromium_gpu_helper.h b/src/core/chromium_gpu_helper.h index 936ad1d24..6242dd068 100644 --- a/src/core/chromium_gpu_helper.h +++ b/src/core/chromium_gpu_helper.h @@ -47,12 +47,9 @@ namespace base { class MessageLoop; } -namespace content { -class SyncPointManager; -} - namespace gpu { struct Mailbox; +class SyncPointManager; namespace gles2 { class MailboxManager; class Texture; @@ -66,10 +63,10 @@ class Texture; QMap<uint32, gfx::TransferableFence> transferFences(); base::MessageLoop *gpu_message_loop(); -content::SyncPointManager *sync_point_manager(); +gpu::SyncPointManager *sync_point_manager(); gpu::gles2::MailboxManager *mailbox_manager(); -void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, content::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback); +void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, gpu::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback); gpu::gles2::Texture* ConsumeTexture(gpu::gles2::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox); unsigned int service_id(gpu::gles2::Texture *tex); diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp index 5af8a6ad8..b9ce722dd 100644 --- a/src/core/chromium_overrides.cpp +++ b/src/core/chromium_overrides.cpp @@ -37,8 +37,9 @@ #include "chromium_overrides.h" #include "gl_context_qt.h" -#include "qtwebenginecoreglobal.h" +#include "qtwebenginecoreglobal_p.h" #include "web_contents_view_qt.h" + #include "base/values.h" #include "content/browser/renderer_host/pepper/pepper_truetype_font_list.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" @@ -47,6 +48,8 @@ #include <QGuiApplication> #include <QScreen> #include <QWindow> +#include <QFontDatabase> +#include <QStringList> #if defined(USE_X11) #include "ui/gfx/x/x11_types.h" @@ -115,8 +118,17 @@ namespace content { // content/common/font_list.h scoped_ptr<base::ListValue> GetFontList_SlowBlocking() { - QT_NOT_USED - return scoped_ptr<base::ListValue>(new base::ListValue); + scoped_ptr<base::ListValue> font_list(new base::ListValue); + + QFontDatabase database; + for (auto family : database.families()){ + base::ListValue* font_item = new base::ListValue(); + font_item->Append(new base::StringValue(family.toStdString())); + font_item->Append(new base::StringValue(family.toStdString())); // should be localized name. + // TODO: Support localized family names. + font_list->Append(font_item); + } + return font_list.Pass(); } #if defined(ENABLE_PLUGINS) @@ -142,39 +154,6 @@ OSExchangeData::Provider* OSExchangeData::CreateProvider() return 0; } -} - -namespace gfx { - -// Stubs for these unused functions that are stripped in case -// of a release aura build but a debug build needs the symbols. - -RenderText* RenderText::CreateNativeInstance() -{ - QT_NOT_USED; - return 0; -} - -#if defined(OS_LINUX) -PlatformFont* PlatformFont::CreateDefault() -{ - QT_NOT_USED; - return 0; -} - -PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont) -{ - QT_NOT_USED; - return 0; -} - -PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string&, int) -{ - QT_NOT_USED; - return 0; -} -#endif - -} // namespace gfx +} // namespace ui #endif // defined(USE_AURA) && !defined(USE_OZONE) diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp index 797f5c7f4..206392840 100644 --- a/src/core/clipboard_qt.cpp +++ b/src/core/clipboard_qt.cpp @@ -331,7 +331,7 @@ SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const 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); + image = image.convertToFormat(QImage::Format_ARGB32); SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeN32(image.width(), image.height(), kOpaque_SkAlphaType)); bitmap.setPixels(const_cast<uchar*>(image.constBits())); @@ -361,7 +361,7 @@ void ClipboardQt::ReadData(const FormatType& format, std::string* result) const *result = std::string(byteArray.constData(), byteArray.length()); } -uint64 ClipboardQt::GetSequenceNumber(ui::ClipboardType type) +uint64 ClipboardQt::GetSequenceNumber(ui::ClipboardType type) const { return clipboardChangeObserver()->getSequenceNumber(type == ui::CLIPBOARD_TYPE_COPY_PASTE ? QClipboard::Clipboard : QClipboard::Selection); } diff --git a/src/core/clipboard_qt.h b/src/core/clipboard_qt.h index 4c7e6ab59..ee1fc7440 100644 --- a/src/core/clipboard_qt.h +++ b/src/core/clipboard_qt.h @@ -62,7 +62,7 @@ private: class ClipboardQt : public ui::Clipboard { public: - virtual uint64 GetSequenceNumber(ui::ClipboardType type) Q_DECL_OVERRIDE; + virtual uint64 GetSequenceNumber(ui::ClipboardType type) const 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; diff --git a/src/core/common/qt_messages.h b/src/core/common/qt_messages.h index c692ee5ca..25a995b27 100644 --- a/src/core/common/qt_messages.h +++ b/src/core/common/qt_messages.h @@ -31,6 +31,9 @@ IPC_MESSAGE_ROUTED1(QtRenderViewObserver_FetchDocumentMarkup, IPC_MESSAGE_ROUTED1(QtRenderViewObserver_FetchDocumentInnerText, uint64 /* requestId */) +IPC_MESSAGE_ROUTED1(QtRenderViewObserver_SetBackgroundColor, + uint32 /* color */) + IPC_MESSAGE_ROUTED1(WebChannelIPCTransport_Message, std::vector<char> /*binaryJSON*/) // User scripts messages diff --git a/src/core/config/desktop_linux.pri b/src/core/config/desktop_linux.pri index 041b094a1..cb4efa607 100644 --- a/src/core/config/desktop_linux.pri +++ b/src/core/config/desktop_linux.pri @@ -15,7 +15,23 @@ GYP_CONFIG += \ use_pango=0 \ host_clang=0 \ clang=0 \ + enable_plugins=1 \ +contains(QT_CONFIG, system-zlib): config_system_minizip: GYP_CONFIG += use_system_zlib=1 +contains(QT_CONFIG, system-png): GYP_CONFIG += use_system_libpng=1 contains(QT_CONFIG, system-jpeg): GYP_CONFIG += use_system_libjpeg=1 +config_system_libevent: GYP_CONFIG += use_system_libevent=1 +config_system_libwebp: GYP_CONFIG += use_system_libwebp=1 +config_system_libsrtp: GYP_CONFIG += use_system_libsrtp=1 +config_system_libxslt: GYP_CONFIG += use_system_libxml=1 +config_system_flac: GYP_CONFIG += use_system_flac=1 +config_system_jsoncpp: GYP_CONFIG += use_system_jsoncpp=1 +config_system_opus: GYP_CONFIG += use_system_opus=1 +config_system_snappy: GYP_CONFIG += use_system_snappy=1 +config_system_speex: GYP_CONFIG += use_system_speex=1 +config_system_vpx: GYP_CONFIG += use_system_libvpx=1 + +contains(WEBENGINE_CONFIG, use_system_icu): GYP_CONFIG += use_system_icu=1 +contains(WEBENGINE_CONFIG, use_system_ffmpeg): GYP_CONFIG += use_system_ffmpeg=1 !contains(QT_CONFIG, pulseaudio): GYP_CONFIG += use_pulseaudio=0 diff --git a/src/core/config/embedded_linux.pri b/src/core/config/embedded_linux.pri index cc8c40f8e..0133dc6b0 100644 --- a/src/core/config/embedded_linux.pri +++ b/src/core/config/embedded_linux.pri @@ -1,7 +1,6 @@ GYP_ARGS += "-D qt_os=\"embedded_linux\" -I config/embedded_linux.gypi" GYP_CONFIG += \ - build_ffmpegsumo=1 \ clang=0 \ desktop_linux=0 \ disable_nacl=1 \ @@ -44,11 +43,25 @@ GYP_CONFIG += \ use_ozone=1 \ use_pango=0 \ use_system_fontconfig=1 \ - use_system_icu=1 \ icu_use_data_file_flag=0 \ use_x11=0 \ v8_use_snapshot=false \ want_separate_host_toolset=1 \ +contains(QT_CONFIG, system-zlib): config_system_minizip: GYP_CONFIG += use_system_zlib=1 +contains(QT_CONFIG, system-png): GYP_CONFIG += use_system_libpng=1 contains(QT_CONFIG, system-jpeg): GYP_CONFIG += use_system_libjpeg=1 !contains(QT_CONFIG, pulseaudio): GYP_CONFIG += use_pulseaudio=0 +config_system_libevent: GYP_CONFIG += use_system_libevent=1 +config_system_libwebp: GYP_CONFIG += use_system_libwebp=1 +config_system_libsrtp: GYP_CONFIG += use_system_libsrtp=1 +config_system_libxslt: GYP_CONFIG += use_system_libxml=1 +config_system_flac: GYP_CONFIG += use_system_flac=1 +config_system_jsoncpp: GYP_CONFIG += use_system_jsoncpp=1 +config_system_opus: GYP_CONFIG += use_system_opus=1 +config_system_snappy: GYP_CONFIG += use_system_snappy=1 +config_system_speex: GYP_CONFIG += use_system_speex=1 +config_system_vpx: GYP_CONFIG += use_system_libvpx=1 + +contains(WEBENGINE_CONFIG, use_system_icu): GYP_CONFIG += use_system_icu=1 +contains(WEBENGINE_CONFIG, use_system_ffmpeg): GYP_CONFIG += use_system_ffmpeg=1 diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 3f42b6fd7..93c77623c 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -14,7 +14,8 @@ GYP_CONFIG += \ mac_sdk_min=\"10.7\" \ mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ make_clang_dir=\"$${QMAKE_CLANG_DIR}\" \ - clang_use_chrome_plugins=0 + clang_use_chrome_plugins=0 \ + enable_plugins=1 QMAKE_MAC_SDK_PATH = "$$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path)" exists($$QMAKE_MAC_SDK_PATH): GYP_CONFIG += mac_sdk_path=\"$${QMAKE_MAC_SDK_PATH}\" diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index f7644c83b..602afbc67 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -28,3 +28,17 @@ contains(QT_CONFIG, angle) { GYP_ARGS += "-D qt_gl=\"opengl\"" } +msvc { + equals(MSVC_VER, 12.0) { + MSVS_VERSION = 2013 + } else:equals(MSVC_VER, 14.0) { + MSVS_VERSION = 2015 + } else { + fatal("Visual Studio compiler version \"$$MSVC_VER\" is not supported by Qt WebEngine") + } + + GYP_ARGS += "-G msvs_version=$$MSVS_VERSION" + +} else { + fatal("Qt WebEngine for Windows can only be built with the Microsoft Visual Studio C++ compiler") +} diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index fdfbaf0f5..91cd0b0c4 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -56,6 +56,7 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_share_group.h" +#include "ui/gl/gpu_timing.h" #include "access_token_store_qt.h" #include "browser_context_adapter.h" @@ -74,6 +75,12 @@ #include "web_engine_context.h" #include "web_engine_library_info.h" +#if defined(ENABLE_PLUGINS) +#include "content/public/browser/browser_ppapi_host.h" +#include "ppapi/host/ppapi_host.h" +#include "renderer/pepper/pepper_host_factory_qt.h" +#endif + #include <QGuiApplication> #include <QLocale> #include <QOpenGLContext> @@ -277,7 +284,11 @@ public: virtual bool MakeCurrent(gfx::GLSurface *) Q_DECL_OVERRIDE { Q_UNREACHABLE(); return false; } virtual void ReleaseCurrent(gfx::GLSurface *) Q_DECL_OVERRIDE { Q_UNREACHABLE(); } virtual bool IsCurrent(gfx::GLSurface *) Q_DECL_OVERRIDE { Q_UNREACHABLE(); return false; } - virtual void SetSwapInterval(int) Q_DECL_OVERRIDE { Q_UNREACHABLE(); } + virtual void OnSetSwapInterval(int) Q_DECL_OVERRIDE { Q_UNREACHABLE(); } + virtual scoped_refptr<gfx::GPUTimingClient> CreateGPUTimingClient() Q_DECL_OVERRIDE + { + return nullptr; + } private: void *m_handle; @@ -360,9 +371,8 @@ content::MediaObserver *ContentBrowserClientQt::GetMediaObserver() return MediaCaptureDevicesDispatcher::GetInstance(); } -void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, const GURL &url, content::WebPreferences *web_prefs) +void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, content::WebPreferences *web_prefs) { - Q_UNUSED(url); if (content::WebContents *webContents = rvh->GetDelegate()->GetAsWebContents()) static_cast<WebContentsDelegateQt*>(webContents->GetDelegate())->overrideWebPreferences(webContents, web_prefs); } @@ -402,41 +412,6 @@ void ContentBrowserClientQt::AllowCertificateError(int render_process_id, int re contentsDelegate->allowCertificateError(errorController); } -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(bridge_id); - Q_UNUSED(user_gesture); - 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); -} - -blink::WebNotificationPermission ContentBrowserClientQt::CheckDesktopNotificationPermission(const GURL&, content::ResourceContext *, int ) -{ - return blink::WebNotificationPermission::WebNotificationPermissionDenied; -} - content::LocationProvider *ContentBrowserClientQt::OverrideSystemLocationProvider() { #ifdef QT_USE_POSITIONING @@ -451,6 +426,11 @@ std::string ContentBrowserClientQt::GetApplicationLocale() return WebEngineLibraryInfo::getApplicationLocale(); } +std::string ContentBrowserClientQt::GetAcceptLangs(content::BrowserContext *context) +{ + return static_cast<BrowserContextQt*>(context)->adapter()->httpAcceptLanguage().toStdString(); +} + void ContentBrowserClientQt::AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) { Q_UNUSED(child_process_id); @@ -460,6 +440,13 @@ void ContentBrowserClientQt::AppendExtraCommandLineSwitches(base::CommandLine* c command_line->AppendSwitchASCII(switches::kLang, GetApplicationLocale()); } +#if defined(ENABLE_PLUGINS) + void ContentBrowserClientQt::DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) { + browser_host->GetPpapiHost()->AddHostFactoryFilter( + scoped_ptr<ppapi::host::HostFactory>(new QtWebEngineCore::PepperHostFactoryQt(browser_host))); + } +#endif + 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 0af5ae9d3..eea7d2a22 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -40,7 +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 "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h" #include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE @@ -51,6 +51,11 @@ class URLRequestContextGetter; namespace content { class BrowserContext; class BrowserMainParts; + +#if defined(ENABLE_PLUGINS) +class BrowserPpapiHost; +#endif + class DevToolsManagerDelegate; class RenderProcessHost; class RenderViewHostDelegateView; @@ -83,7 +88,7 @@ public: virtual content::MediaObserver* GetMediaObserver() 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 OverrideWebkitPrefs(content::RenderViewHost *, content::WebPreferences *) Q_DECL_OVERRIDE; virtual void AllowCertificateError( int render_process_id, int render_frame_id, @@ -96,26 +101,18 @@ public: bool expired_previous_decision, const base::Callback<void(bool)>& callback, content::CertificateRequestResultType* result) Q_DECL_OVERRIDE; - virtual void 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_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; - virtual blink::WebNotificationPermission CheckDesktopNotificationPermission(const GURL& source_origin, content::ResourceContext* context, int render_process_id) Q_DECL_OVERRIDE; - virtual std::string GetApplicationLocale() Q_DECL_OVERRIDE; + std::string GetAcceptLangs(content::BrowserContext* context) Q_DECL_OVERRIDE; virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) Q_DECL_OVERRIDE; +#if defined(ENABLE_PLUGINS) + virtual void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) Q_DECL_OVERRIDE; +#endif + private: BrowserMainPartsQt* m_browserMainParts; scoped_ptr<ResourceDispatcherHostDelegateQt> m_resourceDispatcherHostDelegate; diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index 20a8df75e..01e1fe383 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -36,11 +36,119 @@ #include "content_client_qt.h" +#include "base/command_line.h" #include "base/strings/string_piece.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "content/public/common/content_constants.h" #include "content/public/common/user_agent.h" #include "ui/base/layout.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#include "type_conversion.h" + +#include <QCoreApplication> +#include <QFile> +#include <QStringBuilder> + +#if defined(ENABLE_PLUGINS) +#include "content/public/common/pepper_plugin_info.h" +#include "ppapi/shared_impl/ppapi_permissions.h" + +static const int32 kPepperFlashPermissions = ppapi::PERMISSION_DEV | + ppapi::PERMISSION_PRIVATE | + ppapi::PERMISSION_BYPASS_USER_GESTURE | + ppapi::PERMISSION_FLASH; + +namespace switches { +const char kPpapiFlashPath[] = "ppapi-flash-path"; +const char kPpapiFlashVersion[] = "ppapi-flash-version"; +} + +// Adopted from chrome_content_client.cc +content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, const std::string& version) +{ + content::PepperPluginInfo plugin; + + plugin.is_out_of_process = true; + plugin.name = content::kFlashPluginName; + plugin.path = path; + plugin.permissions = kPepperFlashPermissions; + + std::vector<std::string> flash_version_numbers; + base::SplitString(version, '.', &flash_version_numbers); + if (flash_version_numbers.size() < 1) + flash_version_numbers.push_back("11"); + else if (flash_version_numbers[0].empty()) + flash_version_numbers[0] = "11"; + if (flash_version_numbers.size() < 2) + flash_version_numbers.push_back("2"); + if (flash_version_numbers.size() < 3) + flash_version_numbers.push_back("999"); + if (flash_version_numbers.size() < 4) + flash_version_numbers.push_back("999"); + + // E.g., "Shockwave Flash 10.2 r154": + plugin.description = plugin.name + " " + flash_version_numbers[0] + "." + flash_version_numbers[1] + " r" + flash_version_numbers[2]; + plugin.version = JoinString(flash_version_numbers, '.'); + content::WebPluginMimeType swf_mime_type(content::kFlashPluginSwfMimeType, + content::kFlashPluginSwfExtension, + content::kFlashPluginSwfDescription); + plugin.mime_types.push_back(swf_mime_type); + content::WebPluginMimeType spl_mime_type(content::kFlashPluginSplMimeType, + content::kFlashPluginSplExtension, + content::kFlashPluginSplDescription); + plugin.mime_types.push_back(spl_mime_type); + + return plugin; +} + +void AddPepperFlashFromSystem(std::vector<content::PepperPluginInfo>* plugins) +{ + QStringList pluginPaths; +#if defined(Q_OS_WIN) && defined(Q_PROCESSOR_X86_32) + QDir pluginDir("C:/Windows/SysWOW64/Macromed/Flash"); + pluginDir.setFilter(QDir::Files); + QStringList nameFilters("pepflashplayer*.dll"); + pluginPaths << pluginDir.entryList(nameFilters); +#endif +#if defined(Q_OS_OSX) + pluginPaths << "/Library/Internet Plug-Ins/PepperFlashPlayer/PepperFlashPlayer.plugin"; // Mac OS X +#endif +#if defined(Q_OS_LINUX) + pluginPaths << "/usr/lib/pepperflashplugin-nonfree/libpepflashplayer.so" // Ubuntu + << "/usr/lib/PepperFlash/libpepflashplayer.so" // Arch + << "/usr/lib64/chromium/PepperFlash/libpepflashplayer.so"; // OpenSuSE +#endif + for (auto it = pluginPaths.constBegin(); it != pluginPaths.constEnd(); ++it) { + if (!QFile(*it).exists()) + continue; + plugins->push_back(CreatePepperFlashInfo(QtWebEngineCore::toFilePath(*it), std::string())); + return; + } +} + +void AddPepperFlashFromCommandLine(std::vector<content::PepperPluginInfo>* plugins) +{ + const base::CommandLine::StringType flash_path = base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(switches::kPpapiFlashPath); + if (flash_path.empty() || !QFile(QtWebEngineCore::toQt(flash_path)).exists()) + return; + + // Read pepper flash plugin version from command-line. (e.g. 16.0.0.235) + std::string flash_version = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kPpapiFlashVersion); + plugins->push_back(CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); +} + +namespace QtWebEngineCore { + +void ContentClientQt::AddPepperPlugins(std::vector<content::PepperPluginInfo>* plugins) +{ + AddPepperFlashFromSystem(plugins); + AddPepperFlashFromCommandLine(plugins); +} + +} +#endif #include <QCoreApplication> #include <QStringBuilder> diff --git a/src/core/content_client_qt.h b/src/core/content_client_qt.h index f68282dcf..309e049dc 100644 --- a/src/core/content_client_qt.h +++ b/src/core/content_client_qt.h @@ -48,6 +48,10 @@ class ContentClientQt : public content::ContentClient { public: static std::string getUserAgent(); +#if defined(ENABLE_PLUGINS) + virtual void AddPepperPlugins(std::vector<content::PepperPluginInfo>* plugins) Q_DECL_OVERRIDE; +#endif + virtual base::StringPiece GetDataResource(int, ui::ScaleFactor) const Q_DECL_OVERRIDE; virtual std::string GetUserAgent() const Q_DECL_OVERRIDE { return getUserAgent(); } virtual base::string16 GetLocalizedString(int message_id) const Q_DECL_OVERRIDE; diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 4003823b1..0688fb015 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -72,7 +72,7 @@ void ContentMainDelegateQt::PreSandboxStartup() // Suppress info, warning and error messages per default. int logLevel = logging::LOG_FATAL; - CommandLine* parsedCommandLine = CommandLine::ForCurrentProcess(); + base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); if (parsedCommandLine->HasSwitch(switches::kLoggingLevel)) { std::string logLevelValue = parsedCommandLine->GetSwitchValueASCII(switches::kLoggingLevel); int level = 0; diff --git a/src/core/cookie_monster_delegate_qt.cpp b/src/core/cookie_monster_delegate_qt.cpp new file mode 100644 index 000000000..6b808e76c --- /dev/null +++ b/src/core/cookie_monster_delegate_qt.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "cookie_monster_delegate_qt.h" + +#include "base/bind.h" +#include "content/public/browser/browser_thread.h" +#include "net/cookies/cookie_util.h" + +#include "api/qwebenginecookiestoreclient.h" +#include "api/qwebenginecookiestoreclient_p.h" +#include "type_conversion.h" + +#include <QStringBuilder> + +namespace QtWebEngineCore { + +static GURL sourceUrlForCookie(const QNetworkCookie &cookie) { + QString urlFragment = QString("%1%2").arg(cookie.domain()).arg(cookie.path()); + return net::cookie_util::CookieOriginToURL(urlFragment.toStdString(), /* is_https */ cookie.isSecure()); +} + +static void onSetCookieCallback(QWebEngineCookieStoreClientPrivate *client, qint64 callbackId, bool success) { + client->onSetCallbackResult(callbackId, success); +} + +static void onDeleteCookiesCallback(QWebEngineCookieStoreClientPrivate *client, qint64 callbackId, int numCookies) { + client->onDeleteCallbackResult(callbackId, numCookies); +} + +static void onGetAllCookiesCallback(QWebEngineCookieStoreClientPrivate *client, qint64 callbackId, const net::CookieList& cookies) { + QByteArray rawCookies; + for (auto&& cookie: cookies) + rawCookies += toQt(cookie).toRawForm() % QByteArrayLiteral("\n"); + + client->onGetAllCallbackResult(callbackId, rawCookies); +} + +CookieMonsterDelegateQt::CookieMonsterDelegateQt() + : m_client(0) + , m_cookieMonster(0) +{ + +} + +CookieMonsterDelegateQt::~CookieMonsterDelegateQt() +{ + +} + +bool CookieMonsterDelegateQt::hasCookieMonster() +{ + return m_cookieMonster.get(); +} + +void CookieMonsterDelegateQt::getAllCookies(quint64 callbackId) +{ + net::CookieMonster::GetCookieListCallback callback = base::Bind(&onGetAllCookiesCallback, m_client->d_func(), callbackId); + m_cookieMonster->GetAllCookiesAsync(callback); +} + +void CookieMonsterDelegateQt::setCookie(quint64 callbackId, const QNetworkCookie &cookie, const QUrl &origin) +{ + Q_ASSERT(hasCookieMonster()); + Q_ASSERT(m_client); + + net::CookieStore::SetCookiesCallback callback; + if (callbackId != CallbackDirectory::NoCallbackId) + callback = base::Bind(&onSetCookieCallback, m_client->d_func(), callbackId); + + net::CookieOptions options; + options.set_include_httponly(); + + GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin); + + m_cookieMonster->SetCookieWithOptionsAsync(gurl, cookie.toRawForm().toStdString(), options, callback); +} + +void CookieMonsterDelegateQt::deleteCookie(const QNetworkCookie &cookie, const QUrl &origin) +{ + Q_ASSERT(hasCookieMonster()); + Q_ASSERT(m_client); + + GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin); + + m_cookieMonster->DeleteCookieAsync(gurl, cookie.name().toStdString(), base::Closure()); +} + +void CookieMonsterDelegateQt::deleteSessionCookies(quint64 callbackId) +{ + Q_ASSERT(hasCookieMonster()); + Q_ASSERT(m_client); + + net::CookieMonster::DeleteCallback callback = base::Bind(&onDeleteCookiesCallback, m_client->d_func(), callbackId); + m_cookieMonster->DeleteSessionCookiesAsync(callback); +} + +void CookieMonsterDelegateQt::deleteAllCookies(quint64 callbackId) +{ + Q_ASSERT(hasCookieMonster()); + Q_ASSERT(m_client); + + net::CookieMonster::DeleteCallback callback = base::Bind(&onDeleteCookiesCallback, m_client->d_func(), callbackId); + m_cookieMonster->DeleteAllAsync(callback); +} + +void CookieMonsterDelegateQt::setCookieMonster(net::CookieMonster* monster) +{ + m_cookieMonster = monster; + + if (m_client) + m_client->d_func()->processPendingUserCookies(); +} + +void CookieMonsterDelegateQt::setClient(QWebEngineCookieStoreClient *client) +{ + m_client = client; + + if (!m_client) + return; + + m_client->d_ptr->delegate = this; + + if (hasCookieMonster()) + m_client->d_func()->processPendingUserCookies(); +} + +void CookieMonsterDelegateQt::OnCookieChanged(const net::CanonicalCookie& cookie, bool removed, ChangeCause cause) +{ + if (!m_client) + return; + m_client->d_ptr->onCookieChanged(toQt(cookie), removed); +} + +} diff --git a/src/core/cookie_monster_delegate_qt.h b/src/core/cookie_monster_delegate_qt.h new file mode 100644 index 000000000..e5e295853 --- /dev/null +++ b/src/core/cookie_monster_delegate_qt.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 COOKIE_MONSTER_DELEGATE_QT_H +#define COOKIE_MONSTER_DELEGATE_QT_H + +#include "qtwebenginecoreglobal.h" + +QT_WARNING_PUSH +// For some reason adding -Wno-unused-parameter to QMAKE_CXXFLAGS has no +// effect with clang, so use a pragma for these dirty chromium headers +QT_WARNING_DISABLE_CLANG("-Wunused-parameter") +#include "base/memory/ref_counted.h" +#include "net/cookies/cookie_monster.h" +QT_WARNING_POP + +#include <QList> +#include <QNetworkCookie> +#include <QPointer> + +QT_FORWARD_DECLARE_CLASS(QWebEngineCookieStoreClient) + +namespace QtWebEngineCore { + +// Extends net::CookieMonster::kDefaultCookieableSchemes with qrc, without enabling +// cookies for the file:// scheme, which is disabled by default in Chromium. +// Since qrc:// is similar to file:// and there are some unknowns about how +// to correctly handle file:// cookies, qrc:// should only be used for testing. +static const char* const kCookieableSchemes[] = + { "http", "https", "qrc", "ws", "wss" }; + +class QWEBENGINE_EXPORT CookieMonsterDelegateQt: public net::CookieMonsterDelegate { + QPointer<QWebEngineCookieStoreClient> m_client; + scoped_refptr<net::CookieMonster> m_cookieMonster; +public: + CookieMonsterDelegateQt(); + ~CookieMonsterDelegateQt(); + + bool hasCookieMonster(); + + void setCookie(quint64 callbackId, const QNetworkCookie &cookie, const QUrl &origin); + void deleteCookie(const QNetworkCookie &cookie, const QUrl &origin); + void getAllCookies(quint64 callbackId); + void deleteSessionCookies(quint64 callbackId); + void deleteAllCookies(quint64 callbackId); + + void setCookieMonster(net::CookieMonster* monster); + void setClient(QWebEngineCookieStoreClient *client); + + void OnCookieChanged(const net::CanonicalCookie& cookie, bool removed, ChangeCause cause) override; +}; + +} + +#endif // COOKIE_MONSTER_DELEGATE_QT_H diff --git a/src/core/core.pro b/src/core/core.pro index cf00f39cb..7f19a48ce 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -8,12 +8,16 @@ core_gyp_generator.file = core_gyp_generator.pro gyp_run.file = gyp_run.pro gyp_run.depends = core_gyp_generator +core_api.file = api/core_api.pro +core_api.depends = gyp_run + # This will take the compile output of ninja, and link+deploy the final binary. core_module.file = core_module.pro -core_module.depends = gyp_run +core_module.depends = core_api SUBDIRS += core_gyp_generator \ gyp_run \ + core_api \ core_module !win32 { diff --git a/src/core/core_common.pri b/src/core/core_common.pri index cefde4302..1ea4e1862 100644 --- a/src/core/core_common.pri +++ b/src/core/core_common.pri @@ -6,7 +6,7 @@ QT += qml quick webchannel QT_PRIVATE += quick-private gui-private core-private # Make QtCreator happy. -CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$${getChromiumSrcDir()} +CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() INCLUDEPATH += $$CHROMIUM_SRC_DIR qtHaveModule(positioning):QT += positioning diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index c745fd19e..1a2679a60 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -18,14 +18,14 @@ DEFINES += QT_NO_KEYWORDS \ # Assume that we want mobile touch and low-end hardware behaviors # whenever we are cross compiling. -cross_compile: DEFINES += QTWEBENGINE_MOBILE_SWITCHES +cross_compile: DEFINES += QTWEBENGINE_EMBEDDED_SWITCHES contains(QT_CONFIG, egl): CONFIG += egl else: DEFINES += QT_NO_EGL RESOURCES += devtools.qrc -INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD $$PWD/api SOURCES = \ access_token_store_qt.cpp \ @@ -42,12 +42,14 @@ SOURCES = \ content_client_qt.cpp \ content_browser_client_qt.cpp \ content_main_delegate_qt.cpp \ + cookie_monster_delegate_qt.cpp \ custom_protocol_handler.cpp \ custom_url_scheme_handler.cpp \ delegated_frame_node.cpp \ desktop_screen_qt.cpp \ dev_tools_http_handler_delegate_qt.cpp \ download_manager_delegate_qt.cpp \ + file_picker_controller.cpp \ gl_context_qt.cpp \ gl_surface_qt.cpp \ javascript_dialog_controller.cpp \ @@ -56,11 +58,19 @@ SOURCES = \ native_web_keyboard_event_qt.cpp \ network_delegate_qt.cpp \ ozone_platform_eglfs.cpp \ + permission_manager_qt.cpp \ process_main.cpp \ + proxy_config_service_qt.cpp \ + proxy_resolver_qt.cpp \ qrc_protocol_handler_qt.cpp \ qt_render_view_observer_host.cpp \ render_widget_host_view_qt.cpp \ renderer/content_renderer_client_qt.cpp \ + renderer/pepper/pepper_flash_browser_host_qt.cpp \ + renderer/pepper/pepper_flash_renderer_host_qt.cpp \ + renderer/pepper/pepper_host_factory_qt.cpp \ + renderer/pepper/pepper_renderer_host_factory_qt.cpp \ + renderer/qt_render_frame_observer.cpp \ renderer/qt_render_view_observer.cpp \ renderer/user_script_controller.cpp \ renderer/web_channel_ipc_transport.cpp \ @@ -103,6 +113,7 @@ HEADERS = \ content_client_qt.h \ content_browser_client_qt.h \ content_main_delegate_qt.h \ + cookie_monster_delegate_qt.h \ custom_protocol_handler.h \ custom_url_scheme_handler.h \ delegated_frame_node.h \ @@ -110,6 +121,7 @@ HEADERS = \ dev_tools_http_handler_delegate_qt.h \ download_manager_delegate_qt.h \ chromium_gpu_helper.h \ + file_picker_controller.h \ gl_context_qt.h \ gl_surface_qt.h \ javascript_dialog_controller_p.h \ @@ -118,13 +130,20 @@ HEADERS = \ media_capture_devices_dispatcher.h \ network_delegate_qt.h \ ozone_platform_eglfs.h \ + permission_manager_qt.h \ process_main.h \ + proxy_config_service_qt.h \ + proxy_resolver_qt.h \ qrc_protocol_handler_qt.h \ qt_render_view_observer_host.h \ - qtwebenginecoreglobal.h \ render_widget_host_view_qt.h \ render_widget_host_view_qt_delegate.h \ renderer/content_renderer_client_qt.h \ + renderer/pepper/pepper_flash_browser_host_qt.h \ + renderer/pepper/pepper_flash_renderer_host_qt.h \ + renderer/pepper/pepper_host_factory_qt.h \ + renderer/pepper/pepper_renderer_host_factory_qt.h \ + renderer/qt_render_frame_observer.h \ renderer/qt_render_view_observer.h \ renderer/user_script_controller.h \ renderer/web_channel_ipc_transport.h \ diff --git a/src/core/core_module.pro b/src/core/core_module.pro index e6a36332f..291aac916 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -9,10 +9,28 @@ QMAKE_INFO_PLIST = Info_mac.plist error("Could not find the linking information that gyp should have generated.") } -# We distribute the module binary but headers are only available in-tree. -CONFIG += no_module_headers +QMAKE_DOCS = $$PWD/doc/qtwebenginecore.qdocconf + load(qt_module) +api_library_name = qtwebenginecoreapi +api_library_path = $$OUT_PWD/api/$$getConfigDir() +LIBS_PRIVATE += -L$$api_library_path +CONFIG *= no_smart_library_merge +osx { + LIBS_PRIVATE += -Wl,-force_load,$${api_library_path}$${QMAKE_DIR_SEP}lib$${api_library_name}.a +} else:win32-msvc* { + LIBS_PRIVATE += /OPT:REF -l$$api_library_name +} else { + LIBS_PRIVATE += -Wl,-whole-archive -l$$api_library_name -Wl,-no-whole-archive +} + +win32-msvc* { + POST_TARGETDEPS += $${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib +} else { + POST_TARGETDEPS += $${api_library_path}$${QMAKE_DIR_SEP}lib$${api_library_name}.a +} + # Using -Wl,-Bsymbolic-functions seems to confuse the dynamic linker # and doesn't let Chromium get access to libc symbols through dlsym. CONFIG -= bsymbolic_functions @@ -31,17 +49,8 @@ resources.files = $$REPACK_DIR/qtwebengine_resources.pak \ $$REPACK_DIR/qtwebengine_resources_100p.pak \ $$REPACK_DIR/qtwebengine_resources_200p.pak -PLUGIN_EXTENSION = .so -PLUGIN_PREFIX = lib -osx: PLUGIN_PREFIX = -win32 { - PLUGIN_EXTENSION = .dll - PLUGIN_PREFIX = -} icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat -plugins.files = $$OUT_PWD/$$getConfigDir()/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_EXTENSION} - !debug_and_release|!build_all|CONFIG(release, debug|release) { contains(QT_CONFIG, qt_framework) { locales.version = Versions @@ -50,12 +59,10 @@ plugins.files = $$OUT_PWD/$$getConfigDir()/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_ resources.path = Resources icu.version = Versions icu.path = Resources - plugins.version = Versions - plugins.path = Libraries # No files, this prepares the bundle Helpers symlink, process.pro will create the directories qtwebengineprocessplaceholder.version = Versions qtwebengineprocessplaceholder.path = Helpers - QMAKE_BUNDLE_DATA += icu locales resources plugins qtwebengineprocessplaceholder + QMAKE_BUNDLE_DATA += icu locales resources qtwebengineprocessplaceholder } else { locales.CONFIG += no_check_exist locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales @@ -63,9 +70,7 @@ plugins.files = $$OUT_PWD/$$getConfigDir()/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_ resources.path = $$[QT_INSTALL_DATA] icu.CONFIG += no_check_exist icu.path = $$[QT_INSTALL_DATA] - plugins.CONFIG += no_check_exist - plugins.path = $$[QT_INSTALL_PLUGINS]/qtwebengine - INSTALLS += icu locales resources plugins + INSTALLS += icu locales resources } !contains(QT_CONFIG, qt_framework): contains(QT_CONFIG, private_tests) { @@ -75,15 +80,7 @@ plugins.files = $$OUT_PWD/$$getConfigDir()/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_ unix: icu_rule.commands = if [ -e $$ICU_FILE ] ; then $$QMAKE_COPY $$ICU_FILE $$ICU_TARGET ; fi win32: icu_rule.commands = if exist $$ICU_FILE ( $$QMAKE_COPY $$ICU_FILE $$ICU_TARGET ) - PLUGIN_DIR = $$shell_path($$[QT_INSTALL_PLUGINS/get]/qtwebengine) - PLUGIN_TARGET = $$shell_path($$PLUGIN_DIR/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_EXTENSION}) - PLUGIN_FILE = $$shell_path($$OUT_PWD/$$getConfigDir()/$${PLUGIN_PREFIX}ffmpegsumo$${PLUGIN_EXTENSION}) - plugins_rule.target = $$PLUGIN_TARGET - unix: plugins_rule.commands = $$QMAKE_MKDIR $$PLUGIN_DIR && if [ -e $$PLUGIN_FILE ] ; then $$QMAKE_COPY $$PLUGIN_FILE $$PLUGIN_TARGET ; fi - win32: plugins_rule.commands = (if not exist $$PLUGIN_DIR ( $$QMAKE_MKDIR $$PLUGIN_DIR )) && \ - if exist $$PLUGIN_FILE ( $$QMAKE_COPY $$PLUGIN_FILE $$PLUGIN_TARGET ) - - QMAKE_EXTRA_TARGETS += icu_rule plugins_rule - PRE_TARGETDEPS += $$ICU_TARGET $$PLUGIN_TARGET + QMAKE_EXTRA_TARGETS += icu_rule + PRE_TARGETDEPS += $$ICU_TARGET } } diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index 6f79d4952..dee381e15 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -76,6 +76,10 @@ #include <EGL/eglext.h> #endif +#ifndef GL_TIMEOUT_IGNORED +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + namespace QtWebEngineCore { class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { @@ -205,7 +209,6 @@ static void waitChromiumSync(gfx::TransferableFence *sync) #endif break; case gfx::TransferableFence::ArbSync: -#ifdef GL_ARB_sync typedef void (QOPENGLF_APIENTRYP WaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout); static WaitSyncPtr glWaitSync_ = 0; if (!glWaitSync_) { @@ -214,7 +217,6 @@ static void waitChromiumSync(gfx::TransferableFence *sync) Q_ASSERT(glWaitSync_); } glWaitSync_(sync->arb.sync, 0, GL_TIMEOUT_IGNORED); -#endif break; } } @@ -250,7 +252,6 @@ static void deleteChromiumSync(gfx::TransferableFence *sync) #endif break; case gfx::TransferableFence::ArbSync: -#ifdef GL_ARB_sync typedef void (QOPENGLF_APIENTRYP DeleteSyncPtr)(GLsync sync); static DeleteSyncPtr glDeleteSync_ = 0; if (!glDeleteSync_) { @@ -260,7 +261,6 @@ static void deleteChromiumSync(gfx::TransferableFence *sync) } glDeleteSync_(sync->arb.sync); sync->reset(); -#endif break; } // If Chromium was able to create a sync, we should have been able to handle its type here too. @@ -409,7 +409,7 @@ void DelegatedFrameNode::preprocess() { QMutexLocker lock(&m_mutex); base::MessageLoop *gpuMessageLoop = gpu_message_loop(); - content::SyncPointManager *syncPointManager = sync_point_manager(); + gpu::SyncPointManager *syncPointManager = sync_point_manager(); Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { m_numPendingSyncPoints++; @@ -444,6 +444,20 @@ void DelegatedFrameNode::preprocess() } } +static YUVVideoMaterial::ColorSpace toQt(cc::YUVVideoDrawQuad::ColorSpace color_space) +{ + switch (color_space) { + case cc::YUVVideoDrawQuad::REC_601: + return YUVVideoMaterial::REC_601; + case cc::YUVVideoDrawQuad::REC_709: + return YUVVideoMaterial::REC_709; + case cc::YUVVideoDrawQuad::JPEG: + return YUVVideoMaterial::JPEG; + } + Q_UNREACHABLE(); + return YUVVideoMaterial::REC_601; +} + void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate) { m_chromiumCompositorData = chromiumCompositorData; @@ -560,7 +574,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, ResourceHolder *resource = findAndHoldResource(tquad->resource_id, resourceCandidates); QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; - textureNode->setTextureCoordinatesTransform(tquad->flipped ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform); + textureNode->setTextureCoordinatesTransform(tquad->y_flipped ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform); textureNode->setRect(toQt(quad->rect)); textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); @@ -628,7 +642,9 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), initAndHoldTexture(uResource, quad->ShouldDrawWithBlending()), initAndHoldTexture(vResource, quad->ShouldDrawWithBlending()), - aResource ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) : 0, toQt(vquad->tex_coord_rect)); + aResource ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) : 0, + toQt(vquad->ya_tex_coord_rect), toQt(vquad->uv_tex_coord_rect), + toQt(vquad->ya_tex_size), toQt(vquad->uv_tex_size), toQt(vquad->color_space)); videoNode->setRect(toQt(quad->rect)); currentLayerChain->appendChildNode(videoNode); break; diff --git a/src/core/dev_tools_http_handler_delegate_qt.cpp b/src/core/dev_tools_http_handler_delegate_qt.cpp index 964d6ad38..2afd75e6e 100644 --- a/src/core/dev_tools_http_handler_delegate_qt.cpp +++ b/src/core/dev_tools_http_handler_delegate_qt.cpp @@ -49,9 +49,11 @@ #include "base/files/file_path.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "components/devtools_discovery/devtools_discovery_manager.h" +#include "components/devtools_discovery/devtools_target_descriptor.h" +#include "components/devtools_http_handler/devtools_http_handler.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/devtools_frontend_host.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" @@ -59,14 +61,18 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/content_switches.h" #include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" #include "net/socket/stream_listen_socket.h" #include "net/socket/tcp_server_socket.h" using namespace content; +using namespace devtools_discovery; +using namespace devtools_http_handler; namespace { const char kTargetTypePage[] = "page"; +const char kTargetTypeSharedWorker[] = "worker"; const char kTargetTypeServiceWorker[] = "service_worker"; const char kTargetTypeOther[] = "other"; @@ -74,15 +80,29 @@ class TCPServerSocketFactory : public DevToolsHttpHandler::ServerSocketFactory { public: TCPServerSocketFactory(const std::string& address, int port, int backlog) - : DevToolsHttpHandler::ServerSocketFactory(address, port, backlog) {} + : m_address(address), m_port(port), m_backlog(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); + scoped_ptr<net::ServerSocket> CreateForHttpServer() override { + scoped_ptr<net::ServerSocket> socket(new net::TCPServerSocket(nullptr, net::NetLog::Source())); + if (socket->ListenWithAddressAndPort(m_address, m_port, m_backlog) != net::OK) + return scoped_ptr<net::ServerSocket>(); + + return socket; + } + + const std::string m_address; + int m_port; + int m_backlog; + DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory); }; -class Target : public content::DevToolsTarget { +class DevToolsDiscoveryProviderQt : public DevToolsDiscoveryManager::Provider { +public: + DevToolsTargetDescriptor::List GetDescriptors() override; +}; + +class Target : public DevToolsTargetDescriptor { public: explicit Target(scoped_refptr<DevToolsAgentHost> agent_host); @@ -92,6 +112,8 @@ public: switch (agent_host_->GetType()) { case DevToolsAgentHost::TYPE_WEB_CONTENTS: return kTargetTypePage; + case DevToolsAgentHost::TYPE_SHARED_WORKER: + return kTargetTypeSharedWorker; case DevToolsAgentHost::TYPE_SERVICE_WORKER: return kTargetTypeServiceWorker; default: @@ -141,17 +163,40 @@ bool Target::Close() const { return agent_host_->Close(); } +DevToolsTargetDescriptor::List DevToolsDiscoveryProviderQt::GetDescriptors() +{ + DevToolsTargetDescriptor::List targets; + for (const auto& agent_host : DevToolsAgentHost::GetOrCreateAll()) { + targets.push_back(new Target(agent_host)); + } + return targets; +} + } // namespace namespace QtWebEngineCore { +scoped_ptr<DevToolsHttpHandler> createDevToolsHttpHandler() +{ + DevToolsHttpHandlerDelegateQt *delegate = new DevToolsHttpHandlerDelegateQt(); + if (!delegate->isValid()) { + delete delegate; + return nullptr; + } + scoped_ptr<DevToolsHttpHandler::ServerSocketFactory> factory(new TCPServerSocketFactory(delegate->bindAddress().toStdString(), delegate->port(), 1)); + // Ownership of the delegate is taken over the devtools http handler. + scoped_ptr<DevToolsHttpHandler> handler(new DevToolsHttpHandler(factory.Pass(), std::string(), delegate, base::FilePath(), base::FilePath(), std::string(), std::string())); + DevToolsDiscoveryManager::GetInstance()->AddProvider(scoped_ptr<DevToolsDiscoveryManager::Provider>(new DevToolsDiscoveryProviderQt())); + return handler; +} + DevToolsHttpHandlerDelegateQt::DevToolsHttpHandlerDelegateQt() - : m_devtoolsHttpHandler(0) - , m_bindAddress(QLatin1String("127.0.0.1")) + : m_bindAddress(QLatin1String("127.0.0.1")) , m_port(0) + , m_valid(false) { const QString inspectorEnv = QString::fromUtf8(qgetenv("QTWEBENGINE_REMOTE_DEBUGGING")); - const CommandLine &commandLine = *CommandLine::ForCurrentProcess(); + const base::CommandLine &commandLine = *base::CommandLine::ForCurrentProcess(); QString portStr; if (commandLine.HasSwitch(switches::kRemoteDebuggingPort)) { @@ -166,26 +211,16 @@ DevToolsHttpHandlerDelegateQt::DevToolsHttpHandlerDelegateQt() } 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 + m_port = portStr.toInt(&m_valid); + m_valid = m_valid && m_port > 0 && m_port < 65535; + if (!m_valid) 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() -{ - // Stop() takes care of deleting the DevToolsHttpHandler. - if (m_devtoolsHttpHandler) - m_devtoolsHttpHandler->Stop(); -} - -void DevToolsHttpHandlerDelegateQt::Initialized(const net::IPEndPoint& ip_address) +void DevToolsHttpHandlerDelegateQt::Initialized(const net::IPEndPoint *ip_address) { - if (ip_address.address().size()) { - QString addressAndPort = QString::fromStdString(ip_address.ToString()); + if (ip_address && 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); @@ -203,42 +238,19 @@ std::string DevToolsHttpHandlerDelegateQt::GetDiscoveryPageHTML() return html; } -bool DevToolsHttpHandlerDelegateQt::BundlesFrontendResources() -{ - return true; -} - -base::FilePath DevToolsHttpHandlerDelegateQt::GetDebugFrontendDir() -{ - return base::FilePath(); -} - -scoped_ptr<net::StreamListenSocket> DevToolsHttpHandlerDelegateQt::CreateSocketForTethering(net::StreamListenSocket::Delegate* delegate, std::string* name) -{ - return scoped_ptr<net::StreamListenSocket>(); -} - -base::DictionaryValue* DevToolsManagerDelegateQt::HandleCommand(DevToolsAgentHost *, base::DictionaryValue *) { - return 0; -} - -std::string DevToolsManagerDelegateQt::GetPageThumbnailData(const GURL& url) +std::string DevToolsHttpHandlerDelegateQt::GetPageThumbnailData(const GURL& url) { return std::string(); } -scoped_ptr<DevToolsTarget> DevToolsManagerDelegateQt::CreateNewTarget(const GURL &) +std::string DevToolsHttpHandlerDelegateQt::GetFrontendResource(const std::string &path) { - return scoped_ptr<DevToolsTarget>(); + return content::DevToolsFrontendHost::GetFrontendResource(path).as_string(); } -void DevToolsManagerDelegateQt::EnumerateTargets(TargetCallback callback) +base::DictionaryValue* DevToolsManagerDelegateQt::HandleCommand(DevToolsAgentHost *, base::DictionaryValue *) { - TargetList targets; - for (const auto& agent_host : DevToolsAgentHost::GetOrCreateAll()) { - targets.push_back(new Target(agent_host)); - } - callback.Run(targets); + return 0; } } //namespace QtWebEngineCore diff --git a/src/core/dev_tools_http_handler_delegate_qt.h b/src/core/dev_tools_http_handler_delegate_qt.h index 902e99507..b998359fd 100644 --- a/src/core/dev_tools_http_handler_delegate_qt.h +++ b/src/core/dev_tools_http_handler_delegate_qt.h @@ -37,43 +37,43 @@ #ifndef DEV_TOOLS_HTTP_HANDLER_DELEGATE_QT_H #define DEV_TOOLS_HTTP_HANDLER_DELEGATE_QT_H -#include "content/public/browser/devtools_http_handler_delegate.h" +#include "components/devtools_http_handler/devtools_http_handler_delegate.h" #include "content/public/browser/devtools_manager_delegate.h" +#include "net/socket/stream_listen_socket.h" #include <QString> #include <QtCore/qcompilerdetection.h> // needed for Q_DECL_OVERRIDE -namespace net { -class StreamListenSocket; -} - namespace content { class BrowserContext; +} + +namespace devtools_http_handler { class DevToolsHttpHandler; -class RenderViewHost; } namespace QtWebEngineCore { -class DevToolsHttpHandlerDelegateQt : public content::DevToolsHttpHandlerDelegate { -public: +scoped_ptr<devtools_http_handler::DevToolsHttpHandler> createDevToolsHttpHandler(); +class DevToolsHttpHandlerDelegateQt : public devtools_http_handler::DevToolsHttpHandlerDelegate { +public: 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; - // Requests the list of all inspectable targets. - // The caller gets the ownership of the returned targets. - virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(net::StreamListenSocket::Delegate *delegate, std::string *name) Q_DECL_OVERRIDE; + bool isValid() const { return m_valid; } + QString bindAddress() const { return m_bindAddress; } + int port() const { return m_port; } + + // devtools_http_handler::DevToolsHttpHandlerDelegate Overrides + void Initialized(const net::IPEndPoint *ip_address) Q_DECL_OVERRIDE; + std::string GetDiscoveryPageHTML() Q_DECL_OVERRIDE; + std::string GetFrontendResource(const std::string&) Q_DECL_OVERRIDE; + std::string GetPageThumbnailData(const GURL &url) Q_DECL_OVERRIDE; private: - content::DevToolsHttpHandler *m_devtoolsHttpHandler; QString m_bindAddress; int m_port; + bool m_valid; }; class DevToolsManagerDelegateQt : public content::DevToolsManagerDelegate { @@ -81,9 +81,6 @@ 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; }; } // namespace QtWebEngineCore diff --git a/src/core/doc/qtwebenginecore.qdocconf b/src/core/doc/qtwebenginecore.qdocconf new file mode 100644 index 000000000..491447706 --- /dev/null +++ b/src/core/doc/qtwebenginecore.qdocconf @@ -0,0 +1,32 @@ +include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) + +project = QtWebEngineCore +description = Qt WebEngineCore Reference Documentation +version = $QT_VERSION + +qhp.projects = QtWebEngineCore + +qhp.QtWebEngineCore.file = qtwebenginecore.qhp +qhp.QtWebEngineCore.namespace = org.qt-project.qtwebenginecore.$QT_VERSION_TAG +qhp.QtWebEngineCore.virtualFolder = qtwebenginecore +qhp.QtWebEngineCore.indexTitle = Qt WebEngine Core +qhp.QtWebEngineCore.indexRoot = + +qhp.QtWebEngineCore.filterAttributes = qtwebenginecore $QT_VERSION qtrefdoc +qhp.QtWebEngineCore.customFilters.Qt.name = QtWebEngineCore $QT_VERSION +qhp.QtWebEngineCore.customFilters.Qt.filterAttributes = qtwebenginecore $QT_VERSION +qhp.QtWebEngineCore.subprojects = classes +qhp.QtWebEngineCore.subprojects.classes.title = C++ Classes +qhp.QtWebEngineCore.subprojects.classes.indexTitle = Qt WebEngine Core C++ Classes +qhp.QtWebEngineCore.subprojects.classes.selectors = class fake:headerfile +qhp.QtWebEngineCore.subprojects.classes.sortPages = true + +depends += qtcore qtdoc qmake + +headerdirs += ../api +sourcedirs += ../api src + +exampledirs += snippets + +navigation.landingpage = "Qt WebEngine Core" +navigation.cppclassespage = "Qt WebEngine Core C++ Class Types" diff --git a/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc b/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc new file mode 100644 index 000000000..4806359c9 --- /dev/null +++ b/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc @@ -0,0 +1,8 @@ +//! [0] +QT += webenginecore +//! [0] + + +//! [1] +#include <QtWebEngineCore> +//! [1] diff --git a/src/core/doc/src/qtwebenginecore.qdoc b/src/core/doc/src/qtwebenginecore.qdoc new file mode 100644 index 000000000..a690d3f0e --- /dev/null +++ b/src/core/doc/src/qtwebenginecore.qdoc @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +/*! + \module QtWebEngineCore + \title Qt WebEngine Core C++ Classes + \brief Provides public API shared by both QtWebEngine and QtWebEngineWidgets + \since 5.6 + + To include the definitions of the module's classes, use the + following directive: + + \snippet qtwebenginecore_build_snippet.qdoc 1 + + If you use qmake to build your projects, Qt WebEngine Core is usually + indirectly included through the \l[QtWebEngine]{Qt WebEngine} or + \l[QtWebEngineWidgets]{Qt WebEngine Widgets} modules. +*/ + +/*! + \page qtwebenginecore-index.html + \title Qt WebEngine Core + \ingroup modules + + \brief Common API shared by both Qt WebEngine and Qt WebEngine Widgets. + + Qt WebEngine Core provides API shared by both Qt WebEngine and + Qt WebEngine Widgets. + + + \section1 License Information + This is a snapshot of the integration of Chromium into Qt. + + Qt Commercial Edition licensees that wish to distribute applications that + use the Qt WebEngine module need to be aware of their obligations under the + GNU Library General Public License (LGPLv2). + + Developers using the Open Source Edition can choose to redistribute + the module under the GNU LGPLv3 or GPLv2 and up. + + \legalese + + Chromium is licensed under the following license: + + Copyright (c) 2013 The Chromium Authors. All rights reserved. + + 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 Google Inc. 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. + + \endlegalese +*/ diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp new file mode 100644 index 000000000..18896c6b4 --- /dev/null +++ b/src/core/file_picker_controller.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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 "file_picker_controller.h" +#include "type_conversion.h" +#include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" + +#include <QFileInfo> +#include <QDir> +#include <QVariant> +#include <QStringList> + +namespace QtWebEngineCore { + +FilePickerController::FilePickerController(FileChooserMode mode, content::WebContents *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) + : QObject(parent) + , m_defaultFileName(defaultFileName) + , m_acceptedMimeTypes(acceptedMimeTypes) + , m_contents(contents) + , m_mode(mode) +{ +} + +void FilePickerController::accepted(const QStringList &files) +{ + FilePickerController::filesSelectedInChooser(files, m_contents); +} + +void FilePickerController::accepted(const QVariant &files) +{ + QStringList stringList; + + if (files.canConvert(QVariant::StringList)) { + stringList = files.toStringList(); + } else if (files.canConvert<QList<QUrl> >()) { + Q_FOREACH (const QUrl &url, files.value<QList<QUrl> >()) + stringList.append(url.toLocalFile()); + } else { + qWarning("An unhandled type '%s' was provided in FilePickerController::accepted(QVariant)", files.typeName()); + } + + FilePickerController::filesSelectedInChooser(stringList, m_contents); +} + +void FilePickerController::rejected() +{ + FilePickerController::filesSelectedInChooser(QStringList(), m_contents); +} + +static QStringList listRecursively(const QDir &dir) +{ + QStringList ret; + QFileInfoList infoList(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden)); + Q_FOREACH (const QFileInfo &fileInfo, infoList) { + if (fileInfo.isDir()) { + ret.append(fileInfo.absolutePath() + QStringLiteral("/.")); // Match chromium's behavior. See chrome/browser/file_select_helper.cc + ret.append(listRecursively(QDir(fileInfo.absoluteFilePath()))); + } else + ret.append(fileInfo.absoluteFilePath()); + } + return ret; +} + +ASSERT_ENUMS_MATCH(FilePickerController::Open, content::FileChooserParams::Open) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParams::OpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) +ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) + +void FilePickerController::filesSelectedInChooser(const QStringList &filesList, content::WebContents *contents) +{ + content::RenderViewHost *rvh = contents->GetRenderViewHost(); + Q_ASSERT(rvh); + QStringList files(filesList); + if (this->m_mode == UploadFolder && !filesList.isEmpty() + && QFileInfo(filesList.first()).isDir()) // Enumerate the directory + files = listRecursively(QDir(filesList.first())); + rvh->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(this->m_mode)); +} + +QStringList FilePickerController::acceptedMimeTypes() +{ + return m_acceptedMimeTypes; +} + +FilePickerController::FileChooserMode FilePickerController::mode() +{ + return m_mode; +} + +QString FilePickerController::defaultFileName() +{ + return m_defaultFileName; +} + +} // namespace diff --git a/src/core/file_picker_controller.h b/src/core/file_picker_controller.h new file mode 100644 index 000000000..347dd11ef --- /dev/null +++ b/src/core/file_picker_controller.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 FILE_PICKER_CONTROLLER_H +#define FILE_PICKER_CONTROLLER_H + +#include "qtwebenginecoreglobal.h" +#include <QObject> +#include <QStringList> + +namespace content { + class WebContents; +} + +namespace QtWebEngineCore { + +class QWEBENGINE_EXPORT FilePickerController : public QObject { + Q_OBJECT +public: + enum FileChooserMode { + Open, + OpenMultiple, + UploadFolder, + Save + }; + + FilePickerController(FileChooserMode mode, content::WebContents *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); + QStringList acceptedMimeTypes(); + QString defaultFileName(); + FileChooserMode mode(); + void filesSelectedInChooser(const QStringList &filesList, content::WebContents *contents); + +public Q_SLOTS: + void accepted(const QStringList &files); + void accepted(const QVariant &files); + void rejected(); + +private: + QString m_defaultFileName; + QStringList m_acceptedMimeTypes; + content::WebContents *m_contents; + FileChooserMode m_mode; + +}; + +} // namespace + +#endif // FILE_PICKER_CONTROLLER_H diff --git a/src/core/gl_surface_qt.cpp b/src/core/gl_surface_qt.cpp index 584bdc227..c905688ce 100644 --- a/src/core/gl_surface_qt.cpp +++ b/src/core/gl_surface_qt.cpp @@ -44,7 +44,7 @@ #include <QGuiApplication> #include "gl_context_qt.h" -#include "qtwebenginecoreglobal.h" +#include "qtwebenginecoreglobal_p.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" @@ -533,6 +533,22 @@ GLSurface::CreateViewGLSurface(gfx::AcceleratedWidget window) return NULL; } +std::string DriverEGL::GetPlatformExtensions() +{ +#if defined(USE_X11) + EGLNativeDisplayType nativeDisplay = reinterpret_cast<EGLNativeDisplayType>(GLContextHelper::getXDisplay()); + EGLDisplay display = eglGetDisplay(nativeDisplay); +#else + EGLDisplay display = GLContextHelper::getEGLDisplay(); +#endif + if (display == EGL_NO_DISPLAY) + return ""; + + DCHECK(g_driver_egl.fn.eglQueryStringFn); + const char* str = g_driver_egl.fn.eglQueryStringFn(display, EGL_EXTENSIONS); + return str ? std::string(str) : ""; +} + } // namespace gfx namespace content { diff --git a/src/core/gl_surface_qt.h b/src/core/gl_surface_qt.h index 21c46e699..4b5da207e 100644 --- a/src/core/gl_surface_qt.h +++ b/src/core/gl_surface_qt.h @@ -39,7 +39,7 @@ #ifndef GL_SURFACE_QT_H_ #define GL_SURFACE_QT_H_ -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" #include "ui/gl/gl_surface.h" #include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro index 3f631302c..bb19a679d 100644 --- a/src/core/gyp_run.pro +++ b/src/core/gyp_run.pro @@ -85,7 +85,7 @@ cross_compile { contains(QT_ARCH, "x86_64"): GYP_ARGS += "-D target_arch=x64" contains(QT_ARCH, "i386"): GYP_ARGS += "-D target_arch=ia32" -contains(WEBENGINE_CONFIG, proprietary_codecs): GYP_ARGS += "-Dproprietary_codecs=1 -Dffmpeg_branding=Chrome -Duse_system_ffmpeg=0" +contains(WEBENGINE_CONFIG, use_proprietary_codecs): GYP_ARGS += "-Dproprietary_codecs=1 -Dffmpeg_branding=Chrome -Duse_system_ffmpeg=0" !contains(QT_CONFIG, qt_framework): contains(QT_CONFIG, private_tests) { GYP_ARGS += "-D qt_install_data=\"$$[QT_INSTALL_DATA/get]\"" diff --git a/src/core/javascript_dialog_manager_qt.h b/src/core/javascript_dialog_manager_qt.h index 4682ce5b8..8bf7ac6b9 100644 --- a/src/core/javascript_dialog_manager_qt.h +++ b/src/core/javascript_dialog_manager_qt.h @@ -66,8 +66,7 @@ public: const content::JavaScriptDialogManager::DialogClosedCallback &callback) Q_DECL_OVERRIDE { Q_UNUSED(messageText); Q_UNUSED(isReload); Q_UNUSED(callback); } virtual bool HandleJavaScriptDialog(content::WebContents *, bool accept, const base::string16 *promptOverride) Q_DECL_OVERRIDE; virtual void CancelActiveAndPendingDialogs(content::WebContents *contents) Q_DECL_OVERRIDE { takeDialogForContents(contents); } - virtual void WebContentsDestroyed(content::WebContents *contents) Q_DECL_OVERRIDE { takeDialogForContents(contents); } - + virtual void ResetDialogState(content::WebContents *contents) Q_DECL_OVERRIDE { takeDialogForContents(contents); } void runDialogForContents(content::WebContents *, WebContentsAdapterClient::JavascriptDialogType, const QString &messageText, const QString &defaultPrompt , const QUrl &,const content::JavaScriptDialogManager::DialogClosedCallback &callback, const QString &title = QString()); diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index 6866afc41..605a17948 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -91,9 +91,8 @@ scoped_ptr<content::MediaStreamUI> getDevicesForDesktopCapture(content::MediaStr devices.push_back(content::MediaStreamDevice( content::MEDIA_DESKTOP_VIDEO_CAPTURE, mediaId.ToString(), "Screen")); if (captureAudio) { - // Use the special loopback device ID for system audio capture. devices.push_back(content::MediaStreamDevice( - content::MEDIA_LOOPBACK_AUDIO_CAPTURE, + content::MEDIA_DESKTOP_AUDIO_CAPTURE, media::AudioManagerBase::kLoopbackInputDeviceId, "System Audio")); } @@ -225,7 +224,7 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(WebContentsAdapter if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE || request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) return; - if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || request.audio_type == content::MEDIA_LOOPBACK_AUDIO_CAPTURE) + if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) // It's still unclear what to make of screen capture. We can rely on existing javascript dialog infrastructure // to experiment with this without exposing it through our API yet. processDesktopCaptureAccessRequest(webContents, request, callback); @@ -279,7 +278,7 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content:: // Audio is only supported for screen capture streams. bool capture_audio = (mediaId.type == content::DesktopMediaID::TYPE_SCREEN && - request.audio_type == content::MEDIA_LOOPBACK_AUDIO_CAPTURE); + request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE); ui = getDevicesForDesktopCapture( devices, mediaId, capture_audio, true, diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index 4e726fec8..5af781007 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -36,31 +36,37 @@ #include "network_delegate_qt.h" +#include "browser_context_adapter.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_request_details.h" #include "content/public/browser/resource_request_info.h" +#include "cookie_monster_delegate_qt.h" #include "ui/base/page_transition_types.h" +#include "url_request_context_getter_qt.h" #include "net/base/load_flags.h" #include "net/url_request/url_request.h" +#include "qwebengineurlrequestinfo.h" +#include "qwebengineurlrequestinfo_p.h" +#include "qwebengineurlrequestinterceptor.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" #include "web_contents_view_qt.h" namespace QtWebEngineCore { -int pageTransitionToNavigationType(ui::PageTransition transition) +static int pageTransitionToNavigationType(ui::PageTransition transition) { int32 qualifier = ui::PageTransitionGetQualifier(transition); if (qualifier & ui::PAGE_TRANSITION_FORWARD_BACK) return WebContentsAdapterClient::BackForwardNavigation; - ui::PageTransition stippedTransition = ui::PageTransitionStripQualifier(transition); + ui::PageTransition strippedTransition = ui::PageTransitionStripQualifier(transition); - switch (stippedTransition) { + switch (strippedTransition) { case ui::PAGE_TRANSITION_LINK: - return WebContentsAdapterClient::LinkClickedNavigation; + return WebContentsAdapterClient::LinkNavigation; case ui::PAGE_TRANSITION_TYPED: return WebContentsAdapterClient::TypedNavigation; case ui::PAGE_TRANSITION_FORM_SUBMIT: @@ -72,29 +78,68 @@ int pageTransitionToNavigationType(ui::PageTransition transition) } } -int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::CompletionCallback &callback, GURL *) +NetworkDelegateQt::NetworkDelegateQt(URLRequestContextGetterQt *requestContext) + : m_requestContextGetter(requestContext) +{ +} + +int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::CompletionCallback &callback, GURL *newUrl) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request); - if (!info) + Q_ASSERT(m_requestContextGetter); + Q_ASSERT(m_requestContextGetter->m_browserContext); + + const content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request); + + content::ResourceType resourceType = content::RESOURCE_TYPE_LAST_TYPE; + int navigationType = QWebEngineUrlRequestInfo::NavigationTypeOther; + + if (resourceInfo) { + resourceType = resourceInfo->GetResourceType(); + navigationType = pageTransitionToNavigationType(resourceInfo->GetPageTransition()); + } + + const QUrl qUrl = toQt(request->url()); + + QWebEngineUrlRequestInterceptor* interceptor = m_requestContextGetter->m_browserContext->requestInterceptor(); + if (interceptor) { + QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType) + , static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType) + , qUrl + , QByteArray::fromStdString(request->method())); + QWebEngineUrlRequestInfo requestInfo(infoPrivate); + if (interceptor->interceptRequest(requestInfo)) { + int result = infoPrivate->shouldBlockRequest ? net::ERR_ABORTED : net::OK; + + if (qUrl != infoPrivate->url) + *newUrl = toGurl(infoPrivate->url); + + if (!infoPrivate->extraHeaders.isEmpty()) { + auto end = infoPrivate->extraHeaders.constEnd(); + for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) + request->SetExtraRequestHeaderByName(header.key().toStdString(), header.value().toStdString(), /* overwrite */ true); + } + + return result; + } + } + + if (!resourceInfo) return net::OK; - content::ResourceType resourceType = info->GetResourceType(); int renderProcessId; int renderFrameId; // Only intercept MAIN_FRAME and SUB_FRAME with an associated render frame. - if (!content::IsResourceTypeFrame(resourceType) || !info->GetRenderFrameForRequest(request, &renderProcessId, &renderFrameId)) + if (!content::IsResourceTypeFrame(resourceType) || !resourceInfo->GetRenderFrameForRequest(request, &renderProcessId, &renderFrameId)) return net::OK; // Track active requests since |callback| and |new_url| are valid // only until OnURLRequestDestroyed is called for this request. m_activeRequests.insert(request); - int navigationType = pageTransitionToNavigationType(info->GetPageTransition()); - RequestParams params = { - toQt(request->url()), - info->IsMainFrame(), + qUrl, + resourceInfo->IsMainFrame(), navigationType, renderProcessId, renderFrameId @@ -172,4 +217,92 @@ void NetworkDelegateQt::NotifyNavigationRequestedOnUIThread(net::URLRequest *req ); } +bool NetworkDelegateQt::OnCanSetCookie(const net::URLRequest& request, + const std::string& cookie_line, + net::CookieOptions*) +{ + return true; +} + +void NetworkDelegateQt::OnResolveProxy(const GURL&, int, const net::ProxyService&, net::ProxyInfo*) +{ +} + +void NetworkDelegateQt::OnProxyFallback(const net::ProxyServer&, int) +{ +} + +int NetworkDelegateQt::OnBeforeSendHeaders(net::URLRequest*, const net::CompletionCallback&, net::HttpRequestHeaders*) +{ + return net::OK; +} + +void NetworkDelegateQt::OnBeforeSendProxyHeaders(net::URLRequest*, const net::ProxyInfo&, net::HttpRequestHeaders*) +{ +} + +void NetworkDelegateQt::OnSendHeaders(net::URLRequest*, const net::HttpRequestHeaders&) +{ +} + +int NetworkDelegateQt::OnHeadersReceived(net::URLRequest*, const net::CompletionCallback&, const net::HttpResponseHeaders*, scoped_refptr<net::HttpResponseHeaders>*, GURL*) +{ + return net::OK; +} + +void NetworkDelegateQt::OnBeforeRedirect(net::URLRequest*, const GURL&) +{ +} + +void NetworkDelegateQt::OnResponseStarted(net::URLRequest*) +{ +} + +void NetworkDelegateQt::OnRawBytesRead(const net::URLRequest&, int) +{ +} + +void NetworkDelegateQt::OnCompleted(net::URLRequest*, bool) +{ +} + +void NetworkDelegateQt::OnPACScriptError(int, const base::string16&) +{ +} + +net::NetworkDelegate::AuthRequiredResponse NetworkDelegateQt::OnAuthRequired(net::URLRequest*, const net::AuthChallengeInfo&, const AuthCallback&, net::AuthCredentials*) +{ + return AUTH_REQUIRED_RESPONSE_NO_ACTION; +} + +bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest&, const net::CookieList&) +{ + return true; +} + +bool NetworkDelegateQt::OnCanAccessFile(const net::URLRequest& request, const base::FilePath& path) const +{ + return true; +} + +bool NetworkDelegateQt::OnCanThrottleRequest(const net::URLRequest&) const +{ + return false; +} + +bool NetworkDelegateQt::OnCanEnablePrivacyMode(const GURL&, const GURL&) const +{ + return false; +} + +bool NetworkDelegateQt::OnFirstPartyOnlyCookieExperimentEnabled() const +{ + return false; +} + +bool NetworkDelegateQt::OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest&, const GURL&, const GURL&) const +{ + return false; +} + } // namespace QtWebEngineCore diff --git a/src/core/network_delegate_qt.h b/src/core/network_delegate_qt.h index 4f4097fd3..1176f99d9 100644 --- a/src/core/network_delegate_qt.h +++ b/src/core/network_delegate_qt.h @@ -42,19 +42,16 @@ #include <QUrl> #include <QSet> -#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE namespace QtWebEngineCore { +class URLRequestContextGetterQt; + class NetworkDelegateQt : public net::NetworkDelegate { + QSet<net::URLRequest *> m_activeRequests; + URLRequestContextGetterQt *m_requestContextGetter; public: - NetworkDelegateQt() {} - virtual ~NetworkDelegateQt() {} - - // net::NetworkDelegate implementation - virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) Q_DECL_OVERRIDE; - virtual void OnURLRequestDestroyed(net::URLRequest* request) Q_DECL_OVERRIDE; - virtual bool OnCanAccessFile(const net::URLRequest& request, const base::FilePath& path) const Q_DECL_OVERRIDE { return true; } + NetworkDelegateQt(URLRequestContextGetterQt *requestContext); struct RequestParams { QUrl url; @@ -72,7 +69,28 @@ public: int navigationRequestAction, const net::CompletionCallback &callback); - QSet<net::URLRequest *> m_activeRequests; + // net::NetworkDelegate implementation + virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* newUrl) override; + virtual void OnURLRequestDestroyed(net::URLRequest* request) override; + virtual bool OnCanSetCookie(const net::URLRequest&, const std::string&, net::CookieOptions*) override; + virtual void OnResolveProxy(const GURL&, int, const net::ProxyService&, net::ProxyInfo*) override; + virtual void OnProxyFallback(const net::ProxyServer&, int) override; + virtual int OnBeforeSendHeaders(net::URLRequest*, const net::CompletionCallback&, net::HttpRequestHeaders*) override; + virtual void OnBeforeSendProxyHeaders(net::URLRequest*, const net::ProxyInfo&, net::HttpRequestHeaders*) override; + virtual void OnSendHeaders(net::URLRequest*, const net::HttpRequestHeaders&) override; + virtual int OnHeadersReceived(net::URLRequest*, const net::CompletionCallback&, const net::HttpResponseHeaders*, scoped_refptr<net::HttpResponseHeaders>*, GURL*) override; + virtual void OnBeforeRedirect(net::URLRequest*, const GURL&) override; + virtual void OnResponseStarted(net::URLRequest*) override; + virtual void OnRawBytesRead(const net::URLRequest&, int) override; + virtual void OnCompleted(net::URLRequest*, bool) override; + virtual void OnPACScriptError(int, const base::string16&) override; + virtual net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(net::URLRequest*, const net::AuthChallengeInfo&, const AuthCallback&, net::AuthCredentials*) override; + virtual bool OnCanGetCookies(const net::URLRequest&, const net::CookieList&) override; + virtual bool OnCanAccessFile(const net::URLRequest& request, const base::FilePath& path) const override; + virtual bool OnCanThrottleRequest(const net::URLRequest&) const override; + virtual bool OnCanEnablePrivacyMode(const GURL&, const GURL&) const override; + virtual bool OnFirstPartyOnlyCookieExperimentEnabled() const override; + virtual bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest&, const GURL&, const GURL&) const override; }; } // namespace QtWebEngineCore diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp new file mode 100644 index 000000000..865874fe6 --- /dev/null +++ b/src/core/permission_manager_qt.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "permission_manager_qt.h" + +#include "content/public/browser/permission_type.h" +#include "content/public/browser/web_contents.h" + +#include "type_conversion.h" +#include "web_contents_delegate_qt.h" + +namespace QtWebEngineCore { + +BrowserContextAdapter::PermissionType toQt(content::PermissionType type) +{ + switch (type) { + case content::PermissionType::GEOLOCATION: + return BrowserContextAdapter::GeolocationPermission; + case content::PermissionType::NOTIFICATIONS: + case content::PermissionType::MIDI_SYSEX: + case content::PermissionType::PUSH_MESSAGING: + case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: + case content::PermissionType::NUM: + break; + } + return BrowserContextAdapter::UnsupportedPermission; +} + +PermissionManagerQt::PermissionManagerQt(BrowserContextAdapter *contextAdapter) + : m_contextAdapter(contextAdapter) + , m_subscriberCount(0) +{ +} + +PermissionManagerQt::~PermissionManagerQt() +{ +} + +void PermissionManagerQt::permissionRequestReply(const QUrl &origin, BrowserContextAdapter::PermissionType type, bool reply) +{ + QPair<QUrl, BrowserContextAdapter::PermissionType> key(origin, type); + m_permissions[key] = reply; + content::PermissionStatus status = reply ? content::PERMISSION_STATUS_GRANTED : content::PERMISSION_STATUS_DENIED; + auto it = m_requests.begin(); + const auto end = m_requests.end(); + while (it != end) { + if (it->origin == origin && it->type == type) { + it->callback.Run(status); + it = m_requests.erase(it); + } else + ++it; + } + Q_FOREACH (const Subscriber &subscriber, m_subscribers) { + if (subscriber.origin == origin && subscriber.type == type) + subscriber.callback.Run(status); + } +} + +void PermissionManagerQt::RequestPermission(content::PermissionType permission, + content::WebContents* web_contents, + int request_id, + const GURL& requesting_origin, + bool user_gesture, + const base::Callback<void(content::PermissionStatus)>& callback) +{ + Q_UNUSED(user_gesture); + BrowserContextAdapter::PermissionType permissionType = toQt(permission); + if (permissionType == BrowserContextAdapter::UnsupportedPermission) { + callback.Run(content::PERMISSION_STATUS_DENIED); + return; + } + + WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(web_contents->GetDelegate()); + Q_ASSERT(contentsDelegate); + Request request = { + request_id, + permissionType, + toQt(requesting_origin), + callback + }; + m_requests.append(request); + if (permissionType == BrowserContextAdapter::GeolocationPermission) + contentsDelegate->requestGeolocationPermission(request.origin); +} + +void PermissionManagerQt::CancelPermissionRequest(content::PermissionType permission, + content::WebContents* web_contents, + int request_id, + const GURL& requesting_origin) +{ + Q_UNUSED(web_contents); + const BrowserContextAdapter::PermissionType permissionType = toQt(permission); + if (permissionType == BrowserContextAdapter::UnsupportedPermission) + return; + + // Should we add API to cancel permissions in the UI level? + const QUrl origin = toQt(requesting_origin); + auto it = m_requests.begin(); + const auto end = m_requests.end(); + while (it != end) { + if (it->id == request_id && it->type == permissionType && it->origin == origin) { + m_requests.erase(it); + return; + } + } + qWarning() << "PermissionManagerQt::CancelPermissionRequest called on unknown request" << request_id << origin << permissionType; +} + +content::PermissionStatus PermissionManagerQt::GetPermissionStatus( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& /*embedding_origin*/) +{ + const BrowserContextAdapter::PermissionType permissionType = toQt(permission); + if (permissionType == BrowserContextAdapter::UnsupportedPermission) + return content::PERMISSION_STATUS_DENIED; + + QPair<QUrl, BrowserContextAdapter::PermissionType> key(toQt(requesting_origin), permissionType); + if (!m_permissions.contains(key)) + return content::PERMISSION_STATUS_ASK; + if (m_permissions[key]) + return content::PERMISSION_STATUS_GRANTED; + return content::PERMISSION_STATUS_DENIED; +} + +void PermissionManagerQt::ResetPermission( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& /*embedding_origin*/) +{ + const BrowserContextAdapter::PermissionType permissionType = toQt(permission); + if (permissionType == BrowserContextAdapter::UnsupportedPermission) + return; + + QPair<QUrl, BrowserContextAdapter::PermissionType> key(toQt(requesting_origin), permissionType); + m_permissions.remove(key); +} + +void PermissionManagerQt::RegisterPermissionUsage( + content::PermissionType /*permission*/, + const GURL& /*requesting_origin*/, + const GURL& /*embedding_origin*/) +{ + // We do not currently track which permissions are used. +} + +int PermissionManagerQt::SubscribePermissionStatusChange( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& /*embedding_origin*/, + const base::Callback<void(content::PermissionStatus)>& callback) +{ + Subscriber subscriber = { + m_subscriberCount++, + toQt(permission), + toQt(requesting_origin), + callback + }; + m_subscribers.append(subscriber); + return subscriber.id; +} + +void PermissionManagerQt::UnsubscribePermissionStatusChange(int subscription_id) +{ + for (int i = 0; i < m_subscribers.count(); i++) { + if (m_subscribers[i].id == subscription_id) { + m_subscribers.removeAt(i); + return; + } + } + qWarning() << "PermissionManagerQt::UnsubscribePermissionStatusChange called on unknown subscription id" << subscription_id; +} + +} // namespace QtWebEngineCore diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h new file mode 100644 index 000000000..75f88f9a9 --- /dev/null +++ b/src/core/permission_manager_qt.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PERMISSION_MANAGER_QT_H +#define PERMISSION_MANAGER_QT_H + +#include "base/callback.h" +#include "content/public/browser/permission_manager.h" +#include "browser_context_adapter.h" + +#include <QHash> +#include <QList> + +namespace QtWebEngineCore { + +class PermissionManagerQt : public content::PermissionManager { + +public: + PermissionManagerQt(BrowserContextAdapter *); + ~PermissionManagerQt(); + typedef BrowserContextAdapter::PermissionType PermissionType; + + void permissionRequestReply(const QUrl &origin, PermissionType type, bool reply); + + // content::PermissionManager implementation: + void RequestPermission( + content::PermissionType permission, + content::WebContents* web_contents, + int request_id, + const GURL& requesting_origin, + bool user_gesture, + const base::Callback<void(content::PermissionStatus)>& callback) override; + + void CancelPermissionRequest( + content::PermissionType permission, + content::WebContents* web_contents, + int request_id, + const GURL& requesting_origin) override; + + content::PermissionStatus GetPermissionStatus( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& embedding_origin) override; + + void ResetPermission( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& embedding_origin) override; + + void RegisterPermissionUsage( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& embedding_origin) override; + + int SubscribePermissionStatusChange( + content::PermissionType permission, + const GURL& requesting_origin, + const GURL& embedding_origin, + const base::Callback<void(content::PermissionStatus)>& callback) override; + + void UnsubscribePermissionStatusChange(int subscription_id) override; + +private: + BrowserContextAdapter *m_contextAdapter; + QHash<QPair<QUrl, PermissionType>, bool> m_permissions; + struct Request { + int id; + PermissionType type; + QUrl origin; + base::Callback<void(content::PermissionStatus)> callback; + }; + QList<Request> m_requests; + struct Subscriber { + int id; + PermissionType type; + QUrl origin; + base::Callback<void(content::PermissionStatus)> callback; + }; + int m_subscriberCount; + QList<Subscriber> m_subscribers; + +}; + +} // namespace QtWebEngineCore + +#endif // PERMISSION_MANAGER_QT_H diff --git a/src/core/proxy_config_service_qt.cpp b/src/core/proxy_config_service_qt.cpp new file mode 100644 index 000000000..933b1a10e --- /dev/null +++ b/src/core/proxy_config_service_qt.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "proxy_config_service_qt.h" + +#include "proxy_resolver_qt.h" + +#include "base/bind.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qtProxy) +{ + net::ProxyServer::Scheme proxyScheme = net::ProxyServer::SCHEME_INVALID; + switch (qtProxy.type()) { + case QNetworkProxy::Socks5Proxy: + proxyScheme = net::ProxyServer::SCHEME_SOCKS5; + break; + case QNetworkProxy::HttpProxy: + case QNetworkProxy::HttpCachingProxy: + case QNetworkProxy::FtpCachingProxy: + proxyScheme = net::ProxyServer::SCHEME_HTTP; + break; + case QNetworkProxy::NoProxy: + default: + proxyScheme = net::ProxyServer::SCHEME_DIRECT; + break; + } + return net::ProxyServer(proxyScheme, net::HostPortPair(qtProxy.hostName().toStdString(), qtProxy.port())); +} + +//================ Based on ChromeProxyConfigService ======================= + +ProxyConfigServiceQt::ProxyConfigServiceQt(net::ProxyConfigService *baseService) + : m_baseService(baseService), + m_registeredObserver(false) +{ +} + +ProxyConfigServiceQt::~ProxyConfigServiceQt() +{ + if (m_registeredObserver && m_baseService.get()) + m_baseService->RemoveObserver(this); +} + +void ProxyConfigServiceQt::AddObserver(net::ProxyConfigService::Observer *observer) +{ + RegisterObserver(); + m_observers.AddObserver(observer); +} + +void ProxyConfigServiceQt::RemoveObserver(net::ProxyConfigService::Observer *observer) +{ + m_observers.RemoveObserver(observer); +} + +net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxyConfig(net::ProxyConfig *config) +{ + RegisterObserver(); + + // Ask the base service if available. + net::ProxyConfig systemConfig; + ConfigAvailability systemAvailability = net::ProxyConfigService::CONFIG_UNSET; + if (m_baseService.get()) + systemAvailability = m_baseService->GetLatestProxyConfig(&systemConfig); + + const QNetworkProxy &qtProxy = QNetworkProxy::applicationProxy(); + if (qtProxy == m_qtApplicationProxy && !m_qtProxyConfig.proxy_rules().empty()) { + *config = m_qtProxyConfig; + return CONFIG_VALID; + } + m_qtApplicationProxy = qtProxy; + m_qtProxyConfig = (systemAvailability == CONFIG_VALID) ? systemConfig : net::ProxyConfig(); + const bool useProxyResolver = ProxyResolverQt::useProxyResolverQt(); + + if (qtProxy.type() == QNetworkProxy::NoProxy) { + *config = systemConfig; + if (useProxyResolver) { + config->set_auto_detect(true); + config->set_pac_mandatory(true); + } + return systemAvailability; + } + + net::ProxyConfig::ProxyRules qtRules; + net::ProxyServer server = fromQNetworkProxy(qtProxy); + switch (qtProxy.type()) { + case QNetworkProxy::HttpProxy: + case QNetworkProxy::Socks5Proxy: + qtRules.type = net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; + qtRules.single_proxies.SetSingleProxyServer(server); + break; + case QNetworkProxy::HttpCachingProxy: + qtRules.type = net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; + qtRules.proxies_for_http.SetSingleProxyServer(server); + break; + case QNetworkProxy::FtpCachingProxy: + qtRules.type = net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; + qtRules.proxies_for_ftp.SetSingleProxyServer(server); + break; + default: + qtRules.type = net::ProxyConfig::ProxyRules::TYPE_NO_RULES; + } + + m_qtProxyConfig.proxy_rules() = qtRules; + if (useProxyResolver) { + m_qtProxyConfig.set_pac_mandatory(true); + m_qtProxyConfig.set_auto_detect(true); + } + *config = m_qtProxyConfig; + return CONFIG_VALID; +} + +void ProxyConfigServiceQt::OnLazyPoll() +{ + if (m_qtApplicationProxy != QNetworkProxy::applicationProxy()) { + net::ProxyConfig unusedConfig; + OnProxyConfigChanged(unusedConfig, CONFIG_VALID); + } + if (m_baseService.get()) + m_baseService->OnLazyPoll(); +} + + +void ProxyConfigServiceQt::OnProxyConfigChanged(const net::ProxyConfig &config, ConfigAvailability availability) +{ + Q_UNUSED(config); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + if (m_qtApplicationProxy != QNetworkProxy::applicationProxy() + || m_qtApplicationProxy.type() == QNetworkProxy::NoProxy) { + net::ProxyConfig actual_config; + availability = GetLatestProxyConfig(&actual_config); + if (availability == CONFIG_PENDING) + return; + FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, m_observers, + OnProxyConfigChanged(actual_config, availability)); + } +} + +void ProxyConfigServiceQt::RegisterObserver() +{ + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (!m_registeredObserver && m_baseService.get()) { + m_baseService->AddObserver(this); + m_registeredObserver = true; + } +} diff --git a/src/core/proxy_config_service_qt.h b/src/core/proxy_config_service_qt.h new file mode 100644 index 000000000..f2f06d3fa --- /dev/null +++ b/src/core/proxy_config_service_qt.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PROXY_CONFIG_SERVICE_QT_H +#define PROXY_CONFIG_SERVICE_QT_H + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" + +#include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service.h" + +#include <QNetworkProxy> + +class ProxyConfigServiceQt + : public net::ProxyConfigService, + public net::ProxyConfigService::Observer { +public: + + static net::ProxyServer fromQNetworkProxy(const QNetworkProxy &); + + explicit ProxyConfigServiceQt(net::ProxyConfigService *baseService); + ~ProxyConfigServiceQt() override; + + // ProxyConfigService implementation: + void AddObserver(net::ProxyConfigService::Observer *observer) override; + void RemoveObserver(net::ProxyConfigService::Observer *observer) override; + ConfigAvailability GetLatestProxyConfig(net::ProxyConfig *config) override; + void OnLazyPoll() override; + +private: + // ProxyConfigService::Observer implementation: + void OnProxyConfigChanged(const net::ProxyConfig& config, + ConfigAvailability availability) override; + + // Makes sure that the observer registration with the base service is set up. + void RegisterObserver(); + + scoped_ptr<net::ProxyConfigService> m_baseService; + ObserverList<net::ProxyConfigService::Observer, true> m_observers; + + // Keep the last QNetworkProxy::applicationProxy state around. + QNetworkProxy m_qtApplicationProxy; + net::ProxyConfig m_qtProxyConfig; + + // Indicates whether the base service registration is done. + bool m_registeredObserver; + + DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceQt); +}; + +#endif // PROXY_CONFIG_SERVICE_QT_H diff --git a/src/core/proxy_resolver_qt.cpp b/src/core/proxy_resolver_qt.cpp new file mode 100644 index 000000000..9db76e910 --- /dev/null +++ b/src/core/proxy_resolver_qt.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "proxy_resolver_qt.h" + +#include "proxy_config_service_qt.h" +#include "type_conversion.h" + +#include "net/base/load_states.h" +#include "net/base/net_errors.h" +#include "net/proxy/proxy_info.h" + +#include <QNetworkProxyFactory> +#include <QNetworkProxyQuery> + +ProxyResolverQt::ProxyResolverQt() + : net::ProxyResolver(/*expects_pac_bytes = */ false) +{ +} + +int ProxyResolverQt::GetProxyForURL(const GURL &url, net::ProxyInfo *results, const net::CompletionCallback &, net::ProxyResolver::RequestHandle *, const net::BoundNetLog &) +{ + QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(QtWebEngineCore::toQt(url))); + if (proxies.empty()) + return net::ERR_FAILED; + if (proxies.size() == 1) { + const QNetworkProxy &qtProxy = proxies.first(); + if (qtProxy.type() == QNetworkProxy::NoProxy) + results->UseDirect(); + else + results->UseProxyServer(ProxyConfigServiceQt::fromQNetworkProxy(qtProxy)); + return net::OK; + } + net::ProxyList proxyList; + Q_FOREACH (const QNetworkProxy &qtProxy, proxies) + proxyList.AddProxyServer(ProxyConfigServiceQt::fromQNetworkProxy(qtProxy)); + results->UseProxyList(proxyList); + return net::OK; +} + +void ProxyResolverQt::CancelRequest(net::ProxyResolver::RequestHandle) +{ + // This is a synchronous ProxyResolver; no possibility for async requests. + NOTREACHED(); +} + +net::LoadState ProxyResolverQt::GetLoadState(net::ProxyResolver::RequestHandle) const +{ + NOTREACHED(); + return net::LOAD_STATE_IDLE; +} + +void ProxyResolverQt::CancelSetPacScript() +{ + NOTREACHED(); +} + +int ProxyResolverQt::SetPacScript(const scoped_refptr<net::ProxyResolverScriptData> &, const net::CompletionCallback &) { + return net::OK; +} diff --git a/src/core/proxy_resolver_qt.h b/src/core/proxy_resolver_qt.h new file mode 100644 index 000000000..4d419fb6e --- /dev/null +++ b/src/core/proxy_resolver_qt.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PROXY_RESOLVER_QT_H +#define PROXY_RESOLVER_QT_H + +#include "net/proxy/proxy_resolver.h" +#include "net/proxy/proxy_resolver_factory.h" +#include <qglobal.h> + + +class ProxyResolverQt : public net::ProxyResolver { +public: + static bool useProxyResolverQt() { return qEnvironmentVariableIsSet("QTWEBENGINE_USE_QT_PROXYRESOLVER"); } + + ProxyResolverQt(); + + int GetProxyForURL(const GURL &url, net::ProxyInfo *results, const net::CompletionCallback & + , RequestHandle*, const net::BoundNetLog&) override; + + void CancelRequest(RequestHandle) override; + + net::LoadState GetLoadState(RequestHandle) const override; + + void CancelSetPacScript() override; + + int SetPacScript(const scoped_refptr<net::ProxyResolverScriptData>& /*script_data*/, const net::CompletionCallback& /*callback*/) override; +}; + +class ProxyResolverFactoryQt : public net::LegacyProxyResolverFactory { +public: + ProxyResolverFactoryQt(bool expects_pac_bytes) : net::LegacyProxyResolverFactory(expects_pac_bytes) + { + } + scoped_ptr<net::ProxyResolver> CreateProxyResolver() override + { + return scoped_ptr<net::ProxyResolver>(new ProxyResolverQt()); + } +}; + +#endif // PROXY_RESOLVER_QT_H diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index cca2bd73f..cad6882eb 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -8,6 +8,8 @@ '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:devtools_discovery', + '<(chromium_src_dir)/components/components.gyp:devtools_http_handler', '<(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', @@ -16,6 +18,7 @@ '<(chromium_src_dir)/content/content.gyp:content_browser', '<(chromium_src_dir)/content/content.gyp:content_common', '<(chromium_src_dir)/content/content.gyp:content_gpu', + '<(chromium_src_dir)/content/content.gyp:content_ppapi_plugin', '<(chromium_src_dir)/content/content.gyp:content_renderer', '<(chromium_src_dir)/content/content.gyp:content_utility', '<(chromium_src_dir)/content/app/resources/content_resources.gyp:content_resources', diff --git a/src/core/qtwebengine_extras.gypi b/src/core/qtwebengine_extras.gypi index e28d6436e..86a4c17bb 100644 --- a/src/core/qtwebengine_extras.gypi +++ b/src/core/qtwebengine_extras.gypi @@ -57,6 +57,7 @@ ['exclude', 'win/accessibility_ids_win\\.h$'], ['exclude', 'win/accessibility_misc_utils\\.(cc|h)$'], ['exclude', 'win/atl_module\\.h$'], + ['exclude', 'audio_classifier\\.(cc|h)$'], ], 'defines': [ 'TOOLKIT_QT', diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 572bc340c..ef6610ecb 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -36,10 +36,12 @@ #include "render_widget_host_view_qt.h" +#include "common/qt_messages.h" #include "browser_accessibility_manager_qt.h" #include "browser_accessibility_qt.h" #include "chromium_overrides.h" #include "delegated_frame_node.h" +#include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" #include "web_contents_adapter.h" @@ -60,10 +62,11 @@ #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/blink/blink_event_util.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" +#include "ui/gfx/geometry/size_conversions.h" #include <QEvent> #include <QFocusEvent> @@ -142,7 +145,7 @@ static inline int firstAvailableId(const QMap<int, int> &map) } static inline ui::GestureProvider::Config QtGestureProviderConfig() { - ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig(); + ui::GestureProvider::Config config = ui::GetGestureProviderConfig(ui::GestureProviderConfigType::CURRENT_PLATFORM); // Causes an assert in CreateWebGestureEventFromGestureEventData and we don't need them in Qt. config.gesture_begin_end_types_enabled = false; config.gesture_detector_config.swipe_enabled = false; @@ -180,12 +183,14 @@ static inline int flagsFromModifiers(Qt::KeyboardModifiers modifiers) return modifierFlags; } +static uint32 s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: 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) + , eventId(++s_eventId) , flags(flagsFromModifiers(modifiers)) , index(index) { @@ -193,7 +198,7 @@ public: Q_ASSERT((action != ACTION_DOWN && action != ACTION_UP) || index == 0); } - virtual int GetId() const Q_DECL_OVERRIDE { return 0; } + virtual uint32 GetUniqueEventId() const Q_DECL_OVERRIDE { return eventId; } virtual Action GetAction() const Q_DECL_OVERRIDE { return action; } virtual int GetActionIndex() const Q_DECL_OVERRIDE { return index; } virtual size_t GetPointerCount() const Q_DECL_OVERRIDE { return touchPoints.size(); } @@ -232,6 +237,7 @@ private: QList<QTouchEvent::TouchPoint> touchPoints; base::TimeTicks eventTime; Action action; + const uint32 eventId; int flags; int index; }; @@ -408,6 +414,14 @@ gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const return gfx::BoundingRect(p1, p2); } +void RenderWidgetHostViewQt::SetBackgroundColor(SkColor color) { + RenderWidgetHostViewBase::SetBackgroundColor(color); + // Set the background of the compositor if necessary + m_delegate->setClearColor(toQt(color)); + // Set the background of the blink::FrameView + m_host->Send(new QtRenderViewObserver_SetBackgroundColor(m_host->GetRoutingID(), color)); +} + // Return value indicates whether the mouse is locked successfully or not. bool RenderWidgetHostViewQt::LockMouse() { @@ -426,27 +440,11 @@ void RenderWidgetHostViewQt::UnlockMouse() m_host->LostMouseLock(); } -void RenderWidgetHostViewQt::WasShown() -{ - m_host->WasShown(ui::LatencyInfo()); -} - -void RenderWidgetHostViewQt::WasHidden() -{ - m_host->WasHidden(); -} - void RenderWidgetHostViewQt::MovePluginWindows(const std::vector<content::WebPluginGeometry>&) { // QT_NOT_YET_IMPLEMENTED } -void RenderWidgetHostViewQt::Blur() -{ - m_host->SetInputMethodActive(false); - m_host->Blur(); -} - void RenderWidgetHostViewQt::UpdateCursor(const content::WebCursor &webCursor) { content::WebCursor::CursorInfo cursorInfo; @@ -600,13 +598,13 @@ void RenderWidgetHostViewQt::SelectionBoundsChanged(const ViewHostMsg_SelectionB m_cursorRect = QRect(caretRect.x(), caretRect.y(), caretRect.width(), caretRect.height()); } -void RenderWidgetHostViewQt::CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& dst_size, content::CopyFromCompositingSurfaceCallback& callback, const SkColorType color_type) +void RenderWidgetHostViewQt::CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& dst_size, content::ReadbackRequestCallback& callback, const SkColorType color_type) { NOTIMPLEMENTED(); Q_UNUSED(src_subrect); Q_UNUSED(dst_size); Q_UNUSED(color_type); - callback.Run(false, SkBitmap()); + callback.Run(SkBitmap(), content::READBACK_FAILED); } void RenderWidgetHostViewQt::CopyFromCompositingSurfaceToVideoFrame(const gfx::Rect& src_subrect, const scoped_refptr<media::VideoFrame>& target, const base::Callback<void(bool)>& callback) @@ -688,7 +686,7 @@ void RenderWidgetHostViewQt::SelectionChanged(const base::string16 &text, size_t void RenderWidgetHostViewQt::OnGestureEvent(const ui::GestureEventData& gesture) { - m_host->ForwardGestureEvent(content::CreateWebGestureEventFromGestureEventData(gesture)); + m_host->ForwardGestureEvent(ui::CreateWebGestureEventFromGestureEventData(gesture)); } QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) @@ -717,12 +715,12 @@ void RenderWidgetHostViewQt::notifyResize() void RenderWidgetHostViewQt::notifyShown() { - WasShown(); + m_host->WasShown(ui::LatencyInfo()); } void RenderWidgetHostViewQt::notifyHidden() { - WasHidden(); + m_host->WasHidden(); } void RenderWidgetHostViewQt::windowBoundsChanged() @@ -808,7 +806,7 @@ QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) co void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, content::InputEventAckState ack_result) { Q_UNUSED(touch); const bool eventConsumed = ack_result == content::INPUT_EVENT_ACK_STATE_CONSUMED; - m_gestureProvider.OnTouchEventAck(eventConsumed); + m_gestureProvider.OnAsyncTouchEventAck(eventConsumed); } void RenderWidgetHostViewQt::sendDelegatedFrameAck() @@ -822,16 +820,10 @@ void RenderWidgetHostViewQt::sendDelegatedFrameAck() void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEvent) { - if (!m_gestureProvider.OnTouchEvent(motionEvent)) + if (!m_gestureProvider.OnTouchEvent(motionEvent).succeeded) return; - // Short-circuit touch forwarding if no touch handlers exist. - if (!m_host->ShouldForwardTouchEvent()) { - const bool eventConsumed = false; - m_gestureProvider.OnTouchEventAck(eventConsumed); - return; - } - blink::WebTouchEvent touchEvent = content::CreateWebTouchEventFromMotionEvent(motionEvent); + blink::WebTouchEvent touchEvent = ui::CreateWebTouchEventFromMotionEvent(motionEvent, false); m_host->ForwardTouchEventWithLatencyInfo(touchEvent, CreateLatencyInfo(touchEvent)); } diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 248c52f6e..274138dcf 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -47,6 +47,7 @@ #include "content/common/gpu/gpu_messages.h" #include "content/common/view_messages.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" +#include "qtwebenginecoreglobal_p.h" #include <QMap> #include <QPoint> #include <QRect> @@ -125,12 +126,10 @@ public: virtual void Hide() Q_DECL_OVERRIDE; virtual bool IsShowing() Q_DECL_OVERRIDE; virtual gfx::Rect GetViewBounds() const Q_DECL_OVERRIDE; + virtual void SetBackgroundColor(SkColor color) Q_DECL_OVERRIDE; virtual bool LockMouse() Q_DECL_OVERRIDE; virtual void UnlockMouse() Q_DECL_OVERRIDE; - virtual void WasShown() Q_DECL_OVERRIDE; - virtual void WasHidden() Q_DECL_OVERRIDE; virtual void MovePluginWindows(const std::vector<content::WebPluginGeometry>&) Q_DECL_OVERRIDE; - virtual void Blur() Q_DECL_OVERRIDE; virtual void UpdateCursor(const content::WebCursor&) Q_DECL_OVERRIDE; virtual void SetIsLoading(bool) Q_DECL_OVERRIDE; virtual void TextInputTypeChanged(ui::TextInputType type, ui::TextInputMode mode, bool can_compose_inline, int flags) Q_DECL_OVERRIDE; @@ -140,7 +139,7 @@ public: 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 CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& dst_size, content::CopyFromCompositingSurfaceCallback& callback, const SkColorType color_type) Q_DECL_OVERRIDE; + virtual void CopyFromCompositingSurface(const gfx::Rect& src_subrect, const gfx::Size& dst_size, content::ReadbackRequestCallback& 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 bool HasAcceleratedSurface(const gfx::Size&) Q_DECL_OVERRIDE; diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index da595b91f..f4aa9b27d 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -96,6 +96,7 @@ public: virtual void move(const QPoint &) = 0; virtual void inputMethodStateChanged(bool editorVisible) = 0; virtual void setTooltip(const QString &) = 0; + virtual void setClearColor(const QColor &color) = 0; }; } // namespace QtWebEngineCore diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index e1333144a..32ba4d55f 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -51,6 +51,7 @@ #include "content/public/common/web_preferences.h" #include "renderer/web_channel_ipc_transport.h" +#include "renderer/qt_render_frame_observer.h" #include "renderer/qt_render_view_observer.h" #include "renderer/user_script_controller.h" @@ -85,6 +86,11 @@ void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view UserScriptController::instance()->renderViewCreated(render_view); } +void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame) +{ + new QtWebEngineCore::QtRenderFrameObserver(render_frame); +} + bool ContentRendererClientQt::HasErrorPage(int httpStatusCode, std::string *errorDomain) { // Use an internal error page, if we have one for the status code. diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h index dcb4e7fcb..fab88441f 100644 --- a/src/core/renderer/content_renderer_client_qt.h +++ b/src/core/renderer/content_renderer_client_qt.h @@ -53,7 +53,7 @@ public: ~ContentRendererClientQt(); virtual void RenderThreadStarted() Q_DECL_OVERRIDE; virtual void RenderViewCreated(content::RenderView *render_view) Q_DECL_OVERRIDE; - + virtual void RenderFrameCreated(content::RenderFrame* render_frame) Q_DECL_OVERRIDE; virtual bool ShouldSuppressErrorPage(content::RenderFrame *, const GURL &) Q_DECL_OVERRIDE; virtual bool HasErrorPage(int httpStatusCode, std::string *errorDomain) Q_DECL_OVERRIDE; virtual void GetNavigationErrorStrings(content::RenderView* renderView, blink::WebFrame* frame, const blink::WebURLRequest& failedRequest diff --git a/src/core/renderer/pepper/pepper_flash_browser_host_qt.cpp b/src/core/renderer/pepper/pepper_flash_browser_host_qt.cpp new file mode 100644 index 000000000..625e89ae4 --- /dev/null +++ b/src/core/renderer/pepper/pepper_flash_browser_host_qt.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "pepper_flash_browser_host_qt.h" + +#include "base/time/time.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "ipc/ipc_message_macros.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/time_conversion.h" +#include "qtwebenginecoreglobal_p.h" +#include "url/gurl.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_MACOSX) +#include <CoreServices/CoreServices.h> +#endif + +using content::BrowserPpapiHost; +using content::BrowserThread; +using content::RenderProcessHost; + +namespace QtWebEngineCore { + + +PepperFlashBrowserHostQt::PepperFlashBrowserHostQt(BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + host_(host), + weak_factory_(this) +{ + int unused; + host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); +} + +PepperFlashBrowserHostQt::~PepperFlashBrowserHostQt() {} + +int32_t PepperFlashBrowserHostQt::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) +{ + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashBrowserHostQt, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_UpdateActivity, + OnUpdateActivity) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetLocalTimeZoneOffset, + OnGetLocalTimeZoneOffset) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_GetLocalDataRestrictions, + OnGetLocalDataRestrictions) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashBrowserHostQt::OnUpdateActivity(ppapi::host::HostMessageContext* host_context) +{ +#if defined(OS_WIN) + // Reading then writing back the same value to the screensaver timeout system + // setting resets the countdown which prevents the screensaver from turning + // on "for a while". As long as the plugin pings us with this message faster + // than the screensaver timeout, it won't go on. + int value = 0; + if (SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &value, 0)) + SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, value, NULL, 0); +#elif defined(OS_MACOSX) + UpdateSystemActivity(OverallAct); +#endif + return PP_OK; +} + +int32_t PepperFlashBrowserHostQt::OnGetLocalTimeZoneOffset( + ppapi::host::HostMessageContext* host_context, + const base::Time& t) +{ + // The reason for this processing being in the browser process is that on + // Linux, the localtime calls require filesystem access prohibited by the + // sandbox. + host_context->reply_msg = PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply( + ppapi::PPGetLocalTimeZoneOffset(t)); + return PP_OK; +} + +int32_t PepperFlashBrowserHostQt::OnGetLocalDataRestrictions( + ppapi::host::HostMessageContext* context) +{ + QT_NOT_YET_IMPLEMENTED + return PP_OK; +} + +} // namespace QtWebEngineCore diff --git a/src/core/renderer/pepper/pepper_flash_browser_host_qt.h b/src/core/renderer/pepper/pepper_flash_browser_host_qt.h new file mode 100644 index 000000000..c5165a1b0 --- /dev/null +++ b/src/core/renderer/pepper/pepper_flash_browser_host_qt.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PEPPER_FLASH_BROWSER_HOST_QT_H +#define PEPPER_FLASH_BROWSER_HOST_QT_H + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/resource_host.h" + +namespace base { +class Time; +} + +namespace content { +class BrowserPpapiHost; +class ResourceContext; +} + +class GURL; + +namespace QtWebEngineCore { + +class PepperFlashBrowserHostQt : public ppapi::host::ResourceHost { +public: + PepperFlashBrowserHostQt(content::BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + ~PepperFlashBrowserHostQt() override; + + // ppapi::host::ResourceHost override. + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + +private: + int32_t OnUpdateActivity(ppapi::host::HostMessageContext* host_context); + int32_t OnGetLocalTimeZoneOffset( + ppapi::host::HostMessageContext* host_context, + const base::Time& t); + int32_t OnGetLocalDataRestrictions(ppapi::host::HostMessageContext* context); + + void GetLocalDataRestrictions(ppapi::host::ReplyMessageContext reply_context, + const GURL& document_url, + const GURL& plugin_url); + + content::BrowserPpapiHost* host_; + int render_process_id_; + base::WeakPtrFactory<PepperFlashBrowserHostQt> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashBrowserHostQt); +}; + +} // namespace QtWebEngineCore + +#endif // PEPPER_FLASH_BROWSER_HOST_QT_H diff --git a/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp b/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp new file mode 100644 index 000000000..8e68d1682 --- /dev/null +++ b/src/core/renderer/pepper/pepper_flash_renderer_host_qt.cpp @@ -0,0 +1,349 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "pepper_flash_renderer_host_qt.h" + +#include <map> +#include <vector> + +#include "base/lazy_instance.h" +#include "base/metrics/histogram.h" +#include "base/strings/string_util.h" +#include "content/public/renderer/pepper_plugin_instance.h" +#include "content/public/renderer/render_thread.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ipc/ipc_message_macros.h" +#include "net/http/http_util.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/trusted/ppb_browser_font_trusted.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkTemplates.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "ui/gfx/geometry/rect.h" +#include "url/gurl.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_ImageData_API; + +namespace { + +// Some non-simple HTTP request headers that Flash may set. +// (Please see http://www.w3.org/TR/cors/#simple-header for the definition of +// simple headers.) +// +// The list and the enum defined below are used to collect data about request +// headers used in PPB_Flash.Navigate() calls, in order to understand the impact +// of rejecting PPB_Flash.Navigate() requests with non-simple headers. +// +// TODO(yzshen): We should be able to remove the histogram recording code once +// we get the answer. +const char* const kRejectedHttpRequestHeaders[] = { + "authorization", // + "cache-control", // + "content-encoding", // + "content-md5", // + "content-type", // If the media type is not one of those covered by the + // simple header definition. + "expires", // + "from", // + "if-match", // + "if-none-match", // + "if-range", // + "if-unmodified-since", // + "pragma", // + "referer" // +}; + +// Please note that new entries should be added right above +// FLASH_NAVIGATE_USAGE_ENUM_COUNT, and existing entries shouldn't be re-ordered +// or removed, since this ordering is used in a histogram. +enum FlashNavigateUsage { + // This section must be in the same order as kRejectedHttpRequestHeaders. + REJECT_AUTHORIZATION = 0, + REJECT_CACHE_CONTROL, + REJECT_CONTENT_ENCODING, + REJECT_CONTENT_MD5, + REJECT_CONTENT_TYPE, + REJECT_EXPIRES, + REJECT_FROM, + REJECT_IF_MATCH, + REJECT_IF_NONE_MATCH, + REJECT_IF_RANGE, + REJECT_IF_UNMODIFIED_SINCE, + REJECT_PRAGMA, + REJECT_REFERER, + + // The navigate request is rejected because of headers not listed above + // (e.g., custom headers). + REJECT_OTHER_HEADERS, + + // Total number of rejected navigate requests. + TOTAL_REJECTED_NAVIGATE_REQUESTS, + + // Total number of navigate requests. + TOTAL_NAVIGATE_REQUESTS, + FLASH_NAVIGATE_USAGE_ENUM_COUNT +}; + +static base::LazyInstance<std::map<std::string, FlashNavigateUsage> > +g_rejected_headers = LAZY_INSTANCE_INITIALIZER; + +bool IsSimpleHeader(const std::string& lower_case_header_name, + const std::string& header_value) +{ + if (lower_case_header_name == "accept" || + lower_case_header_name == "accept-language" || + lower_case_header_name == "content-language") + return true; + + if (lower_case_header_name == "content-type") { + std::string lower_case_mime_type; + std::string lower_case_charset; + bool had_charset = false; + net::HttpUtil::ParseContentType(header_value, + &lower_case_mime_type, + &lower_case_charset, + &had_charset, + NULL); + return lower_case_mime_type == "application/x-www-form-urlencoded" || + lower_case_mime_type == "multipart/form-data" || + lower_case_mime_type == "text/plain"; + } + + return false; +} + +void RecordFlashNavigateUsage(FlashNavigateUsage usage) +{ + DCHECK_NE(FLASH_NAVIGATE_USAGE_ENUM_COUNT, usage); + UMA_HISTOGRAM_ENUMERATION( + "Plugin.FlashNavigateUsage", + usage, + FLASH_NAVIGATE_USAGE_ENUM_COUNT); +} + +} // namespace + +namespace QtWebEngineCore { + +PepperFlashRendererHostQt::PepperFlashRendererHostQt( + content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + host_(host), + weak_factory_(this) +{ +} + +PepperFlashRendererHostQt::~PepperFlashRendererHostQt() { + // This object may be destroyed in the middle of a sync message. If that is + // the case, make sure we respond to all the pending navigate calls. + std::vector<ppapi::host::ReplyMessageContext>::reverse_iterator it; + for (it = navigate_replies_.rbegin(); it != navigate_replies_.rend(); ++it) + SendReply(*it, IPC::Message()); +} + +int32_t PepperFlashRendererHostQt::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) +{ + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashRendererHostQt, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetProxyForURL, + OnGetProxyForURL) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_SetInstanceAlwaysOnTop, + OnSetInstanceAlwaysOnTop) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_DrawGlyphs, + OnDrawGlyphs) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_Navigate, OnNavigate) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_IsRectTopmost, + OnIsRectTopmost) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_InvokePrinting, + OnInvokePrinting) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashRendererHostQt::OnGetProxyForURL( + ppapi::host::HostMessageContext* host_context, + const std::string& url) +{ + GURL gurl(url); + if (!gurl.is_valid()) + return PP_ERROR_FAILED; + std::string proxy; + bool result = content::RenderThread::Get()->ResolveProxy(gurl, &proxy); + if (!result) + return PP_ERROR_FAILED; + host_context->reply_msg = PpapiPluginMsg_Flash_GetProxyForURLReply(proxy); + return PP_OK; +} + +int32_t PepperFlashRendererHostQt::OnSetInstanceAlwaysOnTop( + ppapi::host::HostMessageContext* host_context, + bool on_top) +{ + content::PepperPluginInstance* plugin_instance = + host_->GetPluginInstance(pp_instance()); + if (plugin_instance) + plugin_instance->SetAlwaysOnTop(on_top); + return PP_OK; +} + +int32_t PepperFlashRendererHostQt::OnDrawGlyphs( + ppapi::host::HostMessageContext* host_context, + ppapi::proxy::PPBFlash_DrawGlyphs_Params params) +{ + if (params.glyph_indices.size() != params.glyph_advances.size() || + params.glyph_indices.empty()) + return PP_ERROR_FAILED; + + return PP_OK; +} + +// CAUTION: This code is subtle because Navigate is a sync call which may +// cause re-entrancy or cause the instance to be destroyed. If the instance +// is destroyed we need to ensure that we respond to all outstanding sync +// messages so that the plugin process does not remain blocked. +int32_t PepperFlashRendererHostQt::OnNavigate( + ppapi::host::HostMessageContext* host_context, + const ppapi::URLRequestInfoData& data, + const std::string& target, + bool from_user_action) +{ + // If our PepperPluginInstance is already destroyed, just return a failure. + content::PepperPluginInstance* plugin_instance = + host_->GetPluginInstance(pp_instance()); + if (!plugin_instance) + return PP_ERROR_FAILED; + + std::map<std::string, FlashNavigateUsage>& rejected_headers = + g_rejected_headers.Get(); + if (rejected_headers.empty()) { + for (size_t i = 0; i < arraysize(kRejectedHttpRequestHeaders); ++i) + rejected_headers[kRejectedHttpRequestHeaders[i]] = + static_cast<FlashNavigateUsage>(i); + } + + net::HttpUtil::HeadersIterator header_iter( + data.headers.begin(), data.headers.end(), "\n\r"); + bool rejected = false; + while (header_iter.GetNext()) { + std::string lower_case_header_name = + base::StringToLowerASCII(header_iter.name()); + if (!IsSimpleHeader(lower_case_header_name, header_iter.values())) { + rejected = true; + + std::map<std::string, FlashNavigateUsage>::const_iterator iter = + rejected_headers.find(lower_case_header_name); + FlashNavigateUsage usage = + iter != rejected_headers.end() ? iter->second : REJECT_OTHER_HEADERS; + RecordFlashNavigateUsage(usage); + } + } + + RecordFlashNavigateUsage(TOTAL_NAVIGATE_REQUESTS); + if (rejected) { + RecordFlashNavigateUsage(TOTAL_REJECTED_NAVIGATE_REQUESTS); + return PP_ERROR_NOACCESS; + } + + // Navigate may call into Javascript (e.g. with a "javascript:" URL), + // or do things like navigate away from the page, either one of which will + // need to re-enter into the plugin. It is safe, because it is essentially + // equivalent to NPN_GetURL, where Flash would expect re-entrancy. + ppapi::proxy::HostDispatcher* host_dispatcher = + ppapi::proxy::HostDispatcher::GetForInstance(pp_instance()); + host_dispatcher->set_allow_plugin_reentrancy(); + + // Grab a weak pointer to ourselves on the stack so we can check if we are + // still alive. + base::WeakPtr<PepperFlashRendererHostQt> weak_ptr = weak_factory_.GetWeakPtr(); + // Keep track of reply contexts in case we are destroyed during a Navigate + // call. Even if we are destroyed, we still need to send these replies to + // unblock the plugin process. + navigate_replies_.push_back(host_context->MakeReplyMessageContext()); + plugin_instance->Navigate(data, target.c_str(), from_user_action); + // This object might have been destroyed by this point. If it is destroyed + // the reply will be sent in the destructor. Otherwise send the reply here. + if (weak_ptr.get()) { + SendReply(navigate_replies_.back(), IPC::Message()); + navigate_replies_.pop_back(); + } + + // Return PP_OK_COMPLETIONPENDING so that no reply is automatically sent. + return PP_OK_COMPLETIONPENDING; +} + +int32_t PepperFlashRendererHostQt::OnIsRectTopmost( + ppapi::host::HostMessageContext* host_context, + const PP_Rect& rect) +{ + content::PepperPluginInstance* plugin_instance = + host_->GetPluginInstance(pp_instance()); + if (plugin_instance && + plugin_instance->IsRectTopmost( + gfx::Rect( + rect.point.x, + rect.point.y, + rect.size.width, + rect.size.height))) + return PP_OK; + return PP_ERROR_FAILED; +} + +int32_t PepperFlashRendererHostQt::OnInvokePrinting( + ppapi::host::HostMessageContext* host_context) +{ + return PP_ERROR_FAILED; +} + +} //QtWebEngineCore diff --git a/src/core/renderer/pepper/pepper_flash_renderer_host_qt.h b/src/core/renderer/pepper/pepper_flash_renderer_host_qt.h new file mode 100644 index 000000000..4a731fad4 --- /dev/null +++ b/src/core/renderer/pepper/pepper_flash_renderer_host_qt.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PEPPER_FLASH_RENDERER_HOST_QT_H +#define PEPPER_FLASH_RENDERER_HOST_QT_H + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/resource_host.h" + +struct PP_Rect; + +namespace ppapi { +struct URLRequestInfoData; +} + +namespace ppapi { +namespace proxy { +struct PPBFlash_DrawGlyphs_Params; +} +} + +namespace content { +class RendererPpapiHost; +} + +namespace QtWebEngineCore { + +class PepperFlashRendererHostQt : public ppapi::host::ResourceHost { +public: + PepperFlashRendererHostQt(content::RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + ~PepperFlashRendererHostQt() override; + + // ppapi::host::ResourceHost override. + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + +private: + int32_t OnGetProxyForURL(ppapi::host::HostMessageContext* host_context, + const std::string& url); + int32_t OnSetInstanceAlwaysOnTop( + ppapi::host::HostMessageContext* host_context, + bool on_top); + int32_t OnDrawGlyphs(ppapi::host::HostMessageContext* host_context, + ppapi::proxy::PPBFlash_DrawGlyphs_Params params); + int32_t OnNavigate(ppapi::host::HostMessageContext* host_context, + const ppapi::URLRequestInfoData& data, + const std::string& target, + bool from_user_action); + int32_t OnIsRectTopmost(ppapi::host::HostMessageContext* host_context, + const PP_Rect& rect); + int32_t OnInvokePrinting(ppapi::host::HostMessageContext* host_context); + + // A stack of ReplyMessageContexts to track Navigate() calls which have not + // yet been replied to. + std::vector<ppapi::host::ReplyMessageContext> navigate_replies_; + + content::RendererPpapiHost* host_; + base::WeakPtrFactory<PepperFlashRendererHostQt> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashRendererHostQt); +}; + +} //QtWebEngineCore +#endif // PEPPER_FLASH_RENDERER_HOST_QT_H diff --git a/src/core/renderer/pepper/pepper_host_factory_qt.cpp b/src/core/renderer/pepper/pepper_host_factory_qt.cpp new file mode 100644 index 000000000..61eeac9a0 --- /dev/null +++ b/src/core/renderer/pepper/pepper_host_factory_qt.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "pepper_host_factory_qt.h" + +#include "build/build_config.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "ppapi/host/message_filter_host.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_permissions.h" +#include "pepper_flash_browser_host_qt.h" + +using ppapi::host::MessageFilterHost; +using ppapi::host::ResourceHost; +using ppapi::host::ResourceMessageFilter; + +namespace QtWebEngineCore { + +PepperHostFactoryQt::PepperHostFactoryQt(content::BrowserPpapiHost* host) + : host_(host) +{ +} + +PepperHostFactoryQt::~PepperHostFactoryQt() {} + +scoped_ptr<ppapi::host::ResourceHost> PepperHostFactoryQt::CreateResourceHost(ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) +{ + DCHECK(host == host_->GetPpapiHost()); + + + if (!host_->IsValidInstance(instance)) + return scoped_ptr<ppapi::host::ResourceHost>(); + + if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_FLASH) + && message.type() == PpapiHostMsg_Flash_Create::ID) + return scoped_ptr<ppapi::host::ResourceHost>( + new PepperFlashBrowserHostQt(host_, + instance, + resource)); + + return scoped_ptr<ppapi::host::ResourceHost>(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/renderer/pepper/pepper_host_factory_qt.h b/src/core/renderer/pepper/pepper_host_factory_qt.h new file mode 100644 index 000000000..22bf87b1b --- /dev/null +++ b/src/core/renderer/pepper/pepper_host_factory_qt.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PEPPER_HOST_FACTORY_QT_H +#define PEPPER_HOST_FACTORY_QT_H + +#include "base/compiler_specific.h" +#include "ppapi/host/host_factory.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/host/ppapi_host.h" + +namespace content { +class BrowserPpapiHost; +} // namespace content + +namespace QtWebEngineCore { + +class PepperHostFactoryQt final : public ppapi::host::HostFactory { +public: + // Non-owning pointer to the filter must outlive this class. + explicit PepperHostFactoryQt(content::BrowserPpapiHost* host); + ~PepperHostFactoryQt() override; + + virtual scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) override; +private: + // Non-owning pointer. + content::BrowserPpapiHost* host_; + + DISALLOW_COPY_AND_ASSIGN(PepperHostFactoryQt); +}; +} // namespace QtWebEngineCore + +#endif // PEPPER_HOST_FACTORY_QT_H diff --git a/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp new file mode 100644 index 000000000..51416d698 --- /dev/null +++ b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "pepper_renderer_host_factory_qt.h" +#include "pepper_flash_renderer_host_qt.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_message_utils.h" +#include "ppapi/shared_impl/ppapi_permissions.h" + + +namespace QtWebEngineCore { + +PepperRendererHostFactoryQt::PepperRendererHostFactoryQt(content::RendererPpapiHost* host) + : host_(host) +{ +} + +PepperRendererHostFactoryQt::~PepperRendererHostFactoryQt() +{ +} + +scoped_ptr<ppapi::host::ResourceHost> PepperRendererHostFactoryQt::CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) +{ + DCHECK_EQ(host_->GetPpapiHost(), host); + + if (!host_->IsValidInstance(instance)) + return scoped_ptr<ppapi::host::ResourceHost>(); + + if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_FLASH) + && message.type() == PpapiHostMsg_Flash_Create::ID) + return scoped_ptr<ppapi::host::ResourceHost>( + new PepperFlashRendererHostQt(host_, + instance, + resource)); + + return scoped_ptr<ppapi::host::ResourceHost>(); +} + +} // QtWebEngineCore diff --git a/src/core/renderer/pepper/pepper_renderer_host_factory_qt.h b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.h new file mode 100644 index 000000000..8631c1e03 --- /dev/null +++ b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 PEPPER_RENDERER_HOST_FACTORY_QT_H +#define PEPPER_RENDERER_HOST_FACTORY_QT_H + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/host/host_factory.h" +#include "content/public/renderer/render_frame_observer.h" + + +namespace content { +class RenderFrame; +} + +namespace QtWebEngineCore { + +class PepperRendererHostFactoryQt : public ppapi::host::HostFactory { +public: + explicit PepperRendererHostFactoryQt(content::RendererPpapiHost* host); + ~PepperRendererHostFactoryQt(); + + // HostFactory. + scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost( + ppapi::host::PpapiHost* host, + PP_Resource resource, + PP_Instance instance, + const IPC::Message& message) override; + +private: + // Not owned by this object. + content::RendererPpapiHost* host_; + + DISALLOW_COPY_AND_ASSIGN(PepperRendererHostFactoryQt); +}; + +} // namespace QtWebEngineCore + +#endif // PEPPER_RENDERER_HOST_FACTORY_QT_H diff --git a/src/core/renderer/qt_render_frame_observer.cpp b/src/core/renderer/qt_render_frame_observer.cpp new file mode 100644 index 000000000..5f06d1e4e --- /dev/null +++ b/src/core/renderer/qt_render_frame_observer.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 "qt_render_frame_observer.h" + +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/host/ppapi_host.h" + +#include "renderer/pepper/pepper_renderer_host_factory_qt.h" +#include "renderer/pepper/pepper_flash_renderer_host_qt.h" + +namespace QtWebEngineCore { + +QtRenderFrameObserver::QtRenderFrameObserver(content::RenderFrame* render_frame) + : RenderFrameObserver(render_frame) +{ +} + +QtRenderFrameObserver::~QtRenderFrameObserver() +{ +} + +#if defined(ENABLE_PLUGINS) +void QtRenderFrameObserver::DidCreatePepperPlugin(content::RendererPpapiHost* host) +{ + host->GetPpapiHost()->AddHostFactoryFilter( + scoped_ptr<ppapi::host::HostFactory>( + new PepperRendererHostFactoryQt(host))); +} +#endif + +} // namespace QtWebEngineCore diff --git a/src/core/renderer/qt_render_frame_observer.h b/src/core/renderer/qt_render_frame_observer.h new file mode 100644 index 000000000..42f2b7464 --- /dev/null +++ b/src/core/renderer/qt_render_frame_observer.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 QT_RENDER_FRAME_OBSERVER_H +#define QT_RENDER_FRAME_OBSERVER_H + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "content/public/renderer/render_frame_observer.h" + + +namespace content { +class RenderFrame; +} + +namespace QtWebEngineCore { + +class QtRenderFrameObserver : public content::RenderFrameObserver { +public: + explicit QtRenderFrameObserver(content::RenderFrame* render_frame); + ~QtRenderFrameObserver(); + +#if defined(ENABLE_PLUGINS) + void DidCreatePepperPlugin(content::RendererPpapiHost* host) override; +#endif + +private: + DISALLOW_COPY_AND_ASSIGN(QtRenderFrameObserver); +}; + +} // namespace QtWebEngineCore + +#endif // QT_RENDER_FRAME_OBSERVER_H diff --git a/src/core/renderer/qt_render_view_observer.cpp b/src/core/renderer/qt_render_view_observer.cpp index 83534dadd..ba91e54ae 100644 --- a/src/core/renderer/qt_render_view_observer.cpp +++ b/src/core/renderer/qt_render_view_observer.cpp @@ -65,6 +65,11 @@ void QtRenderViewObserver::onFetchDocumentInnerText(quint64 requestId) render_view()->GetWebView()->mainFrame()->contentAsText(std::numeric_limits<std::size_t>::max()))); } +void QtRenderViewObserver::onSetBackgroundColor(quint32 color) +{ + render_view()->GetWebView()->setBaseBackgroundColor(color); +} + void QtRenderViewObserver::OnFirstVisuallyNonEmptyLayout() { Send(new QtRenderViewObserverHost_DidFirstVisuallyNonEmptyLayout(routing_id())); @@ -76,6 +81,7 @@ bool QtRenderViewObserver::OnMessageReceived(const IPC::Message& message) IPC_BEGIN_MESSAGE_MAP(QtRenderViewObserver, message) IPC_MESSAGE_HANDLER(QtRenderViewObserver_FetchDocumentMarkup, onFetchDocumentMarkup) IPC_MESSAGE_HANDLER(QtRenderViewObserver_FetchDocumentInnerText, onFetchDocumentInnerText) + IPC_MESSAGE_HANDLER(QtRenderViewObserver_SetBackgroundColor, onSetBackgroundColor) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; diff --git a/src/core/renderer/qt_render_view_observer.h b/src/core/renderer/qt_render_view_observer.h index cb77cd0c9..3f7829a92 100644 --- a/src/core/renderer/qt_render_view_observer.h +++ b/src/core/renderer/qt_render_view_observer.h @@ -47,6 +47,7 @@ public: private: void onFetchDocumentMarkup(quint64 requestId); void onFetchDocumentInnerText(quint64 requestId); + void onSetBackgroundColor(quint32 color); void OnFirstVisuallyNonEmptyLayout() Q_DECL_OVERRIDE; diff --git a/src/core/resources/resources.gyp b/src/core/resources/resources.gyp index 4d653df12..6293cdf3b 100644 --- a/src/core/resources/resources.gyp +++ b/src/core/resources/resources.gyp @@ -15,7 +15,7 @@ }, 'dependencies': [ '<(chromium_src_dir)/content/app/strings/content_strings.gyp:content_strings', - '<(chromium_src_dir)/webkit/blink_resources.gyp:blink_resources', + '<(chromium_src_dir)/blink/public/blink_resources.gyp:blink_resources', '<(chromium_src_dir)/content/browser/devtools/devtools_resources.gyp:devtools_resources', '../chrome_qt.gyp:chrome_resources', ], @@ -29,7 +29,7 @@ 'variables': { 'pak_inputs': [ '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak', - '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/blink/devtools_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/ui/resources/webui_resources.pak', diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 66fcd4dd0..9e5461888 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -41,15 +41,17 @@ #include <QDateTime> #include <QDir> #include <QMatrix4x4> +#include <QNetworkCookie> #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 "net/cookies/canonical_cookie.h" #include "third_party/skia/include/utils/SkMatrix44.h" #include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/rect.h" +#include "ui/gfx/geometry/rect.h" #include "url/gurl.h" namespace QtWebEngineCore { @@ -92,6 +94,11 @@ inline QPoint toQt(const gfx::Point &point) return QPoint(point.x(), point.y()); } +inline gfx::Point toGfx(const QPoint& point) +{ + return gfx::Point(point.x(), point.y()); +} + inline QRect toQt(const gfx::Rect &rect) { return QRect(rect.x(), rect.y(), rect.width(), rect.height()); @@ -122,6 +129,11 @@ inline QColor toQt(const SkColor &c) return QColor(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), SkColorGetA(c)); } +inline SkColor toSk(const QColor &c) +{ + return c.rgba(); +} + inline QMatrix4x4 toQt(const SkMatrix44 &m) { QMatrix4x4 qtMatrix( @@ -142,6 +154,18 @@ inline base::Time toTime(const QDateTime &dateTime) { return base::Time::FromInternalValue(dateTime.toMSecsSinceEpoch()); } +inline QNetworkCookie toQt(const net::CanonicalCookie & cookie) +{ + QNetworkCookie qCookie = QNetworkCookie(QByteArray::fromStdString(cookie.Name()), QByteArray::fromStdString(cookie.Value())); + qCookie.setDomain(toQt(cookie.Domain())); + if (!cookie.ExpiryDate().is_null()) + qCookie.setExpirationDate(toQt(cookie.ExpiryDate())); + qCookie.setHttpOnly(cookie.IsHttpOnly()); + qCookie.setPath(toQt(cookie.Path())); + qCookie.setSecure(cookie.IsSecure()); + return qCookie; +} + inline base::FilePath::StringType toFilePathString(const QString &str) { #if defined(OS_WIN) diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 10923e4cb..a50fcbe0e 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -41,7 +41,6 @@ #include "base/threading/worker_pool.h" #include "base/threading/sequenced_worker_pool.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/cookie_crypto_delegate.h" #include "content/public/browser/cookie_store_factory.h" #include "content/public/common/content_switches.h" #include "net/base/cache_type.h" @@ -70,9 +69,14 @@ #include "browser_context_adapter.h" #include "custom_protocol_handler.h" #include "custom_url_scheme_handler.h" +#include "cookie_monster_delegate_qt.h" #include "content_client_qt.h" #include "network_delegate_qt.h" +#include "proxy_config_service_qt.h" +#include "proxy_resolver_qt.h" #include "qrc_protocol_handler_qt.h" +#include "qwebenginecookiestoreclient.h" +#include "qwebenginecookiestoreclient_p.h" #include "type_conversion.h" namespace QtWebEngineCore { @@ -84,6 +88,7 @@ using content::BrowserThread; URLRequestContextGetterQt::URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers) : m_ignoreCertificateErrors(false) , m_browserContext(browserContext) + , m_cookieDelegate(new CookieMonsterDelegateQt()) { std::swap(m_protocolHandlers, *protocolHandlers); @@ -100,7 +105,7 @@ net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() if (!m_urlRequestContext) { m_urlRequestContext.reset(new net::URLRequestContext()); - m_networkDelegate.reset(new NetworkDelegateQt); + m_networkDelegate.reset(new NetworkDelegateQt(this)); m_urlRequestContext->set_network_delegate(m_networkDelegate.get()); generateStorage(); @@ -117,10 +122,10 @@ void URLRequestContextGetterQt::updateStorageSettings() // 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 = net::ProxyService::CreateSystemProxyConfigService( + m_proxyConfigService = new ProxyConfigServiceQt(net::ProxyService::CreateSystemProxyConfigService( content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) - ); + )); if (m_storage) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateStorage, this)); } @@ -150,26 +155,23 @@ void URLRequestContextGetterQt::generateStorage() generateCookieStore(); generateUserAgent(); - m_storage->set_channel_id_service(new net::ChannelIDService( + m_storage->set_channel_id_service(scoped_ptr<net::ChannelIDService>(new net::ChannelIDService( new net::DefaultChannelIDStore(NULL), - base::WorkerPool::GetTaskRunner(true))); + base::WorkerPool::GetTaskRunner(true)))); m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); scoped_ptr<net::HostResolver> host_resolver(net::HostResolver::CreateDefaultResolver(NULL)); // The System Proxy Resolver has issues on Windows with unconfigured network cards, - // which is why we want to use the v8 one. However, V8ProxyResolver doesn't work reliably with - // --single-process (See also the warnings in net/proxy/proxy_resolver_v8.h). - base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kSingleProcess)) { - m_storage->set_proxy_service( - net::ProxyService::CreateUsingSystemProxyResolver(proxyConfigService, 0, NULL)); + // which is why we want to use the v8 one + if (ProxyResolverQt::useProxyResolverQt()) { + scoped_ptr<ProxyResolverFactoryQt> factory(new ProxyResolverFactoryQt(false)); + m_storage->set_proxy_service(new net::ProxyService(proxyConfigService, factory.Pass(), nullptr)); } else { if (!m_dhcpProxyScriptFetcherFactory) m_dhcpProxyScriptFetcherFactory.reset(new net::DhcpProxyScriptFetcherFactory); - net::ProxyResolverV8::EnsureIsolateCreated(); m_storage->set_proxy_service(net::CreateProxyServiceUsingV8ProxyResolver( proxyConfigService, new net::ProxyScriptFetcherImpl(m_urlRequestContext.get()), @@ -206,6 +208,8 @@ void URLRequestContextGetterQt::generateCookieStore() // 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_cookieDelegate->setCookieMonster(0); + m_cookieDelegate->setClient(m_browserContext->cookieStoreClient()); net::CookieStore* cookieStore = 0; switch (m_browserContext->persistentCookiesPolicy()) { @@ -214,7 +218,8 @@ void URLRequestContextGetterQt::generateCookieStore() content::CreateCookieStore(content::CookieStoreConfig( base::FilePath(), content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES, - NULL, NULL) + NULL, + m_cookieDelegate.get()) ); break; case BrowserContextAdapter::AllowPersistentCookies: @@ -222,7 +227,8 @@ void URLRequestContextGetterQt::generateCookieStore() content::CreateCookieStore(content::CookieStoreConfig( toFilePath(m_browserContext->cookiesPath()), content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, - NULL, NULL) + NULL, + m_cookieDelegate.get()) ); break; case BrowserContextAdapter::ForcePersistentCookies: @@ -230,11 +236,16 @@ void URLRequestContextGetterQt::generateCookieStore() content::CreateCookieStore(content::CookieStoreConfig( toFilePath(m_browserContext->cookiesPath()), content::CookieStoreConfig::RESTORED_SESSION_COOKIES, - NULL, NULL) + NULL, + m_cookieDelegate.get()) ); break; } m_storage->set_cookie_store(cookieStore); + + net::CookieMonster * const cookieMonster = cookieStore->GetCookieMonster(); + cookieMonster->SetCookieableSchemes(kCookieableSchemes, arraysize(kCookieableSchemes)); + m_cookieDelegate->setCookieMonster(cookieMonster); } void URLRequestContextGetterQt::updateUserAgent() @@ -243,13 +254,32 @@ void URLRequestContextGetterQt::updateUserAgent() content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateUserAgent, this)); } +class HttpUserAgentSettingsQt : public net::HttpUserAgentSettings +{ + const BrowserContextAdapter *m_browserContext; +public: + HttpUserAgentSettingsQt(const BrowserContextAdapter *ctx) + : m_browserContext(ctx) + { + } + + std::string GetAcceptLanguage() const Q_DECL_OVERRIDE + { + return m_browserContext->httpAcceptLanguage().toStdString(); + } + + std::string GetUserAgent() const Q_DECL_OVERRIDE + { + return m_browserContext->httpUserAgent().toStdString(); + } +}; + void URLRequestContextGetterQt::generateUserAgent() { Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); - m_storage->set_http_user_agent_settings( - new net::StaticHttpUserAgentSettings("en-us,en", m_browserContext->httpUserAgent().toStdString())); + m_storage->set_http_user_agent_settings(new HttpUserAgentSettingsQt(m_browserContext)); } void URLRequestContextGetterQt::updateHttpCache() diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 38cfd7957..c7a4366ec 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -49,12 +49,14 @@ #include "net/url_request/url_request_job_factory_impl.h" #include "net/proxy/dhcp_proxy_script_fetcher_factory.h" +#include "cookie_monster_delegate_qt.h" +#include "network_delegate_qt.h" + #include "qglobal.h" #include <qatomic.h> namespace net { class MappedHostResolver; -class NetworkDelegate; class ProxyConfigService; } @@ -93,10 +95,12 @@ private: QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; scoped_ptr<net::URLRequestContext> m_urlRequestContext; - scoped_ptr<net::NetworkDelegate> m_networkDelegate; + scoped_ptr<NetworkDelegateQt> m_networkDelegate; scoped_ptr<net::URLRequestContextStorage> m_storage; scoped_ptr<net::URLRequestJobFactoryImpl> m_jobFactory; scoped_ptr<net::DhcpProxyScriptFetcherFactory> m_dhcpProxyScriptFetcherFactory; + scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate; + friend class NetworkDelegateQt; }; } // namespace QtWebEngineCore diff --git a/src/core/user_script_controller_host.cpp b/src/core/user_script_controller_host.cpp index 227a639b1..d57518275 100644 --- a/src/core/user_script_controller_host.cpp +++ b/src/core/user_script_controller_host.cpp @@ -52,9 +52,12 @@ namespace QtWebEngineCore { class UserScriptControllerHost::WebContentsObserverHelper : public content::WebContentsObserver { public: WebContentsObserverHelper(UserScriptControllerHost *, content::WebContents *); - virtual void AboutToNavigateRenderView(content::RenderViewHost* renderViewHost) Q_DECL_OVERRIDE; - virtual void WebContentsDestroyed() Q_DECL_OVERRIDE; + // WebContentsObserver overrides: + void RenderViewCreated(content::RenderViewHost *renderViewHost) override; + void RenderViewHostChanged(content::RenderViewHost *oldHost, content::RenderViewHost *newHost) override; + void WebContentsDestroyed() override; + private: UserScriptControllerHost *m_controllerHost; }; @@ -65,13 +68,23 @@ UserScriptControllerHost::WebContentsObserverHelper::WebContentsObserverHelper(U { } -void UserScriptControllerHost::WebContentsObserverHelper::AboutToNavigateRenderView(content::RenderViewHost *renderViewHost) +void UserScriptControllerHost::WebContentsObserverHelper::RenderViewCreated(content::RenderViewHost *renderViewHost) { content::WebContents *contents = web_contents(); Q_FOREACH (const UserScript &script, m_controllerHost->m_perContentsScripts.value(contents)) renderViewHost->Send(new RenderViewObserverHelper_AddScript(renderViewHost->GetRoutingID(), script.data())); } +void UserScriptControllerHost::WebContentsObserverHelper::RenderViewHostChanged(content::RenderViewHost *oldHost, + content::RenderViewHost *newHost) +{ + oldHost->Send(new RenderViewObserverHelper_ClearScripts(oldHost->GetRoutingID())); + + content::WebContents *contents = web_contents(); + Q_FOREACH (const UserScript &script, m_controllerHost->m_perContentsScripts.value(contents)) + newHost->Send(new RenderViewObserverHelper_AddScript(newHost->GetRoutingID(), script.data())); +} + void UserScriptControllerHost::WebContentsObserverHelper::WebContentsDestroyed() { m_controllerHost->webContentsDestroyed(web_contents()); diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 8c13035e8..999fc881c 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -46,6 +46,7 @@ #include "browser_context_qt.h" #include "media_capture_devices_dispatcher.h" #include "qt_render_view_observer_host.h" +#include "qwebenginecallback_p.h" #include "type_conversion.h" #include "web_channel_ipc_transport_host.h" #include "web_contents_adapter_client.h" @@ -57,6 +58,7 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/child_process_security_policy.h" +#include <content/public/browser/download_manager.h> #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" @@ -66,7 +68,6 @@ #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 <QDir> @@ -165,19 +166,6 @@ static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint6 adapterClient->didRunJavaScript(requestId, fromJSValue(result)); } -static QStringList listRecursively(const QDir& dir) { - QStringList ret; - QFileInfoList infoList(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot |QDir::Hidden)); - Q_FOREACH (const QFileInfo &fileInfo, infoList) { - if (fileInfo.isDir()) { - ret.append(fileInfo.absolutePath() + QStringLiteral("/.")); // Match chromium's behavior. See chrome/browser/file_select_helper.cc - ret.append(listRecursively(QDir(fileInfo.absoluteFilePath()))); - } else - ret.append(fileInfo.absoluteFilePath()); - } - return ret; -} - static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient, content::BrowserContext *browserContext) { content::WebContents::CreateParams create_params(browserContext, NULL); @@ -217,9 +205,6 @@ static void serializeNavigationHistory(const content::NavigationController &cont output << entry->GetIsOverridingUserAgent(); output << static_cast<qint64>(entry->GetTimestamp().ToInternalValue()); output << entry->GetHttpStatusCode(); - // If you want to navigate a named frame in Chrome, you will first need to - // add support for persisting it. It is currently only used for layout tests. - CHECK(entry->GetFrameToNavigate().empty()); } } } @@ -323,7 +308,7 @@ WebContentsAdapterPrivate::WebContentsAdapterPrivate() : engineContext(WebEngineContext::current()) , webChannel(0) , adapterClient(0) - , nextRequestId(1) + , nextRequestId(CallbackDirectory::ReservedCallbackIdsEnd) , lastFindRequestId(0) { } @@ -495,6 +480,7 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT params.base_url_for_data_url = toGurl(baseUrl); params.virtual_url_for_data_url = baseUrl.isEmpty() ? GURL(url::kAboutBlankURL) : toGurl(baseUrl); params.can_load_local_resources = true; + params.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_API); d->webContents->GetController().LoadURLWithParams(params); } @@ -772,6 +758,38 @@ void WebContentsAdapter::updateWebPreferences(const content::WebPreferences & we d->webContents->GetRenderViewHost()->UpdateWebkitPreferences(webPreferences); } +void WebContentsAdapter::download(const QUrl &url, const QString &suggestedFileName) +{ + content::BrowserContext *bctx = webContents()->GetBrowserContext(); + content::DownloadManager *dlm = content::BrowserContext::GetDownloadManager(bctx); + if (!dlm) + return; + + scoped_ptr<content::DownloadUrlParameters> params( + content::DownloadUrlParameters::FromWebContents(webContents(), toGurl(url))); + params->set_suggested_name(toString16(suggestedFileName)); + dlm->DownloadUrl(params.Pass()); +} + +void WebContentsAdapter::copyImageAt(const QPoint &location) +{ + Q_D(WebContentsAdapter); + d->webContents->GetRenderViewHost()->CopyImageAt(location.x(), location.y()); +} + +ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerNoAction, blink::WebMediaPlayerAction::Unknown) +ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerPlay, blink::WebMediaPlayerAction::Play) +ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerMute, blink::WebMediaPlayerAction::Mute) +ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerLoop, blink::WebMediaPlayerAction::Loop) +ASSERT_ENUMS_MATCH(WebContentsAdapter::MediaPlayerControls, blink::WebMediaPlayerAction::Controls) + +void WebContentsAdapter::executeMediaPlayerActionAt(const QPoint &location, MediaPlayerAction action, bool enable) +{ + Q_D(WebContentsAdapter); + blink::WebMediaPlayerAction blinkAction((blink::WebMediaPlayerAction::Type)action, enable); + d->webContents->GetRenderViewHost()->ExecuteMediaPlayerActionAtLocation(toGfx(location), blinkAction); +} + void WebContentsAdapter::wasShown() { Q_D(WebContentsAdapter); @@ -793,7 +811,7 @@ void WebContentsAdapter::grantMediaAccessPermission(const QUrl &securityOrigin, void WebContentsAdapter::runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed) { Q_D(WebContentsAdapter); - d->webContentsDelegate->geolocationPermissionReply(securityOrigin, allowed); + d->browserContextAdapter->permissionRequestReply(securityOrigin, BrowserContextAdapter::GeolocationPermission, allowed); } void WebContentsAdapter::grantMouseLockPermission(bool granted) @@ -820,21 +838,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) +void WebContentsAdapter::backgroundColorChanged() { Q_D(WebContentsAdapter); - content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); - Q_ASSERT(rvh); - QStringList files(fileList); - if (mode == WebContentsAdapterClient::UploadFolder && !fileList.isEmpty() - && QFileInfo(fileList.first()).isDir()) // Enumerate the directory - files = listRecursively(QDir(fileList.first())); - rvh->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(mode)); + if (content::RenderWidgetHostView *rwhv = d->webContents->GetRenderWidgetHostView()) + rwhv->SetBackgroundColor(toSk(d->adapterClient->backgroundColor())); } content::WebContents *WebContentsAdapter::webContents() const diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 5ea55c1b8..902cc61ff 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -104,7 +104,6 @@ public: void serializeNavigationHistory(QDataStream &output); void setZoomFactor(qreal); qreal currentZoomFactor() const; - void filesSelectedInChooser(const QStringList &fileList, WebContentsAdapterClient::FileChooserMode); void runJavaScript(const QString &javaScript); quint64 runJavaScriptCallbackResult(const QString &javaScript); quint64 fetchDocumentMarkup(); @@ -112,6 +111,19 @@ public: quint64 findText(const QString &subString, bool caseSensitively, bool findBackward); void stopFinding(); void updateWebPreferences(const content::WebPreferences &webPreferences); + void download(const QUrl &url, const QString &suggestedFileName); + + // Must match blink::WebMediaPlayerAction::Type. + enum MediaPlayerAction { + MediaPlayerNoAction, + MediaPlayerPlay, + MediaPlayerMute, + MediaPlayerLoop, + MediaPlayerControls, + MediaPlayerTypeLast = MediaPlayerControls + }; + void copyImageAt(const QPoint &location); + void executeMediaPlayerActionAt(const QPoint &location, MediaPlayerAction action, bool enable); void wasShown(); void wasHidden(); @@ -120,6 +132,7 @@ public: void grantMouseLockPermission(bool granted); void dpiScaleChanged(); + void backgroundColorChanged(); QAccessibleInterface *browserAccessible(); BrowserContextQt* browserContext(); BrowserContextAdapter* browserContextAdapter(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 3ed3ab9ab..86b5d1b79 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -53,6 +53,7 @@ QT_FORWARD_DECLARE_CLASS(CertificateErrorController) namespace QtWebEngineCore { class BrowserContextAdapter; +class FilePickerController; class JavaScriptDialogController; class RenderWidgetHostViewQt; class RenderWidgetHostViewQtDelegate; @@ -65,10 +66,55 @@ class WebEngineSettings; class WebEngineContextMenuData { public: + WebEngineContextMenuData() + : mediaType(MediaTypeNone) + , hasImageContent(false) + , mediaFlags(0) + { + } + + // Must match blink::WebContextMenuData::MediaType: + enum MediaType { + // No special node is in context. + MediaTypeNone, + // An image node is selected. + MediaTypeImage, + // A video node is selected. + MediaTypeVideo, + // An audio node is selected. + MediaTypeAudio, + // A canvas node is selected. + MediaTypeCanvas, + // A file node is selected. + MediaTypeFile, + // A plugin node is selected. + MediaTypePlugin, + MediaTypeLast = MediaTypePlugin + }; + // Must match blink::WebContextMenuData::MediaFlags: + enum MediaFlags { + MediaNone = 0x0, + MediaInError = 0x1, + MediaPaused = 0x2, + MediaMuted = 0x4, + MediaLoop = 0x8, + MediaCanSave = 0x10, + MediaHasAudio = 0x20, + MediaCanToggleControls = 0x40, + MediaControls = 0x80, + MediaCanPrint = 0x100, + MediaCanRotate = 0x200, + }; + QPoint pos; QUrl linkUrl; QString linkText; QString selectedText; + QUrl mediaUrl; + MediaType mediaType; + bool hasImageContent; + uint mediaFlags; + QString suggestedFileName; // Some likely candidates for future additions as we add support for the related actions: // bool isImageBlocked; // bool isEditable; @@ -104,14 +150,6 @@ public: InternalAuthorizationDialog = 0x10, }; - // Must match the ones in file_chooser_params.h - enum FileChooserMode { - Open, - OpenMultiple, - UploadFolder, - Save - }; - enum NavigationRequestAction { AcceptRequest, // Make room in the valid range of the enum for extra actions exposed in Experimental. @@ -119,7 +157,7 @@ public: }; enum NavigationType { - LinkClickedNavigation, + LinkNavigation, TypedNavigation, FormSubmittedNavigation, BackForwardNavigation, @@ -152,6 +190,7 @@ public: virtual void selectionChanged() = 0; virtual QRectF viewportRect() const = 0; virtual qreal dpiScale() const = 0; + virtual QColor backgroundColor() const = 0; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0; virtual void loadCommitted() = 0; virtual void loadVisuallyCommitted() = 0; @@ -165,7 +204,7 @@ public: virtual void requestFullScreen(bool) = 0; virtual bool isFullScreen() const = 0; virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) = 0; - virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) = 0; + virtual void runFileChooser(FilePickerController *controller) = 0; virtual void didRunJavaScript(quint64 requestId, const QVariant& result) = 0; virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) = 0; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index f9db91b3e..93fabf15a 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -41,6 +41,7 @@ #include "web_contents_delegate_qt.h" #include "browser_context_adapter.h" +#include "file_picker_controller.h" #include "media_capture_devices_dispatcher.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" @@ -107,7 +108,7 @@ content::WebContents *WebContentsDelegateQt::OpenURLFromTab(content::WebContents return target; } -void WebContentsDelegateQt::NavigationStateChanged(const content::WebContents* source, content::InvalidateTypes changed_flags) +void WebContentsDelegateQt::NavigationStateChanged(content::WebContents* source, content::InvalidateTypes changed_flags) { if (changed_flags & content::INVALIDATE_TYPE_URL) m_viewClient->urlChanged(toQt(source->GetVisibleURL())); @@ -126,7 +127,7 @@ void WebContentsDelegateQt::AddNewContents(content::WebContents* source, content void WebContentsDelegateQt::CloseContents(content::WebContents *source) { m_viewClient->close(); - GetJavaScriptDialogManager()->CancelActiveAndPendingDialogs(source); + GetJavaScriptDialogManager(source)->CancelActiveAndPendingDialogs(source); } void WebContentsDelegateQt::LoadProgressChanged(content::WebContents* source, double progress) @@ -228,36 +229,47 @@ void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::Favic } } -content::JavaScriptDialogManager *WebContentsDelegateQt::GetJavaScriptDialogManager() +content::JavaScriptDialogManager *WebContentsDelegateQt::GetJavaScriptDialogManager(content::WebContents *) { return JavaScriptDialogManagerQt::GetInstance(); } -void WebContentsDelegateQt::ToggleFullscreenModeForTab(content::WebContents* web_contents, bool enter_fullscreen) +void WebContentsDelegateQt::EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL& origin) { - if (m_viewClient->isFullScreen() != enter_fullscreen) { - m_viewClient->requestFullScreen(enter_fullscreen); + Q_UNUSED(origin); // FIXME + if (!m_viewClient->isFullScreen()) { + m_viewClient->requestFullScreen(true); web_contents->GetRenderViewHost()->WasResized(); } } +void WebContentsDelegateQt::ExitFullscreenModeForTab(content::WebContents *web_contents) +{ + if (m_viewClient->isFullScreen()) { + m_viewClient->requestFullScreen(false); + web_contents->GetRenderViewHost()->WasResized(); + } +} + bool WebContentsDelegateQt::IsFullscreenForTabOrPending(const content::WebContents* web_contents) const { return m_viewClient->isFullScreen(); } -ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Open, content::FileChooserParams::Open) -ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Save, content::FileChooserParams::Save) +ASSERT_ENUMS_MATCH(FilePickerController::Open, content::FileChooserParams::Open) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParams::OpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) +ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) void WebContentsDelegateQt::RunFileChooser(content::WebContents *web_contents, const content::FileChooserParams ¶ms) { - Q_UNUSED(web_contents) QStringList acceptedMimeTypes; acceptedMimeTypes.reserve(params.accept_types.size()); for (std::vector<base::string16>::const_iterator it = params.accept_types.begin(); it < params.accept_types.end(); ++it) acceptedMimeTypes.append(toQt(*it)); - m_viewClient->runFileChooser(static_cast<WebContentsAdapterClient::FileChooserMode>(params.mode), toQt(params.default_file_name.value()), acceptedMimeTypes); + FilePickerController *controller = new FilePickerController(static_cast<FilePickerController::FileChooserMode>(params.mode), web_contents, toQt(params.default_file_name.value()), acceptedMimeTypes); + m_viewClient->runFileChooser(controller); } bool WebContentsDelegateQt::AddMessageToConsole(content::WebContents *source, int32 level, const base::string16 &message, int32 line_no, const base::string16 &source_id) @@ -334,28 +346,9 @@ void WebContentsDelegateQt::allowCertificateError(const QSharedPointer<Certifica m_viewClient->allowCertificateError(errorController); } -void WebContentsDelegateQt::requestGeolocationPermission(const GURL &requestingFrameOrigin, const base::Callback<void (bool)> &resultCallback) +void WebContentsDelegateQt::requestGeolocationPermission(const QUrl &requestingOrigin) { - 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) -{ - auto it = m_geolocationPermissionRequests.find(origin); - if (it != m_geolocationPermissionRequests.end()) { - (*it).Run(permission); - m_geolocationPermissionRequests.erase(it); - } + m_viewClient->runGeolocationPermissionRequest(requestingOrigin); } void WebContentsDelegateQt::ShowValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view, const base::string16 &main_text, const base::string16 &sub_text) diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 254177d24..b983738e9 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -39,6 +39,7 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" +#include "content/public/common/permission_status.mojom.h" #include "base/callback.h" @@ -72,13 +73,14 @@ public: // WebContentsDelegate overrides virtual content::WebContents *OpenURLFromTab(content::WebContents *source, const content::OpenURLParams ¶ms) Q_DECL_OVERRIDE; - virtual void NavigationStateChanged(const content::WebContents* source, content::InvalidateTypes changed_flags) Q_DECL_OVERRIDE; + virtual void NavigationStateChanged(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 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 content::JavaScriptDialogManager *GetJavaScriptDialogManager(content::WebContents *source) Q_DECL_OVERRIDE; + virtual void EnterFullscreenModeForTab(content::WebContents* web_contents, const GURL& origin) Q_DECL_OVERRIDE; + virtual void ExitFullscreenModeForTab(content::WebContents*) Q_DECL_OVERRIDE; virtual bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const Q_DECL_OVERRIDE; virtual void RunFileChooser(content::WebContents *, const content::FileChooserParams ¶ms) Q_DECL_OVERRIDE; virtual bool AddMessageToConsole(content::WebContents* source, int32 level, const base::string16& message, int32 line_no, const base::string16& source_id) Q_DECL_OVERRIDE; @@ -101,15 +103,11 @@ public: 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); + void requestGeolocationPermission(const QUrl &requestingOrigin); 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 af0c1fe38..c32753435 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -53,8 +53,10 @@ void WebContentsViewQt::initialize(WebContentsAdapterClient* client) m_factoryClient = client; // Check if a RWHV was created before the initialization. - if (m_webContents->GetRenderWidgetHostView()) - static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())->setAdapterClient(client); + if (auto rwhv = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) { + rwhv->setAdapterClient(client); + rwhv->SetBackgroundColor(toSk(client->backgroundColor())); + } } content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) @@ -82,6 +84,14 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForPopupWidget(c return view; } +void WebContentsViewQt::RenderViewCreated(content::RenderViewHost* host) +{ + // The render process is done creating the RenderView and it's ready to be routed + // messages at this point. + if (m_client) + host->GetView()->SetBackgroundColor(toSk(m_client->backgroundColor())); +} + void WebContentsViewQt::CreateView(const gfx::Size& initial_size, gfx::NativeView context) { // This is passed through content::WebContents::CreateParams::context either as the native view's client @@ -111,6 +121,26 @@ void WebContentsViewQt::SetInitialFocus() Focus(); } +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeNone, blink::WebContextMenuData::MediaTypeNone) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeImage, blink::WebContextMenuData::MediaTypeImage) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeVideo, blink::WebContextMenuData::MediaTypeVideo) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeAudio, blink::WebContextMenuData::MediaTypeAudio) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeCanvas, blink::WebContextMenuData::MediaTypeCanvas) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeFile, blink::WebContextMenuData::MediaTypeFile) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypePlugin, blink::WebContextMenuData::MediaTypePlugin) + +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaNone, blink::WebContextMenuData::MediaNone) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaInError, blink::WebContextMenuData::MediaInError) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaPaused, blink::WebContextMenuData::MediaPaused) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaMuted, blink::WebContextMenuData::MediaMuted) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaLoop, blink::WebContextMenuData::MediaLoop) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanSave, blink::WebContextMenuData::MediaCanSave) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaHasAudio, blink::WebContextMenuData::MediaHasAudio) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanToggleControls, blink::WebContextMenuData::MediaCanToggleControls) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaControls, blink::WebContextMenuData::MediaControls) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanPrint, blink::WebContextMenuData::MediaCanPrint) +ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanRotate, blink::WebContextMenuData::MediaCanRotate) + static WebEngineContextMenuData fromParams(const content::ContextMenuParams ¶ms) { WebEngineContextMenuData ret; @@ -118,6 +148,11 @@ static WebEngineContextMenuData fromParams(const content::ContextMenuParams &par ret.linkUrl = toQt(params.link_url); ret.linkText = toQt(params.link_text.data()); ret.selectedText = toQt(params.selection_text.data()); + ret.mediaUrl = toQt(params.src_url); + ret.mediaType = (WebEngineContextMenuData::MediaType)params.media_type; + ret.hasImageContent = params.has_image_contents; + ret.mediaFlags = params.media_flags; + ret.suggestedFileName = toQt(params.suggested_filename.data()); return ret; } diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index 896955f7d..cbbca2371 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -43,8 +43,9 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" -#include "web_contents_adapter_client.h" +#include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt.h" +#include "web_contents_adapter_client.h" #include "web_contents_delegate_qt.h" #include "web_engine_context.h" @@ -75,7 +76,7 @@ public: virtual void SetPageTitle(const base::string16& title) Q_DECL_OVERRIDE { } - virtual void RenderViewCreated(content::RenderViewHost* host) Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } + virtual void RenderViewCreated(content::RenderViewHost* host) Q_DECL_OVERRIDE; virtual void RenderViewSwappedIn(content::RenderViewHost* host) Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED } diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 8bc047321..727cfb491 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -202,34 +202,35 @@ WebEngineContext::WebEngineContext() Q_FOREACH (const QString& arg, QCoreApplication::arguments()) args << arg.toUtf8(); + bool useEmbeddedSwitches = args.removeAll("--enable-embedded-switches"); +#if defined(QTWEBENGINE_EMBEDDED_SWITCHES) + useEmbeddedSwitches = !args.removeAll("--disable-embedded-switches"); +#endif + QVector<const char*> argv(args.size()); for (int i = 0; i < args.size(); ++i) argv[i] = args[i].constData(); - CommandLine::Init(argv.size(), argv.constData()); + base::CommandLine::Init(argv.size(), argv.constData()); - CommandLine* parsedCommandLine = CommandLine::ForCurrentProcess(); + base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); parsedCommandLine->AppendSwitchPath(switches::kBrowserSubprocessPath, WebEngineLibraryInfo::getPath(content::CHILD_PROCESS_EXE)); parsedCommandLine->AppendSwitch(switches::kNoSandbox); - parsedCommandLine->AppendSwitch(switches::kDisablePlugins); parsedCommandLine->AppendSwitch(switches::kEnableDelegatedRenderer); parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing); parsedCommandLine->AppendSwitch(switches::kInProcessGPU); -#if defined(QTWEBENGINE_MOBILE_SWITCHES) - // Inspired by the Android port's default switches - parsedCommandLine->AppendSwitch(switches::kEnableOverlayScrollbar); - parsedCommandLine->AppendSwitch(switches::kEnablePinch); - parsedCommandLine->AppendSwitch(switches::kEnableViewport); - parsedCommandLine->AppendSwitch(switches::kEnableViewportMeta); - parsedCommandLine->AppendSwitch(switches::kMainFrameResizesAreOrientationChanges); - parsedCommandLine->AppendSwitch(switches::kDisableAcceleratedVideoDecode); - parsedCommandLine->AppendSwitch(switches::kDisableGpuShaderDiskCache); - parsedCommandLine->AppendSwitch(switches::kDisable2dCanvasAntialiasing); - parsedCommandLine->AppendSwitch(switches::kEnableImplSidePainting); - parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing); - - parsedCommandLine->AppendSwitchASCII(switches::kProfilerTiming, switches::kProfilerTimingDisabledValue); -#endif + if (useEmbeddedSwitches) { + // Inspired by the Android port's default switches + parsedCommandLine->AppendSwitch(switches::kEnableOverlayScrollbar); + parsedCommandLine->AppendSwitch(switches::kEnablePinch); + parsedCommandLine->AppendSwitch(switches::kEnableViewport); + parsedCommandLine->AppendSwitch(switches::kMainFrameResizesAreOrientationChanges); + parsedCommandLine->AppendSwitch(switches::kDisableAcceleratedVideoDecode); + parsedCommandLine->AppendSwitch(switches::kDisableGpuShaderDiskCache); + parsedCommandLine->AppendSwitch(switches::kDisable2dCanvasAntialiasing); + parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing); + parsedCommandLine->AppendSwitchASCII(switches::kProfilerTiming, switches::kProfilerTimingDisabledValue); + } GLContextHelper::initialize(); @@ -260,13 +261,13 @@ WebEngineContext::WebEngineContext() contentMainParams.sandbox_info = &sandbox_info; #endif m_contentRunner->Initialize(contentMainParams); - m_browserRunner->Initialize(content::MainFunctionParams(*CommandLine::ForCurrentProcess())); + m_browserRunner->Initialize(content::MainFunctionParams(*base::CommandLine::ForCurrentProcess())); // Once the MessageLoop has been created, attach a top-level RunLoop. m_runLoop.reset(new base::RunLoop); m_runLoop->BeforeRun(); - m_devtools.reset(new DevToolsHttpHandlerDelegateQt); + m_devtools = createDevToolsHttpHandler(); // 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. diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index dea54ef8a..8f034f18f 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -41,6 +41,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "components/devtools_http_handler/devtools_http_handler.h" #include <QExplicitlySharedDataPointer> @@ -59,7 +61,6 @@ namespace QtWebEngineCore { class BrowserContextAdapter; class ContentMainDelegateQt; -class DevToolsHttpHandlerDelegateQt; class SurfaceFactoryQt; } // namespace @@ -84,7 +85,7 @@ private: scoped_ptr<content::BrowserMainRunner> m_browserRunner; QObject* m_globalQObject; QExplicitlySharedDataPointer<QtWebEngineCore::BrowserContextAdapter> m_defaultBrowserContext; - scoped_ptr<QtWebEngineCore::DevToolsHttpHandlerDelegateQt> m_devtools; + scoped_ptr<devtools_http_handler::DevToolsHttpHandler> 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 980e9a39a..bc030d8f7 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -162,7 +162,6 @@ QString pluginsPath() if (!initialized) { initialized = true; - const QStringList directories = QCoreApplication::libraryPaths(); Q_FOREACH (const QString &dir, directories) { const QString candidate = dir % "/" % QLatin1String("qtwebengine"); @@ -173,7 +172,6 @@ QString pluginsPath() } if (pluginsPath.isEmpty()) { - qWarning("Qt WebEngine Plugins directory not found. Trying fallback directory... Plugins as for example video codecs MAY NOT work."); pluginsPath = fallbackDir(); } } @@ -276,7 +274,7 @@ base::string16 WebEngineLibraryInfo::getApplicationName() std::string WebEngineLibraryInfo::getApplicationLocale() { - CommandLine *parsedCommandLine = CommandLine::ForCurrentProcess(); + base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess(); if (!parsedCommandLine->HasSwitch(switches::kLang)) return QLocale().bcp47Name().toStdString(); diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 74c60b778..b59ec7311 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -213,6 +213,8 @@ void WebEngineSettings::initDefaults(bool offTheRecord) m_attributes.insert(HyperlinkAuditingEnabled, false); m_attributes.insert(ScrollAnimatorEnabled, false); m_attributes.insert(ErrorPageEnabled, true); + m_attributes.insert(PluginsEnabled, false); + m_attributes.insert(FullscreenSupportEnabled, false); // Default fonts QFont defaultFont; @@ -277,6 +279,8 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p prefs->hyperlink_auditing_enabled = testAttribute(HyperlinkAuditingEnabled); prefs->enable_scroll_animator = testAttribute(ScrollAnimatorEnabled); prefs->enable_error_page = testAttribute(ErrorPageEnabled); + prefs->plugins_enabled = testAttribute(PluginsEnabled); + prefs->fullscreen_supported = testAttribute(FullscreenSupportEnabled); // Fonts settings. prefs->standard_font_family_map[content::kCommonScript] = toString16(fontFamily(StandardFont)); diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index e9d8010a8..1d8f83184 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -71,6 +71,8 @@ public: HyperlinkAuditingEnabled, ScrollAnimatorEnabled, ErrorPageEnabled, + PluginsEnabled, + FullscreenSupportEnabled, }; // Must match the values from the public API in qwebenginesettings.h. diff --git a/src/core/yuv_video_node.cpp b/src/core/yuv_video_node.cpp index 23528c8ec..815ea7d51 100644 --- a/src/core/yuv_video_node.cpp +++ b/src/core/yuv_video_node.cpp @@ -61,12 +61,16 @@ protected: "attribute highp vec4 a_position;\n" "attribute mediump vec2 a_texCoord;\n" "uniform highp mat4 matrix;\n" - "varying mediump vec2 v_texCoord;\n" - "uniform mediump vec2 texScale;\n" - "uniform mediump vec2 texOffset;\n" + "varying mediump vec2 v_yaTexCoord;\n" + "varying mediump vec2 v_uvTexCoord;\n" + "uniform mediump vec2 yaTexScale;\n" + "uniform mediump vec2 yaTexOffset;\n" + "uniform mediump vec2 uvTexScale;\n" + "uniform mediump vec2 uvTexOffset;\n" "void main() {\n" " gl_Position = matrix * a_position;\n" - " v_texCoord = a_texCoord * texScale + texOffset;\n" + " v_yaTexCoord = a_texCoord * yaTexScale + yaTexOffset;\n" + " v_uvTexCoord = a_texCoord * uvTexScale + uvTexOffset;\n" "}"; return shader; } @@ -74,19 +78,26 @@ protected: virtual const char *fragmentShader() const Q_DECL_OVERRIDE { // Keep in sync with cc::FragmentShaderYUVVideo static const char *shader = - "varying mediump vec2 v_texCoord;\n" + "varying mediump vec2 v_yaTexCoord;\n" + "varying mediump vec2 v_uvTexCoord;\n" "uniform sampler2D y_texture;\n" "uniform sampler2D u_texture;\n" "uniform sampler2D v_texture;\n" - "uniform lowp float alpha;\n" - "uniform lowp vec3 yuv_adj;\n" - "uniform lowp mat3 yuv_matrix;\n" + "uniform mediump float alpha;\n" + "uniform mediump vec3 yuv_adj;\n" + "uniform mediump mat3 yuv_matrix;\n" + "uniform mediump vec4 ya_clamp_rect;\n" + "uniform mediump vec4 uv_clamp_rect;\n" "void main() {\n" - " lowp float y_raw = texture2D(y_texture, v_texCoord).x;\n" - " lowp float u_unsigned = texture2D(u_texture, v_texCoord).x;\n" - " lowp float v_unsigned = texture2D(v_texture, v_texCoord).x;\n" - " lowp vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" - " lowp vec3 rgb = yuv_matrix * yuv;\n" + " mediump vec2 ya_clamped =\n" + " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n" + " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n" + " mediump vec2 uv_clamped =\n" + " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n" + " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n" + " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n" + " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" + " mediump vec3 rgb = yuv_matrix * yuv;\n" " gl_FragColor = vec4(rgb, 1.0) * alpha;\n" "}"; return shader; @@ -94,8 +105,12 @@ protected: virtual void initialize() Q_DECL_OVERRIDE { m_id_matrix = program()->uniformLocation("matrix"); - m_id_texScale = program()->uniformLocation("texScale"); - m_id_texOffset = program()->uniformLocation("texOffset"); + m_id_yaTexScale = program()->uniformLocation("yaTexScale"); + m_id_uvTexScale = program()->uniformLocation("uvTexScale"); + m_id_yaTexOffset = program()->uniformLocation("yaTexOffset"); + m_id_uvTexOffset = program()->uniformLocation("uvTexOffset"); + m_id_yaClampRect = program()->uniformLocation("ya_clamp_rect"); + m_id_uvClampRect = program()->uniformLocation("uv_clamp_rect"); m_id_yTexture = program()->uniformLocation("y_texture"); m_id_uTexture = program()->uniformLocation("u_texture"); m_id_vTexture = program()->uniformLocation("v_texture"); @@ -105,8 +120,12 @@ protected: } int m_id_matrix; - int m_id_texScale; - int m_id_texOffset; + int m_id_yaTexScale; + int m_id_uvTexScale; + int m_id_yaTexOffset; + int m_id_uvTexOffset; + int m_id_yaClampRect; + int m_id_uvClampRect; int m_id_yTexture; int m_id_uTexture; int m_id_vTexture; @@ -123,21 +142,28 @@ protected: virtual const char *fragmentShader() const Q_DECL_OVERRIDE { // Keep in sync with cc::FragmentShaderYUVAVideo static const char *shader = - "varying mediump vec2 v_texCoord;\n" + "varying mediump vec2 v_yaTexCoord;\n" + "varying mediump vec2 v_uvTexCoord;\n" "uniform sampler2D y_texture;\n" "uniform sampler2D u_texture;\n" "uniform sampler2D v_texture;\n" "uniform sampler2D a_texture;\n" - "uniform lowp float alpha;\n" - "uniform lowp vec3 yuv_adj;\n" - "uniform lowp mat3 yuv_matrix;\n" + "uniform mediump float alpha;\n" + "uniform mediump vec3 yuv_adj;\n" + "uniform mediump mat3 yuv_matrix;\n" + "uniform mediump vec4 ya_clamp_rect;\n" + "uniform mediump vec4 uv_clamp_rect;\n" "void main() {\n" - " lowp float y_raw = texture2D(y_texture, v_texCoord).x;\n" - " lowp float u_unsigned = texture2D(u_texture, v_texCoord).x;\n" - " lowp float v_unsigned = texture2D(v_texture, v_texCoord).x;\n" - " lowp float a_raw = texture2D(a_texture, v_texCoord).x;\n" - " lowp vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" - " lowp vec3 rgb = yuv_matrix * yuv;\n" + " mediump vec2 ya_clamped =\n" + " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n" + " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n" + " mediump vec2 uv_clamped =\n" + " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n" + " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n" + " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n" + " mediump float a_raw = texture2D(a_texture, ya_clamped).x;\n" + " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n" + " mediump vec3 rgb = yuv_matrix * yuv;\n" " gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);\n" "}"; return shader; @@ -156,6 +182,8 @@ void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial * { Q_UNUSED(oldMaterial); + // Keep logic in sync with logic in GLRenderer::DrawYUVVideoQuad: + YUVVideoMaterial *mat = static_cast<YUVVideoMaterial *>(newMaterial); program()->setUniformValue(m_id_yTexture, 0); program()->setUniformValue(m_id_uTexture, 1); @@ -170,18 +198,47 @@ void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial * glFuncs.glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit mat->m_yTexture->bind(); - program()->setUniformValue(m_id_texOffset, mat->m_texCoordRect.topLeft()); - program()->setUniformValue(m_id_texScale, mat->m_texCoordRect.size()); + const QSizeF yaSizeScale(1.0f / mat->m_yaTexSize.width(), 1.0f / mat->m_yaTexSize.height()); + const QSizeF uvSizeScale(1.0f / mat->m_uvTexSize.width(), 1.0f / mat->m_uvTexSize.height()); + + const QPointF yaTexOffset(mat->m_yaTexCoordRect.left() * yaSizeScale.width(), mat->m_yaTexCoordRect.top() * yaSizeScale.height()); + const QPointF uvTexOffset(mat->m_uvTexCoordRect.left() * uvSizeScale.width(), mat->m_uvTexCoordRect.top() * uvSizeScale.height()); + const QSizeF yaTexScale(mat->m_yaTexCoordRect.width() * yaSizeScale.width(), mat->m_yaTexCoordRect.height() * yaSizeScale.height()); + const QSizeF uvTexScale(mat->m_uvTexCoordRect.width() * uvSizeScale.width(), mat->m_uvTexCoordRect.height() * uvSizeScale.height()); + program()->setUniformValue(m_id_yaTexOffset, yaTexOffset); + program()->setUniformValue(m_id_uvTexOffset, uvTexOffset); + program()->setUniformValue(m_id_yaTexScale, yaTexScale); + program()->setUniformValue(m_id_uvTexScale, uvTexScale); + QRectF yaClampRect(yaTexOffset, yaTexScale); + QRectF uvClampRect(uvTexOffset, uvTexScale); + yaClampRect = yaClampRect.marginsRemoved(QMarginsF(yaSizeScale.width() * 0.5f, yaSizeScale.height() * 0.5f, + yaSizeScale.width() * 0.5f, yaSizeScale.height() * 0.5f)); + uvClampRect = uvClampRect.marginsRemoved(QMarginsF(uvSizeScale.width() * 0.5f, uvSizeScale.height() * 0.5f, + uvSizeScale.width() * 0.5f, uvSizeScale.height() * 0.5f)); + + const QVector4D yaClampV(yaClampRect.left(), yaClampRect.top(), yaClampRect.right(), yaClampRect.bottom()); + const QVector4D uvClampV(uvClampRect.left(), uvClampRect.top(), uvClampRect.right(), uvClampRect.bottom()); + program()->setUniformValue(m_id_yaClampRect, yaClampV); + program()->setUniformValue(m_id_uvClampRect, uvClampV); // These values are magic numbers that are used in the transformation from YUV // to RGB color values. They are taken from the following webpage: // http://www.fourcc.org/fccyvrgb.php - const float yuv_to_rgb[9] = { + const float yuv_to_rgb_rec601[9] = { 1.164f, 0.0f, 1.596f, 1.164f, -.391f, -.813f, 1.164f, 2.018f, 0.0f, }; - const QMatrix3x3 yuvMatrix(yuv_to_rgb); + const float yuv_to_rgb_rec709[9] = { + 1.164f, 0.0f, 1.793f, + 1.164f, -0.213f, -0.533f, + 1.164f, 2.112f, 0.0f, + }; + const float yuv_to_rgb_jpeg[9] = { + 1.f, 0.0f, 1.402f, + 1.f, -.34414f, -.71414f, + 1.f, 1.772f, 0.0f, + }; // These values map to 16, 128, and 128 respectively, and are computed // as a fraction over 256 (e.g. 16 / 256 = 0.0625). @@ -189,9 +246,35 @@ void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial * // Y - 16 : Gives 16 values of head and footroom for overshooting // U - 128 : Turns unsigned U into signed U [-128,127] // V - 128 : Turns unsigned V into signed V [-128,127] - const QVector3D yuvAdjust(-0.0625f, -0.5f, -0.5f); - program()->setUniformValue(m_id_yuvMatrix, yuvMatrix); - program()->setUniformValue(m_id_yuvAdjust, yuvAdjust); + const float yuv_adjust_constrained[3] = { + -0.0625f, -0.5f, -0.5f, + }; + + // Same as above, but without the head and footroom. + const float yuv_adjust_full[3] = { + 0.0f, -0.5f, -0.5f, + }; + + const float *yuv_to_rgb = 0; + const float *yuv_adjust = 0; + + switch (mat->m_colorSpace) { + case YUVVideoMaterial::REC_601: + yuv_to_rgb = yuv_to_rgb_rec601; + yuv_adjust = yuv_adjust_constrained; + break; + case YUVVideoMaterial::REC_709: + yuv_to_rgb = yuv_to_rgb_rec709; + yuv_adjust = yuv_adjust_constrained; + break; + case YUVVideoMaterial::JPEG: + yuv_to_rgb = yuv_to_rgb_jpeg; + yuv_adjust = yuv_adjust_full; + break; + } + + program()->setUniformValue(m_id_yuvMatrix, QMatrix3x3(yuv_to_rgb)); + program()->setUniformValue(m_id_yuvAdjust, QVector3D(yuv_adjust[0], yuv_adjust[1], yuv_adjust[2])); if (state.isOpacityDirty()) program()->setUniformValue(m_id_opacity, state.opacity()); @@ -217,11 +300,17 @@ void YUVAVideoMaterialShader::updateState(const RenderState &state, QSGMaterial } -YUVVideoMaterial::YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, const QRectF &texCoordRect) +YUVVideoMaterial::YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace) : m_yTexture(yTexture) , m_uTexture(uTexture) , m_vTexture(vTexture) - , m_texCoordRect(texCoordRect) + , m_yaTexCoordRect(yaTexCoordRect) + , m_uvTexCoordRect(uvTexCoordRect) + , m_yaTexSize(yaTexSize) + , m_uvTexSize(uvTexSize) + , m_colorSpace(colorspace) { } @@ -240,8 +329,10 @@ int YUVVideoMaterial::compare(const QSGMaterial *other) const return m_vTexture->textureId() - m->m_vTexture->textureId(); } -YUVAVideoMaterial::YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QRectF &texCoordRect) - : YUVVideoMaterial(yTexture, uTexture, vTexture, texCoordRect) +YUVAVideoMaterial::YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace) + : YUVVideoMaterial(yTexture, uTexture, vTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace) , m_aTexture(aTexture) { setFlag(Blending, aTexture); @@ -260,15 +351,17 @@ int YUVAVideoMaterial::compare(const QSGMaterial *other) const return (m_aTexture ? m_aTexture->textureId() : 0) - (m->m_aTexture ? m->m_aTexture->textureId() : 0); } -YUVVideoNode::YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QRectF &texCoordRect) +YUVVideoNode::YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace) : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) { setGeometry(&m_geometry); setFlag(QSGNode::OwnsMaterial); if (aTexture) - m_material = new YUVAVideoMaterial(yTexture, uTexture, vTexture, aTexture, texCoordRect); + m_material = new YUVAVideoMaterial(yTexture, uTexture, vTexture, aTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace); else - m_material = new YUVVideoMaterial(yTexture, uTexture, vTexture, texCoordRect); + m_material = new YUVVideoMaterial(yTexture, uTexture, vTexture, yaTexCoordRect, uvTexCoordRect, yaTexSize, uvTexSize, colorspace); setMaterial(m_material); } diff --git a/src/core/yuv_video_node.h b/src/core/yuv_video_node.h index f96df56ce..457c2c7fe 100644 --- a/src/core/yuv_video_node.h +++ b/src/core/yuv_video_node.h @@ -50,7 +50,14 @@ QT_END_NAMESPACE class YUVVideoMaterial : public QSGMaterial { public: - YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, const QRectF &texCoordRect); + enum ColorSpace { + REC_601, // SDTV standard with restricted "studio swing" color range. + REC_709, // HDTV standard with restricted "studio swing" color range. + JPEG // Full color range [0, 255] JPEG color space. + }; + YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + ColorSpace colorspace); virtual QSGMaterialType *type() const Q_DECL_OVERRIDE { static QSGMaterialType theType; @@ -63,13 +70,20 @@ public: QSGTexture *m_yTexture; QSGTexture *m_uTexture; QSGTexture *m_vTexture; - QRectF m_texCoordRect; + QRectF m_yaTexCoordRect; + QRectF m_uvTexCoordRect; + QSizeF m_yaTexSize; + QSizeF m_uvTexSize; + ColorSpace m_colorSpace; + }; class YUVAVideoMaterial : public YUVVideoMaterial { public: - YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QRectF &texCoordRect); + YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + ColorSpace colorspace); virtual QSGMaterialType *type() const Q_DECL_OVERRIDE{ static QSGMaterialType theType; @@ -85,7 +99,9 @@ public: class YUVVideoNode : public QSGGeometryNode { public: - YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QRectF &texCoordRect); + YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, + const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, + YUVVideoMaterial::ColorSpace colorspace); void setRect(const QRectF &rect); private: diff --git a/src/webengine/api/qquickwebenginenewviewrequest.cpp b/src/webengine/api/qquickwebenginenewviewrequest.cpp index 36c5e44e1..dd197dfe4 100644 --- a/src/webengine/api/qquickwebenginenewviewrequest.cpp +++ b/src/webengine/api/qquickwebenginenewviewrequest.cpp @@ -90,7 +90,7 @@ bool QQuickWebEngineNewViewRequest::isUserInitiated() const */ void QQuickWebEngineNewViewRequest::openIn(QQuickWebEngineView *view) { - if (!m_adapter) { + if (!m_adapter && !m_requestedUrl.isValid()) { 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."); @@ -101,6 +101,9 @@ void QQuickWebEngineNewViewRequest::openIn(QQuickWebEngineView *view) qWarning("Trying to open a WebEngineNewViewRequest in an invalid WebEngineView."); return; } - view->d_func()->adoptWebContents(m_adapter.data()); + if (m_adapter) + view->d_func()->adoptWebContents(m_adapter.data()); + else + view->setUrl(m_requestedUrl); m_adapter.reset(); } diff --git a/src/webengine/api/qquickwebenginenewviewrequest_p.h b/src/webengine/api/qquickwebenginenewviewrequest_p.h index f9fac13e9..b408812ba 100644 --- a/src/webengine/api/qquickwebenginenewviewrequest_p.h +++ b/src/webengine/api/qquickwebenginenewviewrequest_p.h @@ -73,6 +73,8 @@ private: QQuickWebEngineView::NewViewDestination m_destination; bool m_isUserInitiated; QExplicitlySharedDataPointer<QtWebEngineCore::WebContentsAdapter> m_adapter; + QUrl m_requestedUrl; + friend class QQuickWebEngineView; friend class QQuickWebEngineViewPrivate; }; diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 69c524356..38b042fff 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -56,6 +56,9 @@ QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(BrowserContextAdapt { m_browserContextRef->addClient(this); m_settings->d_ptr->initDefaults(browserContext->isOffTheRecord()); + // Fullscreen API was implemented before the supported setting, so we must + // make it default true to avoid change in default API behavior. + m_settings->d_ptr->setAttribute(QtWebEngineCore::WebEngineSettings::FullscreenSupportEnabled, true); } QQuickWebEngineProfilePrivate::~QQuickWebEngineProfilePrivate() @@ -396,6 +399,28 @@ void QQuickWebEngineProfile::setHttpCacheMaximumSize(int maximumSize) emit httpCacheMaximumSizeChanged(); } +/*! + \qmlproperty QString WebEngineProfile::httpAcceptLanguage + + The value of the Accept-Language HTTP request-header field. + + \since QtWebEngine 1.2 +*/ +QString QQuickWebEngineProfile::httpAcceptLanguage() const +{ + Q_D(const QQuickWebEngineProfile); + return d->browserContext()->httpAcceptLanguage(); +} + +void QQuickWebEngineProfile::setHttpAcceptLanguage(const QString &httpAcceptLanguage) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->httpAcceptLanguage() == httpAcceptLanguage) + return; + d->browserContext()->setHttpAcceptLanguage(httpAcceptLanguage); + emit httpAcceptLanguageChanged(); +} + QQuickWebEngineProfile *QQuickWebEngineProfile::defaultProfile() { static QQuickWebEngineProfile *profile = new QQuickWebEngineProfile( diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h index d07428cab..1824b3e96 100644 --- a/src/webengine/api/qquickwebengineprofile_p.h +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -74,6 +74,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineProfile : public QObject { 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(QString httpAcceptLanguage READ httpAcceptLanguage WRITE setHttpAcceptLanguage NOTIFY httpAcceptLanguageChanged FINAL) Q_PROPERTY(PersistentCookiesPolicy persistentCookiesPolicy READ persistentCookiesPolicy WRITE setPersistentCookiesPolicy NOTIFY persistentCookiesPolicyChanged FINAL) Q_PROPERTY(int httpCacheMaximumSize READ httpCacheMaximumSize WRITE setHttpCacheMaximumSize NOTIFY httpCacheMaximumSizeChanged FINAL) public: @@ -115,6 +116,9 @@ public: int httpCacheMaximumSize() const; void setHttpCacheMaximumSize(int maxSize); + Q_REVISION(2) QString httpAcceptLanguage() const; + Q_REVISION(2) void setHttpAcceptLanguage(const QString &httpAcceptLanguage); + static QQuickWebEngineProfile *defaultProfile(); signals: @@ -126,6 +130,7 @@ signals: void httpCacheTypeChanged(); void persistentCookiesPolicyChanged(); void httpCacheMaximumSizeChanged(); + Q_REVISION(2) void httpAcceptLanguageChanged(); void downloadRequested(QQuickWebEngineDownloadItem *download); void downloadFinished(QQuickWebEngineDownloadItem *download); diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp index 8a88bac68..6a012ba39 100644 --- a/src/webengine/api/qquickwebenginesettings.cpp +++ b/src/webengine/api/qquickwebenginesettings.cpp @@ -209,6 +209,31 @@ bool QQuickWebEngineSettings::errorPageEnabled() const } /*! + \qmlproperty bool WebEngineSettings::pluginsEnabled + + This setting enables general support for plugins. + + It is disabled by default. +*/ +bool QQuickWebEngineSettings::pluginsEnabled() const +{ + return d_ptr->testAttribute(WebEngineSettings::PluginsEnabled); +} + +/*! + \qmlproperty bool WebEngineSettings::fullscreenSupportEnabled + \since QtWebEngine 1.2 + + This setting tells the web engine if fullscreen is supported in this application or not. + + It is enabled by default. +*/ +bool QQuickWebEngineSettings::fullscreenSupportEnabled() const +{ + return d_ptr->testAttribute(WebEngineSettings::FullscreenSupportEnabled); +} + +/*! \qmlproperty QString WebEngineSettings::defaultTextEncoding The \a encoding, must be a string describing an encoding such as "utf-8", @@ -312,6 +337,22 @@ void QQuickWebEngineSettings::setErrorPageEnabled(bool on) Q_EMIT errorPageEnabledChanged(); } +void QQuickWebEngineSettings::setPluginsEnabled(bool on) +{ + bool wasOn = d_ptr->testAttribute(WebEngineSettings::PluginsEnabled); + d_ptr->setAttribute(WebEngineSettings::PluginsEnabled, on); + if (wasOn != on) + Q_EMIT pluginsEnabledChanged(); +} + +void QQuickWebEngineSettings::setFullscreenSupportEnabled(bool on) +{ + bool wasOn = d_ptr->testAttribute(WebEngineSettings::FullscreenSupportEnabled); + d_ptr->setAttribute(WebEngineSettings::FullscreenSupportEnabled, on); + if (wasOn != on) + Q_EMIT fullscreenSupportEnabledChanged(); +} + void QQuickWebEngineSettings::setDefaultTextEncoding(QString encoding) { const QString oldDefaultTextEncoding = d_ptr->defaultTextEncoding(); diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index 213505078..e3f28ac92 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -71,6 +71,8 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_PROPERTY(bool localContentCanAccessFileUrls READ localContentCanAccessFileUrls WRITE setLocalContentCanAccessFileUrls NOTIFY localContentCanAccessFileUrlsChanged) Q_PROPERTY(bool hyperlinkAuditingEnabled READ hyperlinkAuditingEnabled WRITE setHyperlinkAuditingEnabled NOTIFY hyperlinkAuditingEnabledChanged) Q_PROPERTY(bool errorPageEnabled READ errorPageEnabled WRITE setErrorPageEnabled NOTIFY errorPageEnabledChanged) + Q_PROPERTY(bool pluginsEnabled READ pluginsEnabled WRITE setPluginsEnabled NOTIFY pluginsEnabledChanged) + Q_PROPERTY(bool fullscreenSupportEnabled READ fullscreenSupportEnabled WRITE setFullscreenSupportEnabled NOTIFY fullscreenSupportEnabledChanged REVISION 1) Q_PROPERTY(QString defaultTextEncoding READ defaultTextEncoding WRITE setDefaultTextEncoding NOTIFY defaultTextEncodingChanged) public: @@ -87,6 +89,8 @@ public: bool localContentCanAccessFileUrls() const; bool hyperlinkAuditingEnabled() const; bool errorPageEnabled() const; + bool pluginsEnabled() const; + bool fullscreenSupportEnabled() const; QString defaultTextEncoding() const; void setAutoLoadImages(bool on); @@ -100,6 +104,8 @@ public: void setLocalContentCanAccessFileUrls(bool on); void setHyperlinkAuditingEnabled(bool on); void setErrorPageEnabled(bool on); + void setPluginsEnabled(bool on); + void setFullscreenSupportEnabled(bool on); void setDefaultTextEncoding(QString encoding); signals: @@ -114,6 +120,8 @@ signals: void localContentCanAccessFileUrlsChanged(); void hyperlinkAuditingEnabledChanged(); void errorPageEnabledChanged(); + void pluginsEnabledChanged(); + Q_REVISION(1) void fullscreenSupportEnabledChanged(); void defaultTextEncodingChanged(); private: diff --git a/src/webengine/api/qquickwebenginetestsupport_p.h b/src/webengine/api/qquickwebenginetestsupport_p.h index 8d52dfa7c..9690e538d 100644 --- a/src/webengine/api/qquickwebenginetestsupport_p.h +++ b/src/webengine/api/qquickwebenginetestsupport_p.h @@ -78,6 +78,9 @@ public: QQuickWebEngineTestSupport(); QQuickWebEngineErrorPage *errorPage() const; +Q_SIGNALS: + void validationMessageShown(const QString &mainText, const QString &subText); + private: QScopedPointer<QQuickWebEngineErrorPage> m_errorPage; }; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 7405cae44..45bb5a140 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -39,6 +39,7 @@ #include "browser_context_adapter.h" #include "certificate_error_controller.h" +#include "file_picker_controller.h" #include "javascript_dialog_controller.h" #include "qquickwebenginehistory_p.h" #include "qquickwebenginecertificateerror_p.h" @@ -63,7 +64,9 @@ #include "web_engine_settings.h" #include "web_engine_visited_links_manager.h" +#include <QClipboard> #include <QGuiApplication> +#include <QMimeData> #include <QQmlComponent> #include <QQmlContext> #include <QQmlEngine> @@ -102,8 +105,10 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() , loadProgress(0) , m_isFullScreen(false) , isLoading(false) + , m_activeFocusOnPress(true) , devicePixelRatio(QGuiApplication::primaryScreen()->devicePixelRatio()) , m_dpiScale(1.0) + , m_backgroundColor(Qt::white) { // The gold standard for mobile web content is 160 dpi, and the devicePixelRatio expected // is the (possibly quantized) ratio of device dpi to 160 dpi. @@ -175,9 +180,17 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu if (!menu) return false; + contextMenuData = data; + // Populate our menu MenuItemHandler *item = 0; + if (!data.linkText.isEmpty() && data.linkUrl.isValid()) { + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::OpenLinkInThisWindow); }); + ui()->addMenuItem(item, QObject::tr("Follow Link")); + } + if (data.selectedText.isEmpty()) { item = new MenuItemHandler(menu); QObject::connect(item, &MenuItemHandler::triggered, q, &QQuickWebEngineView::goBack); @@ -191,15 +204,67 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu QObject::connect(item, &MenuItemHandler::triggered, q, &QQuickWebEngineView::reload); ui()->addMenuItem(item, QObject::tr("Reload"), QStringLiteral("view-refresh")); } else { - item = new CopyMenuItem(menu, data.selectedText); - ui()->addMenuItem(item, QObject::tr("Copy...")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::Copy); }); + ui()->addMenuItem(item, QObject::tr("Copy")); } - if (!data.linkText.isEmpty() && data.linkUrl.isValid()) { - item = new NavigateMenuItem(menu, adapter, data.linkUrl); - ui()->addMenuItem(item, QObject::tr("Navigate to...")); - item = new CopyMenuItem(menu, data.linkUrl.toString()); - ui()->addMenuItem(item, QObject::tr("Copy link address")); + if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) { + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyLinkToClipboard); }); + ui()->addMenuItem(item, QObject::tr("Copy Link URL")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadLinkToDisk); }); + ui()->addMenuItem(item, QObject::tr("Save Link...")); + } + if (contextMenuData.mediaUrl.isValid()) { + switch (contextMenuData.mediaType) { + case WebEngineContextMenuData::MediaTypeImage: + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageUrlToClipboard); }); + ui()->addMenuItem(item, QObject::tr("Copy Image URL")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageToClipboard); }); + ui()->addMenuItem(item, QObject::tr("Copy Image")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadImageToDisk); }); + ui()->addMenuItem(item, QObject::tr("Save Image")); + break; + case WebEngineContextMenuData::MediaTypeCanvas: + Q_UNREACHABLE(); // mediaUrl is invalid for canvases + break; + case WebEngineContextMenuData::MediaTypeAudio: + case WebEngineContextMenuData::MediaTypeVideo: + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyMediaUrlToClipboard); }); + ui()->addMenuItem(item, QObject::tr("Copy Media URL")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadMediaToDisk); }); + ui()->addMenuItem(item, QObject::tr("Download Media")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaPlayPause); }); + ui()->addMenuItem(item, QObject::tr("Toggle Play/Pause")); + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaLoop); }); + ui()->addMenuItem(item, QObject::tr("Toggle Looping")); + if (contextMenuData.mediaFlags & WebEngineContextMenuData::MediaHasAudio) { + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaMute); }); + ui()->addMenuItem(item, QObject::tr("Toggle Mute")); + } + if (contextMenuData.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) { + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaControls); }); + ui()->addMenuItem(item, QObject::tr("Toggle Media Controls")); + } + break; + default: + break; + } + } else if (contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeCanvas) { + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageToClipboard); }); + ui()->addMenuItem(item, QObject::tr("Copy Image")); } // FIXME: expose the context menu data as an attached property to make this more useful @@ -251,9 +316,9 @@ void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url Q_EMIT q->featurePermissionRequested(url, QQuickWebEngineView::Geolocation); } -void QQuickWebEngineViewPrivate::runFileChooser(FileChooserMode mode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) +void QQuickWebEngineViewPrivate::runFileChooser(FilePickerController* controller) { - ui()->showFilePicker(mode, defaultFileName, acceptedMimeTypes, adapter); + ui()->showFilePicker(controller); } void QQuickWebEngineViewPrivate::passOnFocus(bool reverse) @@ -310,6 +375,11 @@ qreal QQuickWebEngineViewPrivate::dpiScale() const return m_dpiScale; } +QColor QQuickWebEngineViewPrivate::backgroundColor() const +{ + return m_backgroundColor; +} + void QQuickWebEngineViewPrivate::loadStarted(const QUrl &provisionalUrl, bool isErrorPage) { Q_Q(QQuickWebEngineView); @@ -581,7 +651,7 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) Q_D(QQuickWebEngineView); d->e->q_ptr = d->q_ptr = this; this->setActiveFocusOnTab(true); - this->setFlag(QQuickItem::ItemIsFocusScope); + this->setFlags(QQuickItem::ItemIsFocusScope | QQuickItem::ItemAcceptsInputMethod); #ifndef QT_NO_ACCESSIBILITY QQuickAccessibleAttached *accessible = QQuickAccessibleAttached::qmlAttachedProperties(this); @@ -763,8 +833,23 @@ void QQuickWebEngineView::setTestSupport(QQuickWebEngineTestSupport *testSupport Q_D(QQuickWebEngineView); d->m_testSupport = testSupport; } + #endif +/*! + * \qmlproperty bool WebEngineView::activeFocusOnPress + * \since QtWebEngine 1.2 + * + * This property specifies whether the view should gain active focus when pressed. + * The default value is true. + * + */ +bool QQuickWebEngineView::activeFocusOnPress() const +{ + Q_D(const QQuickWebEngineView); + return d->m_activeFocusOnPress; +} + void QQuickWebEngineViewPrivate::didRunJavaScript(quint64 requestId, const QVariant &result) { Q_Q(QQuickWebEngineView); @@ -783,6 +868,11 @@ void QQuickWebEngineViewPrivate::didFindText(quint64 requestId, int matchCount) } void QQuickWebEngineViewPrivate::showValidationMessage(const QRect &anchor, const QString &mainText, const QString &subText) { +#ifdef ENABLE_QML_TESTSUPPORT_API + if (m_testSupport) + Q_EMIT m_testSupport->validationMessageShown(mainText, subText); +#endif + ui()->showMessageBubble(anchor, mainText, subText); } @@ -858,6 +948,34 @@ qreal QQuickWebEngineView::zoomFactor() const return d->adapter->currentZoomFactor(); } +/*! + \qmlproperty bool WebEngineView::backgroundColor + \since QtWebEngine 1.2 + + Sets this property to change the color of the WebEngineView's background, + behing the document's body. You can set it to "transparent" or to a translucent + color to see through the document, or you can set this color to match your + web content in an hybrid app to prevent the white flashes that may appear + during loading. + + The default value is white. +*/ +QColor QQuickWebEngineView::backgroundColor() const +{ + Q_D(const QQuickWebEngineView); + return d->m_backgroundColor; +} + +void QQuickWebEngineView::setBackgroundColor(const QColor &color) +{ + Q_D(QQuickWebEngineView); + if (color == d->m_backgroundColor) + return; + d->m_backgroundColor = color; + d->ensureContentsAdapter(); + d->adapter->backgroundColorChanged(); + emit backgroundColorChanged(); +} bool QQuickWebEngineView::isFullScreen() const { @@ -965,6 +1083,16 @@ void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQu } } +void QQuickWebEngineView::setActiveFocusOnPress(bool arg) +{ + Q_D(QQuickWebEngineView); + if (d->m_activeFocusOnPress == arg) + return; + + d->m_activeFocusOnPress = arg; + emit activeFocusOnPressChanged(arg); +} + void QQuickWebEngineView::goBackOrForward(int offset) { Q_D(QQuickWebEngineView); @@ -1010,6 +1138,162 @@ void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &va QQuickItem::itemChange(change, value); } +void QQuickWebEngineView::triggerWebAction(WebAction action) +{ + Q_D(QQuickWebEngineView); + switch (action) { + case Back: + d->adapter->navigateToOffset(-1); + break; + case Forward: + d->adapter->navigateToOffset(1); + break; + case Stop: + d->adapter->stop(); + break; + case Reload: + d->adapter->reload(); + break; + case ReloadAndBypassCache: + d->adapter->reloadAndBypassCache(); + break; + case Cut: + d->adapter->cut(); + break; + case Copy: + d->adapter->copy(); + break; + case Paste: + d->adapter->paste(); + break; + case Undo: + d->adapter->undo(); + break; + case Redo: + d->adapter->redo(); + break; + case SelectAll: + d->adapter->selectAll(); + break; + case PasteAndMatchStyle: + d->adapter->pasteAndMatchStyle(); + break; + case OpenLinkInThisWindow: + if (d->contextMenuData.linkUrl.isValid()) + setUrl(d->contextMenuData.linkUrl); + break; + case OpenLinkInNewWindow: + if (d->contextMenuData.linkUrl.isValid()) { + QQuickWebEngineNewViewRequest request; + request.m_requestedUrl = d->contextMenuData.linkUrl; + request.m_isUserInitiated = true; + request.m_destination = NewViewInWindow; + Q_EMIT newViewRequested(&request); + } + break; + case OpenLinkInNewTab: + if (d->contextMenuData.linkUrl.isValid()) { + QQuickWebEngineNewViewRequest request; + request.m_requestedUrl = d->contextMenuData.linkUrl; + request.m_isUserInitiated = true; + request.m_destination = NewViewInBackgroundTab; + Q_EMIT newViewRequested(&request); + } + break; + case CopyLinkToClipboard: + if (d->contextMenuData.linkUrl.isValid()) { + QString urlString = d->contextMenuData.linkUrl.toString(QUrl::FullyEncoded); + QString title = d->contextMenuData.linkText.toHtmlEscaped(); + QMimeData *data = new QMimeData(); + data->setText(urlString); + QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>"); + data->setHtml(html); + data->setUrls(QList<QUrl>() << d->contextMenuData.linkUrl); + qApp->clipboard()->setMimeData(data); + } + break; + case DownloadLinkToDisk: + if (d->contextMenuData.linkUrl.isValid()) + d->adapter->download(d->contextMenuData.linkUrl, d->contextMenuData.suggestedFileName); + break; + case CopyImageToClipboard: + if (d->contextMenuData.hasImageContent && + (d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeImage || + d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeCanvas)) + { + d->adapter->copyImageAt(d->contextMenuData.pos); + } + break; + case CopyImageUrlToClipboard: + if (d->contextMenuData.mediaUrl.isValid() && d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeImage) { + QString urlString = d->contextMenuData.mediaUrl.toString(QUrl::FullyEncoded); + QString title = d->contextMenuData.linkText; + if (!title.isEmpty()) + title = QStringLiteral(" alt=\"%1\"").arg(title.toHtmlEscaped()); + QMimeData *data = new QMimeData(); + data->setText(urlString); + QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral("></img>"); + data->setHtml(html); + data->setUrls(QList<QUrl>() << d->contextMenuData.mediaUrl); + qApp->clipboard()->setMimeData(data); + } + break; + case DownloadImageToDisk: + case DownloadMediaToDisk: + if (d->contextMenuData.mediaUrl.isValid()) + d->adapter->download(d->contextMenuData.mediaUrl, d->contextMenuData.suggestedFileName); + break; + case CopyMediaUrlToClipboard: + if (d->contextMenuData.mediaUrl.isValid() && + (d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeAudio || + d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeVideo)) + { + QString urlString = d->contextMenuData.mediaUrl.toString(QUrl::FullyEncoded); + QMimeData *data = new QMimeData(); + data->setText(urlString); + if (d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeAudio) + data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"></audio>")); + else + data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"></video>")); + data->setUrls(QList<QUrl>() << d->contextMenuData.mediaUrl); + qApp->clipboard()->setMimeData(data); + } + break; + case ToggleMediaControls: + if (d->contextMenuData.mediaUrl.isValid() && d->contextMenuData.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) { + bool enable = !(d->contextMenuData.mediaFlags & WebEngineContextMenuData::MediaControls); + d->adapter->executeMediaPlayerActionAt(d->contextMenuData.pos, WebContentsAdapter::MediaPlayerControls, enable); + } + break; + case ToggleMediaLoop: + if (d->contextMenuData.mediaUrl.isValid() && + (d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeAudio || + d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeVideo)) + { + bool enable = !(d->contextMenuData.mediaFlags & WebEngineContextMenuData::MediaLoop); + d->adapter->executeMediaPlayerActionAt(d->contextMenuData.pos, WebContentsAdapter::MediaPlayerLoop, enable); + } + break; + case ToggleMediaPlayPause: + if (d->contextMenuData.mediaUrl.isValid() && + (d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeAudio || + d->contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeVideo)) + { + bool enable = (d->contextMenuData.mediaFlags & WebEngineContextMenuData::MediaPaused); + d->adapter->executeMediaPlayerActionAt(d->contextMenuData.pos, WebContentsAdapter::MediaPlayerPlay, enable); + } + break; + case ToggleMediaMute: + if (d->contextMenuData.mediaUrl.isValid() && d->contextMenuData.mediaFlags & WebEngineContextMenuData::MediaHasAudio) { + bool enable = (d->contextMenuData.mediaFlags & WebEngineContextMenuData::MediaMuted); + d->adapter->executeMediaPlayerActionAt(d->contextMenuData.pos, WebContentsAdapter::MediaPlayerMute, enable); + } + break; + default: + Q_UNREACHABLE(); + } +} + void QQuickWebEngineViewPrivate::userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script) { Q_ASSERT(p && p->data); diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 3385db425..5b99dc3e2 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -84,6 +84,8 @@ private: bool m_toggleOn; }; +#define LATEST_WEBENGINEVIEW_REVISION 2 + class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_OBJECT Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) @@ -100,6 +102,8 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(QQuickWebEngineHistory *navigationHistory READ navigationHistory CONSTANT FINAL REVISION 1) Q_PROPERTY(QQmlWebChannel *webChannel READ webChannel WRITE setWebChannel NOTIFY webChannelChanged REVISION 1) Q_PROPERTY(QQmlListProperty<QQuickWebEngineScript> userScripts READ userScripts FINAL) + Q_PROPERTY(bool activeFocusOnPress READ activeFocusOnPress WRITE setActiveFocusOnPress NOTIFY activeFocusOnPressChanged REVISION 2) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged REVISION 2) #ifdef ENABLE_QML_TESTSUPPORT_API Q_PROPERTY(QQuickWebEngineTestSupport *testSupport READ testSupport WRITE setTestSupport FINAL) @@ -113,6 +117,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_ENUMS(Feature); Q_ENUMS(JavaScriptConsoleMessageLevel); Q_FLAGS(FindFlags); + Q_ENUMS(WebAction); public: QQuickWebEngineView(QQuickItem *parent = 0); @@ -129,6 +134,8 @@ public: bool isFullScreen() const; qreal zoomFactor() const; void setZoomFactor(qreal arg); + QColor backgroundColor() const; + void setBackgroundColor(const QColor &color); QQuickWebEngineViewExperimental *experimental() const; @@ -181,6 +188,44 @@ public: Geolocation }; + enum WebAction { + NoWebAction = - 1, + Back, + Forward, + Stop, + Reload, + + Cut, + Copy, + Paste, + + Undo, + Redo, + SelectAll, + ReloadAndBypassCache, + + PasteAndMatchStyle, + + OpenLinkInThisWindow, + OpenLinkInNewWindow, + OpenLinkInNewTab, + CopyLinkToClipboard, + DownloadLinkToDisk, + + CopyImageToClipboard, + CopyImageUrlToClipboard, + DownloadImageToDisk, + + CopyMediaUrlToClipboard, + ToggleMediaControls, + ToggleMediaLoop, + ToggleMediaPlayPause, + ToggleMediaMute, + DownloadMediaToDisk, + + WebActionCount + }; + // must match WebContentsAdapterClient::JavaScriptConsoleMessageLevel enum JavaScriptConsoleMessageLevel { InfoMessageLevel = 0, @@ -211,6 +256,8 @@ public: void setTestSupport(QQuickWebEngineTestSupport *testSupport); #endif + bool activeFocusOnPress() const; + public Q_SLOTS: void runJavaScript(const QString&, const QJSValue & = QJSValue()); void loadHtml(const QString &html, const QUrl &baseUrl = QUrl()); @@ -223,6 +270,8 @@ public Q_SLOTS: Q_REVISION(1) void findText(const QString &subString, FindFlags options = 0, const QJSValue &callback = QJSValue()); Q_REVISION(1) void fullScreenCancelled(); Q_REVISION(1) void grantFeaturePermission(const QUrl &securityOrigin, Feature, bool granted); + Q_REVISION(2) void setActiveFocusOnPress(bool arg); + Q_REVISION(2) void triggerWebAction(WebAction action); Q_SIGNALS: void titleChanged(); @@ -241,7 +290,8 @@ Q_SIGNALS: Q_REVISION(1) void zoomFactorChanged(qreal arg); Q_REVISION(1) void profileChanged(); Q_REVISION(1) void webChannelChanged(); - + Q_REVISION(2) void activeFocusOnPressChanged(bool); + Q_REVISION(2) void backgroundColorChanged(); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 60aa0d9f4..dd03aaeb4 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -134,6 +134,7 @@ public: virtual void selectionChanged() Q_DECL_OVERRIDE { } virtual QRectF viewportRect() const Q_DECL_OVERRIDE; virtual qreal dpiScale() const Q_DECL_OVERRIDE; + virtual QColor backgroundColor() const Q_DECL_OVERRIDE; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) Q_DECL_OVERRIDE; virtual void loadCommitted() Q_DECL_OVERRIDE; virtual void loadVisuallyCommitted() Q_DECL_OVERRIDE; @@ -147,7 +148,7 @@ public: virtual bool contextMenuRequested(const QtWebEngineCore::WebEngineContextMenuData &) Q_DECL_OVERRIDE; virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) Q_DECL_OVERRIDE; virtual void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) Q_DECL_OVERRIDE; - virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE; + virtual void runFileChooser(QtWebEngineCore::FilePickerController *controller) Q_DECL_OVERRIDE; virtual void didRunJavaScript(quint64, const QVariant&) Q_DECL_OVERRIDE; virtual void didFetchDocumentMarkup(quint64, const QString&) Q_DECL_OVERRIDE { } virtual void didFetchDocumentInnerText(quint64, const QString&) Q_DECL_OVERRIDE { } @@ -190,11 +191,13 @@ public: QQuickWebEngineTestSupport *m_testSupport; #endif QQmlComponent *contextMenuExtraItems; + QtWebEngineCore::WebEngineContextMenuData contextMenuData; QUrl explicitUrl; QUrl icon; int loadProgress; bool m_isFullScreen; bool isLoading; + bool m_activeFocusOnPress; qreal devicePixelRatio; QMap<quint64, QJSValue> m_callbacks; QList<QSharedPointer<CertificateErrorController> > m_certificateErrorControllers; @@ -203,6 +206,7 @@ private: QScopedPointer<QtWebEngineCore::UIDelegatesManager> m_uIDelegatesManager; QList<QQuickWebEngineScript *> m_userScripts; qreal m_dpiScale; + QColor m_backgroundColor; }; #ifndef QT_NO_ACCESSIBILITY diff --git a/src/webengine/plugin/experimental/experimental.pro b/src/webengine/plugin/experimental/experimental.pro index 36162e359..d1b59326a 100644 --- a/src/webengine/plugin/experimental/experimental.pro +++ b/src/webengine/plugin/experimental/experimental.pro @@ -6,7 +6,7 @@ IMPORT_VERSION = 1.0 QT += webengine qml quick QT_PRIVATE += webengine-private -INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api +INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/core/api $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api SOURCES = plugin.cpp diff --git a/src/webengine/plugin/experimental/plugin.cpp b/src/webengine/plugin/experimental/plugin.cpp index 29b5413f4..507286e2f 100644 --- a/src/webengine/plugin/experimental/plugin.cpp +++ b/src/webengine/plugin/experimental/plugin.cpp @@ -68,7 +68,7 @@ public: QObject::tr("Cannot create a separate instance of WebEngineViewport")); // Use the latest revision of QQuickWebEngineView when importing QtWebEngine.experimental 1.0 - qmlRegisterRevision<QQuickWebEngineView, 1>(uri, 1, 0); + qmlRegisterRevision<QQuickWebEngineView, LATEST_WEBENGINEVIEW_REVISION>(uri, 1, 0); } }; diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index c5ef11a5e..e4b96c47b 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -69,6 +69,7 @@ public: qmlRegisterUncreatableType<QQuickWebEngineNavigationRequest>(uri, 1, 0, "WebEngineNavigationRequest", QObject::tr("Cannot create separate instance of WebEngineNavigationRequest")); qmlRegisterType<QQuickWebEngineView, 1>(uri, 1, 1, "WebEngineView"); + qmlRegisterType<QQuickWebEngineView, 2>(uri, 1, 2, "WebEngineView"); qmlRegisterType<QQuickWebEngineProfile>(uri, 1, 1, "WebEngineProfile"); qmlRegisterType<QQuickWebEngineScript>(uri, 1, 1, "WebEngineScript"); qmlRegisterUncreatableType<QQuickWebEngineCertificateError>(uri, 1, 1, "WebEngineCertificateError", QObject::tr("Cannot create separate instance of WebEngineCertificateError")); @@ -76,6 +77,7 @@ public: 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")); + qmlRegisterUncreatableType<QQuickWebEngineSettings, 1>(uri, 1, 2, "WebEngineSettings", QObject::tr("Cannot create a separate instance of WebEngineSettings")); qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 1, "WebEngine", webEngineSingletonProvider); qmlRegisterUncreatableType<QQuickWebEngineHistory>(uri, 1, 1, "NavigationHistory", QObject::tr("Cannot create a separate instance of NavigationHistory")); @@ -83,6 +85,9 @@ public: QObject::tr("Cannot create a separate instance of NavigationHistory")); qmlRegisterUncreatableType<QQuickWebEngineFullScreenRequest>(uri, 1, 1, "FullScreenRequest", QObject::tr("Cannot create a separate instance of FullScreenRequest")); + + // For now (1.x import), the latest revision matches the minor version of the import. + qmlRegisterRevision<QQuickWebEngineView, LATEST_WEBENGINEVIEW_REVISION>(uri, 1, LATEST_WEBENGINEVIEW_REVISION); } }; diff --git a/src/webengine/plugin/plugin.pro b/src/webengine/plugin/plugin.pro index 5682e90ed..b6acc760f 100644 --- a/src/webengine/plugin/plugin.pro +++ b/src/webengine/plugin/plugin.pro @@ -1,12 +1,12 @@ CXX_MODULE = qml TARGET = qtwebengineplugin TARGETPATH = QtWebEngine -IMPORT_VERSION = 1.0 +IMPORT_VERSION = 1.2 QT += webengine qml quick QT_PRIVATE += webengine-private -INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api $$QTWEBENGINE_ROOT/include/QtWebEngine +INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/core/api $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api $$QTWEBENGINE_ROOT/include/QtWebEngine SOURCES = plugin.cpp 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 a3999ccab..9fc1ed3eb 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -64,10 +64,14 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW void RenderWidgetHostViewQtDelegateQuick::initAsChild(WebContentsAdapterClient* container) { - QQuickWebEngineViewPrivate *viewPrivate = static_cast<QQuickWebEngineViewPrivate *>(container); - setParentItem(viewPrivate->q_func()); - setSize(viewPrivate->q_func()->boundingRect().size()); + QQuickWebEngineView *view = static_cast<QQuickWebEngineViewPrivate *>(container)->q_func(); + setParentItem(view); + setSize(view->boundingRect().size()); + // Focus on creation if the view accepts it + if (view->activeFocusOnPress()) + setFocus(true); m_initialized = true; + } void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r) @@ -176,9 +180,11 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis if (qApp->inputMethod()->isVisible() == editorVisible) return; - setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible); - qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); - qApp->inputMethod()->setVisible(editorVisible); + if (parentItem() && parentItem()->flags() & QQuickItem::ItemAcceptsInputMethod) { + qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); + qApp->inputMethod()->setVisible(editorVisible); + } + } void RenderWidgetHostViewQtDelegateQuick::focusInEvent(QFocusEvent *event) @@ -193,7 +199,7 @@ void RenderWidgetHostViewQtDelegateQuick::focusOutEvent(QFocusEvent *event) void RenderWidgetHostViewQtDelegateQuick::mousePressEvent(QMouseEvent *event) { - if (!m_isPopup) + if (!m_isPopup && (parentItem() && parentItem()->property("activeFocusOnPress").toBool())) forceActiveFocus(); m_client->forwardEvent(event); } @@ -225,7 +231,8 @@ void RenderWidgetHostViewQtDelegateQuick::wheelEvent(QWheelEvent *event) void RenderWidgetHostViewQtDelegateQuick::touchEvent(QTouchEvent *event) { - if (event->type() == QEvent::TouchBegin && !m_isPopup) + if (event->type() == QEvent::TouchBegin && !m_isPopup + && (parentItem() && parentItem()->property("activeFocusOnPress").toBool())) forceActiveFocus(); m_client->forwardEvent(event); } 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 ddd0e4d9e..eb2860b27 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -70,6 +70,8 @@ public: virtual void move(const QPoint&) Q_DECL_OVERRIDE { } virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; virtual void setTooltip(const QString&) Q_DECL_OVERRIDE { } + // The QtQuick view doesn't have a backbuffer of its own and doesn't need this + virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } protected: virtual void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE; 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 cda51a1ab..a4b08482f 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -73,6 +73,7 @@ public: virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; virtual void inputMethodStateChanged(bool) Q_DECL_OVERRIDE {} virtual void setTooltip(const QString &tooltip) Q_DECL_OVERRIDE; + virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } private: QScopedPointer<RenderWidgetHostViewQtDelegate> m_realDelegate; diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index d22e6546f..bacf48419 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -37,12 +37,14 @@ #include "ui_delegates_manager.h" #include "api/qquickwebengineview_p.h" +#include "file_picker_controller.h" #include "javascript_dialog_controller.h" #include <QAbstractListModel> #include <QClipboard> #include <QFileInfo> #include <QGuiApplication> +#include <QMimeData> #include <QQmlContext> #include <QQmlEngine> #include <QQmlProperty> @@ -107,32 +109,6 @@ MenuItemHandler::MenuItemHandler(QObject *parent) { } - -CopyMenuItem::CopyMenuItem(QObject *parent, const QString &textToCopy) - : MenuItemHandler(parent) - , m_textToCopy(textToCopy) -{ - connect(this, &MenuItemHandler::triggered, this, &CopyMenuItem::onTriggered); -} - -void CopyMenuItem::onTriggered() -{ - qApp->clipboard()->setText(m_textToCopy); -} - -NavigateMenuItem::NavigateMenuItem(QObject *parent, const QExplicitlySharedDataPointer<WebContentsAdapter> &adapter, const QUrl &targetUrl) - : MenuItemHandler(parent) - , m_adapter(adapter) - , m_targetUrl(targetUrl) -{ - connect(this, &MenuItemHandler::triggered, this, &NavigateMenuItem::onTriggered); -} - -void NavigateMenuItem::onTriggered() -{ - m_adapter->load(m_targetUrl); -} - #define COMPONENT_MEMBER_INIT(TYPE, COMPONENT) \ , COMPONENT##Component(0) @@ -341,50 +317,8 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d QMetaObject::invokeMethod(dialog, "open"); } -namespace { -class FilePickerController : public QObject { - Q_OBJECT -public: - FilePickerController(WebContentsAdapterClient::FileChooserMode, const QExplicitlySharedDataPointer<WebContentsAdapter> &, QObject * = 0); - -public Q_SLOTS: - void accepted(const QVariant &files); - void rejected(); - -private: - QExplicitlySharedDataPointer<WebContentsAdapter> m_adapter; - WebContentsAdapterClient::FileChooserMode m_mode; - -}; - - -FilePickerController::FilePickerController(WebContentsAdapterClient::FileChooserMode mode, const QExplicitlySharedDataPointer<WebContentsAdapter> &adapter, QObject *parent) - : QObject(parent) - , m_adapter(adapter) - , m_mode(mode) -{ -} - -void FilePickerController::accepted(const QVariant &files) -{ - QStringList stringList; - Q_FOREACH (const QUrl &url, files.value<QList<QUrl> >()) - stringList.append(url.toLocalFile()); - m_adapter->filesSelectedInChooser(stringList, m_mode); -} - -void FilePickerController::rejected() -{ - m_adapter->filesSelectedInChooser(QStringList(), m_mode); -} - -} // namespace - - -void UIDelegatesManager::showFilePicker(WebContentsAdapterClient::FileChooserMode mode, const QString &defaultFileName, const QStringList &acceptedMimeTypes, const QExplicitlySharedDataPointer<WebContentsAdapter> &adapter) +void UIDelegatesManager::showFilePicker(FilePickerController *controller) { - Q_UNUSED(defaultFileName); - Q_UNUSED(acceptedMimeTypes); if (!ensureComponentLoaded(FilePicker)) return; @@ -397,23 +331,24 @@ void UIDelegatesManager::showFilePicker(WebContentsAdapterClient::FileChooserMod filePickerComponent->completeCreate(); // Fine-tune some properties depending on the mode. - switch (mode) { - case WebContentsAdapterClient::Open: + switch (controller->mode()) { + case FilePickerController::Open: break; - case WebContentsAdapterClient::Save: + case FilePickerController::Save: filePicker->setProperty("selectExisting", false); break; - case WebContentsAdapterClient::OpenMultiple: + case FilePickerController::OpenMultiple: filePicker->setProperty("selectMultiple", true); break; - case WebContentsAdapterClient::UploadFolder: + case FilePickerController::UploadFolder: filePicker->setProperty("selectFolder", true); break; default: Q_UNREACHABLE(); } - FilePickerController *controller = new FilePickerController(mode, adapter, filePicker); + controller->setParent(filePicker); + QQmlProperty filesPickedSignal(filePicker, QStringLiteral("onFilesSelected")); CHECK_QML_SIGNAL_PROPERTY(filesPickedSignal, filePickerComponent->url()); QQmlProperty rejectSignal(filePicker, QStringLiteral("onRejected")); @@ -464,5 +399,3 @@ void UIDelegatesManager::moveMessageBubble(const QRect &anchor) } } // namespace QtWebEngineCore - -#include "ui_delegates_manager.moc" diff --git a/src/webengine/ui_delegates_manager.h b/src/webengine/ui_delegates_manager.h index f2b78f792..37cbb85df 100644 --- a/src/webengine/ui_delegates_manager.h +++ b/src/webengine/ui_delegates_manager.h @@ -73,6 +73,7 @@ QT_END_NAMESPACE namespace QtWebEngineCore { class JavaScriptDialogController; +class FilePickerController; const char *defaultPropertyName(QObject *obj); @@ -85,29 +86,6 @@ Q_SIGNALS: void triggered(); }; -class CopyMenuItem : public MenuItemHandler { - Q_OBJECT -public: - CopyMenuItem(QObject *parent, const QString &textToCopy); - -private: - void onTriggered(); - - QString m_textToCopy; -}; - -class NavigateMenuItem : public MenuItemHandler { - Q_OBJECT -public: - NavigateMenuItem(QObject *parent, const QExplicitlySharedDataPointer<WebContentsAdapter> &adapter, const QUrl &targetUrl); - -private: - void onTriggered(); - - QExplicitlySharedDataPointer<WebContentsAdapter> m_adapter; - QUrl m_targetUrl; -}; - class UIDelegatesManager { public: @@ -124,8 +102,7 @@ public: QObject *addMenu(QObject *parentMenu, const QString &title, const QPoint &pos = QPoint()); QQmlContext *creationContextForComponent(QQmlComponent *); void showDialog(QSharedPointer<JavaScriptDialogController>); - void showFilePicker(WebContentsAdapterClient::FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes - , const QExplicitlySharedDataPointer<WebContentsAdapter> &); + void showFilePicker(FilePickerController *controller); void showMessageBubble(const QRect &anchor, const QString &mainText, const QString &subText); void hideMessageBubble(); void moveMessageBubble(const QRect &anchor); diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 6cba9c5d9..8bb5a8e77 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -3,12 +3,12 @@ TARGET = QtWebEngine # For our export macros DEFINES += QT_BUILD_WEBENGINE_LIB -QT += qml quick -QT_PRIVATE += webenginecore quick-private gui-private core-private +QT += qml quick webenginecore +QT_PRIVATE += quick-private gui-private core-private QMAKE_DOCS = $$PWD/doc/qtwebengine.qdocconf -INCLUDEPATH += $$PWD api ../core +INCLUDEPATH += $$PWD api ../core ../core/api SOURCES = \ api/qquickwebenginecertificateerror.cpp \ diff --git a/src/webenginewidgets/api/qwebenginecertificateerror.h b/src/webenginewidgets/api/qwebenginecertificateerror.h index 90b23208c..7706ea32d 100644 --- a/src/webenginewidgets/api/qwebenginecertificateerror.h +++ b/src/webenginewidgets/api/qwebenginecertificateerror.h @@ -37,10 +37,10 @@ #ifndef QWEBENGINECERTIFICATEERROR_H #define QWEBENGINECERTIFICATEERROR_H -#include "qtwebenginewidgetsglobal.h" +#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> -#include <QtCore/QScopedPointer> -#include <QtCore/QUrl> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qurl.h> QT_BEGIN_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h index d362131f2..1428ad4c3 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.h +++ b/src/webenginewidgets/api/qwebenginedownloaditem.h @@ -37,9 +37,9 @@ #ifndef QWEBENGINEDOWNLOADITEM_H #define QWEBENGINEDOWNLOADITEM_H -#include "qtwebenginewidgetsglobal.h" +#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> -#include <QObject> +#include <QtCore/qobject.h> QT_BEGIN_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 6207a2b30..e7d4e60e5 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -25,6 +25,7 @@ #include "browser_context_adapter.h" #include "certificate_error_controller.h" +#include "file_picker_controller.h" #include "javascript_dialog_controller.h" #include "qwebenginehistory.h" #include "qwebenginehistory_p.h" @@ -54,6 +55,7 @@ #include <QLayout> #include <QMenu> #include <QMessageBox> +#include <QMimeData> #include <QStandardPaths> #include <QStyle> #include <QUrl> @@ -77,106 +79,6 @@ static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::Wind } } -CallbackDirectory::~CallbackDirectory() -{ - // "Cancel" pending callbacks by calling them with an invalid value. - // This guarantees that each callback is called exactly once. - Q_FOREACH (const CallbackSharedDataPointer &sharedPtr, m_callbackMap) { - switch (sharedPtr.type) { - case CallbackSharedDataPointer::Variant: - (*sharedPtr.variantCallback)(QVariant()); - break; - case CallbackSharedDataPointer::String: - (*sharedPtr.stringCallback)(QString()); - break; - case CallbackSharedDataPointer::Bool: - (*sharedPtr.boolCallback)(false); - break; - default: - Q_UNREACHABLE(); - } - } -} - -void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<VariantCallback> &callback) -{ - m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data())); -} - -void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<StringCallback> &callback) -{ - m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data())); -} - -void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<BoolCallback> &callback) -{ - m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data())); -} - -void CallbackDirectory::invoke(quint64 requestId, const QVariant &result) -{ - CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId); - if (sharedPtr) { - Q_ASSERT(sharedPtr.type == CallbackSharedDataPointer::Variant); - (*sharedPtr.variantCallback)(result); - } -} - -void CallbackDirectory::invoke(quint64 requestId, const QString &result) -{ - CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId); - if (sharedPtr) { - Q_ASSERT(sharedPtr.type == CallbackSharedDataPointer::String); - (*sharedPtr.stringCallback)(result); - } -} - -void CallbackDirectory::invoke(quint64 requestId, bool result) -{ - CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId); - if (sharedPtr) { - Q_ASSERT(sharedPtr.type == CallbackSharedDataPointer::Bool); - (*sharedPtr.boolCallback)(result); - } -} - -void CallbackDirectory::CallbackSharedDataPointer::doRef() -{ - switch (type) { - case None: - break; - case Variant: - variantCallback->ref.ref(); - break; - case String: - stringCallback->ref.ref(); - break; - case Bool: - boolCallback->ref.ref(); - break; - } -} - -void CallbackDirectory::CallbackSharedDataPointer::doDeref() -{ - switch (type) { - case None: - break; - case Variant: - if (!variantCallback->ref.deref()) - delete variantCallback; - break; - case String: - if (!stringCallback->ref.deref()) - delete stringCallback; - break; - case Bool: - if (!boolCallback->ref.deref()) - delete boolCallback; - break; - } -} - QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) : adapter(new WebContentsAdapter) , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this))) @@ -185,6 +87,7 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) , view(0) , isLoading(false) , scriptCollection(new QWebEngineScriptCollectionPrivate(browserContextAdapter()->userScriptController(), adapter.data())) + , m_backgroundColor(Qt::white) { memset(actions, 0, sizeof(actions)); } @@ -247,6 +150,11 @@ qreal QWebEnginePagePrivate::dpiScale() const return 1.0; } +QColor QWebEnginePagePrivate::backgroundColor() const +{ + return m_backgroundColor; +} + void QWebEnginePagePrivate::loadStarted(const QUrl &provisionalUrl, bool isErrorPage) { Q_UNUSED(provisionalUrl); @@ -531,6 +439,33 @@ void QWebEnginePage::setWebChannel(QWebChannel *channel) d->adapter->setWebChannel(channel); } +/*! + \property QWebEnginePage::backgroundColor + \brief the page's background color, behing the document's body. + \since 5.6 + + You can set it to Qt::transparent or to a translucent + color to see through the document, or you can set this color to match your + web content in an hybrid app to prevent the white flashes that may appear + during loading. + + The default value is white. +*/ +QColor QWebEnginePage::backgroundColor() const +{ + Q_D(const QWebEnginePage); + return d->m_backgroundColor; +} + +void QWebEnginePage::setBackgroundColor(const QColor &color) +{ + Q_D(QWebEnginePage); + if (d->m_backgroundColor == color) + return; + d->m_backgroundColor = color; + d->adapter->backgroundColorChanged(); +} + void QWebEnginePage::setView(QWidget *view) { QWebEngineViewPrivate::bind(qobject_cast<QWebEngineView*>(view), this); @@ -614,6 +549,48 @@ QAction *QWebEnginePage::action(WebAction action) const case PasteAndMatchStyle: text = tr("Paste and Match Style"); break; + case OpenLinkInThisWindow: + text = tr("Open Link in This Window"); + break; + case OpenLinkInNewWindow: + text = tr("Open Link in New Window"); + break; + case OpenLinkInNewTab: + text = tr("Open Link in New Tab"); + break; + case CopyLinkToClipboard: + text = tr("Copy Link URL"); + break; + case DownloadLinkToDisk: + text = tr("Save Link..."); + break; + case CopyImageToClipboard: + text = tr("Copy Image"); + break; + case CopyImageUrlToClipboard: + text = tr("Copy Image URL"); + break; + case DownloadImageToDisk: + text = tr("Save Image"); + break; + case CopyMediaUrlToClipboard: + text = tr("Copy Media URL"); + break; + case ToggleMediaControls: + text = tr("Toggle Media Controls"); + break; + case ToggleMediaLoop: + text = tr("Toggle Looping"); + break; + case ToggleMediaPlayPause: + text = tr("Toggle Play/Pause"); + break; + case ToggleMediaMute: + text = tr("Toggle Mute"); + break; + case DownloadMediaToDisk: + text = tr("Download Media"); + break; default: break; } @@ -671,6 +648,113 @@ void QWebEnginePage::triggerAction(WebAction action, bool) case PasteAndMatchStyle: d->adapter->pasteAndMatchStyle(); break; + case OpenLinkInThisWindow: + if (d->m_menuData.linkUrl.isValid()) + setUrl(d->m_menuData.linkUrl); + break; + case OpenLinkInNewWindow: + if (d->m_menuData.linkUrl.isValid()) { + QWebEnginePage *newPage = createWindow(WebBrowserWindow); + if (newPage) + newPage->setUrl(d->m_menuData.linkUrl); + } + break; + case OpenLinkInNewTab: + if (d->m_menuData.linkUrl.isValid()) { + QWebEnginePage *newPage = createWindow(WebBrowserTab); + if (newPage) + newPage->setUrl(d->m_menuData.linkUrl); + } + break; + case CopyLinkToClipboard: + if (d->m_menuData.linkUrl.isValid()) { + QString urlString = d->m_menuData.linkUrl.toString(QUrl::FullyEncoded); + QString title = d->m_menuData.linkText.toHtmlEscaped(); + QMimeData *data = new QMimeData(); + data->setText(urlString); + QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>"); + data->setHtml(html); + data->setUrls(QList<QUrl>() << d->m_menuData.linkUrl); + qApp->clipboard()->setMimeData(data); + } + break; + case DownloadLinkToDisk: + if (d->m_menuData.linkUrl.isValid()) + d->adapter->download(d->m_menuData.linkUrl, d->m_menuData.suggestedFileName); + break; + case CopyImageToClipboard: + if (d->m_menuData.hasImageContent && + (d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeImage || + d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeCanvas)) + { + d->adapter->copyImageAt(d->m_menuData.pos); + } + break; + case CopyImageUrlToClipboard: + if (d->m_menuData.mediaUrl.isValid() && d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeImage) { + QString urlString = d->m_menuData.mediaUrl.toString(QUrl::FullyEncoded); + QString title = d->m_menuData.linkText; + if (!title.isEmpty()) + title = QStringLiteral(" alt=\"%1\"").arg(title.toHtmlEscaped()); + QMimeData *data = new QMimeData(); + data->setText(urlString); + QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral("></img>"); + data->setHtml(html); + data->setUrls(QList<QUrl>() << d->m_menuData.mediaUrl); + qApp->clipboard()->setMimeData(data); + } + break; + case DownloadImageToDisk: + case DownloadMediaToDisk: + if (d->m_menuData.mediaUrl.isValid()) + d->adapter->download(d->m_menuData.mediaUrl, d->m_menuData.suggestedFileName); + break; + case CopyMediaUrlToClipboard: + if (d->m_menuData.mediaUrl.isValid() && + (d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio || + d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeVideo)) + { + QString urlString = d->m_menuData.mediaUrl.toString(QUrl::FullyEncoded); + QMimeData *data = new QMimeData(); + data->setText(urlString); + if (d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio) + data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"></audio>")); + else + data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"></video>")); + data->setUrls(QList<QUrl>() << d->m_menuData.mediaUrl); + qApp->clipboard()->setMimeData(data); + } + break; + case ToggleMediaControls: + if (d->m_menuData.mediaUrl.isValid() && d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) { + bool enable = !(d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaControls); + d->adapter->executeMediaPlayerActionAt(d->m_menuData.pos, WebContentsAdapter::MediaPlayerControls, enable); + } + break; + case ToggleMediaLoop: + if (d->m_menuData.mediaUrl.isValid() && + (d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio || + d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeVideo)) + { + bool enable = !(d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaLoop); + d->adapter->executeMediaPlayerActionAt(d->m_menuData.pos, WebContentsAdapter::MediaPlayerLoop, enable); + } + break; + case ToggleMediaPlayPause: + if (d->m_menuData.mediaUrl.isValid() && + (d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio || + d->m_menuData.mediaType == WebEngineContextMenuData::MediaTypeVideo)) + { + bool enable = (d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaPaused); + d->adapter->executeMediaPlayerActionAt(d->m_menuData.pos, WebContentsAdapter::MediaPlayerPlay, enable); + } + break; + case ToggleMediaMute: + if (d->m_menuData.mediaUrl.isValid() && d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaHasAudio) { + bool enable = (d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaMuted); + d->adapter->executeMediaPlayerActionAt(d->m_menuData.pos, WebContentsAdapter::MediaPlayerMute, enable); + } + break; default: Q_UNREACHABLE(); } @@ -681,12 +765,10 @@ void QWebEnginePage::findText(const QString &subString, FindFlags options, const Q_D(QWebEnginePage); if (subString.isEmpty()) { d->adapter->stopFinding(); - if (resultCallback.d) - (*resultCallback.d)(false); + d->m_callbacks.invokeEmpty(resultCallback); } else { quint64 requestId = d->adapter->findText(subString, options & FindCaseSensitively, options & FindBackward); - if (resultCallback.d) - d->m_callbacks.registerCallback(requestId, resultCallback.d); + d->m_callbacks.registerCallback(requestId, resultCallback); } } @@ -703,6 +785,7 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData if (!view) return false; + m_menuData = WebEngineContextMenuData(); QContextMenuEvent event(QContextMenuEvent::Mouse, data.pos, view->mapToGlobal(data.pos)); switch (view->contextMenuPolicy()) { case Qt::PreventContextMenu: @@ -727,7 +810,6 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData } Q_ASSERT(view->d_func()->m_pendingContextMenuEvent); view->d_func()->m_pendingContextMenuEvent = false; - m_menuData = WebEngineContextMenuData(); return true; } @@ -807,42 +889,18 @@ void QWebEnginePagePrivate::moveValidationMessage(const QRect &anchor) #endif } -namespace { -class SaveToClipboardFunctor -{ - QString m_text; -public: - SaveToClipboardFunctor(const QString &text) - : m_text(text) - {} - void operator()() const - { - qApp->clipboard()->setText(m_text); - } -}; - -class LoadUrlFunctor -{ - QWebEnginePage *m_page; - QUrl m_url; -public: - LoadUrlFunctor(QWebEnginePage *page, const QUrl &url) - : m_page(page) - , m_url(url) - {} - void operator()() const - { - m_page->load(m_url); - } -}; -} - QMenu *QWebEnginePage::createStandardContextMenu() { Q_D(QWebEnginePage); QMenu *menu = new QMenu(d->view); QAction *action = 0; WebEngineContextMenuData contextMenuData(d->m_menuData); + if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) { + action = QWebEnginePage::action(OpenLinkInThisWindow); + action->setText(tr("Follow Link")); + menu->addAction(action); + menu->addAction(QWebEnginePage::action(DownloadLinkToDisk)); + } if (contextMenuData.selectedText.isEmpty()) { action = new QAction(QIcon::fromTheme(QStringLiteral("go-previous")), tr("&Back"), menu); connect(action, &QAction::triggered, d->view, &QWebEngineView::back); @@ -858,20 +916,40 @@ QMenu *QWebEnginePage::createStandardContextMenu() connect(action, &QAction::triggered, d->view, &QWebEngineView::reload); menu->addAction(action); } else { - action = new QAction(tr("Copy..."), menu); - connect(action, &QAction::triggered, SaveToClipboardFunctor(contextMenuData.selectedText)); - menu->addAction(action); + menu->addAction(QWebEnginePage::action(Copy)); } if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) { - menu->addSeparator(); - action = new QAction(tr("Navigate to..."), menu); - connect(action, &QAction::triggered, LoadUrlFunctor(this, contextMenuData.linkUrl)); - menu->addAction(action); - action = new QAction(tr("Copy link address"), menu); - connect(action, &QAction::triggered, SaveToClipboardFunctor(contextMenuData.linkUrl.toString())); - menu->addAction(action); + menu->addAction(QWebEnginePage::action(CopyLinkToClipboard)); } + if (contextMenuData.mediaUrl.isValid()) { + switch (contextMenuData.mediaType) { + case WebEngineContextMenuData::MediaTypeImage: + menu->addAction(QWebEnginePage::action(DownloadImageToDisk)); + menu->addAction(QWebEnginePage::action(CopyImageUrlToClipboard)); + menu->addAction(QWebEnginePage::action(CopyImageToClipboard)); + break; + case WebEngineContextMenuData::MediaTypeCanvas: + Q_UNREACHABLE(); // mediaUrl is invalid for canvases + break; + case WebEngineContextMenuData::MediaTypeAudio: + case WebEngineContextMenuData::MediaTypeVideo: + menu->addAction(QWebEnginePage::action(DownloadMediaToDisk)); + menu->addAction(QWebEnginePage::action(CopyMediaUrlToClipboard)); + menu->addAction(QWebEnginePage::action(ToggleMediaPlayPause)); + menu->addAction(QWebEnginePage::action(ToggleMediaLoop)); + if (d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaHasAudio) + menu->addAction(QWebEnginePage::action(ToggleMediaMute)); + if (d->m_menuData.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) + menu->addAction(QWebEnginePage::action(ToggleMediaControls)); + break; + default: + break; + } + } else if (contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeCanvas) { + menu->addAction(QWebEnginePage::action(CopyImageToClipboard)); + } + return menu; } @@ -914,17 +992,22 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine } } -static inline QWebEnginePage::FileSelectionMode toPublic(WebContentsAdapterClient::FileChooserMode mode) +static inline QWebEnginePage::FileSelectionMode toPublic(FilePickerController::FileChooserMode mode) { // Should the underlying values change, we'll need a switch here. return static_cast<QWebEnginePage::FileSelectionMode>(mode); } -void QWebEnginePagePrivate::runFileChooser(WebContentsAdapterClient::FileChooserMode mode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) +void QWebEnginePagePrivate::runFileChooser(FilePickerController *controller) { Q_Q(QWebEnginePage); - QStringList selectedFileNames = q->chooseFiles(toPublic(mode), (QStringList() << defaultFileName), acceptedMimeTypes); - adapter->filesSelectedInChooser(selectedFileNames, mode); + + QStringList selectedFileNames = q->chooseFiles(toPublic(controller->mode()), (QStringList() << controller->defaultFileName()), controller->acceptedMimeTypes()); + + if (!selectedFileNames.empty()) + controller->accepted(selectedFileNames); + else + controller->rejected(); } WebEngineSettings *QWebEnginePagePrivate::webEngineSettings() const @@ -942,14 +1025,14 @@ void QWebEnginePage::toHtml(const QWebEngineCallback<const QString &> &resultCal { Q_D(const QWebEnginePage); quint64 requestId = d->adapter->fetchDocumentMarkup(); - d->m_callbacks.registerCallback(requestId, resultCallback.d); + d->m_callbacks.registerCallback(requestId, resultCallback); } void QWebEnginePage::toPlainText(const QWebEngineCallback<const QString &> &resultCallback) const { Q_D(const QWebEnginePage); quint64 requestId = d->adapter->fetchDocumentInnerText(); - d->m_callbacks.registerCallback(requestId, resultCallback.d); + d->m_callbacks.registerCallback(requestId, resultCallback); } void QWebEnginePage::setHtml(const QString &html, const QUrl &baseUrl) @@ -1016,7 +1099,7 @@ void QWebEnginePage::runJavaScript(const QString& scriptSource, const QWebEngine { Q_D(QWebEnginePage); quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource); - d->m_callbacks.registerCallback(requestId, resultCallback.d); + d->m_callbacks.registerCallback(requestId, resultCallback); } /*! @@ -1041,8 +1124,8 @@ QWebEnginePage *QWebEnginePage::createWindow(WebWindowType type) return 0; } -ASSERT_ENUMS_MATCH(WebContentsAdapterClient::Open, QWebEnginePage::FileSelectOpen) -ASSERT_ENUMS_MATCH(WebContentsAdapterClient::OpenMultiple, QWebEnginePage::FileSelectOpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::Open, QWebEnginePage::FileSelectOpen) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, QWebEnginePage::FileSelectOpenMultiple) QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) { @@ -1051,23 +1134,23 @@ QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringLis Q_UNUSED(acceptedMimeTypes); QStringList ret; QString str; - switch (static_cast<WebContentsAdapterClient::FileChooserMode>(mode)) { - case WebContentsAdapterClient::OpenMultiple: + switch (static_cast<FilePickerController::FileChooserMode>(mode)) { + case FilePickerController::OpenMultiple: ret = QFileDialog::getOpenFileNames(view(), QString()); break; // Chromium extension, not exposed as part of the public API for now. - case WebContentsAdapterClient::UploadFolder: + case FilePickerController::UploadFolder: str = QFileDialog::getExistingDirectory(view(), tr("Select folder to upload")) + QLatin1Char('/'); if (!str.isNull()) ret << str; break; - case WebContentsAdapterClient::Save: + case FilePickerController::Save: str = QFileDialog::getSaveFileName(view(), QString(), (QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + oldFiles.first())); if (!str.isNull()) ret << str; break; default: - case WebContentsAdapterClient::Open: + case FilePickerController::Open: str = QFileDialog::getOpenFileName(view(), QString(), oldFiles.first()); if (!str.isNull()) ret << str; diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index b4cf52298..471fd7290 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -39,6 +39,7 @@ #include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> #include <QtWebEngineWidgets/qwebenginecertificateerror.h> +#include <QtWebEngineCore/qwebenginecallback.h> #include <QtCore/qobject.h> #include <QtCore/qurl.h> @@ -56,37 +57,6 @@ class QWebEngineProfile; class QWebEngineScriptCollection; class QWebEngineSettings; -namespace QtWebEnginePrivate { - -template <typename T> -class QWebEngineCallbackPrivateBase : public QSharedData { -public: - virtual ~QWebEngineCallbackPrivateBase() {} - virtual void operator()(T) = 0; -}; - -template <typename T, typename F> -class QWebEngineCallbackPrivate : public QWebEngineCallbackPrivateBase<T> { -public: - QWebEngineCallbackPrivate(F callable) : m_callable(callable) {} - virtual void operator()(T value) Q_DECL_OVERRIDE { m_callable(value); } -private: - F m_callable; -}; - -} // namespace QtWebEnginePrivate - -template <typename T> -class QWebEngineCallback { -public: - template <typename F> - QWebEngineCallback(F f) : d(new QtWebEnginePrivate::QWebEngineCallbackPrivate<T, F>(f)) { } - QWebEngineCallback() { } -private: - QExplicitlySharedDataPointer<QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> > d; - friend class QWebEnginePage; -}; - class QWEBENGINEWIDGETS_EXPORT QWebEnginePage : public QObject { Q_OBJECT Q_PROPERTY(QString selectedText READ selectedText) @@ -98,6 +68,7 @@ class QWEBENGINEWIDGETS_EXPORT QWebEnginePage : public QObject { Q_PROPERTY(QString title READ title) Q_PROPERTY(QUrl url READ url WRITE setUrl) Q_PROPERTY(QUrl iconUrl READ iconUrl) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor) public: enum WebAction { @@ -118,6 +89,23 @@ public: PasteAndMatchStyle, + OpenLinkInThisWindow, + OpenLinkInNewWindow, + OpenLinkInNewTab, + CopyLinkToClipboard, + DownloadLinkToDisk, + + CopyImageToClipboard, + CopyImageUrlToClipboard, + DownloadImageToDisk, + + CopyMediaUrlToClipboard, + ToggleMediaControls, + ToggleMediaLoop, + ToggleMediaPlayPause, + ToggleMediaMute, + DownloadMediaToDisk, + WebActionCount }; @@ -236,6 +224,8 @@ public: QWebChannel *webChannel() const; void setWebChannel(QWebChannel *); + QColor backgroundColor() const; + void setBackgroundColor(const QColor &color); Q_SIGNALS: void loadStarted(); @@ -261,7 +251,6 @@ Q_SIGNALS: protected: virtual QWebEnginePage *createWindow(WebWindowType type); - virtual QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes); virtual void javaScriptAlert(const QUrl &securityOrigin, const QString& msg); virtual bool javaScriptConfirm(const QUrl &securityOrigin, const QString& msg); diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 0fcd05d3c..af37ae82f 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -50,10 +50,10 @@ #include "qwebenginepage.h" +#include "qwebenginecallback_p.h" #include "qwebenginescriptcollection.h" #include "web_contents_adapter_client.h" #include <QtCore/qcompilerdetection.h> -#include <QSharedData> namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegate; @@ -67,49 +67,6 @@ class QWebEngineProfile; class QWebEngineSettings; class QWebEngineView; -class CallbackDirectory { -public: - typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QVariant&> VariantCallback; - typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QString&> StringCallback; - typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<bool> BoolCallback; - - ~CallbackDirectory(); - void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<VariantCallback> &callback); - void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<StringCallback> &callback); - void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<BoolCallback> &callback); - void invoke(quint64 requestId, const QVariant &result); - void invoke(quint64 requestId, const QString &result); - void invoke(quint64 requestId, bool result); - -private: - struct CallbackSharedDataPointer { - enum { - None, - Variant, - String, - Bool - } type; - union { - VariantCallback *variantCallback; - StringCallback *stringCallback; - BoolCallback *boolCallback; - }; - CallbackSharedDataPointer() : type(None) { } - CallbackSharedDataPointer(VariantCallback *callback) : type(Variant), variantCallback(callback) { callback->ref.ref(); } - CallbackSharedDataPointer(StringCallback *callback) : type(String), stringCallback(callback) { callback->ref.ref(); } - CallbackSharedDataPointer(BoolCallback *callback) : type(Bool), boolCallback(callback) { callback->ref.ref(); } - CallbackSharedDataPointer(const CallbackSharedDataPointer &other) : type(other.type), variantCallback(other.variantCallback) { doRef(); } - ~CallbackSharedDataPointer() { doDeref(); } - operator bool () const { return type != None; } - - private: - void doRef(); - void doDeref(); - }; - - QHash<quint64, CallbackSharedDataPointer> m_callbackMap; -}; - class QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient { public: @@ -129,6 +86,7 @@ public: virtual void selectionChanged() Q_DECL_OVERRIDE; virtual QRectF viewportRect() const Q_DECL_OVERRIDE; virtual qreal dpiScale() const Q_DECL_OVERRIDE; + virtual QColor backgroundColor() const Q_DECL_OVERRIDE; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) Q_DECL_OVERRIDE; virtual void loadCommitted() Q_DECL_OVERRIDE; virtual void loadVisuallyCommitted() Q_DECL_OVERRIDE { } @@ -142,7 +100,7 @@ public: virtual void requestFullScreen(bool) Q_DECL_OVERRIDE { } virtual bool isFullScreen() const Q_DECL_OVERRIDE { return false; } virtual void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) Q_DECL_OVERRIDE; - virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE; + virtual void runFileChooser(QtWebEngineCore::FilePickerController *controller) Q_DECL_OVERRIDE; virtual void didRunJavaScript(quint64 requestId, const QVariant& result) Q_DECL_OVERRIDE; virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) Q_DECL_OVERRIDE; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) Q_DECL_OVERRIDE; @@ -176,13 +134,13 @@ public: QWebEngineProfile *profile; QWebEngineSettings *settings; QWebEngineView *view; - QSize viewportSize; QUrl explicitUrl; QtWebEngineCore::WebEngineContextMenuData m_menuData; bool isLoading; QWebEngineScriptCollection scriptCollection; + QColor m_backgroundColor; - mutable CallbackDirectory m_callbacks; + mutable QtWebEngineCore::CallbackDirectory m_callbacks; mutable QAction *actions[QWebEnginePage::WebActionCount]; }; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 2e5f685fd..29010b0dd 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -36,6 +36,7 @@ #include "qwebengineprofile.h" +#include "qwebenginecookiestoreclient.h" #include "qwebenginedownloaditem.h" #include "qwebenginedownloaditem_p.h" #include "qwebenginepage.h" @@ -354,6 +355,28 @@ void QWebEngineProfile::setHttpCacheType(QWebEngineProfile::HttpCacheType httpCa } /*! + Sets the value of the Accept-Language HTTP request-header field. + + \since 5.6 + */ +void QWebEngineProfile::setHttpAcceptLanguage(const QString &httpAcceptLanguage) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpAcceptLanguage(httpAcceptLanguage); +} + +/*! + Returns the value of the Accept-Language HTTP request-header field. + + \since 5.6 + */ +QString QWebEngineProfile::httpAcceptLanguage() const +{ + Q_D(const QWebEngineProfile); + return d->browserContext()->httpAcceptLanguage(); +} + +/*! Returns the current policy for persistent cookies. If the profile is off-the-record NoPersistentCookies is returned. @@ -403,6 +426,24 @@ void QWebEngineProfile::setHttpCacheMaximumSize(int maxSize) d->browserContext()->setHttpCacheMaxSize(maxSize); } +QWebEngineCookieStoreClient* QWebEngineProfile::cookieStoreClient() +{ + Q_D(QWebEngineProfile); + return d->browserContext()->cookieStoreClient(); +} + +void QWebEngineProfile::setCookieStoreClient(QWebEngineCookieStoreClient *client) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setCookieStoreClient(client); +} + +void QWebEngineProfile::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setRequestInterceptor(interceptor); +} + /*! Clears all links from the visited links database. diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h index 4308fe75d..06e11eeca 100644 --- a/src/webenginewidgets/api/qwebengineprofile.h +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -37,22 +37,24 @@ #ifndef QWEBENGINEPROFILE_H #define QWEBENGINEPROFILE_H -#include "qtwebenginewidgetsglobal.h" +#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> -#include <QObject> -#include <QScopedPointer> -#include <QString> +#include <QtCore/qobject.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qstring.h> QT_BEGIN_NAMESPACE class QObject; class QUrl; +class QWebEngineCookieStoreClient; class QWebEngineDownloadItem; class QWebEnginePage; class QWebEnginePagePrivate; class QWebEngineProfilePrivate; class QWebEngineSettings; class QWebEngineScriptCollection; +class QWebEngineUrlRequestInterceptor; class QWEBENGINEWIDGETS_EXPORT QWebEngineProfile : public QObject { Q_OBJECT @@ -87,12 +89,19 @@ public: HttpCacheType httpCacheType() const; void setHttpCacheType(QWebEngineProfile::HttpCacheType); + void setHttpAcceptLanguage(const QString &httpAcceptLanguage); + QString httpAcceptLanguage() const; + PersistentCookiesPolicy persistentCookiesPolicy() const; void setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy); int httpCacheMaximumSize() const; void setHttpCacheMaximumSize(int maxSize); + QWebEngineCookieStoreClient* cookieStoreClient(); + void setCookieStoreClient(QWebEngineCookieStoreClient *client); + void setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); + void clearAllVisitedLinks(); void clearVisitedLinks(const QList<QUrl> &urls); bool visitedLinksContainsUrl(const QUrl &url) const; diff --git a/src/webenginewidgets/api/qwebenginescript.h b/src/webenginewidgets/api/qwebenginescript.h index 2b03cd06f..4cff2631d 100644 --- a/src/webenginewidgets/api/qwebenginescript.h +++ b/src/webenginewidgets/api/qwebenginescript.h @@ -36,10 +36,11 @@ #ifndef QWEBENGINESCRIPT_H #define QWEBENGINESCRIPT_H -#include "qtwebenginewidgetsglobal.h" -#include <QtCore/QSharedDataPointer> -#include <QtCore/QString> +#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> + +#include <QtCore/qshareddata.h> +#include <QtCore/qstring.h> namespace QtWebEngineCore { class UserScript; diff --git a/src/webenginewidgets/api/qwebenginescriptcollection.h b/src/webenginewidgets/api/qwebenginescriptcollection.h index fe3ce2861..40196b478 100644 --- a/src/webenginewidgets/api/qwebenginescriptcollection.h +++ b/src/webenginewidgets/api/qwebenginescriptcollection.h @@ -37,12 +37,12 @@ #ifndef QWEBENGINESCRIPTCOLLECTION_H #define QWEBENGINESCRIPTCOLLECTION_H -#include "qtwebenginewidgetsglobal.h" +#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> +#include <QtWebEngineWidgets/qwebenginescript.h> -#include "qwebenginescript.h" -#include <QtCore/QScopedPointer> -#include <QtCore/QList> -#include <QtCore/QSet> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qlist.h> +#include <QtCore/qset.h> QT_BEGIN_NAMESPACE class QWebEngineScriptCollectionPrivate; diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index dadc3bfe1..aaa93ab9f 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -72,6 +72,8 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web return WebEngineSettings::ScrollAnimatorEnabled; case QWebEngineSettings::ErrorPageEnabled: return WebEngineSettings::ErrorPageEnabled; + case QWebEngineSettings::PluginsEnabled: + return WebEngineSettings::PluginsEnabled; default: return WebEngineSettings::UnsupportedInCoreSettings; } diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index 44339a2f6..50a93e393 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -58,7 +58,8 @@ public: LocalContentCanAccessFileUrls, HyperlinkAuditingEnabled, ScrollAnimatorEnabled, - ErrorPageEnabled + ErrorPageEnabled, + PluginsEnabled }; enum FontSize { diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index 40c5c8d04..676643387 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -98,6 +98,22 @@ \value SelectAll Selects all content. \value PasteAndMatchStyle Paste content from the clipboard with current style. + \value OpenLinkInThisWindow Open the current link in the current window. (Added in Qt 5.6) + \value OpenLinkInNewWindow Open the current link in a new window. (Added in Qt 5.6) + \value OpenLinkInNewTab Open the current link in a new tab. (Added in Qt 5.6) + \value CopyLinkToClipboard Copy the current link to the clipboard. (Added in Qt 5.6) + + \value CopyImageToClipboard Copy the clicked image to the clipboard. (Added in Qt 5.6) + \value CopyImageUrlToClipboard Copy the clicked image's URL to the clipboard. (Added in Qt 5.6) + \value CopyMediaUrlToClipboard Copy the hovered audio or video's URL to the clipboard. (Added in Qt 5.6) + \value ToggleMediaControls Toggles between showing and hiding the controls for the hovered audio or video element. (Added in Qt 5.6) + \value ToggleMediaLoop Toggles whether the hovered audio or video should loop on completetion or not. (Added in Qt 5.6) + \value ToggleMediaPlayPause Toggles the play/pause state of the hovered audio or video element. (Added in Qt 5.6) + \value ToggleMediaMute Mutes or unmutes the hovered audio or video element. (Added in Qt 5.6) + \value DownloadLinkToDisk Download the current link to the disk. (Added in Qt 5.6) + \value DownloadImageToDisk Download the highlighted image to the disk. (Added in Qt 5.6) + \value DownloadMediaToDisk Download the hovered audio or video to the disk. (Added in Qt 5.6) + \omitvalue WebActionCount */ 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 dba37cea7..76ca8d354 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -59,6 +59,7 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende , m_rootNode(new QSGRootNode) , m_sgEngine(new QSGEngine) , m_isPopup(false) + , m_clearColor(Qt::white) { setFocusPolicy(Qt::StrongFocus); @@ -218,6 +219,19 @@ void RenderWidgetHostViewQtDelegateWidget::setTooltip(const QString &tooltip) setToolTip(wrappedTip); } +void RenderWidgetHostViewQtDelegateWidget::setClearColor(const QColor &color) +{ + m_clearColor = color; + // QOpenGLWidget is usually blended by punching holes into widgets + // above it to simulate the visual stacking order. If we want it to be + // transparent we have to throw away the proper stacking order and always + // blend the complete normal widgets backing store under it. + bool isTranslucent = color.alpha() < 255; + setAttribute(Qt::WA_AlwaysStackOnTop, isTranslucent); + setAttribute(Qt::WA_OpaquePaintEvent, !isTranslucent); + update(); +} + QVariant RenderWidgetHostViewQtDelegateWidget::inputMethodQuery(Qt::InputMethodQuery query) const { return m_client->inputMethodQuery(query); @@ -270,7 +284,7 @@ void RenderWidgetHostViewQtDelegateWidget::initializeGL() m_sgEngine->initialize(QOpenGLContext::currentContext()); m_sgRenderer.reset(m_sgEngine->createRenderer()); m_sgRenderer->setRootNode(m_rootNode.data()); - m_sgRenderer->setClearColor(Qt::white); + m_sgRenderer->setClearColor(m_clearColor); } void RenderWidgetHostViewQtDelegateWidget::paintGL() 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 d0dfdc689..d228bd487 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -78,6 +78,7 @@ public: virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; virtual void setTooltip(const QString &tooltip) Q_DECL_OVERRIDE; + virtual void setClearColor(const QColor &color) Q_DECL_OVERRIDE; protected: bool event(QEvent *event) Q_DECL_OVERRIDE; @@ -98,6 +99,7 @@ private: QScopedPointer<QSGEngine> m_sgEngine; QScopedPointer<QSGAbstractRenderer> m_sgRenderer; bool m_isPopup; + QColor m_clearColor; QList<QMetaObject::Connection> m_windowConnections; }; diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 1f7974bd2..0d92767c1 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -3,12 +3,12 @@ TARGET = QtWebEngineWidgets # For our export macros DEFINES += QT_BUILD_WEBENGINEWIDGETS_LIB -QT += webengine widgets network quick -QT_PRIVATE += webenginecore quick-private gui-private core-private +QT += webengine webenginecore widgets network quick +QT_PRIVATE += quick-private gui-private core-private QMAKE_DOCS = $$PWD/doc/qtwebenginewidgets.qdocconf -INCLUDEPATH += $$PWD api ../core ../webengine/api +INCLUDEPATH += $$PWD api ../core ../core/api ../webengine/api SOURCES = \ api/qtwebenginewidgetsglobal.cpp \ diff --git a/sync.profile b/sync.profile index 774941d56..11d7b0548 100644 --- a/sync.profile +++ b/sync.profile @@ -1,10 +1,12 @@ %modules = ( # path to module name map "QtWebEngine" => "$basedir/src/webengine", "QtWebEngineWidgets" => "$basedir/src/webenginewidgets", + "QtWebEngineCore" => "$basedir/src/core", ); %moduleheaders = ( # restrict the module headers to those found in relative path "QtWebEngine" => "api", "QtWebEngineWidgets" => "api", + "QtWebEngineCore" => "api", ); %classnames = ( ); diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index f14305f72..06430cf8e 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -4,4 +4,6 @@ SUBDIRS = quick qtHaveModule(webenginewidgets) { SUBDIRS += widgets +# core tests depend on widgets for now + SUBDIRS += core } diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro new file mode 100644 index 000000000..ed0a61532 --- /dev/null +++ b/tests/auto/core/core.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +CONFIG += ordered + +SUBDIRS += \ + qwebenginecookiestoreclient \ + qwebengineurlrequestinterceptor \ diff --git a/tests/auto/core/qwebenginecookiestoreclient/qwebenginecookiestoreclient.pro b/tests/auto/core/qwebenginecookiestoreclient/qwebenginecookiestoreclient.pro new file mode 100644 index 000000000..ff6c49628 --- /dev/null +++ b/tests/auto/core/qwebenginecookiestoreclient/qwebenginecookiestoreclient.pro @@ -0,0 +1,2 @@ +include(../tests.pri) +exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc diff --git a/tests/auto/core/qwebenginecookiestoreclient/resources/content.html b/tests/auto/core/qwebenginecookiestoreclient/resources/content.html new file mode 100644 index 000000000..360ad65ef --- /dev/null +++ b/tests/auto/core/qwebenginecookiestoreclient/resources/content.html @@ -0,0 +1,5 @@ +<html> +<body> +<a>This is test content</a> +</body> +</html> diff --git a/tests/auto/core/qwebenginecookiestoreclient/resources/index.html b/tests/auto/core/qwebenginecookiestoreclient/resources/index.html new file mode 100644 index 000000000..d41866712 --- /dev/null +++ b/tests/auto/core/qwebenginecookiestoreclient/resources/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <script type="text/javascript"> + function generateCookieString(key, value, options) { + key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent); + key = key.replace(/\(/g, '%28').replace(/\)/g, '%29'); + value = (value + '').replace(/[^!#$&-+\--:<-\[\]-~]/g, encodeURIComponent); + options = options || {}; + + var cookieString = key + '=' + value; + cookieString += options.path ? '; Path=' + options.path : ''; + cookieString += options.domain ? '; Domain=' + options.domain : ''; + cookieString += options.expires ? '; Expires=' + options.expires.toUTCString() : ''; + cookieString += options.secure ? '; Secure' : ''; + + console.log(cookieString) + return cookieString; +}; +function setCookie() { + var name = "SessionCookie" + var value = "QtWebEngineCookieTest" + document.cookie = generateCookieString(name, value, {}) + + name = "CookieWithExpiresField" + value = "QtWebEngineCookieTest" + var daysValid = 10; + var date = new Date(); + date.setTime(date.getTime() + (daysValid*24*60*60*1000)); + var expires = date; + var options = {}; + options.expires = expires; + document.cookie = generateCookieString(name, value, options) +} +</script> + </head> + <body onload="setCookie()"> + </body> +</html> diff --git a/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp b/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp new file mode 100644 index 000000000..0f007d643 --- /dev/null +++ b/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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 "../../widgets/util.h" +#include <QtTest/QtTest> +#include <QtWebEngineCore/qwebenginecallback.h> +#include <QtWebEngineCore/qwebenginecookiestoreclient.h> +#include <QtWebEngineWidgets/qwebenginepage.h> +#include <QtWebEngineWidgets/qwebengineprofile.h> +#include <QtWebEngineWidgets/qwebengineview.h> + +class tst_QWebEngineCookieStoreClient : public QObject +{ + Q_OBJECT + +public: + tst_QWebEngineCookieStoreClient(); + ~tst_QWebEngineCookieStoreClient(); + +public Q_SLOTS: + void init(); + void cleanup(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void cookieSignals(); + void setAndDeleteCookie(); + void batchCookieTasks(); +}; + +tst_QWebEngineCookieStoreClient::tst_QWebEngineCookieStoreClient() +{ +} + +tst_QWebEngineCookieStoreClient::~tst_QWebEngineCookieStoreClient() +{ +} + +void tst_QWebEngineCookieStoreClient::init() +{ +} + +void tst_QWebEngineCookieStoreClient::cleanup() +{ +} + +void tst_QWebEngineCookieStoreClient::initTestCase() +{ +} + +void tst_QWebEngineCookieStoreClient::cleanupTestCase() +{ +} + +void tst_QWebEngineCookieStoreClient::cookieSignals() +{ + QWebEngineView view; + QWebEngineCookieStoreClient client; + + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); + QSignalSpy cookieAddedSpy(&client, SIGNAL(cookieAdded(const QNetworkCookie &))); + QSignalSpy cookieRemovedSpy(&client, SIGNAL(cookieRemoved(const QNetworkCookie &))); + + view.page()->profile()->setCookieStoreClient(&client); + + view.load(QUrl("qrc:///resources/index.html")); + + QTRY_COMPARE(loadSpy.count(), 1); + QVariant success = loadSpy.takeFirst().takeFirst(); + QVERIFY(success.toBool()); + QTRY_COMPARE(cookieAddedSpy.count(), 2); + + // try whether updating a cookie to be expired results in that cookie being removed. + QNetworkCookie expiredCookie(QNetworkCookie::parseCookies(QByteArrayLiteral("SessionCookie=delete; expires=Thu, 01-Jan-1970 00:00:00 GMT; path=///resources")).first()); + client.setCookie(expiredCookie, QUrl("qrc:///resources/index.html")); + QTRY_COMPARE(cookieRemovedSpy.count(), 1); + cookieRemovedSpy.clear(); + + // try removing the other cookie. + QNetworkCookie nonSessionCookie(QNetworkCookie::parseCookies(QByteArrayLiteral("CookieWithExpiresField=QtWebEngineCookieTest; path=///resources")).first()); + client.deleteCookie(nonSessionCookie, QUrl("qrc:///resources/index.html")); + QTRY_COMPARE(cookieRemovedSpy.count(), 1); +} + +void tst_QWebEngineCookieStoreClient::setAndDeleteCookie() +{ + QWebEngineView view; + QWebEngineCookieStoreClient client; + + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); + QSignalSpy cookieAddedSpy(&client, SIGNAL(cookieAdded(const QNetworkCookie &))); + QSignalSpy cookieRemovedSpy(&client, SIGNAL(cookieRemoved(const QNetworkCookie &))); + + QNetworkCookie cookie1(QNetworkCookie::parseCookies(QByteArrayLiteral("khaos=I9GX8CWI; Domain=.example.com; Path=/docs")).first()); + QNetworkCookie cookie2(QNetworkCookie::parseCookies(QByteArrayLiteral("Test%20Cookie=foobar; domain=example.com; Path=/")).first()); + QNetworkCookie cookie3(QNetworkCookie::parseCookies(QByteArrayLiteral("SessionCookie=QtWebEngineCookieTest; Path=///resources")).first()); + QNetworkCookie expiredCookie3(QNetworkCookie::parseCookies(QByteArrayLiteral("SessionCookie=delete; expires=Thu, 01-Jan-1970 00:00:00 GMT; path=///resources")).first()); + + // check if pending cookies are set and removed + client.setCookieWithCallback(cookie1, [](bool success) { QVERIFY(success); }); + client.setCookieWithCallback(cookie2, [](bool success) { QVERIFY(success); }); + client.deleteCookie(cookie1); + + view.page()->profile()->setCookieStoreClient(&client); + view.load(QUrl("qrc:///resources/content.html")); + + QTRY_COMPARE(loadSpy.count(), 1); + QVariant success = loadSpy.takeFirst().takeFirst(); + QVERIFY(success.toBool()); + QTRY_COMPARE(cookieAddedSpy.count(), 2); + QTRY_COMPARE(cookieRemovedSpy.count(), 1); + cookieAddedSpy.clear(); + cookieRemovedSpy.clear(); + + client.setCookieWithCallback(cookie3, [](bool success) { QVERIFY(success); }); + // updating a cookie with an expired 'expires' field should remove the cookie with the same name + client.setCookieWithCallback(expiredCookie3, [](bool success) { QVERIFY(success); }); + client.deleteCookie(cookie2); + QTRY_COMPARE(cookieAddedSpy.count(), 1); + QTRY_COMPARE(cookieRemovedSpy.count(), 2); +} + +void tst_QWebEngineCookieStoreClient::batchCookieTasks() +{ + QWebEngineView view; + QWebEngineCookieStoreClient client; + + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); + QSignalSpy cookieAddedSpy(&client, SIGNAL(cookieAdded(const QNetworkCookie &))); + QSignalSpy cookieRemovedSpy(&client, SIGNAL(cookieRemoved(const QNetworkCookie &))); + + QNetworkCookie cookie1(QNetworkCookie::parseCookies(QByteArrayLiteral("khaos=I9GX8CWI; Domain=.example.com; Path=/docs")).first()); + QNetworkCookie cookie2(QNetworkCookie::parseCookies(QByteArrayLiteral("Test%20Cookie=foobar; domain=example.com; Path=/")).first()); + + int capture = 0; + + client.setCookieWithCallback(cookie1, [&capture](bool success) { QVERIFY(success); ++capture; }); + client.setCookieWithCallback(cookie2, [&capture](bool success) { QVERIFY(success); ++capture; }); + + view.page()->profile()->setCookieStoreClient(&client); + view.load(QUrl("qrc:///resources/index.html")); + + QTRY_COMPARE(loadSpy.count(), 1); + QVariant success = loadSpy.takeFirst().takeFirst(); + QVERIFY(success.toBool()); + QTRY_COMPARE(cookieAddedSpy.count(), 4); + QTRY_COMPARE(cookieRemovedSpy.count(), 0); + QTRY_COMPARE(capture, 2); + capture = 0; + + cookieAddedSpy.clear(); + cookieRemovedSpy.clear(); + + client.getAllCookies([&capture](const QByteArray& cookieLine) { + ++capture; + QCOMPARE(QNetworkCookie::parseCookies(cookieLine).count(), 4); + }); + + client.deleteSessionCookiesWithCallback([&capture](int numDeleted) { + ++capture; + QCOMPARE(numDeleted, 3); + }); + + client.deleteAllCookiesWithCallback([&capture](int numDeleted) { + ++capture; + QCOMPARE(numDeleted, 1); + }); + + QTRY_COMPARE(capture, 3); +} + +QTEST_MAIN(tst_QWebEngineCookieStoreClient) +#include "tst_qwebenginecookiestoreclient.moc" diff --git a/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.qrc b/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.qrc new file mode 100644 index 000000000..afeae268b --- /dev/null +++ b/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>resources/index.html</file> + <file>resources/content.html</file> +</qresource> +</RCC> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro b/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro new file mode 100644 index 000000000..ff6c49628 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro @@ -0,0 +1,2 @@ +include(../tests.pri) +exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/content.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/content.html new file mode 100644 index 000000000..360ad65ef --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/content.html @@ -0,0 +1,5 @@ +<html> +<body> +<a>This is test content</a> +</body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/index.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/index.html new file mode 100644 index 000000000..a744dbd99 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/index.html @@ -0,0 +1,16 @@ +<html> + <head> + <script type="text/javascript"> + function post() { + var form = document.createElement("form"); + form.setAttribute("method", "POST"); + document.body.appendChild(form); + form.submit(); + return true; + } +</script> + </head> + <body> + <h1>Test page</h1> + </body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp new file mode 100644 index 000000000..b0ef9a1ba --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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 "../../widgets/util.h" +#include <QtTest/QtTest> +#include <QtWebEngineCore/qwebengineurlrequestinterceptor.h> +#include <QtWebEngineWidgets/qwebenginepage.h> +#include <QtWebEngineWidgets/qwebengineprofile.h> +#include <QtWebEngineWidgets/qwebengineview.h> + +class tst_QWebEngineUrlRequestInterceptor : public QObject +{ + Q_OBJECT + +public: + tst_QWebEngineUrlRequestInterceptor(); + ~tst_QWebEngineUrlRequestInterceptor(); + +public Q_SLOTS: + void init(); + void cleanup(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void interceptRequest(); +}; + +tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor() +{ +} + +tst_QWebEngineUrlRequestInterceptor::~tst_QWebEngineUrlRequestInterceptor() +{ +} + +void tst_QWebEngineUrlRequestInterceptor::init() +{ +} + +void tst_QWebEngineUrlRequestInterceptor::cleanup() +{ +} + +void tst_QWebEngineUrlRequestInterceptor::initTestCase() +{ +} + +void tst_QWebEngineUrlRequestInterceptor::cleanupTestCase() +{ +} + +class TestRequestInterceptor: public QWebEngineUrlRequestInterceptor +{ +public: + QList<QUrl> observedUrls; + bool shouldIntercept; + + bool interceptRequest(QWebEngineUrlRequestInfo &info) override + { + info.blockRequest(info.method() != QByteArrayLiteral("GET")); + if (info.url().toString().endsWith(QLatin1String("__placeholder__"))) + info.redirectTo(QUrl("qrc:///resources/content.html")); + + observedUrls.append(info.url()); + return shouldIntercept; + } + TestRequestInterceptor(bool intercept) + : shouldIntercept(intercept) + { + } +}; + +void tst_QWebEngineUrlRequestInterceptor::interceptRequest() +{ + QWebEngineView view; + TestRequestInterceptor interceptor(/* intercept */ true); + + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); + view.page()->profile()->setRequestInterceptor(&interceptor); + view.load(QUrl("qrc:///resources/index.html")); + QTRY_COMPARE(loadSpy.count(), 1); + QVariant success = loadSpy.takeFirst().takeFirst(); + QVERIFY(success.toBool()); + loadSpy.clear(); + QVariant ok; + + view.page()->runJavaScript("post();", [&ok](const QVariant result){ ok = result; }); + QTRY_VERIFY(ok.toBool()); + QTRY_COMPARE(loadSpy.count(), 1); + success = loadSpy.takeFirst().takeFirst(); + // We block non-GET requests, so this should not succeed. + QVERIFY(!success.toBool()); + loadSpy.clear(); + + view.load(QUrl("qrc:///resources/__placeholder__")); + QTRY_COMPARE(loadSpy.count(), 1); + success = loadSpy.takeFirst().takeFirst(); + // The redirection for __placeholder__ should succeed. + QVERIFY(success.toBool()); + loadSpy.clear(); + QCOMPARE(interceptor.observedUrls.count(), 4); + + + // Make sure that registering an observer does not modify the request. + TestRequestInterceptor observer(/* intercept */ false); + view.page()->profile()->setRequestInterceptor(&observer); + view.load(QUrl("qrc:///resources/__placeholder__")); + QTRY_COMPARE(loadSpy.count(), 1); + success = loadSpy.takeFirst().takeFirst(); + // Since we do not intercept, loading an invalid path should not succeed. + QVERIFY(!success.toBool()); + QCOMPARE(observer.observedUrls.count(), 1); +} + +QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor) +#include "tst_qwebengineurlrequestinterceptor.moc" diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc new file mode 100644 index 000000000..afeae268b --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>resources/index.html</file> + <file>resources/content.html</file> +</qresource> +</RCC> diff --git a/tests/auto/core/tests.pri b/tests/auto/core/tests.pri new file mode 100644 index 000000000..7046487db --- /dev/null +++ b/tests/auto/core/tests.pri @@ -0,0 +1,18 @@ +TEMPLATE = app + +# FIXME: Re-enable once we want to run tests on the CI +# CONFIG += testcase + +CONFIG += c++11 + +VPATH += $$_PRO_FILE_PWD_ +TARGET = tst_$$TARGET + +SOURCES += $${TARGET}.cpp +INCLUDEPATH += $$PWD + +QT += testlib network webenginewidgets widgets +osx: CONFIG -= app_bundle + +# This define is used by some tests to look up resources in the source tree +DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\" diff --git a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp index 28a77d8cd..b5894a248 100644 --- a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp +++ b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp @@ -86,7 +86,7 @@ void tst_InspectorServer::prepareWebViewComponent() m_component.reset(new QQmlComponent(engine, this)); m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n" - "import QtWebEngine 1.1\n" + "import QtWebEngine 1.2\n" "WebEngineView { }") , QUrl()); } diff --git a/tests/auto/quick/qmltests/data/TestWebEngineView.qml b/tests/auto/quick/qmltests/data/TestWebEngineView.qml index a97739404..8a01dfa09 100644 --- a/tests/auto/quick/qmltests/data/TestWebEngineView.qml +++ b/tests/auto/quick/qmltests/data/TestWebEngineView.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 import QtWebEngine.experimental 1.0 WebEngineView { diff --git a/tests/auto/quick/qmltests/data/directoryupload.html b/tests/auto/quick/qmltests/data/directoryupload.html new file mode 100644 index 000000000..6a6e4580c --- /dev/null +++ b/tests/auto/quick/qmltests/data/directoryupload.html @@ -0,0 +1,16 @@ +<html> +<head> +<meta name="viewport" initial-scale=1"> +<title> Directory Upload </title> +<script src = "./titleupdate.js"> +</script> + +<body> +<input type="file" id="upfile" webkitdirectory="" directory="" onchange="updateTitle()"> +<script> +window.onload = function() { +document.getElementById("upfile").focus() +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/forms.html b/tests/auto/quick/qmltests/data/forms.html new file mode 100644 index 000000000..8dc3472f2 --- /dev/null +++ b/tests/auto/quick/qmltests/data/forms.html @@ -0,0 +1,40 @@ +<html> +<head> + <title>Forms</title> + <script type="text/javascript"> + function updateFocus() { + var name = window.location.hash.substring(1); + var element = document.getElementsByName(name)[0]; + + element.focus(); + } + </script> +</head> +<body onload="updateFocus();"> + <form> + <input type="url" required/> + <input type="submit" name="url_empty"/> + </form> + <form> + <input type="url" value="invalid" required/> + <input type="submit" name="url_invalid"/> + </form> + <form> + <input type="url" value="invalid" title="url_title" required/> + <input type="submit" name="url_title"/> + </form> + + <form> + <input type="email" required/> + <input type="submit" name="email_empty"/> + </form> + <form> + <input type="email" value="invalid" required/> + <input type="submit" name="email_invalid"/> + </form> + <form> + <input type="email" value="invalid" title="email_title" required/> + <input type="submit" name="email_title"/> + </form> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/multifileupload.html b/tests/auto/quick/qmltests/data/multifileupload.html new file mode 100644 index 000000000..cc87d8f41 --- /dev/null +++ b/tests/auto/quick/qmltests/data/multifileupload.html @@ -0,0 +1,17 @@ +<html> +<head> +<meta name="viewport" initial-scale=1"> +<title> Mutli-file Upload </title> +<script src = "./titleupdate.js"> +</script> + +<body> +<input type="file" name="file" id="upfile" onchange="updateTitle()" multiple/> + +<script> +window.onload = function() { +document.getElementById("upfile").focus() +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/singlefileupload.html b/tests/auto/quick/qmltests/data/singlefileupload.html new file mode 100644 index 000000000..8469aa128 --- /dev/null +++ b/tests/auto/quick/qmltests/data/singlefileupload.html @@ -0,0 +1,17 @@ +<html> +<head> +<meta name="viewport" initial-scale=1"> +<title> Single File Upload </title> +<script src = "./titleupdate.js"> +</script> + +<body> +<input type="file" name="file" id="upfile" onchange="updateTitle()"/> + +<script> +window.onload = function() { +document.getElementById("upfile").focus() +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/titleupdate.js b/tests/auto/quick/qmltests/data/titleupdate.js new file mode 100644 index 000000000..cfcc52c60 --- /dev/null +++ b/tests/auto/quick/qmltests/data/titleupdate.js @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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$ +** +****************************************************************************/ + +function updateTitle() +{ + var inp = document.getElementById("upfile"); + var allfiles = new String(""); + var name = new String(""); + for (var i = 0; i < inp.files.length; ++i) { + name = inp.files.item(i).name; + if (allfiles.length == 0) + allfiles = name; + else + allfiles = allfiles + "," + name; + } + document.title = allfiles; +} diff --git a/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml b/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml new file mode 100644 index 000000000..eaca8822b --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_activeFocusOnPress.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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.5 +import QtTest 1.0 + +Item { + id: root + width: 300 + height: 400 + TextInput { + id: textInput + anchors { + top: parent.top + left: parent.left + right: parent.right + } + focus: true + text: "foo" + } + + TestWebEngineView { + id: webEngineView + activeFocusOnPress: false + anchors { + top: textInput.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } + + TestCase { + name: "ActiveFocusOnPress" + when:windowShown + + function test_activeFocusOnPress() { + textInput.forceActiveFocus() + verify(textInput.activeFocus) + mouseClick(root, 150, 300, Qt.LeftButton) + verify(textInput.activeFocus) + } + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml b/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml index dfb983c43..51c1d5580 100644 --- a/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml +++ b/tests/auto/quick/qmltests/data/tst_desktopBehaviorLoadHtml.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_favIconLoad.qml b/tests/auto/quick/qmltests/data/tst_favIconLoad.qml index 73190f1bd..df5479eec 100644 --- a/tests/auto/quick/qmltests/data/tst_favIconLoad.qml +++ b/tests/auto/quick/qmltests/data/tst_favIconLoad.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_filePicker.qml b/tests/auto/quick/qmltests/data/tst_filePicker.qml new file mode 100644 index 000000000..02b2dd024 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_filePicker.qml @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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.2 +import "../mock-delegates/TestParams" 1.0 + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + + SignalSpy { + id: titleSpy + target: webEngineView + signalName: "titleChanged" + } + + TestCase { + name: "WebEngineViewSingleFileUpload" + when: windowShown + + function init() { + FilePickerParams.filePickerOpened = false + FilePickerParams.selectFiles = false + FilePickerParams.selectedFilesUrl = [] + titleSpy.clear() + } + + // FIXME: Almost every second url loading progress does get stuck at about 90 percent, so the loadFinished signal won't arrive. + // This cleanup function is a workaround for this problem. + function cleanup() { + webEngineView.url = Qt.resolvedUrl("about:blank") + webEngineView.waitForLoadSucceeded() + } + + function test_acceptSingleFileSelection() { + webEngineView.url = Qt.resolvedUrl("singlefileupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + FilePickerParams.selectFiles = true + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("test1.html")) + + keyPress(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + wait(100) // The ui delegate is invoked asynchronously + verify(FilePickerParams.filePickerOpened) + titleSpy.wait() + compare(webEngineView.title, "test1.html") + } + + function test_acceptMultipleFilesSelection() { + webEngineView.url = Qt.resolvedUrl("multifileupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + FilePickerParams.selectFiles = true + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("test1.html")) + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("test2.html")) + + keyPress(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + wait(100) + verify(FilePickerParams.filePickerOpened) + titleSpy.wait() + compare(webEngineView.title, "test1.html,test2.html") + } + + function test_acceptDirectory() { + webEngineView.url = Qt.resolvedUrl("directoryupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + FilePickerParams.selectFiles = true + FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("../data")) + + keyPress(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + wait(100) // The ui delegate is invoked asynchronously + verify(FilePickerParams.filePickerOpened) + titleSpy.wait() + compare(webEngineView.title, "data") + } + + function test_reject() { + webEngineView.url = Qt.resolvedUrl("singlefileupload.html") + verify(webEngineView.waitForLoadSucceeded()) + + titleSpy.clear() + keyPress(Qt.Key_Enter) // Focus is on the button. Open FileDialog. + wait(100) + compare(titleSpy.count, 0) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_findText.qml b/tests/auto/quick/qmltests/data/tst_findText.qml index b51da0b2e..9c4aa48c1 100644 --- a/tests/auto/quick/qmltests/data/tst_findText.qml +++ b/tests/auto/quick/qmltests/data/tst_findText.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_formValidation.qml b/tests/auto/quick/qmltests/data/tst_formValidation.qml new file mode 100644 index 000000000..4acb7ce63 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_formValidation.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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.2 +import QtWebEngine.testsupport 1.0 + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + + testSupport: WebEngineTestSupport { + id: testSupportAPI + } + + SignalSpy { + id: showSpy + target: testSupportAPI + signalName: "validationMessageShown" + } + + TestCase { + name: "WebEngineViewFormValidation" + when: windowShown + + function init() { + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + showSpy.clear() + } + + function test_urlForm() { + webEngineView.url = Qt.resolvedUrl("forms.html#url_empty") + verify(webEngineView.waitForLoadSucceeded()) + keyPress(Qt.Key_Enter) + showSpy.wait() + compare(showSpy.signalArguments[0][0], "Please fill out this field.") + + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.url = Qt.resolvedUrl("forms.html#url_invalid") + verify(webEngineView.waitForLoadSucceeded()) + keyPress(Qt.Key_Enter) + showSpy.wait() + compare(showSpy.signalArguments[1][0], "Please enter a URL.") + + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.url = Qt.resolvedUrl("forms.html#url_title") + verify(webEngineView.waitForLoadSucceeded()) + keyPress(Qt.Key_Enter) + showSpy.wait() + compare(showSpy.signalArguments[2][1], "url_title") + } + + function test_emailForm() { + webEngineView.url = Qt.resolvedUrl("forms.html#email_empty") + verify(webEngineView.waitForLoadSucceeded()) + keyPress(Qt.Key_Enter) + showSpy.wait() + compare(showSpy.signalArguments[0][0], "Please fill out this field.") + + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.url = Qt.resolvedUrl("forms.html#email_invalid") + verify(webEngineView.waitForLoadSucceeded()) + keyPress(Qt.Key_Enter) + showSpy.wait() + compare(showSpy.signalArguments[1][0], "Please include an '@' in the email address. 'invalid' is missing an '@'.") + + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.url = Qt.resolvedUrl("forms.html#email_title") + verify(webEngineView.waitForLoadSucceeded()) + keyPress(Qt.Key_Enter) + showSpy.wait() + compare(showSpy.signalArguments[2][1], "email_title") + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml b/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml index 58a49da5a..75b45bfac 100644 --- a/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml +++ b/tests/auto/quick/qmltests/data/tst_javaScriptDialogs.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.0 +import QtWebEngine 1.2 import "../mock-delegates/TestParams" 1.0 TestWebEngineView { diff --git a/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml b/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml index 230ee9635..c127d7391 100644 --- a/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml +++ b/tests/auto/quick/qmltests/data/tst_keyboardModifierMapping.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_linkHovered.qml b/tests/auto/quick/qmltests/data/tst_linkHovered.qml index c9fbd5520..31d90615b 100644 --- a/tests/auto/quick/qmltests/data/tst_linkHovered.qml +++ b/tests/auto/quick/qmltests/data/tst_linkHovered.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_loadFail.qml b/tests/auto/quick/qmltests/data/tst_loadFail.qml index 0885fc193..c2a4b6e13 100644 --- a/tests/auto/quick/qmltests/data/tst_loadFail.qml +++ b/tests/auto/quick/qmltests/data/tst_loadFail.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 import QtWebEngine.experimental 1.0 import QtWebEngine.testsupport 1.0 diff --git a/tests/auto/quick/qmltests/data/tst_loadHtml.qml b/tests/auto/quick/qmltests/data/tst_loadHtml.qml index b8acd0dd7..ee1149b16 100644 --- a/tests/auto/quick/qmltests/data/tst_loadHtml.qml +++ b/tests/auto/quick/qmltests/data/tst_loadHtml.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_loadProgress.qml b/tests/auto/quick/qmltests/data/tst_loadProgress.qml index 9f8b6f6f7..096861c4d 100644 --- a/tests/auto/quick/qmltests/data/tst_loadProgress.qml +++ b/tests/auto/quick/qmltests/data/tst_loadProgress.qml @@ -41,22 +41,39 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView width: 400 height: 300 + property var loadProgressArray: [] + + onLoadProgressChanged: { + loadProgressArray.push(webEngineView.loadProgress) + } + TestCase { name: "WebEngineViewLoadProgress" function test_loadProgress() { compare(webEngineView.loadProgress, 0) + loadProgressArray = [] + webEngineView.url = Qt.resolvedUrl("test1.html") - compare(webEngineView.loadProgress, 0) verify(webEngineView.waitForLoadSucceeded()) - compare(webEngineView.loadProgress, 100) + + // Test whether the chromium emits progress numbers in ascending order + var loadProgressMin = 0 + for (var i in loadProgressArray) { + var loadProgress = loadProgressArray[i] + verify(loadProgressMin <= loadProgress) + loadProgressMin = loadProgress + } + + // The progress must be 100% at the end + compare(loadProgressArray[loadProgressArray.length - 1], 100) } } } diff --git a/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml b/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml index 8e2e99b64..7b0bac61b 100644 --- a/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml +++ b/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml index 2400a5ed6..fb692c472 100644 --- a/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml +++ b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml @@ -41,7 +41,7 @@ import QtQuick 2.3 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 Item { width: 300 diff --git a/tests/auto/quick/qmltests/data/tst_loadUrl.qml b/tests/auto/quick/qmltests/data/tst_loadUrl.qml index 922925b48..c8abf2bb0 100644 --- a/tests/auto/quick/qmltests/data/tst_loadUrl.qml +++ b/tests/auto/quick/qmltests/data/tst_loadUrl.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 import QtWebEngine.experimental 1.0 TestWebEngineView { diff --git a/tests/auto/quick/qmltests/data/tst_navigationHistory.qml b/tests/auto/quick/qmltests/data/tst_navigationHistory.qml index 3acde3abc..f7875bb78 100644 --- a/tests/auto/quick/qmltests/data/tst_navigationHistory.qml +++ b/tests/auto/quick/qmltests/data/tst_navigationHistory.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_navigationRequested.qml b/tests/auto/quick/qmltests/data/tst_navigationRequested.qml index 72eb0aac9..7d49cda90 100644 --- a/tests/auto/quick/qmltests/data/tst_navigationRequested.qml +++ b/tests/auto/quick/qmltests/data/tst_navigationRequested.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_properties.qml b/tests/auto/quick/qmltests/data/tst_properties.qml index 738ef532d..9418252cb 100644 --- a/tests/auto/quick/qmltests/data/tst_properties.qml +++ b/tests/auto/quick/qmltests/data/tst_properties.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_runJavaScript.qml b/tests/auto/quick/qmltests/data/tst_runJavaScript.qml index 6cf3a71fb..07e7130c6 100644 --- a/tests/auto/quick/qmltests/data/tst_runJavaScript.qml +++ b/tests/auto/quick/qmltests/data/tst_runJavaScript.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_titleChanged.qml b/tests/auto/quick/qmltests/data/tst_titleChanged.qml index adc8564c0..8d9dae0a4 100644 --- a/tests/auto/quick/qmltests/data/tst_titleChanged.qml +++ b/tests/auto/quick/qmltests/data/tst_titleChanged.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 TestWebEngineView { id: webEngineView diff --git a/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml index 1c32c73a9..5fefd0fe5 100644 --- a/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml +++ b/tests/auto/quick/qmltests/data/tst_unhandledKeyEventPropagation.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 Item { id: parentItem diff --git a/tests/auto/quick/qmltests/data/tst_userScripts.qml b/tests/auto/quick/qmltests/data/tst_userScripts.qml index a9ed933d9..8a3b8207f 100644 --- a/tests/auto/quick/qmltests/data/tst_userScripts.qml +++ b/tests/auto/quick/qmltests/data/tst_userScripts.qml @@ -41,7 +41,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 Item { WebEngineScript { diff --git a/tests/auto/quick/qmltests/data/tst_webchannel.qml b/tests/auto/quick/qmltests/data/tst_webchannel.qml index dce585b67..51e37d50e 100644 --- a/tests/auto/quick/qmltests/data/tst_webchannel.qml +++ b/tests/auto/quick/qmltests/data/tst_webchannel.qml @@ -40,7 +40,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.2 import QtWebEngine.experimental 1.0 import QtWebChannel 1.0 diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/FilePicker.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/FilePicker.qml new file mode 100644 index 000000000..5ee231c19 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/FilePicker.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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.2 +import "../../TestParams" 1.0 + +QtObject { + property bool selectMultiple: false; + property bool selectExisting: false; + property bool selectFolder: false; + + signal filesSelected(var fileList); + signal rejected(); + + function open() { + FilePickerParams.filePickerOpened = true; + if (FilePickerParams.selectFiles) + filesSelected(FilePickerParams.selectedFilesUrl) + else + rejected() + } +} diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/qmldir b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/qmldir index 1ebabd335..cf8ac0512 100644 --- a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/qmldir +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/UIDelegates/qmldir @@ -1,4 +1,5 @@ module QtWebEngine.UIDelegates AlertDialog 1.0 AlertDialog.qml ConfirmDialog 1.0 ConfirmDialog.qml +FilePicker 1.0 FilePicker.qml PromptDialog 1.0 PromptDialog.qml diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml new file mode 100644 index 000000000..f0f2d9368 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company 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$ +** +****************************************************************************/ + +pragma Singleton +import QtQuick 2.0 + +QtObject { + property var selectedFilesUrl: []; + property bool selectFiles: false; + property bool filePickerOpened: false; +} diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir b/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir index f2ed87a75..a21dd8236 100644 --- a/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/qmldir @@ -1,4 +1,5 @@ # QML module so that the autotests can set testing parameters module TestParams +singleton FilePickerParams 1.0 FilePickerParams.qml singleton JSDialogParams 1.0 JSDialogParams.qml diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 68e9dc002..aac0c449c 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -12,22 +12,29 @@ OTHER_FILES += \ $$PWD/data/change-document-title.js \ $$PWD/data/download.zip \ $$PWD/data/confirm.html \ + $$PWD/data/directoryupload.html \ $$PWD/data/favicon.html \ $$PWD/data/favicon.png \ $$PWD/data/favicon2.html \ + $$PWD/data/forms.html \ $$PWD/data/javascript.html \ $$PWD/data/link.html \ $$PWD/data/prompt.html \ + $$PWD/data/multifileupload.html \ $$PWD/data/redirect.html \ + $$PWD/data/singlefileupload.html \ $$PWD/data/small-favicon.png \ $$PWD/data/test1.html \ $$PWD/data/test2.html \ $$PWD/data/test3.html \ $$PWD/data/test4.html \ $$PWD/data/keyboardModifierMapping.html \ + $$PWD/data/titleupdate.js \ $$PWD/data/tst_desktopBehaviorLoadHtml.qml \ $$PWD/data/tst_download.qml \ $$PWD/data/tst_favIconLoad.qml \ + $$PWD/data/tst_filePicker.qml \ + $$PWD/data/tst_formValidation.qml \ $$PWD/data/tst_javaScriptDialogs.qml \ $$PWD/data/tst_linkHovered.qml \ $$PWD/data/tst_loadFail.qml \ @@ -47,12 +54,13 @@ OTHER_FILES += \ $$PWD/data/tst_keyboardModifierMapping.qml \ $$PWD/mock-delegates/QtWebEngine/UIDelegates/AlertDialog.qml \ $$PWD/mock-delegates/QtWebEngine/UIDelegates/ConfirmDialog.qml \ + $$PWD/mock-delegates/QtWebEngine/UIDelegates/FilePicker.qml \ $$PWD/mock-delegates/QtWebEngine/UIDelegates/PromptDialog.qml \ $$PWD/mock-delegates/QtWebEngine/UIDelegates/qmldir \ + $$PWD/mock-delegates/TestParams/FilePickerParams.qml \ $$PWD/mock-delegates/TestParams/JSDialogParams.qml \ $$PWD/mock-delegates/TestParams/qmldir \ - load(qt_build_paths) DEFINES += QUICK_TEST_SOURCE_DIR=\\\"$$re_escape($$PWD$${QMAKE_DIR_SEP}data)\\\" diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 2cbcf0979..40dc3cb61 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -73,7 +73,7 @@ tst_QQuickWebEngineView::tst_QQuickWebEngineView() static QQmlEngine *engine = new QQmlEngine(this); m_component.reset(new QQmlComponent(engine, this)); m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n" - "import QtWebEngine 1.1\n" + "import QtWebEngine 1.2\n" "WebEngineView {}") , QUrl()); } @@ -335,12 +335,10 @@ void tst_QQuickWebEngineView::titleUpdate() webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/file_that_does_not_exist.html"))); QVERIFY(waitForLoadFailed(webEngineView())); QCOMPARE(titleSpy.size(), 0); - } void tst_QQuickWebEngineView::transparentWebEngineViews() { - showWebEngineView(); // This should not crash. @@ -348,13 +346,10 @@ void tst_QQuickWebEngineView::transparentWebEngineViews() webEngineView1->setParentItem(m_window->contentItem()); QScopedPointer<QQuickWebEngineView> webEngineView2(newWebEngineView()); webEngineView2->setParentItem(m_window->contentItem()); -#if !defined(QQUICKWEBENGINEVIEW_EXPERIMENTAL_TRANSPARENTBACKGROUND) - QWARN("QQUICKWEBENGINEVIEW_EXPERIMENTAL_TRANSPARENTBACKGROUND"); -#else - QVERIFY(!webEngineView1->experimental()->transparentBackground()); - webEngineView2->experimental()->setTransparentBackground(true); - QVERIFY(webEngineView2->experimental()->transparentBackground()); -#endif + + QVERIFY(webEngineView1->backgroundColor() != Qt::transparent); + webEngineView2->setBackgroundColor(Qt::transparent); + QVERIFY(webEngineView2->backgroundColor() == Qt::transparent); webEngineView1->setSize(QSizeF(300, 400)); webEngineView1->loadHtml("<html><body bgcolor=\"red\"></body></html>"); @@ -367,7 +362,24 @@ void tst_QQuickWebEngineView::transparentWebEngineViews() webEngineView2->setVisible(true); QTest::qWait(200); - // FIXME: test actual rendering results; https://bugs.webkit.org/show_bug.cgi?id=80609. + + // Result image: black text on red background. + QImage grabbedWindow = m_window->grabWindow(); + + QSet<int> redComponents; + for (int i = 0, width = grabbedWindow.width(); i < width; i++) { + for (int j = 0, height = grabbedWindow.height(); j < height; j++) { + QColor color(grabbedWindow.pixel(i, j)); + redComponents.insert(color.red()); + // There are no green or blue components between red and black. + QVERIFY(color.green() == 0); + QVERIFY(color.blue() == 0); + } + } + + QVERIFY(redComponents.count() > 1); + QVERIFY(redComponents.contains(0)); // black + QVERIFY(redComponents.contains(255)); // red } void tst_QQuickWebEngineView::inputMethod() diff --git a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp index 5d15537b3..e0e876fc8 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp +++ b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp @@ -184,7 +184,7 @@ void tst_QQuickWebEngineViewGraphics::reparentToOtherWindow() void tst_QQuickWebEngineViewGraphics::setHtml(const QString &html) { QString htmlData = QUrl::toPercentEncoding(html); - QString qmlData = QUrl::toPercentEncoding(QStringLiteral("import QtQuick 2.0; import QtWebEngine 1.1; WebEngineView { width: 150; height: 150; url: loadUrl }")); + QString qmlData = QUrl::toPercentEncoding(QStringLiteral("import QtQuick 2.0; import QtWebEngine 1.2; WebEngineView { width: 150; height: 150; url: loadUrl }")); m_view->rootContext()->setContextProperty("loadUrl", QUrl(QStringLiteral("data:text/html,%1").arg(htmlData))); m_view->setSource(QUrl(QStringLiteral("data:text/plain,%1").arg(qmlData))); m_view->create(); diff --git a/tests/quicktestbrowser/BrowserWindow.qml b/tests/quicktestbrowser/BrowserWindow.qml index f93a6ccd1..9f15d188e 100644 --- a/tests/quicktestbrowser/BrowserWindow.qml +++ b/tests/quicktestbrowser/BrowserWindow.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.1 -import QtWebEngine 1.1 +import QtWebEngine 1.2 import QtWebEngine.experimental 1.0 import QtQuick.Controls 1.0 @@ -76,6 +76,7 @@ ApplicationWindow { property alias autoLoadImages: loadImages.checked; property alias javaScriptEnabled: javaScriptEnabled.checked; property alias errorPageEnabled: errorPageEnabled.checked; + property alias pluginsEnabled: pluginsEnabled.checked; } // Make sure the Qt.WindowFullscreenButtonHint is set on OS X. @@ -245,6 +246,12 @@ ApplicationWindow { checked: true } MenuItem { + id: pluginsEnabled + text: "Plugins On" + checkable: true + checked: true + } + MenuItem { id: offTheRecordEnabled text: "Off The Record" checkable: true @@ -347,6 +354,7 @@ ApplicationWindow { settings.autoLoadImages: appSettings.autoLoadImages settings.javascriptEnabled: appSettings.javaScriptEnabled settings.errorPageEnabled: appSettings.errorPageEnabled + settings.pluginsEnabled: appSettings.pluginsEnabled onCertificateError: { if (!acceptedCertificates.shouldAutoAccept(error)){ diff --git a/tools/buildscripts/gyp_qtwebengine b/tools/buildscripts/gyp_qtwebengine index 970cce54e..116f8f2bd 100755 --- a/tools/buildscripts/gyp_qtwebengine +++ b/tools/buildscripts/gyp_qtwebengine @@ -140,6 +140,8 @@ if __name__ == '__main__': args.extend(['-D', 'linux_use_bundled_binutils=0']) args.extend(['-D', 'linux_use_gold_flags=0']) args.extend(['-D', 'clang_use_chrome_plugins=0']) + # We do not want to ship more external binary blobs, so let v8 embed its startup data. + args.extend(['-D', 'v8_use_external_startup_data=0']) # Trigger Qt-specific build conditions. args.extend(['-D', 'use_qt=1']) # Tweak the output location and format (hardcode ninja for now if not set) diff --git a/tools/qmake/config.tests/snappy/snappy.cpp b/tools/qmake/config.tests/snappy/snappy.cpp new file mode 100644 index 000000000..7948303fc --- /dev/null +++ b/tools/qmake/config.tests/snappy/snappy.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 <snappy.h> + +int main(int, char **) +{ + snappy::Source* src = 0; + snappy::Sink* sink = 0; + return 0; +} diff --git a/tools/qmake/config.tests/snappy/snappy.pro b/tools/qmake/config.tests/snappy/snappy.pro new file mode 100644 index 000000000..890174a13 --- /dev/null +++ b/tools/qmake/config.tests/snappy/snappy.pro @@ -0,0 +1,3 @@ +linux:SOURCES += snappy.cpp +LIBS += -lsnappy +CONFIG -= qt diff --git a/tools/qmake/config.tests/srtp/srtp.cpp b/tools/qmake/config.tests/srtp/srtp.cpp new file mode 100644 index 000000000..12400f126 --- /dev/null +++ b/tools/qmake/config.tests/srtp/srtp.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 <srtp/srtp.h> + +int main(int, char **) +{ + err_status_t status = srtp_init(); + return status == err_status_ok; +} diff --git a/tools/qmake/config.tests/srtp/srtp.pro b/tools/qmake/config.tests/srtp/srtp.pro new file mode 100644 index 000000000..2151d64aa --- /dev/null +++ b/tools/qmake/config.tests/srtp/srtp.pro @@ -0,0 +1,3 @@ +linux:SOURCES += srtp.cpp +LIBS += -lsrtp +CONFIG -= qt diff --git a/tools/qmake/mkspecs/features/configure.prf b/tools/qmake/mkspecs/features/configure.prf index 7b111b78f..17bdc8ba1 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/tools/qmake/mkspecs/features/configure.prf @@ -23,10 +23,70 @@ defineTest(runConfigure) { linux:!config_libcap:skipBuild("libcap development package appears to be missing") linux:!config_khr:skipBuild("khronos development headers appear to be missing (mesa/libegl1-mesa-dev)") contains(QT_CONFIG, xcb) { - for(package, $$list("libdrm xcomposite xi xrandr")) { + for(package, $$list("libdrm xcomposite xi xrandr xscrnsaver")) { !packagesExist($$package):skipBuild("Unmet dependency: $$package") } } - isEmpty(skipBuildReason):cache(CONFIG, add, $$list(webengine_successfully_configured)) + + linux { + packagesExist(minizip, zlib): WEBENGINE_CONFIG += config_system_minizip + else: log("System zlib or minizip not found. Using Chromium's copies.$${EOL}") + packagesExist(libwebp,libwebpdemux): WEBENGINE_CONFIG += config_system_libwebp + else: log("System libwebp or libwebpdemux not found. Using Chromium's copies.$${EOL}") + packagesExist(libxml-2.0,libxslt): WEBENGINE_CONFIG += config_system_libxslt + else: log("System libxml2 or libxslt not found. Using Chromium's copies.$${EOL}") + for(package, $$list("libevent flac jsoncpp opus speex")) { + packagesExist($$package): WEBENGINE_CONFIG += config_system_$$package + else: log("System $$package not found. Using Chromium's copy.$${EOL}") + } + packagesExist("\'vpx >= 1.4\'"): WEBENGINE_CONFIG += config_system_vpx + else: log("System vpx >= 1.4 not found. Using Chromium's copy.$${EOL}") + config_srtp: WEBENGINE_CONFIG += config_system_libsrtp + else: log("System libsrtp not found. Using Chromium's copy.$${EOL}") + config_snappy: WEBENGINE_CONFIG += config_system_snappy + else: log("System snappy not found. Using Chromium's copy.$${EOL}") + } + + isEmpty(skipBuildReason): { + cache(CONFIG, add, $$list(webengine_successfully_configured)) + !isEmpty(WEBENGINE_CONFIG): cache(CONFIG, add, $$list($$WEBENGINE_CONFIG)) + } +} + +# This is called from default_post, at which point we've also parsed +# command line options +defineTest(finalizeConfigure) { + linux { + contains(WEBENGINE_CONFIG, use_system_icu) { + packagesExist("icu-uc icu-i18n") { + log("ICU............................... Using system version$${EOL}") + } else { + log("ICU............................... System ICU not found$${EOL}") + skipBuild("Unmet dependencies: icu-uc, icu-i18n") + } + } else { + log("ICU............................... Using internal copy (Default, force system ICU with WEBENGINE_CONFIG += use_system_icu)$${EOL}") + } + contains(WEBENGINE_CONFIG, use_system_ffmpeg) { + packagesExist("libavcodec libavformat libavutil") { + packagesExist("libwebp, libwebpdemux, opus, \'vpx >= 1.4\'"){ + log("FFMPEG............................ Using system version$${EOL}") + } else { + log("FFMPEG............................ Conflicting FFMPEG dependencies$${EOL}") + skipBuild("Unmet dependencies: opus, vpx, libwebp, libwebpdemux") + } + } else { + log("FFMPEG............................ System FFMPEG not found$${EOL}") + skipBuild("Unmet dependencies: libavcodec, libavformat, libavutil") + } + } else { + log("FFMPEG............................ Using internal copy (Default, force system FFMPEG with WEBENGINE_CONFIG += use_system_ffmpeg)$${EOL}") + } + } + contains(WEBENGINE_CONFIG, use_proprietary_codecs) { + log("Proprietary codecs (H264, MP3).... Enabled$${EOL}") + } else { + log("Proprietary codecs (H264, MP3).... Not enabled (Default, enable with WEBENGINE_CONFIG += use_proprietary_codecs)$${EOL}") + } } diff --git a/tools/qmake/mkspecs/features/default_post.prf b/tools/qmake/mkspecs/features/default_post.prf index d09ba05fd..64e8cb1fe 100644 --- a/tools/qmake/mkspecs/features/default_post.prf +++ b/tools/qmake/mkspecs/features/default_post.prf @@ -1,4 +1,7 @@ load(default_post) +load(functions) + +root_project_file:isPlatformSupported(): finalizeConfigure() !isEmpty(skipBuildReason) { SUBDIRS = diff --git a/tools/qmake/mkspecs/features/default_pre.prf b/tools/qmake/mkspecs/features/default_pre.prf index 2e556c2a6..6506e67ad 100644 --- a/tools/qmake/mkspecs/features/default_pre.prf +++ b/tools/qmake/mkspecs/features/default_pre.prf @@ -16,7 +16,9 @@ load(default_pre) load(functions) # Check platform support and run config tests early enough to bail -equals(_PRO_FILE_, "$$QTWEBENGINE_ROOT/qtwebengine.pro"): isPlatformSupported() { +equals(_PRO_FILE_, "$$QTWEBENGINE_ROOT/qtwebengine.pro"): CONFIG += root_project_file + +root_project_file:isPlatformSupported() { load(configure) runConfigure() } diff --git a/tools/scripts/take_snapshot.py b/tools/scripts/take_snapshot.py index bd2ec4e56..836d230e8 100755 --- a/tools/scripts/take_snapshot.py +++ b/tools/scripts/take_snapshot.py @@ -78,7 +78,7 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/android_tools') or '/tests/' in file_path or ('/test/' in file_path and - not '/webrtc/test/testsupport/' in file_path and + not '/webrtc/' in file_path and not file_path.startswith('net/test/') and not file_path.endswith('mock_chrome_application_mac.h') and not file_path.endswith('perftimer.h') and @@ -100,9 +100,9 @@ def isInChromiumBlacklist(file_path): not 'repack_locales' in file_path and not 'third_party/chromevox' in file_path and 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 'common/localized_error' in file_path and + not 'media/desktop_streams_registry.' in file_path and + not 'common/chrome_switches.' 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 @@ -113,16 +113,24 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('chromeos') or file_path.startswith('cloud_print') or (file_path.startswith('components') and + not file_path.startswith('components/device_event_log') and + not file_path.startswith('components/devtools_') and + not file_path.startswith('components/error_page') and + not file_path.startswith('components/mime_util') and + not file_path.startswith('components/printing') and + not file_path.startswith('components/resources') and + not file_path.startswith('components/scheduler') and + not file_path.startswith('components/strings') and not file_path.startswith('components/tracing') and not file_path.startswith('components/visitedlink') and - not file_path.startswith('components/error_page') and + not file_path.startswith('components/webcrypto') 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('content/shell') and + not file_path.startswith('content/shell/common')) or file_path.startswith('courgette') or (file_path.startswith('extensions') and - # Included by generated sources of ui/accessibility/ax_enums.idl not 'browser/extension_function_registry.h' in file_path and not 'browser/extension_function_histogram_value.h' in file_path) or file_path.startswith('google_update') @@ -136,19 +144,14 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('sync') or file_path.startswith('testing/android') or file_path.startswith('testing/buildbot') - or file_path.startswith('third_party/accessibility-developer-tools') - or file_path.startswith('third_party/GTM') or file_path.startswith('third_party/WebKit/LayoutTests') or file_path.startswith('third_party/WebKit/ManualTests') or file_path.startswith('third_party/WebKit/PerformanceTests') - or file_path.startswith('third_party/active_doc') - or file_path.startswith('third_party/android_crazy_linker') - or file_path.startswith('third_party/android_platform') - or file_path.startswith('third_party/android_testrunner') - or file_path.startswith('third_party/aosp') - or file_path.startswith('third_party/apache-mime4j') + or file_path.startswith('third_party/accessibility-audit') + or file_path.startswith('third_party/android_') or file_path.startswith('third_party/apache-win32') or file_path.startswith('third_party/apple_sample_code') + or file_path.startswith('third_party/ashmem') or file_path.startswith('third_party/binutils') or file_path.startswith('third_party/bison') or (file_path.startswith('third_party/cacheinvalidation') and @@ -157,26 +160,19 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/cld_2') or file_path.startswith('third_party/codesighs') or file_path.startswith('third_party/colorama') - 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+') or file_path.startswith('third_party/google_appengine_cloudstorage') or file_path.startswith('third_party/google_toolbox_for_mac') - or file_path.startswith('third_party/guava/src') - or file_path.startswith('third_party/httpcomponents-client') - or file_path.startswith('third_party/httpcomponents-core') - or file_path.startswith('third_party/hunspell') or file_path.startswith('third_party/hunspell_dictionaries') + or file_path.startswith('third_party/hunspell_new') 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') @@ -188,21 +184,20 @@ 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/polymer') and + not file_path.startswith('third_party/polymer/components-chromium/')) or file_path.startswith('third_party/pdfsqueeze') or file_path.startswith('third_party/pefile') or file_path.startswith('third_party/perl') or file_path.startswith('third_party/pdfium') or file_path.startswith('third_party/psyco_win32') - or file_path.startswith('third_party/python_26') or file_path.startswith('third_party/scons-2.0.1') - or file_path.startswith('third_party/syzygy') - or file_path.startswith('third_party/swig') - or file_path.startswith('third_party/webgl') or file_path.startswith('third_party/trace-viewer') - or file_path.startswith('third_party/xulrunner-sdk') + or file_path.startswith('third_party/undoview') + or file_path.startswith('third_party/webgl') or (file_path.startswith('tools') and not file_path.startswith('tools/clang') and + not file_path.startswith('tools/compile_test') and not file_path.startswith('tools/generate_library_loader') and not file_path.startswith('tools/generate_shim_headers') and not file_path.startswith('tools/generate_stubs') and diff --git a/tools/scripts/version_resolver.py b/tools/scripts/version_resolver.py index 419fb72d1..b223e4fef 100644 --- a/tools/scripts/version_resolver.py +++ b/tools/scripts/version_resolver.py @@ -51,8 +51,8 @@ import json import urllib2 import git_submodule as GitSubmodule -chromium_version = '40.0.2214.115' -chromium_branch = '2214' +chromium_version = '44.0.2403.91' +chromium_branch = '2403' ninja_version = 'v1.5.3' json_url = 'http://omahaproxy.appspot.com/all.json' @@ -64,6 +64,7 @@ upstream_src_dir = os.path.abspath(snapshot_src_dir + '_upstream') submodule_blacklist = [ 'third_party/WebKit/LayoutTests/w3c/csswg-test' , 'third_party/WebKit/LayoutTests/w3c/web-platform-tests' + , 'third_party/jsoncpp/source' , 'chrome/tools/test/reference_build/chrome_mac' , 'chrome/tools/test/reference_build/chrome_linux' , 'chrome/tools/test/reference_build/chrome_win' @@ -91,7 +92,7 @@ def readReleaseChannels(): return channels def readSubmodules(): - git_deps = subprocess.check_output(['git', 'show', chromium_version +':.DEPS.git']) + git_deps = subprocess.check_output(['git', 'show', chromium_version +':DEPS']) parser = GitSubmodule.DEPSParser() git_submodules = parser.parse(git_deps) |