diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-05-30 10:19:31 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-05-30 10:19:38 +0200 |
commit | d4cb1d15ae8cf57b931b021490b0776cc70f0b32 (patch) | |
tree | 86282a3ed6a2ada1905c00a5b695bfc0bfb525a2 | |
parent | b0324c5e020b98cbc0caf8176bbdfc5cd80b545e (diff) | |
parent | 95ca17c45aea718cade487640edc63e08bc23820 (diff) |
Merge remote-tracking branch 'origin/5.9' into dev
Change-Id: I962033871a1ef624807a4e1869fe869406aa73f7
86 files changed, 1956 insertions, 231 deletions
diff --git a/.qmake.conf b/.qmake.conf index 802e4b53b..76ab2f4b2 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,5 +1,3 @@ -QMAKEPATH += $$PWD/tools/qmake - # Resolve root directories for sources QTWEBENGINE_ROOT = $$PWD QTWEBENGINE_OUT_ROOT = $$shadowed($$PWD) diff --git a/tools/qmake/config.tests/alsa/alsa.pro b/config.tests/alsa/alsa.pro index 7322b6fb8..7322b6fb8 100644 --- a/tools/qmake/config.tests/alsa/alsa.pro +++ b/config.tests/alsa/alsa.pro diff --git a/tools/qmake/config.tests/alsa/alsatest.cpp b/config.tests/alsa/alsatest.cpp index ea511cd21..ea511cd21 100644 --- a/tools/qmake/config.tests/alsa/alsatest.cpp +++ b/config.tests/alsa/alsatest.cpp diff --git a/tools/qmake/config.tests/khr/khr.cpp b/config.tests/khr/khr.cpp index df81bd6b2..df81bd6b2 100644 --- a/tools/qmake/config.tests/khr/khr.cpp +++ b/config.tests/khr/khr.cpp diff --git a/tools/qmake/config.tests/khr/khr.pro b/config.tests/khr/khr.pro index b8e935f5a..b8e935f5a 100644 --- a/tools/qmake/config.tests/khr/khr.pro +++ b/config.tests/khr/khr.pro diff --git a/tools/qmake/config.tests/libvpx/libvpx.cpp b/config.tests/libvpx/libvpx.cpp index 258790309..258790309 100644 --- a/tools/qmake/config.tests/libvpx/libvpx.cpp +++ b/config.tests/libvpx/libvpx.cpp diff --git a/tools/qmake/config.tests/libvpx/libvpx.pro b/config.tests/libvpx/libvpx.pro index aff6d1857..aff6d1857 100644 --- a/tools/qmake/config.tests/libvpx/libvpx.pro +++ b/config.tests/libvpx/libvpx.pro diff --git a/tools/qmake/config.tests/snappy/snappy.cpp b/config.tests/snappy/snappy.cpp index d52c73bd0..d52c73bd0 100644 --- a/tools/qmake/config.tests/snappy/snappy.cpp +++ b/config.tests/snappy/snappy.cpp diff --git a/tools/qmake/config.tests/snappy/snappy.pro b/config.tests/snappy/snappy.pro index 890174a13..890174a13 100644 --- a/tools/qmake/config.tests/snappy/snappy.pro +++ b/config.tests/snappy/snappy.pro diff --git a/tools/qmake/config.tests/srtp/srtp.cpp b/config.tests/srtp/srtp.cpp index 7dfcc832a..7dfcc832a 100644 --- a/tools/qmake/config.tests/srtp/srtp.cpp +++ b/config.tests/srtp/srtp.cpp diff --git a/tools/qmake/config.tests/srtp/srtp.pro b/config.tests/srtp/srtp.pro index 2151d64aa..2151d64aa 100644 --- a/tools/qmake/config.tests/srtp/srtp.pro +++ b/config.tests/srtp/srtp.pro diff --git a/tools/qmake/config.tests/winversion/winversion.cpp b/config.tests/winversion/winversion.cpp index 3a7b67212..3a7b67212 100644 --- a/tools/qmake/config.tests/winversion/winversion.cpp +++ b/config.tests/winversion/winversion.cpp diff --git a/tools/qmake/config.tests/winversion/winversion.pro b/config.tests/winversion/winversion.pro index dc501a2f6..dc501a2f6 100644 --- a/tools/qmake/config.tests/winversion/winversion.pro +++ b/config.tests/winversion/winversion.pro diff --git a/configure.json b/configure.json index 605807a36..e82247ec5 100644 --- a/configure.json +++ b/configure.json @@ -4,13 +4,11 @@ "printsupport" ], - "testDir": "tools/qmake/config.tests", - "commandline": { "options": { "alsa": "boolean", "embedded": "boolean", - "optimize-for-size": { "type": "boolean", "name": "optimize_size" }, + "webengine-icu": { "type": "enum", "name": "system-icu", "values": { "system": "yes", "qt": "no" } }, "ffmpeg": { "type": "enum", "name": "system-ffmpeg", "values": { "system": "yes", "qt": "no" } }, "opus": { "type": "enum", "name": "system-opus", "values": { "system": "yes", "qt": "no" } }, "webp": { "type": "enum", "name": "system-webp", "values": { "system": "yes", "qt": "no" } }, @@ -37,6 +35,12 @@ { "type": "pkgConfig", "args": "libpulse >= 0.9.10 libpulse-mainloop-glib" } ] }, + "icu": { + "label": "icu >= 53", + "sources": [ + { "type": "pkgConfig", "args": "icu-uc >= 53 icu-i18n >= 53" } + ] + }, "ffmpeg": { "label": "libavcodec libavformat libavutil", "sources": [ @@ -87,14 +91,10 @@ }, "embedded": { "label": "Embedded build", + "purpose": "Enables the embedded build configuration.", + "section": "WebEngine", "condition": "config.unix", "autoDetect": "tests.embedded", - "purpose": "Enables the embedded build configuration", - "output": [ "privateFeature" ] - }, - "optimize_size": { - "label": "Optimize for size", - "autoDetect": "tests.embedded", "output": [ "privateFeature" ] }, "alsa": { @@ -110,32 +110,37 @@ }, "pepper-plugins": { "label": "Pepper Plugins", + "purpose": "Enables use of Pepper Flash and Widevine plugins.", + "section": "WebEngine", "autoDetect": "!features.embedded", - "purpose": "Enables use of Pepper Flash and Widevine plugins", "output": [ "privateFeature" ] }, "printing-and-pdf": { "label": "Printing and PDF", + "purpose": "Provides printing and output to PDF.", + "section": "WebEngine", "condition": "module.printsupport && features.printer", "autoDetect": "!features.embedded", - "purpose": "Enables printing and output to PDF", "output": [ "privateFeature" ] }, "proprietary-codecs": { "label": "Proprietary Codecs", + "purpose": "Enables the use of proprietary codecs such as h.264/h.265 and MP3.", + "section": "WebEngine", "autoDetect": false, - "purpose": "Enables the use of proprietary codecs such as h.264/h.265 and MP3", "output": [ "privateFeature" ] }, "spellchecker": { "label": "Spellchecker", - "purpose": "Enables the use of Chromium's spellchecker", + "purpose": "Provides a spellchecker.", + "section": "WebEngine", "output": [ "privateFeature" ] }, "webrtc": { "label": "WebRTC", + "purpose": "Provides WebRTC support.", + "section": "WebEngine", "autoDetect": "!features.embedded", - "purpose": "Enables WebRTC support", "output": [ "privateFeature" ] }, "system-webp": { @@ -156,6 +161,12 @@ "condition": "libs.ffmpeg && features.system-opus && features.system-webp", "output": [ "privateFeature" ] }, + "system-icu": { + "label": "ICU", + "autoDetect": false, + "condition": "libs.icu", + "output": [ "privateFeature" ] + }, "system-ninja": { "label": "Using system ninja", "condition": "tests.ninja", @@ -182,7 +193,6 @@ "section": "Qt WebEngine", "entries": [ "embedded", - "optimize_size", "pepper-plugins", "printing-and-pdf", "proprietary-codecs", @@ -203,6 +213,7 @@ "section": "System libraries", "condition": "config.unix", "entries": [ + "system-icu", "system-webp", "system-opus", "system-ffmpeg" diff --git a/dist/changes-5.9.0 b/dist/changes-5.9.0 new file mode 100644 index 000000000..00c79fb92 --- /dev/null +++ b/dist/changes-5.9.0 @@ -0,0 +1,119 @@ +Qt 5.9 introduces many new features and improvements as well as bugfixes +over the 5.8.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + +**************************************************************************** +* General * +**************************************************************************** + +Important Changes +----------------- + + - Configure options are now handled by the global configure script. This + means options previously controlled by WEBENGINE_CONFIG options should + now use configure flags. For instance the configure command-line option + -proprietary-codecs replaces WEBENGINE_CONFIG+=use_proprietary_codecs. + - [QTBUG-54650, QTBUG-59922] Accessibility is now disabled by default on + Linux, like it is in Chrome, due to poor options for enabling it + conditionally and its heavy performance impact. Set the environment + variable QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY to enable it again. + + +Chromium Snapshot +----------------- + + - Updated the Chromium version to 56.0.2924.122. + - Security fixes from Chromium up to version 58.0.3029.96 + Including fixes for: CVE-2017-5029, CVE-2017-5032, CVE-2017-5033, + CVE-2017-5034, CVE-2017-5036, CVE-2017-5039, CVE-2017-5040, CVE-2017-5044, + CVE-2017-5045, CVE-2017-5046, CVE-2017-5052, CVE-2017-5053, CVE-2017-5055, + CVE-2017-5057, CVE-2017-5058, CVE-2017-5059, CVE-2017-5060, CVE-2017-5061, + CVE-2017-5062, CVE-2017-5065, CVE-2017-5066, CVE-2017-5067, CVE-2017-5068, + CVE-2017-5069 + - Changed the Chromium build-system to GN. + + +Qt WebengineCore +---------------- + + - [QTBUG-56531] Enabled filesystem: protocol handler. + - [QTBUG-57720] Optimized incremental scene-graph rendering in particular + for software rendering. + - [QTBUG-58362, QTBUG-60031] Fixed IME issues on Chinese and Japanese. + - [QTBUG-55766, QTBUG-58362, QTBUG-55766] Fixed selection and IME issues. + - [QTBUG-58982] Fixed crash on exit on macOS. + - [QTBUG-59127] Fixed movementX and movementY properties of mouse events. + - [QTBUG-59168] Fixed 5.8 regression in handling <input type="file">. + - [QTBUG-59407] Fixed black bar on some youtube videos with OpenGL disabled. + - [QTBUG-60049] Enabled brotli support. + + +**************************************************************************** +* APIs * +**************************************************************************** + +General +------- + + - Took Q_ENUM to use on QtWebEngineWidgets interfaces. + - Added a setting to again allow insecure origins to request geolocation. + - [QTBUG-54053] Fixed support for macOS Airplay. + - [QTBUG-56677] Made printing to a PDF file emit the signal. + pdfPrintingFinished() in both QQuickWebEngineView and QWebEnginePage. + - [QTBUG-57354] Fixed font loading issue on macOS. + - [QTBUG-57924] Fixed assert on right-clicking Flash apps. + - [QTBUG-58037] Fixed drag and drop issues. + - [QTBUG-58488] Fixed window type of popups on X11. + - [QTBUG-58561] Stopped firing too many mousemove events. + - [QTBUG-58650] Fixed segfault when changing cookie policy. + - [QTBUG-58920] Fixed crash while dragging on Windows. + - [QTBUG-59053] Fixed a conflict with single letter short-cuts and + editable input fields. + - [QTBUG-59273] Now handles Qt::AA_UseSoftwareOpenGL. + + +DownloadItem +------------ + + - [QTBUG-58155] Fixed that (QWebEngine)DownloadItem::path() incorrectly + returned percentage-encoded filenames when the suggested path was based + on a URL. Percentage-decoding the path is generally not only incorrect + when the path is not based on URL, but also dangerous as it can lead to + downloads that escape the download folder. + - [QTBUG-56839] Added a downloadInterruptReason property for interrupted + downloads to download items. + + +Qt WebEngine +------------ + + - [QTBUG-51034] Added profile-wide user scripts like the widgets API has. + + +Qt WebEngineWidgets +------------------- + + - [QTBUG-53314, QTBUG-53372] Added the QWebEngineHttpRequest class for + sending HTTP requests over the network using HTTP POST or with custom + HTTP headers. + - [QTBUG-58381] Fixed active tab bug (5.8 regression). + - [QTBUG-58515] Fixed issue with QWebEngineView::setFocus(). + - [QTBUG-58563] Fixed segfault when closing tab with active search. + - [QTBUG-58673] QWebEnginePage: Started calling the javaScriptConfirm + method also for unload dialogs (onbeforeunload handlers). + - [QTBUG-59599] Fixed QWebEngineHistory::currentItem() segfault. + - [QTBUG-60236] Fixed crash on exit with url-request interceptors. diff --git a/examples/webengine/quicknanobrowser/ApplicationRoot.qml b/examples/webengine/quicknanobrowser/ApplicationRoot.qml index 6735be932..78defab80 100644 --- a/examples/webengine/quicknanobrowser/ApplicationRoot.qml +++ b/examples/webengine/quicknanobrowser/ApplicationRoot.qml @@ -70,18 +70,18 @@ QtObject { onClosing: destroy() } function createWindow(profile) { - var newWindow = browserWindowComponent.createObject(root) - newWindow.currentWebView.profile = profile - profile.downloadRequested.connect(newWindow.onDownloadRequested) - return newWindow + var newWindow = browserWindowComponent.createObject(root); + newWindow.currentWebView.profile = profile; + profile.downloadRequested.connect(newWindow.onDownloadRequested); + return newWindow; } function createDialog(profile) { - var newDialog = browserDialogComponent.createObject(root) - newDialog.currentWebView.profile = profile - return newDialog + var newDialog = browserDialogComponent.createObject(root); + newDialog.currentWebView.profile = profile; + return newDialog; } function load(url) { - var browserWindow = createWindow(defaultProfile) - browserWindow.currentWebView.url = url + var browserWindow = createWindow(defaultProfile); + browserWindow.currentWebView.url = url; } } diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml index c008425d9..16efc9e37 100644 --- a/examples/webengine/quicknanobrowser/BrowserWindow.qml +++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml @@ -48,15 +48,16 @@ ** ****************************************************************************/ +import Qt.labs.settings 1.0 +import QtQml 2.2 import QtQuick 2.2 -import QtWebEngine 1.2 import QtQuick.Controls 1.0 +import QtQuick.Controls.Private 1.0 as QQCPrivate import QtQuick.Controls.Styles 1.0 +import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.0 import QtQuick.Window 2.1 -import QtQuick.Controls.Private 1.0 -import QtQuick.Dialogs 1.2 -import Qt.labs.settings 1.0 +import QtWebEngine 1.3 ApplicationWindow { id: browserWindow @@ -74,24 +75,24 @@ ApplicationWindow { // Create a styleItem to determine the platform. // When using style "mac", ToolButtons are not supposed to accept focus. - StyleItem { id: styleItem } + QQCPrivate.StyleItem { id: styleItem } property bool platformIsMac: styleItem.style == "mac" Settings { id : appSettings - property alias autoLoadImages: loadImages.checked; - property alias javaScriptEnabled: javaScriptEnabled.checked; - property alias errorPageEnabled: errorPageEnabled.checked; - property alias pluginsEnabled: pluginsEnabled.checked; - property alias fullScreenSupportEnabled: fullScreenSupportEnabled.checked; - property alias autoLoadIconsForPage: autoLoadIconsForPage.checked; - property alias touchIconsEnabled: touchIconsEnabled.checked; + property alias autoLoadImages: loadImages.checked + property alias javaScriptEnabled: javaScriptEnabled.checked + property alias errorPageEnabled: errorPageEnabled.checked + property alias pluginsEnabled: pluginsEnabled.checked + property alias fullScreenSupportEnabled: fullScreenSupportEnabled.checked + property alias autoLoadIconsForPage: autoLoadIconsForPage.checked + property alias touchIconsEnabled: touchIconsEnabled.checked } Action { shortcut: "Ctrl+D" onTriggered: { - downloadView.visible = !downloadView.visible + downloadView.visible = !downloadView.visible; } } Action { @@ -106,14 +107,14 @@ ApplicationWindow { shortcut: StandardKey.Refresh onTriggered: { if (currentWebView) - currentWebView.reload() + currentWebView.reload(); } } Action { shortcut: StandardKey.AddTab onTriggered: { - tabs.createEmptyTab(currentWebView.profile) - tabs.currentIndex = tabs.count - 1 + tabs.createEmptyTab(currentWebView.profile); + tabs.currentIndex = tabs.count - 1; addressBar.forceActiveFocus(); addressBar.selectAll(); } @@ -128,23 +129,23 @@ ApplicationWindow { shortcut: "Escape" onTriggered: { if (currentWebView.state == "FullScreen") { - browserWindow.visibility = browserWindow.previousVisibility - fullScreenNotification.hide() + browserWindow.visibility = browserWindow.previousVisibility; + fullScreenNotification.hide(); currentWebView.triggerWebAction(WebEngineView.ExitFullScreen); } } } Action { shortcut: "Ctrl+0" - onTriggered: currentWebView.zoomFactor = 1.0; + onTriggered: currentWebView.zoomFactor = 1.0 } Action { shortcut: StandardKey.ZoomOut - onTriggered: currentWebView.zoomFactor -= 0.1; + onTriggered: currentWebView.zoomFactor -= 0.1 } Action { shortcut: StandardKey.ZoomIn - onTriggered: currentWebView.zoomFactor += 0.1; + onTriggered: currentWebView.zoomFactor += 0.1 } Action { @@ -187,7 +188,7 @@ ApplicationWindow { toolBar: ToolBar { id: navigationBar RowLayout { - anchors.fill: parent; + anchors.fill: parent ToolButton { enabled: currentWebView && (currentWebView.canGoBack || currentWebView.canGoForward) menu:Menu { @@ -294,7 +295,7 @@ ApplicationWindow { id: httpDiskCacheEnabled text: "HTTP Disk Cache" checkable: !currentWebView.profile.offTheRecord - checked: (currentWebView.profile.httpCacheType == WebEngineProfile.DiskHttpCache) + checked: (currentWebView.profile.httpCacheType === WebEngineProfile.DiskHttpCache) onToggled: currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache } MenuItem { @@ -336,12 +337,12 @@ ApplicationWindow { TabView { id: tabs function createEmptyTab(profile) { - var tab = addTab("", tabComponent) + var tab = addTab("", tabComponent); // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately. - tab.active = true - tab.title = Qt.binding(function() { return tab.item.title }) - tab.item.profile = profile - return tab + tab.active = true; + tab.title = Qt.binding(function() { return tab.item.title }); + tab.item.profile = profile; + return tab; } anchors.fill: parent @@ -355,10 +356,10 @@ ApplicationWindow { onLinkHovered: { if (hoveredUrl == "") - resetStatusText.start() + resetStatusText.start(); else { - resetStatusText.stop() - statusText.text = hoveredUrl + resetStatusText.stop(); + statusText.text = hoveredUrl; } } @@ -385,69 +386,69 @@ ApplicationWindow { settings.touchIconsEnabled: appSettings.touchIconsEnabled onCertificateError: { - error.defer() - sslDialog.enqueue(error) + error.defer(); + sslDialog.enqueue(error); } onNewViewRequested: { if (!request.userInitiated) - print("Warning: Blocked a popup window.") + print("Warning: Blocked a popup window."); else if (request.destination == WebEngineView.NewViewInTab) { - var tab = tabs.createEmptyTab(currentWebView.profile) - tabs.currentIndex = tabs.count - 1 - request.openIn(tab.item) + var tab = tabs.createEmptyTab(currentWebView.profile); + tabs.currentIndex = tabs.count - 1; + request.openIn(tab.item); } else if (request.destination == WebEngineView.NewViewInBackgroundTab) { - var tab = tabs.createEmptyTab(currentWebView.profile) - request.openIn(tab.item) + var backgroundTab = tabs.createEmptyTab(currentWebView.profile); + request.openIn(backgroundTab.item); } else if (request.destination == WebEngineView.NewViewInDialog) { - var dialog = applicationRoot.createDialog(currentWebView.profile) - request.openIn(dialog.currentWebView) + var dialog = applicationRoot.createDialog(currentWebView.profile); + request.openIn(dialog.currentWebView); } else { - var window = applicationRoot.createWindow(currentWebView.profile) - request.openIn(window.currentWebView) + var window = applicationRoot.createWindow(currentWebView.profile); + request.openIn(window.currentWebView); } } onFullScreenRequested: { if (request.toggleOn) { - webEngineView.state = "FullScreen" - browserWindow.previousVisibility = browserWindow.visibility - browserWindow.showFullScreen() - fullScreenNotification.show() + webEngineView.state = "FullScreen"; + browserWindow.previousVisibility = browserWindow.visibility; + browserWindow.showFullScreen(); + fullScreenNotification.show(); } else { - webEngineView.state = "" - browserWindow.visibility = browserWindow.previousVisibility - fullScreenNotification.hide() + webEngineView.state = ""; + browserWindow.visibility = browserWindow.previousVisibility; + fullScreenNotification.hide(); } - request.accept() + request.accept(); } onRenderProcessTerminated: { - var status = "" + var status = ""; switch (terminationStatus) { case WebEngineView.NormalTerminationStatus: - status = "(normal exit)" + status = "(normal exit)"; break; case WebEngineView.AbnormalTerminationStatus: - status = "(abnormal exit)" + status = "(abnormal exit)"; break; case WebEngineView.CrashedTerminationStatus: - status = "(crashed)" + status = "(crashed)"; break; case WebEngineView.KilledTerminationStatus: - status = "(killed)" + status = "(killed)"; break; } - print("Render process exited with code " + exitCode + " " + status) - reloadTimer.running = true + print("Render process exited with code " + exitCode + " " + status); + reloadTimer.running = true; } onWindowCloseRequested: { if (tabs.count == 1) - browserWindow.close() + browserWindow.close(); else - tabs.removeTab(tabs.currentIndex) + tabs.removeTab(tabs.currentIndex); } Timer { @@ -473,19 +474,19 @@ ApplicationWindow { "you may not be connected with the host you tried to connect to.\n" + "Do you wish to override the security check and continue?" onYes: { - certErrors.shift().ignoreCertificateError() - presentError() + certErrors.shift().ignoreCertificateError(); + presentError(); } onNo: reject() onRejected: reject() function reject(){ - certErrors.shift().rejectCertificate() - presentError() + certErrors.shift().rejectCertificate(); + presentError(); } function enqueue(error){ - certErrors.push(error) - presentError() + certErrors.push(error); + presentError(); } function presentError(){ visible = certErrors.length > 0 @@ -503,9 +504,9 @@ ApplicationWindow { } function onDownloadRequested(download) { - downloadView.visible = true - downloadView.append(download) - download.accept() + downloadView.visible = true; + downloadView.append(download); + download.accept(); } Rectangle { diff --git a/examples/webengine/quicknanobrowser/DownloadView.qml b/examples/webengine/quicknanobrowser/DownloadView.qml index 13be4bd78..ed28c761c 100644 --- a/examples/webengine/quicknanobrowser/DownloadView.qml +++ b/examples/webengine/quicknanobrowser/DownloadView.qml @@ -64,8 +64,8 @@ Rectangle { } function append(download) { - downloadModel.append(download) - downloadModel.downloads.push(download) + downloadModel.append(download); + downloadModel.downloads.push(download); } Component { @@ -113,14 +113,14 @@ Rectangle { anchors.right: parent.right iconSource: "icons/process-stop.png" onClicked: { - var download = downloadModel.downloads[index] + var download = downloadModel.downloads[index]; - download.cancel() + download.cancel(); downloadModel.downloads = downloadModel.downloads.filter(function (el) { return el.id !== download.id; }); - downloadModel.remove(index) + downloadModel.remove(index); } } } @@ -167,7 +167,7 @@ Rectangle { text: "OK" anchors.centerIn: parent onClicked: { - downloadView.visible = false + downloadView.visible = false; } } } diff --git a/examples/webengine/quicknanobrowser/FullScreenNotification.qml b/examples/webengine/quicknanobrowser/FullScreenNotification.qml index 80a63d479..f0487e868 100644 --- a/examples/webengine/quicknanobrowser/FullScreenNotification.qml +++ b/examples/webengine/quicknanobrowser/FullScreenNotification.qml @@ -51,14 +51,14 @@ Rectangle { opacity: 0 function show() { - visible = true - opacity = 1 - reset.start() + visible = true; + opacity = 1; + reset.start(); } function hide() { - reset.stop() - opacity = 0 + reset.stop(); + opacity = 0; } Behavior on opacity { @@ -66,7 +66,7 @@ Rectangle { duration: 750 onStopped: { if (opacity == 0) - visible = false + visible = false; } } } diff --git a/examples/webenginewidgets/html2pdf/doc/images/html2pdf-example.png b/examples/webenginewidgets/html2pdf/doc/images/html2pdf-example.png Binary files differnew file mode 100644 index 000000000..e8055f798 --- /dev/null +++ b/examples/webenginewidgets/html2pdf/doc/images/html2pdf-example.png diff --git a/examples/webenginewidgets/html2pdf/doc/src/html2pdf.qdoc b/examples/webenginewidgets/html2pdf/doc/src/html2pdf.qdoc new file mode 100644 index 000000000..97301977f --- /dev/null +++ b/examples/webenginewidgets/html2pdf/doc/src/html2pdf.qdoc @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example webenginewidgets/html2pdf + \title WebEngine Widgets Html2Pdf Example + \ingroup webengine-widgetexamples + \brief Converts web pages to PDF documents using Qt WebEngine + + \image html2pdf-example.png + + \e {Html2Pdf} demonstrates how to use Qt WebEngine to implement a + command-line application for converting web pages into PDF documents. + + \include examples-run.qdocinc + + \section1 The Conversion Process + + In order to convert a web page into a PDF document we need to: + + \list 1 + \li Create a \l QWebEnginePage. + \li Tell the \l QWebEnginePage to begin loading the target URL and wait for it to finish. + \li Tell the \l QWebEnginePage to begin converting the loaded page into a PDF file and again wait for it to finish. + \li Once the conversion is finished, exit the program. + \endlist + + This process is encapsulated in the \e {Html2PdfConverter} class: + + \quotefromfile webenginewidgets/html2pdf/html2pdf.cpp + \skipto #include + \printuntil Html2PdfConverter + \printuntil /^\};/ + + In the constructor we create the \l QWebEnginePage and connect to its \l + QWebEnginePage::loadFinished and \l QWebEnginePage::pdfPrintingFinished + signals: + + \skipto Html2PdfConverter::Html2PdfConverter + \printuntil /^\}/ + + The \c run() method will trigger the conversion process by asking \l + QWebEnginePage to start loading the target URL. We then enter the main event + loop: + + \skipto Html2PdfConverter::run + \printuntil /^\}/ + + After the loading is finished we begin PDF generation. We ask the \l + QWebEnginePage::printToPdf method to write the output directly to disk: + + \skipto Html2PdfConverter::loadFinished + \printuntil /^\}/ + + Once we receive the signal that the PDF conversion has finished, all that + remains is to report potential errors and exit the program: + + \skipto Html2PdfConverter::pdfPrintingFinished + \printuntil /^\}/ + + \section1 The Main Function + + Our \c main function is responsible for setting up a \l QApplication and + parsing command line arguments: + + \skipto int main + \printuntil /^\}/ + + Note that to use Qt WebEngine Widgets we need to create a \l QApplication + and not a \l QCoreApplication, even though this is a command line + application. +*/ diff --git a/examples/webenginewidgets/html2pdf/html2pdf.cpp b/examples/webenginewidgets/html2pdf/html2pdf.cpp new file mode 100644 index 000000000..44e692a22 --- /dev/null +++ b/examples/webenginewidgets/html2pdf/html2pdf.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 <QApplication> +#include <QCommandLineParser> +#include <QFile> +#include <QWebEnginePage> + +#include <functional> + +using namespace std; +using namespace std::placeholders; + +class Html2PdfConverter : public QObject +{ + Q_OBJECT +public: + explicit Html2PdfConverter(QString inputPath, QString outputPath); + int run(); + +private slots: + void loadFinished(bool ok); + void pdfPrintingFinished(const QString &filePath, bool success); + +private: + QString m_inputPath; + QString m_outputPath; + QScopedPointer<QWebEnginePage> m_page; +}; + +Html2PdfConverter::Html2PdfConverter(QString inputPath, QString outputPath) + : m_inputPath(move(inputPath)) + , m_outputPath(move(outputPath)) + , m_page(new QWebEnginePage) +{ + connect(m_page.data(), &QWebEnginePage::loadFinished, + this, &Html2PdfConverter::loadFinished); + connect(m_page.data(), &QWebEnginePage::pdfPrintingFinished, + this, &Html2PdfConverter::pdfPrintingFinished); +} + +int Html2PdfConverter::run() +{ + m_page->load(QUrl::fromUserInput(m_inputPath)); + return QApplication::exec(); +} + +void Html2PdfConverter::loadFinished(bool ok) +{ + if (!ok) { + QTextStream(stderr) + << tr("failed to load URL '%1'").arg(m_inputPath) << "\n"; + QCoreApplication::exit(1); + return; + } + + m_page->printToPdf(m_outputPath); +} + +void Html2PdfConverter::pdfPrintingFinished(const QString &filePath, bool success) +{ + if (!success) { + QTextStream(stderr) + << tr("failed to print to output file '%1'").arg(filePath) << "\n"; + QCoreApplication::exit(1); + } else { + QCoreApplication::quit(); + } +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QCoreApplication::setApplicationName("html2pdf"); + QCoreApplication::setApplicationVersion(QT_VERSION_STR); + + QCommandLineParser parser; + parser.setApplicationDescription( + QCoreApplication::translate("main", "Converts the web page INPUT into the PDF file OUTPUT.")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument( + QCoreApplication::translate("main", "INPUT"), + QCoreApplication::translate("main", "Input URL for PDF conversion.")); + parser.addPositionalArgument( + QCoreApplication::translate("main", "OUTPUT"), + QCoreApplication::translate("main", "Output file name for PDF conversion.")); + + parser.process(QCoreApplication::arguments()); + + const QStringList requiredArguments = parser.positionalArguments(); + if (requiredArguments.size() != 2) + parser.showHelp(1); + + Html2PdfConverter converter(requiredArguments.at(0), requiredArguments.at(1)); + return converter.run(); +} + +#include "html2pdf.moc" diff --git a/examples/webenginewidgets/html2pdf/html2pdf.pro b/examples/webenginewidgets/html2pdf/html2pdf.pro new file mode 100644 index 000000000..f041d23db --- /dev/null +++ b/examples/webenginewidgets/html2pdf/html2pdf.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += webenginewidgets + +SOURCES += html2pdf.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/html2pdf +INSTALLS += target diff --git a/examples/webenginewidgets/maps/doc/images/maps-example.png b/examples/webenginewidgets/maps/doc/images/maps-example.png Binary files differnew file mode 100644 index 000000000..4f699f521 --- /dev/null +++ b/examples/webenginewidgets/maps/doc/images/maps-example.png diff --git a/examples/webenginewidgets/maps/doc/src/maps.qdoc b/examples/webenginewidgets/maps/doc/src/maps.qdoc new file mode 100644 index 000000000..1082cd1e2 --- /dev/null +++ b/examples/webenginewidgets/maps/doc/src/maps.qdoc @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example webenginewidgets/maps + \title WebEngine Widgets Maps Example + \ingroup webengine-widgetexamples + \brief Demonstrates how to handle geolocation requests + + \image maps-example.png + + \e {Maps} demonstrates how to handle geolocation requests originating from + a \l QWebEnginePage. + + The \l {https://www.w3.org/TR/geolocation-API/}{Geolocation API} is a + JavaScript API that web applications can use to determine the user's + physical location to show on a map, for example. As Qt WebEngine relies on + \l {Qt Location} to power this API a viable location backend is needed for + the target platform. + + To avoid accidentally sending location information to third parties + geolocation requests are denied by default. This example demonstrates the + steps an application must take in order to start accepting these requests. + + \include examples-run.qdocinc + + \section1 The Code + + The example program consists of a single class, \c MainWindow, inheriting + from \l QMainWindow: + + \quotefromfile webenginewidgets/maps/mainwindow.h + \skipto #include + \printuntil /^\}/ + + In the constructor we first set up the \l QWebEngineView as the central + widget: + + \quotefromfile webenginewidgets/maps/mainwindow.cpp + \skipto MainWindow::MainWindow + \printuntil setCentralWidget + + We then proceed to connect a lambda function to the \l + QWebEnginePage::featurePermissionRequested signal: + + \skipto m_view->page() + \printuntil QWebEnginePage::Feature + + This signal is emitted whenever a web page requests to make use of a certain + feature or device, including not only location services but also audio + capture devices or mouse locking, for example. In this example we only + handle requests for location services: + + \printuntil return + + Now comes the part where we actually ask the user for permission: + + \printuntil securityOrigin + \printuntil }); + + Note that the question includes the host component of the web site's URI (\c + securityOrigin) to inform the user as to exactly which web site will be + receiving their location data. + + We use the \l QWebEnginePage::setFeaturePermission method to communicate the + user's answer back to the web page. + + Finally we ask the \l QWebEnginePage to load the web page that might want to + use location services: + + \printuntil /^\}/ + + \sa {html5-geolocation}{Qt WebEngine HTML5 Geolocation}, {Qt Location} +*/ diff --git a/examples/webenginewidgets/maps/main.cpp b/examples/webenginewidgets/maps/main.cpp new file mode 100644 index 000000000..c2d711106 --- /dev/null +++ b/examples/webenginewidgets/maps/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication app(argc, argv); + + MainWindow mainWindow; + mainWindow.show(); + + return app.exec(); +} diff --git a/examples/webenginewidgets/maps/mainwindow.cpp b/examples/webenginewidgets/maps/mainwindow.cpp new file mode 100644 index 000000000..f548e67c2 --- /dev/null +++ b/examples/webenginewidgets/maps/mainwindow.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 "mainwindow.h" + +#include <QMessageBox> + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , m_view(new QWebEngineView(this)) +{ + setCentralWidget(m_view); + + QWebEnginePage *page = m_view->page(); + + connect(page, &QWebEnginePage::featurePermissionRequested, + [this, page](const QUrl &securityOrigin, QWebEnginePage::Feature feature) { + if (feature != QWebEnginePage::Geolocation) + return; + + QMessageBox msgBox(this); + msgBox.setText(tr("%1 wants to know your location").arg(securityOrigin.host())); + msgBox.setInformativeText(tr("Do you want to send your current location to this website?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + + if (msgBox.exec() == QMessageBox::Yes) { + page->setFeaturePermission( + securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser); + } else { + page->setFeaturePermission( + securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser); + } + }); + + page->load(QUrl(QStringLiteral("https://maps.google.com"))); +} diff --git a/examples/webenginewidgets/maps/mainwindow.h b/examples/webenginewidgets/maps/mainwindow.h new file mode 100644 index 000000000..c4377caaf --- /dev/null +++ b/examples/webenginewidgets/maps/mainwindow.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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$ +** +****************************************************************************/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QWebEngineView> + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = nullptr); + +private: + QWebEngineView *m_view; +}; + +#endif // MAINWINDOW_H diff --git a/examples/webenginewidgets/maps/maps.pro b/examples/webenginewidgets/maps/maps.pro new file mode 100644 index 000000000..3fee49077 --- /dev/null +++ b/examples/webenginewidgets/maps/maps.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +QT += webenginewidgets + +HEADERS += \ + mainwindow.h + +SOURCES += main.cpp \ + mainwindow.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/maps +INSTALLS += target diff --git a/examples/webenginewidgets/markdowneditor/document.h b/examples/webenginewidgets/markdowneditor/document.h index 3c16c251d..bc6552731 100644 --- a/examples/webenginewidgets/markdowneditor/document.h +++ b/examples/webenginewidgets/markdowneditor/document.h @@ -57,7 +57,7 @@ class Document : public QObject { Q_OBJECT - Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged) + Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged FINAL) public: explicit Document(QObject *parent = nullptr) : QObject(parent) {} diff --git a/examples/webenginewidgets/markdowneditor/mainwindow.h b/examples/webenginewidgets/markdowneditor/mainwindow.h index ad0320373..817f626d8 100644 --- a/examples/webenginewidgets/markdowneditor/mainwindow.h +++ b/examples/webenginewidgets/markdowneditor/mainwindow.h @@ -67,7 +67,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); void openFile(const QString &path); diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp index 7a3e638cc..0b85e2bb0 100644 --- a/examples/webenginewidgets/simplebrowser/browserwindow.cpp +++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp @@ -107,6 +107,13 @@ BrowserWindow::BrowserWindow(QWidget *parent, Qt::WindowFlags flags) m_urlLineEdit->setFavIcon(QIcon(QStringLiteral(":defaulticon.png"))); + QAction *focusUrlLineEditAction = new QAction(this); + addAction(focusUrlLineEditAction); + focusUrlLineEditAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_L)); + connect(focusUrlLineEditAction, &QAction::triggered, this, [this] () { + m_urlLineEdit->setFocus(Qt::ShortcutFocusReason); + }); + handleWebViewTitleChanged(tr("Qt Simple Browser")); m_tabWidget->createTab(); } diff --git a/examples/webenginewidgets/spellchecker/webview.cpp b/examples/webenginewidgets/spellchecker/webview.cpp index 0e52e7628..80158f7e5 100644 --- a/examples/webenginewidgets/spellchecker/webview.cpp +++ b/examples/webenginewidgets/spellchecker/webview.cpp @@ -69,7 +69,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) QMenu *menu = page()->createStandardContextMenu(); menu->addSeparator(); - QAction *spellcheckAction = new QAction(tr("Check Spelling")); + QAction *spellcheckAction = new QAction(tr("Check Spelling"), nullptr); spellcheckAction->setCheckable(true); spellcheckAction->setChecked(profile->isSpellCheckEnabled()); connect(spellcheckAction, &QAction::toggled, this, [profile](bool toogled) { diff --git a/examples/webenginewidgets/videoplayer/data/index.html b/examples/webenginewidgets/videoplayer/data/index.html new file mode 100644 index 000000000..4a1bdc33e --- /dev/null +++ b/examples/webenginewidgets/videoplayer/data/index.html @@ -0,0 +1,23 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <style type="text/css"> + #ytplayer { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + </style> + </head> + <body> + <iframe + id="ytplayer" + src="https://www.youtube.com/embed/CjyjEUFn_FI" + frameborder="0" + allowfullscreen> + </iframe> + </body> +</html> diff --git a/examples/webenginewidgets/videoplayer/data/videoplayer.qrc b/examples/webenginewidgets/videoplayer/data/videoplayer.qrc new file mode 100644 index 000000000..c3322b454 --- /dev/null +++ b/examples/webenginewidgets/videoplayer/data/videoplayer.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>index.html</file> + </qresource> +</RCC> diff --git a/examples/webenginewidgets/videoplayer/doc/images/videoplayer-example.png b/examples/webenginewidgets/videoplayer/doc/images/videoplayer-example.png Binary files differnew file mode 100644 index 000000000..9cf51d84a --- /dev/null +++ b/examples/webenginewidgets/videoplayer/doc/images/videoplayer-example.png diff --git a/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc b/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc new file mode 100644 index 000000000..599e13e6c --- /dev/null +++ b/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example webenginewidgets/videoplayer + \title WebEngine Widgets Video Player Example + \ingroup webengine-widgetexamples + \brief Displays full screen video using \l QWebEngineView + + \image videoplayer-example.png + + \e {Video Player} demonstrates how to support full screen playback of HTML5 + video using \l QWebEngineView. + + \l {https://fullscreen.spec.whatwg.org/}{The Fullscreen API} is a + cross-browser Javascript API that enables a web page to request that one of + its HTML elements be made to occupy the user's entire screen. It is + commonly used for full screen video playback via the \c <video> element, but + can in principle be used to display any HTML content in full screen mode. Qt + WebEngine supports this API, however it is disabled by default. This example + shows the steps needed to switch it on, including: + + \list + \li Enabling it in \l QWebEngineSettings. + \li Handling the \l QWebEnginePage::fullScreenRequested signal by creating + a new full screen window. + \li Displaying a notification popup to ensure that the user is aware + that something is being displayed full screen. + \endlist + + \include examples-run.qdocinc + + \section1 Overview + + Once started, the example program will create a normal (non-fullscreen) + window with a \l QWebEngineView showing an embedded YouTube video player. + You can then click on the full screen toggle button (bottom-right corner) to + enter full screen mode. This should also display a centered notification + overlay informing you that you can exit full screen mode by pressing the + escape key. + + Implementation-wise entering full screen mode entails creating a new full + screen window with a separate \l QWebEngineView instance and migrating the + \l QWebEnginePage from the normal window's \l QWebEngineView to this new \l + QWebEngineView. Exiting full screen mode reverses this migration. + + The example code is divided between three classes, \c MainWindow, \c + FullScreenWindow, and \c FullScreenNotification. The classes \c MainWindow + and \c FullScreenWindow are each responsible for managing one top-level + window, while \c FullScreenNotification is responsible for styling and + animating the notification box. A \c MainWindow is created on startup and + lives for the entire program runtime, while a new \c FullScreenWindow is + created every time full screen mode is entered. + + \section1 MainWindow Class Declaration + + A \c MainWindow is a \l QMainWindow with a \l QWebEngineView as the central + widget: + + \quotefromfile webenginewidgets/videoplayer/mainwindow.h + \skipto #include + \printuntil /^\}/ + + \section1 MainWindow Class Definition + + In the constructor we start by setting up the \l QWebEngineView as the + central widget: + + \quotefromfile webenginewidgets/videoplayer/mainwindow.cpp + \skipto MainWindow::MainWindow + \printuntil setCentralWidget + + We then configure Qt WebEngine to advertise support for the Fullscreen API: + + \printline QWebEngineSettings + + Without this line the full screen toggle button would be disabled (grayed + out) as the Javascript running on the page can detect that our browser + does not support full screen mode. + + Next we connect the \c fullScreenRequested signal to our slot: + + \printuntil &MainWindow::fullScreenRequested + + This signal is emitted whenever the Javascript on the page wants to enter or + exit full screen mode. Without handling this signal (but still keeping the + \c FullScreenSupportEnabled attribute as \c true) the toggle button will be + enabled but clicking on it will have no effect as Javascript's full screen + request will be denied. + + Finally, we load some HTML (see + \l{webenginewidgets/videoplayer/data/index.html}{index.html} included with + the example) into our \l QWebEngineView: + + \printline load + + The second part of \c MainWindow is handling the full screen requests: + + \skipto MainWindow::fullScreenRequested + \printuntil /^\}/ + + We create a new \c FullScreenWindow when entering full screen mode, and + delete it when exiting. + + \section1 FullScreenWindow Class Declaration + + A \c FullScreenWindow is a \l QWidget containing a \l QWebEngineView and a + \c FullScreenNotification. + + \quotefromfile webenginewidgets/videoplayer/fullscreenwindow.h + \skipto #include + \printuntil /^\}/ + + \section1 FullScreenWindow Class Definition + + The constructor is responsible for hiding the normal window (while saving + its geometry) and showing the new \c FullScreenWindow instead: + + \quotefromfile webenginewidgets/videoplayer/fullscreenwindow.cpp + \skipto FullScreenWindow::FullScreenWindow + \printuntil /^\}/ + + The call to \l QWebEngineView::setPage will move the web page from the \c + MainWindow's view to \c FullScreenWindow's view. + + In the destructor we use the same method to move the page back, after which + we restore the main window's geometry and visibility: + + \skipto FullScreenWindow::~FullScreenWindow + \printuntil /^\}/ + + We override \l QWidget::resizeEvent to do manual layout, keeping the \l + QWebEngineView maximized, and the \c FullScreenNotification centered within + the window: + + \skipto FullScreenWindow::resizeEvent + \printuntil /^\}/ + + \section1 FullScreenNotification Class Declaration + + A \c FullScreenNotification is just a \l QLabel with some styling and + animation: + + \quotefromfile webenginewidgets/videoplayer/fullscreennotification.h + \skipto #include + \printuntil /^\}/ + + \section1 FullScreenWindow Class Definition + + In the constructor we configure the QLabel and set up a delayed fade-out + animation using \l {The Animation Framework}: + + \quotefromfile webenginewidgets/videoplayer/fullscreennotification.cpp + \skipto FullScreenNotification::FullScreenNotification + \printuntil /^\}/ + + The custom signal \c shown, which we use to trigger the animation, is + emitted from the \c showEvent method: + + \skipto FullScreenNotification::showEvent + \printuntil /^\}/ +*/ diff --git a/examples/webenginewidgets/videoplayer/fullscreennotification.cpp b/examples/webenginewidgets/videoplayer/fullscreennotification.cpp new file mode 100644 index 000000000..e65e2cbad --- /dev/null +++ b/examples/webenginewidgets/videoplayer/fullscreennotification.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 "fullscreennotification.h" + +#include <QGraphicsOpacityEffect> +#include <QPropertyAnimation> +#include <QSequentialAnimationGroup> + +FullScreenNotification::FullScreenNotification(QWidget *parent) + : QLabel(parent) + , m_previouslyVisible(false) +{ + setText(tr("You are now in full screen mode. Press ESC to quit!")); + setStyleSheet( + "font-size: 24px;" + "color: white;" + "background-color: black;" + "border-color: white;" + "border-width: 2px;" + "border-style: solid;" + "padding: 100px"); + setAttribute(Qt::WA_TransparentForMouseEvents); + + auto effect = new QGraphicsOpacityEffect; + effect->setOpacity(1); + setGraphicsEffect(effect); + + auto animations = new QSequentialAnimationGroup(this); + animations->addPause(3000); + auto opacityAnimation = new QPropertyAnimation(effect, "opacity", animations); + opacityAnimation->setDuration(2000); + opacityAnimation->setStartValue(1.0); + opacityAnimation->setEndValue(0.0); + opacityAnimation->setEasingCurve(QEasingCurve::OutQuad); + animations->addAnimation(opacityAnimation); + + connect(this, &FullScreenNotification::shown, + [animations](){ animations->start(); }); + + connect(animations, &QAbstractAnimation::finished, + [this](){ this->hide(); }); +} + +void FullScreenNotification::showEvent(QShowEvent *event) +{ + QLabel::showEvent(event); + if (!m_previouslyVisible && isVisible()) + emit shown(); + m_previouslyVisible = isVisible(); +} diff --git a/examples/webenginewidgets/videoplayer/fullscreennotification.h b/examples/webenginewidgets/videoplayer/fullscreennotification.h new file mode 100644 index 000000000..9f1befb9f --- /dev/null +++ b/examples/webenginewidgets/videoplayer/fullscreennotification.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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$ +** +****************************************************************************/ +#ifndef FULLSCREENNOTIFICATION_H +#define FULLSCREENNOTIFICATION_H + +#include <QLabel> + +class FullScreenNotification : public QLabel +{ + Q_OBJECT +public: + FullScreenNotification(QWidget *parent = nullptr); + +protected: + void showEvent(QShowEvent *event) override; + +signals: + void shown(); + +private: + bool m_previouslyVisible; +}; + +#endif // FULLSCREENNOTIFICATION_H diff --git a/examples/webenginewidgets/videoplayer/fullscreenwindow.cpp b/examples/webenginewidgets/videoplayer/fullscreenwindow.cpp new file mode 100644 index 000000000..df28839a2 --- /dev/null +++ b/examples/webenginewidgets/videoplayer/fullscreenwindow.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 "fullscreenwindow.h" + +#include "fullscreennotification.h" + +#include <QAction> +#include <QLabel> +#include <QWebEngineView> + +FullScreenWindow::FullScreenWindow(QWebEngineView *oldView, QWidget *parent) + : QWidget(parent) + , m_view(new QWebEngineView(this)) + , m_notification(new FullScreenNotification(this)) + , m_oldView(oldView) + , m_oldGeometry(oldView->window()->geometry()) +{ + m_view->stackUnder(m_notification); + + auto exitAction = new QAction(this); + exitAction->setShortcut(Qt::Key_Escape); + connect(exitAction, &QAction::triggered, [this]() { + m_view->triggerPageAction(QWebEnginePage::ExitFullScreen); + }); + addAction(exitAction); + + m_view->setPage(m_oldView->page()); + setGeometry(m_oldGeometry); + showFullScreen(); + m_oldView->window()->hide(); +} + +FullScreenWindow::~FullScreenWindow() +{ + m_oldView->setPage(m_view->page()); + m_oldView->window()->setGeometry(m_oldGeometry); + m_oldView->window()->show(); + hide(); +} + +void FullScreenWindow::resizeEvent(QResizeEvent *event) +{ + QRect viewGeometry(QPoint(0, 0), size()); + m_view->setGeometry(viewGeometry); + + QRect notificationGeometry(QPoint(0, 0), m_notification->sizeHint()); + notificationGeometry.moveCenter(viewGeometry.center()); + m_notification->setGeometry(notificationGeometry); + + QWidget::resizeEvent(event); +} diff --git a/examples/webenginewidgets/videoplayer/fullscreenwindow.h b/examples/webenginewidgets/videoplayer/fullscreenwindow.h new file mode 100644 index 000000000..dda0a9885 --- /dev/null +++ b/examples/webenginewidgets/videoplayer/fullscreenwindow.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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$ +** +****************************************************************************/ +#ifndef FULLSCREENWINDOW_H +#define FULLSCREENWINDOW_H + +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QWebEngineView; +QT_END_NAMESPACE + +class FullScreenNotification; + +class FullScreenWindow : public QWidget +{ + Q_OBJECT +public: + explicit FullScreenWindow(QWebEngineView *oldView, QWidget *parent = nullptr); + ~FullScreenWindow(); + +protected: + void resizeEvent(QResizeEvent *event) override; + +private: + QWebEngineView *m_view; + FullScreenNotification *m_notification; + QWebEngineView *m_oldView; + QRect m_oldGeometry; +}; + +#endif // FULLSCREENWINDOW_H diff --git a/examples/webenginewidgets/videoplayer/main.cpp b/examples/webenginewidgets/videoplayer/main.cpp new file mode 100644 index 000000000..fcddd988e --- /dev/null +++ b/examples/webenginewidgets/videoplayer/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication app(argc, argv); + + MainWindow mainWindow; + mainWindow.show(); + + return app.exec(); +} diff --git a/examples/webenginewidgets/videoplayer/mainwindow.cpp b/examples/webenginewidgets/videoplayer/mainwindow.cpp new file mode 100644 index 000000000..55885e0c5 --- /dev/null +++ b/examples/webenginewidgets/videoplayer/mainwindow.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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 "mainwindow.h" + +#include <QWebEngineView> +#include <QWebEngineSettings> +#include <QWebEngineFullScreenRequest> + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , m_view(new QWebEngineView(this)) +{ + setCentralWidget(m_view); + m_view->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); + connect(m_view->page(), + &QWebEnginePage::fullScreenRequested, + this, + &MainWindow::fullScreenRequested); + m_view->load(QUrl(QStringLiteral("qrc:/index.html"))); +} + +void MainWindow::fullScreenRequested(QWebEngineFullScreenRequest request) +{ + if (request.toggleOn()) { + if (m_fullScreenWindow) + return; + request.accept(); + m_fullScreenWindow.reset(new FullScreenWindow(m_view)); + } else { + if (!m_fullScreenWindow) + return; + request.accept(); + m_fullScreenWindow.reset(); + } +} diff --git a/examples/webenginewidgets/videoplayer/mainwindow.h b/examples/webenginewidgets/videoplayer/mainwindow.h new file mode 100644 index 000000000..a270c6295 --- /dev/null +++ b/examples/webenginewidgets/videoplayer/mainwindow.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** 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$ +** +****************************************************************************/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "fullscreenwindow.h" + +#include <QMainWindow> +#include <QWebEngineView> +#include <QWebEngineFullScreenRequest> + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + +private slots: + void fullScreenRequested(QWebEngineFullScreenRequest request); + +private: + QWebEngineView *m_view; + QScopedPointer<FullScreenWindow> m_fullScreenWindow; +}; + +#endif // MAINWINDOW_H diff --git a/examples/webenginewidgets/videoplayer/videoplayer.pro b/examples/webenginewidgets/videoplayer/videoplayer.pro new file mode 100644 index 000000000..ab55992e0 --- /dev/null +++ b/examples/webenginewidgets/videoplayer/videoplayer.pro @@ -0,0 +1,19 @@ +TEMPLATE = app + +QT += webenginewidgets + +HEADERS += \ + mainwindow.h \ + fullscreenwindow.h \ + fullscreennotification.h + +SOURCES += main.cpp \ + mainwindow.cpp \ + fullscreenwindow.cpp \ + fullscreennotification.cpp + +RESOURCES += \ + data/videoplayer.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/videoplayer +INSTALLS += target diff --git a/examples/webenginewidgets/webenginewidgets.pro b/examples/webenginewidgets/webenginewidgets.pro index 4e4ca868b..217c4f016 100644 --- a/examples/webenginewidgets/webenginewidgets.pro +++ b/examples/webenginewidgets/webenginewidgets.pro @@ -5,9 +5,13 @@ SUBDIRS += \ contentmanipulation \ cookiebrowser \ demobrowser \ + html2pdf \ markdowneditor \ simplebrowser \ - stylesheetbrowser + stylesheetbrowser \ + videoplayer + +qtHaveModule(positioning): SUBDIRS += maps contains(WEBENGINE_CONFIG, use_spellchecker):!cross_compile { !contains(WEBENGINE_CONFIG, use_native_spellchecker) { diff --git a/tools/qmake/mkspecs/features/configure.prf b/mkspecs/features/configure.prf index 55a7c45a4..c1e919603 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/mkspecs/features/configure.prf @@ -11,7 +11,7 @@ defineTest(runConfigure) { # Ignore the cached config tests results in case they were not successful CONFIG += recheck #Override the config.tests path - QMAKE_CONFIG_TESTS_DIR = $$QTWEBENGINE_ROOT/tools/qmake/config.tests + QMAKE_CONFIG_TESTS_DIR = $$QTWEBENGINE_ROOT/config.tests CONFIG_TESTS = $$files($$QMAKE_CONFIG_TESTS_DIR/*.pro, true) log("Running configure tests$${EOL}") for(test, CONFIG_TESTS) { @@ -30,18 +30,27 @@ defineTest(runConfigure) { qtConfig(spellchecker): WEBENGINE_CONFIG += use_spellchecker qtConfig(webrtc): WEBENGINE_CONFIG += use_webrtc qtConfig(embedded): WEBENGINE_CONFIG += embedded_build - qtConfig(optimize_size): WEBENGINE_CONFIG += reduce_binary_size qtConfig(system-webp): WEBENGINE_CONFIG += use_system_libwebp - else: WEBENGINE_CONFIG += use_bundled_libwebp qtConfig(system-opus): WEBENGINE_CONFIG += use_system_opus - else: WEBENGINE_CONFIG += use_bundled_opus qtConfig(system-ffmpeg): WEBENGINE_CONFIG += use_system_ffmpeg - else: WEBENGINE_CONFIG += use_bundled_ffmpeg + qtConfig(system-icu): WEBENGINE_CONFIG += use_system_icu + !contains(WEBENGINE_CONFIG, use_system_libwebp): WEBENGINE_CONFIG += use_bundled_libwebp + !contains(WEBENGINE_CONFIG, use_system_opus): WEBENGINE_CONFIG += use_bundled_opus + !contains(WEBENGINE_CONFIG, use_system_ffmpeg): WEBENGINE_CONFIG += use_bundled_ffmpeg + !contains(WEBENGINE_CONFIG, use_system_icu): WEBENGINE_CONFIG += use_bundled_icu } else { - cross_compile: WEBENGINE_CONFIG += embedded_build reduce_binary_size + # Feature defaults when building with Qt 5.6 LTS: + cross_compile { + WEBENGINE_CONFIG += embedded_build reduce_binary_size + } else { + WEBENGINE_CONFIG += use_spellchecker use_webrtc use_pepper_plugins use_printing use_pdf + } } isQtMinimum(5, 9) { qtConfig(appstore-compliant): WEBENGINE_CONFIG += use_appstore_compliant_code + optimize_size: WEBENGINE_CONFIG += reduce_binary_size + } else { + qtConfig(embedded): WEBENGINE_CONFIG += reduce_binary_size } linux { @@ -110,10 +119,8 @@ defineTest(runConfigure) { WEBENGINE_CONFIG += use_bundled_snappy } - !contains(WEBENGINE_CONFIG, embedded_build) { - packagesExist(nss): WEBENGINE_CONFIG += use_nss - else: log("System NSS not found, BoringSSL will be used.$${EOL}") - } + packagesExist(nss): WEBENGINE_CONFIG += use_nss + else: log("System NSS not found, BoringSSL will be used.$${EOL}") } win32 { @@ -134,18 +141,18 @@ defineTest(runConfigure) { unix:!darwin { log("System library dependencies:$${EOL}") - use?(system_icu) { - packagesExist("icu-uc icu-i18n") { - log(" ICU ................................ Using system version$${EOL}") + !isQtMinimum(5, 8) { + use?(system_icu) { + packagesExist("\'icu-uc >= 53\', \'icu-i18n >= 53\'") { + log(" ICU ................................ Using system version$${EOL}") + } else { + log(" ICU ................................ System ICU not found$${EOL}") + skipBuild("Unmet dependencies: icu-uc, icu-i18n") + } } else { - log(" ICU ................................ System ICU not found$${EOL}") - skipBuild("Unmet dependencies: icu-uc, icu-i18n") + log(" ICU ................................ Using internal copy (Default, force system ICU with WEBENGINE_CONFIG+=use_system_icu)$${EOL}") + WEBENGINE_CONFIG += use_bundled_icu } - } else { - log(" ICU ................................ Using internal copy (Default, force system ICU with WEBENGINE_CONFIG+=use_system_icu)$${EOL}") - WEBENGINE_CONFIG += use_bundled_icu - } - !isQtMinimum(5, 8) { use?(system_ffmpeg) { packagesExist("libavcodec libavformat libavutil") { packagesExist("libwebp, libwebpdemux, opus, \'vpx >= 1.4\'"){ @@ -180,7 +187,7 @@ defineTest(runConfigure) { use?(proprietary_codecs) { log(" Proprietary codecs (H264, MP3) ..... Enabled$${EOL}") } else { - log(" Proprietary codecs (H264, MP3) ..... Not enabled (Default, enable with WEBENGINE_CONFIG+=use_proprietary_codecs)$${EOL}") + log(" Proprietary codecs (H264, MP3) ..... Not enabled (Default, enable with -proprietary-codecs)$${EOL}") } qtHaveModule(positioning): { log(" Geolocation ........................ Enabled$${EOL}") @@ -195,11 +202,6 @@ defineTest(runConfigure) { } } osx { - use?(appstore_compliant_code) { - log(" Mac App Store Compliant ............ Enabled$${EOL}") - } else { - log(" Mac App Store Compliant ............ Not enabled (Default, enable with WEBENGINE_CONFIG+=use_appstore_compliant_code)$${EOL}") - } use?(native_spellchecker) { log("Native Spellchecker .............. Enabled$${EOL}") } else { diff --git a/tools/qmake/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index c7440fa7a..c7440fa7a 100644 --- a/tools/qmake/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf diff --git a/tools/qmake/mkspecs/features/functions.prf b/mkspecs/features/functions.prf index eb421f8b5..8dd21f410 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/mkspecs/features/functions.prf @@ -13,18 +13,6 @@ defineTest(isQtMinimum) { } } -defineTest(isMinMSVCVersion) { - actual = $$split(MSVC_VER, .) - actual_major = $$member(actual, 0) - actual_minor = $$member(actual, 1) - requested_major = $$1 - requested_minor = $$2 - lessThan(actual_major, $$requested_major): return(false) - greaterThan(actual_major, $$requested_major): return(true) - lessThan(actual_minor, $$requested_minor): return(false) - return(true) -} - defineTest(isPlatformSupported) { QT_FOR_CONFIG += gui-private linux { @@ -38,15 +26,6 @@ defineTest(isPlatformSupported) { skipBuild("WinRT is not supported.") return(false) } - msvc { - !isMinMSVCVersion(14, 0) { - skipBuild("Qt WebEngine on Windows requires MSVC 2015 Update 2 or later.") - return(false) - } - } else { - skipBuild("Qt WebEngine on Windows requires MSVC 2015 Update 2 or later.") - return(false) - } isBuildingOnWin32() { skipBuild("Qt WebEngine on Windows must be built on a 64-bit machine.") } diff --git a/tools/qmake/mkspecs/features/gn_generator.prf b/mkspecs/features/gn_generator.prf index 91c045cfa..1f730acd0 100644 --- a/tools/qmake/mkspecs/features/gn_generator.prf +++ b/mkspecs/features/gn_generator.prf @@ -242,3 +242,5 @@ TEMPLATE = aux SOURCES = HEADERS = RESOURCES = + +QMAKE_DISTCLEAN += $$GN_FILE diff --git a/qtwebengine.pro b/qtwebengine.pro index b6e735876..5ae80ea8c 100644 --- a/qtwebengine.pro +++ b/qtwebengine.pro @@ -13,12 +13,14 @@ isPlatformSupported() { log(QtWebEngine will not be built.$${EOL}) } +QMAKE_DISTCLEAN += .qmake.cache + OTHER_FILES = \ tools/buildscripts/* \ tools/scripts/* \ - tools/qmake/config.tests/khr/* \ - tools/qmake/config.tests/libcap/* \ - tools/qmake/config.tests/libvpx/* \ - tools/qmake/config.tests/snappy/* \ - tools/qmake/config.tests/srtp/* \ - tools/qmake/mkspecs/features/* + config.tests/khr/* \ + config.tests/libcap/* \ + config.tests/libvpx/* \ + config.tests/snappy/* \ + config.tests/srtp/* \ + mkspecs/features/* diff --git a/src/3rdparty b/src/3rdparty -Subproject 898afbbf79637101bbd5e6ab12695ced6a759ae +Subproject aa2fdd6be3d465280d2a0c3aacdc738bb4ffec0 diff --git a/src/buildtools/configure_target.pro b/src/buildtools/configure_target.pro index 6ec914dd5..31aa283f6 100644 --- a/src/buildtools/configure_target.pro +++ b/src/buildtools/configure_target.pro @@ -29,3 +29,5 @@ GN_FILE = $$OUT_PWD/../toolchain/BUILD.gn !build_pass { write_file($$GN_FILE, GN_CONTENTS, append) } + +QMAKE_DISTCLEAN += $$GN_FILE diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index cda01db40..22c165e2a 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -50,6 +50,10 @@ SOURCES = \ qwebengineurlrequestjob.cpp \ qwebengineurlschemehandler.cpp +unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static { + SOURCES += qtbug-60565.cpp +} + msvc { # Create a list of object files that can be used as response file for the linker. # This is done to simulate -whole-archive on MSVC. diff --git a/src/core/api/qtbug-60565.cpp b/src/core/api/qtbug-60565.cpp new file mode 100644 index 000000000..21b545cca --- /dev/null +++ b/src/core/api/qtbug-60565.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 <new> +#include <unistd.h> + +#if defined(__LP64__) +# define SIZE_T_MANGLING "m" +#else +# define SIZE_T_MANGLING "j" +#endif + +#define SHIM_ALIAS_SYMBOL(fn) __attribute__((weak, alias(#fn))) + +extern "C" { + +__asm__(".symver __ShimCppNew, _Znw" SIZE_T_MANGLING "@Qt_5"); +void* __ShimCppNew(size_t size) + SHIM_ALIAS_SYMBOL(ShimCppNew); + +__asm__(".symver __ShimCppDelete, _ZdlPv@Qt_5"); +void __ShimCppDelete(void* address) + SHIM_ALIAS_SYMBOL(ShimCppDelete); + +__asm__(".symver __ShimCppNewArray, _Zna" SIZE_T_MANGLING "@Qt_5"); +void* __ShimCppNewArray(size_t size) + SHIM_ALIAS_SYMBOL(ShimCppNewArray); + +__asm__(".symver __ShimCppDeleteArray, _ZdaPv@Qt_5"); +void __ShimCppDeleteArray(void* address) + SHIM_ALIAS_SYMBOL(ShimCppDeleteArray); + +__asm__(".symver __ShimCppNewNoThrow, _Znw" SIZE_T_MANGLING "RKSt9nothrow_t@Qt_5"); +void __ShimCppNewNoThrow(size_t size, const std::nothrow_t&) noexcept + SHIM_ALIAS_SYMBOL(ShimCppNew); + +__asm__(".symver __ShimCppNewArrayNoThrow, _Zna" SIZE_T_MANGLING "RKSt9nothrow_t@Qt_5"); +void __ShimCppNewArrayNoThrow(size_t size, const std::nothrow_t&) noexcept + SHIM_ALIAS_SYMBOL(ShimCppNewArray); + +__asm__(".symver __ShimCppDeleteNoThrow, _ZdlPvRKSt9nothrow_t@Qt_5"); +void __ShimCppDeleteNoThrow(void* address, const std::nothrow_t&) noexcept + SHIM_ALIAS_SYMBOL(ShimCppDelete); + +__asm__(".symver __ShimCppDeleteArrayNoThrow, _ZdaPvRKSt9nothrow_t@Qt_5"); +void __ShimCppDeleteArrayNoThrow(void* address, const std::nothrow_t&) noexcept + SHIM_ALIAS_SYMBOL(ShimCppDeleteArray); + +static void* __shimCppNew(size_t size); +static void* __shimCppNewArray(size_t size); +static void __shimCppDelete(void *address); +static void __shimCppDeleteArray(void *address); + +static void* ShimCppNew(size_t size) { + return __shimCppNew(size); +} + +static void* ShimCppNewArray(size_t size) { + return __shimCppNewArray(size); +} + +static void ShimCppDelete(void* address) { + __shimCppDelete(address); +} + +static void ShimCppDeleteArray(void* address) { + __shimCppDeleteArray(address); +} +} // extern "C" + +static void* __shimCppNew(size_t size) { + return operator new(size); +} + +static void* __shimCppNewArray(size_t size) { + return operator new[](size); +} + +static void __shimCppDelete(void* address) { + operator delete(address); +} + +static void __shimCppDeleteArray(void* address) { + operator delete[](address); +} diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp index 1da186584..bec76ad81 100644 --- a/src/core/browser_context_adapter.cpp +++ b/src/core/browser_context_adapter.cpp @@ -162,6 +162,8 @@ QWebEngineUrlRequestInterceptor *BrowserContextAdapter::requestInterceptor() void BrowserContextAdapter::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) { + if (m_requestInterceptor == interceptor) + return; m_requestInterceptor = interceptor; if (m_browserContext->url_request_getter_.get()) m_browserContext->url_request_getter_->updateRequestInterceptor(); diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index cdd1ce7b6..ddb397565 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -38,5 +38,3 @@ use?(spellchecker) { } else { macos: gn_args += use_browser_spellchecker=false } - -use?(appstore_compliant_code): gn_args += appstore_compliant_code=true diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index b10a02fbd..e58fa93d7 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -161,7 +161,14 @@ void AddPepperFlashFromSystem(std::vector<content::PepperPluginInfo>* plugins) pluginPaths << ppapiPluginsPath() + QStringLiteral("/pepflashplayer.dll"); #endif #if defined(Q_OS_OSX) - pluginPaths << "/Library/Internet Plug-Ins/PepperFlashPlayer/PepperFlashPlayer.plugin"; // Mac OS X + pluginPaths << "/Library/Internet Plug-Ins/PepperFlashPlayer/PepperFlashPlayer.plugin"; // System path + QDir potentialDir(QDir::homePath() + "/Library/Application Support/Google/Chrome/PepperFlash"); + if (potentialDir.exists()) { + QFileInfoList versionDirs = potentialDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed); + for (int i = 0; i < versionDirs.size(); ++i) { + pluginPaths << versionDirs.at(i).absoluteFilePath() + "/PepperFlashPlayer.plugin"; + } + } pluginPaths << ppapiPluginsPath() + QStringLiteral("/PepperFlashPlayer.plugin"); #endif #if defined(Q_OS_LINUX) diff --git a/src/core/core.pro b/src/core/core.pro index 91c5044b6..6cc8080e0 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -41,7 +41,7 @@ core_api.depends = gn_run # A fake project for qt creator core_project.file = core_project.pro -core_project.depends = core_headers +core_project.depends = gn_run SUBDIRS += \ core_headers \ diff --git a/src/core/core_common.pri b/src/core/core_common.pri index 9c29aea71..370fe4d2a 100644 --- a/src/core/core_common.pri +++ b/src/core/core_common.pri @@ -5,8 +5,4 @@ TARGET = QtWebEngineCore QT += qml quick webchannel QT_PRIVATE += quick-private gui-private core-private webenginecoreheaders-private -# Make QtCreator happy. -CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() -INCLUDEPATH += $$CHROMIUM_SRC_DIR - qtHaveModule(positioning):QT += positioning diff --git a/src/core/core_module.pro b/src/core/core_module.pro index f4f3fb736..44e8ac613 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -130,9 +130,6 @@ icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat } OTHER_FILES = \ - $$files(../3rdparty/chromium/*.h, true) \ - $$files(../3rdparty/chromium/*.cc, true) \ - $$files(../3rdparty/chromium/*.mm, true) \ $$files(../3rdparty/chromium/*.py, true) \ $$files(../3rdparty/chromium/*.gyp, true) \ $$files(../3rdparty/chromium/*.gypi, true) \ diff --git a/src/core/core_project.pro b/src/core/core_project.pro index 8418ab22b..c046ce1ff 100644 --- a/src/core/core_project.pro +++ b/src/core/core_project.pro @@ -1,3 +1,18 @@ TEMPLATE = lib +# Fake project to make QtCreator happy. -include(core_chromium.pri) +include(core_common.pri) + +linking_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}.pri + +!include($$linking_pri) { + error("Could not find the linking information that gn should have generated.") +} + +CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() +INCLUDEPATH += $$CHROMIUM_SRC_DIR \ + $$OUT_PWD/$$getConfigDir()/gen + +SOURCES += $$NINJA_SOURCES +HEADERS += $$NINJA_HEADERS +DEFINES += $$NINJA_DEFINES diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index a4b2a4036..e49bc553f 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -209,6 +209,7 @@ protected: QVector<QSGNode*> *m_sceneGraphNodes; }; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) class DelegatedNodeTreeUpdater : public DelegatedNodeTreeHandler { public: @@ -303,6 +304,7 @@ public: private: QVector<QSGNode*>::iterator m_nodeIterator; }; +#endif class DelegatedNodeTreeCreator : public DelegatedNodeTreeHandler { @@ -872,8 +874,13 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // We first compare if the render passes from the previous frame data are structurally // equivalent to the render passes in the current frame data. If they are, we are going // to reuse the old nodes. Otherwise, we will delete the old nodes and build a new tree. +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) cc::DelegatedFrameData *previousFrameData = m_chromiumCompositorData->previousFrameData.get(); const bool buildNewTree = !areRenderPassStructuresEqual(frameData, previousFrameData) || m_sceneGraphNodes.empty(); +#else + // No updates possible with old scenegraph nodes + const bool buildNewTree = true; +#endif m_chromiumCompositorData->previousFrameData = nullptr; SGObjects previousSGObjects; @@ -887,11 +894,13 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, delete oldChain; m_sceneGraphNodes.clear(); nodeHandler.reset(new DelegatedNodeTreeCreator(&m_sceneGraphNodes, apiDelegate)); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) } else { // Save the texture strong refs so they only go out of scope when the method returns and // the new vector of texture strong refs has been filled. qSwap(m_sgObjects.textureStrongRefs, textureStrongRefs); nodeHandler.reset(new DelegatedNodeTreeUpdater(&m_sceneGraphNodes)); +#endif } // The RenderPasses list is actually a tree where a parent RenderPass is connected // to its dependencies through a RenderPassId reference in one or more RenderPassQuads. diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 6568398a8..cf22273e4 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -97,6 +97,7 @@ enum ImStateFlags { TextInputStateUpdated = 1 << 0, TextSelectionUpdated = 1 << 1, TextSelectionBoundsUpdated = 1 << 2, + TextSelectionFlags = TextSelectionUpdated | TextSelectionBoundsUpdated, AllFlags = TextInputStateUpdated | TextSelectionUpdated | TextSelectionBoundsUpdated }; @@ -237,6 +238,19 @@ private: float dpiScale; }; +bool isAccessibilityEnabled() { + // On Linux accessibility is disabled by default due to performance issues, + // and can be re-enabled by setting the QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment + // variable. For details, see QTBUG-59922. +#ifdef Q_OS_LINUX + static bool accessibility_enabled + = qEnvironmentVariableIsSet("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY"); +#else + const bool accessibility_enabled = true; +#endif + return accessibility_enabled; +} + RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget) : m_host(content::RenderWidgetHostImpl::From(widget)) , m_gestureProvider(QtGestureProviderConfig(), this) @@ -253,16 +267,18 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget , m_needsBeginFrames(false) , m_addedFrameObserver(false) , m_imState(0) - , m_anchorPositionWithinSelection(0) - , m_cursorPositionWithinSelection(0) + , m_anchorPositionWithinSelection(-1) + , m_cursorPositionWithinSelection(-1) , m_cursorPosition(0) , m_emptyPreviousSelection(true) { m_host->SetView(this); #ifndef QT_NO_ACCESSIBILITY - QAccessible::installActivationObserver(this); - if (QAccessible::isActive()) - content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); + if (isAccessibilityEnabled()) { + QAccessible::installActivationObserver(this); + if (QAccessible::isActive()) + content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); + } #endif // QT_NO_ACCESSIBILITY auto* task_runner = base::ThreadTaskRunnerHandle::Get().get(); m_beginFrameSource.reset(new cc::DelayBasedBeginFrameSource( @@ -761,8 +777,10 @@ void RenderWidgetHostViewQt::OnSelectionBoundsChanged(content::TextInputManager Q_UNUSED(updated_view); m_imState |= ImStateFlags::TextSelectionBoundsUpdated; - if (m_imState == ImStateFlags::AllFlags) + if (m_imState == ImStateFlags::AllFlags + || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { selectionChanged(); + } } void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) @@ -779,8 +797,10 @@ void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *t #endif // defined(USE_X11) m_imState |= ImStateFlags::TextSelectionUpdated; - if (m_imState == ImStateFlags::AllFlags) + if (m_imState == ImStateFlags::AllFlags + || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { selectionChanged(); + } } void RenderWidgetHostViewQt::selectionChanged() @@ -788,6 +808,22 @@ void RenderWidgetHostViewQt::selectionChanged() // Reset input manager state m_imState = 0; + // Handle text selection out of an input field + if (getTextInputType() == ui::TEXT_INPUT_TYPE_NONE) { + if (GetSelectedText().empty() && m_emptyPreviousSelection) + return; + + // Reset position values to emit selectionChanged signal when clearing text selection + // by clicking into an input field. These values are intended to be used by inputMethodQuery + // so they are not expected to be valid when selection is out of an input field. + m_anchorPositionWithinSelection = -1; + m_cursorPositionWithinSelection = -1; + + m_emptyPreviousSelection = GetSelectedText().empty(); + m_adapterClient->selectionChanged(); + return; + } + const content::TextInputManager::TextSelection *selection = text_input_manager_->GetTextSelection(); if (!selection) return; @@ -802,8 +838,8 @@ void RenderWidgetHostViewQt::selectionChanged() return; } - uint newAnchorPositionWithinSelection = 0; - uint newCursorPositionWithinSelection = 0; + int newAnchorPositionWithinSelection = 0; + int newCursorPositionWithinSelection = 0; if (text_input_manager_->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { newAnchorPositionWithinSelection = selection->range.GetMax() - selection->offset; diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 799930830..3b679923e 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -263,8 +263,8 @@ private: gfx::SizeF m_lastContentsSize; uint m_imState; - uint m_anchorPositionWithinSelection; - uint m_cursorPositionWithinSelection; + int m_anchorPositionWithinSelection; + int m_cursorPositionWithinSelection; uint m_cursorPosition; bool m_emptyPreviousSelection; QString m_surroundingText; diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 561b3c2b0..234109f1f 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -369,7 +369,7 @@ void URLRequestContextGetterQt::generateUserAgent() Q_ASSERT(m_storage); QMutexLocker lock(&m_mutex); - m_updateUserAgent = true; + m_updateUserAgent = false; m_storage->set_http_user_agent_settings(std::unique_ptr<net::HttpUserAgentSettings>( new net::StaticHttpUserAgentSettings(m_httpAcceptLanguage.toStdString(), m_httpUserAgent.toStdString()))); diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index d67d972c8..444429c75 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -1184,7 +1184,9 @@ void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropD bool dValid = true; QMetaObject::Connection onDestroyed = QObject::connect(dragSource, &QObject::destroyed, [&dValid](){ dValid = false; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) QDrag::cancel(); +#endif }); drag->setMimeData(mimeDataFromDropData(*d->currentDropData)); diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 81f968d11..2748d2a0f 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -91,6 +91,7 @@ #ifndef QT_NO_OPENGL # include <QOpenGLContext> #endif +#include <QQuickWindow> #include <QStringList> #include <QSurfaceFormat> #include <QVector> @@ -157,6 +158,10 @@ bool usingQtQuick2DRenderer() } } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) + if (device.isEmpty()) + device = QQuickWindow::sceneGraphBackend(); +#endif if (device.isEmpty()) device = QString::fromLocal8Bit(qgetenv("QT_QUICK_BACKEND")); if (device.isEmpty()) @@ -319,6 +324,14 @@ WebEngineContext::WebEngineContext() // Enabled on OS X and Linux but currently not working. It worked in 5.7 on OS X. parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferVideoFrames); +#if defined(Q_OS_MACOS) + // Accelerated decoding currently does not work on macOS due to issues with OpenGL Rectangle + // texture support. See QTBUG-60002. + parsedCommandLine->AppendSwitch(switches::kDisableAcceleratedVideoDecode); + // Same problem with Pepper using OpenGL images. + parsedCommandLine->AppendSwitch(switches::kDisablePepper3DImageChromium); +#endif + if (useEmbeddedSwitches) { // Inspired by the Android port's default switches if (!parsedCommandLine->HasSwitch(switches::kDisableOverlayScrollbar)) diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp index 61e26c4a3..a86f868b3 100644 --- a/src/tools/qwebengine_convert_dict/main.cpp +++ b/src/tools/qwebengine_convert_dict/main.cpp @@ -107,6 +107,14 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words, return true; } +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) +QString frameworkIcuDataPath() +{ + return QLibraryInfo::location(QLibraryInfo::LibrariesPath) + + QStringLiteral("/QtWebEngineCore.framework/Resources/"); +} +#endif + int main(int argc, char *argv[]) { QTextStream out(stdout); @@ -132,6 +140,14 @@ int main(int argc, char *argv[]) icuDataDir = icuPossibleEnvDataDir; icuDataDirFound = true; } +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + // In a macOS Qt framework build, the resources are inside the QtWebEngineCore framework + // Resources directory, rather than in the Qt install location. + else if (QFileInfo::exists(frameworkIcuDataPath())) { + icuDataDir = frameworkIcuDataPath(); + icuDataDirFound = true; + } +#endif // Try to find the ICU data directory in the installed Qt location. else if (QFileInfo::exists(icuDataDir)) { icuDataDirFound = true; diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index f22ec86a4..260d8958b 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -153,6 +153,8 @@ QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(QSharedPointer<Brow QQuickWebEngineProfilePrivate::~QQuickWebEngineProfilePrivate() { + m_browserContextRef->setRequestInterceptor(nullptr); + m_browserContextRef->removeClient(this); Q_FOREACH (QQuickWebEngineDownloadItem* download, m_ongoingDownloads) { diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index dac844fdb..ab6a9c79a 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -234,7 +234,7 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu } ui()->addMenuSeparator(menu); } - if (!data.linkText().isEmpty() && data.linkUrl().isValid()) { + if (data.linkUrl().isValid()) { item = new MenuItemHandler(menu); QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::OpenLinkInThisWindow); }); ui()->addMenuItem(item, QQuickWebEngineView::tr("Follow Link")); diff --git a/src/webengine/doc/qtwebengine.qdocconf b/src/webengine/doc/qtwebengine.qdocconf index fe83b082f..ea9c6f21b 100644 --- a/src/webengine/doc/qtwebengine.qdocconf +++ b/src/webengine/doc/qtwebengine.qdocconf @@ -33,7 +33,7 @@ qhp.QtWebEngine.subprojects.examples.indexTitle = Qt WebEngine Examples qhp.QtWebEngine.subprojects.examples.selectors = doc:example qhp.QtWebEngine.subprojects.examples.sortPages = true -manifestmeta.highlighted.names += "QtWebEngine/WebEngine Markdown Editor Example" \ +manifestmeta.highlighted.names += "QtWebEngine/WebEngine Widgets Simple Browser Example" \ "QtWebEngine/WebEngine Quick Nano Browser" tagfile = ../../../doc/qtwebengine/qtwebengine.tags @@ -67,7 +67,7 @@ exampledirs += . \ ../../core/doc/snippets \ ../../webenginewidgets/doc/snippets -examples.fileextensions += *.aff *.dic +examples.fileextensions += *.aff *.dic *.html imagedirs += images diff --git a/src/webengine/doc/src/qtwebengine-deploying.qdoc b/src/webengine/doc/src/qtwebengine-deploying.qdoc index 351ef49de..8530bc075 100644 --- a/src/webengine/doc/src/qtwebengine-deploying.qdoc +++ b/src/webengine/doc/src/qtwebengine-deploying.qdoc @@ -141,11 +141,4 @@ directory specified by QLibraryInfo::location(QLibraryInfo::TranslationsPath) \endlist - - \section2 Deploying Audio and Video Codecs - - To support HTML5 video, you must additionally deploy - \c ffmpegsumo.dll (WebM codec plugin) into the \c qtwebengine directory - under the application install path or under the path that the - \c PluginsPath variable was set to in \c qt.conf. */ diff --git a/src/webengine/doc/src/qtwebengine-overview.qdoc b/src/webengine/doc/src/qtwebengine-overview.qdoc index ff35b45cf..e180b22c0 100644 --- a/src/webengine/doc/src/qtwebengine-overview.qdoc +++ b/src/webengine/doc/src/qtwebengine-overview.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -89,7 +89,7 @@ \l{https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md}{overview} that is part of the documentation in the \l {Chromium Project} upstream source tree. - This version of Qt WebEngine is based on Chromium version 53.0.2785.148, with + This version of Qt WebEngine is based on Chromium version 56.0.2924.122, with additional security fixes from newer versions. \section2 Qt WebEngine Process diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc index 06a4a53a9..2eeda6e8a 100644 --- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc @@ -114,17 +114,18 @@ \section1 Mac App Store Compatibility - By default, Qt WebEngine uses private \macos API, which might cause an application to be - rejected when submitted to the Mac App Store. To configure Qt WebEngine not to use these API - calls, Qt has to be reconfigured with the \c -appstore-compliant switch. - - However, this will cause some behavioral changes, such as: + Applications using Qt WebEngine are not compatible with the Mac App Store, because: \list - \li The \macos Kill Ring functionality will no longer work (emacs-like copy pasting). - \li Certain Chromium sandboxing cleanup is not done. - \li Text areas will be painted with a different style. - \li Text fields might be painted with a different style on Mountain Lion (\macos 10.8). + \li The Chromium part of the code uses several private API methods, which are prohibited by + the App Store. + \li Applications submitted to the App Store must be code-signed with the App Sandbox feature + enabled. The App Sandbox feature interferes with Chromium's own sandbox + initialization, which results in Chromium not being properly initialized. This also + ties in with the private API usage. Furthermore, standalone Chromium itself is not + officially tested with the App Sandbox enabled, and even if work is done to bypass + the App Store's restrictions, that would not guarantee correct behavior of the library. + \endlist \section1 macOS Airplay Support on MacBooks with Dual GPUs @@ -161,4 +162,24 @@ set to 1 or alternatively the \c{--no-sandbox} command line argument can be passed to the user application executable. + \section1 Accessibility and Performance + + Qt WebEngine enables accessibility support for web pages when the following conditions + are met: + + \list + \li Qt Core is configured and built with accessibility support enabled. + \li The QPA plugin is notified by the operating system that accessibility should be + activated. This happens for example when using a screen reader application on Windows + or VoiceOver on \macos. + \endlist + + Due to some limitations, the Linux QPA plugin almost always reports that accessibility should + be activated. On big HTML pages, this can cause a significant slowdown in rendering speed. + + Because of that, from Qt 5.9 onwards, Qt WebEngine accessibility support is disabled by default + on Linux. + It can be re-enabled by setting the \c QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment + variable to a non-empty value. + */ diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 4a47a49eb..6cc496d5b 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -50,6 +50,7 @@ #include <QQmlContext> #include <QQmlEngine> #include <QQmlProperty> +#include <QQuickWindow> #include <QCursor> #include <QList> #include <QScreen> @@ -559,7 +560,11 @@ void UIDelegatesManager::showToolTip(const QString &text) int width = QQmlProperty(m_toolTip.data(), QStringLiteral("width")).read().toInt(); QSize toolTipSize(width, height); QPoint position = m_view->cursor().pos(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) position = m_view->mapFromGlobal(calculateToolTipPosition(position, toolTipSize)).toPoint(); +#else + position = m_view->window()->mapFromGlobal(calculateToolTipPosition(position, toolTipSize)); +#endif QQmlProperty(m_toolTip.data(), QStringLiteral("x")).write(position.x()); QQmlProperty(m_toolTip.data(), QStringLiteral("y")).write(position.y()); diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp index 1950221c7..c1d9a3698 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.cpp +++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp @@ -131,10 +131,8 @@ void QWebEngineDownloadItemPrivate::update(const BrowserContextAdapterClient::Do Q_ASSERT(downloadState != QWebEngineDownloadItem::DownloadRequested); - if (toDownloadInterruptReason(info.downloadInterruptReason) != interruptReason) { + if (toDownloadInterruptReason(info.downloadInterruptReason) != interruptReason) interruptReason = toDownloadInterruptReason(info.downloadInterruptReason); - Q_EMIT q->interruptReasonChanged(); - } if (toDownloadState(info.state) != downloadState) { downloadState = toDownloadState(info.state); @@ -224,19 +222,14 @@ quint32 QWebEngineDownloadItem::id() const /*! \fn QWebEngineDownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) - This signal is emitted whenever the download's \a bytesReceived or - \a bytesTotal changes. - - \sa totalBytes(), receivedBytes() -*/ - -/*! - \fn QWebEngineDownloadItem::interruptReasonChanged() - \since 5.9 + This signal is emitted to indicate the progress of the download request. - This signal is emitted whenever the reason of the download's interruption changes. + The \a bytesReceived parameter indicates the number of bytes received, while + \a bytesTotal indicates the total number of bytes expected to be downloaded. + If the size of the file to be downloaded is not known, \c bytesTotal will be + 0. - \sa interruptReason(), QWebEngineDownloadItem::DownloadInterruptReason + \sa totalBytes(), receivedBytes() */ /*! diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h index 846194f40..a4b6c08aa 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.h +++ b/src/webenginewidgets/api/qwebenginedownloaditem.h @@ -134,7 +134,6 @@ Q_SIGNALS: void finished(); void stateChanged(QWebEngineDownloadItem::DownloadState state); void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void interruptReasonChanged(); private: Q_DISABLE_COPY(QWebEngineDownloadItem) diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 40180d9b8..03e5ac3f5 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -1656,7 +1656,7 @@ QMenu *QWebEnginePage::createStandardContextMenu() menu->addSeparator(); } - if (!contextMenuData.linkText().isEmpty() && contextMenuData.linkUrl().isValid()) { + if (contextMenuData.linkUrl().isValid()) { action = QWebEnginePage::action(OpenLinkInThisWindow); action->setText(tr("Follow Link")); menu->addAction(action); diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index abed066d3..cd4fc8b02 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -156,6 +156,10 @@ QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<BrowserContext QWebEngineProfilePrivate::~QWebEngineProfilePrivate() { + // In the case the user sets this profile as the parent of the interceptor + // it can be deleted before the browser-context still referencing it is. + m_browserContextRef->setRequestInterceptor(nullptr); + delete m_settings; m_settings = 0; m_browserContextRef->removeClient(this); diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro index 09b0dd69d..c1b2147bd 100644 --- a/tests/auto/core/core.pro +++ b/tests/auto/core/core.pro @@ -3,3 +3,6 @@ TEMPLATE = subdirs SUBDIRS += \ qwebenginecookiestore \ qwebengineurlrequestinterceptor \ + +# QTBUG-60268 +boot2qt: SUBDIRS = "" diff --git a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml index 754a9e018..7a04d5f5b 100644 --- a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml +++ b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml @@ -93,7 +93,7 @@ TestWebEngineView { compare(newViewRequest.destination, WebEngineView.NewViewInTab); verify(!newViewRequest.userInitiated); - verify(dialog.webEngineView.waitForLoadSucceeded); + verify(dialog.webEngineView.waitForLoadSucceeded()); compare(dialog.webEngineView.url, ""); newViewRequestedSpy.clear(); dialog.destroy(); @@ -109,7 +109,7 @@ TestWebEngineView { compare(newViewRequest.destination, WebEngineView.NewViewInDialog); verify(!newViewRequest.userInitiated); - verify(dialog.webEngineView.waitForLoadSucceeded); + verify(dialog.webEngineView.waitForLoadSucceeded()); newViewRequestedSpy.clear(); dialog.destroy(); @@ -128,7 +128,7 @@ TestWebEngineView { compare(newViewRequest.destination, WebEngineView.NewViewInDialog); verify(newViewRequest.userInitiated); - verify(dialog.webEngineView.waitForLoadSucceeded); + verify(dialog.webEngineView.waitForLoadSucceeded()); newViewRequestedSpy.clear(); dialog.destroy(); } diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index d220348ab..8733ccac1 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -11,3 +11,6 @@ isQMLTestSupportApiEnabled() { qmltests \ qquickwebengineviewgraphics } + +# QTBUG-60268 +boot2qt: SUBDIRS -= inspectorserver qquickwebenginedefaultsurfaceformat qquickwebengineview diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index b03418aea..bef77d3f1 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -3025,7 +3025,13 @@ void tst_QWebEnginePage::progressSignal() int previousValue = -1; for (QSignalSpy::ConstIterator it = progressSpy.begin(); it < progressSpy.end(); ++it) { int current = (*it).first().toInt(); - QVERIFY(current >= previousValue); + // verbose output for faulty condition + if (!(current >= previousValue)) { + qDebug() << "faulty progress values:"; + for (QSignalSpy::ConstIterator it2 = progressSpy.begin(); it2 < progressSpy.end(); ++it2) + qDebug() << (*it2).first().toInt(); + QVERIFY(current >= previousValue); + } previousValue = current; } diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 32a518ad8..37c7ae881 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -100,7 +100,8 @@ private Q_SLOTS: void softwareInputPanel(); void inputMethods(); - void textSelection(); + void textSelectionInInputField(); + void textSelectionOutOfInputField(); void hiddenText(); void emptyInputMethodEvent(); void imeComposition(); @@ -1584,7 +1585,7 @@ void tst_QWebEngineView::inputMethods() QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine")); } -void tst_QWebEngineView::textSelection() +void tst_QWebEngineView::textSelectionInInputField() { QWebEngineView view; view.show(); @@ -1662,6 +1663,96 @@ void tst_QWebEngineView::textSelection() QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("QtWebEngi")); } +void tst_QWebEngineView::textSelectionOutOfInputField() +{ + QWebEngineView view; + view.show(); + + QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged())); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " This is a text" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + QCOMPARE(selectionChangedSpy.count(), 0); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); + + // Simple click should not update text selection, however it updates selection bounds in Chromium + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center()); + QCOMPARE(selectionChangedSpy.count(), 0); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); + + // Workaround for macOS: press ctrl+a without key text + QKeyEvent keyPressCtrlA(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier); + QKeyEvent keyReleaseCtrlA(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier); + + // Select text by ctrl+a + QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA); + QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + QVERIFY(view.hasSelection()); + QCOMPARE(view.page()->selectedText(), QString("This is a text")); + + // Deselect text by mouse click + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center()); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 2); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); + + selectionChangedSpy.clear(); + view.setHtml("<html><body>" + " This is a text" + " <br>" + " <input type='text' id='input1' value='QtWebEngine' size='50'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + QCOMPARE(selectionChangedSpy.count(), 0); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); + + // Make sure the input field does not have the focus + evaluateJavaScriptSync(view.page(), "document.getElementById('input1').blur()"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + + // Select the whole page by ctrl+a + QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA); + QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + QVERIFY(view.hasSelection()); + QVERIFY(view.page()->selectedText().startsWith(QString("This is a text"))); + + // Remove selection by clicking into an input field + QPoint textInputCenter = elementCenter(view.page(), "input1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + QCOMPARE(selectionChangedSpy.count(), 2); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); + + // Select the content of the input field by ctrl+a + QApplication::sendEvent(view.focusProxy(), &keyPressCtrlA); + QApplication::sendEvent(view.focusProxy(), &keyReleaseCtrlA); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 3); + QVERIFY(view.hasSelection()); + QCOMPARE(view.page()->selectedText(), QString("QtWebEngine")); + + // Deselect input field's text by mouse click + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center()); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 4); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); +} + void tst_QWebEngineView::hiddenText() { QWebEngineView view; diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro index de00e5f07..90352310e 100644 --- a/tests/auto/widgets/widgets.pro +++ b/tests/auto/widgets/widgets.pro @@ -20,3 +20,8 @@ contains(WEBENGINE_CONFIG, use_spellchecker):!cross_compile { message("Spellcheck test will not be built because it depends on usage of Hunspell dictionaries.") } } + +# QTBUG-60268 +boot2qt: SUBDIRS -= qwebengineaccessibility qwebenginedefaultsurfaceformat \ + qwebenginefaviconmanager qwebenginepage qwebenginehistory \ + qwebengineprofile qwebenginescript qwebengineview |