diff --git a/configure.json b/configure.json index f9719b3c6d2631fe548a20a28da27352b9665878..e82247ec56cc3ca9248b8d414163f3e0e8bba327 100644 --- a/configure.json +++ b/configure.json @@ -8,6 +8,7 @@ "options": { "alsa": "boolean", "embedded": "boolean", + "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" } }, @@ -34,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": [ @@ -154,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", @@ -200,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 0000000000000000000000000000000000000000..00c79fb9224cb1244471bfa0c36c319351c6f379 --- /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/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml index 596e4a76ed532bfd635955d685058293011e47d0..16efc9e372be4e5911793b237a38e76aaa701b19 100644 --- a/examples/webengine/quicknanobrowser/BrowserWindow.qml +++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml @@ -52,7 +52,7 @@ import Qt.labs.settings 1.0 import QtQml 2.2 import QtQuick 2.2 import QtQuick.Controls 1.0 -import QtQuick.Controls.Private 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 @@ -75,7 +75,7 @@ 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 { diff --git a/examples/webenginewidgets/spellchecker/webview.cpp b/examples/webenginewidgets/spellchecker/webview.cpp index 0e52e7628dd6defffa2c52543f3af64b541c12bf..80158f7e524100c46f60ae6ae18d690a1385084f 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/mkspecs/features/configure.prf b/mkspecs/features/configure.prf index 9b0be0140097fd08855a465d7061238c906150e8..c1e919603b0d114733108c4ed50ecc0f4cd44977 100644 --- a/mkspecs/features/configure.prf +++ b/mkspecs/features/configure.prf @@ -31,13 +31,20 @@ defineTest(runConfigure) { qtConfig(webrtc): WEBENGINE_CONFIG += use_webrtc qtConfig(embedded): WEBENGINE_CONFIG += embedded_build 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 @@ -112,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 { @@ -136,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\'"){ @@ -182,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}") @@ -197,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/src/3rdparty b/src/3rdparty index 898afbbf79637101bbd5e6ab12695ced6a759ae7..aa2fdd6be3d465280d2a0c3aacdc738bb4ffec05 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 898afbbf79637101bbd5e6ab12695ced6a759ae7 +Subproject commit aa2fdd6be3d465280d2a0c3aacdc738bb4ffec05 diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index cda01db40d041ffe92f1b73101eac12313c64171..22c165e2a04c196b5c9fad21633114aa14d99d39 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 0000000000000000000000000000000000000000..21b545ccaf600feecbccd0f7adb7c82e7579f5e1 --- /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 1da186584ce950e81db4b8b2c94e2995bbf51422..bec76ad810381fa3eacfb5ad4d319e25af3e09b5 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 cdd1ce7b6c423d80168a169f548e360a3ff7d719..ddb397565eb0876fbc1554e6e46386efc8081b40 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/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index a4b2a4036c090c2d9ebba0b7dc4933b76e579195..e49bc553f49bc4582fe86d4e83d0300550b37107 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 6568398a8e9b847e0c2cf0c47671b8a439e2f71b..cf22273e450ca91299560501bdcabe4910641ba8 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 79993083080768af3debcb350533c1c15f3b16a3..3b679923e950f6b86ffa73dc06673ef445233b80 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/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index d67d972c839e78d5bf70f09284ec20f47c7626fe..444429c756656affa84e5bbf5d932ec96525f3a4 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 60622b4ae6fd25368202366dc59df96ca75d7a02..2748d2a0f523e04e42cc5da69ceac1ae300c37ee 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -158,8 +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()) @@ -322,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 61e26c4a38644aacced7fb34b94487d2f75e389b..a86f868b3ffda05efe934298079caaa5b66d5d3d 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 f22ec86a4e3c072e7acdc339faca4a157d50ee5d..260d8958b934f0ffb74fea8cddbe7e474486fc44 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/doc/qtwebengine.qdocconf b/src/webengine/doc/qtwebengine.qdocconf index bc63addbe56243c6234dec4afe22e099b09b231d..ea9c6f21bb10f3e542f92205c4576cfa81d091e8 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 diff --git a/src/webengine/doc/src/qtwebengine-overview.qdoc b/src/webengine/doc/src/qtwebengine-overview.qdoc index ff35b45cf0cb72e10640c4b0541ef3c3cf565f99..e180b22c01f65b270f4492453a22815d434de458 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 06a4a53a9000f4ed73318f1b00b2348d1ffdd1a4..2eeda6e8a41d3ed19af63fa6382ad8cae57002be 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 4a47a49ebf56127862342a1984d398d425c6bf29..6cc496d5b643b653b73e35508b2c16e2c76f970a 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 d578bf0e3d2d00ed5a903c337f8c56f76267cf05..c1d9a36985e55bfb2bf0e08d48518808ca07c0db 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); @@ -234,15 +232,6 @@ quint32 QWebEngineDownloadItem::id() const \sa totalBytes(), receivedBytes() */ -/*! - \fn QWebEngineDownloadItem::interruptReasonChanged() - \since 5.9 - - This signal is emitted whenever the reason of the download's interruption changes. - - \sa interruptReason(), QWebEngineDownloadItem::DownloadInterruptReason -*/ - /*! \enum QWebEngineDownloadItem::DownloadState diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h index 846194f40301b708dabe99660320fe86da254fa9..a4b6c08aa7ebe78ccefbddf638e4dcd07ffc15df 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/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index abed066d3303f15b3251798072524d03248b3444..cd4fc8b0260fbda0e1335bc13c4eda01a14a9824 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/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 32a518ad8e80da99fb122a8ff01f6e3ab7dddcc3..37c7ae881bef1a00209f6161760c9d2ff001d542 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;