summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-11-03 07:31:53 +0100
committerLiang Qi <liang.qi@qt.io>2017-11-03 07:31:53 +0100
commitb045cf0ab9756a67a5a1037c231199ee9bf2d074 (patch)
tree43831df602905b64552cf31a233127bed9904fc8
parent0bbaf0d5d7b2d406eda57d40370b00fb79cc0aeb (diff)
parent7f7af6290a63bdab76855da5866881c8a53f045c (diff)
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts: src/3rdparty Change-Id: Ie6b1922db2269e0e0561022162228a7c8609c9ba
-rw-r--r--configure.json8
-rw-r--r--dist/changes-5.9.272
-rw-r--r--examples/webengine/webengine.pro8
-rw-r--r--examples/webenginewidgets/simplebrowser/browser.cpp8
-rw-r--r--examples/webenginewidgets/simplebrowser/browser.h4
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.cpp19
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.h4
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc57
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.cpp5
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.h4
-rw-r--r--examples/webenginewidgets/spellchecker/spellchecker.pro3
-rw-r--r--examples/webenginewidgets/webenginewidgets.pro3
m---------src/3rdparty0
-rw-r--r--src/buildtools/gn.pro2
-rw-r--r--src/core/api/core_api.pro8
-rw-r--r--src/core/content_main_delegate_qt.cpp34
-rw-r--r--src/core/core_module.pro4
-rw-r--r--src/core/delegated_frame_node.cpp45
-rw-r--r--src/core/delegated_frame_node.h3
-rw-r--r--src/core/gn_run.pro2
-rw-r--r--src/core/render_widget_host_view_qt.cpp24
-rw-r--r--src/core/render_widget_host_view_qt.h4
-rw-r--r--src/core/surface_factory_qt.cpp30
-rw-r--r--src/core/type_conversion.h5
-rw-r--r--src/core/url_request_context_getter_qt.cpp19
-rw-r--r--src/core/url_request_context_getter_qt.h2
-rw-r--r--src/core/url_request_custom_job.cpp62
-rw-r--r--src/core/url_request_custom_job.h4
-rw-r--r--src/core/url_request_custom_job_delegate.cpp11
-rw-r--r--src/core/url_request_custom_job_delegate.h3
-rw-r--r--src/core/url_request_custom_job_proxy.cpp7
-rw-r--r--src/core/url_request_custom_job_proxy.h6
-rw-r--r--src/core/web_event_factory.cpp48
-rw-r--r--src/core/web_event_factory.h1
-rw-r--r--src/src.pro2
-rw-r--r--src/tools/qwebengine_convert_dict/main.cpp6
-rw-r--r--src/webengine/api/qquickwebenginefaviconprovider.cpp6
-rw-r--r--src/webengine/webengine.pro2
-rw-r--r--src/webenginewidgets/api/qwebengineprofile.cpp32
-rw-r--r--src/webenginewidgets/api/qwebengineprofile_p.h19
-rw-r--r--src/webenginewidgets/webenginewidgets.pro1
-rw-r--r--tests/auto/quick/quick.pro1
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp85
-rw-r--r--tests/auto/widgets/tests.pri1
-rw-r--r--tests/auto/widgets/widgets.pro8
45 files changed, 592 insertions, 90 deletions
diff --git a/configure.json b/configure.json
index ba7a84273..ecf6e1132 100644
--- a/configure.json
+++ b/configure.json
@@ -388,7 +388,7 @@
},
"system-libxml2" : {
"label": "libxml2",
- "condition": "config.unix && tests.srtp",
+ "condition": "config.unix && tests.libxml2",
"output": [ "privateFeature" ]
},
"winversion" : {
@@ -433,15 +433,15 @@
"label": "Spellchecker",
"purpose": "Provides a spellchecker.",
"section": "WebEngine",
- "output": [ "privateFeature" ]
+ "output": [ "publicFeature" ]
},
"native-spellchecker": {
"label": "Native Spellchecker",
- "purpose": "Provides a native spellchecker.",
+ "purpose": "Use the system's native spellchecking engine.",
"section": "WebEngine",
"autoDetect": false,
"condition": "config.macos && features.spellchecker",
- "output": [ "privateFeature" ]
+ "output": [ "publicFeature" ]
},
"ui-delegates": {
"label": "UI Delegates",
diff --git a/dist/changes-5.9.2 b/dist/changes-5.9.2
new file mode 100644
index 000000000..6cc9dbe37
--- /dev/null
+++ b/dist/changes-5.9.2
@@ -0,0 +1,72 @@
+Qt 5.9.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.9.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.9 series is binary compatible with the 5.8.x series.
+Applications compiled for 5.8 will continue to run with 5.9.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* General *
+****************************************************************************
+
+ - Chromium Snapshot:
+ * Security fixes from Chromium up to version 61.0.3163.79
+ Including: CVE-2017-5092, CVE-2017-5093, CVE-2017-5095, CVE-2017-5097,
+ CVE-2017-5099, CVE-2017-5102, CVE-2017-5103, CVE-2017-5107,
+ CVE-2017-5112, CVE-2017-5114, CVE-2017-5117 and CVE-2017-5118
+ * Fixed Skia to to render text correctly with FreeType 2.8.1
+ * [QTBUG-50389] Fixed assert on some flash content
+
+ - QtWebEngine:
+ * [QTBUG-57505] Handle --force-webrtc-ip-handling-policy on command-line
+ * [QTBUG-58306] Fixed handling of menu key
+ * [QTBUG-60790] Fixed dragging images to desktop
+ * [QTBUG-61354] Set referrer on download requests
+ * [QTBUG-61429] Fixed cancelling IME composition
+ * [QTBUG-61506] Stop searching when navigating away
+ * [QTBUG-61910] Fixed an issue where system proxy settings were not
+ picked up correctly
+ * [QTBUG-62112] Fixed upside-down rendering in software rendering mode
+ * [QTBUG-62112] Fixed rendering of content with preserve-3d in CSS
+ * [QTBUG-62311] Fixed hang when exiting with open combobox
+ * [QTBUG-62808] Handle --explicitly-allowed-ports on command-line
+ * [QTBUG-62898] Fixed accessing webchannels from document-creation
+ user-scripts after navigation.
+ * [QTBUG-62942] Fixed committing IME composition on touch events
+
+ - QWebEngineView:
+ * [QTBUG-61621] Fixed propagation of unhandled key press events
+
+ - WebEngineView:
+ * The callback version of printToPdf is now called with a proper
+ bytearray result instead of a PDF data in a javascript string.
+
+****************************************************************************
+* Platform Specific Changes *
+****************************************************************************
+
+ - Linux:
+ * [QTBUG-61528, QTBUG-62673] Fixed various multilib build configurations
+ * [QTBUG-61846] Fixed host builds on Arm and MIPS
+
+ - Windows:
+ * [QTBUG-60334] Fixed location of IME window
+ * [QTBUG-62146] Fixed following system font configuration
+ * [QTBUG-62200] Fixed assert on hover
+ * Allow WebGL to work with software OpenGL using the new command-line
+ argument --enable-webgl-software-rendering
+
+ - macOS:
+ * [QTBUG-60605] Use OpenGL core-profile when the main application does
diff --git a/examples/webengine/webengine.pro b/examples/webengine/webengine.pro
index 3f55888cb..b20b8f118 100644
--- a/examples/webengine/webengine.pro
+++ b/examples/webengine/webengine.pro
@@ -3,5 +3,9 @@ TEMPLATE=subdirs
SUBDIRS += \
customdialogs \
minimal \
- quicknanobrowser \
- recipebrowser
+ quicknanobrowser
+
+qtHaveModule(quickcontrols2) {
+ SUBDIRS += \
+ recipebrowser
+}
diff --git a/examples/webenginewidgets/simplebrowser/browser.cpp b/examples/webenginewidgets/simplebrowser/browser.cpp
index f5a69793f..c50974531 100644
--- a/examples/webenginewidgets/simplebrowser/browser.cpp
+++ b/examples/webenginewidgets/simplebrowser/browser.cpp
@@ -61,11 +61,15 @@ Browser::Browser()
QObject::connect(
QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
&m_downloadManagerWidget, &DownloadManagerWidget::downloadRequested);
+ QObject::connect(
+ &m_otrProfile, &QWebEngineProfile::downloadRequested,
+ &m_downloadManagerWidget, &DownloadManagerWidget::downloadRequested);
}
-BrowserWindow *Browser::createWindow()
+BrowserWindow *Browser::createWindow(bool offTheRecord)
{
- auto mainWindow = new BrowserWindow(this);
+ auto profile = offTheRecord ? &m_otrProfile : QWebEngineProfile::defaultProfile();
+ auto mainWindow = new BrowserWindow(this, profile);
m_windows.append(mainWindow);
QObject::connect(mainWindow, &QObject::destroyed, [this, mainWindow]() {
m_windows.removeOne(mainWindow);
diff --git a/examples/webenginewidgets/simplebrowser/browser.h b/examples/webenginewidgets/simplebrowser/browser.h
index 0ea30a7f5..9240cc987 100644
--- a/examples/webenginewidgets/simplebrowser/browser.h
+++ b/examples/webenginewidgets/simplebrowser/browser.h
@@ -54,6 +54,7 @@
#include "downloadmanagerwidget.h"
#include <QVector>
+#include <QWebEngineProfile>
class BrowserWindow;
@@ -64,12 +65,13 @@ public:
QVector<BrowserWindow*> windows() { return m_windows; }
- BrowserWindow *createWindow();
+ BrowserWindow *createWindow(bool offTheRecord = false);
DownloadManagerWidget &downloadManagerWidget() { return m_downloadManagerWidget; }
private:
QVector<BrowserWindow*> m_windows;
DownloadManagerWidget m_downloadManagerWidget;
+ QWebEngineProfile m_otrProfile;
};
#endif // BROWSER_H
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
index e114ae0f3..016d58afe 100644
--- a/examples/webenginewidgets/simplebrowser/browserwindow.cpp
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
@@ -67,9 +67,10 @@
#include <QVBoxLayout>
#include <QWebEngineProfile>
-BrowserWindow::BrowserWindow(Browser *browser)
+BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile)
: m_browser(browser)
- , m_tabWidget(new TabWidget(this))
+ , m_profile(profile)
+ , m_tabWidget(new TabWidget(profile, this))
, m_progressBar(new QProgressBar(this))
, m_historyBackAction(nullptr)
, m_historyForwardAction(nullptr)
@@ -141,6 +142,7 @@ QMenu *BrowserWindow::createFileMenu(TabWidget *tabWidget)
{
QMenu *fileMenu = new QMenu(tr("&File"));
fileMenu->addAction(tr("&New Window"), this, &BrowserWindow::handleNewWindowTriggered, QKeySequence::New);
+ fileMenu->addAction(tr("New &Incognito Window"), this, &BrowserWindow::handleNewIncognitoWindowTriggered);
QAction *newTabAction = new QAction(tr("New &Tab"), this);
newTabAction->setShortcuts(QKeySequence::AddTab);
@@ -403,10 +405,14 @@ void BrowserWindow::handleWebActionEnabledChanged(QWebEnginePage::WebAction acti
void BrowserWindow::handleWebViewTitleChanged(const QString &title)
{
+ QString suffix = m_profile->isOffTheRecord()
+ ? tr("Qt Simple Browser (Incognito)")
+ : tr("Qt Simple Browser");
+
if (title.isEmpty())
- setWindowTitle(tr("Qt Simple Browser"));
+ setWindowTitle(suffix);
else
- setWindowTitle(tr("%1 - Qt Simple Browser").arg(title));
+ setWindowTitle(title + " - " + suffix);
}
void BrowserWindow::handleNewWindowTriggered()
@@ -414,6 +420,11 @@ void BrowserWindow::handleNewWindowTriggered()
m_browser->createWindow();
}
+void BrowserWindow::handleNewIncognitoWindowTriggered()
+{
+ m_browser->createWindow(/* offTheRecord: */ true);
+}
+
void BrowserWindow::handleFileOpenTriggered()
{
QUrl url = QFileDialog::getOpenFileUrl(this, tr("Open Web Resource"), QString(),
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.h b/examples/webenginewidgets/simplebrowser/browserwindow.h
index 36f00605c..b522a6b9d 100644
--- a/examples/webenginewidgets/simplebrowser/browserwindow.h
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.h
@@ -69,7 +69,7 @@ class BrowserWindow : public QMainWindow
Q_OBJECT
public:
- BrowserWindow(Browser *browser);
+ BrowserWindow(Browser *browser, QWebEngineProfile *profile);
QSize sizeHint() const override;
TabWidget *tabWidget() const;
WebView *currentTab() const;
@@ -80,6 +80,7 @@ protected:
private slots:
void handleNewWindowTriggered();
+ void handleNewIncognitoWindowTriggered();
void handleFileOpenTriggered();
void handleFindActionTriggered();
void handleShowWindowTriggered();
@@ -97,6 +98,7 @@ private:
private:
Browser *m_browser;
+ QWebEngineProfile *m_profile;
TabWidget *m_tabWidget;
QProgressBar *m_progressBar;
QAction *m_historyBackAction;
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
index 741ad864d..4f44d9f6c 100644
--- a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
@@ -202,9 +202,6 @@
\section1 Implementing WebPage Functionality
- As mentioned earlier, each \c WebView contains a \c WebPage instance that
- was created by using QWebEngineProfile::defaultProfile().
-
We implement \c WebPage as a subclass of QWebEnginePage to enable HTTP,
proxy authentication, and ignoring SSL certificate errors when accessing web
pages:
@@ -242,8 +239,16 @@
over to \c TabWidget::setUrl:
\quotefromfile webenginewidgets/simplebrowser/browserwindow.cpp
+ \skipto BrowserWindow::BrowserWindow
+ \printline BrowserWindow::BrowserWindow
+ \skipto /^\{/
+ \printline /^\{/
+ \dots
\skipto connect(m_urlLineEdit
- \printline connect
+ \printuntil });
+ \dots
+ \skipto /^\}/
+ \printline /^\}/
The call is forwarded to the currently selected tab:
@@ -255,6 +260,50 @@
The \c setUrl() method of \c WebView just forwards the \c url to the associated \c WebPage,
which in turn starts the downloading of the page's content in the background.
+ \section1 Implementing Private Browsing
+
+ \e{Private browsing}, \e{incognito mode}, or \e{off-the-record mode} is a
+ feature of many browsers where normally persistent data, such as cookies,
+ the HTTP cache, or browsing history, is kept only in memory, leaving no
+ trace on disk. In this example we will implement private browsing on the
+ window level with tabs in one window all in either normal or private mode.
+ Alternatively we could implement private browsing on the tab-level, with
+ some tabs in a window in normal mode, others in private mode.
+
+ Implementing private browsing is quite easy using Qt WebEngine. All one has
+ to do is to create a new \l{QWebEngineProfile} and use it in the
+ \l{QWebEnginePage} instead of the default profile. In the example this new
+ profile is created and owned by the \c Browser object:
+
+ \quotefromfile webenginewidgets/simplebrowser/browser.h
+ \skipto /^class Browser$/
+ \printuntil public:
+ \dots
+ \skipto createWindow
+ \printline createWindow
+ \skipto private:
+ \printline private:
+ \dots
+ \skipto m_otrProfile
+ \printline m_otrProfile
+ \printline /^\};$/
+
+ The default constructor for \l{QWebEngineProfile} already puts it in
+ \e{off-the-record} mode. All that is left to do is to pass the appropriate
+ profile down to the appropriate \l QWebEnginePage objects. The \c Browser
+ object will hand to each new \c BrowserWindow either the global default
+ profile (see \l{QWebEngineProfile::defaultProfile}) or its own
+ off-the-record profile:
+
+ \quotefromfile webenginewidgets/simplebrowser/browser.cpp
+ \skipto Browser::createWindow
+ \printuntil mainWindow = new BrowserWindow
+ \skipto return mainWindow
+ \printuntil /^\}/
+
+ The \c BrowserWindow and \c TabWidget objects will then ensure that all \l
+ QWebEnginePage objects contained in a window will use this profile.
+
\section1 Managing Downloads
Downloads are associated with a \l QWebEngineProfile. Whenever a download is
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
index c3a90bce7..e7376c7a5 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
@@ -55,8 +55,9 @@
#include <QTabBar>
#include <QWebEngineProfile>
-TabWidget::TabWidget(QWidget *parent)
+TabWidget::TabWidget(QWebEngineProfile *profile, QWidget *parent)
: QTabWidget(parent)
+ , m_profile(profile)
{
QTabBar *tabBar = this->tabBar();
tabBar->setTabsClosable(true);
@@ -201,7 +202,7 @@ WebView *TabWidget::createTab()
WebView *TabWidget::createBackgroundTab()
{
WebView *webView = new WebView;
- WebPage *webPage = new WebPage(QWebEngineProfile::defaultProfile(), webView);
+ WebPage *webPage = new WebPage(m_profile, webView);
webView->setPage(webPage);
setupView(webView);
int index = addTab(webView, tr("(Untitled)"));
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.h b/examples/webenginewidgets/simplebrowser/tabwidget.h
index f33ecf897..5b09f2708 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.h
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.h
@@ -65,7 +65,7 @@ class TabWidget : public QTabWidget
Q_OBJECT
public:
- TabWidget(QWidget *parent = nullptr);
+ TabWidget(QWebEngineProfile *profile, QWidget *parent = nullptr);
WebView *currentWebView() const;
@@ -100,6 +100,8 @@ private slots:
private:
WebView *webView(int index) const;
void setupView(WebView *webView);
+
+ QWebEngineProfile *m_profile;
};
#endif // TABWIDGET_H
diff --git a/examples/webenginewidgets/spellchecker/spellchecker.pro b/examples/webenginewidgets/spellchecker/spellchecker.pro
index 4c7ad2c36..a5f59974a 100644
--- a/examples/webenginewidgets/spellchecker/spellchecker.pro
+++ b/examples/webenginewidgets/spellchecker/spellchecker.pro
@@ -1,5 +1,4 @@
-include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine
TEMPLATE = app
TARGET = spellchecker
diff --git a/examples/webenginewidgets/webenginewidgets.pro b/examples/webenginewidgets/webenginewidgets.pro
index 63deb5854..8e91c530b 100644
--- a/examples/webenginewidgets/webenginewidgets.pro
+++ b/examples/webenginewidgets/webenginewidgets.pro
@@ -1,5 +1,4 @@
-include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine
TEMPLATE=subdirs
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 04cd5620124dc05c019a582363a93a78665b181
+Subproject 0c43a097b39603be90162b519927a7e47f15ae9
diff --git a/src/buildtools/gn.pro b/src/buildtools/gn.pro
index 02d3df652..9d9af9eb8 100644
--- a/src/buildtools/gn.pro
+++ b/src/buildtools/gn.pro
@@ -4,7 +4,7 @@ option(host_build)
!debug_and_release: CONFIG += release
include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine webengine-private
build_pass|!debug_and_release {
!qtConfig(system-gn): CONFIG(release, debug|release) {
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro
index 05166536e..270595378 100644
--- a/src/core/api/core_api.pro
+++ b/src/core/api/core_api.pro
@@ -55,3 +55,11 @@ unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static {
SOURCES += qtbug-60565.cpp \
qtbug-61521.cpp
}
+
+msvc {
+ # Create a list of object files that can be used as response file for the linker.
+ # This is done to simulate -whole-archive on MSVC.
+ QMAKE_POST_LINK = \
+ "if exist $(DESTDIR_TARGET).objects del $(DESTDIR_TARGET).objects$$escape_expand(\\n\\t)" \
+ "for %%a in ($(OBJECTS)) do echo $$shell_quote($$shell_path($$OUT_PWD))\\%%a >> $(DESTDIR_TARGET).objects"
+}
diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp
index 720db77bf..359e0b3d9 100644
--- a/src/core/content_main_delegate_qt.cpp
+++ b/src/core/content_main_delegate_qt.cpp
@@ -40,19 +40,23 @@
#include "content_main_delegate_qt.h"
#include "base/command_line.h"
+#include <base/i18n/rtl.h>
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
+#include <chrome/grit/generated_resources.h>
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/resource/resource_bundle.h"
+#include <ui/base/webui/jstemplate_builder.h>
#include "net/grit/net_resources.h"
#include "net/base/net_module.h"
#include "content_client_qt.h"
#include "renderer/content_renderer_client_qt.h"
+#include "type_conversion.h"
#include "web_engine_library_info.h"
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
@@ -63,12 +67,38 @@
#include "ui/base/ui_base_switches.h"
#endif
+#include <QtCore/qcoreapplication.h>
+
namespace QtWebEngineCore {
+// The logic of this function is based on chrome/common/net/net_resource_provider.cc
+// 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.Chromium file.
+static std::string constructDirHeaderHTML()
+{
+ base::DictionaryValue dict;
+ dict.SetString("header", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_HEADER));
+ dict.SetString("parentDirText", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_PARENT));
+ dict.SetString("headerName", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_NAME));
+ dict.SetString("headerSize", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_SIZE));
+ dict.SetString("headerDateModified",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_DATE_MODIFIED));
+ dict.SetString("language", l10n_util::GetLanguage(base::i18n::GetConfiguredLocale()));
+ dict.SetString("listingParsingErrorBoxText",
+ l10n_util::GetStringFUTF16(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT,
+ toString16(QCoreApplication::applicationName())));
+ dict.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
+ std::string html = webui::GetI18nTemplateHtml(
+ ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML),
+ &dict);
+ return html;
+}
+
static base::StringPiece PlatformResourceProvider(int key) {
if (key == IDR_DIR_HEADER_HTML) {
- base::StringPiece html_data = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML);
- return html_data;
+ static std::string html_data = constructDirHeaderHTML();
+ return base::StringPiece(html_data);
}
return base::StringPiece();
}
diff --git a/src/core/core_module.pro b/src/core/core_module.pro
index 55b20cda2..78bb8baee 100644
--- a/src/core/core_module.pro
+++ b/src/core/core_module.pro
@@ -61,7 +61,9 @@ osx {
QMAKE_LFLAGS_DEBUG -= /DEBUG
QMAKE_LFLAGS_DEBUG += /DEBUG:FASTLINK
}
- QMAKE_LFLAGS += /WHOLEARCHIVE:$${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib
+ # Simulate -whole-archive by passing the list of object files that belong to the public
+ # API library as response file to the linker.
+ QMAKE_LFLAGS += @$${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib.objects
} else {
LIBS_PRIVATE += -Wl,-whole-archive -l$$api_library_name -Wl,-no-whole-archive
}
diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp
index d0d840ecb..d6ee87950 100644
--- a/src/core/delegated_frame_node.cpp
+++ b/src/core/delegated_frame_node.cpp
@@ -849,8 +849,8 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
// countering the scale of devicePixel-scaled tiles when rendering them
// to the final surface.
QMatrix4x4 matrix;
- matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio,
- 1 / m_chromiumCompositorData->frameDevicePixelRatio);
+ const float devicePixelRatio = m_chromiumCompositorData->frameDevicePixelRatio;
+ matrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
if (QSGTransformNode::matrix() != matrix)
setMatrix(matrix);
@@ -872,11 +872,19 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
frameData->resource_list.clear();
QScopedPointer<DelegatedNodeTreeHandler> nodeHandler;
+ const QSizeF viewportSizeInPt = apiDelegate->screenRect().size();
+ const QSize viewportSize = (viewportSizeInPt * devicePixelRatio).toSize();
+
// We first compare if the render passes from the previous frame data are structurally
// equivalent to the render passes in the current frame data. If they are, we are going
// to reuse the old nodes. Otherwise, we will delete the old nodes and build a new tree.
- cc::CompositorFrame *previousFrameData = &m_chromiumCompositorData->previousFrameData;
- const bool buildNewTree = !areRenderPassStructuresEqual(frameData, previousFrameData) || m_sceneGraphNodes.empty();
+ //
+ // Additionally, because we clip (i.e. don't build scene graph nodes for) quads outside
+ // of the visible area, we also have to rebuild the tree whenever the window is resized.
+ const bool buildNewTree =
+ !areRenderPassStructuresEqual(frameData, &m_chromiumCompositorData->previousFrameData) ||
+ m_sceneGraphNodes.empty() ||
+ viewportSize != m_previousViewportSize;
m_chromiumCompositorData->previousFrameData = cc::CompositorFrame();
SGObjects previousSGObjects;
@@ -904,10 +912,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
// All RenderPasses except the last one are rendered to an FBO.
cc::RenderPass *rootRenderPass = frameData->render_pass_list.back().get();
- QRectF screenRectQt = apiDelegate->screenRect();
- gfx::Size thisSize(int(screenRectQt.width() * m_chromiumCompositorData->frameDevicePixelRatio),
- int(screenRectQt.height() * m_chromiumCompositorData->frameDevicePixelRatio));
-
+ gfx::Rect viewportRect(toGfx(viewportSize));
for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) {
cc::RenderPass *pass = frameData->render_pass_list.at(i).get();
@@ -939,12 +944,14 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
scissorRect = pass->output_rect;
} else {
renderPassParent = this;
- scissorRect = gfx::Rect(thisSize);
+ scissorRect = viewportRect;
scissorRect += rootRenderPass->output_rect.OffsetFromOrigin();
}
- if (scissorRect.IsEmpty())
+ if (scissorRect.IsEmpty()) {
+ holdResources(pass, resourceCandidates);
continue;
+ }
QSGNode *renderPassChain = nullptr;
if (buildNewTree)
@@ -967,8 +974,10 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
if (quadState->is_clipped)
targetRect.Intersect(quadState->clip_rect);
targetRect.Intersect(scissorRect);
- if (targetRect.IsEmpty())
+ if (targetRect.IsEmpty()) {
+ holdResources(quad, resourceCandidates);
continue;
+ }
if (quadState->sorting_context_id != currentSortingContextId) {
flushPolygons(&polygonQueue, renderPassChain,
@@ -1007,6 +1016,8 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
ResourceHolderIterator end = resourceCandidates.constEnd();
for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it)
resourcesToRelease->push_back((*it)->returnResource());
+
+ m_previousViewportSize = viewportSize;
}
void DelegatedFrameNode::flushPolygons(
@@ -1224,6 +1235,18 @@ ResourceHolder *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, QHa
return resource.data();
}
+void DelegatedFrameNode::holdResources(const cc::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates)
+{
+ for (auto resource : quad->resources)
+ findAndHoldResource(resource, candidates);
+}
+
+void DelegatedFrameNode::holdResources(const cc::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates)
+{
+ for (const auto &quad : pass->quad_list)
+ holdResources(quad, candidates);
+}
+
QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate)
{
// QSGTextures must be destroyed in the scene graph thread as part of the QSGNode tree,
diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h
index b83f4682a..c627cdf95 100644
--- a/src/core/delegated_frame_node.h
+++ b/src/core/delegated_frame_node.h
@@ -126,6 +126,8 @@ private:
static void fenceAndUnlockQt(DelegatedFrameNode *frameNode);
ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates);
+ void holdResources(const cc::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates);
+ void holdResources(const cc::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates);
QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0);
QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData;
@@ -143,6 +145,7 @@ private:
bool m_contextShared;
QScopedPointer<QOffscreenSurface> m_offsurface;
#endif
+ QSize m_previousViewportSize;
};
} // namespace QtWebEngineCore
diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro
index c565b99a4..a9089c569 100644
--- a/src/core/gn_run.pro
+++ b/src/core/gn_run.pro
@@ -1,5 +1,5 @@
include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine webengine-private
TEMPLATE = aux
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 7ce71a81d..a12dea6ad 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -282,6 +282,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget
, m_cursorPositionWithinSelection(-1)
, m_cursorPosition(0)
, m_emptyPreviousSelection(true)
+ , m_wheelAckPending(false)
{
m_host->SetView(this);
#ifndef QT_NO_ACCESSIBILITY
@@ -1315,7 +1316,28 @@ void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active)
void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev)
{
- m_host->ForwardWheelEvent(WebEventFactory::toWebWheelEvent(ev, dpiScale()));
+ if (!m_wheelAckPending) {
+ Q_ASSERT(m_pendingWheelEvents.isEmpty());
+ m_wheelAckPending = true;
+ m_host->ForwardWheelEvent(WebEventFactory::toWebWheelEvent(ev, dpiScale()));
+ return;
+ }
+ if (!m_pendingWheelEvents.isEmpty()) {
+ // Try to combine with this wheel event with the last pending one.
+ if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev, dpiScale()))
+ return;
+ }
+ m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev, dpiScale()));
+}
+
+void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &/*event*/, content::InputEventAckState /*ack_result*/)
+{
+ m_wheelAckPending = false;
+ if (!m_pendingWheelEvents.isEmpty()) {
+ m_wheelAckPending = true;
+ m_host->ForwardWheelEvent(m_pendingWheelEvents.takeFirst());
+ }
+ // TODO: We could forward unhandled wheelevents to our parent.
}
void RenderWidgetHostViewQt::clearPreviousTouchMotionState()
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index 74f14d0d4..c896cf058 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -153,6 +153,7 @@ public:
bool HasAcceleratedSurface(const gfx::Size&) override;
void DidCreateNewRendererCompositorFrameSink(cc::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) override;
void SubmitCompositorFrame(const viz::LocalSurfaceId&, cc::CompositorFrame) override;
+ void WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState ack_result) override;
void GetScreenInfo(content::ScreenInfo* results);
gfx::Rect GetBoundsInRootWindow() override;
@@ -274,6 +275,9 @@ private:
QString m_surroundingText;
bool m_imeHasHiddenTextCapability;
+
+ bool m_wheelAckPending;
+ QList<blink::WebMouseWheelEvent> m_pendingWheelEvents;
};
} // namespace QtWebEngineCore
diff --git a/src/core/surface_factory_qt.cpp b/src/core/surface_factory_qt.cpp
index d0741506a..c976e8b04 100644
--- a/src/core/surface_factory_qt.cpp
+++ b/src/core/surface_factory_qt.cpp
@@ -56,7 +56,13 @@
#if defined(USE_OZONE)
#include <EGL/egl.h>
-#include <dlfcn.h>
+
+#ifndef QT_LIBDIR_EGL
+#define QT_LIBDIR_EGL "/usr/lib"
+#endif
+#ifndef QT_LIBDIR_GLES2
+#define QT_LIBDIR_GLES2 QT_LIBDIR_EGL
+#endif
namespace QtWebEngineCore {
@@ -92,21 +98,29 @@ base::NativeLibrary LoadLibrary(const base::FilePath& filename) {
bool GLOzoneQt::LoadGLES2Bindings(gl::GLImplementation /*implementation*/)
{
- base::NativeLibrary eglgles2Library = dlopen(NULL, RTLD_LAZY);
- if (!eglgles2Library) {
- LOG(ERROR) << "Failed to open EGL/GLES2 context " << dlerror();
+ base::FilePath libEGLPath = QtWebEngineCore::toFilePath(QT_LIBDIR_EGL);
+ libEGLPath = libEGLPath.Append("libEGL.so.1");
+ base::NativeLibrary eglLibrary = LoadLibrary(libEGLPath);
+ if (!eglLibrary)
+ return false;
+
+ base::FilePath libGLES2Path = QtWebEngineCore::toFilePath(QT_LIBDIR_GLES2);
+ libGLES2Path = libGLES2Path.Append("libGLESv2.so.2");
+ base::NativeLibrary gles2Library = LoadLibrary(libGLES2Path);
+ if (!gles2Library)
return false;
- }
- gl::GLGetProcAddressProc get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(base::GetFunctionPointerFromNativeLibrary(eglgles2Library, "eglGetProcAddress"));
+ gl::GLGetProcAddressProc get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(base::GetFunctionPointerFromNativeLibrary(eglLibrary, "eglGetProcAddress"));
if (!get_proc_address) {
LOG(ERROR) << "eglGetProcAddress not found.";
- base::UnloadNativeLibrary(eglgles2Library);
+ base::UnloadNativeLibrary(eglLibrary);
+ base::UnloadNativeLibrary(gles2Library);
return false;
}
gl::SetGLGetProcAddressProc(get_proc_address);
- gl::AddGLNativeLibrary(eglgles2Library);
+ gl::AddGLNativeLibrary(eglLibrary);
+ gl::AddGLNativeLibrary(gles2Library);
return true;
}
diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h
index d9ba735bd..eb7c9d48b 100644
--- a/src/core/type_conversion.h
+++ b/src/core/type_conversion.h
@@ -142,6 +142,11 @@ inline QRectF toQt(const gfx::RectF &rect)
return QRectF(rect.x(), rect.y(), rect.width(), rect.height());
}
+inline gfx::Size toGfx(const QSize &size)
+{
+ return gfx::Size(size.width(), size.height());
+}
+
inline QSize toQt(const gfx::Size &size)
{
return QSize(size.width(), size.height());
diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp
index 4f30881c8..b77cd50f9 100644
--- a/src/core/url_request_context_getter_qt.cpp
+++ b/src/core/url_request_context_getter_qt.cpp
@@ -59,6 +59,8 @@
#include "net/dns/mapped_host_resolver.h"
#include "net/extras/sqlite/sqlite_channel_id_store.h"
#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_auth_preferences.h"
+#include "net/http/http_auth_scheme.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties_impl.h"
@@ -209,6 +211,13 @@ void URLRequestContextGetterQt::generateAllStorage()
m_updateAllStorage = false;
}
+static const char* const kDefaultAuthSchemes[] = { net::kBasicAuthScheme,
+ net::kDigestAuthScheme,
+#if defined(USE_KERBEROS) && !defined(OS_ANDROID)
+ net::kNegotiateAuthScheme,
+#endif
+ net::kNtlmAuthScheme };
+
void URLRequestContextGetterQt::generateStorage()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
@@ -251,7 +260,15 @@ void URLRequestContextGetterQt::generateStorage()
m_storage->set_ssl_config_service(new net::SSLConfigServiceDefaults);
m_storage->set_transport_security_state(std::unique_ptr<net::TransportSecurityState>(new net::TransportSecurityState()));
- m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
+ if (!m_httpAuthPreferences) {
+ std::vector<std::string> auth_types(std::begin(kDefaultAuthSchemes), std::end(kDefaultAuthSchemes));
+ m_httpAuthPreferences.reset(new net::HttpAuthPreferences(auth_types
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+ , std::string() /* gssapi library name */
+#endif
+ ));
+ }
+ m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerRegistryFactory::Create(m_httpAuthPreferences.get(), host_resolver.get()));
m_storage->set_http_server_properties(std::unique_ptr<net::HttpServerProperties>(new net::HttpServerPropertiesImpl));
// Give |m_storage| ownership at the end in case it's |mapped_host_resolver|.
diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h
index 511d9eb04..495c9eb28 100644
--- a/src/core/url_request_context_getter_qt.h
+++ b/src/core/url_request_context_getter_qt.h
@@ -62,6 +62,7 @@
#include <QtCore/qsharedpointer.h>
namespace net {
+class HttpAuthPreferences;
class MappedHostResolver;
class ProxyConfigService;
}
@@ -126,6 +127,7 @@ private:
scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate;
content::URLRequestInterceptorScopedVector m_requestInterceptors;
std::unique_ptr<net::HttpNetworkSession> m_httpNetworkSession;
+ std::unique_ptr<net::HttpAuthPreferences> m_httpAuthPreferences;
QList<QByteArray> m_installedCustomSchemes;
QWebEngineUrlRequestInterceptor* m_requestInterceptor;
diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp
index 47c9b3b4c..b49135f79 100644
--- a/src/core/url_request_custom_job.cpp
+++ b/src/core/url_request_custom_job.cpp
@@ -56,6 +56,9 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request,
, m_proxy(new URLRequestCustomJobProxy(this, scheme, adapter))
, m_device(nullptr)
, m_error(0)
+ , m_pendingReadSize(0)
+ , m_pendingReadPos(0)
+ , m_pendingReadBuffer(nullptr)
{
}
@@ -83,6 +86,12 @@ void URLRequestCustomJob::Kill()
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (m_device && m_device->isOpen())
m_device->close();
+ if (m_pendingReadBuffer) {
+ m_pendingReadBuffer->Release();
+ m_pendingReadBuffer = nullptr;
+ m_pendingReadSize = 0;
+ m_pendingReadPos = 0;
+ }
m_device = nullptr;
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&URLRequestCustomJobProxy::release,
@@ -127,13 +136,64 @@ int URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize)
if (m_error)
return m_error;
qint64 rv = m_device ? m_device->read(buf->data(), bufSize) : -1;
- if (rv >= 0) {
+ if (rv > 0) {
return static_cast<int>(rv);
+ } else if (rv == 0) {
+ // Returning zero is interpreted as EOF by Chromium, so only
+ // return zero if we are the end of the file.
+ if (m_device->atEnd())
+ return 0;
+ // Otherwise return IO_PENDING and call ReadRawDataComplete when we have data
+ // for them.
+ buf->AddRef();
+ m_pendingReadPos = 0;
+ m_pendingReadSize = bufSize;
+ m_pendingReadBuffer = buf;
+ return ERR_IO_PENDING;
} else {
// QIODevice::read might have called fail on us.
if (m_error)
return m_error;
+ if (m_device && m_device->atEnd())
+ return 0;
return ERR_FAILED;
}
}
+
+void URLRequestCustomJob::notifyReadyRead()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (!m_device)
+ return;
+ if (!m_pendingReadSize)
+ return;
+ Q_ASSERT(m_pendingReadBuffer);
+ if (!m_pendingReadBuffer)
+ return;
+
+ qint64 rv = m_device->read(m_pendingReadBuffer->data() + m_pendingReadPos, m_pendingReadSize - m_pendingReadPos);
+ if (rv == 0)
+ return;
+ if (rv < 0) {
+ if (m_error)
+ rv = m_error;
+ else if (m_device->atEnd())
+ rv = 0;
+ else
+ rv = ERR_FAILED;
+ } else {
+ m_pendingReadPos += rv;
+ if (m_pendingReadPos < m_pendingReadSize && !m_device->atEnd())
+ return;
+ rv = m_pendingReadPos;
+ }
+ // killJob may be called from ReadRawDataComplete
+ net::IOBuffer *buf = m_pendingReadBuffer;
+ m_pendingReadBuffer = nullptr;
+ m_pendingReadSize = 0;
+ m_pendingReadPos = 0;
+ ReadRawDataComplete(rv);
+ buf->Release();
+}
+
} // namespace
diff --git a/src/core/url_request_custom_job.h b/src/core/url_request_custom_job.h
index 68a834d48..021cf3204 100644
--- a/src/core/url_request_custom_job.h
+++ b/src/core/url_request_custom_job.h
@@ -70,12 +70,16 @@ protected:
virtual ~URLRequestCustomJob();
private:
+ void notifyReadyRead();
scoped_refptr<URLRequestCustomJobProxy> m_proxy;
std::string m_mimeType;
std::string m_charset;
GURL m_redirect;
QIODevice *m_device;
int m_error;
+ int m_pendingReadSize;
+ int m_pendingReadPos;
+ net::IOBuffer *m_pendingReadBuffer;
friend class URLRequestCustomJobProxy;
diff --git a/src/core/url_request_custom_job_delegate.cpp b/src/core/url_request_custom_job_delegate.cpp
index 14de9a812..6b82cebb5 100644
--- a/src/core/url_request_custom_job_delegate.cpp
+++ b/src/core/url_request_custom_job_delegate.cpp
@@ -73,16 +73,23 @@ QByteArray URLRequestCustomJobDelegate::method() const
void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device)
{
+ if (device)
+ QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead);
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
base::Bind(&URLRequestCustomJobProxy::reply,
m_proxy,contentType.toStdString(),device));
}
+void URLRequestCustomJobDelegate::slotReadyRead()
+{
+ content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&URLRequestCustomJobProxy::readyRead, m_proxy));
+}
+
void URLRequestCustomJobDelegate::abort()
{
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
- base::Bind(&URLRequestCustomJobProxy::abort,
- m_proxy));
+ base::Bind(&URLRequestCustomJobProxy::abort, m_proxy));
}
void URLRequestCustomJobDelegate::redirect(const QUrl &url)
diff --git a/src/core/url_request_custom_job_delegate.h b/src/core/url_request_custom_job_delegate.h
index eb99f3576..3f5e6d591 100644
--- a/src/core/url_request_custom_job_delegate.h
+++ b/src/core/url_request_custom_job_delegate.h
@@ -74,6 +74,9 @@ public:
void abort();
void fail(Error);
+private Q_SLOTS:
+ void slotReadyRead();
+
private:
URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy,
const QUrl &url,
diff --git a/src/core/url_request_custom_job_proxy.cpp b/src/core/url_request_custom_job_proxy.cpp
index d53602c85..832d3d11e 100644
--- a/src/core/url_request_custom_job_proxy.cpp
+++ b/src/core/url_request_custom_job_proxy.cpp
@@ -144,6 +144,13 @@ void URLRequestCustomJobProxy::fail(int error)
// else we fail on the next read, or the read that might already be in progress
}
+void URLRequestCustomJobProxy::readyRead()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (m_job)
+ m_job->notifyReadyRead();
+}
+
void URLRequestCustomJobProxy::initialize(GURL url, std::string method)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/src/core/url_request_custom_job_proxy.h b/src/core/url_request_custom_job_proxy.h
index df7171f5e..3ea30a4e1 100644
--- a/src/core/url_request_custom_job_proxy.h
+++ b/src/core/url_request_custom_job_proxy.h
@@ -63,6 +63,7 @@ public:
QWeakPointer<const BrowserContextAdapter> adapter);
~URLRequestCustomJobProxy();
+ // Called from URLRequestCustomJobDelegate via post:
//void setReplyCharset(const std::string &);
void reply(std::string mimeType, QIODevice *device);
void redirect(GURL url);
@@ -70,12 +71,13 @@ public:
void fail(int error);
void release();
void initialize(GURL url, std::string method);
+ void readyRead();
- //IO thread owned
+ // IO thread owned:
URLRequestCustomJob *m_job;
bool m_started;
- //UI thread owned
+ // UI thread owned:
std::string m_scheme;
URLRequestCustomJobDelegate *m_delegate;
QWeakPointer<const BrowserContextAdapter> m_adapter;
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index b785adec0..2e0323f6d 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -1289,38 +1289,56 @@ WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, doub
}
#endif
-blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale)
+static void setBlinkWheelEventDelta(blink::WebMouseWheelEvent &webEvent)
{
- WebMouseWheelEvent webEvent;
- webEvent.delta_x = 0;
- webEvent.delta_y = 0;
- webEvent.wheel_ticks_x = 0;
- webEvent.wheel_ticks_y = 0;
- webEvent.SetType(webEventTypeForEvent(ev));
- webEvent.SetModifiers(modifiersForEvent(ev));
- webEvent.SetTimeStampSeconds(currentTimeForEvent(ev));
-
- webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep;
- webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep;
-
// We can't use the device specific QWheelEvent::pixelDelta(), so we calculate
// a pixel delta based on ticks and scroll per line.
static const float cDefaultQtScrollStep = 20.f;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
- const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines();
+ static const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines();
#else
- const int wheelScrollLines = 3;
+ static const int wheelScrollLines = 3;
#endif
webEvent.delta_x = webEvent.wheel_ticks_x * wheelScrollLines * cDefaultQtScrollStep;
webEvent.delta_y = webEvent.wheel_ticks_y * wheelScrollLines * cDefaultQtScrollStep;
+}
+
+blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale)
+{
+ WebMouseWheelEvent webEvent;
+ webEvent.SetType(webEventTypeForEvent(ev));
+ webEvent.SetModifiers(modifiersForEvent(ev));
+ webEvent.SetTimeStampSeconds(currentTimeForEvent(ev));
webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale);
webEvent.SetPositionInScreen(ev->globalX(), ev->globalY());
+ webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep;
+ webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep;
+ setBlinkWheelEventDelta(webEvent);
+
return webEvent;
}
+bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev, double dpiScale)
+{
+ if (webEventTypeForEvent(ev) != webEvent.GetType())
+ return false;
+ if (modifiersForEvent(ev) != webEvent.GetModifiers())
+ return false;
+
+ webEvent.SetTimeStampSeconds(currentTimeForEvent(ev));
+ webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale);
+ webEvent.SetPositionInScreen(ev->globalX(), ev->globalY());
+
+ webEvent.wheel_ticks_x += static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep;
+ webEvent.wheel_ticks_y += static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep;
+ setBlinkWheelEventDelta(webEvent);
+
+ return true;
+}
+
content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev)
{
content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev));
diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h
index c9ae86a73..ca0f6035f 100644
--- a/src/core/web_event_factory.h
+++ b/src/core/web_event_factory.h
@@ -70,6 +70,7 @@ public:
static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale);
#endif
static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale);
+ static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale);
static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*);
};
diff --git a/src/src.pro b/src/src.pro
index 1cd23f9fa..76d342c8d 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,5 +1,5 @@
include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine webengine-private
TEMPLATE = subdirs
diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp
index e7dcc22d9..3a1a1ff64 100644
--- a/src/tools/qwebengine_convert_dict/main.cpp
+++ b/src/tools/qwebengine_convert_dict/main.cpp
@@ -30,6 +30,7 @@
#include <QTextStream>
#include <QLibraryInfo>
#include <QDir>
+#include <QCoreApplication>
// see also src/core/type_conversion.h
inline base::FilePath::StringType toFilePathString(const QString &str)
@@ -117,6 +118,11 @@ QString frameworkIcuDataPath()
int main(int argc, char *argv[])
{
+ // Required only for making QLibraryInfo::location() return a valid path, when the application
+ // picks up a qt.conf file (which is the case for official Qt packages).
+ QCoreApplication app(argc, argv);
+ Q_UNUSED(app);
+
QTextStream out(stdout);
if (argc != 3) {
diff --git a/src/webengine/api/qquickwebenginefaviconprovider.cpp b/src/webengine/api/qquickwebenginefaviconprovider.cpp
index b5ad6960a..3255f22be 100644
--- a/src/webengine/api/qquickwebenginefaviconprovider.cpp
+++ b/src/webengine/api/qquickwebenginefaviconprovider.cpp
@@ -70,7 +70,11 @@ QUrl QQuickWebEngineFaviconProvider::faviconProviderUrl(const QUrl &url)
QUrl providerUrl;
providerUrl.setScheme(QStringLiteral("image"));
providerUrl.setHost(identifier());
- providerUrl.setPath(QStringLiteral("/%1").arg(url.toString()));
+ providerUrl.setPath(QStringLiteral("/%1").arg(url.toString(QUrl::RemoveQuery | QUrl::RemoveFragment)));
+ if (url.hasQuery())
+ providerUrl.setQuery(url.query(QUrl::FullyDecoded));
+ if (url.hasFragment())
+ providerUrl.setFragment(url.fragment(QUrl::FullyDecoded));
return providerUrl;
}
diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro
index 4b2170cbc..24fa2d9d8 100644
--- a/src/webengine/webengine.pro
+++ b/src/webengine/webengine.pro
@@ -1,5 +1,5 @@
include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine webengine-private
TARGET = QtWebEngine
diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp
index f844ddcd6..c4de46b67 100644
--- a/src/webenginewidgets/api/qwebengineprofile.cpp
+++ b/src/webenginewidgets/api/qwebengineprofile.cpp
@@ -145,24 +145,35 @@ using QtWebEngineCore::BrowserContextAdapter;
\sa QWebEngineDownloadItem, QWebEnginePage::download()
*/
-QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter> browserContext)
+QWebEngineBrowserContext::QWebEngineBrowserContext(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext, QWebEngineProfilePrivate *profile)
+ : QObject(BrowserContextAdapter::globalQObjectRoot())
+ , browserContextRef(browserContext)
+ , m_profile(profile)
+{
+ browserContextRef->addClient(m_profile);
+}
+
+QWebEngineBrowserContext::~QWebEngineBrowserContext()
+{
+ Q_ASSERT(m_profile);
+ // In the case the user sets this profile as the parent of the interceptor
+ // it can be deleted before the browser-context still referencing it is.
+ browserContextRef->setRequestInterceptor(nullptr);
+ browserContextRef->removeClient(m_profile);
+}
+
+QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext)
: m_settings(new QWebEngineSettings())
, m_scriptCollection(new QWebEngineScriptCollection(new QWebEngineScriptCollectionPrivate(browserContext->userResourceController())))
- , m_browserContextRef(browserContext)
+ , m_browserContext(new QWebEngineBrowserContext(browserContext, this))
{
- m_browserContextRef->addClient(this);
m_settings->d_ptr->initDefaults();
}
QWebEngineProfilePrivate::~QWebEngineProfilePrivate()
{
- // In the case the user sets this profile as the parent of the interceptor
- // it can be deleted before the browser-context still referencing it is.
- m_browserContextRef->setRequestInterceptor(nullptr);
-
delete m_settings;
m_settings = 0;
- m_browserContextRef->removeClient(this);
Q_FOREACH (QWebEngineDownloadItem* download, m_ongoingDownloads) {
if (download)
@@ -172,6 +183,11 @@ QWebEngineProfilePrivate::~QWebEngineProfilePrivate()
m_ongoingDownloads.clear();
}
+QSharedPointer<QtWebEngineCore::BrowserContextAdapter> QWebEngineProfilePrivate::browserContext() const
+{
+ return m_browserContext->browserContextRef;
+}
+
void QWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId)
{
m_ongoingDownloads.remove(downloadId);
diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h
index ffb28ec6d..8cbf241f3 100644
--- a/src/webenginewidgets/api/qwebengineprofile_p.h
+++ b/src/webenginewidgets/api/qwebengineprofile_p.h
@@ -65,15 +65,30 @@ class BrowserContextAdapter;
QT_BEGIN_NAMESPACE
+class QWebEngineProfilePrivate;
class QWebEngineSettings;
+// This is a wrapper class for BrowserContextAdapter. BrowserContextAdapter must be destructed before WebEngineContext
+// is destructed. Therefore access it via the QWebEngineBrowserContext which parent is the WebEngineContext::globalQObject.
+// This guarantees the destruction together with the WebEngineContext.
+class QWebEngineBrowserContext : public QObject {
+public:
+ QWebEngineBrowserContext(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext, QWebEngineProfilePrivate *profile);
+ ~QWebEngineBrowserContext();
+
+ QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContextRef;
+
+private:
+ QWebEngineProfilePrivate *m_profile;
+};
+
class QWebEngineProfilePrivate : public QtWebEngineCore::BrowserContextAdapterClient {
public:
Q_DECLARE_PUBLIC(QWebEngineProfile)
QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext);
~QWebEngineProfilePrivate();
- QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const { return m_browserContextRef; }
+ QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const;
QWebEngineSettings *settings() const { return m_settings; }
void downloadDestroyed(quint32 downloadId);
@@ -85,7 +100,7 @@ private:
QWebEngineProfile *q_ptr;
QWebEngineSettings *m_settings;
QScopedPointer<QWebEngineScriptCollection> m_scriptCollection;
- QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef;
+ QPointer<QWebEngineBrowserContext> m_browserContext;
QMap<quint32, QPointer<QWebEngineDownloadItem> > m_ongoingDownloads;
};
diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro
index 29c961c80..958dec07b 100644
--- a/src/webenginewidgets/webenginewidgets.pro
+++ b/src/webenginewidgets/webenginewidgets.pro
@@ -1,4 +1,3 @@
-include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
QT_FOR_CONFIG += webengine-private
TARGET = QtWebEngineWidgets
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index 75217c1ec..2e6343469 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -1,4 +1,3 @@
-include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
QT_FOR_CONFIG += webengine-private
TEMPLATE = subdirs
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 093bc2e43..400105152 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -49,6 +49,7 @@ private Q_SLOTS:
void urlSchemeHandlers();
void urlSchemeHandlerFailRequest();
void urlSchemeHandlerFailOnRead();
+ void urlSchemeHandlerStreaming();
void customUserAgent();
void httpAcceptLanguage();
void downloadItem();
@@ -178,6 +179,74 @@ public:
}
};
+class StreamingIODevice : public QIODevice {
+ Q_OBJECT
+public:
+ StreamingIODevice(QObject *parent) : QIODevice(parent), m_bytesRead(0), m_bytesAvailable(0)
+ {
+ setOpenMode(QIODevice::ReadOnly);
+ m_timer.start(100, this);
+ }
+ bool isSequential() const override { return true; }
+ qint64 bytesAvailable() const override
+ { return m_bytesAvailable; }
+ bool atEnd() const override
+ {
+ return (m_data.size() >= 1000 && m_bytesRead >= 1000);
+ }
+protected:
+ void timerEvent(QTimerEvent *) override
+ {
+ QMutexLocker lock(&m_mutex);
+ m_bytesAvailable += 200;
+ m_data.append(200, 'c');
+ emit readyRead();
+ if (m_data.size() >= 1000) {
+ m_timer.stop();
+ emit readChannelFinished();
+ }
+ }
+
+ qint64 readData(char *data, qint64 maxlen) override
+ {
+ QMutexLocker lock(&m_mutex);
+ qint64 len = qMin(qint64(m_bytesAvailable), maxlen);
+ if (len) {
+ memcpy(data, m_data.constData() + m_bytesRead, len);
+ m_bytesAvailable -= len;
+ m_bytesRead += len;
+ } else if (m_data.size() > 0)
+ return -1;
+
+ return len;
+ }
+ qint64 writeData(const char *, qint64) override
+ {
+ return 0;
+ }
+
+private:
+ QMutex m_mutex;
+ QByteArray m_data;
+ QBasicTimer m_timer;
+ int m_bytesRead;
+ int m_bytesAvailable;
+};
+
+class StreamingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
+{
+public:
+ StreamingUrlSchemeHandler(QObject *parent = nullptr)
+ : QWebEngineUrlSchemeHandler(parent)
+ {
+ }
+
+ void requestStarted(QWebEngineUrlRequestJob *job)
+ {
+ job->reply("text/plain;charset=utf-8", new StreamingIODevice(job));
+ }
+};
+
static bool loadSync(QWebEngineView *view, const QUrl &url, int timeout = 5000)
{
// Ripped off QTRY_VERIFY.
@@ -310,6 +379,22 @@ void tst_QWebEngineProfile::urlSchemeHandlerFailOnRead()
QCOMPARE(toPlainTextSync(view.page()), QString());
}
+void tst_QWebEngineProfile::urlSchemeHandlerStreaming()
+{
+ StreamingUrlSchemeHandler handler;
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("stream", &handler);
+ QWebEngineView view;
+ QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
+ view.setPage(new QWebEnginePage(&profile, &view));
+ view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+ view.load(QUrl(QStringLiteral("stream://whatever")));
+ QVERIFY(loadFinishedSpy.wait());
+ QByteArray result;
+ result.append(1000, 'c');
+ QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result));
+}
+
void tst_QWebEngineProfile::customUserAgent()
{
QString defaultUserAgent = QWebEngineProfile::defaultProfile()->httpUserAgent();
diff --git a/tests/auto/widgets/tests.pri b/tests/auto/widgets/tests.pri
index dc0461e2b..7bd00834c 100644
--- a/tests/auto/widgets/tests.pri
+++ b/tests/auto/widgets/tests.pri
@@ -1,4 +1,3 @@
-include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
QT_FOR_CONFIG += webengine-private
TEMPLATE = app
diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro
index e007df711..fbabdeaad 100644
--- a/tests/auto/widgets/widgets.pro
+++ b/tests/auto/widgets/widgets.pro
@@ -1,10 +1,8 @@
-include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri)
-QT_FOR_CONFIG += webengine-private
+QT_FOR_CONFIG += webengine
TEMPLATE = subdirs
SUBDIRS += \
- qwebengineaccessibility \
qwebenginedefaultsurfaceformat \
qwebenginedownloads \
qwebenginefaviconmanager \
@@ -18,6 +16,10 @@ SUBDIRS += \
qwebenginesettings \
qwebengineview
+qtConfig(accessibility) {
+ SUBDIRS += qwebengineaccessibility
+}
+
qtConfig(spellchecker):!cross_compile {
!qtConfig(native-spellchecker) {
SUBDIRS += qwebenginespellcheck