summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.pri8
-rw-r--r--examples/webenginewidgets/notifications/data/data.qrc6
-rw-r--r--examples/webenginewidgets/notifications/data/icon.pngbin0 -> 2252 bytes
-rw-r--r--examples/webenginewidgets/notifications/data/index.html90
-rw-r--r--examples/webenginewidgets/notifications/doc/images/notifications-example.pngbin0 -> 14732 bytes
-rw-r--r--examples/webenginewidgets/notifications/doc/src/notifications.qdoc156
-rw-r--r--examples/webenginewidgets/notifications/main.cpp100
-rw-r--r--examples/webenginewidgets/notifications/notificationpopup.h132
-rw-r--r--examples/webenginewidgets/notifications/notifications.pro10
-rw-r--r--examples/webenginewidgets/webenginewidgets.pro1
-rw-r--r--mkspecs/features/functions.prf9
-rw-r--r--src/core/config/functions.pri8
-rw-r--r--src/core/config/linux.pri6
-rw-r--r--src/core/config/windows.pri8
-rw-r--r--src/core/configure.json1
-rw-r--r--src/core/core_module.pro2
-rw-r--r--src/core/net/network_delegate_qt.cpp10
-rw-r--r--src/core/net/url_request_notification.cpp13
-rw-r--r--src/core/profile_adapter.cpp42
-rw-r--r--src/core/render_widget_host_view_qt.cpp4
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h1
-rw-r--r--src/core/web_engine_context.cpp32
-rw-r--r--src/core/web_engine_settings.cpp4
-rw-r--r--src/webengine/api/qquickwebenginedownloaditem.cpp12
-rw-r--r--src/webengine/api/qquickwebengineview.cpp1
-rw-r--r--src/webengine/doc/src/webengineview_lgpl.qdoc58
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.cpp15
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.h1
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp47
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.h8
-rw-r--r--src/webenginewidgets/api/qwebenginedownloaditem.cpp11
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp36
-rw-r--r--src/webenginewidgets/doc/src/qtwebkitportingguide.qdoc9
-rw-r--r--src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc23
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp7
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h1
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro1
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp43
-rw-r--r--tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp123
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp12
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp80
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp15
42 files changed, 1048 insertions, 98 deletions
diff --git a/configure.pri b/configure.pri
index 8db31ddd3..d03d3c8e0 100644
--- a/configure.pri
+++ b/configure.pri
@@ -1,3 +1,5 @@
+include(src/core/config/functions.pri)
+
# this must be done outside any function
QTWEBENGINE_SOURCE_TREE = $$PWD
@@ -297,12 +299,12 @@ defineTest(qtConfTest_isWindowsHostCompiler64) {
# Fixme QTBUG-71772
defineTest(qtConfTest_hasThumbFlag) {
- FLAG = $$extractCFlag("-mthumb")
+ FLAG = $$qtwebengine_extractCFlag("-mthumb")
!isEmpty(FLAG): return(true)
- FLAG = $$extractCFlag("-marm")
+ FLAG = $$qtwebengine_extractCFlag("-marm")
!isEmpty(FLAG): return(false)
- MARCH = $$extractCFlag("-march=.*")
+ MARCH = $$qtwebengine_extractCFlag("-march=.*")
MARMV = $$replace(MARCH, "armv",)
!isEmpty(MARMV) {
MARMV = $$split(MARMV,)
diff --git a/examples/webenginewidgets/notifications/data/data.qrc b/examples/webenginewidgets/notifications/data/data.qrc
new file mode 100644
index 000000000..bc252b89c
--- /dev/null
+++ b/examples/webenginewidgets/notifications/data/data.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>index.html</file>
+ <file>icon.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/webenginewidgets/notifications/data/icon.png b/examples/webenginewidgets/notifications/data/icon.png
new file mode 100644
index 000000000..4c3870c06
--- /dev/null
+++ b/examples/webenginewidgets/notifications/data/icon.png
Binary files differ
diff --git a/examples/webenginewidgets/notifications/data/index.html b/examples/webenginewidgets/notifications/data/index.html
new file mode 100644
index 000000000..ebb73b573
--- /dev/null
+++ b/examples/webenginewidgets/notifications/data/index.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<html>
+<head>
+<title>Web Notifications Example</title>
+<script>
+ var notificationsCreated = 0
+
+ function getPermission() { return document.Notification }
+ function resetPermission(permission = 'default') {
+ document.Notification = permission
+ document.getElementById('state').value = getPermission()
+ }
+
+ function createNotification() {
+ let title = 'Notification #' + ++notificationsCreated
+ let options = { body: 'Visit doc.qt.io for more info!', icon: 'icon.png', }
+
+ let notification = new Notification(title, options)
+ document.notification = notification
+
+ notification.onerror = function(error) {
+ document.getElementById('act').value += ' with error'
+ document.notification = null
+ }
+ notification.onshow = function() {
+ document.getElementById('act').value += ', shown'
+ document.getElementById('close').style.display = 'inline'
+ }
+ notification.onclick = function() {
+ document.getElementById('act').value += ', clicked'
+ }
+ notification.onclose = function() {
+ if (document.notification && notification == document.notification) {
+ document.getElementById('act').value += ' and closed'
+ document.getElementById('close').style.display = 'none'
+ document.notification = null
+ }
+ }
+
+ console.log('...notification created [Title: ' + title + ']')
+ document.getElementById('act').value = 'Notification was created'
+ }
+
+ function onMakeNotification() {
+ if (getPermission() == 'granted') {
+ createNotification()
+ } else if (getPermission() == 'denied') {
+ setTimeout(function() {
+ if (window.confirm('Notifications are disabled!\n' +
+ 'Permission needs to be granted by user. Reset?'))
+ resetPermission()
+ }, 1)
+ } else {
+ Notification.requestPermission().then(function (permission) {
+ console.info('notifications request: ' + permission)
+ resetPermission(permission)
+ if (permission == 'granted')
+ createNotification()
+ })
+ }
+ }
+
+ function closeNotification() { if (document.notification) document.notification.close() }
+
+ document.addEventListener('DOMContentLoaded', function() { resetPermission(Notification.permission) })
+</script>
+</head>
+<body style='text-align:center;'>
+ <h3>Click the button to send a notification</h3>
+
+ <button onclick='onMakeNotification()'>Notify!</button>
+
+ <p>
+ <output id='act'></output>
+ <button id='close' style='display: none;' onclick='closeNotification()'>Close</button>
+ </p><br>
+
+ <p>
+ <label for='state'>Permission:</label>
+ <output id='state'></output>
+ <button onclick='resetPermission()'>Reset</button>
+ </p><br>
+
+ <h4>More info can be found on:</h4>
+ <ul style='list-style-type: none;'>
+ <li>W3 <a href='https://www.w3.org/TR/notifications'>Web Notifications</a> standard</li>
+ <li>Documentation for <a href='https://doc.qt.io'>Qt WebEngine</a> module</li>
+ </ul>
+</body>
+</html>
diff --git a/examples/webenginewidgets/notifications/doc/images/notifications-example.png b/examples/webenginewidgets/notifications/doc/images/notifications-example.png
new file mode 100644
index 000000000..671cd1703
--- /dev/null
+++ b/examples/webenginewidgets/notifications/doc/images/notifications-example.png
Binary files differ
diff --git a/examples/webenginewidgets/notifications/doc/src/notifications.qdoc b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
new file mode 100644
index 000000000..2c999e7e1
--- /dev/null
+++ b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example webenginewidgets/notifications
+ \title WebEngine Notifications Example
+ \ingroup webengine-widgetexamples
+ \brief Demonstrates how to pass HTML5 web notifications to users.
+
+ \image notifications-example.png
+
+ \e {\WebEngine Notifications} demonstrates how to use the
+ \l QWebEngineProfile::setNotificationPresenter() method and
+ \l QWebEngineNotification class to show an HTML5 web
+ notification to the user.
+
+ \include examples-run.qdocinc
+
+ \section1 HTML Page
+
+ In this example, we create an internal HTML page that is added through
+ a resource collection file (.qrc). The page displays buttons for requesting
+ permissions and creating a notification. In addition, it contains JavaScript
+ logic for triggering these actions.
+
+ \quotefromfile webenginewidgets/notifications/data/index.html
+ \skipto Notification.requestPermission
+ \printline requestPermission
+ \dots
+ \skipto if
+ \printuntil createNotification()
+ \printline /^})$/
+
+ \quotefromfile webenginewidgets/notifications/data/index.html
+ \skipto createNotification()
+ \printuntil Notification
+ \dots
+ \printline /^})$/
+
+ \section1 Main Function
+
+ In the \c main function, we instantiate a QWebEngineView, load our internal
+ HTML page, and set up the required callbacks for notifications handling.
+
+ \section2 Requesting Feature Permissions
+
+ We then use the \l QWebEnginePage::featurePermissionRequested() call to
+ request the user's permission to show notifications on their device.
+
+ \quotefromfile webenginewidgets/notifications/main.cpp
+ \skipto featurePermissionRequested
+ \printuntil });
+
+ \section2 Handling New Notifications
+
+ We then construct a \c NotificationPopup that encapsulates
+ the data of the HTML web notification. We also use the
+ \l QWebEngineProfile::setNotificationPresenter() call to set
+ our handler, which we use in conjunction with our \c popup
+ to handle all new notifications.
+
+ \skipto popup
+ \printuntil });
+
+ \section1 Presenting Notifications to Users
+
+ The \c NotificationPopup class in this example is a simple
+ QWidget-based class that uses multiple QLabel instances
+ for displaying the notification's title, message, and icon.
+
+ \quotefromfile webenginewidgets/notifications/notificationpopup.h
+ \skipto class NotificationPopup
+ \printto public:
+
+ \section2 Presenting Notifications
+
+ Inside the \c present method, we first close and release the previous
+ notification if we have one and then take ownership of a new notification
+ by calling the \c std::unique_ptr::swap method on our internal notification
+ instance.
+
+ \skipto present
+ \printto m_title
+
+ Then we query the notification instance for a title, a message,
+ and an icon by calling \l QWebEngineNotification::title(),
+ \l QWebEngineNotification::message(), \l QWebEngineNotification::icon()
+ and set up the appropriate labels in our popup.
+
+ \printuntil m_icon
+
+ After that we are ready to display our notification to the user
+ by calling the \l QWidget::show() method. On this step we also call the
+ \l QWebEngineNotification::show() method to notify \c JavaScript code
+ about our \e show event.
+
+ \printuntil notification->show
+
+ Finally, we set up a callback to handle the \e close event from the
+ \c JavaScript side by connecting to the \l QWebEngineNotification::closed()
+ signal. We also schedule a timer event to close our active notification
+ automatically.
+
+ \skipto QWebEngineNotification::closed
+ \printuntil QTimer
+ \printline /^\}/
+
+ \section2 Closing Active Notification
+
+ We execute the \e close step for the currently active notification either by
+ timeout or by handling the \c JavaScript event. First, we hide the popup
+ widget itself by calling \l QWidget::hide(). Then, we notify the \c JavaScript
+ code by calling the \l QWebEngineNotification::close() method. Finally, we
+ destroy the notification object through the \c std::unique_ptr::reset() method.
+
+ \skipto onClosed
+ \dots
+ \skipto hide()
+ \printuntil reset
+
+ \section2 Implementing User Interaction
+
+ To implement the \e click step for a notification, we handle mouse interaction
+ through \l QWidget::mouseReleaseEvent(). On this event, the \c JavaScript code
+ is notified by calling the \l QWebEngineNotification::click() method.
+ Then we automatically perform the \e close step as a notification is
+ considered fully handled and no longer needed, and therefore can be destroyed.
+
+ \skipto mouseReleaseEvent
+ \printuntil onClosed
+ \printuntil /^\}/
+*/
diff --git a/examples/webenginewidgets/notifications/main.cpp b/examples/webenginewidgets/notifications/main.cpp
new file mode 100644
index 000000000..661b82ff5
--- /dev/null
+++ b/examples/webenginewidgets/notifications/main.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "notificationpopup.h"
+
+#include <QApplication>
+#include <QDesktopServices>
+#include <QWebEnginePage>
+#include <QWebEngineProfile>
+#include <QWebEngineView>
+
+class WebEnginePage : public QWebEnginePage {
+public:
+ WebEnginePage(QWidget *parent) : QWebEnginePage(parent) { }
+
+ bool acceptNavigationRequest(const QUrl &url, NavigationType, bool) override {
+ if (url.scheme() != "https")
+ return true;
+ QDesktopServices::openUrl(url);
+ return false;
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QCoreApplication::setOrganizationName("QtExamples");
+ QApplication app(argc, argv);
+
+ QWebEngineView view;
+
+ // set custom page to open all page's links for https scheme in system browser
+ view.setPage(new WebEnginePage(&view));
+
+ QObject::connect(view.page(), &QWebEnginePage::featurePermissionRequested,
+ [&] (const QUrl &origin, QWebEnginePage::Feature feature) {
+ if (feature != QWebEnginePage::Notifications)
+ return;
+ view.page()->setFeaturePermission(origin, feature, QWebEnginePage::PermissionGrantedByUser);
+ });
+
+ auto profile = view.page()->profile();
+ auto popup = new NotificationPopup(&view);
+ profile->setNotificationPresenter([&] (std::unique_ptr<QWebEngineNotification> notification) {
+ popup->present(notification);
+ });
+
+ view.resize(640, 480);
+ view.show();
+ view.setUrl(QStringLiteral("qrc:/index.html"));
+ return app.exec();
+}
+
diff --git a/examples/webenginewidgets/notifications/notificationpopup.h b/examples/webenginewidgets/notifications/notificationpopup.h
new file mode 100644
index 000000000..fcbb003b9
--- /dev/null
+++ b/examples/webenginewidgets/notifications/notificationpopup.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QPushButton>
+#include <QSpacerItem>
+#include <QTimer>
+#include <QVBoxLayout>
+#include <QWebEngineNotification>
+
+#include <memory>
+
+class NotificationPopup : public QWidget {
+ Q_OBJECT
+
+ QLabel m_icon, m_title, m_message;
+ std::unique_ptr<QWebEngineNotification> notification;
+
+public:
+ NotificationPopup(QWidget *parent) : QWidget(parent) {
+ setWindowFlags(Qt::ToolTip);
+ auto rootLayout = new QHBoxLayout(this);
+
+ rootLayout->addWidget(&m_icon);
+
+ auto bodyLayout = new QVBoxLayout;
+ rootLayout->addLayout(bodyLayout);
+
+ auto titleLayout = new QHBoxLayout;
+ bodyLayout->addLayout(titleLayout);
+
+ titleLayout->addWidget(&m_title);
+ titleLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
+
+ auto close = new QPushButton(tr("Close"));
+ titleLayout->addWidget(close);
+ connect(close, &QPushButton::clicked, this, &NotificationPopup::onClosed);
+
+ bodyLayout->addWidget(&m_message);
+ adjustSize();
+ }
+
+ void present(std::unique_ptr<QWebEngineNotification> &newNotification) {
+ if (notification) {
+ notification->close();
+ notification.reset();
+ }
+
+ notification.swap(newNotification);
+
+ m_title.setText("<b>" + notification->title() + "</b>");
+ m_message.setText(notification->message());
+ m_icon.setPixmap(QPixmap::fromImage(notification->icon()).scaledToHeight(m_icon.height()));
+
+ show();
+ notification->show();
+
+ connect(notification.get(), &QWebEngineNotification::closed, this, &NotificationPopup::onClosed);
+ QTimer::singleShot(10000, notification.get(), [&] () { onClosed(); });
+
+ // position our popup in the right corner of its parent widget
+ move(parentWidget()->mapToGlobal(parentWidget()->rect().bottomRight() - QPoint(width() + 10, height() + 10)));
+ }
+
+protected slots:
+ void onClosed() {
+ hide();
+ notification->close();
+ notification.reset();
+ }
+
+protected:
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ QWidget::mouseReleaseEvent(event);
+ if (notification && event->button() == Qt::LeftButton) {
+ notification->click();
+ onClosed();
+ }
+ }
+};
+
diff --git a/examples/webenginewidgets/notifications/notifications.pro b/examples/webenginewidgets/notifications/notifications.pro
new file mode 100644
index 000000000..6e276d405
--- /dev/null
+++ b/examples/webenginewidgets/notifications/notifications.pro
@@ -0,0 +1,10 @@
+QT += webenginewidgets
+
+HEADERS = notificationpopup.h
+
+SOURCES = main.cpp
+
+RESOURCES = data/data.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/notifications
+INSTALLS += target
diff --git a/examples/webenginewidgets/webenginewidgets.pro b/examples/webenginewidgets/webenginewidgets.pro
index 0d47aac80..deb42a8cd 100644
--- a/examples/webenginewidgets/webenginewidgets.pro
+++ b/examples/webenginewidgets/webenginewidgets.pro
@@ -7,6 +7,7 @@ SUBDIRS += \
minimal \
contentmanipulation \
cookiebrowser \
+ notifications \
simplebrowser \
stylesheetbrowser \
videoplayer \
diff --git a/mkspecs/features/functions.prf b/mkspecs/features/functions.prf
index f6aeea21a..9efa8958f 100644
--- a/mkspecs/features/functions.prf
+++ b/mkspecs/features/functions.prf
@@ -10,15 +10,6 @@ defineReplace(getChromiumSrcDir) {
return($$git_chromium_src_dir)
}
-defineReplace(extractCFlag) {
- CFLAGS = $$QMAKE_CC $$QMAKE_CFLAGS
- OPTION = $$find(CFLAGS, $$1)
- OPTION = $$split(OPTION, =)
- PARAM = $$member(OPTION, 1)
- !isEmpty(PARAM): return ($$PARAM)
- return ($$OPTION)
-}
-
defineReplace(which) {
out = $$1
win32 {
diff --git a/src/core/config/functions.pri b/src/core/config/functions.pri
new file mode 100644
index 000000000..8c11faa16
--- /dev/null
+++ b/src/core/config/functions.pri
@@ -0,0 +1,8 @@
+defineReplace(qtwebengine_extractCFlag) {
+ CFLAGS = $$QMAKE_CC $$QMAKE_CFLAGS
+ OPTION = $$find(CFLAGS, $$1)
+ OPTION = $$split(OPTION, =)
+ PARAM = $$member(OPTION, 1)
+ !isEmpty(PARAM): return ($$PARAM)
+ return ($$OPTION)
+}
diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri
index fcce4c316..e45273cca 100644
--- a/src/core/config/linux.pri
+++ b/src/core/config/linux.pri
@@ -1,4 +1,10 @@
include(common.pri)
+include(functions.pri)
+
+defineReplace(extractCFlag) {
+ return($$qtwebengine_extractCFlag($$1))
+}
+
QT_FOR_CONFIG += gui-private webenginecore-private
gn_args += \
diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri
index 429e4e45f..385faeed0 100644
--- a/src/core/config/windows.pri
+++ b/src/core/config/windows.pri
@@ -8,9 +8,6 @@ gn_args += \
win_linker_timing=true \
com_init_check_hook_disabled=true
-use_lld_linker: gn_args += use_lld=true
-else: gn_args += use_lld=false
-
clang_cl {
clang_full_path = $$system_path($$which($${QMAKE_CXX}))
# Remove the "\bin\clang-cl.exe" part:
@@ -18,10 +15,11 @@ clang_cl {
clang_prefix = $$join(clang_dir,,,"\..")
gn_args += \
is_clang=true \
+ use_ldd=true \
clang_use_chrome_plugins=false \
- clang_base_path=$$system_quote($$system_path($$clean_path($$clang_prefix)))
+ clang_base_path=\"$$system_path($$clean_path($$clang_prefix))\"
} else {
- gn_args += is_clang=false
+ gn_args += is_clang=false use_lld=false
}
isDeveloperBuild() {
diff --git a/src/core/configure.json b/src/core/configure.json
index 6bc6a213c..bb8ad7997 100644
--- a/src/core/configure.json
+++ b/src/core/configure.json
@@ -5,6 +5,7 @@
"gui-private",
"printsupport"
],
+ "condition": "module.gui",
"testDir": "../../config.tests",
"commandline": {
"options": {
diff --git a/src/core/core_module.pro b/src/core/core_module.pro
index 2bfbc65b9..f5234f88b 100644
--- a/src/core/core_module.pro
+++ b/src/core/core_module.pro
@@ -61,7 +61,7 @@ osx {
# Remove unused functions and data in debug non-developer builds, because the binaries will
# be smaller in the shipped packages.
QMAKE_LFLAGS += /OPT:REF
- } else:CONFIG(debug, debug|release) {
+ } else:CONFIG(debug, debug|release):!clang_cl {
# Make sure to override qtbase's QMAKE_LFLAGS_DEBUG option in debug developer builds,
# because qmake chooses and overrides the option when it gets appended to QMAKE_LFLAGS in
# qtbase\mkspecs\features\default_post.prf, regardless of what Chromium passes back from GN.
diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp
index 31da45314..7f278fd92 100644
--- a/src/core/net/network_delegate_qt.cpp
+++ b/src/core/net/network_delegate_qt.cpp
@@ -150,8 +150,14 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet
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);
+ for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) {
+ std::string h = header.key().toStdString();
+ if (base::LowerCaseEqualsASCII(h, "referer")) {
+ request->SetReferrer(header.value().toStdString());
+ } else {
+ request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true);
+ }
+ }
}
if (result != net::OK)
diff --git a/src/core/net/url_request_notification.cpp b/src/core/net/url_request_notification.cpp
index 6da661cff..e37ad35bc 100644
--- a/src/core/net/url_request_notification.cpp
+++ b/src/core/net/url_request_notification.cpp
@@ -109,7 +109,8 @@ void URLRequestNotification::notify()
if (m_profileAdapter) {
QWebEngineUrlRequestInterceptor* interceptor = m_profileAdapter->requestInterceptor();
- interceptor->interceptRequest(m_requestInfo);
+ if (!interceptor->property("deprecated").toBool())
+ interceptor->interceptRequest(m_requestInfo);
}
WebContentsAdapterClient *client =
@@ -171,8 +172,14 @@ void URLRequestNotification::complete(int error)
if (!m_requestInfo.d_ptr->extraHeaders.isEmpty()) {
auto end = m_requestInfo.d_ptr->extraHeaders.constEnd();
- for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header)
- m_request->SetExtraRequestHeaderByName(header.key().toStdString(), header.value().toStdString(), /* overwrite */ true);
+ for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header) {
+ std::string h = header.key().toStdString();
+ if (base::LowerCaseEqualsASCII(h, "referer")) {
+ m_request->SetReferrer(header.value().toStdString());
+ } else {
+ m_request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true);
+ }
+ }
}
}
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index a275952e7..ff0199833 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -443,18 +443,32 @@ void ProfileAdapter::setHttpCacheMaxSize(int maxSize)
m_profile->m_profileIOData->updateHttpCache();
}
-static bool isInternalScheme(const QByteArray &scheme)
+enum class SchemeType { Protected, Overridable, Custom };
+static SchemeType schemeType(const QByteArray &canonicalScheme)
{
- static QSet<QByteArray> internalSchemes{
- QByteArrayLiteral("qrc"),
- QByteArrayLiteral("data"),
+ static const QSet<QByteArray> blacklist{
+ QByteArrayLiteral("about"),
QByteArrayLiteral("blob"),
- QByteArrayLiteral("http"),
- QByteArrayLiteral("https"),
- QByteArrayLiteral("ftp"),
+ QByteArrayLiteral("data"),
QByteArrayLiteral("javascript"),
+ QByteArrayLiteral("qrc"),
+ // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below)
+ };
+
+ static const QSet<QByteArray> whitelist{
+ QByteArrayLiteral("gopher"),
};
- return internalSchemes.contains(scheme);
+
+ bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size()));
+ bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme();
+ bool blacklisted = blacklist.contains(canonicalScheme);
+ bool whitelisted = whitelist.contains(canonicalScheme);
+
+ if (whitelisted)
+ return SchemeType::Overridable;
+ if (blacklisted || (standardSyntax && !customScheme))
+ return SchemeType::Protected;
+ return SchemeType::Custom;
}
QWebEngineUrlSchemeHandler *ProfileAdapter::urlSchemeHandler(const QByteArray &scheme)
@@ -480,7 +494,7 @@ void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler)
auto it = m_customUrlSchemeHandlers.begin();
while (it != m_customUrlSchemeHandlers.end()) {
if (it.value() == handler) {
- if (isInternalScheme(it.key())) {
+ if (schemeType(it.key()) == SchemeType::Protected) {
qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", it.key().constData());
continue;
}
@@ -497,7 +511,7 @@ void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler)
void ProfileAdapter::removeUrlScheme(const QByteArray &scheme)
{
QByteArray canonicalScheme = scheme.toLower();
- if (isInternalScheme(canonicalScheme)) {
+ if (schemeType(canonicalScheme) == SchemeType::Protected) {
qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", scheme.constData());
return;
}
@@ -509,15 +523,19 @@ void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngin
{
Q_ASSERT(handler);
QByteArray canonicalScheme = scheme.toLower();
- if (isInternalScheme(canonicalScheme)) {
+ SchemeType type = schemeType(canonicalScheme);
+
+ if (type == SchemeType::Protected) {
qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData());
return;
}
+
if (m_customUrlSchemeHandlers.value(canonicalScheme, handler) != handler) {
qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData());
return;
}
- if (QWebEngineUrlScheme::schemeByName(canonicalScheme) == QWebEngineUrlScheme())
+
+ if (type == SchemeType::Custom)
qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() "
"before installing the custom scheme handler.", scheme.constData());
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 8b1a9075b..994e3a3d6 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -934,9 +934,9 @@ void RenderWidgetHostViewQt::visualPropertiesChanged()
m_viewRectInDips = toGfx(m_delegate->viewGeometry().toAlignedRect());
gfx::Rect oldWindowRect = m_windowRectInDips;
- QWindow *window = m_delegate->window();
- m_windowRectInDips = window ? toGfx(window->frameGeometry()) : gfx::Rect();
+ m_windowRectInDips = toGfx(m_delegate->windowGeometry());
+ QWindow *window = m_delegate->window();
content::ScreenInfo oldScreenInfo = m_screenInfo;
m_screenInfo = screenInfoFromQScreen(window ? window->screen() : nullptr);
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index cbf92a8d4..6066284d9 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -91,6 +91,7 @@ public:
virtual ~RenderWidgetHostViewQtDelegate() { }
virtual void initAsPopup(const QRect&) = 0;
virtual QRectF viewGeometry() const = 0;
+ virtual QRect windowGeometry() const = 0;
virtual void setKeyboardFocus() = 0;
virtual bool hasKeyboardFocus() = 0;
virtual void lockMouse() = 0;
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp
index 33cc723f5..a3a5881bf 100644
--- a/src/core/web_engine_context.cpp
+++ b/src/core/web_engine_context.cpp
@@ -363,7 +363,15 @@ ProxyAuthentication WebEngineContext::qProxyNetworkAuthentication(QString host,
const static char kChromiumFlagsEnv[] = "QTWEBENGINE_CHROMIUM_FLAGS";
const static char kDisableSandboxEnv[] = "QTWEBENGINE_DISABLE_SANDBOX";
-static void appendToFeatureSwitch(base::CommandLine *commandLine, const char *featureSwitch, const char *feature)
+static void appendToFeatureList(std::string &featureList, const char *feature)
+{
+ if (featureList.empty())
+ featureList = feature;
+ else
+ featureList = featureList + "," + feature;
+}
+
+static void appendToFeatureSwitch(base::CommandLine *commandLine, const char *featureSwitch, std::string feature)
{
if (!commandLine->HasSwitch(featureSwitch)) {
commandLine->AppendSwitchASCII(featureSwitch, feature);
@@ -475,35 +483,41 @@ WebEngineContext::WebEngineContext()
if (isDesktopGLOrSoftware || isGLES2Context)
parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext);
#endif
+
+ std::string disableFeatures;
+ std::string enableFeatures;
// Needed to allow navigations within pages that were set using setHtml(). One example is
// tst_QWebEnginePage::acceptNavigationRequest.
// This is deprecated behavior, and will be removed in a future Chromium version, as per
// upstream Chromium commit ba52f56207a4b9d70b34880fbff2352e71a06422.
- appendToFeatureSwitch(parsedCommandLine, switches::kEnableFeatures, features::kAllowContentInitiatedDataUrlNavigations.name);
+ appendToFeatureList(enableFeatures, features::kAllowContentInitiatedDataUrlNavigations.name);
// Surface synchronization breaks our current graphics integration (since 65)
- appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kEnableSurfaceSynchronization.name);
+ appendToFeatureList(disableFeatures, features::kEnableSurfaceSynchronization.name);
// Viz Display Compositor is enabled by default since 73. Doesn't work for us (also implies SurfaceSynchronization)
- appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kVizDisplayCompositor.name);
+ appendToFeatureList(disableFeatures, features::kVizDisplayCompositor.name);
// The video-capture service is not functioning at this moment (since 69)
- appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kMojoVideoCapture.name);
+ appendToFeatureList(disableFeatures, features::kMojoVideoCapture.name);
// Breaks WebEngineNewViewRequest.userInitiated API (since 73)
- appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kUserActivationV2.name);
+ appendToFeatureList(disableFeatures, features::kUserActivationV2.name);
- appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kBackgroundFetch.name);
+ appendToFeatureList(disableFeatures, features::kBackgroundFetch.name);
#if QT_CONFIG(webengine_printing_and_pdf)
- appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, printing::features::kUsePdfCompositorServiceForPrint.name);
+ appendToFeatureList(disableFeatures, printing::features::kUsePdfCompositorServiceForPrint.name);
#endif
if (useEmbeddedSwitches) {
// embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc
- appendToFeatureSwitch(parsedCommandLine, switches::kEnableFeatures, features::kOverlayScrollbar.name);
+ appendToFeatureList(enableFeatures, features::kOverlayScrollbar.name);
if (!parsedCommandLine->HasSwitch(switches::kDisablePinch))
parsedCommandLine->AppendSwitch(switches::kEnablePinch);
parsedCommandLine->AppendSwitch(switches::kEnableViewport);
parsedCommandLine->AppendSwitch(switches::kMainFrameResizesAreOrientationChanges);
parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing);
}
+
+ appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, disableFeatures);
+ appendToFeatureSwitch(parsedCommandLine, switches::kEnableFeatures, enableFeatures);
base::FeatureList::InitializeInstance(
parsedCommandLine->GetSwitchValueASCII(switches::kEnableFeatures),
parsedCommandLine->GetSwitchValueASCII(switches::kDisableFeatures));
diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp
index 5a01308a1..b6250a65f 100644
--- a/src/core/web_engine_settings.cpp
+++ b/src/core/web_engine_settings.cpp
@@ -345,6 +345,10 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p
{
// Override for now
prefs->touch_event_feature_detection_enabled = isTouchEventsAPIEnabled();
+#if !QT_CONFIG(webengine_embedded_build)
+ prefs->available_hover_types = ui::HOVER_TYPE_HOVER;
+ prefs->primary_hover_type = ui::HOVER_TYPE_HOVER;
+#endif
if (prefs->viewport_enabled) {
// We need to enable the viewport options together as it doesn't really work
// to enable them separately. With viewport-enabled we match Android defaults.
diff --git a/src/webengine/api/qquickwebenginedownloaditem.cpp b/src/webengine/api/qquickwebenginedownloaditem.cpp
index cdb95fa53..7d51ed21d 100644
--- a/src/webengine/api/qquickwebenginedownloaditem.cpp
+++ b/src/webengine/api/qquickwebenginedownloaditem.cpp
@@ -43,6 +43,8 @@
#include "profile_adapter.h"
#include "qquickwebengineprofile_p.h"
+#include "QFileInfo"
+
using QtWebEngineCore::ProfileAdapterClient;
QT_BEGIN_NAMESPACE
@@ -427,6 +429,16 @@ void QQuickWebEngineDownloadItem::setPath(QString path)
return;
}
if (d->downloadPath != path) {
+ if (QFileInfo(path).fileName().isEmpty()) {
+ qWarning("The download path does not include file name.");
+ return;
+ }
+
+ if (QFileInfo(path).isDir()) {
+ qWarning("The download path matches with an already existing directory path.");
+ return;
+ }
+
d->downloadPath = path;
Q_EMIT pathChanged();
}
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 9826ebfe2..976e6ed04 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -219,6 +219,7 @@ RenderWidgetHostViewQtDelegate *QQuickWebEngineViewPrivate::CreateRenderWidgetHo
RenderWidgetHostViewQtDelegateQuick *quickDelegate = new RenderWidgetHostViewQtDelegateQuick(client, /*isPopup = */ true);
if (hasWindowCapability) {
RenderWidgetHostViewQtDelegateQuickWindow *wrapperWindow = new RenderWidgetHostViewQtDelegateQuickWindow(quickDelegate);
+ wrapperWindow->setVirtualParent(q);
quickDelegate->setParentItem(wrapperWindow->contentItem());
return wrapperWindow;
}
diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index 3537bbd19..38c84f848 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Qt Company Ltd.
+ * Copyright (C) 2019 The Qt Company Ltd.
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (c) 2012 Hewlett-Packard Development Company, L.P.
*
@@ -395,6 +395,11 @@
runJavaScript("document.title", function(result) { console.log(result); });
\endcode
+ Only "plain data" can be returned from JavaScript as the result value.
+ Supported data types include all of the JSON data types as well as, for
+ example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for
+ example, \c{Function} and \c{Promise}.
+
The script will run in the same \e world as other scripts that are
part of the loaded site.
@@ -486,7 +491,8 @@
a web engine view can be used to create a UI element that should not get focus. This can be
useful in a hybrid UI.
- \sa activeFocusOnPressChanged, WebEngineSettings::focusOnNavigationEnabled
+ \sa activeFocusOnPress, activeFocusOnPressChanged,
+ WebEngineSettings::focusOnNavigationEnabled
*/
/*!
@@ -524,7 +530,8 @@
\qmlsignal WebEngineView::certificateError(WebEngineCertificateError error)
\since QtWebEngine 1.1
- This signal is emitted when an invalid certificate error is raised while loading a given request.
+ This signal is emitted when an invalid certificate error, \a error, is
+ raised while loading a given request.
The certificate error can be handled by using the methods of the WebEngineCertificateError
type.
@@ -560,7 +567,7 @@
\qmlsignal WebEngineView::newViewRequested(WebEngineNewViewRequest request)
\since QtWebEngine 1.1
- This signal is emitted when a page load is requested to happen in a separate
+ This signal is emitted when \a request is issued to load a page in a separate
web engine view. This can either be because the current page requested it explicitly
through a JavaScript call to \c window.open, or because the user clicked on a link
while holding Shift, Ctrl, or a built-in combination that triggers the page to open
@@ -579,8 +586,8 @@
\qmlsignal WebEngineView::fullScreenRequested(FullScreenRequest request)
\since QtWebEngine 1.1
- This signal is emitted when the web page requests fullscreen mode through the
- JavaScript API.
+ This signal is emitted when the web page issues the \a request for
+ fullscreen mode through the JavaScript API.
\sa isFullScreen
*/
@@ -589,10 +596,10 @@
\qmlsignal WebEngineView::activeFocusOnPressChanged(bool activeFocusOnPress)
\since QtWebEngine 1.2
- This signal is emitted when the ability of the web engine view to get focus when clicked
- changes.
+ This signal is emitted when the value of \a activeFocusOnPress changes.
+ It specifies whether the view should gain active focus when pressed.
- \sa setActiveFocusOnPress()
+ \sa activeFocusOnPress, setActiveFocusOnPress()
*/
/*!
@@ -1109,7 +1116,8 @@
\qmlsignal WebEngineView::audioMutedChanged(bool muted)
\since QtWebEngine 1.3
- This signal is emitted when the page's audio is (un)muted using audioMuted property.
+ This signal is emitted when the value of \a muted changes. The value is
+ specified using the \l audioMuted property.
\note Not to be confused with a specific HTML5 audio / video element being muted.
\sa audioMuted, recentlyAudibleChanged
@@ -1127,10 +1135,10 @@
\qmlsignal WebEngineView::recentlyAudibleChanged(bool recentlyAudible)
\since QtWebEngine 1.3
- This signal is emitted when the page's audible state is changed, due to audio
- being played or stopped.
+ This signal is emitted when the page's audible state, specified by
+ \a recentlyAudible, is changed, due to audio being played or stopped.
- \note The signal is also emitted when the audioMuted property changes.
+ \note The signal is also emitted when the \l audioMuted property changes.
Also if the audio is paused, this signal is emitted with an approximate \b{two-second
delay}, from the moment the audio is paused.
@@ -1176,7 +1184,7 @@
PDF and returns immediately. To be informed about the result of the
request, connect to the signal pdfPrintingFinished().
- If you leave out \a pageSizeID, it defaults to \c A4. If you leave out
+ If you leave out \a pageSizeId, it defaults to \c A4. If you leave out
\a orientation, it defaults to \c Portrait.
\sa pdfPrintingFinished()
@@ -1192,7 +1200,7 @@
The \a resultCallback must take a string parameter. This string will contain the document's data upon successful printing and an empty
string otherwise.
- If you leave out \a pageSizeID, it defaults to \c A4. If you leave out
+ If you leave out \a pageSizeId, it defaults to \c A4. If you leave out
\a orientation, it defaults to \c Portrait.
*/
@@ -1207,8 +1215,8 @@
\qmlsignal WebEngineView::wasRecentlyAudibleChanged(bool wasRecentlyAudible)
\since QtWebEngine 1.3
- This signal is emitted when the page's audible state is changed, due to audio
- being played or stopped.
+ This signal is emitted when the page's audible state, specified by
+ \a wasRecentlyAudible, is changed, due to audio being played or stopped.
\note The signal is also emitted when calling the setAudioMuted method.
Also if the audio is paused, this signal is emitted with an approximate \b{2 second
@@ -1221,7 +1229,7 @@
This signal is emitted when an authentication dialog is requested.
- The request can be handled by using the methods of the AuthenticationDialogRequest
+ The \a request can be handled by using the methods of the AuthenticationDialogRequest
type.
\note Signal handlers need to call \c{request.accepted = true} to prevent a
@@ -1236,7 +1244,7 @@
This signal is emitted when a JavaScript dialog is requested.
- The request can be handled by using the methods of the JavaScriptDialogRequest
+ The \a request can be handled by using the methods of the JavaScriptDialogRequest
type.
\note Signal handlers need to call \c{request.accepted = true} to prevent a
@@ -1251,7 +1259,7 @@
This signal is emitted when a color picker dialog is requested.
- The request can be handled by using the methods of the ColorDialogRequest
+ The \a request can be handled by using the methods of the ColorDialogRequest
type.
\note Signal handlers need to call \c{request.accepted = true} to prevent a
@@ -1265,7 +1273,7 @@
This signal is emitted when a file picker dialog is requested.
- The request error can be handled by using the methods of the FileDialogRequest
+ The \a request can be handled by using the methods of the FileDialogRequest
type.
\note Signal handlers need to call \c{request.accepted = true} to prevent a
@@ -1287,7 +1295,7 @@
This signal is emitted when a context menu is requested.
- The request can be handled by using the properties of the ContextMenuRequest
+ The \a request can be handled by using the properties of the ContextMenuRequest
type.
\note Signal handlers need to call \c{request.accepted = true} to prevent a
@@ -1302,7 +1310,7 @@
\qmlsignal WebEngineView::quotaRequested(QuotaRequest request)
\since QtWebEngine 1.7
- This signal is emitted when the web page requests larger persistent storage
+ This signal is emitted when the web page issues a \a request for a larger persistent storage
than the application's current allocation in File System API. The default quota
is 0 bytes.
@@ -1361,7 +1369,7 @@
\since QtWebEngine 1.7
This signal is emitted when the web page tries to register a custom protocol
- using the \l registerProtocolHandler API.
+ by issuing a \l registerProtocolHandler \a request.
\sa RegisterProtocolHandlerRequest
*/
@@ -1457,7 +1465,7 @@
\qmlmethod WebEngineAction WebEngineView::action(WebAction action)
\since 5.12
- Returns a \l WebEngineAction for the specified \l WebAction action.
+ Returns a \l WebEngineAction for the specified \l WebAction \a action.
WebEngineView also takes care of implementing the action,
so that upon triggering the corresponding action is performed on the view.
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 e756ee157..b636448b3 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -101,7 +101,20 @@ void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r)
QRectF RenderWidgetHostViewQtDelegateQuick::viewGeometry() const
{
- return QRectF(mapToGlobal(QPointF(0, 0)), size());
+ // Transform the entire rect to find the correct top left corner.
+ const QPointF p1 = mapToGlobal(mapFromScene(QPointF(0, 0)));
+ const QPointF p2 = mapToGlobal(mapFromScene(QPointF(width(), height())));
+ QRectF geometry = QRectF(p1, p2).normalized();
+ // But keep the size untransformed to behave like other QQuickItems.
+ geometry.setSize(size());
+ return geometry;
+}
+
+QRect RenderWidgetHostViewQtDelegateQuick::windowGeometry() const
+{
+ if (!window())
+ return QRect();
+ return window()->frameGeometry();
}
void RenderWidgetHostViewQtDelegateQuick::setKeyboardFocus()
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 4edf37cff..00158b3ac 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h
@@ -60,6 +60,7 @@ public:
void initAsPopup(const QRect&) override;
QRectF viewGeometry() const override;
+ QRect windowGeometry() const override;
void setKeyboardFocus() override;
bool hasKeyboardFocus() override;
void lockMouse() override;
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
index 3c6c743e0..c085aacd7 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -44,8 +44,9 @@
namespace QtWebEngineCore {
-RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegate *realDelegate)
+RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegateQuick *realDelegate)
: m_realDelegate(realDelegate)
+ , m_virtualParent(nullptr)
{
setFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
}
@@ -54,17 +55,48 @@ RenderWidgetHostViewQtDelegateQuickWindow::~RenderWidgetHostViewQtDelegateQuickW
{
}
+void RenderWidgetHostViewQtDelegateQuickWindow::setVirtualParent(QQuickItem *virtualParent)
+{
+ Q_ASSERT(virtualParent);
+ m_virtualParent = virtualParent;
+}
+
+static inline QRectF mapRectToGlobal(const QQuickItem *item, const QRectF &rect)
+{
+ const QPointF p1 = item->mapToGlobal(rect.topLeft());
+ const QPointF p2 = item->mapToGlobal(rect.bottomRight());
+ return QRectF(p1, p2).normalized();
+}
+
+static inline QRectF mapRectFromGlobal(const QQuickItem *item, const QRectF &rect)
+{
+ const QPointF p1 = item->mapFromGlobal(rect.topLeft());
+ const QPointF p2 = item->mapFromGlobal(rect.bottomRight());
+ return QRectF(p1, p2).normalized();
+}
+
void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &screenRect)
{
- m_realDelegate->initAsPopup(QRect(QPoint(0, 0), screenRect.size()));
- setGeometry(screenRect);
+ QRectF popupRect(screenRect);
+ popupRect = mapRectFromGlobal(m_virtualParent, popupRect);
+ popupRect = m_virtualParent->mapRectToScene(popupRect);
+ popupRect = mapRectToGlobal(m_virtualParent, popupRect);
+
+ m_realDelegate->initAsPopup(QRect(QPoint(0, 0), popupRect.size().toSize()));
+ popupRect.setSize(screenRect.size());
+ setGeometry(popupRect.toAlignedRect());
raise();
show();
}
QRectF RenderWidgetHostViewQtDelegateQuickWindow::viewGeometry() const
{
- return m_realDelegate->viewGeometry();
+ return geometry();
+}
+
+QRect RenderWidgetHostViewQtDelegateQuickWindow::windowGeometry() const
+{
+ return frameGeometry();
}
void RenderWidgetHostViewQtDelegateQuickWindow::show()
@@ -133,7 +165,12 @@ void RenderWidgetHostViewQtDelegateQuickWindow::resize(int width, int height)
void RenderWidgetHostViewQtDelegateQuickWindow::move(const QPoint &screenPos)
{
- QQuickWindow::setPosition(screenPos);
+ QRectF popupRect(screenPos, size());
+ popupRect = mapRectFromGlobal(m_virtualParent, popupRect);
+ popupRect = m_virtualParent->mapRectToScene(popupRect);
+ popupRect = mapRectToGlobal(m_virtualParent, popupRect);
+
+ QQuickWindow::setPosition(popupRect.topLeft().toPoint());
}
} // namespace QtWebEngineCore
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 039f6102a..ab583bd63 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
@@ -52,11 +52,12 @@ namespace QtWebEngineCore {
class RenderWidgetHostViewQtDelegateQuickWindow : public QQuickWindow , public RenderWidgetHostViewQtDelegate {
public:
- RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegate *realDelegate);
+ RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegateQuick *realDelegate);
~RenderWidgetHostViewQtDelegateQuickWindow();
void initAsPopup(const QRect&) override;
QRectF viewGeometry() const override;
+ QRect windowGeometry() const override;
void setKeyboardFocus() override {}
bool hasKeyboardFocus() override { return false; }
void lockMouse() override {}
@@ -79,8 +80,11 @@ public:
void setClearColor(const QColor &) override { }
bool copySurface(const QRect &, const QSize &, QImage &) override { return false; }
+ void setVirtualParent(QQuickItem *virtualParent);
+
private:
- QScopedPointer<RenderWidgetHostViewQtDelegate> m_realDelegate;
+ QScopedPointer<RenderWidgetHostViewQtDelegateQuick> m_realDelegate;
+ QQuickItem *m_virtualParent;
};
} // namespace QtWebEngineCore
diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp
index 4575f2929..05c6956ea 100644
--- a/src/webenginewidgets/api/qwebenginedownloaditem.cpp
+++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp
@@ -43,6 +43,7 @@
#include "profile_adapter.h"
#include "qwebengineprofile_p.h"
+#include "QFileInfo"
QT_BEGIN_NAMESPACE
@@ -534,6 +535,16 @@ void QWebEngineDownloadItem::setPath(QString path)
return;
}
+ if (QFileInfo(path).fileName().isEmpty()) {
+ qWarning("The download path does not include file name.");
+ return;
+ }
+
+ if (QFileInfo(path).isDir()) {
+ qWarning("The download path matches with an already existing directory path.");
+ return;
+ }
+
d->downloadPath = path;
}
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index e1b9a8fe3..86736d42b 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -686,24 +686,34 @@ void QWebEnginePagePrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView
auto oldView = page ? page->d_func()->view : nullptr;
auto oldPage = view ? view->d_func()->page : nullptr;
+ bool ownNewPage = false;
+ bool deleteOldPage = false;
+
// Change pointers first.
if (page && oldView != view) {
- if (oldView)
+ if (oldView) {
+ ownNewPage = oldView->d_func()->m_ownsPage;
oldView->d_func()->page = nullptr;
+ oldView->d_func()->m_ownsPage = false;
+ }
page->d_func()->view = view;
}
if (view && oldPage != page) {
- if (oldPage)
- oldPage->d_func()->view = nullptr;
+ if (oldPage) {
+ if (oldPage->d_func())
+ oldPage->d_func()->view = nullptr;
+ deleteOldPage = view->d_func()->m_ownsPage;
+ }
+ view->d_func()->m_ownsPage = ownNewPage;
view->d_func()->page = page;
}
// Then notify.
auto widget = page ? page->d_func()->widget : nullptr;
- auto oldWidget = oldPage ? oldPage->d_func()->widget : nullptr;
+ auto oldWidget = (oldPage && oldPage->d_func()) ? oldPage->d_func()->widget : nullptr;
if (page && oldView != view && oldView) {
oldView->d_func()->pageChanged(page, nullptr);
@@ -712,17 +722,15 @@ void QWebEnginePagePrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView
}
if (view && oldPage != page) {
- view->d_func()->pageChanged(oldPage, page);
+ if (oldPage && oldPage->d_func())
+ view->d_func()->pageChanged(oldPage, page);
+ else
+ view->d_func()->pageChanged(nullptr, page);
if (oldWidget != widget)
view->d_func()->widgetChanged(oldWidget, widget);
-
- // At this point m_ownsPage should still refer to oldPage,
- // it is only set for the new page after binding.
- if (view->d_func()->m_ownsPage) {
- delete oldPage;
- view->d_func()->m_ownsPage = false;
- }
}
+ if (deleteOldPage)
+ delete oldPage;
}
void QWebEnginePagePrivate::bindPageAndWidget(QWebEnginePage *page, RenderWidgetHostViewQtDelegateWidget *widget)
@@ -733,7 +741,7 @@ void QWebEnginePagePrivate::bindPageAndWidget(QWebEnginePage *page, RenderWidget
// Change pointers first.
if (widget && oldPage != page) {
- if (oldPage)
+ if (oldPage && oldPage->d_func())
oldPage->d_func()->widget = nullptr;
widget->m_page = page;
}
@@ -746,7 +754,7 @@ void QWebEnginePagePrivate::bindPageAndWidget(QWebEnginePage *page, RenderWidget
// Then notify.
- if (widget && oldPage != page && oldPage) {
+ if (widget && oldPage != page && oldPage && oldPage->d_func()) {
if (auto oldView = oldPage->d_func()->view)
oldView->d_func()->widgetChanged(widget, nullptr);
}
diff --git a/src/webenginewidgets/doc/src/qtwebkitportingguide.qdoc b/src/webenginewidgets/doc/src/qtwebkitportingguide.qdoc
index e3fdc4ff1..9e8cc463c 100644
--- a/src/webenginewidgets/doc/src/qtwebkitportingguide.qdoc
+++ b/src/webenginewidgets/doc/src/qtwebkitportingguide.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -266,7 +266,6 @@
page.runJavaScript("document.documentElement.contentEditable = true");
\endcode
-
\section1 Unavailable Qt WebKit API
The Qt \WebKit classes and methods in this list will not be available in \QWE.
@@ -310,5 +309,11 @@
engine process them by overloading the QWebEnginePage::acceptNavigationRequest()
function. This is necessary when an HTML document is used as part of the user interface,
and not to display external data, for example, when displaying a list of results.
+
+ \note \l{QWebEnginePage::}{acceptNavigationRequest()} starts the
+ loading process and emits the \l{QWebEnginePage::}{loadStarted()}
+ signal \e before the request is accepted or rejected. Therefore, a
+ \l{QWebEnginePage::}{loadFinished()} signal that returns \c false
+ is to be expected even after delegating the request.
\endtable
*/
diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
index c451344d2..e63423be8 100644
--- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2015 The Qt Company Ltd.
+ Copyright (C) 2019 The Qt Company Ltd.
Copyright (C) 2008, 2009, 2012 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2007 Staikos Computing Services Inc.
Copyright (C) 2007 Apple Inc.
@@ -383,6 +383,11 @@
used as part of the user interface, and not to display external data, for example, when
displaying a list of results.
+ \note The loading process is started and the loadStarted() signal is emitted
+ \e before the request is accepted or rejected. Therefore, a loadFinished()
+ signal that returns \c false is to be expected even after delegating the
+ request.
+
The \l{QWebEngineUrlRequestInterceptor} class offers further options for intercepting and
manipulating requests.
*/
@@ -530,7 +535,7 @@
This signal is emitted when a page starts loading content.
- \sa loadFinished()
+ \sa loadFinished(), acceptNavigationRequest()
*/
/*!
@@ -550,7 +555,14 @@
is independent of script execution or page rendering.
\a ok will indicate whether the load was successful or any error occurred.
- \sa loadStarted()
+ \note Navigation requests can be delegated to the Qt application instead
+ of having the HTML handler engine process them by overloading the
+ acceptNavigationRequest() function. Because the loading process is started
+ and the loadStarted() signal is emitted \e before the request is accepted
+ or rejected, a \c loadFinished() signal that returns \c false is to be
+ expected even after delegating the request.
+
+ \sa loadStarted(), acceptNavigationRequest()
*/
/*!
@@ -760,6 +772,11 @@
page.runJavaScript("document.title", [](const QVariant &v) { qDebug() << v.toString(); });
\endcode
+ Only "plain data" can be returned from JavaScript as the result value.
+ Supported data types include all of the JSON data types as well as, for
+ example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for
+ example, \c{Function} and \c{Promise}.
+
\warning Do not execute lengthy routines in the callback function, because it might block the
rendering of the web engine page.
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 140314681..817d6e408 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -238,6 +238,13 @@ QRectF RenderWidgetHostViewQtDelegateWidget::viewGeometry() const
return QRectF(mapToGlobal(pos()), size());
}
+QRect RenderWidgetHostViewQtDelegateWidget::windowGeometry() const
+{
+ if (!window())
+ return QRect();
+ return window()->frameGeometry();
+}
+
void RenderWidgetHostViewQtDelegateWidget::setKeyboardFocus()
{
// The root item always has focus within the root focus scope:
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 a736aa5cf..7746c4405 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
@@ -67,6 +67,7 @@ public:
void initAsPopup(const QRect&) override;
QRectF viewGeometry() const override;
+ QRect windowGeometry() const override;
void setKeyboardFocus() override;
bool hasKeyboardFocus() override;
void lockMouse() override;
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro b/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro
index e99c7f493..9c239f1a7 100644
--- a/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/qwebengineurlrequestinterceptor.pro
@@ -1 +1,2 @@
include(../tests.pri)
+include(../../shared/http.pri)
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
index 5629998fd..7d3ad1440 100644
--- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
@@ -34,6 +34,9 @@
#include <QtWebEngineWidgets/qwebengineprofile.h>
#include <QtWebEngineWidgets/qwebenginesettings.h>
+#include <httpserver.h>
+#include <httpreqrep.h>
+
class tst_QWebEngineUrlRequestInterceptor : public QObject
{
Q_OBJECT
@@ -61,6 +64,7 @@ private Q_SLOTS:
void requestInterceptorByResourceType_data();
void requestInterceptorByResourceType();
void firstPartyUrlHttp();
+ void passRefererHeader();
};
tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor()
@@ -99,6 +103,9 @@ struct RequestInfo {
int resourceType;
};
+static const QByteArray kHttpHeaderReferrerValue = QByteArrayLiteral("http://somereferrer.com/");
+static const QByteArray kHttpHeaderRefererName = QByteArrayLiteral("referer");
+
class TestRequestInterceptor : public QWebEngineUrlRequestInterceptor
{
public:
@@ -115,6 +122,9 @@ public:
if (shouldIntercept && info.requestUrl().toString().endsWith(QLatin1String("__placeholder__")))
info.redirect(QUrl("qrc:///resources/content.html"));
+ // Set referrer header
+ info.setHttpHeader(kHttpHeaderRefererName, kHttpHeaderReferrerValue);
+
requestInfos.append(info);
}
@@ -510,5 +520,38 @@ void tst_QWebEngineUrlRequestInterceptor::firstPartyUrlHttp()
QCOMPARE(info.firstPartyUrl, firstPartyUrl);
}
+void tst_QWebEngineUrlRequestInterceptor::passRefererHeader()
+{
+ // Create HTTP Server to parse the request.
+ HttpServer httpServer;
+
+ if (!httpServer.start())
+ QSKIP("Failed to start http server");
+
+ bool succeeded = false;
+ connect(&httpServer, &HttpServer::newRequest, [&succeeded](HttpReqRep *rr) {
+ const QByteArray headerValue = rr->requestHeader(kHttpHeaderRefererName);
+ QCOMPARE(headerValue, kHttpHeaderReferrerValue);
+ succeeded = headerValue == kHttpHeaderReferrerValue;
+ rr->setResponseStatus(200);
+ rr->sendResponse();
+ });
+
+ QWebEngineProfile profile;
+ TestRequestInterceptor interceptor(true);
+ profile.setUrlRequestInterceptor(&interceptor);
+
+ QWebEnginePage page(&profile);
+ QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
+ QWebEngineHttpRequest httpRequest;
+ QUrl requestUrl = httpServer.url();
+ httpRequest.setUrl(requestUrl);
+ page.load(httpRequest);
+
+ QVERIFY(spy.wait());
+ (void) httpServer.stop();
+ QVERIFY(succeeded);
+}
+
QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor)
#include "tst_qwebengineurlrequestinterceptor.moc"
diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
index 3a38c115d..bc474457a 100644
--- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
+++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
@@ -77,6 +77,7 @@ private Q_SLOTS:
void downloadToDefaultLocation();
void downloadToNonExistentDir();
void downloadToReadOnlyDir();
+ void downloadPathValidation();
private:
void saveLink(QPoint linkPos);
@@ -1115,5 +1116,127 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
QFile(m_profile->downloadPath()).setPermissions(QFileDevice::WriteOwner);
}
+void tst_QWebEngineDownloadItem::downloadPathValidation()
+{
+ const QString fileName = "test.txt";
+ QString downloadPath;
+ QString originalDownloadPath;
+
+ QTemporaryDir tmpDir;
+ QVERIFY(tmpDir.isValid());
+
+ // Set up HTTP server
+ ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
+ if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) {
+ rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream"));
+ rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment"));
+ rr->setResponseBody(QByteArrayLiteral("a"));
+ rr->sendResponse();
+ } else {
+ rr->setResponseStatus(404);
+ rr->sendResponse();
+ }
+ });
+
+ // Set up profile and download handler
+ QPointer<QWebEngineDownloadItem> downloadItem;
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ downloadItem = item;
+ originalDownloadPath = item->path();
+
+ item->setPath(downloadPath);
+ // TODO: Do not cancel download from 5.13. This is for not messing up system download path.
+ // Use m_profile->setDownloadPath(tmpDir.path()) at initialization.
+ if (item->path() != downloadPath)
+ item->cancel();
+ else
+ item->accept();
+
+ connect(item, &QWebEngineDownloadItem::stateChanged, [&, item](QWebEngineDownloadItem::DownloadState downloadState) {
+ if (downloadState == QWebEngineDownloadItem::DownloadInterrupted) {
+ item->cancel();
+ }
+ });
+
+ connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
+ QCOMPARE(item->isFinished(), true);
+ QCOMPARE(item->totalBytes(), item->receivedBytes());
+ QVERIFY(item->receivedBytes() > 0);
+ QCOMPARE(item->page(), m_page);
+ });
+ });
+
+ QString oldPath = QDir::currentPath();
+ QDir::setCurrent(tmpDir.path());
+
+ // Set only the file name.
+ downloadItem.clear();
+ originalDownloadPath = "";
+ downloadPath = fileName;
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadItem);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCompleted);
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::NoReason);
+ QCOMPARE(downloadItem->path(), fileName);
+
+ // Set only the directory path.
+ downloadItem.clear();
+ originalDownloadPath = "";
+ downloadPath = tmpDir.path();
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadItem);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::UserCanceled);
+ QCOMPARE(downloadItem->path(), originalDownloadPath);
+
+ // Set only the directory path with separator.
+ downloadItem.clear();
+ originalDownloadPath = "";
+ downloadPath = tmpDir.path() + QDir::separator();
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadItem);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::UserCanceled);
+ QCOMPARE(downloadItem->path(), originalDownloadPath);
+
+ // Set only the directory with the current directory path without ending separator.
+ downloadItem.clear();
+ originalDownloadPath = "";
+ downloadPath = ".";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadItem);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::UserCanceled);
+ QCOMPARE(downloadItem->path(), originalDownloadPath);
+
+ // Set only the directory with the current directory path with ending separator.
+ downloadItem.clear();
+ originalDownloadPath = "";
+ downloadPath = "./";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadItem);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::UserCanceled);
+ QCOMPARE(downloadItem->path(), originalDownloadPath);
+
+
+
+ downloadItem.clear();
+ originalDownloadPath = "";
+ downloadPath = "...";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadItem);
+ QTRY_COMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled);
+#if !defined(Q_OS_WIN)
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::FileFailed);
+ QCOMPARE(downloadItem->path(), downloadPath);
+#else
+ // Windows interprets the "..." path as a valid path. It will be the current path.
+ QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::UserCanceled);
+ QCOMPARE(downloadItem->path(), originalDownloadPath);
+#endif // !defined(Q_OS_WIN)
+ QDir::setCurrent(oldPath);
+}
+
QTEST_MAIN(tst_QWebEngineDownloadItem)
#include "tst_qwebenginedownloaditem.moc"
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 19f9b6df1..dd1140a4f 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -1656,6 +1656,18 @@ void tst_QWebEnginePage::runJavaScript()
JavaScriptCallbackUndefined callbackUndefined;
page.runJavaScript("undefined", QWebEngineCallback<const QVariant&>(callbackUndefined));
+ JavaScriptCallback callbackDate(QVariant(42.0));
+ page.runJavaScript("new Date(42000)", QWebEngineCallback<const QVariant&>(callbackDate));
+
+ JavaScriptCallback callbackBlob(QVariant(QByteArray(8, 0)));
+ page.runJavaScript("new ArrayBuffer(8)", QWebEngineCallback<const QVariant&>(callbackBlob));
+
+ JavaScriptCallbackUndefined callbackFunction;
+ page.runJavaScript("(function(){})", QWebEngineCallback<const QVariant&>(callbackFunction));
+
+ JavaScriptCallback callbackPromise(QVariant(QVariantMap{}));
+ page.runJavaScript("new Promise(function(){})", QWebEngineCallback<const QVariant&>(callbackPromise));
+
QVERIFY(watcher.wait());
}
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 1822069be..8b75067ee 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -32,6 +32,7 @@
#include <QtWebEngineCore/qwebengineurlrequestinterceptor.h>
#include <QtWebEngineCore/qwebengineurlrequestjob.h>
#include <QtWebEngineCore/qwebenginecookiestore.h>
+#include <QtWebEngineCore/qwebengineurlscheme.h>
#include <QtWebEngineCore/qwebengineurlschemehandler.h>
#include <QtWebEngineWidgets/qwebengineprofile.h>
#include <QtWebEngineWidgets/qwebenginepage.h>
@@ -44,6 +45,7 @@ class tst_QWebEngineProfile : public QObject
Q_OBJECT
private Q_SLOTS:
+ void initTestCase();
void init();
void cleanup();
void privateProfile();
@@ -55,14 +57,33 @@ private Q_SLOTS:
void urlSchemeHandlerFailOnRead();
void urlSchemeHandlerStreaming();
void urlSchemeHandlerRequestHeaders();
+ void urlSchemeHandlerInstallation();
void customUserAgent();
void httpAcceptLanguage();
void downloadItem();
void changePersistentPath();
void initiator();
+ void badDeleteOrder();
void qtbug_71895(); // this should be the last test
};
+void tst_QWebEngineProfile::initTestCase()
+{
+ QWebEngineUrlScheme foo("foo");
+ QWebEngineUrlScheme stream("stream");
+ QWebEngineUrlScheme letterto("letterto");
+ QWebEngineUrlScheme aviancarrier("aviancarrier");
+ foo.setSyntax(QWebEngineUrlScheme::Syntax::Host);
+ stream.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort);
+ stream.setDefaultPort(8080);
+ letterto.setSyntax(QWebEngineUrlScheme::Syntax::Path);
+ aviancarrier.setSyntax(QWebEngineUrlScheme::Syntax::Path);
+ QWebEngineUrlScheme::registerScheme(foo);
+ QWebEngineUrlScheme::registerScheme(stream);
+ QWebEngineUrlScheme::registerScheme(letterto);
+ QWebEngineUrlScheme::registerScheme(aviancarrier);
+}
+
void tst_QWebEngineProfile::init()
{
//make sure defualt global profile is 'default' across all the tests
@@ -84,6 +105,7 @@ void tst_QWebEngineProfile::cleanup()
profile->setCachePath(QString());
profile->setPersistentStoragePath(QString());
profile->setHttpCacheType(QWebEngineProfile::DiskHttpCache);
+ profile->removeAllUrlSchemeHandlers();
}
void tst_QWebEngineProfile::privateProfile()
@@ -505,6 +527,46 @@ void tst_QWebEngineProfile::urlSchemeHandlerRequestHeaders()
QVERIFY(loadFinishedSpy.wait());
}
+void tst_QWebEngineProfile::urlSchemeHandlerInstallation()
+{
+ FailingUrlSchemeHandler handler;
+ QWebEngineProfile profile;
+
+ // Builtin schemes that *cannot* be overridden.
+ for (auto scheme : { "about", "blob", "data", "javascript", "qrc", "https", "http", "file",
+ "ftp", "wss", "ws", "filesystem", "FileSystem" }) {
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression("Cannot install a URL scheme handler overriding internal scheme.*"));
+ auto prevHandler = profile.urlSchemeHandler(scheme);
+ profile.installUrlSchemeHandler(scheme, &handler);
+ QCOMPARE(profile.urlSchemeHandler(scheme), prevHandler);
+ }
+
+ // Builtin schemes that *can* be overridden.
+ for (auto scheme : { "gopher", "GOPHER" }) {
+ profile.installUrlSchemeHandler(scheme, &handler);
+ QCOMPARE(profile.urlSchemeHandler(scheme), &handler);
+ profile.removeUrlScheme(scheme);
+ }
+
+ // Other schemes should be registered with QWebEngineUrlScheme first, but
+ // handler installation still succeeds to preserve backwards compatibility.
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression("Please register the custom scheme.*"));
+ profile.installUrlSchemeHandler("tst", &handler);
+ QCOMPARE(profile.urlSchemeHandler("tst"), &handler);
+
+ // Existing handler cannot be overridden.
+ FailingUrlSchemeHandler handler2;
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression("URL scheme handler already installed.*"));
+ profile.installUrlSchemeHandler("tst", &handler2);
+ QCOMPARE(profile.urlSchemeHandler("tst"), &handler);
+ profile.removeUrlScheme("tst");
+}
void tst_QWebEngineProfile::customUserAgent()
{
@@ -630,6 +692,24 @@ void tst_QWebEngineProfile::initiator()
QCOMPARE(handler.initiator, QUrl());
}
+void tst_QWebEngineProfile::badDeleteOrder()
+{
+ QWebEngineProfile *profile = new QWebEngineProfile();
+ QWebEngineView *view = new QWebEngineView();
+ view->resize(640, 480);
+ view->show();
+ QVERIFY(QTest::qWaitForWindowExposed(view));
+ QWebEnginePage *page = new QWebEnginePage(profile, view);
+ view->setPage(page);
+
+ QSignalSpy spyLoadFinished(page, SIGNAL(loadFinished(bool)));
+ page->setHtml(QStringLiteral("<html><body><h1>Badly handled page!</h1></body></html>"));
+ QTRY_COMPARE(spyLoadFinished.count(), 1);
+
+ delete profile;
+ delete view;
+}
+
void tst_QWebEngineProfile::qtbug_71895()
{
QWebEngineView view;
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 74adbaba9..d3ea27fc2 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -197,6 +197,7 @@ private Q_SLOTS:
void closeOpenerTab();
void switchPage();
void setPageDeletesImplicitPage();
+ void setPageDeletesImplicitPage2();
void setViewDeletesImplicitPage();
void setPagePreservesExplicitPage();
void setViewPreservesExplicitPage();
@@ -3211,6 +3212,20 @@ void tst_QWebEngineView::setPageDeletesImplicitPage()
QVERIFY(!implicitPage); // should be deleted
}
+void tst_QWebEngineView::setPageDeletesImplicitPage2()
+{
+ QWebEngineView view1;
+ QWebEngineView view2;
+ QPointer<QWebEnginePage> implicitPage = view1.page();
+ view2.setPage(view1.page());
+ QVERIFY(implicitPage);
+ QVERIFY(view1.page() != implicitPage);
+ QWebEnginePage explicitPage;
+ view2.setPage(&explicitPage);
+ QCOMPARE(view2.page(), &explicitPage);
+ QVERIFY(!implicitPage); // should be deleted
+}
+
void tst_QWebEngineView::setViewDeletesImplicitPage()
{
QWebEngineView view;