summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/webengine/lifecycle/WebBrowser.qml172
-rw-r--r--examples/webengine/lifecycle/WebTab.qml212
-rw-r--r--examples/webengine/lifecycle/WebTabBar.qml100
-rw-r--r--examples/webengine/lifecycle/WebTabButton.qml158
-rw-r--r--examples/webengine/lifecycle/WebTabStack.qml98
-rw-r--r--examples/webengine/lifecycle/WebToolButton.qml63
-rw-r--r--examples/webengine/lifecycle/doc/images/lifecycle-automatic.pngbin0 -> 8148 bytes
-rw-r--r--examples/webengine/lifecycle/doc/images/lifecycle-manual.pngbin0 -> 5855 bytes
-rw-r--r--examples/webengine/lifecycle/doc/images/lifecycle.pngbin0 -> 24494 bytes
-rw-r--r--examples/webengine/lifecycle/doc/src/lifecycle.qdoc167
-rw-r--r--examples/webengine/lifecycle/lifecycle.pro10
-rw-r--r--examples/webengine/lifecycle/main.cpp66
-rw-r--r--examples/webengine/lifecycle/qtquickcontrols2.conf6
-rw-r--r--examples/webengine/lifecycle/resources.qrc11
-rw-r--r--examples/webengine/quicknanobrowser/ApplicationRoot.qml2
-rw-r--r--examples/webengine/quicknanobrowser/BrowserWindow.qml2
-rw-r--r--examples/webengine/quicknanobrowser/DownloadView.qml2
-rw-r--r--examples/webengine/webengine.pro1
-rw-r--r--examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp6
-rw-r--r--examples/webenginewidgets/simplebrowser/downloadwidget.cpp2
-rw-r--r--mkspecs/features/platform.prf8
m---------src/3rdparty0
-rw-r--r--src/core/accessibility_tree_formatter_qt.cpp6
-rw-r--r--src/core/api/qtwebenginecoreglobal.cpp3
-rw-r--r--src/core/api/qwebengineurlrequestinfo.cpp54
-rw-r--r--src/core/api/qwebengineurlrequestinfo.h7
-rw-r--r--src/core/api/qwebengineurlrequestinfo_p.h3
-rw-r--r--src/core/api/qwebengineurlscheme.cpp10
-rw-r--r--src/core/api/qwebengineurlscheme.h1
-rw-r--r--src/core/authentication_dialog_controller.cpp15
-rw-r--r--src/core/authentication_dialog_controller_p.h10
-rw-r--r--src/core/browser_accessibility_qt.cpp8
-rw-r--r--src/core/browser_main_parts_qt.cpp64
-rw-r--r--src/core/browser_main_parts_qt.h14
-rw-r--r--src/core/browser_message_filter_qt.cpp2
-rw-r--r--src/core/browser_message_filter_qt.h2
-rw-r--r--src/core/browsing_data_remover_delegate_qt.cpp4
-rw-r--r--src/core/chromium_overrides.cpp17
-rw-r--r--src/core/common/qt_messages.h4
-rw-r--r--src/core/compositor/compositor_resource_tracker.h7
-rw-r--r--src/core/compositor/delegated_frame_node.cpp19
-rw-r--r--src/core/config/common.pri5
-rw-r--r--src/core/config/linux.pri1
-rw-r--r--src/core/config/mac_osx.pri1
-rw-r--r--src/core/content_browser_client_qt.cpp46
-rw-r--r--src/core/content_browser_client_qt.h19
-rw-r--r--src/core/content_main_delegate_qt.cpp5
-rw-r--r--src/core/core_chromium.pri3
-rw-r--r--src/core/devtools_frontend_qt.cpp18
-rw-r--r--src/core/download_manager_delegate_qt.cpp33
-rw-r--r--src/core/download_manager_delegate_qt.h1
-rw-r--r--src/core/extensions/component_extension_resource_manager_qt.cpp19
-rw-r--r--src/core/extensions/component_extension_resource_manager_qt.h8
-rw-r--r--src/core/extensions/extension_system_qt.h6
-rw-r--r--src/core/extensions/extension_web_contents_observer_qt.h2
-rw-r--r--src/core/extensions/extensions_browser_client_qt.cpp27
-rw-r--r--src/core/extensions/extensions_browser_client_qt.h4
-rw-r--r--src/core/favicon_manager.cpp14
-rw-r--r--src/core/favicon_manager.h1
-rw-r--r--src/core/login_delegate_qt.cpp67
-rw-r--r--src/core/login_delegate_qt.h22
-rw-r--r--src/core/media_capture_devices_dispatcher.cpp51
-rw-r--r--src/core/net/client_cert_override.cpp20
-rw-r--r--src/core/net/client_cert_override.h4
-rw-r--r--src/core/net/cookie_monster_delegate_qt.cpp34
-rw-r--r--src/core/net/cookie_monster_delegate_qt.h7
-rw-r--r--src/core/net/network_delegate_qt.cpp17
-rw-r--r--src/core/net/url_request_custom_job.cpp26
-rw-r--r--src/core/net/url_request_custom_job.h3
-rw-r--r--src/core/net/url_request_custom_job_proxy.cpp3
-rw-r--r--src/core/net/webui_controller_factory_qt.cpp3
-rw-r--r--src/core/ozone/gl_context_qt.cpp11
-rw-r--r--src/core/ozone/gl_context_qt.h2
-rw-r--r--src/core/ozone/gl_ozone_glx_qt.cpp6
-rw-r--r--src/core/ozone/gl_ozone_glx_qt.h3
-rw-r--r--src/core/ozone/gl_surface_egl_qt.cpp7
-rw-r--r--src/core/ozone/gl_surface_glx_qt.cpp2
-rw-r--r--src/core/ozone/gl_surface_qt.cpp2
-rw-r--r--src/core/ozone/gl_surface_qt.h2
-rw-r--r--src/core/platform_notification_service_qt.cpp37
-rw-r--r--src/core/platform_notification_service_qt.h27
-rw-r--r--src/core/pref_service_adapter.cpp205
-rw-r--r--src/core/pref_service_adapter.h85
-rw-r--r--src/core/printing/print_view_manager_qt.cpp1
-rw-r--r--src/core/printing/print_view_manager_qt.h2
-rw-r--r--src/core/profile_adapter.cpp53
-rw-r--r--src/core/profile_adapter.h4
-rw-r--r--src/core/profile_adapter_client.h3
-rw-r--r--src/core/profile_io_data_qt.cpp35
-rw-r--r--src/core/profile_io_data_qt.h1
-rw-r--r--src/core/profile_qt.cpp95
-rw-r--r--src/core/profile_qt.h20
-rw-r--r--src/core/qtwebengine.gni1
-rw-r--r--src/core/qtwebengine_resources.gni2
-rw-r--r--src/core/qtwebengine_sources.gni7
-rw-r--r--src/core/render_widget_host_view_qt.cpp22
-rw-r--r--src/core/render_widget_host_view_qt.h11
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h2
-rw-r--r--src/core/renderer/content_renderer_client_qt.cpp18
-rw-r--r--src/core/renderer/content_renderer_client_qt.h4
-rw-r--r--src/core/renderer/content_settings_observer_qt.cpp25
-rw-r--r--src/core/renderer/content_settings_observer_qt.h9
-rw-r--r--src/core/renderer/web_channel_ipc_transport.cpp4
-rw-r--r--src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp4
-rw-r--r--src/core/user_notification_controller.cpp8
-rw-r--r--src/core/web_contents_adapter.cpp375
-rw-r--r--src/core/web_contents_adapter.h33
-rw-r--r--src/core/web_contents_adapter_client.h18
-rw-r--r--src/core/web_contents_delegate_qt.cpp133
-rw-r--r--src/core/web_contents_delegate_qt.h33
-rw-r--r--src/core/web_contents_view_qt.h3
-rw-r--r--src/core/web_engine_context.cpp46
-rw-r--r--src/core/web_engine_settings.cpp6
-rw-r--r--src/core/web_engine_settings.h8
-rw-r--r--src/core/web_event_factory.cpp12
-rw-r--r--src/webengine/api/qquickwebenginedialogrequests.cpp110
-rw-r--r--src/webengine/api/qquickwebenginedialogrequests_p.h33
-rw-r--r--src/webengine/api/qquickwebenginedownloaditem.cpp140
-rw-r--r--src/webengine/api/qquickwebenginedownloaditem_p.h19
-rw-r--r--src/webengine/api/qquickwebenginedownloaditem_p_p.h6
-rw-r--r--src/webengine/api/qquickwebenginenavigationrequest.cpp2
-rw-r--r--src/webengine/api/qquickwebengineprofile.cpp10
-rw-r--r--src/webengine/api/qquickwebengineview.cpp74
-rw-r--r--src/webengine/api/qquickwebengineview_p.h26
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h5
-rw-r--r--src/webengine/doc/src/webengineview_lgpl.qdoc65
-rw-r--r--src/webengine/plugin/plugin.cpp28
-rw-r--r--src/webengine/plugin/plugin.pro2
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.cpp6
-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.cpp5
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.h1
-rw-r--r--src/webengine/ui_delegates_manager.cpp6
-rw-r--r--src/webenginewidgets/api/qwebenginedownloaditem.cpp107
-rw-r--r--src/webenginewidgets/api/qwebenginedownloaditem.h9
-rw-r--r--src/webenginewidgets/api/qwebenginedownloaditem_p.h3
-rw-r--r--src/webenginewidgets/api/qwebenginehistory.cpp4
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp193
-rw-r--r--src/webenginewidgets/api/qwebenginepage.h27
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h6
-rw-r--r--src/webenginewidgets/api/qwebengineprofile.cpp7
-rw-r--r--src/webenginewidgets/api/qwebengineview.cpp14
-rw-r--r--src/webenginewidgets/api/qwebengineview.h1
-rw-r--r--src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc1
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp6
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h1
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp69
-rw-r--r--tests/auto/quick/dialogs/BLACKLIST2
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp26
-rw-r--r--tests/auto/quick/qmltests/data/tst_action.qml16
-rw-r--r--tests/auto/quick/qmltests/data/tst_download.qml61
-rw-r--r--tests/auto/quick/qquickwebengineview/BLACKLIST7
-rw-r--r--tests/auto/widgets/accessibility/tst_accessibility.cpp1
-rw-r--r--tests/auto/widgets/loadsignals/tst_loadsignals.cpp3
-rw-r--r--tests/auto/widgets/origins/resources/redirect.css8
-rw-r--r--tests/auto/widgets/origins/resources/redirect.html10
-rw-r--r--tests/auto/widgets/origins/tst_origins.cpp70
-rw-r--r--tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp169
-rw-r--r--tests/auto/widgets/qwebenginepage/BLACKLIST7
-rw-r--r--tests/auto/widgets/qwebenginepage/resources/lifecycle.html17
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp699
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc1
-rw-r--r--tests/auto/widgets/qwebengineprofile/BLACKLIST2
-rw-r--r--tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp15
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp39
-rw-r--r--tests/auto/widgets/spellchecking/tst_spellchecking.cpp83
-rw-r--r--tests/quicktestbrowser/main.cpp2
-rwxr-xr-xtools/scripts/take_snapshot.py5
-rw-r--r--tools/scripts/version_resolver.py4
170 files changed, 4632 insertions, 797 deletions
diff --git a/.qmake.conf b/.qmake.conf
index dceae50da..bf9b346b8 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -5,4 +5,4 @@ QTWEBENGINE_OUT_ROOT = $$shadowed($$PWD)
load(qt_build_config)
CONFIG += warning_clean
-MODULE_VERSION = 5.13.1
+MODULE_VERSION = 5.14.0
diff --git a/examples/webengine/lifecycle/WebBrowser.qml b/examples/webengine/lifecycle/WebBrowser.qml
new file mode 100644
index 000000000..23c2500e2
--- /dev/null
+++ b/examples/webengine/lifecycle/WebBrowser.qml
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Window 2.12
+
+ApplicationWindow {
+ id: root
+
+ readonly property Action newTabAction: Action {
+ text: qsTr("New tab")
+ shortcut: StandardKey.AddTab
+ onTriggered: root.createNewTab({url: "about:blank"})
+ }
+
+ visible: true
+ width: Screen.width * 0.5
+ height: Screen.height * 0.5
+ title: tabStack.currentTab ? tabStack.currentTab.title : ""
+
+ header: WebTabBar {
+ id: tabBar
+
+ z: 1
+
+ newTabAction: root.newTabAction
+ }
+
+ WebTabStack {
+ id: tabStack
+
+ z: 0
+ anchors.fill: parent
+
+ currentIndex: tabBar.currentIndex
+ freezeDelay: freezeSpin.enabled && freezeSpin.value
+ discardDelay: discardSpin.enabled && discardSpin.value
+
+ onCloseRequested: function(index) {
+ root.closeTab(index)
+ }
+
+ onDrawerRequested: drawer.toggle()
+ }
+
+ Drawer {
+ id: drawer
+
+ edge: Qt.RightEdge
+ height: root.height
+
+ Control {
+ padding: 16
+ contentItem: ColumnLayout {
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Settings")
+ font.capitalization: Font.AllUppercase
+ }
+ MenuSeparator {}
+ CheckBox {
+ id: lifecycleCheck
+ text: qsTr("Automatic lifecycle control")
+ checked: true
+ }
+ CheckBox {
+ id: freezeCheck
+ text: qsTr("Freeze after delay (seconds)")
+ enabled: lifecycleCheck.checked
+ checked: true
+ }
+ SpinBox {
+ id: freezeSpin
+ editable: true
+ enabled: freezeCheck.checked
+ value: 60
+ from: 1
+ to: 60*60
+ }
+ CheckBox {
+ id: discardCheck
+ text: qsTr("Discard after delay (seconds)")
+ enabled: lifecycleCheck.checked
+ checked: true
+ }
+ SpinBox {
+ id: discardSpin
+ editable: true
+ enabled: discardCheck.checked
+ value: 60*60
+ from: 1
+ to: 60*60
+ }
+ }
+ }
+
+ function toggle() {
+ if (drawer.visible)
+ drawer.close()
+ else
+ drawer.open()
+ }
+ }
+
+ Component.onCompleted: {
+ createNewTab({url: "https://www.qt.io"})
+ }
+
+ function createNewTab(properties) {
+ const tab = tabStack.createNewTab(properties)
+ tabBar.createNewTab({tab: tab})
+ tabBar.currentIndex = tab.index
+ return tab
+ }
+
+ function closeTab(index) {
+ if (tabStack.count == 1)
+ Qt.quit()
+ tabBar.closeTab(index)
+ tabStack.closeTab(index)
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTab.qml b/examples/webengine/lifecycle/WebTab.qml
new file mode 100644
index 000000000..645758104
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTab.qml
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQml 2.12
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import QtWebEngine 1.11
+
+ColumnLayout {
+ id: root
+
+ signal closeRequested
+ signal drawerRequested
+
+ property int freezeDelay
+ property int discardDelay
+
+ property alias icon : view.icon
+ property alias loading : view.loading
+ property alias url : view.url
+ property alias lifecycleState : view.lifecycleState
+ property alias recommendedState : view.recommendedState
+
+ readonly property string title : {
+ if (view.url == "about:blank")
+ return qsTr("New tab")
+ if (view.title)
+ return view.title
+ return view.url
+ }
+
+ readonly property Action backAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Back)
+ enabled: webAction.enabled
+ text: qsTr("Back")
+ shortcut: root.visible && StandardKey.Back
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action forwardAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Forward)
+ enabled: webAction.enabled
+ text: qsTr("Forward")
+ shortcut: root.visible && StandardKey.Forward
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action reloadAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Reload)
+ enabled: webAction.enabled
+ text: qsTr("Reload")
+ shortcut: root.visible && StandardKey.Refresh
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action stopAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Stop)
+ enabled: webAction.enabled
+ text: qsTr("Stop")
+ shortcut: root.visible && StandardKey.Cancel
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action closeAction: Action {
+ text: qsTr("Close")
+ shortcut: root.visible && StandardKey.Close
+ onTriggered: root.closeRequested()
+ }
+
+ readonly property Action activateAction: Action {
+ text: qsTr("Active")
+ checkable: true
+ checked: view.lifecycleState == WebEngineView.LifecycleState.Active
+ enabled: checked || (view.lifecycleState != WebEngineView.LifecycleState.Active)
+ onTriggered: view.lifecycleState = WebEngineView.LifecycleState.Active
+ }
+
+ readonly property Action freezeAction: Action {
+ text: qsTr("Frozen")
+ checkable: true
+ checked: view.lifecycleState == WebEngineView.LifecycleState.Frozen
+ enabled: checked || (!view.visible && view.lifecycleState == WebEngineView.LifecycleState.Active)
+ onTriggered: view.lifecycleState = WebEngineView.LifecycleState.Frozen
+ }
+
+ readonly property Action discardAction: Action {
+ text: qsTr("Discarded")
+ checkable: true
+ checked: view.lifecycleState == WebEngineView.LifecycleState.Discarded
+ enabled: checked || (!view.visible && view.lifecycleState == WebEngineView.LifecycleState.Frozen)
+ onTriggered: view.lifecycleState = WebEngineView.LifecycleState.Discarded
+ }
+
+ spacing: 0
+
+ ToolBar {
+ Layout.fillWidth: true
+ Material.elevation: 0
+ Material.background: Material.color(Material.Grey, Material.Shade800)
+
+ RowLayout {
+ anchors.fill: parent
+ WebToolButton {
+ action: root.backAction
+ text: "←"
+ ToolTip.text: root.backAction.text
+ }
+ WebToolButton {
+ action: root.forwardAction
+ text: "→"
+ ToolTip.text: root.forwardAction.text
+ }
+ WebToolButton {
+ action: root.reloadAction
+ visible: root.reloadAction.enabled
+ text: "↻"
+ ToolTip.text: root.reloadAction.text
+ }
+ WebToolButton {
+ action: root.stopAction
+ visible: root.stopAction.enabled
+ text: "✕"
+ ToolTip.text: root.stopAction.text
+ }
+ TextField {
+ Layout.fillWidth: true
+ Layout.topMargin: 6
+
+ placeholderText: qsTr("Type a URL")
+ text: view.url == "about:blank" ? "" : view.url
+ selectByMouse: true
+
+ onAccepted: { view.url = text }
+ }
+ WebToolButton {
+ text: "⋮"
+ ToolTip.text: qsTr("Settings")
+ onClicked: root.drawerRequested()
+ }
+ }
+ }
+
+ WebEngineView {
+ id: view
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ Timer {
+ interval: {
+ switch (view.recommendedState) {
+ case WebEngineView.LifecycleState.Active:
+ return 1
+ case WebEngineView.LifecycleState.Frozen:
+ return root.freezeDelay * 1000
+ case WebEngineView.LifecycleState.Discarded:
+ return root.discardDelay * 1000
+ }
+ }
+ running: interval && view.lifecycleState != view.recommendedState
+ onTriggered: view.lifecycleState = view.recommendedState
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTabBar.qml b/examples/webengine/lifecycle/WebTabBar.qml
new file mode 100644
index 000000000..326ad39d2
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTabBar.qml
@@ -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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+
+Pane {
+ id: root
+
+ property Action newTabAction
+
+ property alias currentIndex: tabBar.currentIndex
+
+ signal closeRequested(int index)
+
+ Material.background: Material.color(Material.Grey, Material.Shade900)
+ Material.elevation: 4
+ padding: 0
+
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+
+ TabBar {
+ id: tabBar
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ WebToolButton {
+ Layout.bottomMargin: 2
+
+ action: root.newTabAction
+ text: "+"
+ ToolTip.text: root.newTabAction.text
+ }
+ }
+
+ Component {
+ id: factory
+ WebTabButton {}
+ }
+
+ function createNewTab(properties) {
+ return factory.createObject(tabBar, properties)
+ }
+
+ function closeTab(index) {
+ tabBar.takeItem(index).destroy()
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTabButton.qml b/examples/webengine/lifecycle/WebTabButton.qml
new file mode 100644
index 000000000..815e2fb09
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTabButton.qml
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import QtWebEngine 1.11
+
+TabButton {
+ id: root
+
+ property WebTab tab
+
+ text: root.tab.title
+
+ ToolTip.delay: 1000
+ ToolTip.visible: root.hovered
+ ToolTip.text: root.text
+
+ padding: 6
+
+ contentItem: RowLayout {
+ Item {
+ implicitWidth: 16
+ implicitHeight: 16
+ BusyIndicator {
+ visible: root.tab.loading
+ anchors.fill: parent
+ leftInset: 0
+ topInset: 0
+ rightInset: 0
+ bottomInset: 0
+ padding: 0
+ }
+ Image {
+ visible: !root.tab.loading
+ source: root.tab.icon
+ anchors.fill: parent
+ }
+ }
+ Label {
+ Layout.fillWidth: true
+ Layout.leftMargin: 4
+ Layout.rightMargin: 4
+ text: root.text
+ elide: Text.ElideRight
+ color: {
+ switch (root.tab.lifecycleState) {
+ case WebEngineView.LifecycleState.Active:
+ return Material.color(Material.Grey, Material.Shade100)
+ case WebEngineView.LifecycleState.Frozen:
+ return Material.color(Material.Blue, Material.Shade400)
+ case WebEngineView.LifecycleState.Discarded:
+ return Material.color(Material.Red, Material.Shade400)
+ }
+ }
+
+ }
+ WebToolButton {
+ action: root.tab.closeAction
+ text: "✕"
+ ToolTip.text: action.text
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ propagateComposedEvents: true
+ onClicked: contextMenu.popup()
+ }
+
+ Menu {
+ id: contextMenu
+ Control {
+ contentItem: Label {
+ text: qsTr("Manual lifecycle control")
+ }
+ verticalPadding: 9
+ horizontalPadding: 14
+ }
+ Repeater {
+ model: [root.tab.activateAction, root.tab.freezeAction, root.tab.discardAction]
+ RadioButton {
+ action: modelData
+ verticalPadding: 9
+ horizontalPadding: 14
+ }
+ }
+ Control {
+ contentItem: Label {
+ text: qsTr("Recommended: %1").arg(recommendedStateText)
+ property string recommendedStateText: {
+ switch (root.tab.recommendedState) {
+ case WebEngineView.LifecycleState.Active:
+ return root.tab.activateAction.text
+ case WebEngineView.LifecycleState.Frozen:
+ return root.tab.freezeAction.text
+ case WebEngineView.LifecycleState.Discarded:
+ return root.tab.discardAction.text
+ }
+ }
+ color: Material.hintTextColor
+ }
+ font.pointSize: 8
+ verticalPadding: 9
+ horizontalPadding: 14
+ }
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTabStack.qml b/examples/webengine/lifecycle/WebTabStack.qml
new file mode 100644
index 000000000..75cbba861
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTabStack.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQml.Models 2.12
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+Rectangle {
+ id: root
+
+ signal closeRequested(int index)
+ signal drawerRequested
+
+ property int freezeDelay
+ property int discardDelay
+
+ property int currentIndex
+ property var currentTab: model.children[currentIndex]
+ property alias count: model.count
+
+ color: "white"
+
+ ObjectModel {
+ id: model
+ }
+
+ Component {
+ id: factory
+ WebTab {
+ readonly property int index : ObjectModel.index
+ anchors.fill: parent
+ visible: index == root.currentIndex
+ freezeDelay: root.freezeDelay
+ discardDelay: root.discardDelay
+ onCloseRequested: root.closeRequested(index)
+ onDrawerRequested: root.drawerRequested()
+ }
+ }
+
+ function createNewTab(properties) {
+ const tab = factory.createObject(root, properties)
+ model.append(tab)
+ return tab
+ }
+
+ function closeTab(index) {
+ const tab = model.get(index)
+ model.remove(index)
+ tab.destroy()
+ }
+}
diff --git a/examples/webengine/lifecycle/WebToolButton.qml b/examples/webengine/lifecycle/WebToolButton.qml
new file mode 100644
index 000000000..958c083cd
--- /dev/null
+++ b/examples/webengine/lifecycle/WebToolButton.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+
+ToolButton {
+ id: root
+ font.bold: true
+ font.pointSize: 12
+ ToolTip.delay: 1000
+ ToolTip.visible: hovered
+ implicitWidth: 32
+ implicitHeight: 32
+}
diff --git a/examples/webengine/lifecycle/doc/images/lifecycle-automatic.png b/examples/webengine/lifecycle/doc/images/lifecycle-automatic.png
new file mode 100644
index 000000000..2c62967af
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/images/lifecycle-automatic.png
Binary files differ
diff --git a/examples/webengine/lifecycle/doc/images/lifecycle-manual.png b/examples/webengine/lifecycle/doc/images/lifecycle-manual.png
new file mode 100644
index 000000000..7fb5c5a80
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/images/lifecycle-manual.png
Binary files differ
diff --git a/examples/webengine/lifecycle/doc/images/lifecycle.png b/examples/webengine/lifecycle/doc/images/lifecycle.png
new file mode 100644
index 000000000..87b719022
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/images/lifecycle.png
Binary files differ
diff --git a/examples/webengine/lifecycle/doc/src/lifecycle.qdoc b/examples/webengine/lifecycle/doc/src/lifecycle.qdoc
new file mode 100644
index 000000000..4151d0597
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/src/lifecycle.qdoc
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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 webengine/lifecycle
+ \title WebEngine Lifecycle Example
+ \ingroup webengine-examples
+ \brief Freezes and discards background tabs to reduce CPU and memory usage.
+
+ \image lifecycle.png
+
+ \e {WebEngine Lifecycle Example} demonstrates how the \l
+ {WebEngineView::}{lifecycleState} and \l {WebEngineView::}{recommendedState}
+ properties of the \l {WebEngineView} can be used to reduce the CPU and
+ memory usage of background tabs in a tabbed browser.
+
+ \include examples-run.qdocinc
+
+ \section1 UI Elements of the Example
+
+ The example uses \l {Qt Quick Controls 2} to implement a traditional tabbed
+ browser in the \l {Material Style} (dark variant). The main application
+ window (\c {WebBrowser.qml}) is divided into a header bar at the top and a
+ main viewing area filling the rest of the window. The header contains the
+ tab bar (\c {WebTabBar.qml}) with one button per tab (\c
+ {WebTabButton.qml}). The main area consists of a stack of tabs (\c
+ {WebTabStack.qml} and \c {WebTab.qml}). Each tab in turn has a tool bar at
+ the top and a \l {WebEngineView} for displaying web pages. Finally, the main
+ window also has a \l {Drawer} for changing settings. The drawer can be
+ opened by clicking the "⋮" button on the tool bar.
+
+ \section1 Overview of Lifecycle States
+
+ Each \l {WebEngineView} item can be in one of three \e {lifecycle states}:
+ active, frozen, or discarded. These states, like the sleep states of a CPU,
+ control the resource usage of web views.
+
+ The \e {active} state is the normal, unrestricted state of a web view. All
+ visible web views are always in the active state, as are all web views that
+ have not yet finished loading. Only invisible, idle web views can be
+ transitioned to other lifecycle states.
+
+ The \e {frozen} state is a low CPU usage state. In this state, most HTML
+ task sources are suspended (frozen) and, as a result, most DOM event
+ processing and JavaScript execution will also be suspended. The web view
+ must be invisible in order to be frozen as rendering is not possible in this
+ state.
+
+ The \e {discarded} state is an extreme resource-saving state. In this state,
+ the browsing context of the web view will be discarded and the corresponding
+ renderer subprocess shut down. CPU and memory usage in this state is reduced
+ virtually to zero. On exiting this state the web page will be automatically
+ reloaded. The process of entering and exiting the discarded state is similar
+ to serializing the browsing history of the web view and destroying the view,
+ then creating a new view and restoring its history.
+
+ See also \l {WebEngineView::LifecycleState}. The equivalent in the Widgets
+ API is \l {QWebEnginePage::LifecycleState}.
+
+ \section2 The \c {lifecycleState} and \c {recommendedState} Properties
+
+ The \l {WebEngineView::}{lifecycleState} property of the \l {WebEngineView}
+ type is a read-write property that controls the current lifecycle state of
+ the web view. This property is designed to place as few restrictions as
+ possible on what states can be transitioned to. For example, it is allowed
+ to freeze a web view that is currently playing music in the background,
+ stopping the music. In order to implement a less aggressive resource-saving
+ strategy that avoids interrupting user-visible background activity, the \l
+ {WebEngineView::} {recommendedState} property must be used.
+
+ The \l {WebEngineView::}{recommendedState} property of the \l
+ {WebEngineView} type is a read-only property that calculates a safe limit on
+ the \l {WebEngineView::}{lifecycleState} property, taking into account the
+ current activity of the web view. So, in the example of a web view playing
+ music in the background, the recommended state will be \c {Active} since a
+ more aggressive state would stop the music. If the application wants to
+ avoid interrupting background activity, then it should avoid putting the web
+ view into a more aggressively resource-saving lifecycle state than what's
+ given by \l {WebEngineView::}{recommendedState}.
+
+ See also \l {WebEngineView::lifecycleState} and \l
+ {WebEngineView::recommendedState}. The equivalents in the Widgets API are \l
+ {QWebEnginePage::lifecycleState} and \l {QWebEnginePage::recommendedState}.
+
+ \section2 The Page Lifecycle API
+
+ The \l {WebEngineView::}{lifecycleState} property is connected to the \l
+ {https://wicg.github.io/page-lifecycle/spec.html}{Page Lifecycle API}, a
+ work-in-progress extension to the HTML standard that specifies two new DOM
+ events, \c {freeze} and \c {resume}, and adds a new \c
+ {Document.wasDiscarded} boolean property. The \c {freeze} and \c {resume}
+ events are fired when transitioning from the \c {Active} to the \c {Frozen
+ state}, and vice-versa. The \c {Document.wasDiscarded} property is set to \c
+ {true} when transition from the \c {Discarded} state to the \c {Active}
+ state.
+
+ \section1 Lifecycle States in the Example
+
+ The example implements two ways of changing the lifecycle state: manual and
+ automatic. The manual way uses the \l {WebEngineView::}{lifecycleState}
+ property directly to change the web view lifecycle state, while the
+ automatic way is timer-based and also takes into account the \l
+ {WebEngineView::}{recommendedState}.
+
+ The tab titles in the tab bar are color coded with frozen tabs shown in blue
+ and discarded in red.
+
+ \section2 Manual Lifecycle Control
+
+ \image lifecycle-manual.png
+
+ Manual control is provided by context menus on the tab bar buttons (\c
+ {WebTabButton.qml}). The menu has three radio buttons, one for each
+ lifecycle state, with the current state checked. Some buttons may be
+ disabled, either because they represent illegal state transitions (for
+ example, a \c {Discarded} view cannot directly transition to the \c {Frozen}
+ state), or because other preconditions are not fulfilled (for example, a
+ visible view can only be in the \c {Active} state).
+
+ \section2 Automatic Lifecycle Control
+
+ \image lifecycle-automatic.png
+
+ Automatic control is implemented with a \l {Timer} in the \c {WebTab}
+ component (\c {WebTab.qml}). The timer is started whenever the \l
+ {WebEngineView::}{lifecycleState} of the web view does not match it's \l
+ {WebEngineView::}{recommendedState}. Once the timer fires, the view's
+ lifecycle state is set to the recommended state.
+
+ The time delay is used to avoid changing the lifecycle state too quickly
+ when the user is switching between tabs. The freezing and discarding delays
+ can be changed in the settings drawer accessed through the "⋮" button on the
+ tool bar.
+
+ This is a rather simple algorithm for automatic lifecycle control, however
+ more sophisticated algorithms could also be conceived and implemented on the
+ basis of the \l {WebEngineView::}{lifecycleState} property. For example, the
+ Chromium browser experimentally uses a pretrained deep neural network to
+ predict the next tab activation time by the user, essentially ranking tabs
+ based on how interesting they are to the user. Implementing such an
+ algorithm is left as an exercise to the reader for now.
+
+*/
diff --git a/examples/webengine/lifecycle/lifecycle.pro b/examples/webengine/lifecycle/lifecycle.pro
new file mode 100644
index 000000000..74fbf23c1
--- /dev/null
+++ b/examples/webengine/lifecycle/lifecycle.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+
+QT += quickcontrols2 webengine
+
+SOURCES += main.cpp
+
+RESOURCES += resources.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/webengine/lifecycle
+INSTALLS += target
diff --git a/examples/webengine/lifecycle/main.cpp b/examples/webengine/lifecycle/main.cpp
new file mode 100644
index 000000000..83907cbaf
--- /dev/null
+++ b/examples/webengine/lifecycle/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+#include <QQuickStyle>
+#include <qtwebengineglobal.h>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setOrganizationName("QtExamples");
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication app(argc, argv);
+ QtWebEngine::initialize();
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/WebBrowser.qml")));
+ return app.exec();
+}
diff --git a/examples/webengine/lifecycle/qtquickcontrols2.conf b/examples/webengine/lifecycle/qtquickcontrols2.conf
new file mode 100644
index 000000000..68c77cec5
--- /dev/null
+++ b/examples/webengine/lifecycle/qtquickcontrols2.conf
@@ -0,0 +1,6 @@
+[Controls]
+Style=Material
+
+[Material]
+Theme=Dark
+Variant=Dense
diff --git a/examples/webengine/lifecycle/resources.qrc b/examples/webengine/lifecycle/resources.qrc
new file mode 100644
index 000000000..41e5092ce
--- /dev/null
+++ b/examples/webengine/lifecycle/resources.qrc
@@ -0,0 +1,11 @@
+<RCC>
+ <qresource prefix="/">
+ <file>WebBrowser.qml</file>
+ <file>WebTab.qml</file>
+ <file>WebTabBar.qml</file>
+ <file>WebTabButton.qml</file>
+ <file>WebTabStack.qml</file>
+ <file>WebToolButton.qml</file>
+ <file>qtquickcontrols2.conf</file>
+ </qresource>
+</RCC>
diff --git a/examples/webengine/quicknanobrowser/ApplicationRoot.qml b/examples/webengine/quicknanobrowser/ApplicationRoot.qml
index 3bc571546..df4bbdb4a 100644
--- a/examples/webengine/quicknanobrowser/ApplicationRoot.qml
+++ b/examples/webengine/quicknanobrowser/ApplicationRoot.qml
@@ -49,7 +49,7 @@
****************************************************************************/
import QtQuick 2.1
-import QtWebEngine 1.9
+import QtWebEngine 1.10
QtObject {
id: root
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index d095703fb..088b23e59 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -57,7 +57,7 @@ import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
import QtQuick.Window 2.1
-import QtWebEngine 1.9
+import QtWebEngine 1.10
ApplicationWindow {
id: browserWindow
diff --git a/examples/webengine/quicknanobrowser/DownloadView.qml b/examples/webengine/quicknanobrowser/DownloadView.qml
index f6ebeab4a..e26c770bc 100644
--- a/examples/webengine/quicknanobrowser/DownloadView.qml
+++ b/examples/webengine/quicknanobrowser/DownloadView.qml
@@ -101,7 +101,7 @@ Rectangle {
}
Label {
id: label
- text: path
+ text: downloadDirectory + "/" + downloadFileName
anchors {
verticalCenter: cancelButton.verticalCenter
left: parent.left
diff --git a/examples/webengine/webengine.pro b/examples/webengine/webengine.pro
index 5ad620390..058868395 100644
--- a/examples/webengine/webengine.pro
+++ b/examples/webengine/webengine.pro
@@ -8,5 +8,6 @@ SUBDIRS += \
qtHaveModule(quickcontrols2) {
SUBDIRS += \
+ lifecycle \
recipebrowser
}
diff --git a/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp b/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp
index e0a511475..b6f9e9c13 100644
--- a/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp
@@ -55,6 +55,7 @@
#include "downloadwidget.h"
#include <QFileDialog>
+#include <QDir>
#include <QWebEngineDownloadItem>
DownloadManagerWidget::DownloadManagerWidget(QWidget *parent)
@@ -68,11 +69,12 @@ void DownloadManagerWidget::downloadRequested(QWebEngineDownloadItem *download)
{
Q_ASSERT(download && download->state() == QWebEngineDownloadItem::DownloadRequested);
- QString path = QFileDialog::getSaveFileName(this, tr("Save as"), download->path());
+ QString path = QFileDialog::getSaveFileName(this, tr("Save as"), QDir(download->downloadDirectory()).filePath(download->downloadFileName()));
if (path.isEmpty())
return;
- download->setPath(path);
+ download->setDownloadDirectory(QFileInfo(path).path());
+ download->setDownloadFileName(QFileInfo(path).fileName());
download->accept();
add(new DownloadWidget(download));
diff --git a/examples/webenginewidgets/simplebrowser/downloadwidget.cpp b/examples/webenginewidgets/simplebrowser/downloadwidget.cpp
index 1d599a19d..835a901c6 100644
--- a/examples/webenginewidgets/simplebrowser/downloadwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/downloadwidget.cpp
@@ -60,7 +60,7 @@ DownloadWidget::DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent
, m_timeAdded(QTime::currentTime())
{
setupUi(this);
- m_dstName->setText(QFileInfo(m_download->path()).fileName());
+ m_dstName->setText(m_download->downloadFileName());
m_srcUrl->setText(m_download->url().toDisplayString());
connect(m_cancelButton, &QPushButton::clicked,
diff --git a/mkspecs/features/platform.prf b/mkspecs/features/platform.prf
index 67be73f74..ef1c86d39 100644
--- a/mkspecs/features/platform.prf
+++ b/mkspecs/features/platform.prf
@@ -29,8 +29,8 @@ defineTest(isPlatformSupported) {
skipBuild("Qt WebEngine on Windows requires MSVC or Clang (MSVC mode).")
return(false)
}
- !isMinWinSDKVersion(10, 16299): {
- skipBuild("Qt WebEngine on Windows requires a Windows SDK version 10.0.16299 or newer.")
+ !isMinWinSDKVersion(10, 17763): {
+ skipBuild("Qt WebEngine on Windows requires a Windows SDK version 10.0.17763 or newer.")
return(false)
}
!qtConfig(webengine-winversion) {
@@ -67,10 +67,6 @@ defineTest(isPlatformSupported) {
skipBuild("C++14 support is required in order to build chromium.")
return(false)
}
- qtConfig(mirclient) {
- skipBuild("Mir is not yet supported as graphics backend for Qt WebEngine.")
- return(false)
- }
static {
skipBuild("Static builds of QtWebEngine aren't supported.")
return(false)
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 7871e09ac266bd23fab100c9b56c14fcbdf2198
+Subproject f5613a4bc321972b8f72654d4c4bc9ba0c36ffb
diff --git a/src/core/accessibility_tree_formatter_qt.cpp b/src/core/accessibility_tree_formatter_qt.cpp
index 706857207..3520087ae 100644
--- a/src/core/accessibility_tree_formatter_qt.cpp
+++ b/src/core/accessibility_tree_formatter_qt.cpp
@@ -63,6 +63,7 @@ private:
const std::string GetAllowEmptyString() override;
const std::string GetAllowString() override;
const std::string GetDenyString() override;
+ const std::string GetDenyNodeString() override;
void AddProperties(const BrowserAccessibility &node, base::DictionaryValue* dict) override;
base::string16 ProcessTreeForOutput(const base::DictionaryValue &node, base::DictionaryValue * = nullptr) override;
};
@@ -198,6 +199,11 @@ const std::string AccessibilityTreeFormatterQt::GetDenyString()
return "@QT-DENY:";
}
+const std::string AccessibilityTreeFormatterQt::GetDenyNodeString()
+{
+ return "@QT-DENY-NODE:";
+}
+
#endif // QT_NO_ACCESSIBILITY
// static
diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp
index 25d0bd3be..0fddacb15 100644
--- a/src/core/api/qtwebenginecoreglobal.cpp
+++ b/src/core/api/qtwebenginecoreglobal.cpp
@@ -125,6 +125,9 @@ Q_WEBENGINECORE_PRIVATE_EXPORT void initialize()
return;
shareContext = new QOpenGLContext;
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
+ format.setOption(QSurfaceFormat::ResetNotification);
+ shareContext->setFormat(format);
shareContext->create();
qAddPostRoutine(deleteShareContext);
qt_gl_set_global_share_context(shareContext);
diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp
index 3cbb4da17..e2101fd02 100644
--- a/src/core/api/qwebengineurlrequestinfo.cpp
+++ b/src/core/api/qwebengineurlrequestinfo.cpp
@@ -46,25 +46,26 @@
QT_BEGIN_NAMESPACE
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMainFrame, content::RESOURCE_TYPE_MAIN_FRAME)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSubFrame, content::RESOURCE_TYPE_SUB_FRAME)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeStylesheet, content::RESOURCE_TYPE_STYLESHEET)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeScript, content::RESOURCE_TYPE_SCRIPT)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeImage, content::RESOURCE_TYPE_IMAGE)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFontResource, content::RESOURCE_TYPE_FONT_RESOURCE)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSubResource, content::RESOURCE_TYPE_SUB_RESOURCE)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeObject, content::RESOURCE_TYPE_OBJECT)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMedia, content::RESOURCE_TYPE_MEDIA)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeWorker, content::RESOURCE_TYPE_WORKER)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSharedWorker, content::RESOURCE_TYPE_SHARED_WORKER)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePrefetch, content::RESOURCE_TYPE_PREFETCH)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFavicon, content::RESOURCE_TYPE_FAVICON)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeXhr, content::RESOURCE_TYPE_XHR)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePing, content::RESOURCE_TYPE_PING)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker, content::RESOURCE_TYPE_SERVICE_WORKER)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeCspReport, content::RESOURCE_TYPE_CSP_REPORT)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePluginResource, content::RESOURCE_TYPE_PLUGIN_RESOURCE)
-ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeLast, content::RESOURCE_TYPE_LAST_TYPE)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMainFrame, content::ResourceType::kMainFrame)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSubFrame, content::ResourceType::kSubFrame)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeStylesheet, content::ResourceType::kStylesheet)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeScript, content::ResourceType::kScript)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeImage, content::ResourceType::kImage)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFontResource, content::ResourceType::kFontResource)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSubResource, content::ResourceType::kSubResource)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeObject, content::ResourceType::kObject)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeMedia, content::ResourceType::kMedia)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeWorker, content::ResourceType::kWorker)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeSharedWorker, content::ResourceType::kSharedWorker)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePrefetch, content::ResourceType::kPrefetch)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFavicon, content::ResourceType::kFavicon)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeXhr, content::ResourceType::kXhr)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePing, content::ResourceType::kPing)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker, content::ResourceType::kServiceWorker)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeCspReport, content::ResourceType::kCspReport)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePluginResource, content::ResourceType::kPluginResource)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeNavigationPreload, content::ResourceType::kNavigationPreload)
+ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeLast, content::ResourceType::kMaxValue)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::LinkNavigation, QWebEngineUrlRequestInfo::NavigationTypeLink)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::TypedNavigation, QWebEngineUrlRequestInfo::NavigationTypeTyped)
@@ -74,6 +75,7 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::BackForwardNavigat
QWebEngineUrlRequestInfo::NavigationTypeBackForward)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::ReloadNavigation, QWebEngineUrlRequestInfo::NavigationTypeReload)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, QWebEngineUrlRequestInfo::NavigationTypeOther)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::RedirectNavigation, QWebEngineUrlRequestInfo::NavigationTypeRedirect)
/*!
\class QWebEngineUrlRequestInfo
@@ -128,12 +130,13 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q
QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource,
QWebEngineUrlRequestInfo::NavigationType navigation,
- const QUrl &u, const QUrl &fpu, const QByteArray &m)
+ const QUrl &u, const QUrl &fpu, const QUrl &i, const QByteArray &m)
: resourceType(resource)
, navigationType(navigation)
, shouldBlockRequest(false)
, url(u)
, firstPartyUrl(fpu)
+ , initiator(i)
, method(m)
, changed(false)
{}
@@ -210,6 +213,7 @@ QWebEngineUrlRequestInfo::ResourceType QWebEngineUrlRequestInfo::resourceType()
\value NavigationTypeFormSubmitted Navigation submits a form.
\value NavigationTypeBackForward Navigation initiated by a history action.
\value NavigationTypeReload Navigation initiated by refreshing the page.
+ \value NavigationTypeRedirect Navigation triggered automatically by page content or remote server.
\value NavigationTypeOther None of the above.
*/
@@ -244,6 +248,16 @@ QUrl QWebEngineUrlRequestInfo::firstPartyUrl() const
}
/*!
+ Returns the origin url of the document which initiated
+ the navigation when a frame navigates another frame.
+ */
+
+QUrl QWebEngineUrlRequestInfo::initiator() const
+{
+ return d_ptr->initiator;
+}
+
+/*!
Returns the HTTP method of the request (for example, GET or POST).
*/
diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h
index cf5a4801d..c2c924b05 100644
--- a/src/core/api/qwebengineurlrequestinfo.h
+++ b/src/core/api/qwebengineurlrequestinfo.h
@@ -76,8 +76,9 @@ public:
ResourceTypeServiceWorker, // the main resource of a service worker.
ResourceTypeCspReport, // Content Security Policy (CSP) violation report
ResourceTypePluginResource, // A resource requested by a plugin
+ ResourceTypeNavigationPreload, // A service worker navigation preload request.
#ifndef Q_QDOC
- ResourceTypeLast,
+ ResourceTypeLast = ResourceTypeNavigationPreload,
#endif
ResourceTypeUnknown = 255
};
@@ -88,7 +89,8 @@ public:
NavigationTypeFormSubmitted,
NavigationTypeBackForward,
NavigationTypeReload,
- NavigationTypeOther
+ NavigationTypeOther,
+ NavigationTypeRedirect,
};
ResourceType resourceType() const;
@@ -96,6 +98,7 @@ public:
QUrl requestUrl() const;
QUrl firstPartyUrl() const;
+ QUrl initiator() const;
QByteArray requestMethod() const;
bool changed() const;
diff --git a/src/core/api/qwebengineurlrequestinfo_p.h b/src/core/api/qwebengineurlrequestinfo_p.h
index 9d795b2b5..35b5610be 100644
--- a/src/core/api/qwebengineurlrequestinfo_p.h
+++ b/src/core/api/qwebengineurlrequestinfo_p.h
@@ -70,7 +70,7 @@ class QWebEngineUrlRequestInfoPrivate {
public:
QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRequestInfo::ResourceType resource,
QWebEngineUrlRequestInfo::NavigationType navigation, const QUrl &u, const QUrl &fpu,
- const QByteArray &m);
+ const QUrl &i, const QByteArray &m);
QWebEngineUrlRequestInfo::ResourceType resourceType;
QWebEngineUrlRequestInfo::NavigationType navigationType;
@@ -78,6 +78,7 @@ public:
QUrl url;
QUrl firstPartyUrl;
+ QUrl initiator;
const QByteArray method;
bool changed;
QHash<QByteArray, QByteArray> extraHeaders;
diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp
index f4efad717..f73992c6b 100644
--- a/src/core/api/qwebengineurlscheme.cpp
+++ b/src/core/api/qwebengineurlscheme.cpp
@@ -59,6 +59,7 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::NoAccessAllowed, url::CustomScheme::NoAc
ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ServiceWorkersAllowed, url::CustomScheme::ServiceWorkersAllowed)
ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ViewSourceAllowed, url::CustomScheme::ViewSourceAllowed)
ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ContentSecurityPolicyIgnored, url::CustomScheme::ContentSecurityPolicyIgnored)
+ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::CorsEnabled, url::CustomScheme::CorsEnabled)
static bool g_schemesLocked = false;
@@ -190,6 +191,13 @@ public:
\value ContentSecurityPolicyIgnored
Indicates that accesses to this scheme should bypass all
Content-Security-Policy checks.
+
+ \value CorsEnabled
+ Enables cross-origin resource sharing (CORS) for this scheme. This flag is
+ required in order to, for example, use the scheme with the \l
+ {https://fetch.spec.whatwg.org/}{Fetch API}, or to deliver CSS fonts to a
+ different origin. The appropriate CORS headers are generated automatically by
+ the QWebEngineUrlRequestJob class. (Added in Qt 5.14)
*/
QWebEngineUrlScheme::QWebEngineUrlScheme(QWebEngineUrlSchemePrivate *d) : d(d) {}
@@ -374,7 +382,7 @@ void QWebEngineUrlScheme::registerScheme(const QWebEngineUrlScheme &scheme)
return;
}
- if (url::IsStandard(scheme.d->name.data(), url::Component(0, scheme.d->name.size()))) {
+ if (url::IsStandard(scheme.d->name.data(), url::Component(0, static_cast<int>(scheme.d->name.size())))) {
qWarning() << "QWebEngineUrlScheme::registerScheme: Scheme" << scheme.name() << "is a standard scheme";
return;
}
diff --git a/src/core/api/qwebengineurlscheme.h b/src/core/api/qwebengineurlscheme.h
index 095b47320..ecac44184 100644
--- a/src/core/api/qwebengineurlscheme.h
+++ b/src/core/api/qwebengineurlscheme.h
@@ -76,6 +76,7 @@ public:
ServiceWorkersAllowed = 0x10,
ViewSourceAllowed = 0x20,
ContentSecurityPolicyIgnored = 0x40,
+ CorsEnabled = 0x80,
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAG(Flags)
diff --git a/src/core/authentication_dialog_controller.cpp b/src/core/authentication_dialog_controller.cpp
index 1133b0bc1..23dd62979 100644
--- a/src/core/authentication_dialog_controller.cpp
+++ b/src/core/authentication_dialog_controller.cpp
@@ -46,7 +46,7 @@
namespace QtWebEngineCore {
-AuthenticationDialogControllerPrivate::AuthenticationDialogControllerPrivate(LoginDelegateQt *loginDelegate)
+AuthenticationDialogControllerPrivate::AuthenticationDialogControllerPrivate(base::WeakPtr<LoginDelegateQt> loginDelegate)
: loginDelegate(loginDelegate)
{
}
@@ -54,9 +54,10 @@ AuthenticationDialogControllerPrivate::AuthenticationDialogControllerPrivate(Log
void AuthenticationDialogControllerPrivate::dialogFinished(bool accepted, const QString &user, const QString &password)
{
base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::IO},
+ FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&LoginDelegateQt::sendAuthToRequester,
- loginDelegate, accepted, user, password));
+ loginDelegate,
+ accepted, user, password));
}
AuthenticationDialogController::AuthenticationDialogController(AuthenticationDialogControllerPrivate *dd)
@@ -71,22 +72,22 @@ AuthenticationDialogController::~AuthenticationDialogController()
QUrl AuthenticationDialogController::url() const
{
- return d->loginDelegate->url();
+ return d->url;
}
QString AuthenticationDialogController::realm() const
{
- return d->loginDelegate->realm();
+ return d->realm;
}
QString AuthenticationDialogController::host() const
{
- return d->loginDelegate->host();
+ return d->host;
}
bool AuthenticationDialogController::isProxy() const
{
- return d->loginDelegate->isProxy();
+ return d->isProxy;
}
void AuthenticationDialogController::accept(const QString &user, const QString &password)
diff --git a/src/core/authentication_dialog_controller_p.h b/src/core/authentication_dialog_controller_p.h
index 16069b9b1..1abff576d 100644
--- a/src/core/authentication_dialog_controller_p.h
+++ b/src/core/authentication_dialog_controller_p.h
@@ -40,7 +40,7 @@
#ifndef AUTHENTICATION_DIALOG_CONTROLLER_P_H
#define AUTHENTICATION_DIALOG_CONTROLLER_P_H
-#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "login_delegate_qt.h"
@@ -49,10 +49,14 @@ namespace QtWebEngineCore {
class AuthenticationDialogControllerPrivate {
public:
- AuthenticationDialogControllerPrivate(LoginDelegateQt *loginDelegate);
+ AuthenticationDialogControllerPrivate(base::WeakPtr<LoginDelegateQt> loginDelegate);
void dialogFinished(bool accepted, const QString &user = QString(), const QString &password = QString());
- scoped_refptr<LoginDelegateQt> loginDelegate;
+ base::WeakPtr<LoginDelegateQt> loginDelegate;
+ QUrl url;
+ QString host;
+ QString realm;
+ bool isProxy;
};
} // namespace QtWebEngineCore
diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp
index 75527ea95..f7e9c1c4f 100644
--- a/src/core/browser_accessibility_qt.cpp
+++ b/src/core/browser_accessibility_qt.cpp
@@ -386,6 +386,8 @@ QAccessible::Role BrowserAccessibilityQt::role() const
return QAccessible::ListItem;
case ax::mojom::Role::kListItem:
return QAccessible::ListItem;
+ case ax::mojom::Role::kListGrid:
+ return QAccessible::List;
case ax::mojom::Role::kListMarker:
return QAccessible::StaticText;
case ax::mojom::Role::kLog:
@@ -727,7 +729,11 @@ void BrowserAccessibilityQt::scrollToSubstring(int startIndex, int endIndex)
{
int count = characterCount();
if (startIndex < endIndex && endIndex < count)
- manager()->ScrollToMakeVisible(*this, GetPageBoundsForRange(startIndex, endIndex - startIndex));
+ manager()->ScrollToMakeVisible(*this,
+ GetRootFrameRangeBoundsRect(
+ startIndex,
+ endIndex - startIndex,
+ ui::AXClippingBehavior::kUnclipped));
}
QVariant BrowserAccessibilityQt::currentValue() const
diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp
index dacaf177f..d42a931d0 100644
--- a/src/core/browser_main_parts_qt.cpp
+++ b/src/core/browser_main_parts_qt.cpp
@@ -42,9 +42,11 @@
#include "api/qwebenginemessagepumpscheduler_p.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_impl.h"
#include "base/message_loop/message_loop_current.h"
+#include "base/message_loop/message_pump_for_ui.h"
#include "base/process/process.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_main_parts.h"
#include "content/public/browser/browser_thread.h"
@@ -58,7 +60,6 @@
#include "extensions/extension_system_factory_qt.h"
#include "common/extensions/extensions_client_qt.h"
#endif //BUILDFLAG(ENABLE_EXTENSIONS)
-#include "services/resource_coordinator/public/cpp/process_resource_coordinator.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
@@ -75,6 +76,7 @@
#endif
#if defined(OS_MACOSX)
+#include "base/message_loop/message_pump_mac.h"
#include "ui/base/idle/idle.h"
#endif
@@ -114,12 +116,7 @@ public:
: m_scheduler([this]() { handleScheduledWork(); })
{}
- void setDelegate(Delegate *delegate)
- {
- m_delegate = delegate;
- }
-
- void Run(Delegate *delegate) override
+ void Run(Delegate *) override
{
// This is used only when MessagePumpForUIQt is used outside of the GUI thread.
NOTIMPLEMENTED();
@@ -134,15 +131,26 @@ public:
void ScheduleWork() override
{
// NOTE: This method may called from any thread at any time.
+ ensureDelegate();
m_scheduler.scheduleWork();
}
void ScheduleDelayedWork(const base::TimeTicks &delayed_work_time) override
{
+ // NOTE: This method may called from any thread at any time.
+ ensureDelegate();
m_scheduler.scheduleDelayedWork(GetTimeIntervalMilliseconds(delayed_work_time));
}
private:
+ void ensureDelegate()
+ {
+ if (!m_delegate) {
+ auto seqMan = base::MessageLoopCurrent::GetCurrentSequenceManagerImpl();
+ m_delegate = static_cast<base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl *>(
+ seqMan->controller_.get());
+ }
+ }
// Both Qt and Chromium keep track of the current GL context by using
// thread-local variables, and naturally they are completely unaware of each
// other. As a result, when a QOpenGLContext is made current, the previous
@@ -190,8 +198,6 @@ private:
void handleScheduledWork()
{
- Q_ASSERT(m_delegate);
-
ScopedGLContextChecker glContextChecker;
bool more_work_is_plausible = m_delegate->DoWork();
@@ -213,29 +219,19 @@ private:
QWebEngineMessagePumpScheduler m_scheduler;
};
-// Needed to access protected constructor from MessageLoop.
-class MessageLoopForUIQt : public base::MessageLoop {
-public:
- MessageLoopForUIQt() : MessageLoop(TYPE_UI, base::BindOnce(&messagePumpFactory))
- {
- BindToCurrentThread();
-
- auto pump = static_cast<MessagePumpForUIQt *>(pump_);
- auto backend = static_cast<base::MessageLoopImpl *>(backend_.get());
- pump->setDelegate(backend);
- }
-private:
- static std::unique_ptr<base::MessagePump> messagePumpFactory()
- {
- return base::WrapUnique(new MessagePumpForUIQt);
+std::unique_ptr<base::MessagePump> messagePumpFactory()
+{
+ static bool madePrimaryPump = false;
+ if (!madePrimaryPump) {
+ madePrimaryPump = true;
+ return std::make_unique<MessagePumpForUIQt>();
}
-};
-
-BrowserMainPartsQt::BrowserMainPartsQt() : content::BrowserMainParts()
-{ }
-
-BrowserMainPartsQt::~BrowserMainPartsQt() = default;
-
+#if defined(OS_MACOSX)
+ return base::MessagePumpMac::Create();
+#else
+ return std::make_unique<base::MessagePumpForUI>();
+#endif
+}
int BrowserMainPartsQt::PreEarlyInitialization()
{
@@ -247,8 +243,6 @@ int BrowserMainPartsQt::PreEarlyInitialization()
void BrowserMainPartsQt::PreMainMessageLoopStart()
{
- // Overrides message loop creation in BrowserMainLoop::MainMessageLoopStart().
- m_mainMessageLoop.reset(new MessageLoopForUIQt);
}
void BrowserMainPartsQt::PreMainMessageLoopRun()
@@ -288,8 +282,6 @@ void BrowserMainPartsQt::ServiceManagerConnectionStarted(content::ServiceManager
{
ServiceQt::GetInstance()->InitConnector();
connection->GetConnector()->WarmService(service_manager::ServiceFilter::ByName("qtwebengine"));
- m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector());
- m_processResourceCoordinator->OnProcessLaunched(base::Process::Current());
}
} // namespace QtWebEngineCore
diff --git a/src/core/browser_main_parts_qt.h b/src/core/browser_main_parts_qt.h
index 4eb10e379..8c6d8340e 100644
--- a/src/core/browser_main_parts_qt.h
+++ b/src/core/browser_main_parts_qt.h
@@ -43,24 +43,22 @@
#include "content/public/browser/browser_main_parts.h"
namespace base {
-class MessageLoop;
+class MessagePump;
}
namespace content {
class ServiceManagerConnection;
}
-namespace resource_coordinator {
-class ProcessResourceCoordinator;
-}
-
namespace QtWebEngineCore {
+std::unique_ptr<base::MessagePump> messagePumpFactory();
+
class BrowserMainPartsQt : public content::BrowserMainParts
{
public:
- BrowserMainPartsQt();
- ~BrowserMainPartsQt();
+ BrowserMainPartsQt() = default;
+ ~BrowserMainPartsQt() override = default;
int PreEarlyInitialization() override;
void PreMainMessageLoopStart() override;
@@ -71,8 +69,6 @@ public:
private:
DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt);
- std::unique_ptr<resource_coordinator::ProcessResourceCoordinator> m_processResourceCoordinator;
- std::unique_ptr<base::MessageLoop> m_mainMessageLoop;
};
} // namespace QtWebEngineCore
diff --git a/src/core/browser_message_filter_qt.cpp b/src/core/browser_message_filter_qt.cpp
index 034447512..c8fc88017 100644
--- a/src/core/browser_message_filter_qt.cpp
+++ b/src/core/browser_message_filter_qt.cpp
@@ -79,8 +79,6 @@ bool BrowserMessageFilterQt::OnMessageReceived(const IPC::Message& message)
void BrowserMessageFilterQt::OnAllowDatabase(int /*render_frame_id*/,
const GURL &origin_url,
const GURL &top_origin_url,
- const base::string16 &/*name*/,
- const base::string16 &/*display_name*/,
bool* allowed)
{
NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(m_profile->GetRequestContext()->GetURLRequestContext()->network_delegate());
diff --git a/src/core/browser_message_filter_qt.h b/src/core/browser_message_filter_qt.h
index d121aa65d..3963fb9d5 100644
--- a/src/core/browser_message_filter_qt.h
+++ b/src/core/browser_message_filter_qt.h
@@ -60,8 +60,6 @@ private:
void OnAllowDatabase(int render_frame_id,
const GURL &origin_url,
const GURL &top_origin_url,
- const base::string16& name,
- const base::string16& display_name,
bool *allowed);
void OnAllowDOMStorage(int render_frame_id,
diff --git a/src/core/browsing_data_remover_delegate_qt.cpp b/src/core/browsing_data_remover_delegate_qt.cpp
index 78e6893ea..005a9820d 100644
--- a/src/core/browsing_data_remover_delegate_qt.cpp
+++ b/src/core/browsing_data_remover_delegate_qt.cpp
@@ -49,7 +49,7 @@
namespace QtWebEngineCore {
bool DoesOriginMatchEmbedderMask(int origin_type_mask,
- const GURL &origin,
+ const url::Origin &origin,
storage::SpecialStoragePolicy *policy) {
Q_UNUSED(origin_type_mask);
Q_UNUSED(origin);
@@ -58,7 +58,7 @@ bool DoesOriginMatchEmbedderMask(int origin_type_mask,
}
content::BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher BrowsingDataRemoverDelegateQt::GetOriginTypeMatcher() const {
- return base::Bind(&DoesOriginMatchEmbedderMask);
+ return base::BindRepeating(&DoesOriginMatchEmbedderMask);
}
bool BrowsingDataRemoverDelegateQt::MayRemoveDownloadHistory() const {
diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp
index c44d75a42..b226c34ea 100644
--- a/src/core/chromium_overrides.cpp
+++ b/src/core/chromium_overrides.cpp
@@ -42,7 +42,6 @@
#include "web_contents_view_qt.h"
#include "base/values.h"
-#include "content/browser/renderer_host/pepper/pepper_truetype_font_list.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/font_list.h"
@@ -120,22 +119,6 @@ std::unique_ptr<base::ListValue> GetFontList_SlowBlocking()
return std::move(font_list);
}
-#if QT_CONFIG(webengine_pepper_plugins)
-// content/browser/renderer_host/pepper/pepper_truetype_font_list.h
-void GetFontFamilies_SlowBlocking(std::vector<std::string> *font_families)
-{
- QFontDatabase database;
- for (auto family : database.families()){
- font_families->push_back(family.toStdString());
- }
-}
-
-void GetFontsInFamily_SlowBlocking(const std::string &, std::vector<ppapi::proxy::SerializedTrueTypeFontDesc> *)
-{
- QT_NOT_USED
-}
-#endif // QT_CONFIG(webengine_pepper_plugins)
-
} // namespace content
namespace aura {
diff --git a/src/core/common/qt_messages.h b/src/core/common/qt_messages.h
index 9add826ae..b99204b74 100644
--- a/src/core/common/qt_messages.h
+++ b/src/core/common/qt_messages.h
@@ -76,12 +76,10 @@ IPC_MESSAGE_ROUTED0(RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout)
// Sent by the renderer process to check whether access to web databases is
// granted by content settings.
-IPC_SYNC_MESSAGE_CONTROL5_1(QtWebEngineHostMsg_AllowDatabase,
+IPC_SYNC_MESSAGE_CONTROL3_1(QtWebEngineHostMsg_AllowDatabase,
int /* render_frame_id */,
GURL /* origin_url */,
GURL /* top origin url */,
- base::string16 /* database name */,
- base::string16 /* database display name */,
bool /* allowed */)
// Sent by the renderer process to check whether access to DOM Storage is
diff --git a/src/core/compositor/compositor_resource_tracker.h b/src/core/compositor/compositor_resource_tracker.h
index 887309395..080891e5f 100644
--- a/src/core/compositor/compositor_resource_tracker.h
+++ b/src/core/compositor/compositor_resource_tracker.h
@@ -40,12 +40,13 @@
#ifndef COMPOSITOR_RESOURCE_TRACKER_H
#define COMPOSITOR_RESOURCE_TRACKER_H
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/containers/flat_set.h"
+
#include "compositor_resource.h"
#include "locked_ptr.h"
-#include <base/callback.h>
-#include <base/containers/flat_set.h>
-
#include <atomic>
#include <vector>
diff --git a/src/core/compositor/delegated_frame_node.cpp b/src/core/compositor/delegated_frame_node.cpp
index 5f474cbfb..19e8d1b82 100644
--- a/src/core/compositor/delegated_frame_node.cpp
+++ b/src/core/compositor/delegated_frame_node.cpp
@@ -195,12 +195,10 @@ public:
{
Q_ASSERT(layer);
Q_ASSERT(m_nodeIterator != m_sceneGraphNodes->end());
- QSGInternalImageNode *imageNode = static_cast<QSGInternalImageNode*>(*m_nodeIterator++);
- imageNode->setTargetRect(rect);
- imageNode->setInnerTargetRect(rect);
- imageNode->setSubSourceRect(layer->convertToNormalizedSourceRect(sourceRect));
+ QSGImageNode *imageNode = static_cast<QSGImageNode*>(*m_nodeIterator++);
+ imageNode->setRect(rect);
+ imageNode->setSourceRect(sourceRect);
imageNode->setTexture(layer);
- imageNode->update();
}
void setupTextureContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect,
@@ -281,13 +279,10 @@ public:
QSGNode *layerChain) override
{
Q_ASSERT(layer);
- // Only QSGInternalImageNode currently supports QSGLayer textures.
- QSGInternalImageNode *imageNode = m_apiDelegate->createInternalImageNode();
- imageNode->setTargetRect(rect);
- imageNode->setInnerTargetRect(rect);
- imageNode->setSubSourceRect(layer->convertToNormalizedSourceRect(sourceRect));
+ QSGImageNode *imageNode = m_apiDelegate->createImageNode();
+ imageNode->setRect(rect);
+ imageNode->setSourceRect(sourceRect);
imageNode->setTexture(layer);
- imageNode->update();
layerChain->appendChildNode(imageNode);
m_sceneGraphNodes->append(imageNode);
@@ -953,7 +948,7 @@ void DelegatedFrameNode::handleQuad(
initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate, GL_TEXTURE_EXTERNAL_OES));
QMatrix4x4 qMatrix;
- convertToQt(squad->matrix.matrix(), qMatrix);
+// convertToQt(squad->matrix.matrix(), qMatrix);
nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), qMatrix, currentLayerChain);
break;
#endif // GL_OES_EGL_image_external
diff --git a/src/core/config/common.pri b/src/core/config/common.pri
index fce89f576..edebdb33c 100644
--- a/src/core/config/common.pri
+++ b/src/core/config/common.pri
@@ -12,6 +12,7 @@ gn_args += \
enable_nacl=false \
enable_remoting=false \
enable_reporting=false \
+ enable_resource_whitelist_generation=false \
enable_swiftshader=false \
enable_web_auth=false \
enable_web_speech=false \
@@ -93,7 +94,7 @@ CONFIG(release, debug|release) {
CONFIG(debug, debug|release) {
gn_args += is_debug=true
gn_args += use_debug_fission=false
- # MSVC requires iterator debug to always match and Qt has leaves it default on.
+ # MSVC requires iterator debug to always match and Qt leaves it default on.
msvc: gn_args += enable_iterator_debugging=true
# We also can not have optimized V8 binaries for MSVC as iterator debugging
@@ -101,7 +102,7 @@ CONFIG(debug, debug|release) {
msvc|v8base_debug: gn_args += v8_optimized_debug=false
}
-!webcore_debug: gn_args += remove_webcore_debug_symbols=true
+!webcore_debug: gn_args += blink_symbol_level=0
!v8base_debug: gn_args += remove_v8base_debug_symbols=true
# Compiling with -Os makes a huge difference in binary size
diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri
index c536b2555..998aedc40 100644
--- a/src/core/config/linux.pri
+++ b/src/core/config/linux.pri
@@ -17,6 +17,7 @@ gn_args += \
use_sysroot=false \
enable_session_service=false \
is_cfi=false \
+ strip_absolute_paths_from_debug_symbols=false \
toolkit_views=false \
use_ozone=true \
ozone_auto_platforms=false \
diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri
index e49df90e7..3f2fe9c0a 100644
--- a/src/core/config/mac_osx.pri
+++ b/src/core/config/mac_osx.pri
@@ -24,6 +24,7 @@ system("$${QMAKE_CLANG_PATH} --version")
gn_args += \
is_clang=true \
use_sysroot=false \
+ use_system_xcode=true \
clang_base_path=\"$${QMAKE_CLANG_DIR}\" \
clang_use_chrome_plugins=false \
mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index f47f85e93..ee420d258 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -87,7 +87,7 @@
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/sandbox/switches.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
-#include "third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom.h"
+#include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gl/gl_context.h"
@@ -195,8 +195,14 @@ public:
}
void* GetHandle() override { return m_handle; }
- // Qt currently never creates contexts using robustness attributes.
- bool WasAllocatedUsingRobustnessExtension() override { return false; }
+ bool WasAllocatedUsingRobustnessExtension() override
+ {
+#if QT_CONFIG(opengl)
+ if (QOpenGLContext *context = qt_gl_global_share_context())
+ return context->format().testOption(QSurfaceFormat::ResetNotification);
+#endif
+ return false;
+ }
// We don't care about the rest, this context shouldn't be used except for its handle.
bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override { Q_UNREACHABLE(); return false; }
@@ -331,7 +337,7 @@ void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, c
}
}
-content::QuotaPermissionContext *ContentBrowserClientQt::CreateQuotaPermissionContext()
+scoped_refptr<content::QuotaPermissionContext> ContentBrowserClientQt::CreateQuotaPermissionContext()
{
return new QuotaPermissionContextQt;
}
@@ -340,7 +346,7 @@ void ContentBrowserClientQt::GetQuotaSettings(content::BrowserContext* context,
content::StoragePartition* partition,
storage::OptionalQuotaSettingsCallback callback)
{
- storage::GetNominalDynamicSettings(partition->GetPath(), context->IsOffTheRecord(), std::move(callback));
+ storage::GetNominalDynamicSettings(partition->GetPath(), context->IsOffTheRecord(), storage::GetDefaultDiskInfoHelper(), std::move(callback));
}
// Copied from chrome/browser/ssl/ssl_error_handler.cc:
@@ -478,11 +484,12 @@ content::DevToolsManagerDelegate* ContentBrowserClientQt::GetDevToolsManagerDele
return new DevToolsManagerDelegateQt;
}
-content::PlatformNotificationService *ContentBrowserClientQt::GetPlatformNotificationService()
+content::PlatformNotificationService *ContentBrowserClientQt::GetPlatformNotificationService(content::BrowserContext *browser_context)
{
- if (!m_platformNotificationService)
- m_platformNotificationService = std::make_unique<PlatformNotificationServiceQt>();
- return m_platformNotificationService.get();
+ ProfileQt *profile = static_cast<ProfileQt *>(browser_context);
+ if (!profile)
+ return nullptr;
+ return profile->platformNotificationService();
}
// This is a really complicated way of doing absolutely nothing, but Mojo demands it:
@@ -524,7 +531,7 @@ public:
{ }
private:
- WEB_CONTENTS_USER_DATA_KEY_DECL()
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
explicit ServiceDriver(content::WebContents* /*web_contents*/) { }
friend class content::WebContentsUserData<ServiceDriver>;
mojo::BindingSet<blink::mojom::InsecureInputService> m_insecureInputServiceBindings;
@@ -536,7 +543,7 @@ void ContentBrowserClientQt::InitFrameInterfaces()
{
m_frameInterfaces = std::make_unique<service_manager::BinderRegistry>();
m_frameInterfacesParameterized = std::make_unique<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>>();
- m_frameInterfacesParameterized->AddInterface(base::Bind(&ServiceDriver::BindInsecureInputService));
+ m_frameInterfacesParameterized->AddInterface(base::BindRepeating(&ServiceDriver::BindInsecureInputService));
}
void ContentBrowserClientQt::BindInterfaceRequestFromFrame(content::RenderFrameHost* render_frame_host,
@@ -741,7 +748,9 @@ bool ContentBrowserClientQt::HandleExternalProtocol(
ui::PageTransition page_transition,
bool has_user_gesture,
const std::string &method,
- const net::HttpRequestHeaders &headers)
+ const net::HttpRequestHeaders &headers,
+ network::mojom::URLLoaderFactoryRequest *factory_request,
+ network::mojom::URLLoaderFactory *&out_factory)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Q_UNUSED(child_id);
@@ -759,18 +768,17 @@ bool ContentBrowserClientQt::HandleExternalProtocol(
return true;
}
-scoped_refptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegate(
- net::AuthChallengeInfo *authInfo,
- content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
- const content::GlobalRequestID &request_id,
+std::unique_ptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegate(
+ const net::AuthChallengeInfo &authInfo,
+ content::WebContents *web_contents,
+ const content::GlobalRequestID & /*request_id*/,
bool /*is_main_frame*/,
const GURL &url,
- scoped_refptr<net::HttpResponseHeaders> response_headers,
+ scoped_refptr<net::HttpResponseHeaders> /*response_headers*/,
bool first_auth_attempt,
LoginAuthRequiredCallback auth_required_callback)
{
- auto loginDelegate = base::MakeRefCounted<LoginDelegateQt>(authInfo, web_contents_getter, url, first_auth_attempt, std::move(auth_required_callback));
- loginDelegate->triggerDialog();
+ auto loginDelegate = std::make_unique<LoginDelegateQt>(authInfo, web_contents, url, first_auth_attempt, std::move(auth_required_callback));
return loginDelegate;
}
diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h
index 0b1c134cc..7f31b7c85 100644
--- a/src/core/content_browser_client_qt.h
+++ b/src/core/content_browser_client_qt.h
@@ -89,7 +89,7 @@ public:
void ResourceDispatcherHostCreated() override;
gl::GLShareGroup* GetInProcessGpuShareGroup() override;
content::MediaObserver* GetMediaObserver() override;
- content::QuotaPermissionContext *CreateQuotaPermissionContext() override;
+ scoped_refptr<content::QuotaPermissionContext> CreateQuotaPermissionContext() override;
void GetQuotaSettings(content::BrowserContext *context,
content::StoragePartition *partition,
storage::OptionalQuotaSettingsCallback callback) override;
@@ -108,7 +108,7 @@ public:
std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(content::ResourceContext *resource_context) override;
content::DevToolsManagerDelegate *GetDevToolsManagerDelegate() override;
- content::PlatformNotificationService *GetPlatformNotificationService() override;
+ content::PlatformNotificationService * GetPlatformNotificationService(content::BrowserContext *browser_context) override;
std::string GetApplicationLocale() override;
std::string GetAcceptLangs(content::BrowserContext* context) override;
@@ -185,11 +185,11 @@ public:
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
#endif
- scoped_refptr<content::LoginDelegate> CreateLoginDelegate(
- net::AuthChallengeInfo *auth_info,
- content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
- const content::GlobalRequestID &request_id,
- bool is_main_frame,
+ std::unique_ptr<content::LoginDelegate> CreateLoginDelegate(
+ const net::AuthChallengeInfo &auth_info,
+ content::WebContents *web_contents,
+ const content::GlobalRequestID& request_id,
+ bool is_request_for_main_frame,
const GURL &url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
bool first_auth_attempt,
@@ -203,7 +203,9 @@ public:
ui::PageTransition page_transition,
bool has_user_gesture,
const std::string &method,
- const net::HttpRequestHeaders &headers) override;
+ const net::HttpRequestHeaders &headers,
+ network::mojom::URLLoaderFactoryRequest *factory_request,
+ network::mojom::URLLoaderFactory *&out_factory) override;
static std::string getUserAgent();
@@ -216,7 +218,6 @@ private:
BrowserMainPartsQt* m_browserMainParts;
std::unique_ptr<content::ResourceDispatcherHostDelegate> m_resourceDispatcherHostDelegate;
- std::unique_ptr<content::PlatformNotificationService> m_platformNotificationService;
scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick;
std::unique_ptr<service_manager::BinderRegistry> m_frameInterfaces;
std::unique_ptr<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>> m_frameInterfacesParameterized;
diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp
index 57f8af63c..6df20896c 100644
--- a/src/core/content_main_delegate_qt.cpp
+++ b/src/core/content_main_delegate_qt.cpp
@@ -165,6 +165,11 @@ void ContentMainDelegateQt::PreSandboxStartup()
logging::SetMinLogLevel(level);
}
}
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+ if (parsedCommandLine->HasSwitch(switches::kSingleProcess))
+ setlocale(LC_NUMERIC, "C");
+#endif
}
content::ContentBrowserClient *ContentMainDelegateQt::CreateContentBrowserClient()
diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri
index 8ff79c782..908387788 100644
--- a/src/core/core_chromium.pri
+++ b/src/core/core_chromium.pri
@@ -104,6 +104,7 @@ SOURCES = \
profile_io_data_qt.cpp \
quota_permission_context_qt.cpp \
quota_request_controller_impl.cpp \
+ pref_service_adapter.cpp \
register_protocol_handler_request_controller_impl.cpp \
render_view_context_menu_qt.cpp \
render_widget_host_view_qt.cpp \
@@ -201,6 +202,7 @@ HEADERS = \
ozone/surface_factory_qt.h \
permission_manager_qt.h \
platform_notification_service_qt.h \
+ pref_service_adapter.h \
process_main.h \
profile_adapter.h \
profile_adapter_client.h \
@@ -244,7 +246,6 @@ HEADERS = \
web_engine_settings.h \
web_event_factory.h
-
qtConfig(webengine-ozone-x11) {
HEADERS += ozone/gl_ozone_glx_qt.h \
ozone/gl_surface_glx_qt.h
diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp
index 28af84bd3..d3f46f648 100644
--- a/src/core/devtools_frontend_qt.cpp
+++ b/src/core/devtools_frontend_qt.cpp
@@ -189,6 +189,8 @@ DevToolsFrontendQt *DevToolsFrontendQt::Show(QSharedPointer<WebContentsAdapter>
frontendAdapter->initialize(site.get());
}
+ frontendAdapter->setInspector(true);
+
content::WebContents *contents = frontendAdapter->webContents();
if (contents == inspectedContents) {
LOG(WARNING) << "You can not inspect yourself";
@@ -231,6 +233,8 @@ DevToolsFrontendQt::DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webCon
DevToolsFrontendQt::~DevToolsFrontendQt()
{
+ if (QSharedPointer<WebContentsAdapter> p = m_webContentsAdapter)
+ p->setInspector(false);
}
void DevToolsFrontendQt::Activate()
@@ -358,7 +362,7 @@ void DevToolsFrontendQt::HandleMessageFromDevToolsFrontend(const std::string &me
std::string method;
base::ListValue *params = nullptr;
base::DictionaryValue *dict = nullptr;
- std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+ std::unique_ptr<base::Value> parsed_message = base::JSONReader::ReadDeprecated(message);
if (!parsed_message || !parsed_message->GetAsDictionary(&dict) || !dict->GetString("method", &method))
return;
int request_id = 0;
@@ -371,7 +375,8 @@ void DevToolsFrontendQt::HandleMessageFromDevToolsFrontend(const std::string &me
return;
m_agentHost->DispatchProtocolMessage(this, protocol_message);
} else if (method == "loadCompleted") {
- web_contents()->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16("DevToolsAPI.setUseSoftMenu(true);"));
+ web_contents()->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16("DevToolsAPI.setUseSoftMenu(true);"),
+ base::NullCallback());
} else if (method == "loadNetworkResource" && params->GetSize() == 3) {
// TODO(pfeldman): handle some of the embedder messages in content.
std::string url;
@@ -449,7 +454,8 @@ void DevToolsFrontendQt::HandleMessageFromDevToolsFrontend(const std::string &me
} else if (method == "clearPreferences") {
ClearPreferences();
} else if (method == "requestFileSystems") {
- web_contents()->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16("DevToolsAPI.fileSystemsLoaded([]);"));
+ web_contents()->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16("DevToolsAPI.fileSystemsLoaded([]);"),
+ base::NullCallback());
} else if (method == "reattach") {
m_agentHost->DetachClient(this);
m_agentHost->AttachClient(this);
@@ -494,7 +500,7 @@ void DevToolsFrontendQt::DispatchProtocolMessage(content::DevToolsAgentHost *age
base::EscapeJSONString(message, true, &param);
std::string code = "DevToolsAPI.dispatchMessage(" + param + ");";
base::string16 javascript = base::UTF8ToUTF16(code);
- web_contents()->GetMainFrame()->ExecuteJavaScript(javascript);
+ web_contents()->GetMainFrame()->ExecuteJavaScript(javascript, base::NullCallback());
return;
}
@@ -505,7 +511,7 @@ void DevToolsFrontendQt::DispatchProtocolMessage(content::DevToolsAgentHost *age
std::string code = "DevToolsAPI.dispatchMessageChunk(" + param + ","
+ std::to_string(pos ? 0 : total_size) + ");";
base::string16 javascript = base::UTF8ToUTF16(code);
- web_contents()->GetMainFrame()->ExecuteJavaScript(javascript);
+ web_contents()->GetMainFrame()->ExecuteJavaScript(javascript, base::NullCallback());
}
}
@@ -529,7 +535,7 @@ void DevToolsFrontendQt::CallClientFunction(const std::string &function_name,
}
}
javascript.append(");");
- web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(javascript));
+ web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(javascript), base::NullCallback());
}
void DevToolsFrontendQt::SendMessageAck(int request_id, const base::Value *arg)
diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp
index 2af958068..34e290317 100644
--- a/src/core/download_manager_delegate_qt.cpp
+++ b/src/core/download_manager_delegate_qt.cpp
@@ -168,22 +168,7 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem*
QDir defaultDownloadDirectory(m_profileAdapter->downloadPath());
- QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(suggestedFilename));
- QString suggestedFilePath = suggestedFile.absoluteFilePath();
- base::FilePath tmpFilePath(toFilePath(suggestedFilePath).NormalizePathSeparatorsTo('/'));
-
- int uniquifier = base::GetUniquePathNumber(tmpFilePath, base::FilePath::StringType());
- if (uniquifier > 0)
- suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)).AsUTF8Unsafe());
- else if (uniquifier == -1) {
- base::Time::Exploded exploded;
- item->GetStartTime().LocalExplode(&exploded);
- std::string suffix = base::StringPrintf(
- " - %04d-%02d-%02dT%02d%02d%02d.%03d", exploded.year, exploded.month,
- exploded.day_of_month, exploded.hour, exploded.minute,
- exploded.second, exploded.millisecond);
- suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(suffix).AsUTF8Unsafe());
- }
+ QString suggestedFilePath = m_profileAdapter->determineDownloadPath(defaultDownloadDirectory.absolutePath(), suggestedFilename, item->GetStartTime().ToTimeT());
item->AddObserver(this);
QList<ProfileAdapterClient*> clients = m_profileAdapter->clients();
@@ -208,7 +193,9 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem*
false /* done */,
downloadType,
item->GetLastReason(),
- adapterClient
+ adapterClient,
+ suggestedFilename,
+ item->GetStartTime().ToTimeT()
};
for (ProfileAdapterClient *client : qAsConst(clients)) {
@@ -217,7 +204,7 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem*
break;
}
- suggestedFile.setFile(info.path);
+ QFileInfo suggestedFile(info.path);
if (info.accepted && !suggestedFile.absoluteDir().mkpath(suggestedFile.absolutePath())) {
qWarning("Creating download path failed, download cancelled: %s", suggestedFile.absolutePath().toUtf8().data());
@@ -278,7 +265,7 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content
acceptedByDefault = true;
}
if (QFileInfo(suggestedFilePath).isRelative()) {
- const QDir downloadDir(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
+ const QDir downloadDir(m_profileAdapter->downloadPath());
suggestedFilePath = downloadDir.absoluteFilePath(suggestedFilePath);
}
@@ -309,7 +296,9 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content
false, /* done */
ProfileAdapterClient::SavePage,
ProfileAdapterClient::NoReason,
- adapterClient
+ adapterClient,
+ QFileInfo(suggestedFilePath).fileName(),
+ time_t(QDateTime::currentMSecsSinceEpoch())
};
for (ProfileAdapterClient *client : qAsConst(clients)) {
@@ -375,7 +364,9 @@ void DownloadManagerDelegateQt::OnDownloadUpdated(download::DownloadItem *downlo
download->IsDone(),
0 /* downloadType (unused) */,
download->GetLastReason(),
- adapterClient
+ adapterClient,
+ toQt(download->GetSuggestedFilename()),
+ download->GetStartTime().ToTimeT()
};
for (ProfileAdapterClient *client : qAsConst(clients)) {
diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h
index 382c57524..6acfa42ce 100644
--- a/src/core/download_manager_delegate_qt.h
+++ b/src/core/download_manager_delegate_qt.h
@@ -109,6 +109,7 @@ private:
bool m_nextDownloadIsUserRequested;
friend class DownloadManagerDelegateInstance;
+ friend class ProfileAdapter;
DISALLOW_COPY_AND_ASSIGN(DownloadManagerDelegateQt);
};
diff --git a/src/core/extensions/component_extension_resource_manager_qt.cpp b/src/core/extensions/component_extension_resource_manager_qt.cpp
index 57e35c231..09311c764 100644
--- a/src/core/extensions/component_extension_resource_manager_qt.cpp
+++ b/src/core/extensions/component_extension_resource_manager_qt.cpp
@@ -60,7 +60,7 @@ ComponentExtensionResourceManagerQt::~ComponentExtensionResourceManagerQt() {}
bool ComponentExtensionResourceManagerQt::IsComponentExtensionResource(const base::FilePath &extension_path,
const base::FilePath &resource_path,
- int *resource_id) const
+ ComponentExtensionResourceInfo* resource_info) const
{
base::FilePath directory_path = extension_path;
base::FilePath resources_dir;
@@ -73,11 +73,13 @@ bool ComponentExtensionResourceManagerQt::IsComponentExtensionResource(const bas
relative_path = relative_path.Append(resource_path);
relative_path = relative_path.NormalizePathSeparators();
- std::map<base::FilePath, int>::const_iterator entry = path_to_resource_id_.find(relative_path);
- if (entry != path_to_resource_id_.end())
- *resource_id = entry->second;
+ auto entry = path_to_resource_info_.find(relative_path);
+ if (entry != path_to_resource_info_.end()) {
+ *resource_info = entry->second;
+ return true;
+ }
- return entry != path_to_resource_id_.end();
+ return false;
}
const ui::TemplateReplacements *ComponentExtensionResourceManagerQt::GetTemplateReplacementsForExtension(const std::string &) const
@@ -85,14 +87,15 @@ const ui::TemplateReplacements *ComponentExtensionResourceManagerQt::GetTemplate
return nullptr;
}
-void ComponentExtensionResourceManagerQt::AddComponentResourceEntries(const GritResourceMap *entries, size_t size)
+void ComponentExtensionResourceManagerQt::AddComponentResourceEntries(const GzippedGritResourceMap *entries, size_t size)
{
for (size_t i = 0; i < size; ++i) {
base::FilePath resource_path = base::FilePath().AppendASCII(entries[i].name);
resource_path = resource_path.NormalizePathSeparators();
- DCHECK(path_to_resource_id_.find(resource_path) == path_to_resource_id_.end());
- path_to_resource_id_[resource_path] = entries[i].value;
+ DCHECK(!base::ContainsKey(path_to_resource_info_, resource_path));
+ path_to_resource_info_[resource_path] = { entries[i].value,
+ entries[i].gzipped };
}
}
diff --git a/src/core/extensions/component_extension_resource_manager_qt.h b/src/core/extensions/component_extension_resource_manager_qt.h
index 2d858630f..c44c23439 100644
--- a/src/core/extensions/component_extension_resource_manager_qt.h
+++ b/src/core/extensions/component_extension_resource_manager_qt.h
@@ -49,7 +49,7 @@
#include "base/files/file_path.h"
#include "extensions/browser/component_extension_resource_manager.h"
-struct GritResourceMap;
+struct GzippedGritResourceMap;
namespace extensions {
@@ -62,15 +62,15 @@ public:
// Overridden from ComponentExtensionResourceManager:
bool IsComponentExtensionResource(const base::FilePath &extension_path,
const base::FilePath &resource_path,
- int *resource_id) const override;
+ ComponentExtensionResourceInfo *resource_info) const override;
const ui::TemplateReplacements *GetTemplateReplacementsForExtension(const std::string& extension_id) const override;
private:
- void AddComponentResourceEntries(const GritResourceMap* entries, size_t size);
+ void AddComponentResourceEntries(const GzippedGritResourceMap* entries, size_t size);
// A map from a resource path to the resource ID. Used by
// IsComponentExtensionResource.
- std::map<base::FilePath, int> path_to_resource_id_;
+ std::map<base::FilePath, ComponentExtensionResourceInfo> path_to_resource_info_;
DISALLOW_COPY_AND_ASSIGN(ComponentExtensionResourceManagerQt);
};
diff --git a/src/core/extensions/extension_system_qt.h b/src/core/extensions/extension_system_qt.h
index 0ebe1d044..712e0104d 100644
--- a/src/core/extensions/extension_system_qt.h
+++ b/src/core/extensions/extension_system_qt.h
@@ -49,12 +49,12 @@
#include <string>
+#include "base/one_shot_event.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension_set.h"
-#include "extensions/common/one_shot_event.h"
namespace extensions {
@@ -120,7 +120,7 @@ public:
void Init(bool extensions_enabled);
- const OneShotEvent &ready() const override { return ready_; }
+ const base::OneShotEvent &ready() const override { return ready_; }
private:
void OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension);
@@ -141,7 +141,7 @@ private:
// For verifying the contents of extensions read from disk.
scoped_refptr<ContentVerifier> content_verifier_;
- OneShotEvent ready_;
+ base::OneShotEvent ready_;
content::BrowserContext *browser_context_;
scoped_refptr<ValueStoreFactory> store_factory_;
diff --git a/src/core/extensions/extension_web_contents_observer_qt.h b/src/core/extensions/extension_web_contents_observer_qt.h
index 267a1095c..5f32562fc 100644
--- a/src/core/extensions/extension_web_contents_observer_qt.h
+++ b/src/core/extensions/extension_web_contents_observer_qt.h
@@ -67,7 +67,7 @@ public:
private:
friend class content::WebContentsUserData<ExtensionWebContentsObserverQt>;
- WEB_CONTENTS_USER_DATA_KEY_DECL()
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserverQt);
};
diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp
index 8bba4128f..fc1def3ca 100644
--- a/src/core/extensions/extensions_browser_client_qt.cpp
+++ b/src/core/extensions/extensions_browser_client_qt.cpp
@@ -69,6 +69,7 @@
#include "net/base/completion_once_callback.h"
#include "net/base/mime_util.h"
#include "net/url_request/url_request_simple_job.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
#include "ui/base/resource/resource_bundle.h"
#include "component_extension_resource_manager_qt.h"
@@ -108,12 +109,12 @@ public:
URLRequestResourceBundleJob(net::URLRequest *request,
net::NetworkDelegate *network_delegate,
const base::FilePath &filename,
- int resource_id,
+ const extensions::ComponentExtensionResourceInfo &resource_info,
const std::string &content_security_policy,
bool send_cors_header)
: net::URLRequestSimpleJob(request, network_delegate)
, filename_(filename)
- , resource_id_(resource_id)
+ , resource_info_(resource_info)
, weak_factory_(this)
{
// Leave cache headers out of resource bundle requests.
@@ -125,7 +126,7 @@ public:
net::CompletionOnceCallback callback) const override
{
const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- *data = rb.LoadDataResourceBytes(resource_id_);
+ *data = rb.LoadDataResourceBytes(resource_info_.resource_id);
// Add the Content-Length header now that we know the resource length.
response_info_.headers->AddHeader(
@@ -171,8 +172,8 @@ private:
// We need the filename of the resource to determine the mime type.
base::FilePath filename_;
- // The resource bundle id to load.
- int resource_id_;
+ // The resource to load.
+ const extensions::ComponentExtensionResourceInfo resource_info_;
net::HttpResponseInfo response_info_;
@@ -266,14 +267,14 @@ net::URLRequestJob *ExtensionsBrowserClientQt::MaybeCreateResourceBundleRequestJ
// extension relative path against resources_path.
resources_path.AppendRelativePath(directory_path, &relative_path)) {
base::FilePath request_path = extensions::file_util::ExtensionURLToRelativeFilePath(request->url());
- int resource_id = 0;
- if (GetComponentExtensionResourceManager()->IsComponentExtensionResource(directory_path, request_path, &resource_id)) {
+ ComponentExtensionResourceInfo resource_info;
+ if (GetComponentExtensionResourceManager()->IsComponentExtensionResource(directory_path, request_path, &resource_info)) {
relative_path = relative_path.Append(request_path);
relative_path = relative_path.NormalizePathSeparators();
return new URLRequestResourceBundleJob(request,
network_delegate,
relative_path,
- resource_id,
+ resource_info,
content_security_policy,
send_cors_header);
}
@@ -284,9 +285,9 @@ net::URLRequestJob *ExtensionsBrowserClientQt::MaybeCreateResourceBundleRequestJ
// Return the resource relative path and id for the given request.
base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::ResourceRequest &request,
const base::FilePath &extension_resources_path,
- int *resource_id) const
+ ComponentExtensionResourceInfo *resource_info) const
{
- *resource_id = 0;
+ *resource_info = {};
// |chrome_resources_path| corresponds to src/chrome/browser/resources in
// source tree.
base::FilePath resources_path;
@@ -303,10 +304,10 @@ base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::R
const base::FilePath request_relative_path =
extensions::file_util::ExtensionURLToRelativeFilePath(request.url);
if (!ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->IsComponentExtensionResource(
- extension_resources_path, request_relative_path, resource_id)) {
+ extension_resources_path, request_relative_path, resource_info)) {
return base::FilePath();
}
- DCHECK_NE(0, *resource_id);
+ DCHECK_NE(0, resource_info->resource_id);
return request_relative_path;
}
@@ -316,7 +317,7 @@ base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::R
void ExtensionsBrowserClientQt::LoadResourceFromResourceBundle(const network::ResourceRequest &request,
network::mojom::URLLoaderRequest loader,
const base::FilePath &resource_relative_path,
- int resource_id,
+ const ComponentExtensionResourceInfo &resource_info,
const std::string &content_security_policy,
network::mojom::URLLoaderClientPtr client,
bool send_cors_header)
diff --git a/src/core/extensions/extensions_browser_client_qt.h b/src/core/extensions/extensions_browser_client_qt.h
index f766b96a7..aa478461f 100644
--- a/src/core/extensions/extensions_browser_client_qt.h
+++ b/src/core/extensions/extensions_browser_client_qt.h
@@ -124,14 +124,14 @@ public:
// Return the resource relative path and id for the given request.
base::FilePath GetBundleResourcePath(const network::ResourceRequest &request,
const base::FilePath &extension_resources_path,
- int *resource_id) const override;
+ ComponentExtensionResourceInfo *resource_info) const override;
// Creates and starts a URLLoader to load an extension resource from the
// embedder's resource bundle (.pak) files. Used for component extensions.
void LoadResourceFromResourceBundle(const network::ResourceRequest &request,
network::mojom::URLLoaderRequest loader,
const base::FilePath &resource_relative_path,
- int resource_id,
+ const ComponentExtensionResourceInfo& resource_info,
const std::string &content_security_policy,
network::mojom::URLLoaderClientPtr client,
bool send_cors_header) override;
diff --git a/src/core/favicon_manager.cpp b/src/core/favicon_manager.cpp
index f7ba858c1..a06da6769 100644
--- a/src/core/favicon_manager.cpp
+++ b/src/core/favicon_manager.cpp
@@ -229,11 +229,10 @@ QList<FaviconInfo> FaviconManager::getFaviconInfoList(bool candidatesOnly) const
QList<FaviconInfo> faviconInfoList = m_faviconInfoMap.values();
if (candidatesOnly) {
- QMutableListIterator<FaviconInfo> it(faviconInfoList);
- while (it.hasNext()) {
- if (!it.next().candidate)
- it.remove();
- }
+ const auto hasNoCandidate = [](const FaviconInfo &info) { return !info.candidate; };
+ faviconInfoList.erase(std::remove_if(faviconInfoList.begin(), faviconInfoList.end(),
+ hasNoCandidate),
+ faviconInfoList.end());
}
return faviconInfoList;
@@ -362,6 +361,11 @@ void FaviconManager::generateCandidateIcon(bool touchIconsEnabled)
}
}
+void FaviconManager::copyStateFrom(FaviconManager *source)
+{
+ m_faviconInfoMap = source->m_faviconInfoMap;
+ m_icons = source->m_icons;
+}
FaviconInfo::FaviconInfo()
: url(QUrl())
diff --git a/src/core/favicon_manager.h b/src/core/favicon_manager.h
index 75d6aa75b..df74f6303 100644
--- a/src/core/favicon_manager.h
+++ b/src/core/favicon_manager.h
@@ -118,6 +118,7 @@ public:
QIcon getIcon(const QUrl &url = QUrl()) const;
FaviconInfo getFaviconInfo(const QUrl &) const;
QList<FaviconInfo> getFaviconInfoList(bool) const;
+ void copyStateFrom(FaviconManager *source);
private:
void update(const QList<FaviconInfo> &);
diff --git a/src/core/login_delegate_qt.cpp b/src/core/login_delegate_qt.cpp
index 0050f87c7..7970b9b46 100644
--- a/src/core/login_delegate_qt.cpp
+++ b/src/core/login_delegate_qt.cpp
@@ -72,36 +72,25 @@
namespace QtWebEngineCore {
-LoginDelegateQt::LoginDelegateQt(
- net::AuthChallengeInfo *authInfo,
- content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
- GURL url,
- bool first_auth_attempt,
- LoginAuthRequiredCallback auth_required_callback)
- : m_authInfo(authInfo)
+LoginDelegateQt::LoginDelegateQt(const net::AuthChallengeInfo &authInfo,
+ content::WebContents *web_contents,
+ GURL url,
+ bool /*first_auth_attempt*/,
+ LoginAuthRequiredCallback auth_required_callback)
+ : content::WebContentsObserver(web_contents)
+ , m_authInfo(authInfo)
, m_url(url)
, m_auth_required_callback(std::move(auth_required_callback))
- , m_webContentsGetter(web_contents_getter)
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-}
-
-LoginDelegateQt::~LoginDelegateQt()
-{
- Q_ASSERT(m_dialogController.isNull());
-}
-
-void LoginDelegateQt::triggerDialog()
+ , m_weakFactory(this)
{
base::PostTaskWithTraits(
FROM_HERE, { content::BrowserThread::UI },
- base::BindOnce(&LoginDelegateQt::triggerDialogOnUI, this));
+ base::BindOnce(&LoginDelegateQt::triggerDialog, m_weakFactory.GetWeakPtr()));
}
-void LoginDelegateQt::OnRequestCancelled()
+LoginDelegateQt::~LoginDelegateQt()
{
destroy();
- // TODO: this should close native dialog, since page can be navigated somewhere else
}
QUrl LoginDelegateQt::url() const
@@ -111,57 +100,55 @@ QUrl LoginDelegateQt::url() const
QString LoginDelegateQt::realm() const
{
- return QString::fromStdString(m_authInfo->realm);
+ return QString::fromStdString(m_authInfo.realm);
}
QString LoginDelegateQt::host() const
{
- return QString::fromStdString(m_authInfo->challenger.host());
+ return QString::fromStdString(m_authInfo.challenger.host());
}
int LoginDelegateQt::port() const
{
- return m_authInfo->challenger.port();
+ return m_authInfo.challenger.port();
}
bool LoginDelegateQt::isProxy() const
{
- return m_authInfo->is_proxy;
+ return m_authInfo.is_proxy;
}
-void LoginDelegateQt::triggerDialogOnUI()
+void LoginDelegateQt::triggerDialog()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (!web_contents())
+ return sendAuthToRequester(false, QString(), QString());
+
if (isProxy()) {
// workaround for 'ws' redefined symbols when including QNetworkProxy
auto authentication = WebEngineContext::qProxyNetworkAuthentication(host(), port());
- if (std::get<0>(authentication)) {
- base::PostTaskWithTraits(
- FROM_HERE, { content::BrowserThread::IO },
- base::BindOnce(&LoginDelegateQt::sendAuthToRequester, this, true,
- std::get<1>(authentication), std::get<2>(authentication)));
-
- return;
- }
+ if (std::get<0>(authentication))
+ return sendAuthToRequester(true, std::get<1>(authentication), std::get<2>(authentication));
}
- content::WebContentsImpl *webContents =
- static_cast<content::WebContentsImpl *>(m_webContentsGetter.Run());
+ content::WebContentsImpl *webContents = static_cast<content::WebContentsImpl *>(web_contents());
if (!webContents)
return;
WebContentsAdapterClient *client = WebContentsViewQt::from(webContents->GetView())->client();
- AuthenticationDialogControllerPrivate *dialogControllerData = new AuthenticationDialogControllerPrivate(this);
+ AuthenticationDialogControllerPrivate *dialogControllerData = new AuthenticationDialogControllerPrivate(m_weakFactory.GetWeakPtr());
+ dialogControllerData->url = url();
+ dialogControllerData->host = host();
+ dialogControllerData->realm = realm();
+ dialogControllerData->isProxy = isProxy();
m_dialogController.reset(new AuthenticationDialogController(dialogControllerData));
client->authenticationRequired(m_dialogController);
}
void LoginDelegateQt::sendAuthToRequester(bool success, const QString &user, const QString &password)
{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
if (!m_auth_required_callback.is_null()) {
- if (success)
+ if (success && web_contents())
std::move(m_auth_required_callback).Run(net::AuthCredentials(toString16(user), toString16(password)));
else
std::move(m_auth_required_callback).Run(base::nullopt);
diff --git a/src/core/login_delegate_qt.h b/src/core/login_delegate_qt.h
index 3a9c073cd..20f302988 100644
--- a/src/core/login_delegate_qt.h
+++ b/src/core/login_delegate_qt.h
@@ -43,6 +43,7 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/login_delegate.h"
#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h"
#include "web_contents_adapter_client.h"
@@ -56,20 +57,17 @@ namespace QtWebEngineCore {
class AuthenticationDialogController;
-class LoginDelegateQt : public content::LoginDelegate {
+class LoginDelegateQt : public content::LoginDelegate,
+ public content::WebContentsObserver
+{
public:
- LoginDelegateQt(net::AuthChallengeInfo *authInfo,
- content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ LoginDelegateQt(const net::AuthChallengeInfo &authInfo,
+ content::WebContents *web_contents,
GURL url,
bool first_auth_attempt,
LoginAuthRequiredCallback auth_required_callback);
- ~LoginDelegateQt();
-
- void triggerDialog();
-
- // LoginDelegate implementation
- void OnRequestCancelled() override;
+ ~LoginDelegateQt() override;
QUrl url() const;
QString realm() const;
@@ -80,14 +78,14 @@ public:
void sendAuthToRequester(bool success, const QString &user, const QString &password);
private:
- void triggerDialogOnUI();
+ void triggerDialog();
void destroy();
- scoped_refptr<net::AuthChallengeInfo> m_authInfo;
+ net::AuthChallengeInfo m_authInfo;
GURL m_url;
LoginAuthRequiredCallback m_auth_required_callback;
- content::ResourceRequestInfo::WebContentsGetter m_webContentsGetter;
+ base::WeakPtrFactory<LoginDelegateQt> m_weakFactory;
// This member is used to keep authentication dialog controller alive until
// authorization is sent or cancelled.
diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp
index ecc46f244..55c0bb39b 100644
--- a/src/core/media_capture_devices_dispatcher.cpp
+++ b/src/core/media_capture_devices_dispatcher.cpp
@@ -45,6 +45,7 @@
#include "javascript_dialog_manager_qt.h"
#include "type_conversion.h"
+#include "web_contents_delegate_qt.h"
#include "web_contents_view_qt.h"
#include "web_engine_settings.h"
@@ -166,6 +167,40 @@ WebContentsAdapterClient::MediaRequestFlags mediaRequestFlagsForRequest(const co
return requestFlags;
}
+// Based on MediaStreamCaptureIndicator::UIDelegate
+class MediaStreamUIQt : public content::MediaStreamUI
+{
+public:
+ MediaStreamUIQt(content::WebContents *webContents, const blink::MediaStreamDevices &devices)
+ : m_delegate(static_cast<WebContentsDelegateQt *>(webContents->GetDelegate())->AsWeakPtr())
+ , m_devices(devices)
+ {
+ DCHECK(!m_devices.empty());
+ }
+
+ ~MediaStreamUIQt() override
+ {
+ if (m_started && m_delegate)
+ m_delegate->removeDevices(m_devices);
+ }
+
+private:
+ gfx::NativeViewId OnStarted(base::OnceClosure, base::RepeatingClosure) override
+ {
+ DCHECK(!m_started);
+ m_started = true;
+ if (m_delegate)
+ m_delegate->addDevices(m_devices);
+ return 0;
+ }
+
+ base::WeakPtr<WebContentsDelegateQt> m_delegate;
+ const blink::MediaStreamDevices m_devices;
+ bool m_started = false;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamUIQt);
+};
+
} // namespace
MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest(const content::MediaStreamRequest &request,
@@ -237,8 +272,12 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content:
base::Unretained(this), webContents));
}
- std::move(callback).Run(devices, devices.empty() ? blink::MEDIA_DEVICE_INVALID_STATE : blink::MEDIA_DEVICE_OK,
- std::unique_ptr<content::MediaStreamUI>());
+ if (devices.empty())
+ std::move(callback).Run(devices, blink::MEDIA_DEVICE_INVALID_STATE,
+ std::unique_ptr<content::MediaStreamUI>());
+ else
+ std::move(callback).Run(devices, blink::MEDIA_DEVICE_OK,
+ std::make_unique<MediaStreamUIQt>(webContents, devices));
}
MediaCaptureDevicesDispatcher *MediaCaptureDevicesDispatcher::GetInstance()
@@ -336,8 +375,12 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content::
getDevicesForDesktopCapture(&devices, mediaId, capture_audio);
- std::move(callback).Run(devices, devices.empty() ? blink::MEDIA_DEVICE_INVALID_STATE : blink::MEDIA_DEVICE_OK,
- std::unique_ptr<content::MediaStreamUI>());
+ if (devices.empty())
+ std::move(callback).Run(devices, blink::MEDIA_DEVICE_INVALID_STATE,
+ std::unique_ptr<content::MediaStreamUI>());
+ else
+ std::move(callback).Run(devices, blink::MEDIA_DEVICE_OK,
+ std::make_unique<MediaStreamUIQt>(webContents, devices));
}
void MediaCaptureDevicesDispatcher::enqueueMediaAccessRequest(content::WebContents *webContents,
diff --git a/src/core/net/client_cert_override.cpp b/src/core/net/client_cert_override.cpp
index 305f0cef0..afb7ab5af 100644
--- a/src/core/net/client_cert_override.cpp
+++ b/src/core/net/client_cert_override.cpp
@@ -78,9 +78,9 @@ public:
: net::ClientCertIdentity(std::move(cert)), m_key(std::move(key)) {}
~ClientCertIdentityOverride() override = default;
- void AcquirePrivateKey(const base::Callback<void(scoped_refptr<net::SSLPrivateKey>)> &private_key_callback) override
+ void AcquirePrivateKey(base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)> private_key_callback) override
{
- private_key_callback.Run(m_key);
+ std::move(private_key_callback).Run(m_key);
}
#if defined(OS_MACOSX)
@@ -125,29 +125,29 @@ net::ClientCertIdentityList ClientCertOverrideStore::GetClientCertsOnUIThread(co
}
void ClientCertOverrideStore::GetClientCertsReturn(const net::SSLCertRequestInfo &cert_request_info,
- const ClientCertListCallback &callback,
+ ClientCertListCallback callback,
net::ClientCertIdentityList &&result)
{
// Continue with native cert store if matching certificatse were not found in memory
if (result.empty() && m_nativeStore)
- m_nativeStore->GetClientCerts(cert_request_info, callback);
+ m_nativeStore->GetClientCerts(cert_request_info, std::move(callback));
else
- callback.Run(std::move(result));
+ std::move(callback).Run(std::move(result));
}
#endif // QT_CONFIG(ssl)
void ClientCertOverrideStore::GetClientCerts(const net::SSLCertRequestInfo &cert_request_info,
- const ClientCertListCallback &callback)
+ ClientCertListCallback callback)
{
#if QT_CONFIG(ssl)
// Access the user-provided data from the UI thread, but return on whatever thread this is.
if (base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, { content::BrowserThread::UI },
base::BindOnce(&ClientCertOverrideStore::GetClientCertsOnUIThread,
- base::Unretained(this), base::ConstRef(cert_request_info)),
+ base::Unretained(this), std::cref(cert_request_info)),
base::BindOnce(&ClientCertOverrideStore::GetClientCertsReturn,
- base::Unretained(this), base::ConstRef(cert_request_info), callback))
+ base::Unretained(this), std::cref(cert_request_info), std::move(callback)))
) {
return;
}
@@ -155,9 +155,9 @@ void ClientCertOverrideStore::GetClientCerts(const net::SSLCertRequestInfo &cert
// Continue with native cert store if we failed to post task
if (m_nativeStore)
- m_nativeStore->GetClientCerts(cert_request_info, callback);
+ m_nativeStore->GetClientCerts(cert_request_info, std::move(callback));
else
- callback.Run(net::ClientCertIdentityList());
+ std::move(callback).Run(net::ClientCertIdentityList());
}
// static
diff --git a/src/core/net/client_cert_override.h b/src/core/net/client_cert_override.h
index 35c1f96af..4f2734485 100644
--- a/src/core/net/client_cert_override.h
+++ b/src/core/net/client_cert_override.h
@@ -57,12 +57,12 @@ public:
ClientCertOverrideStore(ClientCertificateStoreData *storeData);
virtual ~ClientCertOverrideStore() override;
void GetClientCerts(const net::SSLCertRequestInfo &cert_request_info,
- const ClientCertListCallback &callback) override;
+ ClientCertListCallback callback) override;
private:
static std::unique_ptr<net::ClientCertStore> createNativeStore();
net::ClientCertIdentityList GetClientCertsOnUIThread(const net::SSLCertRequestInfo &request);
void GetClientCertsReturn(const net::SSLCertRequestInfo &cert_request_info,
- const ClientCertListCallback &callback,
+ ClientCertListCallback callback,
net::ClientCertIdentityList &&result);
ClientCertificateStoreData *m_storeData;
std::unique_ptr<net::ClientCertStore> m_nativeStore;
diff --git a/src/core/net/cookie_monster_delegate_qt.cpp b/src/core/net/cookie_monster_delegate_qt.cpp
index 3253b08b9..5f7b75f57 100644
--- a/src/core/net/cookie_monster_delegate_qt.cpp
+++ b/src/core/net/cookie_monster_delegate_qt.cpp
@@ -140,10 +140,29 @@ void CookieMonsterDelegateQt::deleteCookie(const QNetworkCookie &cookie, const Q
void CookieMonsterDelegateQt::DeleteCookieOnIOThread(const GURL& url, const std::string& cookie_name)
{
- if (m_cookieMonster)
- m_cookieMonster->DeleteCookieAsync(url, cookie_name, base::Closure());
+ if (m_cookieMonster) {
+ net::CookieMonster::GetCookieListCallback callback =
+ base::BindOnce(&CookieMonsterDelegateQt::GetCookiesToDeleteCallback, this, cookie_name);
+ m_cookieMonster->GetAllCookiesForURLAsync(url, std::move(callback));
+ }
}
+void CookieMonsterDelegateQt::GetCookiesToDeleteCallback(const std::string& cookie_name, const net::CookieList &cookies, const net::CookieStatusList &statusList)
+{
+ Q_UNUSED(statusList);
+ if (!m_cookieMonster)
+ return;
+
+ net::CookieList cookiesToDelete;
+ for (auto cookie : cookies) {
+ if (cookie.Name() == cookie_name)
+ cookiesToDelete.push_back(cookie);
+ }
+ for (auto cookie : cookiesToDelete)
+ m_cookieMonster->DeleteCanonicalCookieAsync(cookie, base::DoNothing());
+}
+
+
void CookieMonsterDelegateQt::deleteSessionCookies(quint64 callbackId)
{
Q_ASSERT(hasCookieMonster());
@@ -234,7 +253,7 @@ void CookieMonsterDelegateQt::OnCookieChanged(const net::CanonicalCookie& cookie
m_client->d_func()->onCookieChanged(toQt(cookie), cause != net::CookieChangeCause::INSERTED);
}
-void CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread(qint64 callbackId, const net::CookieList &cookies)
+void CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread(qint64 callbackId, const net::CookieList &cookies, const net::CookieStatusList &statusList)
{
QByteArray rawCookies;
for (auto &&cookie : cookies)
@@ -245,11 +264,11 @@ void CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread(qint64 callbackId,
base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId, rawCookies));
}
-void CookieMonsterDelegateQt::SetCookieCallbackOnIOThread(qint64 callbackId, bool success)
+void CookieMonsterDelegateQt::SetCookieCallbackOnIOThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status)
{
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, success));
+ base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, status));
}
void CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread(qint64 callbackId, uint numCookies)
@@ -265,10 +284,11 @@ void CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread(qint64 callbackId,
m_client->d_func()->onGetAllCallbackResult(callbackId, cookies);
}
-void CookieMonsterDelegateQt::SetCookieCallbackOnUIThread(qint64 callbackId, bool success)
+void CookieMonsterDelegateQt::SetCookieCallbackOnUIThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status)
{
if (m_client)
- m_client->d_func()->onSetCallbackResult(callbackId, success);
+ m_client->d_func()->onSetCallbackResult(callbackId,
+ status == net::CanonicalCookie::CookieInclusionStatus::INCLUDE);
}
void CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread(qint64 callbackId, uint numCookies)
diff --git a/src/core/net/cookie_monster_delegate_qt.h b/src/core/net/cookie_monster_delegate_qt.h
index 88e92b560..2ac04acb4 100644
--- a/src/core/net/cookie_monster_delegate_qt.h
+++ b/src/core/net/cookie_monster_delegate_qt.h
@@ -107,12 +107,13 @@ private:
void DeleteSessionCookiesOnIOThread(net::CookieMonster::DeleteCallback callback);
void DeleteAllOnIOThread(net::CookieMonster::DeleteCallback callback);
- void GetAllCookiesCallbackOnIOThread(qint64 callbackId, const net::CookieList &cookies);
- void SetCookieCallbackOnIOThread(qint64 callbackId, bool success);
+ void GetCookiesToDeleteCallback(const std::string& cookie_name, const net::CookieList &cookies, const net::CookieStatusList &statusList);
+ void GetAllCookiesCallbackOnIOThread(qint64 callbackId, const net::CookieList &cookies, const net::CookieStatusList &statusList);
+ void SetCookieCallbackOnIOThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status);
void DeleteCookiesCallbackOnIOThread(qint64 callbackId, uint numCookies);
void GetAllCookiesCallbackOnUIThread(qint64 callbackId, const QByteArray &cookies);
- void SetCookieCallbackOnUIThread(qint64 callbackId, bool success);
+ void SetCookieCallbackOnUIThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status);
void DeleteCookiesCallbackOnUIThread(qint64 callbackId, uint numCookies);
};
diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp
index 7f278fd92..68bf34d31 100644
--- a/src/core/net/network_delegate_qt.cpp
+++ b/src/core/net/network_delegate_qt.cpp
@@ -64,13 +64,13 @@ namespace QtWebEngineCore {
WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition)
{
+ if (ui::PageTransitionIsRedirect(transition))
+ return WebContentsAdapterClient::RedirectNavigation;
+
int32_t qualifier = ui::PageTransitionGetQualifier(transition);
if (qualifier & ui::PAGE_TRANSITION_FORWARD_BACK)
return WebContentsAdapterClient::BackForwardNavigation;
- // FIXME: Make redirects a separate type:
- if (qualifier & ui::PAGE_TRANSITION_CLIENT_REDIRECT)
- return WebContentsAdapterClient::OtherNavigation;
ui::PageTransition strippedTransition = ui::PageTransitionStripQualifier(transition);
@@ -90,7 +90,7 @@ WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::Page
static QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType)
{
- if (resourceType >= 0 && resourceType < content::ResourceType(QWebEngineUrlRequestInfo::ResourceTypeLast))
+ if (resourceType >= content::ResourceType::kMainFrame && resourceType <= content::ResourceType::kMaxValue)
return static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType);
return QWebEngineUrlRequestInfo::ResourceTypeUnknown;
}
@@ -109,9 +109,9 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Q_ASSERT(m_profileIOData);
- const content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request);
+ content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request);
- content::ResourceType resourceType = content::RESOURCE_TYPE_LAST_TYPE;
+ content::ResourceType resourceType = content::ResourceType::kMaxValue;
WebContentsAdapterClient::NavigationType navigationType = WebContentsAdapterClient::OtherNavigation;
if (resourceInfo) {
@@ -122,15 +122,18 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet
const QUrl qUrl = toQt(request->url());
QUrl firstPartyUrl = QUrl();
- if (resourceType == content::ResourceType::RESOURCE_TYPE_SUB_FRAME)
+ if (resourceType == content::ResourceType::kSubFrame)
firstPartyUrl = toQt(request->first_party_url());
else
firstPartyUrl = toQt(request->site_for_cookies());
+ const QUrl initiator = request->initiator().has_value() ? toQt(request->initiator()->GetURL()) : QUrl();
+
QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType),
toQt(navigationType),
qUrl,
firstPartyUrl,
+ initiator,
QByteArray::fromStdString(request->method()));
QWebEngineUrlRequestInfo requestInfo(infoPrivate);
diff --git a/src/core/net/url_request_custom_job.cpp b/src/core/net/url_request_custom_job.cpp
index cba9b4dc5..dd213d4f8 100644
--- a/src/core/net/url_request_custom_job.cpp
+++ b/src/core/net/url_request_custom_job.cpp
@@ -40,10 +40,13 @@
#include "url_request_custom_job.h"
#include "url_request_custom_job_proxy.h"
+#include "api/qwebengineurlscheme.h"
+#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
+#include "net/http/http_util.h"
#include <QIODevice>
@@ -62,6 +65,9 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request,
, m_pendingReadSize(0)
, m_pendingReadPos(0)
, m_pendingReadBuffer(nullptr)
+ , m_corsEnabled(QWebEngineUrlScheme::schemeByName(QByteArray::fromStdString(scheme))
+ .flags().testFlag(QWebEngineUrlScheme::CorsEnabled))
+ , m_httpStatusCode(500)
{
}
@@ -136,6 +142,26 @@ bool URLRequestCustomJob::GetCharset(std::string* charset)
return false;
}
+void URLRequestCustomJob::GetResponseInfo(HttpResponseInfo* info)
+{
+ // Based on net::URLRequestRedirectJob::StartAsync()
+
+ if (!m_corsEnabled)
+ return;
+
+ std::string headers;
+ headers += base::StringPrintf("HTTP/1.1 %i OK\n", m_httpStatusCode);
+ if (m_redirect.is_valid())
+ headers += base::StringPrintf("Location: %s\n", m_redirect.spec().c_str());
+ std::string origin;
+ if (request_->extra_request_headers().GetHeader("Origin", &origin)) {
+ headers += base::StringPrintf("Access-Control-Allow-Origin: %s\n", origin.c_str());
+ headers += "Access-Control-Allow-Credentials: true\n";
+ }
+
+ info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+}
+
bool URLRequestCustomJob::IsRedirectResponse(GURL* location, int* http_status_code, bool* /*insecure_scheme_was_upgraded*/)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
diff --git a/src/core/net/url_request_custom_job.h b/src/core/net/url_request_custom_job.h
index 16be76f29..e1e8e9fba 100644
--- a/src/core/net/url_request_custom_job.h
+++ b/src/core/net/url_request_custom_job.h
@@ -64,6 +64,7 @@ public:
int ReadRawData(net::IOBuffer *buf, int buf_size) override;
bool GetMimeType(std::string *mimeType) const override;
bool GetCharset(std::string *charset) override;
+ void GetResponseInfo(net::HttpResponseInfo* info) override;
bool IsRedirectResponse(GURL* location, int* http_status_code, bool* insecure_scheme_was_upgraded) override;
protected:
@@ -80,6 +81,8 @@ private:
int m_pendingReadSize;
int m_pendingReadPos;
net::IOBuffer *m_pendingReadBuffer;
+ const bool m_corsEnabled;
+ int m_httpStatusCode;
friend class URLRequestCustomJobProxy;
diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp
index 72d14450e..b9ccf7ea4 100644
--- a/src/core/net/url_request_custom_job_proxy.cpp
+++ b/src/core/net/url_request_custom_job_proxy.cpp
@@ -100,6 +100,7 @@ void URLRequestCustomJobProxy::reply(std::string mimeType, QIODevice *device)
m_job->set_expected_content_size(size);
if (m_job->m_device && m_job->m_device->isReadable()) {
m_started = true;
+ m_job->m_httpStatusCode = 200;
m_job->NotifyHeadersComplete();
} else {
fail(ERR_INVALID_URL);
@@ -114,6 +115,7 @@ void URLRequestCustomJobProxy::redirect(GURL url)
if (m_job->m_device || m_job->m_error)
return;
m_job->m_redirect = url;
+ m_job->m_httpStatusCode = 303;
m_started = true;
m_job->NotifyHeadersComplete();
}
@@ -138,6 +140,7 @@ void URLRequestCustomJobProxy::fail(int error)
if (!m_job)
return;
m_job->m_error = error;
+ m_job->m_httpStatusCode = 500;
if (m_job->m_device)
m_job->m_device->close();
if (!m_started)
diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp
index ec36e70d9..92bb8854f 100644
--- a/src/core/net/webui_controller_factory_qt.cpp
+++ b/src/core/net/webui_controller_factory_qt.cpp
@@ -52,7 +52,6 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/devtools_ui.h"
#include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h"
-#include "chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
@@ -129,8 +128,6 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co
// after the host name.
if (url.host() == chrome::kChromeUIQuotaInternalsHost)
return &NewWebUI<QuotaInternalsUI>;
- if (url.host_piece() == chrome::kChromeUITaskSchedulerInternalsHost)
- return &NewWebUI<TaskSchedulerInternalsUI>;
if (url.SchemeIs(content::kChromeDevToolsScheme)) {
// if (!DevToolsUIBindings::IsValidFrontendURL(url))
diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp
index c4a075544..9813a3256 100644
--- a/src/core/ozone/gl_context_qt.cpp
+++ b/src/core/ozone/gl_context_qt.cpp
@@ -163,6 +163,17 @@ QFunctionPointer GLContextHelper::getEglGetProcAddress()
return get_proc_address;
}
+bool GLContextHelper::isCreateContextRobustnessSupported()
+{
+#if QT_CONFIG(opengl)
+ if (QGuiApplication::platformName() == QLatin1String("offscreen"))
+ return false;
+
+ if (QOpenGLContext *context = qt_gl_global_share_context())
+ return context->format().testOption(QSurfaceFormat::ResetNotification);
+#endif
+ return false;
+}
QT_END_NAMESPACE
#if defined(OS_WIN)
diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h
index 59ee567aa..8559af313 100644
--- a/src/core/ozone/gl_context_qt.h
+++ b/src/core/ozone/gl_context_qt.h
@@ -64,6 +64,8 @@ public:
static void* getNativeDisplay();
static QFunctionPointer getGlXGetProcAddress();
static QFunctionPointer getEglGetProcAddress();
+ static bool isCreateContextRobustnessSupported();
+
private:
Q_INVOKABLE bool initializeContextOnBrowserThread(gl::GLContext* context, gl::GLSurface* surface, gl::GLContextAttribs attribs);
diff --git a/src/core/ozone/gl_ozone_glx_qt.cpp b/src/core/ozone/gl_ozone_glx_qt.cpp
index e3a4f4708..f934a5c80 100644
--- a/src/core/ozone/gl_ozone_glx_qt.cpp
+++ b/src/core/ozone/gl_ozone_glx_qt.cpp
@@ -111,8 +111,10 @@ void GLOzoneGLXQt::ShutdownGL() {
}
bool GLOzoneGLXQt::GetGLWindowSystemBindingInfo(
- gl::GLWindowSystemBindingInfo* info) {
- return gl::GetGLWindowSystemBindingInfoGLX(info);
+ const gl::GLVersionInfo &gl_info,
+ gl::GLWindowSystemBindingInfo *info)
+{
+ return gl::GetGLWindowSystemBindingInfoGLX(gl_info, info);
}
scoped_refptr<gl::GLContext> GLOzoneGLXQt::CreateGLContext(
diff --git a/src/core/ozone/gl_ozone_glx_qt.h b/src/core/ozone/gl_ozone_glx_qt.h
index ffbd60454..1596ea12f 100644
--- a/src/core/ozone/gl_ozone_glx_qt.h
+++ b/src/core/ozone/gl_ozone_glx_qt.h
@@ -60,7 +60,8 @@ public:
void SetDisabledExtensionsPlatform(
const std::string& disabled_extensions) override;
bool GetGLWindowSystemBindingInfo(
- gl::GLWindowSystemBindingInfo* info) override;
+ const gl::GLVersionInfo &gl_info,
+ gl::GLWindowSystemBindingInfo *info) override;
scoped_refptr<gl::GLContext> CreateGLContext(
gl::GLShareGroup* share_group,
diff --git a/src/core/ozone/gl_surface_egl_qt.cpp b/src/core/ozone/gl_surface_egl_qt.cpp
index 8715a5095..97c6cdee6 100644
--- a/src/core/ozone/gl_surface_egl_qt.cpp
+++ b/src/core/ozone/gl_surface_egl_qt.cpp
@@ -128,7 +128,7 @@ EGLDisplay GLSurfaceEGL::GetHardwareDisplay()
bool GLSurfaceEGL::IsCreateContextRobustnessSupported()
{
- return false;
+ return GLContextHelper::isCreateContextRobustnessSupported() && HasEGLExtension("EGL_EXT_create_context_robustness");
}
bool GLSurfaceEGL::IsCreateContextBindGeneratesResourceSupported()
@@ -164,6 +164,11 @@ bool GLSurfaceEGL::IsCreateContextClientArraysSupported()
return false;
}
+bool GLSurfaceEGL::IsPixelFormatFloatSupported()
+{
+ return false;
+}
+
void GLSurfaceEGL::ShutdownOneOff()
{
}
diff --git a/src/core/ozone/gl_surface_glx_qt.cpp b/src/core/ozone/gl_surface_glx_qt.cpp
index 24772889f..e150c940a 100644
--- a/src/core/ozone/gl_surface_glx_qt.cpp
+++ b/src/core/ozone/gl_surface_glx_qt.cpp
@@ -68,7 +68,7 @@ bool GLSurfaceGLX::IsCreateContextSupported()
bool GLSurfaceGLX::IsCreateContextRobustnessSupported()
{
- return false; // ExtensionsContain(g_extensions, "GLX_ARB_create_context_robustness");
+ return GLContextHelper::isCreateContextRobustnessSupported() && HasGLXExtension("GLX_ARB_create_context_robustness");
}
bool GLSurfaceGLX::IsEXTSwapControlSupported()
diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp
index 551ba888c..82f8cd0e5 100644
--- a/src/core/ozone/gl_surface_qt.cpp
+++ b/src/core/ozone/gl_surface_qt.cpp
@@ -107,7 +107,7 @@ bool GLSurfaceQt::IsOffscreen()
return true;
}
-gfx::SwapResult GLSurfaceQt::SwapBuffers(const PresentationCallback &callback)
+gfx::SwapResult GLSurfaceQt::SwapBuffers(PresentationCallback callback)
{
LOG(ERROR) << "Attempted to call SwapBuffers on a pbuffer.";
Q_UNREACHABLE();
diff --git a/src/core/ozone/gl_surface_qt.h b/src/core/ozone/gl_surface_qt.h
index 514527df9..cbdc8876a 100644
--- a/src/core/ozone/gl_surface_qt.h
+++ b/src/core/ozone/gl_surface_qt.h
@@ -57,7 +57,7 @@ public:
void *GetDisplay() override;
void *GetConfig() override;
bool IsOffscreen() override;
- gfx::SwapResult SwapBuffers(const PresentationCallback &callback) override;
+ gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
gfx::Size GetSize() override;
GLSurfaceFormat GetFormat() override;
diff --git a/src/core/platform_notification_service_qt.cpp b/src/core/platform_notification_service_qt.cpp
index f3457c7aa..d8abec17f 100644
--- a/src/core/platform_notification_service_qt.cpp
+++ b/src/core/platform_notification_service_qt.cpp
@@ -105,12 +105,13 @@ struct PersistentNotificationDelegate : UserNotificationController::Delegate {
};
-PlatformNotificationServiceQt::PlatformNotificationServiceQt() {}
+PlatformNotificationServiceQt::PlatformNotificationServiceQt(content::BrowserContext *browserContext)
+ : browser_context(browserContext)
+{}
PlatformNotificationServiceQt::~PlatformNotificationServiceQt() {}
void PlatformNotificationServiceQt::DisplayNotification(
- content::BrowserContext *browser_context,
const std::string &notification_id,
const GURL &origin,
const blink::PlatformNotificationData &notificationData,
@@ -131,7 +132,6 @@ void PlatformNotificationServiceQt::DisplayNotification(
}
void PlatformNotificationServiceQt::DisplayPersistentNotification(
- content::BrowserContext *browser_context,
const std::string &notification_id,
const GURL &service_worker_origin,
const GURL &origin,
@@ -151,9 +151,7 @@ void PlatformNotificationServiceQt::DisplayPersistentNotification(
client->showNotification(controller);
}
-void PlatformNotificationServiceQt::CloseNotification(
- content::BrowserContext *browser_context,
- const std::string &notification_id)
+void PlatformNotificationServiceQt::CloseNotification(const std::string &notification_id)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ProfileQt *profile = static_cast<ProfileQt*>(browser_context);
@@ -164,9 +162,7 @@ void PlatformNotificationServiceQt::CloseNotification(
notificationController->closeNotification();
}
-void PlatformNotificationServiceQt::ClosePersistentNotification(
- content::BrowserContext *browser_context,
- const std::string &notification_id)
+void PlatformNotificationServiceQt::ClosePersistentNotification(const std::string &notification_id)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ProfileQt *profile = static_cast<ProfileQt*>(browser_context);
@@ -177,26 +173,24 @@ void PlatformNotificationServiceQt::ClosePersistentNotification(
notificationController->closeNotification();
}
-void PlatformNotificationServiceQt::GetDisplayedNotifications(
- content::BrowserContext *browser_context,
- const DisplayedNotificationsCallback &callback)
+void PlatformNotificationServiceQt::GetDisplayedNotifications(DisplayedNotificationsCallback callback)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ProfileQt *profile = static_cast<ProfileQt *>(browser_context);
- std::unique_ptr<std::set<std::string>> movableStdStringSet = std::make_unique<std::set<std::string>>();
+ std::set<std::string> movableStdStringSet;
auto it = profile->profileAdapter()->persistentNotifications().constBegin();
const auto end = profile->profileAdapter()->persistentNotifications().constEnd();
while (it != end) {
if (it.value()->isShown())
- movableStdStringSet->insert(it.key().toStdString());
+ movableStdStringSet.insert(it.key().toStdString());
++it;
}
- callback.Run(std::move(movableStdStringSet), true /* supports_synchronization */);
+ std::move(callback).Run(std::move(movableStdStringSet), true /* supports_synchronization */);
}
-int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId(content::BrowserContext *browser_context)
+int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
auto prefs = static_cast<ProfileQt *>(browser_context)->GetPrefs();
@@ -205,4 +199,15 @@ int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId(content:
return nextId;
}
+void PlatformNotificationServiceQt::ScheduleTrigger(base::Time /*timestamp*/)
+{
+ Q_UNIMPLEMENTED();
+}
+
+base::Time PlatformNotificationServiceQt::ReadNextTriggerTimestamp()
+{
+ Q_UNIMPLEMENTED();
+ return base::Time::Max();
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/platform_notification_service_qt.h b/src/core/platform_notification_service_qt.h
index 66cee9ed0..12aa2619b 100644
--- a/src/core/platform_notification_service_qt.h
+++ b/src/core/platform_notification_service_qt.h
@@ -42,26 +42,28 @@
#include "content/public/browser/platform_notification_service.h"
+namespace content {
+class BrowserContext;
+}
+
namespace QtWebEngineCore {
class PlatformNotificationServiceQt : public content::PlatformNotificationService {
public:
- PlatformNotificationServiceQt();
+ PlatformNotificationServiceQt(content::BrowserContext *browserContext);
~PlatformNotificationServiceQt() override;
// Displays the notification described in |notification_data| to the user. A
// closure through which the notification can be closed will be stored in the
// |cancel_callback| argument. This method must be called on the UI thread.
- void DisplayNotification(content::BrowserContext* browser_context,
- const std::string& notification_id,
+ void DisplayNotification(const std::string& notification_id,
const GURL& origin,
const blink::PlatformNotificationData& notificationData,
const blink::NotificationResources& notificationResources) override;
// Displays the persistent notification described in |notification_data| to
// the user. This method must be called on the UI thread.
- void DisplayPersistentNotification(content::BrowserContext* browser_context,
- const std::string& notification_id,
+ void DisplayPersistentNotification(const std::string& notification_id,
const GURL& service_worker_origin,
const GURL& origin,
const blink::PlatformNotificationData& notification_data,
@@ -69,22 +71,27 @@ public:
// Closes the notification identified by |notification_id|.
// This method must be called on the UI thread.
- void CloseNotification(content::BrowserContext* browser_context, const std::string& notification_id) override;
+ void CloseNotification(const std::string& notification_id) override;
// Closes the persistent notification identified by |persistent_notification_id|.
// This method must be called on the UI thread.
- void ClosePersistentNotification(content::BrowserContext* browser_context, const std::string& notification_id) override;
+ void ClosePersistentNotification(const std::string& notification_id) override;
// Retrieves the ids of all currently displaying notifications and
// posts |callback| with the result.
- void GetDisplayedNotifications(content::BrowserContext* browser_context, const DisplayedNotificationsCallback& callback) override;
+ void GetDisplayedNotifications(DisplayedNotificationsCallback callback) override;
// Reads the value of the next persistent notification ID from the profile and
// increments the value, as it is called once per notification write.
- virtual int64_t ReadNextPersistentNotificationId(content::BrowserContext* browser_context) override;
+ int64_t ReadNextPersistentNotificationId() override;
+
+ void ScheduleTrigger(base::Time timestamp) override;
+ base::Time ReadNextTriggerTimestamp() override;
// Records a given notification to UKM.
- virtual void RecordNotificationUkmEvent(content::BrowserContext*, const content::NotificationDatabaseData&) override { }
+ void RecordNotificationUkmEvent(const content::NotificationDatabaseData&) override { }
+
+ content::BrowserContext *browser_context;
};
} // namespace QtWebEngineCore
diff --git a/src/core/pref_service_adapter.cpp b/src/core/pref_service_adapter.cpp
new file mode 100644
index 000000000..8a33a4b60
--- /dev/null
+++ b/src/core/pref_service_adapter.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pref_service_adapter.h"
+
+#include "command_line_pref_store_qt.h"
+#include "profile_adapter.h"
+#include "type_conversion.h"
+#include "web_engine_context.h"
+
+#include "content/public/browser/browser_thread.h"
+#include "components/prefs/pref_member.h"
+#include "components/prefs/in_memory_pref_store.h"
+#include "components/prefs/json_pref_store.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_service_factory.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/user_prefs/user_prefs.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "chrome/common/pref_names.h"
+#include "extensions/buildflags/buildflags.h"
+#include "content/public/browser/browser_context.h"
+
+#if QT_CONFIG(webengine_spellchecker)
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#include "components/spellcheck/browser/pref_names.h"
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "components/guest_view/browser/guest_view_manager.h"
+#include "extensions/browser/extension_protocols.h"
+#include "extensions/browser/pref_names.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/common/constants.h"
+#endif
+
+namespace {
+static const char kPrefMediaDeviceIDSalt[] = "qtwebengine.media_device_salt_id";
+}
+
+namespace QtWebEngineCore {
+
+void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ PrefServiceFactory factory;
+ factory.set_command_line_prefs(base::MakeRefCounted<CommandLinePrefStoreQt>(
+ WebEngineContext::commandLine()));
+
+ QString userPrefStorePath = profileAdapter.dataPath();
+ if (userPrefStorePath.isEmpty() || profileAdapter.isOffTheRecord()) {
+ factory.set_user_prefs(new InMemoryPrefStore);
+ } else {
+ userPrefStorePath += QDir::separator();
+ userPrefStorePath += QStringLiteral("user_prefs.json");
+ factory.set_user_prefs(base::MakeRefCounted<JsonPrefStore>(toFilePath(userPrefStorePath)));
+ }
+
+ PrefRegistrySimple *registry = new PrefRegistrySimple();
+ PrefProxyConfigTrackerImpl::RegisterPrefs(registry);
+
+#if QT_CONFIG(webengine_spellchecker)
+ // Initial spellcheck settings
+ registry->RegisterStringPref(prefs::kAcceptLanguages, std::string());
+ registry->RegisterListPref(spellcheck::prefs::kSpellCheckDictionaries);
+ registry->RegisterListPref(spellcheck::prefs::kSpellCheckForcedDictionaries);
+ registry->RegisterListPref(spellcheck::prefs::kSpellCheckBlacklistedDictionaries);
+ registry->RegisterStringPref(spellcheck::prefs::kSpellCheckDictionary, std::string());
+ registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckEnable, false);
+ registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckUseSpellingService, false);
+#endif // QT_CONFIG(webengine_spellchecker)
+ registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false);
+ registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000);
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ registry->RegisterDictionaryPref(extensions::pref_names::kExtensions);
+ registry->RegisterListPref(extensions::pref_names::kInstallAllowList);
+ registry->RegisterListPref(extensions::pref_names::kInstallDenyList);
+ registry->RegisterDictionaryPref(extensions::pref_names::kInstallForceList);
+ registry->RegisterDictionaryPref(extensions::pref_names::kLoginScreenExtensions);
+ registry->RegisterListPref(extensions::pref_names::kAllowedTypes);
+ registry->RegisterBooleanPref(extensions::pref_names::kStorageGarbageCollect, false);
+ registry->RegisterListPref(extensions::pref_names::kAllowedInstallSites);
+ registry->RegisterStringPref(extensions::pref_names::kLastChromeVersion, std::string());
+ registry->RegisterListPref(extensions::pref_names::kNativeMessagingBlacklist);
+ registry->RegisterListPref(extensions::pref_names::kNativeMessagingWhitelist);
+ registry->RegisterBooleanPref(extensions::pref_names::kNativeMessagingUserLevelHosts, true);
+ registry->RegisterBooleanPref(extensions::pref_names::kInsecureExtensionUpdatesEnabled, false);
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
+
+ // Media device salt id key
+ // Can't be a random value since every time we run the setup code the
+ // default value will be different. We'll need to initialize it later.
+ registry->RegisterStringPref(kPrefMediaDeviceIDSalt, std::string());
+
+ m_prefService = factory.Create(registry);
+
+ // Initialize salt value if none was stored before
+ if (m_prefService->GetString(kPrefMediaDeviceIDSalt).empty()) {
+ m_prefService->SetString(kPrefMediaDeviceIDSalt,
+ content::BrowserContext::CreateRandomMediaDeviceIDSalt());
+ }
+
+#if QT_CONFIG(webengine_spellchecker)
+ // Ignore stored values for these options to preserve backwards compatibility.
+ m_prefService->ClearPref(spellcheck::prefs::kSpellCheckEnable);
+ m_prefService->ClearPref(spellcheck::prefs::kSpellCheckDictionaries);
+#endif // QT_CONFIG(webengine_spellchecker)
+}
+
+void PrefServiceAdapter::commit()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Make sure modified preferences are written to disk
+ m_prefService->CommitPendingWrite();
+}
+
+PrefService* PrefServiceAdapter::prefService()
+{
+ return m_prefService.get();
+}
+
+const PrefService* PrefServiceAdapter::prefService() const
+{
+ return m_prefService.get();
+}
+
+std::string PrefServiceAdapter::mediaDeviceIdSalt() const
+{
+ return m_prefService->GetString(kPrefMediaDeviceIDSalt);
+}
+
+#if QT_CONFIG(webengine_spellchecker)
+
+void PrefServiceAdapter::setSpellCheckLanguages(const QStringList &languages)
+{
+ StringListPrefMember dictionaries_pref;
+ dictionaries_pref.Init(spellcheck::prefs::kSpellCheckDictionaries, m_prefService.get());
+ std::vector<std::string> dictionaries;
+ dictionaries.reserve(languages.size());
+ for (const auto &language : languages)
+ dictionaries.push_back(language.toStdString());
+ dictionaries_pref.SetValue(dictionaries);
+}
+
+QStringList PrefServiceAdapter::spellCheckLanguages() const
+{
+ QStringList spellcheck_dictionaries;
+ for (const auto &value : *m_prefService->GetList(spellcheck::prefs::kSpellCheckDictionaries)) {
+ std::string dictionary;
+ if (value.GetAsString(&dictionary))
+ spellcheck_dictionaries.append(QString::fromStdString(dictionary));
+ }
+
+ return spellcheck_dictionaries;
+}
+
+void PrefServiceAdapter::setSpellCheckEnabled(bool enabled)
+{
+ m_prefService->SetBoolean(spellcheck::prefs::kSpellCheckEnable, enabled);
+}
+
+bool PrefServiceAdapter::isSpellCheckEnabled() const
+{
+ return m_prefService->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
+}
+
+#endif // QT_CONFIG(webengine_spellchecker)
+}
diff --git a/src/core/pref_service_adapter.h b/src/core/pref_service_adapter.h
new file mode 100644
index 000000000..83f6a322e
--- /dev/null
+++ b/src/core/pref_service_adapter.h
@@ -0,0 +1,85 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PREF_SRVICE_ADAPTER_H
+#define PREF_SERIVE_ADAPTER_H
+
+#include "components/prefs/pref_service.h"
+#include "qtwebenginecoreglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+class ProfileAdapter;
+
+namespace QtWebEngineCore {
+
+class ProfileAdapter;
+
+// PrefServiceAdapter manages the collection of tunable preferences.
+// Any new preference should be defined and register in the registry
+// before it can be used
+class PrefServiceAdapter
+{
+public:
+
+ PrefServiceAdapter() = default;
+
+ void setup(const ProfileAdapter &adapter);
+ void commit();
+ PrefService *prefService();
+ const PrefService *prefService() const;
+ std::string mediaDeviceIdSalt() const;
+
+#if QT_CONFIG(webengine_spellchecker)
+ void setSpellCheckLanguages(const QStringList &languages);
+ QStringList spellCheckLanguages() const;
+ void setSpellCheckEnabled(bool enabled);
+ bool isSpellCheckEnabled() const;
+#endif // QT_CONFIG(webengine_spellchecker)
+
+private:
+ std::unique_ptr<PrefService> m_prefService;
+};
+
+}
+
+#endif // PREF_SERIVE_ADAPTER_H
diff --git a/src/core/printing/print_view_manager_qt.cpp b/src/core/printing/print_view_manager_qt.cpp
index b6a2b42ec..7d8039100 100644
--- a/src/core/printing/print_view_manager_qt.cpp
+++ b/src/core/printing/print_view_manager_qt.cpp
@@ -98,7 +98,6 @@ static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data,
const base::FilePath &path,
const QtWebEngineCore::PrintViewManagerQt::PrintToPDFFileCallback &saveCallback)
{
- base::AssertBlockingAllowedDeprecated();
DCHECK_GT(data->size(), 0U);
printing::MetafileSkia metafile;
diff --git a/src/core/printing/print_view_manager_qt.h b/src/core/printing/print_view_manager_qt.h
index 20b988200..14f2688dd 100644
--- a/src/core/printing/print_view_manager_qt.h
+++ b/src/core/printing/print_view_manager_qt.h
@@ -137,7 +137,7 @@ private:
void PrintPreviewDone();
private:
- WEB_CONTENTS_USER_DATA_KEY_DECL()
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
content::RenderFrameHost *m_printPreviewRfh;
base::FilePath m_pdfOutputPath;
PrintToPDFCallback m_pdfPrintCallback;
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index ebb533206..551663cf0 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -57,6 +57,8 @@
#include "web_engine_context.h"
#include "web_contents_adapter_client.h"
+#include "base/files/file_util.h"
+#include "base/time/time_to_iso8601.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -126,6 +128,7 @@ void ProfileAdapter::setStorageName(const QString &storageName)
return;
m_name = storageName;
if (!m_offTheRecord) {
+ m_profile->setupPrefService();
if (m_profile->m_urlRequestContextGetter.get())
m_profile->m_profileIOData->updateStorageSettings();
if (m_visitedLinksManager)
@@ -138,6 +141,7 @@ void ProfileAdapter::setOffTheRecord(bool offTheRecord)
if (offTheRecord == m_offTheRecord)
return;
m_offTheRecord = offTheRecord;
+ m_profile->setupPrefService();
if (m_profile->m_urlRequestContextGetter.get())
m_profile->m_profileIOData->updateStorageSettings();
if (m_visitedLinksManager)
@@ -263,6 +267,7 @@ void ProfileAdapter::setDataPath(const QString &path)
return;
m_dataPath = path;
if (!m_offTheRecord) {
+ m_profile->setupPrefService();
if (m_profile->m_urlRequestContextGetter.get())
m_profile->m_profileIOData->updateStorageSettings();
if (m_visitedLinksManager)
@@ -310,16 +315,6 @@ QString ProfileAdapter::cookiesPath() const
return QString();
}
-QString ProfileAdapter::channelIdPath() const
-{
- if (m_offTheRecord)
- return QString();
- QString basePath = dataPath();
- if (!basePath.isEmpty())
- return basePath % QLatin1String("/Origin Bound Certs");
- return QString();
-}
-
QString ProfileAdapter::httpCachePath() const
{
if (m_offTheRecord)
@@ -595,7 +590,7 @@ void ProfileAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage)
std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
for (content::WebContentsImpl *web_contents : list) {
if (web_contents->GetBrowserContext() == m_profile.data()) {
- content::RendererPreferences* rendererPrefs = web_contents->GetMutableRendererPrefs();
+ blink::mojom::RendererPreferences *rendererPrefs = web_contents->GetMutableRendererPrefs();
rendererPrefs->accept_languages = httpAcceptLanguageWithoutQualities().toStdString();
web_contents->GetRenderViewHost()->SyncRendererPrefs();
}
@@ -616,14 +611,14 @@ void ProfileAdapter::clearHttpCache()
void ProfileAdapter::setSpellCheckLanguages(const QStringList &languages)
{
#if QT_CONFIG(webengine_spellchecker)
- m_profile->setSpellCheckLanguages(languages);
+ m_profile->prefServiceAdapter().setSpellCheckLanguages(languages);
#endif
}
QStringList ProfileAdapter::spellCheckLanguages() const
{
#if QT_CONFIG(webengine_spellchecker)
- return m_profile->spellCheckLanguages();
+ return m_profile->prefServiceAdapter().spellCheckLanguages();
#else
return QStringList();
#endif
@@ -632,14 +627,14 @@ QStringList ProfileAdapter::spellCheckLanguages() const
void ProfileAdapter::setSpellCheckEnabled(bool enabled)
{
#if QT_CONFIG(webengine_spellchecker)
- m_profile->setSpellCheckEnabled(enabled);
+ m_profile->prefServiceAdapter().setSpellCheckEnabled(enabled);
#endif
}
bool ProfileAdapter::isSpellCheckEnabled() const
{
#if QT_CONFIG(webengine_spellchecker)
- return m_profile->isSpellCheckEnabled();
+ return m_profile->prefServiceAdapter().isSpellCheckEnabled();
#else
return false;
#endif
@@ -690,6 +685,34 @@ bool ProfileAdapter::isUsedForGlobalCertificateVerification() const
return m_usedForGlobalCertificateVerification;
}
+QString ProfileAdapter::determineDownloadPath(const QString &downloadDirectory, const QString &suggestedFilename, const time_t &startTime)
+{
+ QFileInfo suggestedFile(QDir(downloadDirectory).absoluteFilePath(suggestedFilename));
+ QString suggestedFilePath = suggestedFile.absoluteFilePath();
+ base::FilePath tmpFilePath(toFilePath(suggestedFilePath).NormalizePathSeparatorsTo('/'));
+
+ int uniquifier = base::GetUniquePathNumber(tmpFilePath, base::FilePath::StringType());
+ if (uniquifier > 0)
+ suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)).AsUTF8Unsafe());
+ else if (uniquifier == -1) {
+ base::Time::Exploded exploded;
+ base::Time::FromTimeT(startTime).LocalExplode(&exploded);
+ std::string suffix = base::StringPrintf(
+ " - %04d-%02d-%02dT%02d%02d%02d.%03d", exploded.year, exploded.month,
+ exploded.day_of_month, exploded.hour, exploded.minute,
+ exploded.second, exploded.millisecond);
+ suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(suffix).AsUTF8Unsafe());
+ }
+ return suggestedFilePath;
+}
+
+QString ProfileAdapter::updateDownloadPath(int downloadId, const QString &directory, const QString &fileName)
+{
+ download::DownloadItem *download = m_downloadManagerDelegate->findDownloadById(downloadId);
+ Q_ASSERT(download);
+ return determineDownloadPath(directory, fileName, download->GetStartTime().ToTimeT());
+}
+
#if QT_CONFIG(ssl)
QWebEngineClientCertificateStore *ProfileAdapter::clientCertificateStore()
{
diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h
index 1f94f59a9..01477d0d9 100644
--- a/src/core/profile_adapter.h
+++ b/src/core/profile_adapter.h
@@ -124,7 +124,6 @@ public:
QString httpCachePath() const;
QString cookiesPath() const;
- QString channelIdPath() const;
QString httpUserAgent() const;
void setHttpUserAgent(const QString &userAgent);
@@ -214,6 +213,9 @@ public:
QHash<QByteArray, QSharedPointer<UserNotificationController>> &persistentNotifications()
{ return m_persistentNotifications; }
+ QString determineDownloadPath(const QString &downloadDirectory, const QString &suggestedFilename, const time_t &startTime);
+ QString updateDownloadPath(int downloadId, const QString &directory, const QString &filename);
+
private:
void updateCustomUrlSchemeHandlers();
void resetVisitedLinksManager();
diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h
index b463043da..dc0f508a1 100644
--- a/src/core/profile_adapter_client.h
+++ b/src/core/profile_adapter_client.h
@@ -55,6 +55,7 @@
#include <QSharedPointer>
#include <QString>
#include <QUrl>
+#include <time.h>
namespace QtWebEngineCore {
@@ -138,6 +139,8 @@ public:
int downloadType;
int downloadInterruptReason;
WebContentsAdapterClient *page;
+ QString suggestedFileName;
+ time_t startTime;
};
virtual ~ProfileAdapterClient() { }
diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp
index 96248a55a..9a5058a5a 100644
--- a/src/core/profile_io_data_qt.cpp
+++ b/src/core/profile_io_data_qt.cpp
@@ -55,7 +55,7 @@
#include "net/cert/ct_log_verifier.h"
#include "net/cert/ct_policy_enforcer.h"
#include "net/cert/multi_log_ct_verifier.h"
-#include "net/extras/sqlite/sqlite_channel_id_store.h"
+#include "net/dns/host_resolver_manager.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_auth_scheme.h"
#include "net/http/http_auth_preferences.h"
@@ -68,6 +68,7 @@
#include "net/proxy_resolution/proxy_config_service.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
#include "net/ssl/channel_id_service.h"
+#include "net/ssl/default_channel_id_store.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/file_protocol_handler.h"
@@ -106,8 +107,6 @@ static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &f
{
if (first.ignore_certificate_errors != second.ignore_certificate_errors)
return false;
- if (first.enable_channel_id != second.enable_channel_id)
- return false;
return true;
}
@@ -118,14 +117,14 @@ static bool doNetworkSessionContextMatch(const net::HttpNetworkSession::Context
return false;
if (first.cert_verifier != second.cert_verifier)
return false;
- if (first.channel_id_service != second.channel_id_service)
- return false;
if (first.proxy_resolution_service != second.proxy_resolution_service)
return false;
if (first.ssl_config_service != second.ssl_config_service)
return false;
if (first.http_auth_handler_factory != second.http_auth_handler_factory)
return false;
+ if (first.http_user_agent_settings != second.http_user_agent_settings)
+ return false;
if (first.http_server_properties != second.http_server_properties)
return false;
if (first.host_resolver != second.host_resolver)
@@ -142,10 +141,10 @@ static net::HttpNetworkSession::Context generateNetworkSessionContext(net::URLRe
net::HttpNetworkSession::Context network_session_context;
network_session_context.transport_security_state = urlRequestContext->transport_security_state();
network_session_context.cert_verifier = urlRequestContext->cert_verifier();
- network_session_context.channel_id_service = urlRequestContext->channel_id_service();
network_session_context.proxy_resolution_service = urlRequestContext->proxy_resolution_service();
network_session_context.ssl_config_service = urlRequestContext->ssl_config_service();
network_session_context.http_auth_handler_factory = urlRequestContext->http_auth_handler_factory();
+ network_session_context.http_user_agent_settings = urlRequestContext->http_user_agent_settings();
network_session_context.http_server_properties = urlRequestContext->http_server_properties();
network_session_context.host_resolver = urlRequestContext->host_resolver();
network_session_context.cert_transparency_verifier = urlRequestContext->cert_transparency_verifier();
@@ -296,6 +295,7 @@ void ProfileIODataQt::generateStorage()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Q_ASSERT(m_urlRequestContext);
+// Q_ASSERT(!m_mutex.tryLock()); // assert locked
// We must stop all requests before deleting their backends.
if (m_storage) {
@@ -337,7 +337,11 @@ void ProfileIODataQt::generateStorage()
ct_verifier->AddLogs(ct_logs);
m_storage->set_cert_transparency_verifier(std::move(ct_verifier));
m_storage->set_ct_policy_enforcer(base::WrapUnique(new net::DefaultCTPolicyEnforcer()));
- m_storage->set_host_resolver(net::HostResolver::CreateDefaultResolver(NULL));
+// static std::unique_ptr<net::HostResolverManager> s_hostResolverManager =
+// std::make_unique<net::HostResolverManager>(net::HostResolver::Options(), nullptr);
+// m_storage->set_host_resolver(net::HostResolver::CreateResolver(s_hostResolverManager.get()));
+ m_storage->set_host_resolver(net::HostResolver::CreateStandaloneResolver(nullptr));
+
m_storage->set_ssl_config_service(std::make_unique<net::SSLConfigServiceDefaults>());
if (!m_httpAuthPreferences) {
m_httpAuthPreferences.reset(new net::HttpAuthPreferences());
@@ -345,7 +349,6 @@ void ProfileIODataQt::generateStorage()
m_httpAuthPreferences->SetServerWhitelist(serverWhitelist);
}
m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(
- m_urlRequestContext->host_resolver(),
m_httpAuthPreferences.get()));
m_storage->set_transport_security_state(std::make_unique<net::TransportSecurityState>());
@@ -389,17 +392,9 @@ void ProfileIODataQt::generateCookieStore()
QMutexLocker lock(&m_mutex);
- scoped_refptr<net::SQLiteChannelIDStore> channel_id_db;
- if (!m_channelIdPath.isEmpty() && m_persistentCookiesPolicy != ProfileAdapter::NoPersistentCookies) {
- channel_id_db = new net::SQLiteChannelIDStore(
- toFilePath(m_channelIdPath),
- base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT}));
- }
-
+ // FIXME: Add code to remove the old database.
m_storage->set_channel_id_service(
- base::WrapUnique(new net::ChannelIDService(
- new net::DefaultChannelIDStore(channel_id_db.get()))));
+ std::make_unique<net::ChannelIDService>(new net::DefaultChannelIDStore(nullptr)));
std::unique_ptr<net::CookieStore> cookieStore;
switch (m_persistentCookiesPolicy) {
@@ -439,7 +434,7 @@ void ProfileIODataQt::generateCookieStore()
const std::vector<std::string> cookieableSchemes(kCookieableSchemes,
kCookieableSchemes + base::size(kCookieableSchemes));
- cookieMonster->SetCookieableSchemes(cookieableSchemes);
+ cookieMonster->SetCookieableSchemes(cookieableSchemes, base::DoNothing());
}
void ProfileIODataQt::generateUserAgent()
@@ -616,7 +611,6 @@ void ProfileIODataQt::setFullConfiguration()
m_requestInterceptor = m_profileAdapter->requestInterceptor();
m_persistentCookiesPolicy = m_profileAdapter->persistentCookiesPolicy();
m_cookiesPath = m_profileAdapter->cookiesPath();
- m_channelIdPath = m_profileAdapter->channelIdPath();
m_httpAcceptLanguage = m_profileAdapter->httpAcceptLanguage();
m_httpUserAgent = m_profileAdapter->httpUserAgent();
m_httpCacheType = m_profileAdapter->httpCacheType();
@@ -681,7 +675,6 @@ void ProfileIODataQt::updateCookieStore()
QMutexLocker lock(&m_mutex);
m_persistentCookiesPolicy = m_profileAdapter->persistentCookiesPolicy();
m_cookiesPath = m_profileAdapter->cookiesPath();
- m_channelIdPath = m_profileAdapter->channelIdPath();
if (!m_pendingStorageRequestGeneration)
requestStorageGeneration();
}
diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h
index c9e73f778..f2dc67f44 100644
--- a/src/core/profile_io_data_qt.h
+++ b/src/core/profile_io_data_qt.h
@@ -170,7 +170,6 @@ private:
ClientCertificateStoreData *m_clientCertificateStoreData;
#endif
QString m_cookiesPath;
- QString m_channelIdPath;
QString m_httpAcceptLanguage;
QString m_httpUserAgent;
ProfileAdapter::HttpCacheType m_httpCacheType;
diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp
index 5977a28a8..19d54df62 100644
--- a/src/core/profile_qt.cpp
+++ b/src/core/profile_qt.cpp
@@ -46,6 +46,7 @@
#include "net/ssl_host_state_delegate_qt.h"
#include "net/url_request_context_getter_qt.h"
#include "permission_manager_qt.h"
+#include "platform_notification_service_qt.h"
#include "qtwebenginecoreglobal_p.h"
#include "type_conversion.h"
#include "web_engine_library_info.h"
@@ -61,6 +62,7 @@
#include "components/prefs/pref_member.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/in_memory_pref_store.h"
+#include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/pref_registry_simple.h"
@@ -92,41 +94,7 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter)
, m_extensionSystem(nullptr)
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
{
- PrefServiceFactory factory;
- factory.set_user_prefs(new InMemoryPrefStore);
- factory.set_command_line_prefs(base::MakeRefCounted<CommandLinePrefStoreQt>(
- WebEngineContext::commandLine()));
- PrefRegistrySimple *registry = new PrefRegistrySimple();
- PrefProxyConfigTrackerImpl::RegisterPrefs(registry);
-#if QT_CONFIG(webengine_spellchecker)
- // Initial spellcheck settings
- registry->RegisterStringPref(prefs::kAcceptLanguages, std::string());
- registry->RegisterListPref(spellcheck::prefs::kSpellCheckDictionaries, std::make_unique<base::ListValue>());
- registry->RegisterListPref(spellcheck::prefs::kSpellCheckForcedDictionaries, std::make_unique<base::ListValue>());
- registry->RegisterStringPref(spellcheck::prefs::kSpellCheckDictionary, std::string());
- registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckEnable, false);
- registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckUseSpellingService, false);
-#endif // QT_CONFIG(webengine_spellchecker)
- registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false);
- registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000);
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- registry->RegisterDictionaryPref(extensions::pref_names::kExtensions);
- registry->RegisterListPref(extensions::pref_names::kInstallAllowList);
- registry->RegisterListPref(extensions::pref_names::kInstallDenyList);
- registry->RegisterDictionaryPref(extensions::pref_names::kInstallForceList);
- registry->RegisterDictionaryPref(extensions::pref_names::kInstallLoginScreenAppList);
- registry->RegisterListPref(extensions::pref_names::kAllowedTypes);
- registry->RegisterBooleanPref(extensions::pref_names::kStorageGarbageCollect, false);
- registry->RegisterListPref(extensions::pref_names::kAllowedInstallSites);
- registry->RegisterStringPref(extensions::pref_names::kLastChromeVersion, std::string());
- registry->RegisterListPref(extensions::pref_names::kNativeMessagingBlacklist);
- registry->RegisterListPref(extensions::pref_names::kNativeMessagingWhitelist);
- registry->RegisterBooleanPref(extensions::pref_names::kNativeMessagingUserLevelHosts, true);
-#endif // BUILDFLAG(ENABLE_EXTENSIONS)
-
- m_prefService = factory.Create(registry);
- user_prefs::UserPrefs::Set(this, m_prefService.get());
+ setupPrefService();
// Mark the context as live. This prevents the use-after-free DCHECK in
// AssertBrowserContextWasntDestroyed from being triggered when a new
@@ -143,6 +111,7 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter)
ProfileQt::~ProfileQt()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ m_prefServiceAdapter.commit();
content::BrowserContext::NotifyWillBeDestroyed(this);
BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(this);
ShutdownStoragePartitions();
@@ -153,12 +122,12 @@ ProfileQt::~ProfileQt()
PrefService* ProfileQt::GetPrefs()
{
- return m_prefService.get();
+ return m_prefServiceAdapter.prefService();
}
const PrefService* ProfileQt::GetPrefs() const
{
- return m_prefService.get();
+ return m_prefServiceAdapter.prefService();
}
base::FilePath ProfileQt::GetPath() const
@@ -313,46 +282,48 @@ void ProfileQt::FailedToLoadDictionary(const std::string &language)
LOG(WARNING) << "Could not load dictionary for:" << language;
LOG(INFO) << "Make sure that correct bdic file is in:" << WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES);
}
+#endif // QT_CONFIG(webengine_spellchecker)
-void ProfileQt::setSpellCheckLanguages(const QStringList &languages)
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+extensions::ExtensionSystemQt* ProfileQt::GetExtensionSystem()
{
- StringListPrefMember dictionaries_pref;
- dictionaries_pref.Init(spellcheck::prefs::kSpellCheckDictionaries, m_prefService.get());
- std::vector<std::string> dictionaries;
- dictionaries.reserve(languages.size());
- for (const auto &language : languages)
- dictionaries.push_back(language.toStdString());
- dictionaries_pref.SetValue(dictionaries);
+ return m_extensionSystem;
}
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
-QStringList ProfileQt::spellCheckLanguages() const
+std::string ProfileQt::GetMediaDeviceIDSalt()
{
- QStringList spellcheck_dictionaries;
- for (const auto &value : *m_prefService->GetList(spellcheck::prefs::kSpellCheckDictionaries)) {
- std::string dictionary;
- if (value.GetAsString(&dictionary))
- spellcheck_dictionaries.append(QString::fromStdString(dictionary));
- }
+ return m_prefServiceAdapter.mediaDeviceIdSalt();
+}
- return spellcheck_dictionaries;
+void ProfileQt::setupPrefService()
+{
+ // Remove previous handler before we set a new one or we will assert
+ // TODO: Remove in Qt6
+ if (m_prefServiceAdapter.prefService() != nullptr) {
+ user_prefs::UserPrefs::Remove(this);
+ m_prefServiceAdapter.commit();
+ }
+ m_prefServiceAdapter.setup(*m_profileAdapter);
+ user_prefs::UserPrefs::Set(this, m_prefServiceAdapter.prefService());
}
-void ProfileQt::setSpellCheckEnabled(bool enabled)
+PrefServiceAdapter &ProfileQt::prefServiceAdapter()
{
- m_prefService->SetBoolean(spellcheck::prefs::kSpellCheckEnable, enabled);
+ return m_prefServiceAdapter;
}
-bool ProfileQt::isSpellCheckEnabled() const
+const PrefServiceAdapter &ProfileQt::prefServiceAdapter() const
{
- return m_prefService->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
+ return m_prefServiceAdapter;
}
-#endif // QT_CONFIG(webengine_spellchecker)
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-extensions::ExtensionSystemQt* ProfileQt::GetExtensionSystem()
+
+content::PlatformNotificationService *ProfileQt::platformNotificationService()
{
- return m_extensionSystem;
+ if (!m_platformNotificationService)
+ m_platformNotificationService = std::make_unique<PlatformNotificationServiceQt>(this);
+ return m_platformNotificationService.get();
}
-#endif // BUILDFLAG(ENABLE_EXTENSIONS)
} // namespace QtWebEngineCore
diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h
index 704c5a6e4..b6ff0a0db 100644
--- a/src/core/profile_qt.h
+++ b/src/core/profile_qt.h
@@ -45,6 +45,7 @@
#include "content/public/browser/resource_context.h"
#include "extensions/buildflags/buildflags.h"
#include "net/url_request/url_request_context.h"
+#include "pref_service_adapter.h"
#include "profile_io_data_qt.h"
#include <QtGlobal>
@@ -107,6 +108,7 @@ public:
std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
base::OnceClosure closure) override;
const content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() const override;
+ std::string GetMediaDeviceIDSalt() override;
// Profile implementation:
PrefService *GetPrefs() override;
@@ -116,17 +118,23 @@ public:
ProfileAdapter *profileAdapter() { return m_profileAdapter; }
+ content::PlatformNotificationService *platformNotificationService();
+
#if QT_CONFIG(webengine_spellchecker)
void FailedToLoadDictionary(const std::string &language) override;
- void setSpellCheckLanguages(const QStringList &languages);
- QStringList spellCheckLanguages() const;
- void setSpellCheckEnabled(bool enabled);
- bool isSpellCheckEnabled() const;
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
extensions::ExtensionSystemQt* GetExtensionSystem();
#endif // defined(ENABLE_EXTENSIONS)
+ // Build/Re-build the preference service. Call when updating the storage
+ // data path.
+ void setupPrefService();
+
+ PrefServiceAdapter &prefServiceAdapter();
+
+ const PrefServiceAdapter &prefServiceAdapter() const;
+
private:
friend class ContentBrowserClientQt;
friend class WebContentsAdapter;
@@ -134,10 +142,12 @@ private:
std::unique_ptr<BrowsingDataRemoverDelegateQt> m_removerDelegate;
std::unique_ptr<PermissionManagerQt> m_permissionManager;
std::unique_ptr<SSLHostStateDelegateQt> m_sslHostStateDelegate;
- std::unique_ptr<PrefService> m_prefService;
scoped_refptr<content::SharedCorsOriginAccessList> m_sharedCorsOriginAccessList;
std::unique_ptr<ProfileIODataQt> m_profileIOData;
+ std::unique_ptr<content::PlatformNotificationService> m_platformNotificationService;
ProfileAdapter *m_profileAdapter;
+ PrefServiceAdapter m_prefServiceAdapter;
+
friend class ProfileAdapter;
#if BUILDFLAG(ENABLE_EXTENSIONS)
extensions::ExtensionSystemQt *m_extensionSystem;
diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni
index 11a72a2e9..d9e01a5b8 100644
--- a/src/core/qtwebengine.gni
+++ b/src/core/qtwebengine.gni
@@ -29,6 +29,7 @@ deps = [
"//components/web_cache/renderer",
"//components/spellcheck:buildflags",
"//components/proxy_config",
+ "//components/user_prefs",
"//content/public/app:browser",
"//content",
"//media:media_buildflags",
diff --git a/src/core/qtwebengine_resources.gni b/src/core/qtwebengine_resources.gni
index 4df1760da..749546741 100644
--- a/src/core/qtwebengine_resources.gni
+++ b/src/core/qtwebengine_resources.gni
@@ -24,7 +24,6 @@ repack("qtwebengine_repack_resources") {
"$root_gen_dir/chrome/browser_resources.pak",
"$root_gen_dir/chrome/common_resources.pak",
"$root_gen_dir/chrome/quota_internals_resources.pak",
- "$root_gen_dir/chrome/task_scheduler_internals_resources.pak",
"$root_gen_dir/components/components_resources.pak",
"$root_gen_dir/content/content_resources.pak",
"$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak",
@@ -36,7 +35,6 @@ repack("qtwebengine_repack_resources") {
deps = [
"//qtwebengine/browser:qt_webengine_resources",
"//chrome/browser/resources:quota_internals_resources",
- "//chrome/browser/resources:task_scheduler_internals_resources",
"//chrome/browser:resources_grit",
"//chrome/common:resources_grit",
"//components/resources:components_resources_grit",
diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni
index 58df7096b..8441ca095 100644
--- a/src/core/qtwebengine_sources.gni
+++ b/src/core/qtwebengine_sources.gni
@@ -23,6 +23,8 @@ source_set("qtwebengine_spellcheck_sources") {
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h",
"//chrome/browser/spellchecker/spellcheck_service.cc",
"//chrome/browser/spellchecker/spellcheck_service.h",
+ "//components/language/core/browser/pref_names.cc",
+ "//components/language/core/browser/pref_names.h",
]
deps = [
"//components/spellcheck/browser",
@@ -72,8 +74,6 @@ source_set("qtwebengine_sources") {
"//chrome/browser/ui/webui/quota_internals/quota_internals_types.h",
"//chrome/browser/ui/webui/quota_internals/quota_internals_ui.cc",
"//chrome/browser/ui/webui/quota_internals/quota_internals_ui.h",
- "//chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.cc",
- "//chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.h",
"//chrome/common/custom_handlers/protocol_handler.cc",
"//chrome/common/custom_handlers/protocol_handler.h",
"//chrome/common/chrome_switches.cc",
@@ -84,13 +84,12 @@ source_set("qtwebengine_sources") {
"//chrome/common/url_constants.h",
"//chrome/common/webui_url_constants.cc",
"//chrome/common/webui_url_constants.h",
- "//components/prefs/in_memory_pref_store.cc",
- "//components/prefs/in_memory_pref_store.h",
]
if (enable_extensions) {
deps += [
":qtwebengine_extensions_features",
+ "//chrome/app:generated_resources",
"//chrome/browser/resources:component_extension_resources_grit",
"//chrome/common/extensions/api",
"//chrome/common/extensions/api:extensions_features",
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 4407e706e..0242506ee 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -56,6 +56,7 @@
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/common/content_switches_internal.h"
@@ -359,7 +360,7 @@ void RenderWidgetHostViewQt::SetBounds(const gfx::Rect &windowRectInDips)
m_delegate->resize(windowRectInDips.width(), windowRectInDips.height());
}
-gfx::NativeView RenderWidgetHostViewQt::GetNativeView() const
+gfx::NativeView RenderWidgetHostViewQt::GetNativeView()
{
// gfx::NativeView is a typedef to a platform specific view
// pointer (HWND, NSView*, GtkWidget*) and other ports use
@@ -396,12 +397,12 @@ void RenderWidgetHostViewQt::Focus()
host()->Focus();
}
-bool RenderWidgetHostViewQt::HasFocus() const
+bool RenderWidgetHostViewQt::HasFocus()
{
return m_delegate->hasKeyboardFocus();
}
-bool RenderWidgetHostViewQt::IsSurfaceAvailableForCopy() const
+bool RenderWidgetHostViewQt::IsSurfaceAvailableForCopy()
{
return true;
}
@@ -433,7 +434,7 @@ bool RenderWidgetHostViewQt::IsShowing()
}
// Retrieve the bounds of the View, in screen coordinates.
-gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const
+gfx::Rect RenderWidgetHostViewQt::GetViewBounds()
{
return m_viewRectInDips;
}
@@ -470,8 +471,7 @@ void RenderWidgetHostViewQt::UpdateCursor(const content::WebCursor &webCursor)
void RenderWidgetHostViewQt::DisplayCursor(const content::WebCursor &webCursor)
{
- content::CursorInfo cursorInfo;
- webCursor.GetCursorInfo(&cursorInfo);
+ const content::CursorInfo &cursorInfo = webCursor.info();
Qt::CursorShape shape = Qt::ArrowCursor;
#if defined(USE_AURA)
ui::CursorType auraType = ui::CursorType::kNull;
@@ -637,7 +637,8 @@ void RenderWidgetHostViewQt::ImeCompositionRangeChanged(const gfx::Range&, const
void RenderWidgetHostViewQt::RenderProcessGone(base::TerminationStatus terminationStatus,
int exitCode)
{
- if (m_adapterClient) {
+ // RenderProcessHost::FastShutdownIfPossible results in TERMINATION_STATUS_STILL_RUNNING
+ if (m_adapterClient && terminationStatus != base::TERMINATION_STATUS_STILL_RUNNING) {
m_adapterClient->renderProcessTerminated(
m_adapterClient->renderProcessExitStatus(terminationStatus),
exitCode);
@@ -695,7 +696,7 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo
m_adapterClient->updateContentsSize(toQt(m_lastContentsSize));
}
-void RenderWidgetHostViewQt::GetScreenInfo(content::ScreenInfo *results) const
+void RenderWidgetHostViewQt::GetScreenInfo(content::ScreenInfo *results)
{
*results = m_screenInfo;
}
@@ -1740,4 +1741,9 @@ void RenderWidgetHostViewQt::synchronizeVisualProperties(const base::Optional<vi
host()->SynchronizeVisualProperties();
}
+std::unique_ptr<content::SyntheticGestureTarget> RenderWidgetHostViewQt::CreateSyntheticGestureTarget()
+{
+ return nullptr;
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index 6e9ddabb9..91d5b8610 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -125,18 +125,18 @@ public:
void InitAsFullscreen(content::RenderWidgetHostView*) override;
void SetSize(const gfx::Size& size) override;
void SetBounds(const gfx::Rect&) override;
- gfx::NativeView GetNativeView() const override;
+ gfx::NativeView GetNativeView() override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
void Focus() override;
- bool HasFocus() const override;
- bool IsSurfaceAvailableForCopy() const override;
+ bool HasFocus() override;
+ bool IsSurfaceAvailableForCopy() override;
void CopyFromSurface(const gfx::Rect &src_rect,
const gfx::Size &output_size,
base::OnceCallback<void(const SkBitmap &)> callback) override;
void Show() override;
void Hide() override;
bool IsShowing() override;
- gfx::Rect GetViewBounds() const override;
+ gfx::Rect GetViewBounds() override;
void UpdateBackgroundColor() override;
bool LockMouse() override;
void UnlockMouse() override;
@@ -156,7 +156,7 @@ public:
viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(const cc::RenderFrameMetadata &metadata) override;
void OnDidUpdateVisualPropertiesComplete(const cc::RenderFrameMetadata &metadata);
- void GetScreenInfo(content::ScreenInfo* results) const override;
+ void GetScreenInfo(content::ScreenInfo *results) override;
gfx::Rect GetBoundsInRootWindow() override;
void ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, content::InputEventAckState ack_result) override;
void ClearCompositorFrame() override;
@@ -170,6 +170,7 @@ public:
uint32_t GetCaptureSequenceNumber() const override;
void ResetFallbackToFirstNavigationSurface() override;
void DidStopFlinging() override;
+ std::unique_ptr<content::SyntheticGestureTarget> CreateSyntheticGestureTarget() override;
// Overridden from ui::GestureProviderClient.
void OnGestureEvent(const ui::GestureEventData& gesture) override;
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index 6066284d9..4ee790ce9 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -65,7 +65,6 @@ class QSGTexture;
class QVariant;
class QInputMethodEvent;
-class QSGInternalImageNode;
class QSGImageNode;
QT_END_NAMESPACE
@@ -102,7 +101,6 @@ public:
virtual QWindow* window() const = 0;
virtual QSGTexture *createTextureFromImage(const QImage &) = 0;
virtual QSGLayer *createLayer() = 0;
- virtual QSGInternalImageNode *createInternalImageNode() = 0;
virtual QSGImageNode *createImageNode() = 0;
virtual QSGRectangleNode *createRectangleNode() = 0;
virtual void update() = 0;
diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp
index 5fd4c7d65..092e6845d 100644
--- a/src/core/renderer/content_renderer_client_qt.cpp
+++ b/src/core/renderer/content_renderer_client_qt.cpp
@@ -280,33 +280,33 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF
if (errorHtml) {
// Use a local error page.
int resourceId;
- base::DictionaryValue errorStrings;
const std::string locale = content::RenderThread::Get()->GetLocale();
// TODO(elproxy): We could potentially get better diagnostics here by first calling
// NetErrorHelper::GetErrorStringsForDnsProbe, but that one is harder to untangle.
- error_page::LocalizedError::GetStrings(
- error.reason(), error.domain(), error.url(), isPost,
- error.stale_copy_in_cache(), false, RenderThreadObserverQt::is_incognito_process(),
- error_page::LocalizedError::OfflineContentOnNetErrorFeatureState::kDisabled,
- false, locale, std::unique_ptr<error_page::ErrorPageParams>(), &errorStrings);
+ error_page::LocalizedError::PageState errorPageState =
+ error_page::LocalizedError::GetPageState(
+ error.reason(), error.domain(), error.url(), isPost,
+ error.stale_copy_in_cache(), false, RenderThreadObserverQt::is_incognito_process(), false,
+ false, locale, std::unique_ptr<error_page::ErrorPageParams>());
+
resourceId = IDR_NET_ERROR_HTML;
const base::StringPiece template_html(ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resourceId));
if (template_html.empty())
NOTREACHED() << "unable to load template. ID: " << resourceId;
else // "t" is the id of the templates root node.
- *errorHtml = webui::GetTemplatesHtml(template_html, &errorStrings, "t");
+ *errorHtml = webui::GetTemplatesHtml(template_html, &errorPageState.strings, "t");
}
}
-unsigned long long ContentRendererClientQt::VisitedLinkHash(const char *canonicalUrl, size_t length)
+uint64_t ContentRendererClientQt::VisitedLinkHash(const char *canonicalUrl, size_t length)
{
return m_visitedLinkSlave->ComputeURLFingerprint(canonicalUrl, length);
}
-bool ContentRendererClientQt::IsLinkVisited(unsigned long long linkHash)
+bool ContentRendererClientQt::IsLinkVisited(uint64_t linkHash)
{
return m_visitedLinkSlave->IsVisited(linkHash);
}
diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h
index dd164fa3a..a13d16b5c 100644
--- a/src/core/renderer/content_renderer_client_qt.h
+++ b/src/core/renderer/content_renderer_client_qt.h
@@ -101,8 +101,8 @@ public:
int http_status,
std::string *error_html) override;
- unsigned long long VisitedLinkHash(const char *canonicalUrl, size_t length) override;
- bool IsLinkVisited(unsigned long long linkHash) override;
+ uint64_t VisitedLinkHash(const char *canonical_url, size_t length) override;
+ bool IsLinkVisited(uint64_t linkHash) override;
blink::WebPrescientNetworking* GetPrescientNetworking() override;
void AddSupportedKeySystems(std::vector<std::unique_ptr<media::KeySystemProperties>>* key_systems) override;
diff --git a/src/core/renderer/content_settings_observer_qt.cpp b/src/core/renderer/content_settings_observer_qt.cpp
index 98954eb4a..a9e89dfee 100644
--- a/src/core/renderer/content_settings_observer_qt.cpp
+++ b/src/core/renderer/content_settings_observer_qt.cpp
@@ -45,7 +45,6 @@
#include "content_settings_observer_qt.h"
#include "content/public/renderer/render_frame.h"
-#include "third_party/blink/public/platform/web_content_setting_callbacks.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/web/web_plugin_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
@@ -53,7 +52,6 @@
#include "common/qt_messages.h"
-using blink::WebContentSettingCallbacks;
using blink::WebSecurityOrigin;
using blink::WebString;
@@ -115,9 +113,7 @@ void ContentSettingsObserverQt::OnDestruct()
delete this;
}
-bool ContentSettingsObserverQt::AllowDatabase(const WebString &name,
- const WebString &display_name,
- unsigned /*estimated_size*/)
+bool ContentSettingsObserverQt::AllowDatabase()
{
blink::WebFrame *frame = render_frame()->GetWebFrame();
if (IsUniqueFrame(frame))
@@ -126,21 +122,20 @@ bool ContentSettingsObserverQt::AllowDatabase(const WebString &name,
bool result = false;
Send(new QtWebEngineHostMsg_AllowDatabase(
routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(),
- url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), name.Utf16(),
- display_name.Utf16(), &result));
+ url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(),
+ &result));
return result;
}
-void ContentSettingsObserverQt::RequestFileSystemAccessAsync(const WebContentSettingCallbacks &callbacks)
+void ContentSettingsObserverQt::RequestFileSystemAccessAsync(base::OnceCallback<void(bool)> callback)
{
blink::WebFrame *frame = render_frame()->GetWebFrame();
if (IsUniqueFrame(frame)) {
- WebContentSettingCallbacks permissionCallbacks(callbacks);
- permissionCallbacks.DoDeny();
+ std::move(callback).Run(false);
return;
}
++m_currentRequestId;
- bool inserted = m_permissionRequests.insert(std::make_pair(m_currentRequestId, callbacks)).second;
+ bool inserted = m_permissionRequests.insert(std::make_pair(m_currentRequestId, std::move(callback))).second;
// Verify there are no duplicate insertions.
DCHECK(inserted);
@@ -190,14 +185,10 @@ void ContentSettingsObserverQt::OnRequestFileSystemAccessAsyncResponse(int reque
if (it == m_permissionRequests.end())
return;
- WebContentSettingCallbacks callbacks = it->second;
+ base::OnceCallback<void(bool)> callback = std::move(it->second);
m_permissionRequests.erase(it);
- if (allowed) {
- callbacks.DoAllow();
- return;
- }
- callbacks.DoDeny();
+ std::move(callback).Run(allowed);
}
void ContentSettingsObserverQt::ClearBlockedContentSettings()
diff --git a/src/core/renderer/content_settings_observer_qt.h b/src/core/renderer/content_settings_observer_qt.h
index 69b0eda9e..9c071aa3c 100644
--- a/src/core/renderer/content_settings_observer_qt.h
+++ b/src/core/renderer/content_settings_observer_qt.h
@@ -51,7 +51,6 @@
#include "url/gurl.h"
namespace blink {
-class WebContentSettingCallbacks;
class WebSecurityOrigin;
}
@@ -68,10 +67,8 @@ public:
~ContentSettingsObserverQt() override;
// blink::WebContentSettingsClient:
- bool AllowDatabase(const blink::WebString &name,
- const blink::WebString &display_name,
- unsigned estimated_size) override;
- void RequestFileSystemAccessAsync(const blink::WebContentSettingCallbacks &callbacks) override;
+ bool AllowDatabase() override;
+ void RequestFileSystemAccessAsync(base::OnceCallback<void(bool)> callback) override;
bool AllowIndexedDB(const blink::WebSecurityOrigin &origin) override;
bool AllowStorage(bool local) override;
@@ -94,7 +91,7 @@ private:
base::flat_map<StoragePermissionsKey, bool> m_cachedStoragePermissions;
int m_currentRequestId;
- base::flat_map<int, blink::WebContentSettingCallbacks> m_permissionRequests;
+ base::flat_map<int, base::OnceCallback<void(bool)>> m_permissionRequests;
DISALLOW_COPY_AND_ASSIGN(ContentSettingsObserverQt);
};
diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp
index 3b9c17b6a..745fe8b1e 100644
--- a/src/core/renderer/web_channel_ipc_transport.cpp
+++ b/src/core/renderer/web_channel_ipc_transport.cpp
@@ -214,9 +214,11 @@ void WebChannelIPCTransport::ResetWorldId()
void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson, uint32_t worldId)
{
- DCHECK(m_canUseContext);
DCHECK(m_worldId == worldId);
+ if (!m_canUseContext)
+ return;
+
QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()),
binaryJson.size(), QJsonDocument::BypassValidation);
DCHECK(doc.isObject());
diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp
index 36c5e6ed1..eba835cd7 100644
--- a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp
+++ b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp
@@ -120,7 +120,7 @@ bool ResourceDispatcherHostDelegateQt::ShouldInterceptResourceAsStream(net::URLR
GURL *origin,
std::string *payload)
{
- const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo* info =
content::ResourceRequestInfo::ForRequest(request);
int render_process_host_id = -1;
@@ -162,7 +162,7 @@ bool ResourceDispatcherHostDelegateQt::ShouldInterceptResourceAsStream(net::URLR
void ResourceDispatcherHostDelegateQt::OnStreamCreated(net::URLRequest *request,
std::unique_ptr<content::StreamInfo> stream)
{
- const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request);
+ content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request);
std::map<net::URLRequest *, StreamTargetInfo>::iterator ix = stream_target_info_.find(request);
CHECK(ix != stream_target_info_.end());
int render_frame_id = -1;
diff --git a/src/core/user_notification_controller.cpp b/src/core/user_notification_controller.cpp
index d169bf854..50d12e8fd 100644
--- a/src/core/user_notification_controller.cpp
+++ b/src/core/user_notification_controller.cpp
@@ -51,14 +51,14 @@
namespace QtWebEngineCore {
-static Qt::LayoutDirection toDirection(blink::PlatformNotificationData::Direction direction)
+static Qt::LayoutDirection toDirection(blink::mojom::NotificationDirection direction)
{
switch (direction) {
- case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
+ case blink::mojom::NotificationDirection::LEFT_TO_RIGHT:
return Qt::LeftToRight;
- case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
+ case blink::mojom::NotificationDirection::RIGHT_TO_LEFT:
return Qt::RightToLeft;
- case blink::PlatformNotificationData::DIRECTION_AUTO:
+ case blink::mojom::NotificationDirection::AUTO:
default:
break;
}
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index ca2479965..ee0b8cc39 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -61,9 +61,10 @@
#include "web_engine_settings.h"
#include "base/command_line.h"
-#include "base/message_loop/message_loop_impl.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
#include "base/values.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
@@ -81,13 +82,11 @@
#include "content/public/common/drop_data.h"
#include "content/public/common/page_state.h"
#include "content/public/common/page_zoom.h"
-#include "content/public/common/renderer_preferences.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/web_preferences.h"
#include "content/public/common/webrtc_ip_handling_policy.h"
#include "extensions/buildflags/buildflags.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
-//#include "third_party/blink/public/web/web_find_options.h"
#include "third_party/blink/public/web/web_media_player_action.h"
#include "printing/buildflags/buildflags.h"
#include "ui/base/clipboard/clipboard.h"
@@ -214,10 +213,10 @@ static QVariant fromJSValue(const base::Value *result)
return ret;
}
-static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint64 requestId, const base::Value *result)
+static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint64 requestId, base::Value result)
{
if (requestId)
- adapterClient->didRunJavaScript(requestId, fromJSValue(result));
+ adapterClient->didRunJavaScript(requestId, fromJSValue(&result));
}
#if QT_CONFIG(webengine_printing_and_pdf)
@@ -478,32 +477,7 @@ void WebContentsAdapter::initialize(content::SiteInstance *site)
m_webContents = content::WebContents::Create(create_params);
}
- content::RendererPreferences* rendererPrefs = m_webContents->GetMutableRendererPrefs();
- rendererPrefs->use_custom_colors = true;
- // Qt returns a flash time (the whole cycle) in ms, chromium expects just the interval in seconds
- const int qtCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
- rendererPrefs->caret_blink_interval = base::TimeDelta::FromMillisecondsD(0.5 * static_cast<double>(qtCursorFlashTime));
- rendererPrefs->user_agent_override = m_profileAdapter->httpUserAgent().toStdString();
- rendererPrefs->accept_languages = m_profileAdapter->httpAcceptLanguageWithoutQualities().toStdString();
-#if QT_CONFIG(webengine_webrtc)
- base::CommandLine* commandLine = base::CommandLine::ForCurrentProcess();
- if (commandLine->HasSwitch(switches::kForceWebRtcIPHandlingPolicy))
- rendererPrefs->webrtc_ip_handling_policy = commandLine->GetSwitchValueASCII(switches::kForceWebRtcIPHandlingPolicy);
- else
- rendererPrefs->webrtc_ip_handling_policy = m_adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly)
- ? content::kWebRTCIPHandlingDefaultPublicInterfaceOnly
- : content::kWebRTCIPHandlingDefault;
-#endif
- // Set web-contents font settings to the default font settings as Chromium constantly overrides
- // the global font defaults with the font settings of the latest web-contents created.
- static const gfx::FontRenderParams params = gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr);
- rendererPrefs->should_antialias_text = params.antialiasing;
- rendererPrefs->use_subpixel_positioning = params.subpixel_positioning;
- rendererPrefs->hinting = params.hinting;
- rendererPrefs->use_autohinter = params.autohinter;
- rendererPrefs->use_bitmaps = params.use_bitmaps;
- rendererPrefs->subpixel_rendering = params.subpixel_rendering;
- m_webContents->GetRenderViewHost()->SyncRendererPrefs();
+ initializeRenderPrefs();
// Create and attach observers to the WebContents.
m_webContentsDelegate.reset(new WebContentsDelegateQt(m_webContents.get(), m_adapterClient));
@@ -540,6 +514,40 @@ void WebContentsAdapter::initialize(content::SiteInstance *site)
m_adapterClient->initializationFinished();
}
+void WebContentsAdapter::initializeRenderPrefs()
+{
+ blink::mojom::RendererPreferences *rendererPrefs = m_webContents->GetMutableRendererPrefs();
+ rendererPrefs->use_custom_colors = true;
+ // Qt returns a flash time (the whole cycle) in ms, chromium expects just the interval in
+ // seconds
+ const int qtCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
+ rendererPrefs->caret_blink_interval =
+ base::TimeDelta::FromMillisecondsD(0.5 * static_cast<double>(qtCursorFlashTime));
+ rendererPrefs->user_agent_override = m_profileAdapter->httpUserAgent().toStdString();
+ rendererPrefs->accept_languages = m_profileAdapter->httpAcceptLanguageWithoutQualities().toStdString();
+#if QT_CONFIG(webengine_webrtc)
+ base::CommandLine* commandLine = base::CommandLine::ForCurrentProcess();
+ if (commandLine->HasSwitch(switches::kForceWebRtcIPHandlingPolicy))
+ rendererPrefs->webrtc_ip_handling_policy =
+ commandLine->GetSwitchValueASCII(switches::kForceWebRtcIPHandlingPolicy);
+ else
+ rendererPrefs->webrtc_ip_handling_policy =
+ m_adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly)
+ ? content::kWebRTCIPHandlingDefaultPublicInterfaceOnly
+ : content::kWebRTCIPHandlingDefault;
+#endif
+ // Set web-contents font settings to the default font settings as Chromium constantly overrides
+ // the global font defaults with the font settings of the latest web-contents created.
+ static const gfx::FontRenderParams params = gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr);
+ rendererPrefs->should_antialias_text = params.antialiasing;
+ rendererPrefs->use_subpixel_positioning = params.subpixel_positioning;
+ rendererPrefs->hinting = params.hinting;
+ rendererPrefs->use_autohinter = params.autohinter;
+ rendererPrefs->use_bitmaps = params.use_bitmaps;
+ rendererPrefs->subpixel_rendering = params.subpixel_rendering;
+ m_webContents->GetRenderViewHost()->SyncRendererPrefs();
+}
+
bool WebContentsAdapter::canGoBack() const
{
CHECK_INITIALIZED(false);
@@ -552,6 +560,12 @@ bool WebContentsAdapter::canGoForward() const
return m_webContents->GetController().CanGoForward();
}
+bool WebContentsAdapter::canGoToOffset(int offset) const
+{
+ CHECK_INITIALIZED(false);
+ return m_webContents->GetController().CanGoToOffset(offset);
+}
+
void WebContentsAdapter::stop()
{
CHECK_INITIALIZED();
@@ -568,16 +582,22 @@ void WebContentsAdapter::stop()
void WebContentsAdapter::reload()
{
CHECK_INITIALIZED();
+ bool wasDiscarded = (m_lifecycleState == LifecycleState::Discarded);
+ setLifecycleState(LifecycleState::Active);
CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost());
- m_webContents->GetController().Reload(content::ReloadType::NORMAL, /*checkRepost = */false);
+ if (!wasDiscarded) // undiscard() already triggers a reload
+ m_webContents->GetController().Reload(content::ReloadType::NORMAL, /*checkRepost = */false);
focusIfNecessary();
}
void WebContentsAdapter::reloadAndBypassCache()
{
CHECK_INITIALIZED();
+ bool wasDiscarded = (m_lifecycleState == LifecycleState::Discarded);
+ setLifecycleState(LifecycleState::Active);
CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost());
- m_webContents->GetController().Reload(content::ReloadType::BYPASSING_CACHE, /*checkRepost = */false);
+ if (!wasDiscarded) // undiscard() already triggers a reload
+ m_webContents->GetController().Reload(content::ReloadType::BYPASSING_CACHE, /*checkRepost = */false);
focusIfNecessary();
}
@@ -600,6 +620,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request)
scoped_refptr<content::SiteInstance> site =
content::SiteInstance::CreateForURL(m_profileAdapter->profile(), gurl);
initialize(site.get());
+ } else {
+ setLifecycleState(LifecycleState::Active);
}
CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost());
@@ -695,6 +717,8 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT
{
if (!isInitialized())
loadDefault();
+ else
+ setLifecycleState(LifecycleState::Active);
CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost());
@@ -831,6 +855,26 @@ void WebContentsAdapter::unselect()
m_webContents->CollapseSelection();
}
+void WebContentsAdapter::navigateBack()
+{
+ CHECK_INITIALIZED();
+ CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost());
+ if (!m_webContents->GetController().CanGoBack())
+ return;
+ m_webContents->GetController().GoBack();
+ focusIfNecessary();
+}
+
+void WebContentsAdapter::navigateForward()
+{
+ CHECK_INITIALIZED();
+ CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost());
+ if (!m_webContents->GetController().CanGoForward())
+ return;
+ m_webContents->GetController().GoForward();
+ focusIfNecessary();
+}
+
void WebContentsAdapter::navigateToIndex(int offset)
{
CHECK_INITIALIZED();
@@ -964,13 +1008,14 @@ void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldI
CHECK_INITIALIZED();
content::RenderViewHost *rvh = m_webContents->GetRenderViewHost();
Q_ASSERT(rvh);
+// static_cast<content::RenderFrameHostImpl *>(rvh->GetMainFrame())->NotifyUserActivation();
if (worldId == 0) {
- rvh->GetMainFrame()->ExecuteJavaScript(toString16(javaScript));
+ rvh->GetMainFrame()->ExecuteJavaScript(toString16(javaScript), base::NullCallback());
return;
}
- content::RenderFrameHost::JavaScriptResultCallback callback = base::Bind(&callbackOnEvaluateJS, m_adapterClient, CallbackDirectory::NoCallbackId);
- rvh->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), callback, worldId);
+ content::RenderFrameHost::JavaScriptResultCallback callback = base::BindOnce(&callbackOnEvaluateJS, m_adapterClient, CallbackDirectory::NoCallbackId);
+ rvh->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(callback), worldId);
}
quint64 WebContentsAdapter::runJavaScriptCallbackResult(const QString &javaScript, quint32 worldId)
@@ -978,11 +1023,12 @@ quint64 WebContentsAdapter::runJavaScriptCallbackResult(const QString &javaScrip
CHECK_INITIALIZED(0);
content::RenderViewHost *rvh = m_webContents->GetRenderViewHost();
Q_ASSERT(rvh);
- content::RenderFrameHost::JavaScriptResultCallback callback = base::Bind(&callbackOnEvaluateJS, m_adapterClient, m_nextRequestId);
+// static_cast<content::RenderFrameHostImpl *>(rvh->GetMainFrame())->NotifyUserActivation();
+ content::RenderFrameHost::JavaScriptResultCallback callback = base::BindOnce(&callbackOnEvaluateJS, m_adapterClient, m_nextRequestId);
if (worldId == 0)
- rvh->GetMainFrame()->ExecuteJavaScript(toString16(javaScript), callback);
+ rvh->GetMainFrame()->ExecuteJavaScript(toString16(javaScript), std::move(callback));
else
- rvh->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), callback, worldId);
+ rvh->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(callback), worldId);
return m_nextRequestId++;
}
@@ -1112,7 +1158,7 @@ void WebContentsAdapter::setAudioMuted(bool muted)
m_webContents->SetAudioMuted(muted);
}
-bool WebContentsAdapter::recentlyAudible()
+bool WebContentsAdapter::recentlyAudible() const
{
CHECK_INITIALIZED(false);
return m_webContents->IsCurrentlyAudible();
@@ -1173,6 +1219,18 @@ bool WebContentsAdapter::hasInspector() const
return false;
}
+bool WebContentsAdapter::isInspector() const
+{
+ return m_inspector;
+}
+
+void WebContentsAdapter::setInspector(bool inspector)
+{
+ m_inspector = inspector;
+ if (inspector)
+ setLifecycleState(LifecycleState::Active);
+}
+
void WebContentsAdapter::openDevToolsFrontend(QSharedPointer<WebContentsAdapter> frontendAdapter)
{
Q_ASSERT(isInitialized());
@@ -1185,7 +1243,10 @@ void WebContentsAdapter::openDevToolsFrontend(QSharedPointer<WebContentsAdapter>
m_devToolsFrontend->Close();
}
+ setLifecycleState(LifecycleState::Active);
+
m_devToolsFrontend = DevToolsFrontendQt::Show(frontendAdapter, m_webContents.get());
+ updateRecommendedState();
}
void WebContentsAdapter::closeDevToolsFrontend()
@@ -1201,6 +1262,7 @@ void WebContentsAdapter::devToolsFrontendDestroyed(DevToolsFrontendQt *frontend)
Q_ASSERT(frontend == m_devToolsFrontend);
Q_UNUSED(frontend);
m_devToolsFrontend = nullptr;
+ updateRecommendedState();
}
void WebContentsAdapter::exitFullScreen()
@@ -1568,7 +1630,11 @@ void WebContentsAdapter::waitForUpdateDragActionCalled()
const qint64 timeout = 3000;
QElapsedTimer t;
t.start();
- base::MessagePump::Delegate *delegate = static_cast<base::MessageLoopImpl *>(base::MessageLoopCurrent::Get().ToMessageLoopBaseDeprecated());
+ auto seqMan = base::MessageLoopCurrent::GetCurrentSequenceManagerImpl();
+ base::MessagePump::Delegate *delegate =
+ static_cast<base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl *>(
+ seqMan->controller_.get());
+
DCHECK(delegate);
m_updateDragActionCalled = false;
for (;;) {
@@ -1666,8 +1732,7 @@ WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) {
break;
case base::TERMINATION_STATUS_STILL_RUNNING:
case base::TERMINATION_STATUS_MAX_ENUM:
- // should be unreachable since Chromium asserts status != TERMINATION_STATUS_STILL_RUNNING
- // before calling this method
+ Q_UNREACHABLE();
break;
}
@@ -1692,6 +1757,230 @@ bool WebContentsAdapter::canViewSource()
return m_webContents->GetController().CanViewSource();
}
+WebContentsAdapter::LifecycleState WebContentsAdapter::lifecycleState() const
+{
+ return m_lifecycleState;
+}
+
+void WebContentsAdapter::setLifecycleState(LifecycleState state)
+{
+ CHECK_INITIALIZED();
+
+ LifecycleState from = m_lifecycleState;
+ LifecycleState to = state;
+
+ const auto warn = [from, to](const char *reason) {
+ static const char *names[] { "Active", "Frozen", "Discarded" };
+ qWarning("setLifecycleState: failed to transition from %s to %s state: %s",
+ names[(int)from], names[(int)to], reason);
+ };
+
+ if (from == to)
+ return;
+
+ if (from == LifecycleState::Active) {
+ if (isVisible()) {
+ warn("page is visible");
+ return;
+ }
+ if (hasInspector() || isInspector()) {
+ warn("DevTools open");
+ return;
+ }
+ }
+
+ if (from == LifecycleState::Discarded && to != LifecycleState::Active) {
+ warn("illegal transition");
+ return;
+ }
+
+ // Prevent recursion due to initializationFinished() in undiscard().
+ m_lifecycleState = to;
+
+ switch (to) {
+ case LifecycleState::Active:
+ if (from == LifecycleState::Frozen)
+ unfreeze();
+ else
+ undiscard();
+ break;
+ case LifecycleState::Frozen:
+ freeze();
+ break;
+ case LifecycleState::Discarded:
+ discard();
+ break;
+ }
+
+ m_adapterClient->lifecycleStateChanged(to);
+ updateRecommendedState();
+}
+
+WebContentsAdapter::LifecycleState WebContentsAdapter::recommendedState() const
+{
+ return m_recommendedState;
+}
+
+WebContentsAdapter::LifecycleState WebContentsAdapter::determineRecommendedState() const
+{
+ CHECK_INITIALIZED(LifecycleState::Active);
+
+ if (m_lifecycleState == LifecycleState::Discarded)
+ return LifecycleState::Discarded;
+
+ if (isVisible())
+ return LifecycleState::Active;
+
+ if (m_webContentsDelegate->loadingState() != WebContentsDelegateQt::LoadingState::Loaded)
+ return LifecycleState::Active;
+
+ if (recentlyAudible())
+ return LifecycleState::Active;
+
+ if (m_webContents->GetSiteInstance()->GetRelatedActiveContentsCount() > 1U)
+ return LifecycleState::Active;
+
+ if (hasInspector() || isInspector())
+ return LifecycleState::Active;
+
+ if (m_webContentsDelegate->isCapturingAudio() || m_webContentsDelegate->isCapturingVideo()
+ || m_webContentsDelegate->isMirroring() || m_webContentsDelegate->isCapturingDesktop())
+ return LifecycleState::Active;
+
+ if (m_webContents->IsCrashed())
+ return LifecycleState::Active;
+
+ if (m_lifecycleState == LifecycleState::Active)
+ return LifecycleState::Frozen;
+
+ // Form input is not saved.
+ if (m_webContents->GetPageImportanceSignals().had_form_interaction)
+ return LifecycleState::Frozen;
+
+ // Do not discard PDFs as they might contain entry that is not saved and they
+ // don't remember their scrolling positions. See crbug.com/547286 and
+ // crbug.com/65244.
+ if (m_webContents->GetContentsMimeType() == "application/pdf")
+ return LifecycleState::Frozen;
+
+ return LifecycleState::Discarded;
+}
+
+void WebContentsAdapter::updateRecommendedState()
+{
+ LifecycleState newState = determineRecommendedState();
+ if (m_recommendedState == newState)
+ return;
+
+ m_recommendedState = newState;
+ m_adapterClient->recommendedStateChanged(newState);
+}
+
+bool WebContentsAdapter::isVisible() const
+{
+ CHECK_INITIALIZED(false);
+
+ // Visibility::OCCLUDED is not used
+ return m_webContents->GetVisibility() == content::Visibility::VISIBLE;
+}
+
+void WebContentsAdapter::setVisible(bool visible)
+{
+ CHECK_INITIALIZED();
+
+ if (isVisible() == visible)
+ return;
+
+ if (visible) {
+ setLifecycleState(LifecycleState::Active);
+ wasShown();
+ } else {
+ Q_ASSERT(m_lifecycleState == LifecycleState::Active);
+ wasHidden();
+ }
+
+ m_adapterClient->visibleChanged(visible);
+ updateRecommendedState();
+}
+
+void WebContentsAdapter::freeze()
+{
+ m_webContents->SetPageFrozen(true);
+}
+
+void WebContentsAdapter::unfreeze()
+{
+ m_webContents->SetPageFrozen(false);
+}
+
+void WebContentsAdapter::discard()
+{
+ // Based on TabLifecycleUnitSource::TabLifecycleUnit::FinishDiscard
+
+ if (m_webContents->IsLoading()) {
+ m_webContentsDelegate->didFailLoad(m_webContentsDelegate->url(), net::Error::ERR_ABORTED,
+ QStringLiteral("Discarded"));
+ }
+
+ content::WebContents::CreateParams createParams(m_profileAdapter->profile());
+ createParams.initially_hidden = true;
+ createParams.desired_renderer_state = content::WebContents::CreateParams::kNoRendererProcess;
+ createParams.last_active_time = m_webContents->GetLastActiveTime();
+ std::unique_ptr<content::WebContents> nullContents = content::WebContents::Create(createParams);
+ std::unique_ptr<WebContentsDelegateQt> nullDelegate(new WebContentsDelegateQt(nullContents.get(), m_adapterClient));
+ nullContents->GetController().CopyStateFrom(&m_webContents->GetController(),
+ /* needs_reload */ false);
+ nullDelegate->copyStateFrom(m_webContentsDelegate.get());
+ nullContents->SetWasDiscarded(true);
+
+ // Kill render process if this is the only page it's got.
+ content::RenderProcessHost *renderProcessHost = m_webContents->GetMainFrame()->GetProcess();
+ renderProcessHost->FastShutdownIfPossible(/* page_count */ 1u,
+ /* skip_unload_handlers */ false);
+
+#if QT_CONFIG(webengine_webchannel)
+ if (m_webChannel)
+ m_webChannel->disconnectFrom(m_webChannelTransport.get());
+ m_webChannelTransport.reset();
+ m_webChannel = nullptr;
+ m_webChannelWorld = 0;
+#endif
+ m_renderViewObserverHost.reset();
+ m_webContentsDelegate.reset();
+ m_webContents.reset();
+
+ m_webContents = std::move(nullContents);
+ initializeRenderPrefs();
+ m_webContentsDelegate = std::move(nullDelegate);
+ m_renderViewObserverHost.reset(new RenderViewObserverHostQt(m_webContents.get(), m_adapterClient));
+ WebContentsViewQt *contentsView =
+ static_cast<WebContentsViewQt *>(static_cast<content::WebContentsImpl *>(m_webContents.get())->GetView());
+ contentsView->setClient(m_adapterClient);
+#if QT_CONFIG(webengine_printing_and_pdf)
+ PrintViewManagerQt::CreateForWebContents(webContents());
+#endif
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ extensions::ExtensionWebContentsObserverQt::CreateForWebContents(webContents());
+#endif
+}
+
+void WebContentsAdapter::undiscard()
+{
+ m_webContents->GetController().SetNeedsReload();
+ m_webContents->GetController().LoadIfNecessary();
+ // Create a RenderView with the initial empty document
+ content::RenderViewHost *rvh = m_webContents->GetRenderViewHost();
+ Q_ASSERT(rvh);
+ if (!rvh->IsRenderViewLive())
+ static_cast<content::WebContentsImpl *>(m_webContents.get())
+ ->CreateRenderViewForRenderManager(rvh, MSG_ROUTING_NONE, MSG_ROUTING_NONE,
+ base::UnguessableToken::Create(),
+ content::FrameReplicationState());
+ m_webContentsDelegate->RenderViewHostChanged(nullptr, rvh);
+ m_adapterClient->initializationFinished();
+ m_adapterClient->selectionChanged();
+}
+
ASSERT_ENUMS_MATCH(WebContentsAdapterClient::UnknownDisposition, WindowOpenDisposition::UNKNOWN)
ASSERT_ENUMS_MATCH(WebContentsAdapterClient::CurrentTabDisposition, WindowOpenDisposition::CURRENT_TAB)
ASSERT_ENUMS_MATCH(WebContentsAdapterClient::SingletonTabDisposition, WindowOpenDisposition::SINGLETON_TAB)
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index da4bc9190..baf9d241c 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -109,8 +109,17 @@ public:
void load(const QWebEngineHttpRequest &request);
void setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl);
+ using LifecycleState = WebContentsAdapterClient::LifecycleState;
+ LifecycleState lifecycleState() const;
+ void setLifecycleState(LifecycleState state);
+ LifecycleState recommendedState() const;
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
bool canGoBack() const;
bool canGoForward() const;
+ bool canGoToOffset(int) const;
void stop();
void reload();
void reloadAndBypassCache();
@@ -130,6 +139,8 @@ public:
void selectAll();
void unselect();
+ void navigateBack();
+ void navigateForward();
void navigateToIndex(int);
void navigateToOffset(int);
int navigationEntryCount();
@@ -155,7 +166,7 @@ public:
ReferrerPolicy referrerPolicy = ReferrerPolicy::Default);
bool isAudioMuted() const;
void setAudioMuted(bool mute);
- bool recentlyAudible();
+ bool recentlyAudible() const;
// Must match blink::WebMediaPlayerAction::Type.
enum MediaPlayerAction {
@@ -171,6 +182,8 @@ public:
void inspectElementAt(const QPoint &location);
bool hasInspector() const;
+ bool isInspector() const;
+ void setInspector(bool inspector);
void exitFullScreen();
void requestClose();
void changedFullScreen();
@@ -178,8 +191,6 @@ public:
void closeDevToolsFrontend();
void devToolsFrontendDestroyed(DevToolsFrontendQt *frontend);
- void wasShown();
- void wasHidden();
void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags);
void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed);
void grantMouseLockPermission(bool granted);
@@ -222,12 +233,25 @@ public:
// meant to be used within WebEngineCore only
void initialize(content::SiteInstance *site);
content::WebContents *webContents() const;
+ void updateRecommendedState();
private:
Q_DISABLE_COPY(WebContentsAdapter)
void waitForUpdateDragActionCalled();
bool handleDropDataFileContents(const content::DropData &dropData, QMimeData *mimeData);
+ void wasShown();
+ void wasHidden();
+
+ LifecycleState determineRecommendedState() const;
+
+ void freeze();
+ void unfreeze();
+ void discard();
+ void undiscard();
+
+ void initializeRenderPrefs();
+
ProfileAdapter *m_profileAdapter;
std::unique_ptr<content::WebContents> m_webContents;
std::unique_ptr<WebContentsDelegateQt> m_webContentsDelegate;
@@ -247,6 +271,9 @@ private:
QPointF m_lastDragScreenPos;
std::unique_ptr<QTemporaryDir> m_dndTmpDir;
DevToolsFrontendQt *m_devToolsFrontend;
+ LifecycleState m_lifecycleState = LifecycleState::Active;
+ LifecycleState m_recommendedState = LifecycleState::Active;
+ bool m_inspector = false;
};
} // namespace QtWebEngineCore
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 540dd5f1f..d53568215 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -381,7 +381,8 @@ public:
FormSubmittedNavigation,
BackForwardNavigation,
ReloadNavigation,
- OtherNavigation
+ OtherNavigation,
+ RedirectNavigation,
};
enum JavaScriptConsoleMessageLevel {
@@ -411,11 +412,26 @@ public:
};
Q_DECLARE_FLAGS(MediaRequestFlags, MediaRequestFlag)
+ enum class LifecycleState {
+ Active,
+ Frozen,
+ Discarded,
+ };
+
+ enum class LoadingState {
+ Unloaded,
+ Loading,
+ Loaded,
+ };
+
virtual ~WebContentsAdapterClient() { }
virtual RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) = 0;
virtual RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegateForPopup(RenderWidgetHostViewQtDelegateClient *client) = 0;
virtual void initializationFinished() = 0;
+ virtual void lifecycleStateChanged(LifecycleState) = 0;
+ virtual void recommendedStateChanged(LifecycleState) = 0;
+ virtual void visibleChanged(bool) = 0;
virtual void titleChanged(const QString&) = 0;
virtual void urlChanged(const QUrl&) = 0;
virtual void iconChanged(const QUrl&) = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 7719e78d7..f18617f8e 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -105,6 +105,8 @@ WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents *webContents,
, m_lastReceivedFindReply(0)
, m_faviconManager(new FaviconManager(webContents, adapterClient))
, m_lastLoadProgress(-1)
+ , m_loadingState(determineLoadingState(webContents))
+ , m_didStartLoadingSeen(m_loadingState == LoadingState::Loading)
, m_frameFocusedObserver(adapterClient)
{
webContents->SetDelegate(this);
@@ -280,6 +282,18 @@ void WebContentsDelegateQt::RenderFrameDeleted(content::RenderFrameHost *render_
m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID());
}
+void WebContentsDelegateQt::RenderProcessGone(base::TerminationStatus status)
+{
+ // Based one TabLoadTracker::RenderProcessGone
+
+ if (status == base::TerminationStatus::TERMINATION_STATUS_NORMAL_TERMINATION
+ || status == base::TerminationStatus::TERMINATION_STATUS_STILL_RUNNING) {
+ return;
+ }
+
+ setLoadingState(LoadingState::Unloaded);
+}
+
void WebContentsDelegateQt::RenderFrameHostChanged(content::RenderFrameHost *old_host, content::RenderFrameHost *new_host)
{
if (old_host) {
@@ -380,6 +394,46 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig
}
}
+void WebContentsDelegateQt::DidStartLoading()
+{
+ // Based on TabLoadTracker::DidStartLoading
+
+ if (!web_contents()->IsLoadingToDifferentDocument())
+ return;
+ if (m_loadingState == LoadingState::Loading) {
+ DCHECK(m_didStartLoadingSeen);
+ return;
+ }
+ m_didStartLoadingSeen = true;
+}
+
+void WebContentsDelegateQt::DidReceiveResponse()
+{
+ // Based on TabLoadTracker::DidReceiveResponse
+
+ if (m_loadingState == LoadingState::Loading) {
+ DCHECK(m_didStartLoadingSeen);
+ return;
+ }
+
+ // A transition to loading requires both DidStartLoading (navigation
+ // committed) and DidReceiveResponse (data has been transmitted over the
+ // network) events to occur. This is because NavigationThrottles can block
+ // actual network requests, but not the rest of the state machinery.
+ if (m_didStartLoadingSeen)
+ setLoadingState(LoadingState::Loading);
+}
+
+void WebContentsDelegateQt::DidStopLoading()
+{
+ // Based on TabLoadTracker::DidStopLoading
+
+ // NOTE: PageAlmostIdle feature not implemented
+
+ if (m_loadingState == LoadingState::Loading)
+ setLoadingState(LoadingState::Loaded);
+}
+
void WebContentsDelegateQt::didFailLoad(const QUrl &url, int errorCode, const QString &errorDescription)
{
m_viewClient->iconChanged(QUrl());
@@ -388,6 +442,9 @@ void WebContentsDelegateQt::didFailLoad(const QUrl &url, int errorCode, const QS
void WebContentsDelegateQt::DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description)
{
+ if (m_loadingState == LoadingState::Loading)
+ setLoadingState(LoadingState::Loaded);
+
if (render_frame_host != web_contents()->GetMainFrame())
return;
@@ -750,6 +807,82 @@ WebContentsAdapter *WebContentsDelegateQt::webContentsAdapter() const
return m_viewClient->webContentsAdapter();
}
+void WebContentsDelegateQt::copyStateFrom(WebContentsDelegateQt *source)
+{
+ m_url = source->m_url;
+ m_title = source->m_title;
+ NavigationStateChanged(web_contents(), content::INVALIDATE_TYPE_URL);
+ m_faviconManager->copyStateFrom(source->m_faviconManager.data());
+}
+
+WebContentsDelegateQt::LoadingState WebContentsDelegateQt::determineLoadingState(content::WebContents *contents)
+{
+ // Based on TabLoadTracker::DetermineLoadingState
+
+ if (contents->IsLoadingToDifferentDocument() && !contents->IsWaitingForResponse())
+ return LoadingState::Loading;
+
+ content::NavigationController &controller = contents->GetController();
+ if (controller.GetLastCommittedEntry() != nullptr && !controller.IsInitialNavigation() && !controller.NeedsReload())
+ return LoadingState::Loaded;
+
+ return LoadingState::Unloaded;
+}
+
+void WebContentsDelegateQt::setLoadingState(LoadingState state)
+{
+ if (m_loadingState == state)
+ return;
+
+ m_loadingState = state;
+
+ webContentsAdapter()->updateRecommendedState();
+}
+
+int &WebContentsDelegateQt::streamCount(blink::MediaStreamType type)
+{
+ // Based on MediaStreamCaptureIndicator::WebContentsDeviceUsage::GetStreamCount
+ switch (type) {
+ case blink::MEDIA_DEVICE_AUDIO_CAPTURE:
+ return m_audioStreamCount;
+
+ case blink::MEDIA_DEVICE_VIDEO_CAPTURE:
+ return m_videoStreamCount;
+
+ case blink::MEDIA_GUM_TAB_AUDIO_CAPTURE:
+ case blink::MEDIA_GUM_TAB_VIDEO_CAPTURE:
+ return m_mirroringStreamCount;
+
+ case blink::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE:
+ case blink::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE:
+ case blink::MEDIA_DISPLAY_VIDEO_CAPTURE:
+ case blink::MEDIA_DISPLAY_AUDIO_CAPTURE:
+ return m_desktopStreamCount;
+
+ case blink::MEDIA_NO_SERVICE:
+ case blink::NUM_MEDIA_TYPES:
+ NOTREACHED();
+ return m_videoStreamCount;
+ }
+ NOTREACHED();
+ return m_videoStreamCount;
+}
+
+void WebContentsDelegateQt::addDevices(const blink::MediaStreamDevices &devices)
+{
+ for (const auto &device : devices)
+ ++streamCount(device.type);
+
+ webContentsAdapter()->updateRecommendedState();
+}
+
+void WebContentsDelegateQt::removeDevices(const blink::MediaStreamDevices &devices)
+{
+ for (const auto &device : devices)
+ ++streamCount(device.type);
+
+ webContentsAdapter()->updateRecommendedState();
+}
FrameFocusedObserver::FrameFocusedObserver(WebContentsAdapterClient *adapterClient)
: m_viewClient(adapterClient)
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 9a3afebed..00b715c30 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -41,6 +41,7 @@
#define WEB_CONTENTS_DELEGATE_QT_H
#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/public/browser/media_capture_devices.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -153,10 +154,14 @@ public:
// WebContentsObserver overrides
void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override;
+ void RenderProcessGone(base::TerminationStatus status) override;
void RenderFrameHostChanged(content::RenderFrameHost *old_host, content::RenderFrameHost *new_host) override;
void RenderViewHostChanged(content::RenderViewHost *old_host, content::RenderViewHost *new_host) override;
void DidStartNavigation(content::NavigationHandle *navigation_handle) override;
void DidFinishNavigation(content::NavigationHandle *navigation_handle) override;
+ void DidStartLoading() override;
+ void DidReceiveResponse() override;
+ void DidStopLoading() override;
void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) override;
void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) override;
void BeforeUnloadFired(bool proceed, const base::TimeTicks& proceed_time) override;
@@ -181,12 +186,32 @@ public:
WebContentsAdapter *webContentsAdapter() const;
WebContentsAdapterClient *adapterClient() const { return m_viewClient; }
+ void copyStateFrom(WebContentsDelegateQt *source);
+
+ using LoadingState = WebContentsAdapterClient::LoadingState;
+ LoadingState loadingState() const { return m_loadingState; }
+
+ void addDevices(const blink::MediaStreamDevices &devices);
+ void removeDevices(const blink::MediaStreamDevices &devices);
+
+ bool isCapturingAudio() const { return m_audioStreamCount > 0; }
+ bool isCapturingVideo() const { return m_videoStreamCount > 0; }
+ bool isMirroring() const { return m_mirroringStreamCount > 0; }
+ bool isCapturingDesktop() const { return m_desktopStreamCount > 0; }
+
+ base::WeakPtr<WebContentsDelegateQt> AsWeakPtr() { return m_weakPtrFactory.GetWeakPtr(); }
+
private:
QWeakPointer<WebContentsAdapter> createWindow(std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture);
void EmitLoadStarted(const QUrl &url, bool isErrorPage = false);
void EmitLoadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString());
void EmitLoadCommitted();
+ LoadingState determineLoadingState(content::WebContents *contents);
+ void setLoadingState(LoadingState state);
+
+ int &streamCount(blink::MediaStreamType type);
+
WebContentsAdapterClient *m_viewClient;
QString m_lastSearchedString;
int m_lastReceivedFindReply;
@@ -196,10 +221,18 @@ private:
QSharedPointer<FilePickerController> m_filePickerController;
QUrl m_initialTargetUrl;
int m_lastLoadProgress;
+ LoadingState m_loadingState;
+ bool m_didStartLoadingSeen;
FrameFocusedObserver m_frameFocusedObserver;
QUrl m_url;
QString m_title;
+ int m_audioStreamCount = 0;
+ int m_videoStreamCount = 0;
+ int m_mirroringStreamCount = 0;
+ int m_desktopStreamCount = 0;
+
+ base::WeakPtrFactory<WebContentsDelegateQt> m_weakPtrFactory { this };
};
} // namespace QtWebEngineCore
diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h
index ec09f9aae..978a2ce2e 100644
--- a/src/core/web_contents_view_qt.h
+++ b/src/core/web_contents_view_qt.h
@@ -111,8 +111,7 @@ public:
void FocusThroughTabTraversal(bool reverse) override;
#if defined(OS_MACOSX)
- void CloseTabAfterEventTracking() override { QT_NOT_YET_IMPLEMENTED }
- bool IsEventTracking() const override { QT_NOT_YET_IMPLEMENTED; return false; }
+ bool CloseTabAfterEventTrackingIfNeeded() override { QT_NOT_YET_IMPLEMENTED return false; }
#endif // defined(OS_MACOSX)
// content::RenderViewHostDelegateView overrides:
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp
index a3a5881bf..a988040ee 100644
--- a/src/core/web_engine_context.cpp
+++ b/src/core/web_engine_context.cpp
@@ -44,9 +44,9 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
-#include "base/message_loop/message_loop_impl.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
+#include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
#include "base/threading/thread_restrictions.h"
#include "cc/base/switches.h"
#if QT_CONFIG(webengine_printing_and_pdf)
@@ -74,12 +74,15 @@
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/ipc/host/gpu_switches.h"
#include "media/audio/audio_manager.h"
+#include "media/base/media_switches.h"
#include "mojo/core/embedder/embedder.h"
#include "net/base/port_util.h"
#include "ppapi/buildflags/buildflags.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
#include "services/service_manager/sandbox/switches.h"
+#include "third_party/blink/public/common/features.h"
#include "ui/events/event_switches.h"
#include "ui/native_theme/native_theme_features.h"
#include "ui/gl/gl_switches.h"
@@ -241,7 +244,8 @@ void WebEngineContext::destroy()
destroyGpuProcess();
base::MessagePump::Delegate *delegate =
- static_cast<base::MessageLoopImpl *>(m_runLoop->delegate_);
+ static_cast<base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl *>(
+ m_runLoop->delegate_);
// Flush the UI message loop before quitting.
while (delegate->DoWork()) { }
@@ -386,7 +390,7 @@ WebEngineContext::WebEngineContext()
: m_mainDelegate(new ContentMainDelegateQt)
, m_globalQObject(new QObject())
{
- base::TaskScheduler::Create("Browser");
+ base::ThreadPool::Create("Browser");
m_contentRunner.reset(content::ContentMainRunner::Create());
m_browserRunner = content::BrowserMainRunner::Create();
@@ -500,17 +504,28 @@ WebEngineContext::WebEngineContext()
// Breaks WebEngineNewViewRequest.userInitiated API (since 73)
appendToFeatureList(disableFeatures, features::kUserActivationV2.name);
- appendToFeatureList(disableFeatures, features::kBackgroundFetch.name);
+ // We do not yet support the network-service, but it is enabled by default since 75.
+ appendToFeatureList(disableFeatures, network::features::kNetworkService.name);
+ // VideoSurfaceLayer is enabled by default since 75. We don't support it.
+ appendToFeatureList(disableFeatures, media::kUseSurfaceLayerForVideo.name);
+ // BlinkGenPropertyTrees is enabled by default in 75, but causes regressions.
+ appendToFeatureList(disableFeatures, blink::features::kBlinkGenPropertyTrees.name);
#if QT_CONFIG(webengine_printing_and_pdf)
appendToFeatureList(disableFeatures, printing::features::kUsePdfCompositorServiceForPrint.name);
#endif
+ // Explicitly tell Chromium about default-on features we do not support
+ appendToFeatureList(disableFeatures, features::kBackgroundFetch.name);
+ appendToFeatureList(disableFeatures, features::kOriginTrials.name);
+ appendToFeatureList(disableFeatures, features::kWebAuth.name);
+ appendToFeatureList(disableFeatures, features::kWebAuthCable.name);
+ appendToFeatureList(disableFeatures, features::kWebPayments.name);
+ appendToFeatureList(disableFeatures, features::kWebUsb.name);
+
if (useEmbeddedSwitches) {
// embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc
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);
@@ -612,11 +627,6 @@ WebEngineContext::WebEngineContext()
SetContentClient(new ContentClientQt);
- content::StartBrowserTaskScheduler();
- content::BrowserTaskExecutor::Create();
-
- mojo::core::Init();
-
content::ContentMainParams contentMainParams(m_mainDelegate.get());
#if defined(OS_WIN)
sandbox::SandboxInterfaceInfo sandbox_info = {0};
@@ -624,12 +634,24 @@ WebEngineContext::WebEngineContext()
contentMainParams.sandbox_info = &sandbox_info;
#endif
m_contentRunner->Initialize(contentMainParams);
- m_browserRunner->Initialize(content::MainFunctionParams(*base::CommandLine::ForCurrentProcess()));
+
+ mojo::core::Init();
+
+ // This block mirrors ContentMainRunnerImpl::RunServiceManager():
+ m_mainDelegate->PreCreateMainMessageLoop();
+ base::MessageLoop::InitMessagePumpForUIFactory(messagePumpFactory);
+ content::BrowserTaskExecutor::Create();
+ m_mainDelegate->PostEarlyInitialization(false);
+ content::StartBrowserThreadPool();
+ content::BrowserTaskExecutor::PostFeatureListSetup();
// Once the MessageLoop has been created, attach a top-level RunLoop.
m_runLoop.reset(new base::RunLoop);
m_runLoop->BeforeRun();
+ content::MainFunctionParams mainParams(*base::CommandLine::ForCurrentProcess());
+ m_browserRunner->Initialize(mainParams);
+
m_devtoolsServer.reset(new DevToolsServerQt());
m_devtoolsServer->start();
// Force the initialization of MediaCaptureDevicesDispatcher on the UI
diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp
index b6250a65f..9bc1279ba 100644
--- a/src/core/web_engine_settings.cpp
+++ b/src/core/web_engine_settings.cpp
@@ -49,10 +49,10 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
-#include "content/public/common/renderer_preferences.h"
#include "content/public/common/web_preferences.h"
-#include "media/base/media_switches.h"
#include "content/public/common/webrtc_ip_handling_policy.h"
+#include "media/base/media_switches.h"
+#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
#include "ui/events/event_switches.h"
#include <QFont>
@@ -401,7 +401,7 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p
prefs->default_encoding = defaultTextEncoding().toStdString();
}
-bool WebEngineSettings::applySettingsToRendererPreferences(content::RendererPreferences *prefs)
+bool WebEngineSettings::applySettingsToRendererPreferences(blink::mojom::RendererPreferences *prefs)
{
bool changed = false;
#if QT_CONFIG(webengine_webrtc)
diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h
index b2a45098a..95eea669f 100644
--- a/src/core/web_engine_settings.h
+++ b/src/core/web_engine_settings.h
@@ -60,10 +60,14 @@
#include <QTimer>
namespace content {
-struct RendererPreferences;
class WebContents;
struct WebPreferences;
}
+namespace blink {
+namespace mojom {
+class RendererPreferences;
+}
+}
namespace QtWebEngineCore {
class WebContentsAdapter;
@@ -169,7 +173,7 @@ public:
private:
void doApply();
void applySettingsToWebPreferences(content::WebPreferences *);
- bool applySettingsToRendererPreferences(content::RendererPreferences *);
+ bool applySettingsToRendererPreferences(blink::mojom::RendererPreferences *);
void setWebContentsAdapter(WebContentsAdapter *adapter) { m_adapter = adapter; }
WebContentsAdapter* m_adapter;
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index b97696030..1b0723cb5 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -92,24 +92,24 @@ static KeyboardDriver keyboardDriverImpl()
{
QString platformName = QGuiApplication::platformName();
- if (platformName == QLatin1Literal("windows"))
+ if (platformName == QLatin1String("windows"))
return KeyboardDriver::Windows;
- if (platformName == QLatin1Literal("cocoa"))
+ if (platformName == QLatin1String("cocoa"))
return KeyboardDriver::Cocoa;
- if (platformName == QLatin1Literal("xcb") || platformName == QLatin1Literal("wayland"))
+ if (platformName == QLatin1String("xcb") || platformName == QLatin1String("wayland"))
return KeyboardDriver::Xkb;
#if QT_CONFIG(libinput)
// Based on QEglFSIntegration::createInputHandlers and QLibInputKeyboard::processKey.
- if (platformName == QLatin1Literal("eglfs") && !qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT"))
+ if (platformName == QLatin1String("eglfs") && !qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT"))
return KeyboardDriver::Xkb;
#endif
#if QT_CONFIG(evdev)
// Based on QEglFSIntegration::createInputHandlers.
- if (platformName == QLatin1Literal("eglfs"))
+ if (platformName == QLatin1String("eglfs"))
return KeyboardDriver::Evdev;
#endif
@@ -1428,7 +1428,7 @@ WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev)
webKitEvent.SetPositionInScreen(WebFloatPoint(ev->screenPos().x(),
ev->screenPos().y()));
- webKitEvent.SetSourceDevice(blink::kWebGestureDeviceTouchpad);
+ webKitEvent.SetSourceDevice(blink::WebGestureDevice::kTouchpad);
Qt::NativeGestureType gestureType = ev->gestureType();
switch (gestureType) {
diff --git a/src/webengine/api/qquickwebenginedialogrequests.cpp b/src/webengine/api/qquickwebenginedialogrequests.cpp
index d6bba9a98..da1aecaf6 100644
--- a/src/webengine/api/qquickwebenginedialogrequests.cpp
+++ b/src/webengine/api/qquickwebenginedialogrequests.cpp
@@ -44,6 +44,9 @@
#include "file_picker_controller.h"
#include "web_contents_adapter_client.h"
+#include <QCursor>
+#include <QQuickItem>
+
QT_BEGIN_NAMESPACE
using namespace QtWebEngineCore;
@@ -823,4 +826,111 @@ void QQuickWebEngineFormValidationMessageRequest::setAccepted(bool accepted)
m_accepted = accepted;
}
+///////////////////////////////////////////////////////////////////////////////
+
+/*!
+ \qmltype TooltipRequest
+ \instantiates QQuickWebEngineTooltipRequest
+ \inqmlmodule QtWebEngine
+ \since QtWebEngine 1.10
+
+ \brief A request for showing a tooltip to the user.
+*/
+
+QQuickWebEngineTooltipRequest::QQuickWebEngineTooltipRequest(
+ const QString &text, QObject *parent):
+ QObject(parent)
+ , m_text(text)
+ , m_type(text.isEmpty() ? RequestType::Hide : RequestType::Show)
+ , m_accepted(false)
+{
+ Q_ASSERT(parent);
+ if (QQuickItem *view = qobject_cast<QQuickItem *>(parent))
+ m_position = view->mapFromGlobal(view->cursor().pos()).toPoint();
+}
+
+QQuickWebEngineTooltipRequest::~QQuickWebEngineTooltipRequest()
+{
+
+}
+
+/*!
+ \qmlproperty int TooltipRequest::x
+ \readonly
+
+ The x coordinate of the top-left corner of the requested tooltip.
+*/
+
+int QQuickWebEngineTooltipRequest::x() const
+{
+ return m_position.x();
+}
+
+/*!
+ \qmlproperty int TooltipRequest::y
+ \readonly
+
+ The y coordinate of the top-left corner of the requested tooltip.
+*/
+
+int QQuickWebEngineTooltipRequest::y() const
+{
+ return m_position.y();
+}
+
+/*!
+ \qmlproperty bool TooltipRequest::text
+ \readonly
+
+ The text of the tooltip. It contains an empty string when the
+ tooltip should be hidden.
+*/
+
+
+QString QQuickWebEngineTooltipRequest::text() const
+{
+ return m_text;
+}
+
+/*!
+ \qmlproperty enumeration TooltipRequest::type
+ \readonly
+
+ The type of the tooltip request.
+
+ \value TooltipRequest.Show
+ The tooltip should be shown.
+ \value TooltipRequest.Hide
+ The tooltip should be hidden.
+*/
+
+QQuickWebEngineTooltipRequest::RequestType QQuickWebEngineTooltipRequest::type() const
+{
+ return m_type;
+}
+
+/*!
+ \qmlproperty bool TooltipRequest::accepted
+
+ Indicates whether the tooltip request has been accepted
+ by the signal handler.
+
+ If the property is \c false after any signal handlers
+ for WebEngineView::tooltipRequested have been executed,
+ a default tooltip will be shown.
+ To prevent this, set \c {request.accepted} to \c true.
+
+ The default is \c false.
+*/
+
+bool QQuickWebEngineTooltipRequest::isAccepted() const
+{
+ return m_accepted;
+}
+
+void QQuickWebEngineTooltipRequest::setAccepted(bool accepted)
+{
+ m_accepted = accepted;
+}
+
QT_END_NAMESPACE
diff --git a/src/webengine/api/qquickwebenginedialogrequests_p.h b/src/webengine/api/qquickwebenginedialogrequests_p.h
index cdb10c26b..5e3f7c547 100644
--- a/src/webengine/api/qquickwebenginedialogrequests_p.h
+++ b/src/webengine/api/qquickwebenginedialogrequests_p.h
@@ -260,6 +260,39 @@ private:
friend class QQuickWebEngineViewPrivate;
};
+class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineTooltipRequest : public QObject {
+ Q_OBJECT
+public:
+ enum RequestType {
+ Show,
+ Hide,
+ };
+ Q_ENUM(RequestType)
+ Q_PROPERTY(int x READ x CONSTANT FINAL)
+ Q_PROPERTY(int y READ y CONSTANT FINAL)
+ Q_PROPERTY(QString text READ text CONSTANT FINAL)
+ Q_PROPERTY(RequestType type READ type CONSTANT FINAL)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted FINAL)
+
+ ~QQuickWebEngineTooltipRequest();
+ int x() const;
+ int y() const;
+ QString text() const;
+ RequestType type() const;
+ bool isAccepted() const;
+ void setAccepted(bool accepted);
+
+private:
+ QQuickWebEngineTooltipRequest(const QString &text = QString(),
+ QObject *parent = nullptr);
+ QPoint m_position;
+ QString m_text;
+ RequestType m_type;
+ bool m_accepted;
+ friend class QQuickWebEngineViewPrivate;
+ Q_DISABLE_COPY(QQuickWebEngineTooltipRequest)
+};
+
QT_END_NAMESPACE
#endif // QQUICKWEBENGINDIALOGREQUESTS_H
diff --git a/src/webengine/api/qquickwebenginedownloaditem.cpp b/src/webengine/api/qquickwebenginedownloaditem.cpp
index 7d51ed21d..f9b305e88 100644
--- a/src/webengine/api/qquickwebenginedownloaditem.cpp
+++ b/src/webengine/api/qquickwebenginedownloaditem.cpp
@@ -43,6 +43,7 @@
#include "profile_adapter.h"
#include "qquickwebengineprofile_p.h"
+#include <QDir>
#include "QFileInfo"
using QtWebEngineCore::ProfileAdapterClient;
@@ -98,7 +99,7 @@ static inline QQuickWebEngineDownloadItem::DownloadInterruptReason toDownloadInt
return static_cast<QQuickWebEngineDownloadItem::DownloadInterruptReason>(reason);
}
-QQuickWebEngineDownloadItemPrivate::QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfile *p)
+QQuickWebEngineDownloadItemPrivate::QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfile *p, const QUrl &url)
: profile(p)
, downloadId(-1)
, downloadState(QQuickWebEngineDownloadItem::DownloadCancelled)
@@ -110,6 +111,7 @@ QQuickWebEngineDownloadItemPrivate::QQuickWebEngineDownloadItemPrivate(QQuickWeb
, downloadFinished(false)
, downloadPaused(false)
, view(nullptr)
+ , downloadUrl(url)
{
}
@@ -388,6 +390,20 @@ qint64 QQuickWebEngineDownloadItem::receivedBytes() const
}
/*!
+ \qmlproperty url WebEngineDownloadItem::url
+ \readonly
+ \since QtWebEngine 1.10
+
+ Returns the download's origin URL.
+*/
+
+QUrl QQuickWebEngineDownloadItem::url() const
+{
+ Q_D(const QQuickWebEngineDownloadItem);
+ return d->downloadUrl;
+}
+
+/*!
\qmlproperty string WebEngineDownloadItem::mimeType
\since QtWebEngine 1.2
@@ -402,6 +418,7 @@ QString QQuickWebEngineDownloadItem::mimeType() const
/*!
\qmlproperty string WebEngineDownloadItem::path
+ \obsolete
Holds the full target path where data is being downloaded to.
@@ -418,7 +435,7 @@ QString QQuickWebEngineDownloadItem::mimeType() const
QString QQuickWebEngineDownloadItem::path() const
{
Q_D(const QQuickWebEngineDownloadItem);
- return d->downloadPath;
+ return QDir::cleanPath(QDir(d->downloadDirectory).filePath(d->downloadFileName));
}
void QQuickWebEngineDownloadItem::setPath(QString path)
@@ -428,7 +445,7 @@ void QQuickWebEngineDownloadItem::setPath(QString path)
qWarning("Setting the download path is not allowed after the download has been accepted.");
return;
}
- if (d->downloadPath != path) {
+ if (QDir(d->downloadDirectory).filePath(d->downloadFileName) != path) {
if (QFileInfo(path).fileName().isEmpty()) {
qWarning("The download path does not include file name.");
return;
@@ -439,12 +456,127 @@ void QQuickWebEngineDownloadItem::setPath(QString path)
return;
}
- d->downloadPath = path;
+ QString newDirectory;
+ QString newFileName;
+
+ if (QFileInfo(path).fileName() == path) {
+ newDirectory = QStringLiteral("");
+ newFileName = path;
+ } else {
+ newDirectory = QFileInfo(path).filePath();
+ newFileName = QFileInfo(path).fileName();
+ }
+
+ if (d->downloadDirectory != newDirectory) {
+ d->downloadDirectory = newDirectory;
+ Q_EMIT pathChanged();
+ Q_EMIT downloadDirectoryChanged();
+ }
+
+ if (d->downloadFileName != newFileName) {
+ d->downloadFileName = newFileName;
+ Q_EMIT pathChanged();
+ Q_EMIT downloadFileNameChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty string WebEngineDownloadItem::downloadDirectory
+ \since QtWebEngine 1.10
+
+ Holds the full target path without file name where data is being downloaded to.
+
+ The download directory can only be set in the
+ \l{WebEngineProfile::downloadRequested}{downloadRequested} handler before
+ the download is accepted.
+
+ \sa WebEngineProfile::downloadRequested(), accept()
+*/
+
+QString QQuickWebEngineDownloadItem::downloadDirectory() const
+{
+ Q_D(const QQuickWebEngineDownloadItem);
+ return d->downloadDirectory;
+}
+
+void QQuickWebEngineDownloadItem::setDownloadDirectory(QString directory)
+{
+ Q_D(QQuickWebEngineDownloadItem);
+ if (d->downloadState != QQuickWebEngineDownloadItem::DownloadRequested) {
+ qWarning("Setting the download directory is not allowed after the download has been accepted.");
+ return;
+ }
+
+ QString changeDirectory = d->downloadDirectory;
+ if (!directory.isEmpty() && changeDirectory != directory) {
+ changeDirectory = directory;
+
+ if (d->downloadDirectory != changeDirectory) {
+ d->downloadDirectory = changeDirectory;
+ Q_EMIT pathChanged();
+ Q_EMIT downloadDirectoryChanged();
+ }
+
+ QString newFileName = QFileInfo(d->profile->d_ptr->profileAdapter()->updateDownloadPath(d->downloadId,
+ d->downloadDirectory,
+ d->suggestedFileName)).fileName();
+ if (d->downloadFileName != newFileName) {
+ d->downloadFileName = newFileName;
+ Q_EMIT pathChanged();
+ Q_EMIT downloadFileNameChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty string WebEngineDownloadItem::downloadFileName
+ \since QtWebEngine 1.10
+
+ Holds the name of the file to which data is being downloaded.
+
+ The download file name can only be set in the
+ \l{WebEngineProfile::downloadRequested}{downloadRequested} handler before
+ the download is accepted.
+
+ \sa WebEngineProfile::downloadRequested(), accept()
+*/
+
+QString QQuickWebEngineDownloadItem::downloadFileName() const
+{
+ Q_D(const QQuickWebEngineDownloadItem);
+ return d->downloadFileName;
+}
+
+void QQuickWebEngineDownloadItem::setDownloadFileName(QString fileName)
+{
+ Q_D(QQuickWebEngineDownloadItem);
+ if (d->downloadState != QQuickWebEngineDownloadItem::DownloadRequested) {
+ qWarning("Setting the download file name is not allowed after the download has been accepted.");
+ return;
+ }
+
+ if (d->downloadFileName != fileName && !fileName.isEmpty()) {
+ d->downloadFileName = fileName;
Q_EMIT pathChanged();
+ Q_EMIT downloadFileNameChanged();
}
}
/*!
+ \qmlproperty string WebEngineDownloadItem::suggestedFileName
+ \since QtWebEngine 1.10
+
+ Returns the suggested file name.
+*/
+
+QString QQuickWebEngineDownloadItem::suggestedFileName() const
+{
+ Q_D(const QQuickWebEngineDownloadItem);
+ return d->suggestedFileName;
+}
+
+/*!
\qmlproperty enumeration WebEngineDownloadItem::savePageFormat
\since QtWebEngine 1.3
diff --git a/src/webengine/api/qquickwebenginedownloaditem_p.h b/src/webengine/api/qquickwebenginedownloaditem_p.h
index d19ca4828..cef99e534 100644
--- a/src/webengine/api/qquickwebenginedownloaditem_p.h
+++ b/src/webengine/api/qquickwebenginedownloaditem_p.h
@@ -55,6 +55,7 @@
#include <QObject>
#include <QScopedPointer>
#include <QString>
+#include <QUrl>
QT_BEGIN_NAMESPACE
@@ -136,6 +137,10 @@ public:
Q_PROPERTY(bool isPaused READ isPaused NOTIFY isPausedChanged REVISION 5 FINAL)
Q_PROPERTY(bool isSavePageDownload READ isSavePageDownload CONSTANT REVISION 6 FINAL)
Q_PROPERTY(QQuickWebEngineView *view READ view CONSTANT REVISION 7 FINAL)
+ Q_PROPERTY(QUrl url READ url CONSTANT REVISION 8 FINAL)
+ Q_PROPERTY(QString suggestedFileName READ suggestedFileName CONSTANT REVISION 8 FINAL)
+ Q_PROPERTY(QString downloadDirectory READ downloadDirectory WRITE setDownloadDirectory NOTIFY downloadDirectoryChanged REVISION 8 FINAL)
+ Q_PROPERTY(QString downloadFileName READ downloadFileName WRITE setDownloadFileName NOTIFY downloadFileNameChanged REVISION 8 FINAL)
Q_INVOKABLE void accept();
Q_INVOKABLE void cancel();
@@ -147,8 +152,8 @@ public:
qint64 totalBytes() const;
qint64 receivedBytes() const;
QString mimeType() const;
- QString path() const;
- void setPath(QString path);
+ QString Q_DECL_DEPRECATED path() const;
+ void Q_DECL_DEPRECATED setPath(QString path);
SavePageFormat savePageFormat() const;
void setSavePageFormat(SavePageFormat format);
DownloadType Q_DECL_DEPRECATED type() const;
@@ -158,6 +163,12 @@ public:
bool isPaused() const;
bool isSavePageDownload() const;
QQuickWebEngineView *view() const;
+ QUrl url() const;
+ QString suggestedFileName() const;
+ QString downloadDirectory() const;
+ void setDownloadDirectory(QString directory);
+ QString downloadFileName() const;
+ void setDownloadFileName(QString fileName);
Q_SIGNALS:
void stateChanged();
@@ -165,11 +176,13 @@ Q_SIGNALS:
void receivedBytesChanged();
void totalBytesChanged();
Q_REVISION(1) void mimeTypeChanged();
- void pathChanged();
+ void Q_DECL_DEPRECATED pathChanged();
Q_REVISION(3) void typeChanged();
Q_REVISION(4) void interruptReasonChanged();
Q_REVISION(5) void isFinishedChanged();
Q_REVISION(5) void isPausedChanged();
+ Q_REVISION(8) void downloadDirectoryChanged();
+ Q_REVISION(8) void downloadFileNameChanged();
private:
QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate*, QObject *parent = 0);
diff --git a/src/webengine/api/qquickwebenginedownloaditem_p_p.h b/src/webengine/api/qquickwebenginedownloaditem_p_p.h
index f444c04a5..51deee18b 100644
--- a/src/webengine/api/qquickwebenginedownloaditem_p_p.h
+++ b/src/webengine/api/qquickwebenginedownloaditem_p_p.h
@@ -67,7 +67,7 @@ class QQuickWebEngineDownloadItemPrivate {
friend class QQuickWebEngineProfilePrivate;
public:
Q_DECLARE_PUBLIC(QQuickWebEngineDownloadItem)
- QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfile *p);
+ QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfile *p, const QUrl &url);
~QQuickWebEngineDownloadItemPrivate();
quint32 downloadId;
@@ -82,6 +82,10 @@ public:
bool downloadFinished;
bool downloadPaused;
QQuickWebEngineView *view;
+ QUrl downloadUrl;
+ QString suggestedFileName;
+ QString downloadDirectory;
+ QString downloadFileName;
void update(const QtWebEngineCore::ProfileAdapterClient::DownloadItemInfo &info);
void updateState(QQuickWebEngineDownloadItem::DownloadState newState);
diff --git a/src/webengine/api/qquickwebenginenavigationrequest.cpp b/src/webengine/api/qquickwebenginenavigationrequest.cpp
index a6e253561..03c1d3d78 100644
--- a/src/webengine/api/qquickwebenginenavigationrequest.cpp
+++ b/src/webengine/api/qquickwebenginenavigationrequest.cpp
@@ -143,6 +143,8 @@ QQuickWebEngineView::NavigationRequestAction QQuickWebEngineNavigationRequest::a
Using navigation history to go to the previous or next page.
\value WebEngineNavigationRequest.ReloadNavigation
Reloading the page.
+ \value WebEngineNavigationRequest.RedirectNavigation
+ Page content or server triggered a redirection or page refresh.
\value WebEngineNavigationRequest.OtherNavigation
Using some other method to go to a page.
*/
diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp
index 4832ba303..57434e296 100644
--- a/src/webengine/api/qquickwebengineprofile.cpp
+++ b/src/webengine/api/qquickwebengineprofile.cpp
@@ -48,6 +48,8 @@
#include "qwebenginecookiestore.h"
#include "qwebenginenotification.h"
+#include <QFileInfo>
+#include <QDir>
#include <QQmlEngine>
#include "profile_adapter.h"
@@ -237,12 +239,14 @@ void QQuickWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
Q_Q(QQuickWebEngineProfile);
Q_ASSERT(!m_ongoingDownloads.contains(info.id));
- QQuickWebEngineDownloadItemPrivate *itemPrivate = new QQuickWebEngineDownloadItemPrivate(q);
+ QQuickWebEngineDownloadItemPrivate *itemPrivate = new QQuickWebEngineDownloadItemPrivate(q, info.url);
itemPrivate->downloadId = info.id;
itemPrivate->downloadState = QQuickWebEngineDownloadItem::DownloadRequested;
itemPrivate->totalBytes = info.totalBytes;
itemPrivate->mimeType = info.mimeType;
- itemPrivate->downloadPath = info.path;
+ itemPrivate->downloadDirectory = QFileInfo(info.path).path();
+ itemPrivate->downloadFileName = QFileInfo(info.path).fileName();
+ itemPrivate->suggestedFileName = info.suggestedFileName;
itemPrivate->savePageFormat = static_cast<QQuickWebEngineDownloadItem::SavePageFormat>(
info.savePageFormat);
itemPrivate->type = static_cast<QQuickWebEngineDownloadItem::DownloadType>(info.downloadType);
@@ -260,7 +264,7 @@ void QQuickWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
Q_EMIT q->downloadRequested(download);
QQuickWebEngineDownloadItem::DownloadState state = download->state();
- info.path = download->path();
+ info.path = QDir(download->downloadDirectory()).filePath(download->downloadFileName());
info.savePageFormat = itemPrivate->savePageFormat;
info.accepted = state != QQuickWebEngineDownloadItem::DownloadCancelled
&& state != QQuickWebEngineDownloadItem::DownloadRequested;
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index bb8428951..30283dc03 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -136,7 +136,7 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate()
memset(actions, 0, sizeof(actions));
QString platform = qApp->platformName().toLower();
- if (platform == QLatin1Literal("eglfs"))
+ if (platform == QLatin1String("eglfs"))
m_ui2Enabled = true;
const QByteArray dialogSet = qgetenv("QTWEBENGINE_DIALOG_SET");
@@ -413,6 +413,11 @@ void QQuickWebEngineViewPrivate::didUpdateTargetURL(const QUrl &hoveredUrl)
Q_EMIT q->linkHovered(hoveredUrl);
}
+void QQuickWebEngineViewPrivate::selectionChanged()
+{
+ updateEditActions();
+}
+
void QQuickWebEngineViewPrivate::recentlyAudibleChanged(bool recentlyAudible)
{
Q_Q(QQuickWebEngineView);
@@ -705,6 +710,25 @@ const QObject *QQuickWebEngineViewPrivate::holdingQObject() const
return q;
}
+void QQuickWebEngineViewPrivate::lifecycleStateChanged(LifecycleState state)
+{
+ Q_Q(QQuickWebEngineView);
+ Q_EMIT q->lifecycleStateChanged(static_cast<QQuickWebEngineView::LifecycleState>(state));
+}
+
+void QQuickWebEngineViewPrivate::recommendedStateChanged(LifecycleState state)
+{
+ Q_Q(QQuickWebEngineView);
+ QTimer::singleShot(0, q, [q, state]() {
+ Q_EMIT q->recommendedStateChanged(static_cast<QQuickWebEngineView::LifecycleState>(state));
+ });
+}
+
+void QQuickWebEngineViewPrivate::visibleChanged(bool visible)
+{
+ Q_UNUSED(visible);
+}
+
#ifndef QT_NO_ACCESSIBILITY
QQuickWebEngineViewAccessible::QQuickWebEngineViewAccessible(QQuickWebEngineView *o)
: QAccessibleObject(o)
@@ -844,8 +868,8 @@ void QQuickWebEngineViewPrivate::initializationFinished()
for (QQuickWebEngineScript *script : qAsConst(m_userScripts))
script->d_func()->bind(profileAdapter()->userResourceController(), adapter.data());
- if (q->window() && q->isVisible())
- adapter->wasShown();
+ if (q->window())
+ adapter->setVisible(q->isVisible());
if (!m_isBeingAdopted)
return;
@@ -944,12 +968,14 @@ void QQuickWebEngineViewPrivate::updateAction(QQuickWebEngineView::WebAction act
break;
case QQuickWebEngineView::Cut:
case QQuickWebEngineView::Copy:
+ case QQuickWebEngineView::Unselect:
+ enabled = adapter->hasFocusedFrame() && !adapter->selectedText().isEmpty();
+ break;
case QQuickWebEngineView::Paste:
case QQuickWebEngineView::Undo:
case QQuickWebEngineView::Redo:
case QQuickWebEngineView::SelectAll:
case QQuickWebEngineView::PasteAndMatchStyle:
- case QQuickWebEngineView::Unselect:
enabled = adapter->hasFocusedFrame();
break;
default:
@@ -1025,13 +1051,13 @@ void QQuickWebEngineView::loadHtml(const QString &html, const QUrl &baseUrl)
void QQuickWebEngineView::goBack()
{
Q_D(QQuickWebEngineView);
- d->adapter->navigateToOffset(-1);
+ d->adapter->navigateBack();
}
void QQuickWebEngineView::goForward()
{
Q_D(QQuickWebEngineView);
- d->adapter->navigateToOffset(1);
+ d->adapter->navigateForward();
}
void QQuickWebEngineView::reload()
@@ -1237,7 +1263,13 @@ bool QQuickWebEngineViewPrivate::isEnabled() const
void QQuickWebEngineViewPrivate::setToolTip(const QString &toolTipText)
{
- ui()->showToolTip(toolTipText);
+ Q_Q(QQuickWebEngineView);
+ QQuickWebEngineTooltipRequest *request = new QQuickWebEngineTooltipRequest(toolTipText, q);
+ // mark the object for gc by creating temporary jsvalue
+ qmlEngine(q)->newQObject(request);
+ Q_EMIT q->tooltipRequested(request);
+ if (!request->isAccepted())
+ ui()->showToolTip(toolTipText);
}
QtWebEngineCore::TouchHandleDrawableClient *QQuickWebEngineViewPrivate::createTouchHandle(const QMap<int, QImage> &images)
@@ -1633,10 +1665,8 @@ void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &va
Q_D(QQuickWebEngineView);
if (d && d->profileInitialized() && d->adapter->isInitialized()
&& (change == ItemSceneChange || change == ItemVisibleHasChanged)) {
- if (window() && isVisible())
- d->adapter->wasShown();
- else
- d->adapter->wasHidden();
+ if (window())
+ d->adapter->setVisible(isVisible());
}
QQuickItem::itemChange(change, value);
}
@@ -1686,10 +1716,10 @@ void QQuickWebEngineView::triggerWebAction(WebAction action)
Q_D(QQuickWebEngineView);
switch (action) {
case Back:
- d->adapter->navigateToOffset(-1);
+ d->adapter->navigateBack();
break;
case Forward:
- d->adapter->navigateToOffset(1);
+ d->adapter->navigateForward();
break;
case Stop:
d->adapter->stop();
@@ -2148,6 +2178,24 @@ void QQuickWebEngineView::lazyInitialize()
d->ensureContentsAdapter();
}
+QQuickWebEngineView::LifecycleState QQuickWebEngineView::lifecycleState() const
+{
+ Q_D(const QQuickWebEngineView);
+ return static_cast<LifecycleState>(d->adapter->lifecycleState());
+}
+
+void QQuickWebEngineView::setLifecycleState(LifecycleState state)
+{
+ Q_D(QQuickWebEngineView);
+ d->adapter->setLifecycleState(static_cast<WebContentsAdapterClient::LifecycleState>(state));
+}
+
+QQuickWebEngineView::LifecycleState QQuickWebEngineView::recommendedState() const
+{
+ Q_D(const QQuickWebEngineView);
+ return static_cast<LifecycleState>(d->adapter->recommendedState());
+}
+
QQuickWebEngineFullScreenRequest::QQuickWebEngineFullScreenRequest()
: m_viewPrivate(0)
, m_toggleOn(false)
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index c851dcb8d..3c8e1d9ec 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -76,6 +76,7 @@ class QQuickWebEngineNavigationRequest;
class QQuickWebEngineNewViewRequest;
class QQuickWebEngineProfile;
class QQuickWebEngineSettings;
+class QQuickWebEngineTooltipRequest;
class QQuickWebEngineFormValidationMessageRequest;
class QQuickWebEngineViewPrivate;
class QWebEngineQuotaRequest;
@@ -104,10 +105,11 @@ private:
const bool m_toggleOn;
};
-#define LATEST_WEBENGINEVIEW_REVISION 9
+#define LATEST_WEBENGINEVIEW_REVISION 10
class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
Q_OBJECT
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged FINAL)
Q_PROPERTY(QUrl icon READ icon NOTIFY iconChanged FINAL)
Q_PROPERTY(bool loading READ isLoading NOTIFY loadingChanged FINAL)
@@ -136,6 +138,9 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
Q_PROPERTY(QQuickWebEngineTestSupport *testSupport READ testSupport WRITE setTestSupport NOTIFY testSupportChanged FINAL)
#endif
+ Q_PROPERTY(LifecycleState lifecycleState READ lifecycleState WRITE setLifecycleState NOTIFY lifecycleStateChanged REVISION 11 FINAL)
+ Q_PROPERTY(LifecycleState recommendedState READ recommendedState NOTIFY recommendedStateChanged REVISION 11 FINAL)
+
public:
QQuickWebEngineView(QQuickItem *parent = 0);
~QQuickWebEngineView();
@@ -172,7 +177,8 @@ public:
FormSubmittedNavigation,
BackForwardNavigation,
ReloadNavigation,
- OtherNavigation
+ OtherNavigation,
+ RedirectNavigation,
};
Q_ENUM(NavigationType)
@@ -459,6 +465,14 @@ public:
};
Q_ENUM(PrintedPageOrientation)
+ // must match WebContentsAdapterClient::LifecycleState
+ enum class LifecycleState {
+ Active,
+ Frozen,
+ Discarded,
+ };
+ Q_ENUM(LifecycleState)
+
// QmlParserStatus
void componentComplete() override;
@@ -490,6 +504,11 @@ public:
void setDevToolsView(QQuickWebEngineView *);
QQuickWebEngineView *devToolsView() const;
+ LifecycleState lifecycleState() const;
+ void setLifecycleState(LifecycleState state);
+
+ LifecycleState recommendedState() const;
+
public Q_SLOTS:
void runJavaScript(const QString&, const QJSValue & = QJSValue());
Q_REVISION(3) void runJavaScript(const QString&, quint32 worldId, const QJSValue & = QJSValue());
@@ -552,6 +571,9 @@ Q_SIGNALS:
Q_REVISION(7) void registerProtocolHandlerRequested(const QWebEngineRegisterProtocolHandlerRequest &request);
Q_REVISION(8) void printRequested();
Q_REVISION(9) void selectClientCertificate(QQuickWebEngineClientCertificateSelection *clientCertSelection);
+ Q_REVISION(10) void tooltipRequested(QQuickWebEngineTooltipRequest *request);
+ Q_REVISION(11) void lifecycleStateChanged(LifecycleState state);
+ Q_REVISION(11) void recommendedStateChanged(LifecycleState state);
#if QT_CONFIG(webengine_testsupport)
void testSupportChanged();
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 10fe5c2fd..e0f2595ec 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -101,12 +101,15 @@ public:
QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override;
QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegateForPopup(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override;
void initializationFinished() override;
+ void lifecycleStateChanged(LifecycleState state) override;
+ void recommendedStateChanged(LifecycleState state) override;
+ void visibleChanged(bool visible) override;
void titleChanged(const QString&) override;
void urlChanged(const QUrl&) override;
void iconChanged(const QUrl&) override;
void loadProgressChanged(int progress) override;
void didUpdateTargetURL(const QUrl&) override;
- void selectionChanged() override { }
+ void selectionChanged() override;
void recentlyAudibleChanged(bool recentlyAudible) override;
QRectF viewportRect() const override;
QColor backgroundColor() const override;
diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index d256997cc..1c4328d01 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -1506,3 +1506,68 @@
\sa WebEngineClientCertificateSelection
*/
+
+/*!
+ \qmlsignal WebEngineView::tooltipRequested(TooltipRequest request)
+ \since QtWebEngine 1.10
+
+ This signal is emitted when the web page wants to show a tooltip at
+ a specified position.
+
+ \note Signal handlers need to call \c{request.accepted = true} to prevent a default tooltip from showing up.
+
+ \sa TooltipRequest
+*/
+
+/*!
+ \qmlproperty enumeration WebEngineView::LifecycleState
+ \since QtWebEngine 1.11
+
+ This enum describes the lifecycle state of the page:
+
+ \value WebEngineView.LifecycleState.Active
+ Normal state.
+ \value WebEngineView.LifecycleState.Frozen
+ Low CPU usage state where most HTML task sources are suspended.
+ \value WebEngineView.LifecycleState.Discarded
+ Very low resource usage state where the entire browsing context is discarded.
+
+ \sa lifecycleState
+*/
+
+/*!
+ \qmlproperty LifecycleState WebEngineView::lifecycleState
+ \since QtWebEngine 1.11
+
+ \brief The current lifecycle state of the page.
+
+ The following restrictions are enforced by the setter:
+
+ \list
+ \li A visible page must remain in the \c{Active} state.
+ \li If the page is being inspected by a \l{devToolsView} then both pages must
+ remain in the \c{Active} states.
+ \li A page in the \c{Discarded} state can only transition to the \c{Active}
+ state. This will cause a reload of the page.
+ \endlist
+
+ These are the only hard limits on the lifecycle state, but see also
+ \l{recommendedState} for the recommended soft limits.
+
+ \sa recommendedState, {WebEngine Lifecycle Example}
+*/
+
+/*!
+ \qmlproperty LifecycleState WebEngineView::recommendedState
+ \since QtWebEngine 1.11
+
+ \brief The recommended limit for the lifecycle state of the page.
+
+ Setting the lifecycle state to a lower resource usage state than the
+ recommended state may cause side-effects such as stopping background audio
+ playback or loss of HTML form input. Setting the lifecycle state to a higher
+ resource state is however completely safe.
+
+ \sa lifecycleState, {WebEngine Lifecycle Example}
+
+*/
diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp
index 56e5c5c9f..ad49d6543 100644
--- a/src/webengine/plugin/plugin.cpp
+++ b/src/webengine/plugin/plugin.cpp
@@ -95,6 +95,8 @@ public:
qmlRegisterType<QQuickWebEngineView, 7>(uri, 1, 7, "WebEngineView");
qmlRegisterType<QQuickWebEngineView, 8>(uri, 1, 8, "WebEngineView");
qmlRegisterType<QQuickWebEngineView, 9>(uri, 1, 9, "WebEngineView");
+ qmlRegisterType<QQuickWebEngineView, 10>(uri, 1, 10, "WebEngineView");
+ qmlRegisterType<QQuickWebEngineView, 11>(uri, 1, 11, "WebEngineView");
qmlRegisterType<QQuickWebEngineProfile>(uri, 1, 1, "WebEngineProfile");
qmlRegisterType<QQuickWebEngineProfile, 1>(uri, 1, 2, "WebEngineProfile");
qmlRegisterType<QQuickWebEngineProfile, 2>(uri, 1, 3, "WebEngineProfile");
@@ -104,21 +106,23 @@ public:
qmlRegisterType<QQuickWebEngineScript>(uri, 1, 1, "WebEngineScript");
qmlRegisterUncreatableType<QQuickWebEngineCertificateError>(uri, 1, 1, "WebEngineCertificateError", msgUncreatableType("WebEngineCertificateError"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem>(uri, 1, 1, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 1>(uri, 1, 2, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 2>(uri, 1, 3, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 3>(uri, 1, 4, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 4>(uri, 1, 5, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 5>(uri, 1, 6, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 6>(uri, 1, 7, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 7>(uri, 1, 8, "WebEngineDownloadItem",
- tr("Cannot create a separate instance of WebEngineDownloadItem"));
+ msgUncreatableType("WebEngineDownloadItem"));
+ qmlRegisterUncreatableType<QQuickWebEngineDownloadItem, 8>(uri, 1, 10, "WebEngineDownloadItem",
+ msgUncreatableType("WebEngineDownloadItem"));
qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 1, "WebEngineNewViewRequest", msgUncreatableType("WebEngineNewViewRequest"));
qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest, 1>(uri, 1, 5, "WebEngineNewViewRequest", tr("Cannot create separate instance of WebEngineNewViewRequest"));
qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 1, "WebEngineSettings", msgUncreatableType("WebEngineSettings"));
@@ -132,11 +136,11 @@ public:
qmlRegisterUncreatableType<QQuickWebEngineSettings, 8>(uri, 1, 9, "WebEngineSettings", msgUncreatableType("WebEngineSettings"));
qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 1, "WebEngine", webEngineSingletonProvider);
qmlRegisterUncreatableType<QQuickWebEngineHistory>(uri, 1, 1, "NavigationHistory",
- tr("Cannot create a separate instance of NavigationHistory"));
+ msgUncreatableType("NavigationHistory"));
qmlRegisterUncreatableType<QQuickWebEngineHistoryListModel>(uri, 1, 1, "NavigationHistoryListModel",
- tr("Cannot create a separate instance of NavigationHistory"));
+ msgUncreatableType("NavigationHistory"));
qmlRegisterUncreatableType<QQuickWebEngineFullScreenRequest>(uri, 1, 1, "FullScreenRequest",
- tr("Cannot create a separate instance of FullScreenRequest"));
+ msgUncreatableType("FullScreenRequest"));
qmlRegisterUncreatableType<QQuickWebEngineContextMenuRequest>(uri, 1, 4, "ContextMenuRequest",
msgUncreatableType("ContextMenuRequest"));
@@ -164,6 +168,8 @@ public:
qmlRegisterUncreatableType<QQuickWebEngineClientCertificateOption>(uri, 1, 9, "WebEngineClientCertificateOption",
msgUncreatableType("WebEngineClientCertificateOption"));
qmlRegisterUncreatableType<QWebEngineNotification>(uri, 1, 9, "WebEngineNotification", msgUncreatableType("WebEngineNotification"));
+ qmlRegisterUncreatableType<QQuickWebEngineTooltipRequest>(uri, 1, 10, "TooltipRequest",
+ msgUncreatableType("TooltipRequest"));
}
private:
diff --git a/src/webengine/plugin/plugin.pro b/src/webengine/plugin/plugin.pro
index 0c1310de3..3b30bece2 100644
--- a/src/webengine/plugin/plugin.pro
+++ b/src/webengine/plugin/plugin.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qtwebengineplugin
TARGETPATH = QtWebEngine
-IMPORT_VERSION = 1.9
+IMPORT_VERSION = 1.10
QT += qml quick
QT_PRIVATE += core-private webenginecore-private webengine-private
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 b636448b3..3a103b9aa 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -170,12 +170,6 @@ QSGLayer *RenderWidgetHostViewQtDelegateQuick::createLayer()
return renderContext->sceneGraphContext()->createLayer(renderContext);
}
-QSGInternalImageNode *RenderWidgetHostViewQtDelegateQuick::createInternalImageNode()
-{
- QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context;
- return renderContext->sceneGraphContext()->createInternalImageNode();
-}
-
QSGImageNode *RenderWidgetHostViewQtDelegateQuick::createImageNode()
{
return QQuickItem::window()->createImageNode();
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 00158b3ac..b55b2d658 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h
@@ -71,7 +71,6 @@ public:
QWindow* window() const override;
QSGTexture *createTextureFromImage(const QImage &) override;
QSGLayer *createLayer() override;
- QSGInternalImageNode *createInternalImageNode() override;
QSGImageNode *createImageNode() override;
QSGRectangleNode *createRectangleNode() override;
void update() 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 c085aacd7..23b9e02c2 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -131,11 +131,6 @@ QSGLayer *RenderWidgetHostViewQtDelegateQuickWindow::createLayer()
return m_realDelegate->createLayer();
}
-QSGInternalImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createInternalImageNode()
-{
- return m_realDelegate->createInternalImageNode();
-}
-
QSGImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createImageNode()
{
return m_realDelegate->createImageNode();
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 ab583bd63..bebbfa439 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
@@ -68,7 +68,6 @@ public:
QWindow* window() const override;
QSGTexture *createTextureFromImage(const QImage &) override;
QSGLayer *createLayer() override;
- QSGInternalImageNode *createInternalImageNode() override;
QSGImageNode *createImageNode() override;
QSGRectangleNode *createRectangleNode() override;
void update() override;
diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp
index 2f371efd5..19274bedf 100644
--- a/src/webengine/ui_delegates_manager.cpp
+++ b/src/webengine/ui_delegates_manager.cpp
@@ -539,14 +539,14 @@ void UIDelegatesManager::showMenu(QObject *menu)
void UIDelegatesManager::showToolTip(const QString &text)
{
- if (!ensureComponentLoaded(ToolTip))
- return;
-
if (text.isEmpty()) {
m_toolTip.reset();
return;
}
+ if (!ensureComponentLoaded(ToolTip))
+ return;
+
if (!m_toolTip.isNull())
return;
diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp
index 05c6956ea..7ce572e2f 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 <QDir>
#include "QFileInfo"
QT_BEGIN_NAMESPACE
@@ -508,6 +509,7 @@ QString QWebEngineDownloadItem::mimeType() const
}
/*!
+ \obsolete
Returns the full target path where data is being downloaded to.
The path includes the file name. The default suggested path is the standard download location
@@ -517,7 +519,7 @@ QString QWebEngineDownloadItem::mimeType() const
QString QWebEngineDownloadItem::path() const
{
Q_D(const QWebEngineDownloadItem);
- return d->downloadPath;
+ return QDir::cleanPath(QDir(d->downloadDirectory).filePath(d->downloadFileName));
}
/*!
@@ -534,18 +536,109 @@ void QWebEngineDownloadItem::setPath(QString path)
qWarning("Setting the download path is not allowed after the download has been accepted.");
return;
}
+ if (QDir(d->downloadDirectory).filePath(d->downloadFileName) != 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;
+ }
+
+ if (QFileInfo(path).fileName() == path) {
+ d->downloadDirectory = QStringLiteral("");
+ d->downloadFileName = path;
+ } else {
+ d->downloadDirectory = QFileInfo(path).filePath();
+ d->downloadFileName = QFileInfo(path).fileName();
+ }
+ }
+}
+
+/*!
+ \since 5.14
+
+ Returns the download directory path.
+*/
+
+QString QWebEngineDownloadItem::downloadDirectory() const
+{
+ Q_D(const QWebEngineDownloadItem);
+ return d->downloadDirectory;
+}
+
+/*!
+ \since 5.14
+
+ Sets the directory path to download the file to.
+
+ The download directory path can only be set in response to the QWebEngineProfile::downloadRequested()
+ signal before the download is accepted. Past that point, this function has no effect on the
+ download item's state.
+*/
- if (QFileInfo(path).fileName().isEmpty()) {
- qWarning("The download path does not include file name.");
+void QWebEngineDownloadItem::setDownloadDirectory(QString directory)
+{
+ Q_D(QWebEngineDownloadItem);
+ if (d->downloadState != QWebEngineDownloadItem::DownloadRequested) {
+ qWarning("Setting the download directory is not allowed after the download has been accepted.");
return;
- }
+ }
+
+ if (!directory.isEmpty() && d->downloadDirectory != directory)
+ d->downloadDirectory = directory;
- if (QFileInfo(path).isDir()) {
- qWarning("The download path matches with an already existing directory path.");
+ d->downloadFileName = QFileInfo(d->profile->profileAdapter()->updateDownloadPath(d->downloadId,
+ d->downloadDirectory,
+ d->suggestedFileName)).fileName();
+}
+
+/*!
+ \since 5.14
+
+ Returns the suggested file name.
+*/
+
+QString QWebEngineDownloadItem::downloadFileName() const
+{
+ Q_D(const QWebEngineDownloadItem);
+ return d->downloadFileName;
+}
+
+/*!
+ \since 5.14
+
+ Sets the file name to download the file to.
+
+ The download file name can only be set in response to the QWebEngineProfile::downloadRequested()
+ signal before the download is accepted. Past that point, this function has no effect on the
+ download item's state.
+*/
+
+void QWebEngineDownloadItem::setDownloadFileName(QString fileName)
+{
+ Q_D(QWebEngineDownloadItem);
+ if (d->downloadState != QWebEngineDownloadItem::DownloadRequested) {
+ qWarning("Setting the download file name is not allowed after the download has been accepted.");
return;
}
- d->downloadPath = path;
+ if (!fileName.isEmpty())
+ d->downloadFileName = fileName;
+}
+
+/*!
+ \since 5.14
+
+ Returns the suggested file name.
+*/
+
+QString QWebEngineDownloadItem::suggestedFileName() const
+{
+ Q_D(const QWebEngineDownloadItem);
+ return d->suggestedFileName;
}
/*!
diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h
index 981a3c374..169d80553 100644
--- a/src/webenginewidgets/api/qwebenginedownloaditem.h
+++ b/src/webenginewidgets/api/qwebenginedownloaditem.h
@@ -118,8 +118,8 @@ public:
qint64 receivedBytes() const;
QUrl url() const;
QString mimeType() const;
- QString path() const;
- void setPath(QString path);
+ QString Q_DECL_DEPRECATED path() const;
+ void Q_DECL_DEPRECATED setPath(QString path);
bool isFinished() const;
bool isPaused() const;
SavePageFormat savePageFormat() const;
@@ -128,6 +128,11 @@ public:
DownloadInterruptReason interruptReason() const;
QString interruptReasonString() const;
bool isSavePageDownload() const;
+ QString suggestedFileName() const;
+ QString downloadDirectory() const;
+ void setDownloadDirectory(QString directory);
+ QString downloadFileName() const;
+ void setDownloadFileName(QString fileName);
QWebEnginePage *page() const;
diff --git a/src/webenginewidgets/api/qwebenginedownloaditem_p.h b/src/webenginewidgets/api/qwebenginedownloaditem_p.h
index b3bc8a3fe..08e478736 100644
--- a/src/webenginewidgets/api/qwebenginedownloaditem_p.h
+++ b/src/webenginewidgets/api/qwebenginedownloaditem_p.h
@@ -78,6 +78,9 @@ public:
const QUrl downloadUrl;
QString mimeType;
bool downloadPaused;
+ QString suggestedFileName;
+ QString downloadDirectory;
+ QString downloadFileName;
qint64 totalBytes;
qint64 receivedBytes;
diff --git a/src/webenginewidgets/api/qwebenginehistory.cpp b/src/webenginewidgets/api/qwebenginehistory.cpp
index 34279b016..6a85b984e 100644
--- a/src/webenginewidgets/api/qwebenginehistory.cpp
+++ b/src/webenginewidgets/api/qwebenginehistory.cpp
@@ -191,13 +191,13 @@ QList<QWebEngineHistoryItem> QWebEngineHistory::forwardItems(int maxItems) const
bool QWebEngineHistory::canGoBack() const
{
Q_D(const QWebEngineHistory);
- return d->page->webContents()->canGoBack();
+ return d->page->webContents()->canGoToOffset(-1);
}
bool QWebEngineHistory::canGoForward() const
{
Q_D(const QWebEngineHistory);
- return d->page->webContents()->canGoForward();
+ return d->page->webContents()->canGoToOffset(1);
}
void QWebEngineHistory::back()
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index a350433b8..e990170eb 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -171,11 +171,11 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile)
qRegisterMetaType<QWebEngineQuotaRequest>();
qRegisterMetaType<QWebEngineRegisterProtocolHandlerRequest>();
- // See wasShown() and wasHidden().
+ // See setVisible().
wasShownTimer.setSingleShot(true);
QObject::connect(&wasShownTimer, &QTimer::timeout, [this](){
ensureInitialized();
- wasShown();
+ adapter->setVisible(true);
});
profile->d_ptr->addWebContentsAdapterClient(this);
@@ -214,6 +214,8 @@ void QWebEnginePagePrivate::initializationFinished()
adapter->setAudioMuted(defaultAudioMuted);
if (!qFuzzyCompare(adapter->currentZoomFactor(), defaultZoomFactor))
adapter->setZoomFactor(defaultZoomFactor);
+ if (view)
+ adapter->setVisible(view->isVisible());
scriptCollection.d->initializationFinished(adapter);
@@ -258,7 +260,10 @@ void QWebEnginePagePrivate::didUpdateTargetURL(const QUrl &hoveredUrl)
void QWebEnginePagePrivate::selectionChanged()
{
Q_Q(QWebEnginePage);
- QTimer::singleShot(0, q, &QWebEnginePage::selectionChanged);
+ QTimer::singleShot(0, q, [this, q]() {
+ updateEditActions();
+ Q_EMIT q->selectionChanged();
+ });
}
void QWebEnginePagePrivate::recentlyAudibleChanged(bool recentlyAudible)
@@ -575,10 +580,10 @@ void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const
switch (action) {
case QWebEnginePage::Back:
- enabled = adapter->canGoBack();
+ enabled = adapter->canGoToOffset(-1);
break;
case QWebEnginePage::Forward:
- enabled = adapter->canGoForward();
+ enabled = adapter->canGoToOffset(1);
break;
case QWebEnginePage::Stop:
enabled = isLoading;
@@ -592,12 +597,14 @@ void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const
break;
case QWebEnginePage::Cut:
case QWebEnginePage::Copy:
+ case QWebEnginePage::Unselect:
+ enabled = adapter->hasFocusedFrame() && !adapter->selectedText().isEmpty();
+ break;
case QWebEnginePage::Paste:
case QWebEnginePage::Undo:
case QWebEnginePage::Redo:
case QWebEnginePage::SelectAll:
case QWebEnginePage::PasteAndMatchStyle:
- case QWebEnginePage::Unselect:
enabled = adapter->hasFocusedFrame();
break;
default:
@@ -649,8 +656,6 @@ void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input)
adapter = std::move(newWebContents);
adapter->setClient(this);
adapter->loadDefault();
- if (view && view->isVisible())
- wasShown();
}
}
@@ -1342,10 +1347,10 @@ void QWebEnginePage::triggerAction(WebAction action, bool)
const QtWebEngineCore::WebEngineContextMenuData *menuData = d->contextData.d;
switch (action) {
case Back:
- d->adapter->navigateToOffset(-1);
+ d->adapter->navigateBack();
break;
case Forward:
- d->adapter->navigateToOffset(1);
+ d->adapter->navigateForward();
break;
case Stop:
d->adapter->stop();
@@ -1607,31 +1612,6 @@ bool QWebEnginePage::event(QEvent *e)
return QObject::event(e);
}
-void QWebEnginePagePrivate::wasShown()
-{
- if (!adapter->isInitialized()) {
- // On the one hand, it is too early to initialize here. The application
- // may call show() before load(), or it may call show() from
- // createWindow(), and then we would create an unnecessary blank
- // WebContents here. On the other hand, if the application calls show()
- // then it expects something to be shown, so we have to initialize.
- // Therefore we have to delay the initialization via the event loop.
- wasShownTimer.start();
- return;
- }
- adapter->wasShown();
-}
-
-void QWebEnginePagePrivate::wasHidden()
-{
- if (!adapter->isInitialized()) {
- // Cancel timer from wasShown() above.
- wasShownTimer.stop();
- return;
- }
- adapter->wasHidden();
-}
-
void QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData &data)
{
#if QT_CONFIG(action)
@@ -1842,6 +1822,26 @@ void QWebEnginePagePrivate::printRequested()
});
}
+void QWebEnginePagePrivate::lifecycleStateChanged(LifecycleState state)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->lifecycleStateChanged(static_cast<QWebEnginePage::LifecycleState>(state));
+}
+
+void QWebEnginePagePrivate::recommendedStateChanged(LifecycleState state)
+{
+ Q_Q(QWebEnginePage);
+ QTimer::singleShot(0, q, [q, state]() {
+ Q_EMIT q->recommendedStateChanged(static_cast<QWebEnginePage::LifecycleState>(state));
+ });
+}
+
+void QWebEnginePagePrivate::visibleChanged(bool visible)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->visibleChanged(visible);
+}
+
/*!
\since 5.13
@@ -2127,6 +2127,10 @@ void QWebEnginePage::runJavaScript(const QString &scriptSource)
{
Q_D(QWebEnginePage);
d->ensureInitialized();
+ if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) {
+ qWarning("runJavaScript: disabled in Discarded state");
+ return;
+ }
d->adapter->runJavaScript(scriptSource, QWebEngineScript::MainWorld);
}
@@ -2134,6 +2138,11 @@ void QWebEnginePage::runJavaScript(const QString& scriptSource, const QWebEngine
{
Q_D(QWebEnginePage);
d->ensureInitialized();
+ if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) {
+ qWarning("runJavaScript: disabled in Discarded state");
+ d->m_callbacks.invokeEmpty(resultCallback);
+ return;
+ }
quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, QWebEngineScript::MainWorld);
d->m_callbacks.registerCallback(requestId, resultCallback);
}
@@ -2512,6 +2521,120 @@ const QWebEngineContextMenuData &QWebEnginePage::contextMenuData() const
return d->contextData;
}
+/*!
+ \enum QWebEnginePage::LifecycleState
+ \since 5.14
+
+ This enum describes the lifecycle state of the page:
+
+ \value Active
+ Normal state.
+ \value Frozen
+ Low CPU usage state where most HTML task sources are suspended.
+ \value Discarded
+ Very low resource usage state where the entire browsing context is discarded.
+
+ \sa lifecycleState, {WebEngine Lifecycle Example}
+*/
+
+/*!
+ \property QWebEnginePage::lifecycleState
+ \since 5.14
+
+ \brief The current lifecycle state of the page.
+
+ The following restrictions are enforced by the setter:
+
+ \list
+ \li A \l{visible} page must remain in the \c{Active} state.
+ \li If the page is being inspected by a \l{devToolsPage} then both pages must
+ remain in the \c{Active} states.
+ \li A page in the \c{Discarded} state can only transition to the \c{Active}
+ state. This will cause a reload of the page.
+ \endlist
+
+ These are the only hard limits on the lifecycle state, but see also
+ \l{recommendedState} for the recommended soft limits.
+
+ \sa recommendedState, {WebEngine Lifecycle Example}
+*/
+
+QWebEnginePage::LifecycleState QWebEnginePage::lifecycleState() const
+{
+ Q_D(const QWebEnginePage);
+ return static_cast<LifecycleState>(d->adapter->lifecycleState());
+}
+
+void QWebEnginePage::setLifecycleState(LifecycleState state)
+{
+ Q_D(QWebEnginePage);
+ d->adapter->setLifecycleState(static_cast<WebContentsAdapterClient::LifecycleState>(state));
+}
+
+/*!
+ \property QWebEnginePage::recommendedState
+ \since 5.14
+
+ \brief The recommended limit for the lifecycle state of the page.
+
+ Setting the lifecycle state to a lower resource usage state than the
+ recommended state may cause side-effects such as stopping background audio
+ playback or loss of HTML form input. Setting the lifecycle state to a higher
+ resource state is however completely safe.
+
+ \sa lifecycleState
+*/
+
+QWebEnginePage::LifecycleState QWebEnginePage::recommendedState() const
+{
+ Q_D(const QWebEnginePage);
+ return static_cast<LifecycleState>(d->adapter->recommendedState());
+}
+
+/*!
+ \property QWebEnginePage::visible
+ \since 5.14
+
+ \brief Whether the page is considered visible in the Page Visibility API.
+
+ Setting this property changes the \c{Document.hidden} and the
+ \c{Document.visibilityState} properties in JavaScript which web sites can use
+ to voluntarily reduce their resource usage if they are not visible to the
+ user.
+
+ If the page is connected to a \l{view} then this property will be managed
+ automatically by the view according to it's own visibility.
+
+ \sa lifecycleState
+*/
+
+bool QWebEnginePage::isVisible() const
+{
+ Q_D(const QWebEnginePage);
+ return d->adapter->isVisible();
+}
+
+void QWebEnginePage::setVisible(bool visible)
+{
+ Q_D(QWebEnginePage);
+
+ if (!d->adapter->isInitialized()) {
+ // On the one hand, it is too early to initialize here. The application
+ // may call show() before load(), or it may call show() from
+ // createWindow(), and then we would create an unnecessary blank
+ // WebContents here. On the other hand, if the application calls show()
+ // then it expects something to be shown, so we have to initialize.
+ // Therefore we have to delay the initialization via the event loop.
+ if (visible)
+ d->wasShownTimer.start();
+ else
+ d->wasShownTimer.stop();
+ return;
+ }
+
+ d->adapter->setVisible(visible);
+}
+
#if QT_CONFIG(action)
QContextMenuBuilder::QContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data,
QWebEnginePage *page,
diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h
index 4956877a9..736d7ed69 100644
--- a/src/webenginewidgets/api/qwebenginepage.h
+++ b/src/webenginewidgets/api/qwebenginepage.h
@@ -88,6 +88,9 @@ class QWEBENGINEWIDGETS_EXPORT QWebEnginePage : public QObject {
Q_PROPERTY(QPointF scrollPosition READ scrollPosition NOTIFY scrollPositionChanged)
Q_PROPERTY(bool audioMuted READ isAudioMuted WRITE setAudioMuted NOTIFY audioMutedChanged)
Q_PROPERTY(bool recentlyAudible READ recentlyAudible NOTIFY recentlyAudibleChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(LifecycleState lifecycleState READ lifecycleState WRITE setLifecycleState NOTIFY lifecycleStateChanged)
+ Q_PROPERTY(LifecycleState recommendedState READ recommendedState NOTIFY recommendedStateChanged)
public:
enum WebAction {
@@ -180,7 +183,8 @@ public:
NavigationTypeFormSubmitted,
NavigationTypeBackForward,
NavigationTypeReload,
- NavigationTypeOther
+ NavigationTypeOther,
+ NavigationTypeRedirect,
};
Q_ENUM(NavigationType)
@@ -221,6 +225,14 @@ public:
};
Q_ENUM(RenderProcessTerminationStatus)
+ // must match WebContentsAdapterClient::LifecycleState
+ enum class LifecycleState {
+ Active,
+ Frozen,
+ Discarded,
+ };
+ Q_ENUM(LifecycleState)
+
explicit QWebEnginePage(QObject *parent = Q_NULLPTR);
QWebEnginePage(QWebEngineProfile *profile, QObject *parent = Q_NULLPTR);
~QWebEnginePage();
@@ -306,6 +318,14 @@ public:
const QWebEngineContextMenuData &contextMenuData() const;
+ LifecycleState lifecycleState() const;
+ void setLifecycleState(LifecycleState state);
+
+ LifecycleState recommendedState() const;
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
Q_SIGNALS:
void loadStarted();
void loadProgress(int progress);
@@ -344,6 +364,11 @@ Q_SIGNALS:
void pdfPrintingFinished(const QString &filePath, bool success);
void printRequested();
+ void visibleChanged(bool visible);
+
+ void lifecycleStateChanged(LifecycleState state);
+ void recommendedStateChanged(LifecycleState state);
+
protected:
virtual QWebEnginePage *createWindow(WebWindowType type);
virtual QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes);
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index dc0ead534..acf95a265 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -92,6 +92,9 @@ public:
QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override;
QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegateForPopup(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override { return CreateRenderWidgetHostViewQtDelegate(client); }
void initializationFinished() override;
+ void lifecycleStateChanged(LifecycleState state) override;
+ void recommendedStateChanged(LifecycleState state) override;
+ void visibleChanged(bool visible) override;
void titleChanged(const QString&) override;
void urlChanged(const QUrl&) override;
void iconChanged(const QUrl&) override;
@@ -167,9 +170,6 @@ public:
void updateAction(QWebEnginePage::WebAction) const;
void _q_webActionTriggered(bool checked);
- void wasShown();
- void wasHidden();
-
QtWebEngineCore::WebContentsAdapter *webContents() { return adapter.data(); }
void recreateFromSerializedHistory(QDataStream &input);
diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp
index 237d68473..6e2db533e 100644
--- a/src/webenginewidgets/api/qwebengineprofile.cpp
+++ b/src/webenginewidgets/api/qwebengineprofile.cpp
@@ -53,6 +53,7 @@
#include "visited_links_manager_qt.h"
#include "web_engine_settings.h"
+#include <QDir>
#include <QtWebEngineCore/qwebengineurlscheme.h>
QT_BEGIN_NAMESPACE
@@ -226,7 +227,9 @@ void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
itemPrivate->downloadId = info.id;
itemPrivate->downloadState = info.accepted ? QWebEngineDownloadItem::DownloadInProgress
: QWebEngineDownloadItem::DownloadRequested;
- itemPrivate->downloadPath = info.path;
+ itemPrivate->downloadDirectory = QFileInfo(info.path).path();
+ itemPrivate->downloadFileName = QFileInfo(info.path).fileName();
+ itemPrivate->suggestedFileName = info.suggestedFileName;
itemPrivate->mimeType = info.mimeType;
itemPrivate->savePageFormat = static_cast<QWebEngineDownloadItem::SavePageFormat>(info.savePageFormat);
itemPrivate->type = static_cast<QWebEngineDownloadItem::DownloadType>(info.downloadType);
@@ -244,7 +247,7 @@ void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
QWebEngineDownloadItem::DownloadState state = download->state();
- info.path = download->path();
+ info.path = QDir(download->downloadDirectory()).filePath(download->downloadFileName());
info.savePageFormat = static_cast<QtWebEngineCore::ProfileAdapterClient::SavePageFormat>(
download->savePageFormat());
info.accepted = state != QWebEngineDownloadItem::DownloadCancelled;
diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp
index 6c08df343..ac979e766 100644
--- a/src/webenginewidgets/api/qwebengineview.cpp
+++ b/src/webenginewidgets/api/qwebengineview.cpp
@@ -378,7 +378,7 @@ void QWebEngineView::contextMenuEvent(QContextMenuEvent *event)
void QWebEngineView::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
- page()->d_ptr->wasShown();
+ page()->setVisible(true);
}
/*!
@@ -387,7 +387,17 @@ void QWebEngineView::showEvent(QShowEvent *event)
void QWebEngineView::hideEvent(QHideEvent *event)
{
QWidget::hideEvent(event);
- page()->d_ptr->wasHidden();
+ page()->setVisible(false);
+}
+
+/*!
+ * \reimp
+ */
+void QWebEngineView::closeEvent(QCloseEvent *event)
+{
+ QWidget::closeEvent(event);
+ page()->setVisible(false);
+ page()->setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
}
#if QT_CONFIG(draganddrop)
diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h
index e3cb7ad75..63a68f46c 100644
--- a/src/webenginewidgets/api/qwebengineview.h
+++ b/src/webenginewidgets/api/qwebengineview.h
@@ -126,6 +126,7 @@ protected:
bool event(QEvent*) override;
void showEvent(QShowEvent *) override;
void hideEvent(QHideEvent *) override;
+ void closeEvent(QCloseEvent *) override;
#if QT_CONFIG(draganddrop)
void dragEnterEvent(QDragEnterEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
index b68caed59..99bbc5162 100644
--- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
@@ -276,6 +276,7 @@
\value NavigationTypeFormSubmitted The navigation request resulted from a form submission.
\value NavigationTypeBackForward The navigation request resulted from a back or forward action.
\value NavigationTypeReload The navigation request resulted from a reload action.
+ \value NavigationTypeRedirect The navigation request resulted from a content or server controlled redirect. This also includes automatic reloads. (Added in Qt 5.14)
\value NavigationTypeOther The navigation request was triggered by other means not covered by the above.
\sa acceptNavigationRequest()
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 88eb9843b..894dca4fa 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -301,12 +301,6 @@ QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer()
return renderContext->sceneGraphContext()->createLayer(renderContext);
}
-QSGInternalImageNode *RenderWidgetHostViewQtDelegateWidget::createInternalImageNode()
-{
- QSGRenderContext *renderContext = QQuickWindowPrivate::get(quickWindow())->context;
- return renderContext->sceneGraphContext()->createInternalImageNode();
-}
-
QSGImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode()
{
return quickWindow()->createImageNode();
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 7746c4405..18f848da5 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
@@ -78,7 +78,6 @@ public:
QWindow* window() const override;
QSGTexture *createTextureFromImage(const QImage &) override;
QSGLayer *createLayer() override;
- QSGInternalImageNode *createInternalImageNode() override;
QSGImageNode *createImageNode() override;
QSGRectangleNode *createRectangleNode() override;
void update() override;
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
index 7d3ad1440..c0762aa14 100644
--- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
@@ -65,6 +65,7 @@ private Q_SLOTS:
void requestInterceptorByResourceType();
void firstPartyUrlHttp();
void passRefererHeader();
+ void initiator();
};
tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor()
@@ -95,11 +96,13 @@ struct RequestInfo {
RequestInfo(QWebEngineUrlRequestInfo &info)
: requestUrl(info.requestUrl())
, firstPartyUrl(info.firstPartyUrl())
+ , initiator(info.initiator())
, resourceType(info.resourceType())
{}
QUrl requestUrl;
QUrl firstPartyUrl;
+ QUrl initiator;
int resourceType;
};
@@ -111,6 +114,7 @@ class TestRequestInterceptor : public QWebEngineUrlRequestInterceptor
public:
QList<RequestInfo> requestInfos;
bool shouldIntercept;
+ QMap<QUrl, QUrl> requestInitiatorUrls;
void interceptRequest(QWebEngineUrlRequestInfo &info) override
{
@@ -125,6 +129,7 @@ public:
// Set referrer header
info.setHttpHeader(kHttpHeaderRefererName, kHttpHeaderReferrerValue);
+ requestInitiatorUrls.insert(info.requestUrl(), info.initiator());
requestInfos.append(info);
}
@@ -553,5 +558,69 @@ void tst_QWebEngineUrlRequestInterceptor::passRefererHeader()
QVERIFY(succeeded);
}
+void tst_QWebEngineUrlRequestInterceptor::initiator()
+{
+ QWebEngineProfile profile;
+ TestRequestInterceptor interceptor(/* intercept */ false);
+ profile.setUrlRequestInterceptor(&interceptor);
+
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+ QUrl url = QUrl("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_video");
+ page.setUrl(QUrl(url));
+ if (!loadSpy.wait(15000) || !loadSpy.at(0).at(0).toBool())
+ QSKIP("Couldn't load page from network, skipping test.");
+
+ QList<RequestInfo> infos;
+
+ // SubFrame
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeSubFrame));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeSubFrame);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // Stylesheet
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeStylesheet));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeStylesheet);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // Script
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeScript));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeScript);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // Image
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeImage));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeImage);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // FontResource
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFontResource));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFontResource);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // Media
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeMedia));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeMedia);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // Favicon
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFavicon));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFavicon);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+
+ // XMLHttpRequest
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeXhr));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeXhr);
+ foreach (auto info, infos)
+ QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]);
+}
+
QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor)
#include "tst_qwebengineurlrequestinterceptor.moc"
diff --git a/tests/auto/quick/dialogs/BLACKLIST b/tests/auto/quick/dialogs/BLACKLIST
new file mode 100644
index 000000000..6d7e2a2fc
--- /dev/null
+++ b/tests/auto/quick/dialogs/BLACKLIST
@@ -0,0 +1,2 @@
+[contextMenuRequested]
+osx-10.13
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 90b768ac7..f464d58d0 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -80,6 +80,7 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *
<< &QQuickWebEngineColorDialogRequest::staticMetaObject
<< &QQuickWebEngineFileDialogRequest::staticMetaObject
<< &QQuickWebEngineFormValidationMessageRequest::staticMetaObject
+ << &QQuickWebEngineTooltipRequest::staticMetaObject
<< &QQuickWebEngineContextMenuRequest::staticMetaObject
<< &QWebEngineQuotaRequest::staticMetaObject
<< &QWebEngineRegisterProtocolHandlerRequest::staticMetaObject
@@ -259,6 +260,12 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineDownloadItem.type --> DownloadType"
<< "QQuickWebEngineDownloadItem.typeChanged() --> void"
<< "QQuickWebEngineDownloadItem.view --> QQuickWebEngineView*"
+ << "QQuickWebEngineDownloadItem.url --> QUrl"
+ << "QQuickWebEngineDownloadItem.suggestedFileName --> QString"
+ << "QQuickWebEngineDownloadItem.downloadDirectory --> QString"
+ << "QQuickWebEngineDownloadItem.downloadDirectoryChanged() --> void"
+ << "QQuickWebEngineDownloadItem.downloadFileName --> QString"
+ << "QQuickWebEngineDownloadItem.downloadFileNameChanged() --> void"
<< "QQuickWebEngineFileDialogRequest.FileModeOpen --> FileMode"
<< "QQuickWebEngineFileDialogRequest.FileModeOpenMultiple --> FileMode"
<< "QQuickWebEngineFileDialogRequest.FileModeSave --> FileMode"
@@ -277,6 +284,13 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineFormValidationMessageRequest.subText --> QString"
<< "QQuickWebEngineFormValidationMessageRequest.text --> QString"
<< "QQuickWebEngineFormValidationMessageRequest.type --> RequestType"
+ << "QQuickWebEngineTooltipRequest.Hide --> RequestType"
+ << "QQuickWebEngineTooltipRequest.Show --> RequestType"
+ << "QQuickWebEngineTooltipRequest.x --> int"
+ << "QQuickWebEngineTooltipRequest.y --> int"
+ << "QQuickWebEngineTooltipRequest.text --> QString"
+ << "QQuickWebEngineTooltipRequest.type --> RequestType"
+ << "QQuickWebEngineTooltipRequest.accepted --> bool"
<< "QQuickWebEngineFullScreenRequest.accept() --> void"
<< "QQuickWebEngineFullScreenRequest.origin --> QUrl"
<< "QQuickWebEngineFullScreenRequest.reject() --> void"
@@ -596,6 +610,9 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.LetterExtra --> PrintedPageSizeId"
<< "QQuickWebEngineView.LetterPlus --> PrintedPageSizeId"
<< "QQuickWebEngineView.LetterSmall --> PrintedPageSizeId"
+ << "QQuickWebEngineView.LifecycleState.Active --> LifecycleState"
+ << "QQuickWebEngineView.LifecycleState.Discarded --> LifecycleState"
+ << "QQuickWebEngineView.LifecycleState.Frozen --> LifecycleState"
<< "QQuickWebEngineView.LinkClickedNavigation --> NavigationType"
<< "QQuickWebEngineView.LoadFailedStatus --> LoadStatus"
<< "QQuickWebEngineView.LoadStartedStatus --> LoadStatus"
@@ -628,6 +645,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.Prc32K --> PrintedPageSizeId"
<< "QQuickWebEngineView.Prc32KBig --> PrintedPageSizeId"
<< "QQuickWebEngineView.Quarto --> PrintedPageSizeId"
+ << "QQuickWebEngineView.RedirectNavigation --> NavigationType"
<< "QQuickWebEngineView.Redo --> WebAction"
<< "QQuickWebEngineView.Reload --> WebAction"
<< "QQuickWebEngineView.ReloadAndBypassCache --> WebAction"
@@ -692,6 +710,8 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.isFullScreenChanged() --> void"
<< "QQuickWebEngineView.javaScriptConsoleMessage(JavaScriptConsoleMessageLevel,QString,int,QString) --> void"
<< "QQuickWebEngineView.javaScriptDialogRequested(QQuickWebEngineJavaScriptDialogRequest*) --> void"
+ << "QQuickWebEngineView.lifecycleState --> LifecycleState"
+ << "QQuickWebEngineView.lifecycleStateChanged(LifecycleState) --> void"
<< "QQuickWebEngineView.linkHovered(QUrl) --> void"
<< "QQuickWebEngineView.loadHtml(QString) --> void"
<< "QQuickWebEngineView.loadHtml(QString,QUrl) --> void"
@@ -715,6 +735,8 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.quotaRequested(QWebEngineQuotaRequest) --> void"
<< "QQuickWebEngineView.recentlyAudible --> bool"
<< "QQuickWebEngineView.recentlyAudibleChanged(bool) --> void"
+ << "QQuickWebEngineView.recommendedState --> LifecycleState"
+ << "QQuickWebEngineView.recommendedStateChanged(LifecycleState) --> void"
<< "QQuickWebEngineView.registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest) --> void"
<< "QQuickWebEngineView.reload() --> void"
<< "QQuickWebEngineView.reloadAndBypassCache() --> void"
@@ -736,6 +758,7 @@ static const QStringList expectedAPI = QStringList()
#endif
<< "QQuickWebEngineView.title --> QString"
<< "QQuickWebEngineView.titleChanged() --> void"
+ << "QQuickWebEngineView.tooltipRequested(QQuickWebEngineTooltipRequest*) --> void"
<< "QQuickWebEngineView.triggerWebAction(WebAction) --> void"
<< "QQuickWebEngineView.url --> QUrl"
<< "QQuickWebEngineView.urlChanged() --> void"
@@ -811,8 +834,9 @@ static void checkKnownType(const QByteArray &typeName)
static void gatherAPI(const QString &prefix, const QMetaEnum &metaEnum, QStringList *output)
{
+ const auto format = metaEnum.isScoped() ? "%1%3.%2 --> %3" : "%1%2 --> %3";
for (int i = 0; i < metaEnum.keyCount(); ++i)
- *output << QString::fromLatin1("%1%2 --> %3").arg(prefix).arg(metaEnum.key(i)).arg(metaEnum.name());
+ *output << QString::fromLatin1(format).arg(prefix).arg(metaEnum.key(i)).arg(metaEnum.name());
}
static void gatherAPI(const QString &prefix, const QMetaProperty &property, QStringList *output)
diff --git a/tests/auto/quick/qmltests/data/tst_action.qml b/tests/auto/quick/qmltests/data/tst_action.qml
index 56a91d8d0..852d4145a 100644
--- a/tests/auto/quick/qmltests/data/tst_action.qml
+++ b/tests/auto/quick/qmltests/data/tst_action.qml
@@ -51,8 +51,8 @@ TestWebEngineView {
{ webAction: WebEngineView.Forward, text: "Forward", iconName: "go-next", enabled: false },
{ webAction: WebEngineView.Stop, text: "Stop", iconName: "", enabled: false },
{ webAction: WebEngineView.Reload, text: "Reload", iconName: "view-refresh", enabled: true },
- { webAction: WebEngineView.Cut, text: "Cut", iconName: "Cut", enabled: true },
- { webAction: WebEngineView.Copy, text: "Copy", iconName: "", enabled: true },
+ { webAction: WebEngineView.Cut, text: "Cut", iconName: "Cut", enabled: false },
+ { webAction: WebEngineView.Copy, text: "Copy", iconName: "", enabled: false },
{ webAction: WebEngineView.Paste, text: "Paste", iconName: "", enabled: true },
{ webAction: WebEngineView.Undo, text: "Undo", iconName: "", enabled: true },
{ webAction: WebEngineView.Redo, text: "Redo", iconName: "", enabled: true },
@@ -76,7 +76,7 @@ TestWebEngineView {
{ webAction: WebEngineView.InspectElement, text: "Inspect", iconName: "", enabled: true },
{ webAction: WebEngineView.ExitFullScreen, text: "Exit full screen", iconName: "", enabled: true },
{ webAction: WebEngineView.RequestClose, text: "Close Page", iconName: "", enabled: true },
- { webAction: WebEngineView.Unselect, text: "Unselect", iconName: "", enabled: true },
+ { webAction: WebEngineView.Unselect, text: "Unselect", iconName: "", enabled: false },
{ webAction: WebEngineView.SavePage, text: "Save page", iconName: "", enabled: true },
{ webAction: WebEngineView.ViewSource, text: "View page source", iconName: "view-source", enabled: true },
{ webAction: WebEngineView.ToggleBold, text: "&Bold", iconName: "", enabled: true },
@@ -110,17 +110,17 @@ TestWebEngineView {
webEngineView.url = Qt.resolvedUrl("test1.html");
verify(webEngineView.waitForLoadSucceeded());
- var copyAction = webEngineView.action(WebEngineView.Copy);
- verify(copyAction);
+ var selectAction = webEngineView.action(WebEngineView.SelectAll);
+ verify(selectAction);
var stopAction = webEngineView.action(WebEngineView.Stop);
verify(stopAction);
- var triggerSpy = createTemporaryObject(signalSpy, actionTests, {target: copyAction, signalName: "triggered"});
+ var triggerSpy = createTemporaryObject(signalSpy, actionTests, {target: selectAction, signalName: "triggered"});
var stopTriggerSpy = createTemporaryObject(signalSpy, actionTests, {target: stopAction, signalName: "triggered"});
- verify(copyAction.enabled);
- copyAction.trigger();
+ verify(selectAction.enabled);
+ selectAction.trigger();
compare(triggerSpy.count, 1);
verify(!stopAction.enabled);
diff --git a/tests/auto/quick/qmltests/data/tst_download.qml b/tests/auto/quick/qmltests/data/tst_download.qml
index 5eb704cce..ff57c76c7 100644
--- a/tests/auto/quick/qmltests/data/tst_download.qml
+++ b/tests/auto/quick/qmltests/data/tst_download.qml
@@ -28,7 +28,7 @@
import QtQuick 2.0
import QtTest 1.0
-import QtWebEngine 1.9
+import QtWebEngine 1.10
import Qt.labs.platform 1.0
TestWebEngineView {
@@ -42,6 +42,14 @@ TestWebEngineView {
property bool cancelDownload: false
property var downloadState: []
property var downloadInterruptReason: null
+ property url downloadUrl: ""
+ property string suggestedFileName: ""
+ property string downloadDirectory: ""
+ property string downloadFileName: ""
+ property string downloadedPath: ""
+ property int downloadDirectoryChanged: 0
+ property int downloadFileNameChanged: 0
+ property int downloadPathChanged: 0
function urlToPath(url) {
var path = url.toString()
@@ -66,21 +74,36 @@ TestWebEngineView {
ignoreUnknownSignals: true
onStateChanged: downloadState.push(target.state)
onInterruptReasonChanged: downloadInterruptReason = target.interruptReason
+ onDownloadDirectoryChanged: downloadDirectoryChanged++
+ onDownloadFileNameChanged: downloadFileNameChanged++
+ onPathChanged: downloadPathChanged++
}
WebEngineProfile {
id: testDownloadProfile
onDownloadRequested: {
+ testDownloadProfile.downloadPath = urlToPath(StandardPaths.writableLocation(StandardPaths.TempLocation))
downloadState.push(download.state)
downloadItemConnections.target = download
if (cancelDownload) {
download.cancel()
} else {
totalBytes = download.totalBytes
- download.path = "testfile.zip"
+ download.downloadDirectory = testDownloadProfile.downloadPath
+ download.downloadFileName = "testfile.zip"
+
+ if (downloadDirectory.length != 0)
+ download.downloadDirectory = testDownloadProfile.downloadPath + downloadDirectory
+
+ if (downloadFileName.length != 0)
+ download.downloadFileName = downloadFileName
+
download.accept()
}
+ downloadUrl = download.url
+ suggestedFileName = download.suggestedFileName
+ downloadedPath = download.downloadDirectory + download.downloadFileName
}
onDownloadFinished: {
receivedBytes = download.receivedBytes;
@@ -99,6 +122,9 @@ TestWebEngineView {
downloadItemConnections.target = null
downloadState = []
downloadInterruptReason = null
+ downloadDirectoryChanged = 0
+ downloadFileNameChanged = 0
+ downloadPathChanged = 0
}
function test_downloadRequest() {
@@ -106,6 +132,8 @@ TestWebEngineView {
webEngineView.url = Qt.resolvedUrl("download.zip")
downLoadRequestedSpy.wait()
compare(downLoadRequestedSpy.count, 1)
+ compare(downloadUrl, webEngineView.url)
+ compare(suggestedFileName, "download.zip")
compare(downloadState[0], WebEngineDownloadItem.DownloadRequested)
verify(!downloadInterruptReason)
}
@@ -115,6 +143,8 @@ TestWebEngineView {
webEngineView.url = Qt.resolvedUrl("download.zip")
downLoadRequestedSpy.wait()
compare(downLoadRequestedSpy.count, 1)
+ compare(downloadUrl, webEngineView.url)
+ compare(suggestedFileName, "download.zip")
compare(totalBytes, 325)
verify(!downloadInterruptReason)
}
@@ -124,6 +154,8 @@ TestWebEngineView {
webEngineView.url = Qt.resolvedUrl("download.zip")
downLoadRequestedSpy.wait()
compare(downLoadRequestedSpy.count, 1)
+ compare(downloadUrl, webEngineView.url)
+ compare(suggestedFileName, "download.zip")
compare(downloadState[0], WebEngineDownloadItem.DownloadRequested)
tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress)
downloadFinishedSpy.wait()
@@ -138,6 +170,8 @@ TestWebEngineView {
webEngineView.url = Qt.resolvedUrl("download.zip")
downLoadRequestedSpy.wait()
compare(downLoadRequestedSpy.count, 1)
+ compare(downloadUrl, webEngineView.url)
+ compare(suggestedFileName, "download.zip")
compare(downloadFinishedSpy.count, 1)
tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadCancelled)
tryCompare(webEngineView, "downloadInterruptReason", WebEngineDownloadItem.UserCanceled)
@@ -153,5 +187,28 @@ TestWebEngineView {
testDownloadProfile.downloadPath = downloadPath;
compare(testDownloadProfile.downloadPath, downloadPath);
}
+
+ function test_downloadToDirectoryWithFileName() {
+ compare(downLoadRequestedSpy.count, 0);
+ compare(downloadDirectoryChanged, 0);
+ compare(downloadFileNameChanged, 0);
+ downloadDirectory = "/test/";
+ downloadFileName = "test.zip";
+ webEngineView.url = Qt.resolvedUrl("download.zip");
+ downLoadRequestedSpy.wait();
+ compare(downLoadRequestedSpy.count, 1);
+ compare(downloadUrl, webEngineView.url);
+ compare(suggestedFileName, "download.zip");
+ compare(downloadState[0], WebEngineDownloadItem.DownloadRequested);
+ tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress);
+ compare(downloadedPath, testDownloadProfile.downloadPath + downloadDirectory + downloadFileName);
+ compare(downloadDirectoryChanged, 1);
+ compare(downloadFileNameChanged, 3);
+ compare(downloadPathChanged, 4);
+ downloadFinishedSpy.wait();
+ compare(totalBytes, receivedBytes);
+ tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted);
+ verify(!downloadInterruptReason);
+ }
}
}
diff --git a/tests/auto/quick/qquickwebengineview/BLACKLIST b/tests/auto/quick/qquickwebengineview/BLACKLIST
index 49c5332ff..d4d5c9844 100644
--- a/tests/auto/quick/qquickwebengineview/BLACKLIST
+++ b/tests/auto/quick/qquickwebengineview/BLACKLIST
@@ -1,5 +1,2 @@
-[javascriptClipboard:default]
-opensuse-leap
-
-[javascriptClipboard:canPaste]
-opensuse-leap
+[transparentWebEngineViews]
+windows
diff --git a/tests/auto/widgets/accessibility/tst_accessibility.cpp b/tests/auto/widgets/accessibility/tst_accessibility.cpp
index b0165cfbc..d69a4c0a7 100644
--- a/tests/auto/widgets/accessibility/tst_accessibility.cpp
+++ b/tests/auto/widgets/accessibility/tst_accessibility.cpp
@@ -389,6 +389,7 @@ void tst_Accessibility::roles()
QWebEngineView webView;
webView.setHtml("<html><body>" + html + "</body></html>");
+ webView.show();
QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished);
QVERIFY(spyFinished.wait());
diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
index e614f3751..c0bb8d5c5 100644
--- a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
+++ b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp
@@ -238,7 +238,8 @@ void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661()
connect(item, &QWebEngineDownloadItem::stateChanged, [&downloadState](QWebEngineDownloadItem::DownloadState newState){
downloadState = newState;
});
- item->setPath(tempDir.filePath(QFileInfo(item->path()).fileName()));
+ item->setDownloadDirectory(tempDir.filePath(QFileInfo(item->path()).path()));
+ item->setDownloadFileName(QFileInfo(item->path()).fileName());
item->accept();
});
diff --git a/tests/auto/widgets/origins/resources/redirect.css b/tests/auto/widgets/origins/resources/redirect.css
new file mode 100644
index 000000000..41d7560cc
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/redirect.css
@@ -0,0 +1,8 @@
+@font-face {
+ font-family: 'MyWebFont';
+ src: url('redirect1:/resources/Akronim-Regular.woff2') format('woff2');
+}
+
+body {
+ font-family: 'MyWebFont', Fallback, sans-serif;
+}
diff --git a/tests/auto/widgets/origins/resources/redirect.html b/tests/auto/widgets/origins/resources/redirect.html
new file mode 100644
index 000000000..04948e14b
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/redirect.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>redirect</title>
+ <link rel="stylesheet" href="redirect1:/resources/redirect.css">
+ </head>
+ <body>
+ Text
+ </body>
+</html>
diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp
index c1307c5e6..02d5bfba3 100644
--- a/tests/auto/widgets/origins/tst_origins.cpp
+++ b/tests/auto/widgets/origins/tst_origins.cpp
@@ -122,6 +122,18 @@ void registerSchemes()
scheme.setDefaultPort(42);
QWebEngineUrlScheme::registerScheme(scheme);
}
+
+ {
+ QWebEngineUrlScheme scheme(QBAL("redirect1"));
+ scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
+ QWebEngineUrlScheme::registerScheme(scheme);
+ }
+
+ {
+ QWebEngineUrlScheme scheme(QBAL("redirect2"));
+ scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
+ QWebEngineUrlScheme::registerScheme(scheme);
+ }
}
Q_CONSTRUCTOR_FUNCTION(registerSchemes)
@@ -145,13 +157,26 @@ public:
profile->installUrlSchemeHandler(QBAL("HostSyntax-ContentSecurityPolicyIgnored"), this);
profile->installUrlSchemeHandler(QBAL("HostAndPortSyntax"), this);
profile->installUrlSchemeHandler(QBAL("HostPortAndUserInformationSyntax"), this);
+ profile->installUrlSchemeHandler(QBAL("redirect1"), this);
+ profile->installUrlSchemeHandler(QBAL("redirect2"), this);
}
+ QVector<QUrl> &requests() { return m_requests; }
+
private:
void requestStarted(QWebEngineUrlRequestJob *job) override
{
+ QUrl url = job->requestUrl();
+ m_requests << url;
+
+ if (url.scheme() == QBAL("redirect1")) {
+ url.setScheme(QBAL("redirect2"));
+ job->redirect(url);
+ return;
+ }
+
QString pathPrefix = QSL(THIS_DIR);
- QString pathSuffix = job->requestUrl().path();
+ QString pathSuffix = url.path();
QFile *file = new QFile(pathPrefix + pathSuffix, job);
if (!file->open(QIODevice::ReadOnly)) {
job->fail(QWebEngineUrlRequestJob::RequestFailed);
@@ -160,8 +185,12 @@ private:
QByteArray mimeType = QBAL("text/html");
if (pathSuffix.endsWith(QSL(".js")))
mimeType = QBAL("application/javascript");
+ else if (pathSuffix.endsWith(QSL(".css")))
+ mimeType = QBAL("text/css");
job->reply(mimeType, file);
}
+
+ QVector<QUrl> m_requests;
};
class tst_Origins final : public QObject {
@@ -169,6 +198,7 @@ class tst_Origins final : public QObject {
private Q_SLOTS:
void initTestCase();
+ void cleanup();
void cleanupTestCase();
void jsUrlCanon();
@@ -187,6 +217,7 @@ private Q_SLOTS:
void serviceWorker();
void viewSource();
void createObjectURL();
+ void redirect();
private:
bool load(const QUrl &url)
@@ -209,10 +240,19 @@ private:
void tst_Origins::initTestCase()
{
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression("Please register the custom scheme 'tst'.*"));
+
m_page = new QWebEnginePage(&m_profile, nullptr);
m_handler = new TstUrlSchemeHandler(&m_profile);
}
+void tst_Origins::cleanup()
+{
+ m_handler->requests().clear();
+}
+
void tst_Origins::cleanupTestCase()
{
delete m_handler;
@@ -346,11 +386,7 @@ void tst_Origins::jsUrlOrigin()
QCOMPARE(eval(QSL("new URL(\"file:/etc/passwd\").origin")), QVariant(QSL("file://")));
QCOMPARE(eval(QSL("new URL(\"file://foo.com/etc/passwd\").origin")), QVariant(QSL("file://")));
- // The qrc scheme should behave like file.
- QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc://")));
- QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc://")));
-
- // Unregistered schemes behaves like opaque origins.
+ // Unregistered schemes behave like file.
QCOMPARE(eval(QSL("new URL(\"tst:/banana\").origin")), QVariant(QSL("tst://")));
QCOMPARE(eval(QSL("new URL(\"tst://foo.com/banana\").origin")), QVariant(QSL("tst://")));
@@ -367,8 +403,9 @@ void tst_Origins::jsUrlOrigin()
QVariant(QSL("hostportanduserinformationsyntax://foo")));
// A PathSyntax scheme should have a 'universal' origin.
- QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")),
- QVariant(QSL("pathsyntax://")));
+ QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")), QVariant(QSL("pathsyntax:")));
+ QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc:")));
+ QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc:")));
// The NoAccessAllowed flag forces opaque origins.
QCOMPARE(eval(QSL("new URL(\"PathSyntax-NoAccessAllowed:foo\").origin")),
@@ -709,7 +746,7 @@ void tst_Origins::serviceWorker()
QVERIFY(load(QSL("qrc:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('qrc://') is not supported.")));
+ .contains(QSL("The URL protocol of the current origin ('qrc:') is not supported.")));
QVERIFY(load(QSL("tst:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
@@ -724,7 +761,7 @@ void tst_Origins::serviceWorker()
QVERIFY(load(QSL("PathSyntax-Secure:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure://') is not supported.")));
+ .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure:') is not supported.")));
QVERIFY(load(QSL("PathSyntax-ServiceWorkersAllowed:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
@@ -775,5 +812,18 @@ void tst_Origins::createObjectURL()
QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:tst:")));
}
+void tst_Origins::redirect()
+{
+ QVERIFY(load(QSL("redirect1:/resources/redirect.html")));
+ QTRY_COMPARE(m_handler->requests().size(), 7);
+ QCOMPARE(m_handler->requests()[0], QUrl(QStringLiteral("redirect1:/resources/redirect.html")));
+ QCOMPARE(m_handler->requests()[1], QUrl(QStringLiteral("redirect2:/resources/redirect.html")));
+ QCOMPARE(m_handler->requests()[2], QUrl(QStringLiteral("redirect1:/resources/redirect.css")));
+ QCOMPARE(m_handler->requests()[3], QUrl(QStringLiteral("redirect2:/resources/redirect.css")));
+ QCOMPARE(m_handler->requests()[4], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2")));
+ QCOMPARE(m_handler->requests()[5], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2")));
+ QCOMPARE(m_handler->requests()[6], QUrl(QStringLiteral("redirect2:/resources/Akronim-Regular.woff2")));
+}
+
QTEST_MAIN(tst_Origins)
#include "tst_origins.moc"
diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
index 3566c2216..6dc7f03c1 100644
--- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
+++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
@@ -78,6 +78,7 @@ private Q_SLOTS:
void downloadToNonExistentDir();
void downloadToReadOnlyDir();
void downloadPathValidation();
+ void downloadToDirectoryWithFileName();
private:
void saveLink(QPoint linkPos);
@@ -447,6 +448,8 @@ void tst_QWebEngineDownloadItem::downloadLink()
QByteArray slashFileName = QByteArrayLiteral("/") + fileName;
QString suggestedPath =
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + slashFileName;
+ QString downloadDirectory = tmpDir.path();
+ QString downloadFileName = fileName;
QString downloadPath = tmpDir.path() + slashFileName;
QUrl downloadUrl = m_server->url(slashFileName);
int acceptedCount = 0;
@@ -460,7 +463,7 @@ void tst_QWebEngineDownloadItem::downloadLink()
QCOMPARE(item->type(), expectedDownloadType(userAction, fileDisposition));
QCOMPARE(item->isSavePageDownload(), false);
QCOMPARE(item->mimeType(), QString(fileMimeTypeDetected));
- QCOMPARE(item->path(), suggestedPath);
+ QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), suggestedPath);
QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat);
QCOMPARE(item->url(), downloadUrl);
QCOMPARE(item->page(), m_page);
@@ -474,14 +477,15 @@ void tst_QWebEngineDownloadItem::downloadLink()
QCOMPARE(item->type(), expectedDownloadType(userAction, fileDisposition));
QCOMPARE(item->isSavePageDownload(), false);
QCOMPARE(item->mimeType(), QString(fileMimeTypeDetected));
- QCOMPARE(item->path(), downloadPath);
+ QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath);
QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat);
QCOMPARE(item->url(), downloadUrl);
QCOMPARE(item->page(), m_page);
finishedCount++;
});
- item->setPath(downloadPath);
+ item->setDownloadDirectory(downloadDirectory);
+ item->setDownloadFileName(downloadFileName);
item->accept();
acceptedCount++;
@@ -575,7 +579,8 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks()
QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat);
QCOMPARE(item->mimeType(), QStringLiteral("text/plain"));
QString filePart = QChar('/') + item->url().fileName();
- QCOMPARE(item->path(), standardDir + filePart);
+ QString fileName = item->url().fileName();
+ QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), standardDir + filePart);
// type() is broken due to race condition in DownloadManagerDelegateQt
if (action1 == ClickLink && action2 == ClickLink) {
@@ -590,7 +595,8 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks()
connect(item, &QWebEngineDownloadItem::finished, [&]() {
finishedCount++;
});
- item->setPath(tmpDir.path() + filePart);
+ item->setDownloadDirectory(tmpDir.path());
+ item->setDownloadFileName(fileName);
item->accept();
acceptedCount++;
@@ -655,7 +661,7 @@ void tst_QWebEngineDownloadItem::downloadPage()
QCOMPARE(item->isSavePageDownload(), true);
// FIXME(juvaldma): why is mimeType always the same?
QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive"));
- QCOMPARE(item->path(), downloadPath);
+ QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath);
QCOMPARE(item->savePageFormat(), savePageFormat);
QCOMPARE(item->url(), downloadUrl);
QCOMPARE(item->page(), m_page);
@@ -670,7 +676,7 @@ void tst_QWebEngineDownloadItem::downloadPage()
QCOMPARE(item->type(), QWebEngineDownloadItem::SavePage);
QCOMPARE(item->isSavePageDownload(), true);
QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive"));
- QCOMPARE(item->path(), downloadPath);
+ QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath);
QCOMPARE(item->savePageFormat(), savePageFormat);
QCOMPARE(item->url(), downloadUrl);
QCOMPARE(item->page(), m_page);
@@ -869,6 +875,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename()
QFETCH(QString, extension);
QString fileName = QString("%1.%2").arg(baseName).arg(extension);
QString downloadedFilePath;
+ QString suggestedFileName;
bool downloadFinished = false;
QTemporaryDir tmpDir;
@@ -890,6 +897,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename()
// Set up profile and download handler
ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ suggestedFileName = item->suggestedFileName();
item->accept();
connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
@@ -899,7 +907,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename()
QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
QCOMPARE(item->type(), QWebEngineDownloadItem::Attachment);
QCOMPARE(item->isSavePageDownload(), false);
- downloadedFilePath = item->path();
+ downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
downloadFinished = true;
});
});
@@ -915,6 +923,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename()
QTRY_VERIFY(downloadFinished);
QVERIFY(QFile(downloadedFilePath).exists());
QCOMPARE(downloadedFilePath, m_profile->downloadPath() + "/" + baseName + " (" + QString::number(i) + ")." + extension);
+ QCOMPARE(suggestedFileName, fileName);
}
}
@@ -925,6 +934,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
QString extension("txt");
QString fileName = QString("%1.%2").arg(baseName).arg(extension);
QString downloadedFilePath;
+ QString suggestedFileName;
bool downloadFinished = false;
QTemporaryDir tmpDir;
@@ -945,6 +955,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
// Set up profile and download handler
ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ suggestedFileName = item->suggestedFileName();
item->accept();
connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
@@ -954,7 +965,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
QCOMPARE(item->page(), m_page);
downloadFinished = true;
- downloadedFilePath = item->path();
+ downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
});
});
@@ -975,6 +986,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
QTRY_VERIFY(downloadFinished);
QVERIFY(QFile(downloadedFilePath).exists());
QCOMPARE(downloadedFilePath, m_profile->downloadPath() + "/" + baseName + " (100)." + extension);
+ QCOMPARE(suggestedFileName, fileName);
// Check if the downloaded files are suffixed with timestamp after the 100th download.
for (int i = 101; i < 103; i++) {
@@ -988,6 +1000,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
// ISO 8601 Date and time in UTC
QRegExp timestamp("^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9])([0-5][0-9])([0-5][0-9])([.][0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9])[0-5][0-9])?$");
QVERIFY(timestamp.exactMatch(match.captured(1)));
+ QCOMPARE(suggestedFileName, fileName);
}
}
@@ -1014,6 +1027,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
QString extension("txt");
QString fileName = QString("%1.%2").arg(baseName).arg(extension);
QString downloadedFilePath;
+ QString suggestedFileName;
bool downloadFinished = false;
QTemporaryDir tmpDir;
@@ -1035,6 +1049,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
// Set up profile and download handler
ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ suggestedFileName = item->suggestedFileName();
item->accept();
connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
@@ -1044,7 +1059,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
QCOMPARE(item->page(), m_page);
downloadFinished = true;
- downloadedFilePath = item->path();
+ downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
});
});
@@ -1056,6 +1071,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir()
QTRY_VERIFY(downloadFinished);
QVERIFY(QFile(downloadedFilePath).exists());
QCOMPARE(downloadedFilePath, nonExistentDownloadPath + "/" + fileName);
+ QCOMPARE(suggestedFileName, fileName);
}
void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
@@ -1067,6 +1083,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
QString extension("txt");
QString fileName = QString("%1.%2").arg(baseName).arg(extension);
QString downloadedFilePath;
+ QString suggestedFileName;
bool downloadAccepted = false;
bool downloadFinished = false;
@@ -1089,6 +1106,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
QPointer<QWebEngineDownloadItem> downloadItem;
ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+ suggestedFileName = item->suggestedFileName();
downloadItem = item;
item->accept();
connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
@@ -1109,6 +1127,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir()
QCOMPARE(downloadItem->isFinished(), false);
QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::FileAccessDenied);
QVERIFY(!QFile(downloadedFilePath).exists());
+ QCOMPARE(suggestedFileName, fileName);
// Clear m_requestedDownloads explicitly because download is accepted but never finished.
m_requestedDownloads.clear();
@@ -1233,5 +1252,135 @@ void tst_QWebEngineDownloadItem::downloadPathValidation()
QDir::setCurrent(oldPath);
}
+void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName()
+{
+ QString downloadDirectory;
+ QString downloadFileName;
+ QString downloadedFilePath;
+ QString downloadedSuggestedFileName;
+ QString fileName = "test.txt";
+ QString uniqueFileName = "test (1).txt";
+
+ bool downloadFinished = false;
+
+ QTemporaryDir tmpDir;
+ QVERIFY(tmpDir.isValid());
+ m_profile->setDownloadPath(tmpDir.path());
+
+ // 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
+ ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) {
+
+ if (!downloadDirectory.isEmpty()) {
+ item->setDownloadDirectory(downloadDirectory);
+ QCOMPARE(item->downloadDirectory(), downloadDirectory);
+ }
+
+ if (!downloadFileName.isEmpty()) {
+ item->setDownloadFileName(downloadFileName);
+ QCOMPARE(item->downloadFileName(), downloadFileName);
+ }
+
+ QCOMPARE(item->path(), QDir(item->downloadDirectory()).filePath(item->downloadFileName()));
+ item->accept();
+
+ connect(item, &QWebEngineDownloadItem::finished, [&, item]() {
+ QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted);
+ QCOMPARE(item->isFinished(), true);
+ QCOMPARE(item->totalBytes(), item->receivedBytes());
+ QVERIFY(item->receivedBytes() > 0);
+ QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason);
+ QCOMPARE(item->page(), m_page);
+ downloadFinished = true;
+ downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName());
+ downloadedSuggestedFileName = item->suggestedFileName();
+ });
+ });
+
+ // Download file to the default download directory.
+ downloadDirectory = "";
+ downloadFileName = "";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(m_profile->downloadPath()).filePath(fileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+
+ // Download the same file to another directory
+ downloadFinished = false;
+ downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator();
+ downloadFileName = "";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(fileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+
+ // Download the same file to the same directory and the file name must be unique.
+ downloadFinished = false;
+ downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator();
+ downloadFileName = "";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(uniqueFileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+
+ // Download another file to the same directory and set file name by
+ // QWebEngineDownloadItem::setDownloadDirectory() and setDownloadFileName() to avoid uniquification.
+ downloadFinished = false;
+ downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator();
+ downloadFileName = "test1.txt";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(downloadFileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+
+ // Download the same file to another directory without uniquifying the file name
+ downloadFinished = false;
+ downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator();
+ downloadFileName = "test1.txt";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(downloadFileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+
+ // Download the same file to same directory and set file name by
+ // QWebEngineDownloadItem::setDownloadDirectory() and setDownloadFileName() to avoid uniquification.
+ downloadFinished = false;
+ downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator();
+ downloadFileName = "test1.txt";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(downloadFileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+
+ // Download the same file in the same directory.
+ // Use the suggested file name (test.txt) and the file name will not be unique because this file name don't yet exists.
+ downloadFinished = false;
+ downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator();
+ downloadFileName = "";
+ m_page->setUrl(m_server->url("/" + fileName));
+ QTRY_VERIFY(downloadFinished);
+ QVERIFY(QFile(downloadedFilePath).exists());
+ QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(fileName));
+ QCOMPARE(downloadedSuggestedFileName, fileName);
+}
+
QTEST_MAIN(tst_QWebEngineDownloadItem)
#include "tst_qwebenginedownloaditem.moc"
diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST
index 2000b0260..4e344c936 100644
--- a/tests/auto/widgets/qwebenginepage/BLACKLIST
+++ b/tests/auto/widgets/qwebenginepage/BLACKLIST
@@ -4,11 +4,6 @@ osx
[mouseMovementProperties]
windows
-[getUserMediaRequestDesktopVideoManyPages]
-windows
-
-[getUserMediaRequestDesktopVideoManyRequests]
-windows
-
[runJavaScriptFromSlot]
osx
+linux
diff --git a/tests/auto/widgets/qwebenginepage/resources/lifecycle.html b/tests/auto/widgets/qwebenginepage/resources/lifecycle.html
new file mode 100644
index 000000000..aa477a359
--- /dev/null
+++ b/tests/auto/widgets/qwebenginepage/resources/lifecycle.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Lifecycle</title>
+ <script>
+ let frozenness = 0;
+ document.addEventListener("freeze", function() {
+ frozenness += 1;
+ });
+ document.addEventListener("resume", function() {
+ frozenness -= 1;
+ });
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 0fa38f9ef..713feca6d 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -202,9 +202,23 @@ private Q_SLOTS:
void sendNotification();
void contentsSize();
+ void setLifecycleState();
+ void setVisible();
+ void discardPreservesProperties();
+ void discardBeforeInitialization();
+ void automaticUndiscard();
+ void setLifecycleStateWithDevTools();
+ void discardPreservesCommittedLoad();
+ void discardAbortsPendingLoad();
+ void discardAbortsPendingLoadAndPreservesCommittedLoad();
+ void recommendedState();
+ void recommendedStateAuto();
+ void setLifecycleStateAndReload();
+
void editActionsWithExplicitFocus();
void editActionsWithInitialFocus();
void editActionsWithFocusOnIframe();
+ void editActionsWithoutSelection();
void customUserAgentInNewTab();
@@ -290,9 +304,9 @@ protected:
{
Q_UNUSED(url);
Q_UNUSED(isMainFrame);
- if (type == QWebEnginePage::NavigationTypeFormSubmitted)
- return m_acceptNavigationRequest;
- return true;
+ if (type == QWebEnginePage::NavigationTypeTyped)
+ return true;
+ return m_acceptNavigationRequest;
}
};
@@ -579,7 +593,7 @@ void tst_QWebEnginePage::acceptNavigationRequestNavigationType()
<< QWebEnginePage::NavigationTypeBackForward
<< QWebEnginePage::NavigationTypeReload
<< QWebEnginePage::NavigationTypeTyped
- << QWebEnginePage::NavigationTypeOther;
+ << QWebEnginePage::NavigationTypeRedirect;
QVERIFY(expectedList.count() == page.navigations.count());
for (int i = 0; i < expectedList.count(); ++i) {
QCOMPARE(page.navigations[i].type, expectedList[i]);
@@ -3408,6 +3422,645 @@ void tst_QWebEnginePage::contentsSize()
QCOMPARE(m_page->contentsSize().height(), 1216);
}
+void tst_QWebEnginePage::setLifecycleState()
+{
+ qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState");
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged);
+ QSignalSpy visibleSpy(&page, &QWebEnginePage::visibleChanged);
+
+ page.load(QStringLiteral("qrc:/resources/lifecycle.html"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false));
+ QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0));
+
+ // Active -> Frozen
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false));
+ QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(1));
+
+ // Frozen -> Active
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false));
+ QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0));
+
+ // Active -> Discarded
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+ QTest::ignoreMessage(QtWarningMsg, "runJavaScript: disabled in Discarded state");
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant());
+ QTest::ignoreMessage(QtWarningMsg, "runJavaScript: disabled in Discarded state");
+ QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant());
+ QCOMPARE(loadSpy.count(), 0);
+
+ // Discarded -> Frozen (illegal!)
+ QTest::ignoreMessage(QtWarningMsg,
+ "setLifecycleState: failed to transition from Discarded to Frozen state: "
+ "illegal transition");
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+
+ // Discarded -> Active
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(true));
+ QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0));
+
+ // Active -> Frozen -> Discarded -> Active
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(lifecycleSpy.count(), 3);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(true));
+ QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0));
+
+ // Reload clears document.wasDiscarded
+ page.triggerAction(QWebEnginePage::Reload);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false));
+}
+
+void tst_QWebEnginePage::setVisible()
+{
+ qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState");
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged);
+ QSignalSpy visibleSpy(&page, &QWebEnginePage::visibleChanged);
+
+ page.load(QStringLiteral("about:blank"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 0);
+ QCOMPARE(page.isVisible(), false);
+
+ // hidden -> visible
+ page.setVisible(true);
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 1);
+ QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(page.isVisible(), true);
+
+ // Active -> Frozen (illegal)
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "setLifecycleState: failed to transition from Active to Frozen state: page is visible");
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(lifecycleSpy.count(), 0);
+
+ // visible -> hidden
+ page.setVisible(false);
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 1);
+ QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(false));
+ QCOMPARE(page.isVisible(), false);
+
+ // Active -> Frozen
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen);
+
+ // hidden -> visible (triggers Frozen -> Active)
+ page.setVisible(true);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 1);
+ QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(page.isVisible(), true);
+
+ // Active -> Discarded (illegal)
+ QTest::ignoreMessage(QtWarningMsg,
+ "setLifecycleState: failed to transition from Active to Discarded state: "
+ "page is visible");
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(lifecycleSpy.count(), 0);
+
+ // visible -> hidden
+ page.setVisible(false);
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 1);
+ QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(false));
+ QCOMPARE(page.isVisible(), false);
+
+ // Active -> Discarded
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+
+ // hidden -> visible (triggers Discarded -> Active)
+ page.setVisible(true);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(visibleSpy.count(), 1);
+ QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(page.isVisible(), true);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+}
+
+void tst_QWebEnginePage::discardPreservesProperties()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+
+ page.load(QStringLiteral("about:blank"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+
+ // Change as many properties as possible to non-default values
+ bool audioMuted = true;
+ QVERIFY(page.isAudioMuted() != audioMuted);
+ page.setAudioMuted(audioMuted);
+ QColor backgroundColor = Qt::black;
+ QVERIFY(page.backgroundColor() != backgroundColor);
+ page.setBackgroundColor(backgroundColor);
+ qreal zoomFactor = 2;
+ QVERIFY(page.zoomFactor() != zoomFactor);
+ page.setZoomFactor(zoomFactor);
+#if QT_CONFIG(webengine_webchannel)
+ QWebChannel *webChannel = new QWebChannel(&page);
+ page.setWebChannel(webChannel);
+#endif
+
+ // Take snapshot of the rest
+ QSizeF contentsSize = page.contentsSize();
+ QIcon icon = page.icon();
+ QUrl iconUrl = page.iconUrl();
+ QUrl requestedUrl = page.requestedUrl();
+ QString title = page.title();
+ QUrl url = page.url();
+
+ // History should be preserved too
+ int historyCount = page.history()->count();
+ QCOMPARE(historyCount, 1);
+ int historyIndex = page.history()->currentItemIndex();
+ QCOMPARE(historyIndex, 0);
+ QWebEngineHistoryItem historyItem = page.history()->currentItem();
+ QVERIFY(historyItem.isValid());
+
+ // Discard + undiscard
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+
+ // Property changes should be preserved
+ QCOMPARE(page.isAudioMuted(), audioMuted);
+ QCOMPARE(page.backgroundColor(), backgroundColor);
+ QCOMPARE(page.contentsSize(), contentsSize);
+ QCOMPARE(page.icon(), icon);
+ QCOMPARE(page.iconUrl(), iconUrl);
+ QCOMPARE(page.requestedUrl(), requestedUrl);
+ QCOMPARE(page.title(), title);
+ QCOMPARE(page.url(), url);
+ QCOMPARE(page.zoomFactor(), zoomFactor);
+#if QT_CONFIG(webengine_webchannel)
+ QCOMPARE(page.webChannel(), webChannel);
+#endif
+ QCOMPARE(page.history()->count(), historyCount);
+ QCOMPARE(page.history()->currentItemIndex(), historyIndex);
+ QCOMPARE(page.history()->currentItem().url(), historyItem.url());
+ QCOMPARE(page.history()->currentItem().originalUrl(), historyItem.originalUrl());
+ QCOMPARE(page.history()->currentItem().title(), historyItem.title());
+}
+
+void tst_QWebEnginePage::discardBeforeInitialization()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ // The call is ignored
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+}
+
+void tst_QWebEnginePage::automaticUndiscard()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+
+ page.load(QStringLiteral("about:blank"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+
+ // setUrl
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ page.setUrl(QStringLiteral("qrc:/resources/lifecycle.html"));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+
+ // setContent
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ page.setContent(QByteArrayLiteral("foo"));
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+}
+
+void tst_QWebEnginePage::setLifecycleStateWithDevTools()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage inspectedPage(&profile);
+ QWebEnginePage devToolsPage(&profile);
+ QSignalSpy devToolsSpy(&devToolsPage, &QWebEnginePage::loadFinished);
+ QSignalSpy inspectedSpy(&inspectedPage, &QWebEnginePage::loadFinished);
+
+ // Ensure pages are initialized
+ inspectedPage.load(QStringLiteral("about:blank"));
+ devToolsPage.load(QStringLiteral("about:blank"));
+ QTRY_COMPARE(inspectedSpy.count(), 1);
+ QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true));
+ QTRY_COMPARE(devToolsSpy.count(), 1);
+ QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
+
+ // Open DevTools with Frozen inspectedPage
+ inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ inspectedPage.setDevToolsPage(&devToolsPage);
+ QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(devToolsSpy.count(), 1);
+ QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
+ inspectedPage.setDevToolsPage(nullptr);
+
+ // Open DevTools with Discarded inspectedPage
+ inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ inspectedPage.setDevToolsPage(&devToolsPage);
+ QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(devToolsSpy.count(), 1);
+ QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
+ QTRY_COMPARE(inspectedSpy.count(), 1);
+ QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true));
+ inspectedPage.setDevToolsPage(nullptr);
+
+ // Open DevTools with Frozen devToolsPage
+ devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ devToolsPage.setInspectedPage(&inspectedPage);
+ QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(devToolsSpy.count(), 1);
+ QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
+ devToolsPage.setInspectedPage(nullptr);
+
+ // Open DevTools with Discarded devToolsPage
+ devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ devToolsPage.setInspectedPage(&inspectedPage);
+ QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(devToolsSpy.count(), 2);
+ QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(false));
+ QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
+ // keep DevTools open
+
+ // Try to change state while DevTools are open
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "setLifecycleState: failed to transition from Active to Frozen state: DevTools open");
+ inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTest::ignoreMessage(QtWarningMsg,
+ "setLifecycleState: failed to transition from Active to Discarded state: "
+ "DevTools open");
+ inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "setLifecycleState: failed to transition from Active to Frozen state: DevTools open");
+ devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QTest::ignoreMessage(QtWarningMsg,
+ "setLifecycleState: failed to transition from Active to Discarded state: "
+ "DevTools open");
+ devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+}
+
+void tst_QWebEnginePage::discardPreservesCommittedLoad()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadStartedSpy(&page, &QWebEnginePage::loadStarted);
+ QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy urlChangedSpy(&page, &QWebEnginePage::urlChanged);
+ QSignalSpy titleChangedSpy(&page, &QWebEnginePage::titleChanged);
+
+ QString url = QStringLiteral("qrc:/resources/lifecycle.html");
+ page.setUrl(url);
+ QTRY_COMPARE(loadStartedSpy.count(), 1);
+ loadStartedSpy.clear();
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(urlChangedSpy.count(), 1);
+ QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url)));
+ QCOMPARE(page.url(), url);
+ QCOMPARE(titleChangedSpy.count(), 2);
+ QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(url));
+ QString title = QStringLiteral("Lifecycle");
+ QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(title));
+ QCOMPARE(page.title(), title);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(loadStartedSpy.count(), 0);
+ QCOMPARE(loadFinishedSpy.count(), 0);
+ QCOMPARE(urlChangedSpy.count(), 0);
+ QCOMPARE(page.url(), QUrl(url));
+ QCOMPARE(titleChangedSpy.count(), 0);
+ QCOMPARE(page.title(), title);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(loadStartedSpy.count(), 1);
+ loadStartedSpy.clear();
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(urlChangedSpy.count(), 0);
+ QCOMPARE(page.url(), url);
+ QCOMPARE(titleChangedSpy.count(), 0);
+ QCOMPARE(page.title(), title);
+}
+
+void tst_QWebEnginePage::discardAbortsPendingLoad()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadStartedSpy(&page, &QWebEnginePage::loadStarted);
+ QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy urlChangedSpy(&page, &QWebEnginePage::urlChanged);
+ QSignalSpy titleChangedSpy(&page, &QWebEnginePage::titleChanged);
+
+ connect(&page, &QWebEnginePage::loadStarted,
+ [&]() { page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); });
+ QUrl url = QStringLiteral("qrc:/resources/lifecycle.html");
+ page.setUrl(url);
+ QTRY_COMPARE(loadStartedSpy.count(), 1);
+ loadStartedSpy.clear();
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(false));
+ QCOMPARE(urlChangedSpy.count(), 2);
+ QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(url));
+ QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl()));
+ QCOMPARE(titleChangedSpy.count(), 0);
+ QCOMPARE(page.url(), QUrl());
+ QCOMPARE(page.title(), QString());
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(loadStartedSpy.count(), 0);
+ QCOMPARE(loadFinishedSpy.count(), 0);
+ QCOMPARE(urlChangedSpy.count(), 0);
+ QCOMPARE(page.url(), QUrl());
+ QCOMPARE(page.title(), QString());
+}
+
+void tst_QWebEnginePage::discardAbortsPendingLoadAndPreservesCommittedLoad()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadStartedSpy(&page, &QWebEnginePage::loadStarted);
+ QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy urlChangedSpy(&page, &QWebEnginePage::urlChanged);
+ QSignalSpy titleChangedSpy(&page, &QWebEnginePage::titleChanged);
+
+ QString url1 = QStringLiteral("qrc:/resources/lifecycle.html");
+ page.setUrl(url1);
+ QTRY_COMPARE(loadStartedSpy.count(), 1);
+ loadStartedSpy.clear();
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(urlChangedSpy.count(), 1);
+ QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url1)));
+ QCOMPARE(page.url(), url1);
+ QCOMPARE(titleChangedSpy.count(), 2);
+ QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(url1));
+ QString title = QStringLiteral("Lifecycle");
+ QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(title));
+ QCOMPARE(page.title(), title);
+
+ connect(&page, &QWebEnginePage::loadStarted,
+ [&]() { page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); });
+ QString url2 = QStringLiteral("about:blank");
+ page.setUrl(url2);
+ QTRY_COMPARE(loadStartedSpy.count(), 1);
+ loadStartedSpy.clear();
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(false));
+ QCOMPARE(urlChangedSpy.count(), 2);
+ QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url2)));
+ QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url1)));
+ QCOMPARE(titleChangedSpy.count(), 0);
+ QCOMPARE(page.url(), url1);
+ QCOMPARE(page.title(), title);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(loadStartedSpy.count(), 0);
+ QCOMPARE(loadFinishedSpy.count(), 0);
+ QCOMPARE(urlChangedSpy.count(), 0);
+ QCOMPARE(page.url(), url1);
+ QCOMPARE(page.title(), title);
+}
+
+void tst_QWebEnginePage::recommendedState()
+{
+ qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState");
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+
+ struct Event {
+ enum { StateChange, RecommendationChange } key;
+ QWebEnginePage::LifecycleState value;
+ };
+ std::vector<Event> events;
+ connect(&page, &QWebEnginePage::lifecycleStateChanged, [&](QWebEnginePage::LifecycleState state) {
+ events.push_back(Event { Event::StateChange, state });
+ });
+ connect(&page, &QWebEnginePage::recommendedStateChanged, [&](QWebEnginePage::LifecycleState state) {
+ events.push_back(Event { Event::RecommendationChange, state });
+ });
+
+ page.load(QStringLiteral("qrc:/resources/lifecycle.html"));
+ QTRY_COMPARE(events.size(), 1u);
+ QCOMPARE(events[0].key, Event::RecommendationChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen);
+
+ page.setVisible(true);
+ QTRY_COMPARE(events.size(), 1u);
+ QCOMPARE(events[0].key, Event::RecommendationChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Active);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Active);
+
+ page.setVisible(false);
+ QTRY_COMPARE(events.size(), 1u);
+ QCOMPARE(events[0].key, Event::RecommendationChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen);
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QTRY_COMPARE(events.size(), 2u);
+ QCOMPARE(events[0].key, Event::RecommendationChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(events[1].key, Event::RecommendationChange);
+ QCOMPARE(events[1].value, QWebEnginePage::LifecycleState::Frozen);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen);
+
+ QWebEnginePage devTools;
+ page.setDevToolsPage(&devTools);
+ QTRY_COMPARE(events.size(), 1u);
+ QCOMPARE(events[0].key, Event::RecommendationChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Active);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Active);
+
+ page.setDevToolsPage(nullptr);
+ QTRY_COMPARE(events.size(), 1u);
+ QCOMPARE(events[0].key, Event::RecommendationChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QTRY_COMPARE(events.size(), 2u);
+ QCOMPARE(events[0].key, Event::StateChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(events[1].key, Event::RecommendationChange);
+ QCOMPARE(events[1].value, QWebEnginePage::LifecycleState::Discarded);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Discarded);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QTRY_COMPARE(events.size(), 1u);
+ QCOMPARE(events[0].key, Event::StateChange);
+ QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Discarded);
+ events.clear();
+ QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Discarded);
+}
+
+void tst_QWebEnginePage::recommendedStateAuto()
+{
+ qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState");
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged);
+ connect(&page, &QWebEnginePage::recommendedStateChanged, &page, &QWebEnginePage::setLifecycleState);
+
+ page.load(QStringLiteral("qrc:/resources/lifecycle.html"));
+ QTRY_COMPARE(lifecycleSpy.count(), 2);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+
+ page.setVisible(true);
+ QTRY_COMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+
+ page.setVisible(false);
+ QTRY_COMPARE(lifecycleSpy.count(), 2);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QTRY_COMPARE(lifecycleSpy.count(), 3);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+
+ QWebEnginePage devTools;
+ page.setDevToolsPage(&devTools);
+ QTRY_COMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+
+ page.setDevToolsPage(nullptr);
+ QTRY_COMPARE(lifecycleSpy.count(), 2);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+}
+
+void tst_QWebEnginePage::setLifecycleStateAndReload()
+{
+ qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState");
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished);
+ QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged);
+
+ page.load(QStringLiteral("qrc:/resources/lifecycle.html"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+ QCOMPARE(lifecycleSpy.count(), 0);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen));
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded));
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ QCOMPARE(lifecycleSpy.count(), 1);
+ QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true));
+}
+
void tst_QWebEnginePage::editActionsWithExplicitFocus()
{
QWebEngineView view;
@@ -3495,6 +4148,44 @@ void tst_QWebEnginePage::editActionsWithFocusOnIframe()
QCOMPARE(page->selectedText(), QStringLiteral("inner"));
}
+void tst_QWebEnginePage::editActionsWithoutSelection()
+{
+ QWebEngineView view;
+ QWebEnginePage *page = view.page();
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+
+ QSignalSpy loadFinishedSpy(page, &QWebEnginePage::loadFinished);
+ QSignalSpy selectionChangedSpy(page, &QWebEnginePage::selectionChanged);
+ QSignalSpy actionChangedSpy(page->action(QWebEnginePage::SelectAll), &QAction::changed);
+
+ page->setHtml(QString("<html><body><div>foo bar</div></body></html>"));
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(actionChangedSpy.count(), 1);
+
+ QVERIFY(!page->action(QWebEnginePage::Cut)->isEnabled());
+ QVERIFY(!page->action(QWebEnginePage::Copy)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Paste)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Undo)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Redo)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled());
+ QVERIFY(!page->action(QWebEnginePage::Unselect)->isEnabled());
+
+ page->triggerAction(QWebEnginePage::SelectAll);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(page->hasSelection(), true);
+ QCOMPARE(page->selectedText(), QStringLiteral("foo bar"));
+
+ QVERIFY(page->action(QWebEnginePage::Cut)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Copy)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Paste)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Undo)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Redo)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled());
+ QVERIFY(page->action(QWebEnginePage::Unselect)->isEnabled());
+}
+
void tst_QWebEnginePage::customUserAgentInNewTab()
{
HttpServer server;
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
index cf32486e7..013a307de 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc
@@ -23,6 +23,7 @@
<file>resources/foo.txt</file>
<file>resources/bar.txt</file>
<file>resources/path with spaces.txt</file>
+ <file>resources/lifecycle.html</file>
</qresource>
<qresource prefix='/shared'>
<file alias='notification.html'>../../shared/data/notification.html</file>
diff --git a/tests/auto/widgets/qwebengineprofile/BLACKLIST b/tests/auto/widgets/qwebengineprofile/BLACKLIST
index fc1c957dd..55806eec4 100644
--- a/tests/auto/widgets/qwebengineprofile/BLACKLIST
+++ b/tests/auto/widgets/qwebengineprofile/BLACKLIST
@@ -1,5 +1,3 @@
-[clearDataFromCache]
-*
[disableCache]
*
diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
index 9a2ee9311..1ba9c13e8 100644
--- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
+++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp
@@ -159,6 +159,14 @@ void tst_QWebEngineScript::loadEvents()
QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected);
QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected);
+ // After discard
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Active);
+ QTRY_COMPARE(page.spy.count(), 1);
+ QCOMPARE(page.spy.takeFirst().value(0).toBool(), true);
+ QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected);
+ QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected);
+
// Multiple frames
page.load(QUrl("qrc:/resources/test_iframe_main.html"));
QTRY_COMPARE(page.spy.count(), 1);
@@ -172,7 +180,7 @@ void tst_QWebEngineScript::loadEvents()
// Cross-process navigation
page.load(QUrl("chrome://gpu"));
- QTRY_COMPARE(page.spy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(page.spy.count(), 1, 20000);
QCOMPARE(page.spy.takeFirst().value(0).toBool(), true);
QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected);
QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected);
@@ -531,6 +539,11 @@ void tst_QWebEngineScript::navigation()
page.setUrl(url3);
QTRY_COMPARE(spyTextChanged.count(), 3);
QCOMPARE(testObject.text(), url3);
+
+ page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ page.setUrl(url1);
+ QTRY_COMPARE(spyTextChanged.count(), 4);
+ QCOMPARE(testObject.text(), url1);
}
// Try to set TestObject::text to an invalid UTF-16 string.
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index a7ff05f55..fa179f2f8 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -201,6 +201,7 @@ private Q_SLOTS:
void setViewDeletesImplicitPage();
void setPagePreservesExplicitPage();
void setViewPreservesExplicitPage();
+ void closeDiscardsPage();
};
// This will be called before the first test function is executed.
@@ -1828,11 +1829,14 @@ void tst_QWebEngineView::softwareInputPanel()
void tst_QWebEngineView::inputContextQueryInput()
{
- TestInputContext testContext;
QWebEngineView view;
view.resize(640, 480);
view.show();
+ // testContext will be destroyed before the view, so no events are sent accidentally
+ // when the view is destroyed.
+ TestInputContext testContext;
+
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
view.setHtml("<html><body>"
@@ -2194,6 +2198,22 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
+ // Select text by ctrl+a
+ QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier);
+ QVERIFY(selectionChangedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 3);
+ QVERIFY(view.hasSelection());
+ QCOMPARE(view.page()->selectedText(), QString("This is a text"));
+
+ // Deselect text via discard+undiscard
+ view.hide();
+ view.page()->setLifecycleState(QWebEnginePage::LifecycleState::Discarded);
+ view.show();
+ QVERIFY(loadFinishedSpy.wait());
+ QCOMPARE(selectionChangedSpy.count(), 4);
+ QVERIFY(!view.hasSelection());
+ QVERIFY(view.page()->selectedText().isEmpty());
+
selectionChangedSpy.clear();
view.setHtml("<html><body>"
" This is a text"
@@ -3068,7 +3088,6 @@ void tst_QWebEngineView::webUIURLs_data()
QTest::newRow("supervised-user-internals") << QUrl("chrome://supervised-user-internals") << false;
QTest::newRow("sync-internals") << QUrl("chrome://sync-internals") << false;
QTest::newRow("system") << QUrl("chrome://system") << false;
- QTest::newRow("taskscheduler-internals") << QUrl("chrome://taskscheduler-internals") << true;
QTest::newRow("terms") << QUrl("chrome://terms") << false;
QTest::newRow("thumbnails") << QUrl("chrome://thumbnails") << false;
QTest::newRow("tracing") << QUrl("chrome://tracing") << false;
@@ -3258,5 +3277,21 @@ void tst_QWebEngineView::setViewPreservesExplicitPage()
QVERIFY(explicitPage1); // should not be deleted
}
+void tst_QWebEngineView::closeDiscardsPage()
+{
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QWebEngineView view;
+ view.setPage(&page);
+ view.resize(300, 300);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QCOMPARE(page.isVisible(), true);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active);
+ view.close();
+ QCOMPARE(page.isVisible(), false);
+ QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+}
+
QTEST_MAIN(tst_QWebEngineView)
#include "tst_qwebengineview.moc"
diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
index d02fc78b9..64df05d89 100644
--- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
+++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
@@ -72,10 +72,7 @@ class tst_Spellchecking : public QObject
private Q_SLOTS:
void init();
void cleanup();
- void initTestCase();
- void spellCheckLanguage();
- void spellCheckLanguages();
- void spellCheckEnabled();
+ void settings();
void spellcheck();
void spellcheck_data();
@@ -84,19 +81,8 @@ private:
WebView *m_view;
};
-void tst_Spellchecking::initTestCase()
-{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- QVERIFY(!profile->isSpellCheckEnabled());
- QVERIFY(profile->spellCheckLanguages().isEmpty());
-}
-
void tst_Spellchecking::init()
{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- profile->setSpellCheckEnabled(false);
- profile->setSpellCheckLanguages(QStringList());
m_view = new WebView();
}
@@ -106,7 +92,6 @@ void tst_Spellchecking::load()
m_view->show();
QSignalSpy spyFinished(m_view->page(), &QWebEnginePage::loadFinished);
QVERIFY(spyFinished.wait());
-
}
void tst_Spellchecking::cleanup()
@@ -114,29 +99,57 @@ void tst_Spellchecking::cleanup()
delete m_view;
}
-void tst_Spellchecking::spellCheckLanguage()
+void tst_Spellchecking::settings()
{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- profile->setSpellCheckLanguages({"en-US"});
- QVERIFY(profile->spellCheckLanguages() == QStringList({"en-US"}));
-}
+ // Default profile has spellchecking disabled
-void tst_Spellchecking::spellCheckLanguages()
-{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- profile->setSpellCheckLanguages({"en-US","de-DE"});
- QVERIFY(profile->spellCheckLanguages() == QStringList({"en-US","de-DE"}));
-}
+ QVERIFY(!QWebEngineProfile::defaultProfile()->isSpellCheckEnabled());
+ QVERIFY(QWebEngineProfile::defaultProfile()->spellCheckLanguages().isEmpty());
+ // New named profiles have spellchecking disabled
-void tst_Spellchecking::spellCheckEnabled()
-{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- profile->setSpellCheckEnabled(true);
- QVERIFY(profile->isSpellCheckEnabled());
+ auto profile1 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile1"));
+ QVERIFY(!profile1->isSpellCheckEnabled());
+ QVERIFY(profile1->spellCheckLanguages().isEmpty());
+
+ auto profile2 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile2"));
+ QVERIFY(!profile2->isSpellCheckEnabled());
+ QVERIFY(profile2->spellCheckLanguages().isEmpty());
+
+ // New otr profiles have spellchecking disabled
+
+ auto profile3 = std::make_unique<QWebEngineProfile>();
+ QVERIFY(!profile2->isSpellCheckEnabled());
+ QVERIFY(profile2->spellCheckLanguages().isEmpty());
+
+ // Settings can be changed
+
+ profile1->setSpellCheckEnabled(true);
+ QVERIFY(profile1->isSpellCheckEnabled());
+
+ profile1->setSpellCheckLanguages({"en-US"});
+ QVERIFY(profile1->spellCheckLanguages() == QStringList({"en-US"}));
+
+ profile1->setSpellCheckLanguages({"en-US","de-DE"});
+ QVERIFY(profile1->spellCheckLanguages() == QStringList({"en-US","de-DE"}));
+
+ // Settings are per profile
+
+ QVERIFY(!profile2->isSpellCheckEnabled());
+ QVERIFY(profile2->spellCheckLanguages().isEmpty());
+
+ QVERIFY(!profile3->isSpellCheckEnabled());
+ QVERIFY(profile3->spellCheckLanguages().isEmpty());
+
+ // Settings are not persisted
+
+ // TODO(juvaldma): Write from dtor currently usually happens *after* the
+ // read from the ctor, so this test would pass even if settings were
+ // persisted. It would start to fail on the second run though.
+ profile1.reset();
+ profile1 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile1"));
+ QVERIFY(!profile1->isSpellCheckEnabled());
+ QVERIFY(profile1->spellCheckLanguages().isEmpty());
}
void tst_Spellchecking::spellcheck()
diff --git a/tests/quicktestbrowser/main.cpp b/tests/quicktestbrowser/main.cpp
index 00c1ee4ad..b886564f3 100644
--- a/tests/quicktestbrowser/main.cpp
+++ b/tests/quicktestbrowser/main.cpp
@@ -88,7 +88,7 @@ int main(int argc, char **argv)
index = rootMeta->indexOfProperty("testProfile");
Q_ASSERT(index != -1);
QMetaProperty profileProperty = rootMeta->property(index);
- profileProperty.write(rootObject, qVariantFromValue(profile));
+ profileProperty.write(rootObject, QVariant::fromValue(profile));
QMetaObject::invokeMethod(rootObject, "load", Q_ARG(QVariant, startupUrl()));
diff --git a/tools/scripts/take_snapshot.py b/tools/scripts/take_snapshot.py
index c6de5977d..3f21dda9c 100755
--- a/tools/scripts/take_snapshot.py
+++ b/tools/scripts/take_snapshot.py
@@ -167,7 +167,6 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('third_party/catapult/tracing/test_data/')
or file_path.startswith('third_party/chromevox')
or file_path.startswith('third_party/chromite')
- or file_path.startswith('third_party/cld_3')
or file_path.startswith('third_party/closure_compiler')
or file_path.startswith('third_party/colorama')
or file_path.startswith('third_party/depot_tools')
@@ -175,6 +174,7 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('third_party/fuschsia-sdk/')
or file_path.startswith('third_party/glslang/src/Test/')
or file_path.startswith('third_party/google_')
+ or file_path.startswith('third_party/grpc/')
or file_path.startswith('third_party/hunspell_dictionaries')
or (file_path.startswith('third_party/icu') and file_path.endswith('icudtl_dat.S'))
or file_path.startswith('third_party/icu/android')
@@ -201,6 +201,7 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('third_party/pylint')
or file_path.startswith('third_party/sfntly/src/cpp/data/fonts')
or file_path.startswith('third_party/sfntly/src/java')
+ or file_path.startswith('third_party/skia/docs/')
or file_path.startswith('third_party/skia/infra')
or file_path.startswith('third_party/sqlite/sqlite-src-')
or file_path.startswith('third_party/speech-dispatcher')
@@ -232,6 +233,7 @@ def isInChromiumBlacklist(file_path):
or ('/fuzz' in file_path and (
'/fuzz/' in file_path
or '/fuzzer/' in file_path
+ or '/fuzzers/' in file_path
or '/fuzzing/' in file_path
))
or ('/test' in file_path and (
@@ -243,6 +245,7 @@ def isInChromiumBlacklist(file_path):
not file_path.endswith('mock_chrome_application_mac.h') and
not file_path.endswith('perftimer.h') and
not file_path.endswith('test-torque.tq') and
+ not file_path.endswith('fonts.conf') and
not 'ozone' in file_path and
not 'clang_coverage' in file_path and
not 'crypto/test/trampoline' in file_path and
diff --git a/tools/scripts/version_resolver.py b/tools/scripts/version_resolver.py
index 450671fa5..532da34e3 100644
--- a/tools/scripts/version_resolver.py
+++ b/tools/scripts/version_resolver.py
@@ -38,8 +38,8 @@ import json
import urllib2
import git_submodule as GitSubmodule
-chromium_version = '73.0.3683.105'
-chromium_branch = '3683'
+chromium_version = '75.0.3770.56'
+chromium_branch = '3770'
ninja_version = 'v1.9.0'
json_url = 'http://omahaproxy.appspot.com/all.json'