diff options
67 files changed, 1178 insertions, 501 deletions
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml index 7b8767b8d..8d62482da 100644 --- a/examples/webengine/quicknanobrowser/BrowserWindow.qml +++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml @@ -367,7 +367,10 @@ ApplicationWindow { return tab; } - anchors.fill: parent + anchors.top: parent.top + anchors.bottom: devToolsView.top + anchors.left: parent.left + anchors.right: parent.right Component.onCompleted: createEmptyTab(defaultProfile) Component { @@ -500,7 +503,7 @@ ApplicationWindow { WebEngineView { id: devToolsView visible: devToolsEnabled.checked - height: 400 + height: visible ? 400 : 0 inspectedView: visible && tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null anchors.left: parent.left anchors.right: parent.right diff --git a/examples/webenginewidgets/maps/maps.pro b/examples/webenginewidgets/maps/maps.pro index b1cb3b28b..fead8fe0b 100644 --- a/examples/webenginewidgets/maps/maps.pro +++ b/examples/webenginewidgets/maps/maps.pro @@ -12,6 +12,6 @@ target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/maps INSTALLS += target !qtConfig(webengine-geolocation) { - error('Qt WebEngine compiled without geolocaton support, this example will not work.') + error('Qt WebEngine compiled without geolocation support, this example will not work.') } diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp index ab9dce4b8..e44410284 100644 --- a/examples/webenginewidgets/simplebrowser/webpage.cpp +++ b/examples/webenginewidgets/simplebrowser/webpage.cpp @@ -66,7 +66,7 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent) connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::handleFeaturePermissionRequested); connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, &WebPage::handleProxyAuthenticationRequired); connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, &WebPage::handleRegisterProtocolHandlerRequested); -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) connect(this, &QWebEnginePage::selectClientCertificate, this, &WebPage::handleSelectClientCertificate); #endif } @@ -197,7 +197,7 @@ void WebPage::handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolH } //! [registerProtocolHandlerRequested] -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void WebPage::handleSelectClientCertificate(QWebEngineClientCertificateSelection selection) { // Just select one. diff --git a/examples/webenginewidgets/simplebrowser/webpage.h b/examples/webenginewidgets/simplebrowser/webpage.h index 0b351ab31..908295894 100644 --- a/examples/webenginewidgets/simplebrowser/webpage.h +++ b/examples/webenginewidgets/simplebrowser/webpage.h @@ -69,7 +69,7 @@ private slots: void handleFeaturePermissionRequested(const QUrl &securityOrigin, Feature feature); void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost); void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request); -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void handleSelectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection); #endif }; diff --git a/mkspecs/features/functions.prf b/mkspecs/features/functions.prf index a26f1258d..c9bd65b03 100644 --- a/mkspecs/features/functions.prf +++ b/mkspecs/features/functions.prf @@ -127,3 +127,12 @@ defineReplace(pkgConfigHostExecutable) { export(QMAKE_DISTCLEAN) return($$system_quote($$system_path($$wrapper_name))) } + +defineTest(hasX11Dependencies) { + for(package, $$list("libdrm xcomposite xcursor xi xrandr xtst")) { + !qtConfig(webengine-system-$$package) { + return(false) + } + } + return(true) +} diff --git a/src/3rdparty b/src/3rdparty -Subproject 156c2b70ceef9a4464a5a241c9f816dea4fd316 +Subproject d521ec6dd1ed0114b9c6d32b047fb024420a6cd diff --git a/src/core/accessibility_tree_formatter_qt.cpp b/src/core/accessibility_tree_formatter_qt.cpp index 6d3129275..8b15c5dee 100644 --- a/src/core/accessibility_tree_formatter_qt.cpp +++ b/src/core/accessibility_tree_formatter_qt.cpp @@ -52,6 +52,7 @@ namespace content { +#ifndef QT_NO_ACCESSIBILITY class AccessibilityTreeFormatterQt : public AccessibilityTreeFormatterBrowser { public: explicit AccessibilityTreeFormatterQt(); @@ -66,12 +67,6 @@ private: base::string16 ProcessTreeForOutput(const base::DictionaryValue &node, base::DictionaryValue * = nullptr) override; }; -// static -AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create() -{ - return new AccessibilityTreeFormatterQt(); -} - AccessibilityTreeFormatterQt::AccessibilityTreeFormatterQt() { } @@ -203,4 +198,16 @@ const std::string AccessibilityTreeFormatterQt::GetDenyString() return "@QT-DENY:"; } +#endif // QT_NO_ACCESSIBILITY + +// static +AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create() +{ +#ifndef QT_NO_ACCESSIBILITY + return new AccessibilityTreeFormatterQt(); +#else + return nullptr; +#endif } + +} // namespace content diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index d3cf72477..a415ade92 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -42,6 +42,10 @@ #include <QGuiApplication> #ifndef QT_NO_OPENGL # include <QOpenGLContext> +#ifdef Q_OS_MACOS +#include <sys/types.h> +#include <sys/sysctl.h> +#endif #endif #include <QThread> @@ -52,6 +56,23 @@ Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); QT_END_NAMESPACE #endif +#ifndef QT_NO_OPENGL +#ifdef Q_OS_MACOS +static bool needsOfflineRendererWorkaround() { + size_t hwmodelsize = 0; + + if (sysctlbyname("hw.model", nullptr, &hwmodelsize, nullptr, 0) == -1) + return false; + + char hwmodel[hwmodelsize]; + if (sysctlbyname("hw.model", &hwmodel, &hwmodelsize, nullptr, 0) == -1) + return false; + + return QString::fromLatin1(hwmodel) == QLatin1String("MacPro6,1"); +} +#endif +#endif + namespace QtWebEngineCore { #ifndef QT_NO_OPENGL static QOpenGLContext *shareContext; @@ -74,7 +95,10 @@ QWEBENGINECORE_PRIVATE_EXPORT void initialize() #ifdef Q_OS_WIN32 qputenv("QT_D3DCREATE_MULTITHREADED", "1"); #endif - +#ifdef Q_OS_MACOS + if (needsOfflineRendererWorkaround()) + qputenv("QT_MAC_PRO_WEBENGINE_WORKAROUND", "1"); +#endif // No need to override the shared context if QApplication already set one (e.g with Qt::AA_ShareOpenGLContexts). if (qt_gl_global_share_context()) return; @@ -107,3 +131,4 @@ QWEBENGINECORE_PRIVATE_EXPORT void initialize() #endif // QT_NO_OPENGL } } // namespace QtWebEngineCore + diff --git a/src/core/api/qwebenginecookiestore.cpp b/src/core/api/qwebenginecookiestore.cpp index abb39f074..035c98342 100644 --- a/src/core/api/qwebenginecookiestore.cpp +++ b/src/core/api/qwebenginecookiestore.cpp @@ -195,7 +195,8 @@ bool QWebEngineCookieStorePrivate::canAccessCookies(const QUrl &firstPartyUrl, c if (!filterCallback) return true; - bool thirdParty = + // Empty first-party URL indicates a first-party request (see net/base/static_cookie_policy.cc) + bool thirdParty = !firstPartyUrl.isEmpty() && !net::registry_controlled_domains::SameDomainOrHost(toGurl(url), toGurl(firstPartyUrl), net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h index edb1f1ed7..345ee9862 100644 --- a/src/core/browser_accessibility_qt.h +++ b/src/core/browser_accessibility_qt.h @@ -41,9 +41,10 @@ #define BROWSER_ACCESSIBILITY_QT_H #include <QtGui/qaccessible.h> -#ifndef QT_NO_ACCESSIBILITY #include "content/browser/accessibility/browser_accessibility.h" +#ifndef QT_NO_ACCESSIBILITY + namespace content { class BrowserAccessibilityQt diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp new file mode 100644 index 000000000..38e048470 --- /dev/null +++ b/src/core/browser_main_parts_qt.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "browser_main_parts_qt.h" + +#include "base/message_loop/message_loop.h" +#include "base/process/process.h" +#include "base/threading/thread_restrictions.h" +#include "content/public/browser/browser_main_parts.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/service_manager_connection.h" +#include "services/resource_coordinator/public/cpp/process_resource_coordinator.h" +#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/cpp/service.h" +#include "ui/display/screen.h" + +#include "service/service_qt.h" +#include "web_engine_context.h" + +#include <QCoreApplication> +#include <QEvent> +#include <QEventLoop> +#include <QObject> +#include <QTimerEvent> + +#if defined(Q_OS_WIN) +#include "ui/display/win/screen_win.h" +#else +#include "desktop_screen_qt.h" +#endif + + +namespace QtWebEngineCore { + +namespace { + +// Return a timeout suitable for the glib loop, -1 to block forever, +// 0 to return right away, or a timeout in milliseconds from now. +int GetTimeIntervalMilliseconds(const base::TimeTicks &from) +{ + if (from.is_null()) + return -1; + + // Be careful here. TimeDelta has a precision of microseconds, but we want a + // value in milliseconds. If there are 5.5ms left, should the delay be 5 or + // 6? It should be 6 to avoid executing delayed work too early. + int delay = static_cast<int>(std::ceil((from - base::TimeTicks::Now()).InMillisecondsF())); + + // If this value is negative, then we need to run delayed work soon. + return delay < 0 ? 0 : delay; +} + +class MessagePumpForUIQt : public QObject, + public base::MessagePump +{ +public: + MessagePumpForUIQt() + : m_delegate(nullptr) + , m_explicitLoop(nullptr) + , m_timerId(0) + { + } + + void Run(Delegate *delegate) override + { + if (!m_delegate) + m_delegate = delegate; + else + Q_ASSERT(delegate == m_delegate); + // This is used only when MessagePumpForUIQt is used outside of the GUI thread. + QEventLoop loop; + m_explicitLoop = &loop; + loop.exec(); + m_explicitLoop = nullptr; + } + + void Quit() override + { + Q_ASSERT(m_explicitLoop); + m_explicitLoop->quit(); + } + + void ScheduleWork() override + { + if (!m_delegate) + m_delegate = base::MessageLoopForUI::current(); + QCoreApplication::postEvent(this, new QTimerEvent(0)); + m_timerScheduledTime = base::TimeTicks::Now(); + } + + void ScheduleDelayedWork(const base::TimeTicks &delayed_work_time) override + { + if (!m_delegate) + m_delegate = base::MessageLoopForUI::current(); + if (delayed_work_time.is_null()) { + killTimer(m_timerId); + m_timerId = 0; + m_timerScheduledTime = base::TimeTicks(); + } else if (!m_timerId || delayed_work_time < m_timerScheduledTime) { + killTimer(m_timerId); + m_timerId = startTimer(GetTimeIntervalMilliseconds(delayed_work_time)); + m_timerScheduledTime = delayed_work_time; + } + } + +protected: + void timerEvent(QTimerEvent *ev) override + { + Q_ASSERT(!ev->timerId() || m_timerId == ev->timerId()); + killTimer(m_timerId); + m_timerId = 0; + m_timerScheduledTime = base::TimeTicks(); + + handleScheduledWork(); + } + +private: + void handleScheduledWork() + { + bool more_work_is_plausible = m_delegate->DoWork(); + + base::TimeTicks delayed_work_time; + more_work_is_plausible |= m_delegate->DoDelayedWork(&delayed_work_time); + + if (more_work_is_plausible) + return ScheduleWork(); + + more_work_is_plausible |= m_delegate->DoIdleWork(); + if (more_work_is_plausible) + return ScheduleWork(); + + ScheduleDelayedWork(delayed_work_time); + } + + Delegate *m_delegate; + QEventLoop *m_explicitLoop; + int m_timerId; + base::TimeTicks m_timerScheduledTime; +}; + +} // anonymous namespace + +std::unique_ptr<base::MessagePump> messagePumpFactory() +{ + return base::WrapUnique(new MessagePumpForUIQt); +} + +BrowserMainPartsQt::BrowserMainPartsQt() : content::BrowserMainParts() +{ } + +BrowserMainPartsQt::~BrowserMainPartsQt() = default; + + +int BrowserMainPartsQt::PreEarlyInitialization() +{ + base::MessageLoop::InitMessagePumpForUIFactory(messagePumpFactory); + return 0; +} + +void BrowserMainPartsQt::PreMainMessageLoopStart() +{ +} + +void BrowserMainPartsQt::PostMainMessageLoopRun() +{ + // The BrowserContext's destructor uses the MessageLoop so it should be deleted + // right before the RenderProcessHostImpl's destructor destroys it. + WebEngineContext::current()->destroyBrowserContext(); +} + +int BrowserMainPartsQt::PreCreateThreads() +{ + base::ThreadRestrictions::SetIOAllowed(true); + // Like ChromeBrowserMainExtraPartsViews::PreCreateThreads does. +#if defined(Q_OS_WIN) + display::Screen::SetScreenInstance(new display::win::ScreenWin); +#else + display::Screen::SetScreenInstance(new DesktopScreenQt); +#endif + return 0; +} + +void BrowserMainPartsQt::ServiceManagerConnectionStarted(content::ServiceManagerConnection *connection) +{ + ServiceQt::GetInstance()->InitConnector(); + connection->GetConnector()->StartService(service_manager::Identity("qtwebengine")); + if (resource_coordinator::IsResourceCoordinatorEnabled()) { + m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector()); + m_processResourceCoordinator->SetLaunchTime(base::Time::Now()); + m_processResourceCoordinator->SetPID(base::Process::Current().Pid()); + } +} + +} // namespace QtWebEngineCore diff --git a/src/core/browser_main_parts_qt.h b/src/core/browser_main_parts_qt.h new file mode 100644 index 000000000..04ca9483d --- /dev/null +++ b/src/core/browser_main_parts_qt.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BROWSER_MAIN_PARTS_QT_H +#define BROWSER_MAIN_PARTS_QT_H + +#include "content/public/browser/browser_main_parts.h" + +namespace base { +class MessagePump; +} + +namespace content { +class ServiceManagerConnection; +} + +namespace resource_coordinator { +class ProcessResourceCoordinator; +} + +namespace QtWebEngineCore { + +std::unique_ptr<base::MessagePump> messagePumpFactory(); + +class BrowserMainPartsQt : public content::BrowserMainParts +{ +public: + BrowserMainPartsQt(); + ~BrowserMainPartsQt(); + + int PreEarlyInitialization() override; + void PreMainMessageLoopStart() override; + void PostMainMessageLoopRun() override; + int PreCreateThreads() override; + void ServiceManagerConnectionStarted(content::ServiceManagerConnection *connection) override; + +private: + DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt); + std::unique_ptr<resource_coordinator::ProcessResourceCoordinator> m_processResourceCoordinator; +}; + +} // namespace QtWebEngineCore + +#endif // BROWSER_MAIN_PARTS_QT_H diff --git a/src/core/client_cert_select_controller.cpp b/src/core/client_cert_select_controller.cpp index 1362322f7..7d08d57c1 100644 --- a/src/core/client_cert_select_controller.cpp +++ b/src/core/client_cert_select_controller.cpp @@ -71,7 +71,7 @@ ClientCertSelectController::~ClientCertSelectController() m_delegate->ContinueWithCertificate(nullptr, nullptr); } -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void ClientCertSelectController::selectNone() { @@ -118,6 +118,6 @@ QVector<QSslCertificate> ClientCertSelectController::certificates() const return out; } -#endif // QT_CONFIG(ssl) +#endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) QT_END_NAMESPACE diff --git a/src/core/client_cert_select_controller.h b/src/core/client_cert_select_controller.h index 4a245c74c..46324ee90 100644 --- a/src/core/client_cert_select_controller.h +++ b/src/core/client_cert_select_controller.h @@ -55,7 +55,7 @@ #include <QtNetwork/qtnetwork-config.h> #include <QtCore/QUrl> -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) #include <QtCore/QVector> #include <QtNetwork/QSslCertificate> #endif @@ -80,12 +80,12 @@ public: ~ClientCertSelectController(); QUrl hostAndPort() const { return m_hostAndPort; } -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void selectNone(); void select(const QSslCertificate &certificate); QVector<QSslCertificate> certificates() const; -#endif // QT_CONFIG(ssl) +#endif private: QUrl m_hostAndPort; diff --git a/src/core/config/common.pri b/src/core/config/common.pri index bb318f1f0..6b79a1f99 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -23,8 +23,7 @@ gn_args += \ !win32: gn_args += \ use_jumbo_build=true \ - jumbo_file_merge_limit=8 \ - jumbo_build_excluded="[\"browser\",\"renderer\"]" + jumbo_file_merge_limit=8 qtConfig(webengine-printing-and-pdf) { gn_args += enable_basic_printing=true enable_print_preview=true diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index 7f634472d..eb8bb7bb0 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -24,7 +24,7 @@ qtConfig(webengine-embedded-build) { !use_gold_linker: gn_args += use_gold=false } -qtConfig(webengine-system-x11) { +qtConfig(webengine-system-x11): hasX11Dependencies() { gn_args += ozone_platform_x11=true } diff --git a/src/core/configure.json b/src/core/configure.json index a72e6ca55..3aba2d55a 100644 --- a/src/core/configure.json +++ b/src/core/configure.json @@ -213,8 +213,21 @@ }, "webengine-freetype": { "label": "freetype >= 2.4.2", + "test": { + "head": [ + "#include <ft2build.h>", + "#include FT_FREETYPE_H", + "#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) < 20402)", + "# error This version of freetype is too old.", + "#endif" + ], + "main": [ + "FT_Face ft_face = 0;", + "FT_Reference_Face(ft_face);" + ] + }, "sources": [ - { "type": "pkgConfig", "args": "freetype2 >= 2.4.2" } + { "type": "pkgConfig", "args": "freetype2" } ] }, "webengine-x11" : { diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 9f1b35ec9..beec6dd26 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -41,15 +41,13 @@ #include "base/json/json_reader.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_restrictions.h" +#include "base/strings/utf_string_conversions.h" #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" #endif #include "components/network_hints/browser/network_hints_message_filter.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/common/url_schemes.h" -#include "content/public/browser/browser_main_parts.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/client_certificate_delegate.h" @@ -72,30 +70,27 @@ #include "mojo/public/cpp/bindings/binding_set.h" #include "printing/buildflags/buildflags.h" #include "net/ssl/client_cert_identity.h" -#include "services/resource_coordinator/public/cpp/process_resource_coordinator.h" -#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" +#include "services/proxy_resolver/proxy_resolver_service.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/service.h" #include "services/service_manager/sandbox/switches.h" #include "third_party/blink/public/platform/modules/insecure_input/insecure_input_service.mojom.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" -#include "ui/display/screen.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gpu_timing.h" #include "url/url_util_qt.h" -#include "service/service_qt.h" #include "qtwebengine/grit/qt_webengine_resources.h" #include "profile_adapter.h" +#include "browser_main_parts_qt.h" #include "browser_message_filter_qt.h" #include "certificate_error_controller.h" #include "certificate_error_controller_p.h" #include "client_cert_select_controller.h" -#include "desktop_screen_qt.h" #include "devtools_manager_delegate_qt.h" #include "login_delegate_qt.h" #include "media_capture_devices_dispatcher.h" @@ -107,15 +102,12 @@ #include "profile_qt.h" #include "quota_permission_context_qt.h" #include "renderer_host/user_resource_controller_host.h" +#include "service/service_qt.h" #include "type_conversion.h" #include "web_contents_delegate_qt.h" #include "web_engine_context.h" #include "web_engine_library_info.h" -#if defined(Q_OS_WIN) -#include "ui/display/win/screen_win.h" -#endif - #if defined(Q_OS_LINUX) #include "global_descriptors_qt.h" #include "ui/base/resource/resource_bundle.h" @@ -156,176 +148,6 @@ QT_END_NAMESPACE namespace QtWebEngineCore { -namespace { - -// Return a timeout suitable for the glib loop, -1 to block forever, -// 0 to return right away, or a timeout in milliseconds from now. -int GetTimeIntervalMilliseconds(const base::TimeTicks& from) { - if (from.is_null()) - return -1; - - // Be careful here. TimeDelta has a precision of microseconds, but we want a - // value in milliseconds. If there are 5.5ms left, should the delay be 5 or - // 6? It should be 6 to avoid executing delayed work too early. - int delay = static_cast<int>( - ceil((from - base::TimeTicks::Now()).InMillisecondsF())); - - // If this value is negative, then we need to run delayed work soon. - return delay < 0 ? 0 : delay; -} - -class MessagePumpForUIQt : public QObject, - public base::MessagePump -{ -public: - MessagePumpForUIQt() - : m_delegate(nullptr) - , m_explicitLoop(0) - , m_timerId(0) - { - } - - void Run(Delegate *delegate) override - { - if (!m_delegate) - m_delegate = delegate; - else - Q_ASSERT(delegate == m_delegate); - // This is used only when MessagePumpForUIQt is used outside of the GUI thread. - QEventLoop loop; - m_explicitLoop = &loop; - loop.exec(); - m_explicitLoop = 0; - } - - void Quit() override - { - Q_ASSERT(m_explicitLoop); - m_explicitLoop->quit(); - } - - void ScheduleWork() override - { - if (!m_delegate) - m_delegate = base::MessageLoopForUI::current(); - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); - } - - void ScheduleDelayedWork(const base::TimeTicks &delayed_work_time) override - { - if (!m_delegate) - m_delegate = base::MessageLoopForUI::current(); - if (delayed_work_time.is_null()) { - killTimer(m_timerId); - m_timerId = 0; - m_timerScheduledTime = base::TimeTicks(); - } else if (!m_timerId || delayed_work_time < m_timerScheduledTime) { - killTimer(m_timerId); - m_timerId = startTimer(GetTimeIntervalMilliseconds(delayed_work_time)); - m_timerScheduledTime = delayed_work_time; - } - } - -protected: - void customEvent(QEvent *ev) override - { - if (handleScheduledWork()) - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); - } - - void timerEvent(QTimerEvent *ev) override - { - Q_ASSERT(m_timerId == ev->timerId()); - killTimer(m_timerId); - m_timerId = 0; - m_timerScheduledTime = base::TimeTicks(); - - base::TimeTicks next_delayed_work_time; - m_delegate->DoDelayedWork(&next_delayed_work_time); - ScheduleDelayedWork(next_delayed_work_time); - } - -private: - bool handleScheduledWork() { - bool more_work_is_plausible = m_delegate->DoWork(); - - base::TimeTicks delayed_work_time; - more_work_is_plausible |= m_delegate->DoDelayedWork(&delayed_work_time); - - if (more_work_is_plausible) - return true; - - more_work_is_plausible |= m_delegate->DoIdleWork(); - if (!more_work_is_plausible) - ScheduleDelayedWork(delayed_work_time); - - return more_work_is_plausible; - } - - Delegate *m_delegate; - QEventLoop *m_explicitLoop; - int m_timerId; - base::TimeTicks m_timerScheduledTime; -}; - -std::unique_ptr<base::MessagePump> messagePumpFactory() -{ - return base::WrapUnique(new MessagePumpForUIQt); -} - -} // anonymous namespace - -class BrowserMainPartsQt : public content::BrowserMainParts -{ -public: - BrowserMainPartsQt() - : content::BrowserMainParts() - { } - - int PreEarlyInitialization() override - { - base::MessageLoop::InitMessagePumpForUIFactory(messagePumpFactory); - return 0; - } - - void PreMainMessageLoopStart() override - { - } - - void PostMainMessageLoopRun() override - { - // The BrowserContext's destructor uses the MessageLoop so it should be deleted - // right before the RenderProcessHostImpl's destructor destroys it. - WebEngineContext::current()->destroyBrowserContext(); - } - - int PreCreateThreads() override - { - base::ThreadRestrictions::SetIOAllowed(true); - // Like ChromeBrowserMainExtraPartsViews::PreCreateThreads does. -#if defined(Q_OS_WIN) - display::Screen::SetScreenInstance(new display::win::ScreenWin); -#else - display::Screen::SetScreenInstance(new DesktopScreenQt); -#endif - return 0; - } - void ServiceManagerConnectionStarted(content::ServiceManagerConnection *connection) override - { - ServiceQt::GetInstance()->InitConnector(); - connection->GetConnector()->StartService(service_manager::Identity("qtwebengine")); - if (resource_coordinator::IsResourceCoordinatorEnabled()) { - m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector()); - m_processResourceCoordinator->SetLaunchTime(base::Time::Now()); - m_processResourceCoordinator->SetPID(base::Process::Current().Pid()); - } - } - -private: - DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt); - std::unique_ptr<resource_coordinator::ProcessResourceCoordinator> m_processResourceCoordinator; -}; - class QtShareGLContext : public gl::GLContext { public: QtShareGLContext(QOpenGLContext *qtContext) @@ -700,6 +522,12 @@ void ContentBrowserClientQt::RegisterInProcessServices(StaticServiceMap* service services->insert(std::make_pair("qtwebengine", info)); } +void ContentBrowserClientQt::RegisterOutOfProcessServices(content::ContentBrowserClient::OutOfProcessServiceMap *services) +{ + (*services)[proxy_resolver::mojom::kProxyResolverServiceName] = + base::BindRepeating(&base::ASCIIToUTF16, "V8 Proxy Resolver"); +} + std::unique_ptr<base::Value> ContentBrowserClientQt::GetServiceManifestOverlay(base::StringPiece name) { ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance(); @@ -708,6 +536,8 @@ std::unique_ptr<base::Value> ContentBrowserClientQt::GetServiceManifestOverlay(b id = IDR_QTWEBENGINE_CONTENT_PACKAGED_SERVICES_MANIFEST_OVERLAY; else if (name == content::mojom::kRendererServiceName) id = IDR_QTWEBENGINE_CONTENT_RENDERER_MANIFEST_OVERLAY; + else if (name == content::mojom::kBrowserServiceName) + id = IDR_QTWEBENGINE_CONTENT_BROWSER_MANIFEST_OVERLAY; if (id == -1) return nullptr; diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index 4d25ddf6a..b2761b311 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -118,6 +118,7 @@ public: const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override; void RegisterInProcessServices(StaticServiceMap* services, content::ServiceManagerConnection* connection) override; + void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override; std::vector<ServiceManifestInfo> GetExtraServiceManifests() override; std::unique_ptr<base::Value> GetServiceManifestOverlay(base::StringPiece name) override; bool CanCreateWindow( diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index d9ddf3f49..2811d5545 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -186,6 +186,12 @@ content::ContentRendererClient *ContentMainDelegateQt::CreateContentRendererClie return new ContentRendererClientQt; } +content::ContentUtilityClient *ContentMainDelegateQt::CreateContentUtilityClient() +{ + m_utilityClient.reset(new ContentUtilityClientQt); + return m_utilityClient.get(); +} + // see icu_util.cc #define ICU_UTIL_DATA_FILE 0 #define ICU_UTIL_DATA_SHARED 1 diff --git a/src/core/content_main_delegate_qt.h b/src/core/content_main_delegate_qt.h index 407687c81..c06afb0fb 100644 --- a/src/core/content_main_delegate_qt.h +++ b/src/core/content_main_delegate_qt.h @@ -43,6 +43,7 @@ #include "content/public/app/content_main_delegate.h" #include "content_browser_client_qt.h" +#include "content_utility_client_qt.h" namespace QtWebEngineCore { @@ -56,11 +57,12 @@ public: content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; - + content::ContentUtilityClient* CreateContentUtilityClient() override; bool BasicStartupComplete(int* /*exit_code*/) override; private: std::unique_ptr<ContentBrowserClientQt> m_browserClient; + std::unique_ptr<ContentUtilityClientQt> m_utilityClient; }; } // namespace QtWebEngineCore diff --git a/src/core/content_utility_client_qt.cpp b/src/core/content_utility_client_qt.cpp new file mode 100644 index 000000000..9e86826fe --- /dev/null +++ b/src/core/content_utility_client_qt.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "content_utility_client_qt.h" + +#include "content/public/utility/utility_thread.h" +#include "services/proxy_resolver/proxy_resolver_service.h" + +ContentUtilityClientQt::ContentUtilityClientQt() { +} + +ContentUtilityClientQt::~ContentUtilityClientQt() = default; + + +void ContentUtilityClientQt::RegisterServices( + ContentUtilityClient::StaticServiceMap* services) { + service_manager::EmbeddedServiceInfo proxy_resolver_info; + proxy_resolver_info.task_runner = + content::ChildThread::Get()->GetIOTaskRunner(); + proxy_resolver_info.factory = + base::Bind(&proxy_resolver::ProxyResolverService::CreateService); + services->emplace(proxy_resolver::mojom::kProxyResolverServiceName, + proxy_resolver_info); +} diff --git a/src/core/content_utility_client_qt.h b/src/core/content_utility_client_qt.h new file mode 100644 index 000000000..df1eb5557 --- /dev/null +++ b/src/core/content_utility_client_qt.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTENT_UTILITY_CLIENT_QT_H +#define CONTENT_UTILITY_CLIENT_QT_H +#include "content/public/utility/content_utility_client.h" + +class MashServiceFactory; +class UtilityMessageHandler; + +class ContentUtilityClientQt : public content::ContentUtilityClient { + public: + ContentUtilityClientQt(); + ~ContentUtilityClientQt() override; + + // content::ContentUtilityClient: + void RegisterServices(StaticServiceMap* services) override; +}; + +#endif diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index c060185ba..f8f99e5fc 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -43,6 +43,7 @@ SOURCES = \ browser_accessibility_manager_qt.cpp \ browser_accessibility_qt.cpp \ browsing_data_remover_delegate_qt.cpp \ + browser_main_parts_qt.cpp \ browser_message_filter_qt.cpp \ certificate_error_controller.cpp \ chromium_gpu_helper.cpp \ @@ -59,6 +60,7 @@ SOURCES = \ content_client_qt.cpp \ content_browser_client_qt.cpp \ content_main_delegate_qt.cpp \ + content_utility_client_qt.cpp \ delegated_frame_node.cpp \ desktop_screen_qt.cpp \ devtools_frontend_qt.cpp \ @@ -130,6 +132,7 @@ HEADERS = \ browser_accessibility_manager_qt.h \ browser_accessibility_qt.h \ browsing_data_remover_delegate_qt.h \ + browser_main_parts_qt.h \ browser_message_filter_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ @@ -147,6 +150,7 @@ HEADERS = \ content_client_qt.h \ content_browser_client_qt.h \ content_main_delegate_qt.h \ + content_utility_client_qt.h \ delegated_frame_node.h \ desktop_screen_qt.h \ devtools_frontend_qt.h \ diff --git a/src/core/login_delegate_qt.cpp b/src/core/login_delegate_qt.cpp index 2dbc27cf2..9659b354a 100644 --- a/src/core/login_delegate_qt.cpp +++ b/src/core/login_delegate_qt.cpp @@ -84,6 +84,7 @@ LoginDelegateQt::~LoginDelegateQt() void LoginDelegateQt::OnRequestCancelled() { destroy(); + // TODO: this should close native dialog, since page can be navigated somewhere else } QUrl LoginDelegateQt::url() const diff --git a/src/core/net/proxy_config_service_qt.cpp b/src/core/net/proxy_config_service_qt.cpp index c5316d54e..13b969281 100644 --- a/src/core/net/proxy_config_service_qt.cpp +++ b/src/core/net/proxy_config_service_qt.cpp @@ -93,9 +93,7 @@ void ProxyConfigServiceQt::RemoveObserver(net::ProxyConfigService::Observer *obs net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxyConfig(net::ProxyConfigWithAnnotation *config) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) m_usesSystemConfiguration = QNetworkProxyFactory::usesSystemConfiguration(); -#endif if (m_usesSystemConfiguration) { // Use Chromium's base service to retrieve system settings net::ProxyConfigWithAnnotation systemConfig; @@ -149,7 +147,6 @@ void ProxyConfigServiceQt::OnLazyPoll() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // We need to update if // - setUseSystemConfiguration() was called in between // - user changed application proxy @@ -160,10 +157,6 @@ void ProxyConfigServiceQt::OnLazyPoll() if (m_baseService.get()) m_baseService->OnLazyPoll(); } -#else - if (m_qtApplicationProxy != QNetworkProxy::applicationProxy()) - Update(); -#endif } // Called when the base service changed diff --git a/src/core/ozone/gl_ozone_glx_qt.cpp b/src/core/ozone/gl_ozone_glx_qt.cpp index 9a0fea7c7..2e7a28a0e 100644 --- a/src/core/ozone/gl_ozone_glx_qt.cpp +++ b/src/core/ozone/gl_ozone_glx_qt.cpp @@ -41,7 +41,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - +#include <QGuiApplication> #include "gl_ozone_glx_qt.h" #include "gl_surface_glx_qt.h" #include "ui/gl/gl_context_glx.h" @@ -49,6 +49,13 @@ #include "ui/gl/gl_glx_api_implementation.h" #include <dlfcn.h> +#ifndef QT_NO_OPENGL +#include <QOpenGLContext> +QT_BEGIN_NAMESPACE +Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); +QT_END_NAMESPACE +#endif + namespace ui { bool GLOzoneGLXQt::InitializeGLOneOffPlatform() { @@ -72,6 +79,16 @@ bool GLOzoneGLXQt::InitializeStaticGLBindings( reinterpret_cast<gl::GLGetProcAddressProc>( base::GetFunctionPointerFromNativeLibrary(library, "glXGetProcAddress")); + +#ifndef QT_NO_OPENGL + if (!get_proc_address) { + // glx handle not loaded, fallback to qpa + if (QOpenGLContext *context = qt_gl_global_share_context()) { + get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>( + context->getProcAddress("glXGetProcAddress")); + } + } +#endif if (!get_proc_address) { LOG(ERROR) << "glxGetProcAddress not found."; base::UnloadNativeLibrary(library); diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp index ee59f3d96..4519bd8fb 100644 --- a/src/core/profile_io_data_qt.cpp +++ b/src/core/profile_io_data_qt.cpp @@ -327,10 +327,11 @@ void ProfileIODataQt::generateStorage() if (!m_dhcpPacFileFetcherFactory) m_dhcpPacFileFetcherFactory.reset(new net::DhcpPacFileFetcherFactory); + proxy_resolver::mojom::ProxyResolverFactoryPtr proxyResolver(std::move(m_proxyResolverFactoryInterface)); m_storage->set_proxy_resolution_service(network::CreateProxyResolutionServiceUsingMojoFactory( - std::move(m_proxyResolverFactory), + std::move(proxyResolver), std::unique_ptr<net::ProxyConfigService>(proxyConfigService), - net::PacFileFetcherImpl::Create(m_urlRequestContext.get()), + net::PacFileFetcherImpl::CreateWithFileUrlSupport(m_urlRequestContext.get()), m_dhcpPacFileFetcherFactory->Create(m_urlRequestContext.get()), host_resolver.get(), nullptr /* NetLog */, @@ -642,8 +643,8 @@ void ProfileIODataQt::updateStorageSettings() new ProxyConfigServiceQt( net::ProxyResolutionService::CreateSystemProxyConfigService( content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO))); - m_proxyResolverFactory = ChromeMojoProxyResolverFactory::CreateWithStrongBinding(); - + //pass interface to io thread + m_proxyResolverFactoryInterface = ChromeMojoProxyResolverFactory::CreateWithStrongBinding().PassInterface(); if (m_initialized) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&ProfileIODataQt::generateAllStorage, m_weakPtr)); diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h index 949497c71..b7706f190 100644 --- a/src/core/profile_io_data_qt.h +++ b/src/core/profile_io_data_qt.h @@ -120,7 +120,7 @@ private: scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate; content::URLRequestInterceptorScopedVector m_requestInterceptors; content::ProtocolHandlerMap m_protocolHandlers; - proxy_resolver::mojom::ProxyResolverFactoryPtr m_proxyResolverFactory; + mojo::InterfacePtrInfo<proxy_resolver::mojom::ProxyResolverFactory> m_proxyResolverFactoryInterface; net::URLRequestJobFactoryImpl *m_baseJobFactory = nullptr; QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; QPointer<ProfileAdapter> m_profileAdapter; // never dereferenced in IO thread and it is passed by qpointer diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni index ba2f6e936..14da1e6cf 100644 --- a/src/core/qtwebengine.gni +++ b/src/core/qtwebengine.gni @@ -31,6 +31,7 @@ deps = [ "//content/public/renderer", "//media:media_buildflags", "//net:net_with_v8", + "//services/proxy_resolver:lib", "//skia", "//third_party/blink/public:blink", "//third_party/mesa:mesa_headers", diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index f96bbff30..792ed1d88 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -90,9 +90,7 @@ #include <QVariant> #include <QWheelEvent> #include <QWindow> -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) #include <QtGui/private/qinputcontrol_p.h> -#endif #include <QtGui/qaccessible.h> namespace QtWebEngineCore { @@ -178,55 +176,7 @@ static inline bool compareTouchPoints(const QTouchEvent::TouchPoint &lhs, const static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) return QInputControl::isCommonTextEditShortcut(ke); -#else - if (ke->modifiers() == Qt::NoModifier - || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - return true; - } else { - switch (ke->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Tab: - return true; - default: - break; - } - } - } else if (ke->matches(QKeySequence::Copy) - || ke->matches(QKeySequence::Paste) - || ke->matches(QKeySequence::Cut) - || ke->matches(QKeySequence::Redo) - || ke->matches(QKeySequence::Undo) - || ke->matches(QKeySequence::MoveToNextWord) - || ke->matches(QKeySequence::MoveToPreviousWord) - || ke->matches(QKeySequence::MoveToStartOfDocument) - || ke->matches(QKeySequence::MoveToEndOfDocument) - || ke->matches(QKeySequence::SelectNextWord) - || ke->matches(QKeySequence::SelectPreviousWord) - || ke->matches(QKeySequence::SelectStartOfLine) - || ke->matches(QKeySequence::SelectEndOfLine) - || ke->matches(QKeySequence::SelectStartOfBlock) - || ke->matches(QKeySequence::SelectEndOfBlock) - || ke->matches(QKeySequence::SelectStartOfDocument) - || ke->matches(QKeySequence::SelectEndOfDocument) - || ke->matches(QKeySequence::SelectAll) - ) { - return true; - } - return false; -#endif } static uint32_t s_eventId = 0; @@ -315,7 +265,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_adapterClient(0) , m_imeInProgress(false) , m_receivedEmptyImeEvent(false) - , m_initPending(false) , m_imState(0) , m_anchorPositionWithinSelection(-1) , m_cursorPositionWithinSelection(-1) @@ -368,18 +317,10 @@ void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterC m_adapterClientDestroyedConnection = QObject::connect(adapterClient->holdingQObject(), &QObject::destroyed, [this] { m_adapterClient = nullptr; }); - if (m_initPending) - InitAsChild(0); } void RenderWidgetHostViewQt::InitAsChild(gfx::NativeView) { - if (!m_adapterClient) { - m_initPending = true; - return; - } - m_initPending = false; - m_delegate->initAsChild(m_adapterClient); } void RenderWidgetHostViewQt::InitAsPopup(content::RenderWidgetHostView*, const gfx::Rect& rect) @@ -750,6 +691,11 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo m_adapterClient->updateScrollPosition(toQt(m_lastScrollOffset)); if (contentsSizeChanged) m_adapterClient->updateContentsSize(toQt(m_lastContentsSize)); + + if (m_pendingResize && host()) { + if (host()->SynchronizeVisualProperties()) + m_pendingResize = false; + } } void RenderWidgetHostViewQt::GetScreenInfo(content::ScreenInfo *results) const @@ -950,10 +896,6 @@ void RenderWidgetHostViewQt::OnDidUpdateVisualPropertiesComplete(const cc::Rende QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) { - if (m_pendingResize && host()) { - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; - } return m_compositor->updatePaintNode(oldNode, m_delegate.get()); } @@ -977,13 +919,13 @@ void RenderWidgetHostViewQt::notifyHidden() void RenderWidgetHostViewQt::windowBoundsChanged() { host()->SendScreenRects(); - if (m_delegate->window()) + if (m_delegate && m_delegate->window()) host()->NotifyScreenInfoChanged(); } void RenderWidgetHostViewQt::windowChanged() { - if (m_delegate->window()) + if (m_delegate && m_delegate->window()) host()->NotifyScreenInfoChanged(); } @@ -1031,7 +973,8 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) return false; } case QEvent::MouseButtonPress: - Focus(); // Fall through. + Focus(); + Q_FALLTHROUGH(); case QEvent::MouseButtonRelease: case QEvent::MouseMove: // Skip second MouseMove event when a window is being adopted, so that Chromium @@ -1052,7 +995,8 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) handleWheelEvent(static_cast<QWheelEvent*>(event)); break; case QEvent::TouchBegin: - Focus(); // Fall through. + Focus(); + Q_FALLTHROUGH(); case QEvent::TouchUpdate: case QEvent::TouchEnd: case QEvent::TouchCancel: @@ -1060,7 +1004,8 @@ bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) break; #if QT_CONFIG(tabletevent) case QEvent::TabletPress: - Focus(); // Fall through. + Focus(); + Q_FALLTHROUGH(); case QEvent::TabletRelease: case QEvent::TabletMove: handleTabletEvent(static_cast<QTabletEvent*>(event)); @@ -1292,13 +1237,12 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) end = qMax(0, start + end); } - QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); + underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT)); - QColor underlineColor(0, 0, 0, 0); + QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); if (format.underlineStyle() != QTextCharFormat::NoUnderline) - underlineColor = format.underlineColor(); + underlines.back().underline_color = toSk(format.underlineColor()); - underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, ui::ImeTextSpan::Thickness::kThin, toSk(underlineColor), SK_ColorTRANSPARENT)); break; } case QInputMethodEvent::Cursor: diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index ad7fc9f13..6a1134ac0 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -246,8 +246,6 @@ private: bool m_receivedEmptyImeEvent; QPoint m_previousMousePosition; - bool m_initPending; - gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; viz::LocalSurfaceId m_localSurfaceId; diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 8936ce63e..991c26ea8 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -91,7 +91,6 @@ public: class QWEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate { public: virtual ~RenderWidgetHostViewQtDelegate() { } - virtual void initAsChild(WebContentsAdapterClient*) = 0; virtual void initAsPopup(const QRect&) = 0; virtual QRectF screenRect() const = 0; virtual QRectF contentsRect() const = 0; diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index 2a9746660..4aff2cff6 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -52,6 +52,7 @@ QImage toQImage(const SkBitmap &bitmap) switch (bitmap.colorType()) { case kUnknown_SkColorType: case kRGBA_F16_SkColorType: + case kRGBA_F32_SkColorType: qWarning("Unknown or unsupported skia image format"); break; case kAlpha_8_SkColorType: diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 762d9f53a..21540f5da 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -516,14 +516,9 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) if (!rvh->IsRenderViewLive()) static_cast<content::WebContentsImpl*>(m_webContents.get())->CreateRenderViewForRenderManager(rvh, MSG_ROUTING_NONE, MSG_ROUTING_NONE, base::UnguessableToken::Create(), content::FrameReplicationState()); - m_adapterClient->initializationFinished(); -} + m_webContentsDelegate->RenderViewHostChanged(nullptr, rvh); -void WebContentsAdapter::reattachRWHV() -{ - CHECK_INITIALIZED(); - if (content::RenderWidgetHostView *rwhv = m_webContents->GetRenderWidgetHostView()) - rwhv->InitAsChild(0); + m_adapterClient->initializationFinished(); } bool WebContentsAdapter::canGoBack() const @@ -1431,11 +1426,7 @@ bool WebContentsAdapter::handleDropDataFileContents(const content::DropData &dro const auto maybeFilename = dropData.GetSafeFilenameForImageFileContents(); const QString fileName = maybeFilename ? toQt(maybeFilename->AsUTF16Unsafe()) : QString(); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) const QString &filePath = m_dndTmpDir->filePath(fileName); -#else - const QString &filePath = m_dndTmpDir->path() + QLatin1Char('/') + fileName; -#endif QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { qWarning("Cannot write temporary file %s.", qUtf8Printable(filePath)); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 8e02a852b..e8e5359be 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -109,8 +109,6 @@ public: void load(const QWebEngineHttpRequest &request); void setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl); - void reattachRWHV(); - bool canGoBack() const; bool canGoForward() const; void stop(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index f1a15ddfd..b4f7d3f95 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -466,6 +466,7 @@ public: virtual void selectClientCert(const QSharedPointer<ClientCertSelectController> &selectController) = 0; virtual void updateScrollPosition(const QPointF &position) = 0; virtual void updateContentsSize(const QSizeF &size) = 0; + virtual void updateNavigationActions() = 0; virtual void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) = 0; virtual bool supportsDragging() const = 0; @@ -474,6 +475,7 @@ public: virtual void setToolTip(const QString& toolTipText) = 0; virtual ClientType clientType() = 0; virtual void printRequested() = 0; + virtual void widgetChanged(RenderWidgetHostViewQtDelegate *newWidget) = 0; virtual void interceptRequest(QWebEngineUrlRequestInfo &) { } virtual ProfileAdapter *profileAdapter() = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 569b939d8..4bde93fd3 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -258,11 +258,20 @@ void WebContentsDelegateQt::RenderFrameDeleted(content::RenderFrameHost *render_ m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID()); } +void WebContentsDelegateQt::RenderViewHostChanged(content::RenderViewHost *, content::RenderViewHost *newHost) +{ + if (newHost && newHost->GetWidget() && newHost->GetWidget()->GetView()) { + auto rwhv = static_cast<RenderWidgetHostViewQt *>(newHost->GetWidget()->GetView()); + m_viewClient->widgetChanged(rwhv->delegate()); + } +} + void WebContentsDelegateQt::EmitLoadStarted(const QUrl &url, bool isErrorPage) { if (m_lastLoadProgress >= 0 && m_lastLoadProgress < 100) // already running return; m_viewClient->loadStarted(url, isErrorPage); + m_viewClient->updateNavigationActions(); m_viewClient->loadProgressChanged(0); m_lastLoadProgress = 0; } @@ -287,6 +296,16 @@ void WebContentsDelegateQt::EmitLoadFinished(bool success, const QUrl &url, bool m_lastLoadProgress = -1; m_viewClient->loadProgressChanged(100); m_viewClient->loadFinished(success, url, isErrorPage, errorCode, errorDescription); + m_viewClient->updateNavigationActions(); +} + +void WebContentsDelegateQt::EmitLoadCommitted() +{ + // Make sure that we don't set the findNext WebFindOptions on a new frame. + m_lastSearchedString = QString(); + + m_viewClient->loadCommitted(); + m_viewClient->updateNavigationActions(); } void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navigation_handle) @@ -302,11 +321,7 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig profileAdapter->visitedLinksManager()->addUrl(url); } - // Make sure that we don't set the findNext WebFindOptions on a new frame. - m_lastSearchedString = QString(); - - // This is currently used for canGoBack/Forward values, which is flattened across frames. For other purposes we might have to pass is_main_frame. - m_viewClient->loadCommitted(); + EmitLoadCommitted(); } // Success is reported by DidFinishLoad, but DidFailLoad is now dead code and needs to be handled below if (navigation_handle->GetNetErrorCode() == net::OK) @@ -325,10 +340,8 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig EmitLoadStarted(toQt(GURL(content::kUnreachableWebDataURL)), true); // If it is already committed we will not see another DidFinishNavigation call or a DidFinishLoad call. - if (navigation_handle->HasCommitted()) { - m_lastSearchedString = QString(); - m_viewClient->loadCommitted(); - } + if (navigation_handle->HasCommitted()) + EmitLoadCommitted(); } } diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 124250a40..9c0f8f484 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -130,6 +130,7 @@ public: // WebContentsObserver overrides void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override; + void RenderViewHostChanged(content::RenderViewHost *old_host, content::RenderViewHost *new_host) override; void DidStartNavigation(content::NavigationHandle *navigation_handle) override; void DidFinishNavigation(content::NavigationHandle *navigation_handle) override; void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) override; @@ -159,6 +160,7 @@ private: QWeakPointer<WebContentsAdapter> createWindow(std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); void EmitLoadStarted(const QUrl &url, bool isErrorPage = false); void EmitLoadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()); + void EmitLoadCommitted(); WebContentsAdapterClient *m_viewClient; QString m_lastSearchedString; diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 7910688d3..3c4465ae3 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -78,8 +78,6 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(conten view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); if (m_client) view->setAdapterClient(m_client); - // Tell the RWHV delegate to attach itself to the native view container. - view->InitAsChild(0); return view; } diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 7e91b3bdb..db74978d3 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -144,10 +144,8 @@ 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()) @@ -364,10 +362,8 @@ WebEngineContext::WebEngineContext() appArgs.append(QString::fromLocal8Bit(qgetenv(kChromiumFlagsEnv)).split(' ')); } -#ifdef Q_OS_WIN bool enableWebGLSoftwareRendering = appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); -#endif bool useEmbeddedSwitches = false; #if defined(QTWEBENGINE_EMBEDDED_SWITCHES) @@ -462,12 +458,10 @@ WebEngineContext::WebEngineContext() bool tryGL = !usingANGLE() && (!usingSoftwareDynamicGL() -#ifdef Q_OS_WIN - // If user requested WebGL support on Windows, instead of using Skia rendering to - // bitmaps, use software rendering via opengl32sw.dll. This might be less + // If user requested WebGL support instead of using Skia rendering to + // bitmaps, use software rendering via software OpenGL. This might be less // performant, but at least provides WebGL support. || enableWebGLSoftwareRendering -#endif ) && !usingQtQuick2DRenderer(); @@ -534,12 +528,10 @@ WebEngineContext::WebEngineContext() if (glType) { parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); parsedCommandLine->AppendSwitch(switches::kInProcessGPU); -#ifdef Q_OS_WIN if (enableWebGLSoftwareRendering) { parsedCommandLine->AppendSwitch(switches::kDisableGpuRasterization); parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlacklist); } -#endif } else { parsedCommandLine->AppendSwitch(switches::kDisableGpu); } diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 479fc38f8..a45f7048b 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -174,14 +174,6 @@ static QString qtTextForKeyEvent(const QKeyEvent *ev, int qtKey, Qt::KeyboardMod if ((qtModifiers & Qt::ControlModifier) && keyboardDriver() == KeyboardDriver::Xkb) text.clear(); - if (!text.isEmpty() || qtKey >= Qt::Key_Escape) - return text; - - QChar ch(qtKey); - if (!(qtModifiers & Qt::ShiftModifier)) // No way to check for caps lock - ch = ch.toLower(); - - text.append(ch); return text; } @@ -1413,11 +1405,7 @@ static void setBlinkWheelEventDelta(blink::WebMouseWheelEvent &webEvent) // a pixel delta based on ticks and scroll per line. static const float cDefaultQtScrollStep = 20.f; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) static const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines(); -#else - static const int wheelScrollLines = 3; -#endif webEvent.delta_x = webEvent.wheel_ticks_x * wheelScrollLines * cDefaultQtScrollStep; webEvent.delta_y = webEvent.wheel_ticks_y * wheelScrollLines * cDefaultQtScrollStep; } @@ -1426,7 +1414,9 @@ blink::WebMouseWheelEvent::Phase toBlinkPhase(QWheelEvent *ev) { switch (ev->phase()) { case Qt::NoScrollPhase: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) case Qt::ScrollMomentum: +#endif return blink::WebMouseWheelEvent::kPhaseNone; case Qt::ScrollBegin: return ev->angleDelta().isNull() ? blink::WebMouseWheelEvent::kPhaseMayBegin : blink::WebMouseWheelEvent::kPhaseBegan; @@ -1451,7 +1441,11 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; webEvent.phase = toBlinkPhase(ev); - webEvent.has_precise_scrolling_deltas = true; +#if defined(Q_OS_DARWIN) + // has_precise_scrolling_deltas is a macOS term meaning it is a system scroll gesture, see qnsview_mouse.mm + webEvent.has_precise_scrolling_deltas = (ev->source() == Qt::MouseEventSynthesizedBySystem); +#endif + setBlinkWheelEventDelta(webEvent); return webEvent; @@ -1465,6 +1459,10 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, return false; if (toBlinkPhase(ev) != webEvent.phase) return false; +#if defined(Q_OS_DARWIN) + if (webEvent.has_precise_scrolling_deltas != (ev->source() == Qt::MouseEventSynthesizedBySystem)) + return false; +#endif webEvent.SetTimeStamp(currentTimeForEvent(ev)); webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); @@ -1495,6 +1493,12 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e webKitEvent.dom_key = domKeyForQtKey(qtKey); else if (!qtText.isEmpty()) webKitEvent.dom_key = ui::DomKey::FromCharacter(qtText.toUcs4().first()); + else { + QChar ch(qtKey); + if (!(qtModifiers & Qt::ShiftModifier)) // No way to check for caps lock + ch = ch.toLower(); + webKitEvent.dom_key = ui::DomKey::FromCharacter(ch.unicode()); + } // The dom_code field should contain the USB keycode of the *physical* key // that was pressed. Physical meaning independent of layout and modifiers. diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 116f49c3c..3bc0be196 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -166,6 +166,9 @@ QQuickWebEngineViewPrivate::~QQuickWebEngineViewPrivate() adapter->stopFinding(); if (faviconProvider) faviconProvider->detach(q_ptr); + // q_ptr->d_ptr might be null due to destroy() + if (q_ptr->d_ptr) + bindViewAndWidget(q_ptr, nullptr); } void QQuickWebEngineViewPrivate::initializeProfile() @@ -188,10 +191,11 @@ bool QQuickWebEngineViewPrivate::profileInitialized() const void QQuickWebEngineViewPrivate::destroy() { - // the profile for this web contens is about to be - // garbage collected, delete WebContent first and - // let the QQuickWebEngineView be collected later by gc. - delete q_ptr->d_ptr.take(); + // The profile for this web contents is about to be + // garbage collected, delete WebContents first and + // let the QQuickWebEngineView be collected later by gc. + bindViewAndWidget(q_ptr, nullptr); + delete q_ptr->d_ptr.take(); } UIDelegatesManager *QQuickWebEngineViewPrivate::ui() @@ -669,6 +673,12 @@ void QQuickWebEngineViewPrivate::printRequested() }); } +void QQuickWebEngineViewPrivate::widgetChanged(RenderWidgetHostViewQtDelegate *newWidgetBase) +{ + Q_Q(QQuickWebEngineView); + bindViewAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateQuick *>(newWidgetBase)); +} + WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const { return m_settings->d_ptr.data(); @@ -846,6 +856,52 @@ void QQuickWebEngineViewPrivate::setFullScreenMode(bool fullscreen) } } +void QQuickWebEngineViewPrivate::bindViewAndWidget(QQuickWebEngineView *view, + RenderWidgetHostViewQtDelegateQuick *widget) +{ + auto oldWidget = view ? view->d_func()->widget : nullptr; + auto oldView = widget ? widget->m_view : nullptr; + + // Change pointers first. + + if (widget && oldView != view) { + if (oldView) + oldView->d_func()->widget = nullptr; + widget->m_view = view; + } + + if (view && oldWidget != widget) { + if (oldWidget) + oldWidget->m_view = nullptr; + view->d_func()->widget = widget; + } + + // Then notify. + + if (widget && oldView != view && oldView) + oldView->d_func()->widgetChanged(widget, nullptr); + + if (view && oldWidget != widget) + view->d_func()->widgetChanged(oldWidget, widget); +} + +void QQuickWebEngineViewPrivate::widgetChanged(RenderWidgetHostViewQtDelegateQuick *oldWidget, + RenderWidgetHostViewQtDelegateQuick *newWidget) +{ + Q_Q(QQuickWebEngineView); + + if (oldWidget) + oldWidget->setParentItem(nullptr); + + if (newWidget) { + newWidget->setParentItem(q); + newWidget->setSize(q->boundingRect().size()); + // Focus on creation if the view accepts it + if (q->activeFocusOnPress()) + newWidget->setFocus(true); + } +} + void QQuickWebEngineViewPrivate::updateAction(QQuickWebEngineView::WebAction action) const { QQuickWebEngineAction *a = actions[action]; @@ -878,6 +934,15 @@ void QQuickWebEngineViewPrivate::updateAction(QQuickWebEngineView::WebAction act a->d_ptr->setEnabled(enabled); } +void QQuickWebEngineViewPrivate::updateNavigationActions() +{ + updateAction(QQuickWebEngineView::Back); + updateAction(QQuickWebEngineView::Forward); + updateAction(QQuickWebEngineView::Stop); + updateAction(QQuickWebEngineView::Reload); + updateAction(QQuickWebEngineView::ReloadAndBypassCache); + updateAction(QQuickWebEngineView::ViewSource); +} QUrl QQuickWebEngineView::url() const { @@ -1485,11 +1550,9 @@ void QQuickWebEngineView::fullScreenCancelled() void QQuickWebEngineView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { QQuickItem::geometryChanged(newGeometry, oldGeometry); - const QList<QQuickItem *> children = childItems(); - for (QQuickItem *child : children) { - if (qobject_cast<RenderWidgetHostViewQtDelegateQuick *>(child)) - child->setSize(newGeometry.size()); - } + Q_D(QQuickWebEngineView); + if (d->widget) + d->widget->setSize(newGeometry.size()); } void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &value) diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index ee38ece6b..cbba9b568 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -63,8 +63,9 @@ #include <QtGui/qaccessibleobject.h> namespace QtWebEngineCore { -class WebContentsAdapter; +class RenderWidgetHostViewQtDelegateQuick; class UIDelegatesManager; +class WebContentsAdapter; } QT_BEGIN_NAMESPACE @@ -145,6 +146,7 @@ public: void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override; void updateScrollPosition(const QPointF &position) override; void updateContentsSize(const QSizeF &size) override; + void updateNavigationActions() override; void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) override; bool supportsDragging() const override; @@ -156,6 +158,7 @@ public: QtWebEngineCore::ProfileAdapter *profileAdapter() override; QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override; void printRequested() override; + void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidgetBase) override; void updateAction(QQuickWebEngineView::WebAction) const; void adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents); @@ -164,6 +167,10 @@ public: void ensureContentsAdapter(); void setFullScreenMode(bool); + static void bindViewAndWidget(QQuickWebEngineView *view, QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *widget); + void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *oldWidget, + QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *newWidget); + // QQmlListPropertyHelpers static void userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script); static int userScripts_count(QQmlListProperty<QQuickWebEngineScript> *p); @@ -197,6 +204,7 @@ public: uint m_webChannelWorld; bool m_isBeingAdopted; mutable QQuickWebEngineAction *actions[QQuickWebEngineView::WebActionCount]; + QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *widget = nullptr; bool profileInitialized() const; diff --git a/src/webengine/doc/qtwebengine.qdocconf b/src/webengine/doc/qtwebengine.qdocconf index dc162bf56..b1e3a2ded 100644 --- a/src/webengine/doc/qtwebengine.qdocconf +++ b/src/webengine/doc/qtwebengine.qdocconf @@ -54,7 +54,6 @@ depends += qtcore \ qtqml \ qtquick \ qtquickcontrols \ - qtquickcontrols2 \ qtdoc \ qtwebchannel \ qtwebview \ diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index baece82f3..d23e64774 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -55,7 +55,6 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW : m_client(client) , m_isPopup(isPopup) , m_isPasswordInput(false) - , m_initialized(false) { setFlag(ItemHasContents); setAcceptedMouseButtons(Qt::AllButtons); @@ -85,16 +84,9 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW } -void RenderWidgetHostViewQtDelegateQuick::initAsChild(WebContentsAdapterClient* container) +RenderWidgetHostViewQtDelegateQuick::~RenderWidgetHostViewQtDelegateQuick() { - QQuickWebEngineView *view = static_cast<QQuickWebEngineViewPrivate *>(container)->q_func(); - setParentItem(view); - setSize(view->boundingRect().size()); - // Focus on creation if the view accepts it - if (view->activeFocusOnPress()) - setFocus(true); - m_initialized = true; - + QQuickWebEngineViewPrivate::bindViewAndWidget(nullptr, this); } void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r) @@ -106,7 +98,6 @@ void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r) setWidth(rect.width()); setHeight(rect.height()); setVisible(true); - m_initialized = true; } QRectF RenderWidgetHostViewQtDelegateQuick::screenRect() const @@ -361,8 +352,7 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It m_windowConnections.append(connect(value.window, SIGNAL(closing(QQuickCloseEvent *)), SLOT(onHide()))); } - if (m_initialized) - m_client->windowChanged(); + m_client->windowChanged(); } else if (change == QQuickItem::ItemVisibleHasChanged) { if (!m_isPopup && !value.boolValue) onHide(); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index 74cddf476..6b855c824 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -44,6 +44,11 @@ #include <QQuickItem> +QT_BEGIN_NAMESPACE +class QQuickWebEngineView; +class QQuickWebEngineViewPrivate; +QT_END_NAMESPACE + namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, public RenderWidgetHostViewQtDelegate @@ -51,8 +56,8 @@ class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, public RenderWidg Q_OBJECT public: RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup); + ~RenderWidgetHostViewQtDelegateQuick(); - void initAsChild(WebContentsAdapterClient* container) override; void initAsPopup(const QRect&) override; QRectF screenRect() const override; QRectF contentsRect() const override; @@ -102,12 +107,14 @@ private slots: void onHide(); private: + friend QQuickWebEngineViewPrivate; + RenderWidgetHostViewQtDelegateClient *m_client; QList<QMetaObject::Connection> m_windowConnections; bool m_isPopup; bool m_isPasswordInput; - bool m_initialized; QPoint m_lastGlobalPos; + QQuickWebEngineView *m_view = nullptr; }; } // namespace QtWebEngineCore diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp index dd37ff6fa..d3c88148e 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -54,13 +54,6 @@ RenderWidgetHostViewQtDelegateQuickWindow::~RenderWidgetHostViewQtDelegateQuickW { } -void RenderWidgetHostViewQtDelegateQuickWindow::initAsChild(WebContentsAdapterClient *container) -{ - Q_UNUSED(container); - // We should only use this wrapper class for webUI popups. - Q_UNREACHABLE(); -} - void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &screenRect) { m_realDelegate->initAsPopup(QRect(QPoint(0, 0), screenRect.size())); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index 6a1be8b7f..df241bf3a 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -55,7 +55,6 @@ public: RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegate *realDelegate); ~RenderWidgetHostViewQtDelegateQuickWindow(); - void initAsChild(WebContentsAdapterClient* container) override; void initAsPopup(const QRect&) override; QRectF screenRect() const override; QRectF contentsRect() const override; diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 252bdc9b6..7e49bc77d 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -508,12 +508,7 @@ public: if (pos.isNull() || !item->contains(pos)) return; const QPoint oldPos = QCursor::pos(); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) const QPoint globalPos = item->mapToGlobal(QPointF(pos)).toPoint(); -#else - const QPoint posInWindow = item->mapToItem(item->window()->contentItem(), QPointF(pos)).toPoint(); - const QPoint globalPos = item->window()->mapToGlobal(posInWindow); -#endif if (oldPos == globalPos) return; m_oldCursorPos = oldPos; diff --git a/src/webenginewidgets/api/qwebengineclientcertificateselection.cpp b/src/webenginewidgets/api/qwebengineclientcertificateselection.cpp index 8d3c8d223..9eca01bbe 100644 --- a/src/webenginewidgets/api/qwebengineclientcertificateselection.cpp +++ b/src/webenginewidgets/api/qwebengineclientcertificateselection.cpp @@ -39,7 +39,7 @@ #include "qwebengineclientcertificateselection.h" -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) #include "client_cert_select_controller.h" @@ -124,4 +124,4 @@ QUrl QWebEngineClientCertificateSelection::host() const QT_END_NAMESPACE -#endif // QT_CONFIG(ssl) +#endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) diff --git a/src/webenginewidgets/api/qwebengineclientcertificateselection.h b/src/webenginewidgets/api/qwebengineclientcertificateselection.h index 15b8a47c6..d451d09ae 100644 --- a/src/webenginewidgets/api/qwebengineclientcertificateselection.h +++ b/src/webenginewidgets/api/qwebengineclientcertificateselection.h @@ -43,7 +43,7 @@ #include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> #include <QtNetwork/qtnetwork-config.h> -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) #include <QtCore/qscopedpointer.h> #include <QtCore/qvector.h> @@ -75,6 +75,6 @@ private: QT_END_NAMESPACE -#endif // QT_CONFIG(ssl) +#endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) #endif // QWEBENGINECLIENTCERTSELECTION_H diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 1f9b2f72a..6a70203be 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -276,8 +276,6 @@ RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostVie // The new delegate will not be deleted by the parent view though, because we unset the parent // when the parent is destroyed. The delegate will be destroyed by Chromium when the popup is // dismissed. - // If the delegate is not for a popup, but for a newly created QWebEngineView, the parent is 0 - // just like before. return new RenderWidgetHostViewQtDelegateWidget(client, this->view); } @@ -371,12 +369,6 @@ void QWebEnginePagePrivate::loadStarted(const QUrl &provisionalUrl, bool isError isLoading = true; QTimer::singleShot(0, q, &QWebEnginePage::loadStarted); - updateNavigationActions(); -} - -void QWebEnginePagePrivate::loadCommitted() -{ - updateNavigationActions(); } void QWebEnginePagePrivate::loadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, const QString &errorDescription) @@ -404,7 +396,6 @@ void QWebEnginePagePrivate::loadFinished(bool success, const QUrl &url, bool isE emit q->loadFinished(success); }); } - updateNavigationActions(); } void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool success) @@ -688,6 +679,8 @@ void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) adapter = std::move(newWebContents); adapter->setClient(this); adapter->loadDefault(); + if (view && view->isVisible()) + wasShown(); } } @@ -728,12 +721,87 @@ const QObject *QWebEnginePagePrivate::holdingQObject() const return q; } +void QWebEnginePagePrivate::widgetChanged(RenderWidgetHostViewQtDelegate *newWidgetBase) +{ + Q_Q(QWebEnginePage); + bindPageAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateWidget *>(newWidgetBase)); +} + void QWebEnginePagePrivate::ensureInitialized() const { if (!adapter->isInitialized()) adapter->loadDefault(); } +void QWebEnginePagePrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView *view) +{ + auto oldView = page ? page->d_func()->view : nullptr; + auto oldPage = view ? view->d_func()->page : nullptr; + + // Change pointers first. + + if (page && oldView != view) { + if (oldView) + oldView->d_func()->page = nullptr; + page->d_func()->view = view; + } + + if (view && oldPage != page) { + if (oldPage) + oldPage->d_func()->view = nullptr; + view->d_func()->page = page; + } + + // Then notify. + + auto widget = page ? page->d_func()->widget : nullptr; + auto oldWidget = oldPage ? oldPage->d_func()->widget : nullptr; + + if (page && oldView != view && oldView) { + oldView->d_func()->pageChanged(page, nullptr); + if (widget) + oldView->d_func()->widgetChanged(widget, nullptr); + } + + if (view && oldPage != page) { + view->d_func()->pageChanged(oldPage, page); + if (oldWidget != widget) + view->d_func()->widgetChanged(oldWidget, widget); + } +} + +void QWebEnginePagePrivate::bindPageAndWidget(QWebEnginePage *page, RenderWidgetHostViewQtDelegateWidget *widget) +{ + auto oldPage = widget ? widget->m_page : nullptr; + auto oldWidget = page ? page->d_func()->widget : nullptr; + + // Change pointers first. + + if (widget && oldPage != page) { + if (oldPage) + oldPage->d_func()->widget = nullptr; + widget->m_page = page; + } + + if (page && oldWidget != widget) { + if (oldWidget) + oldWidget->m_page = nullptr; + page->d_func()->widget = widget; + } + + // Then notify. + + if (widget && oldPage != page && oldPage) { + if (auto oldView = oldPage->d_func()->view) + oldView->d_func()->widgetChanged(widget, nullptr); + } + + if (page && oldWidget != widget) { + if (auto view = page->d_func()->view) + view->d_func()->widgetChanged(oldWidget, widget); + } +} + QWebEnginePage::QWebEnginePage(QObject* parent) : QObject(parent) , d_ptr(new QWebEnginePagePrivate()) @@ -905,7 +973,8 @@ QWebEnginePage::~QWebEnginePage() Q_D(QWebEnginePage); setDevToolsPage(nullptr); d->adapter->stopFinding(); - QWebEngineViewPrivate::removePageFromView(this); + QWebEnginePagePrivate::bindPageAndView(this, nullptr); + QWebEnginePagePrivate::bindPageAndWidget(this, nullptr); } QWebEngineHistory *QWebEnginePage::history() const @@ -1074,9 +1143,9 @@ bool QWebEnginePage::recentlyAudible() const return d->adapter->isInitialized() && d->adapter->recentlyAudible(); } -void QWebEnginePage::setView(QWidget *view) +void QWebEnginePage::setView(QWidget *newViewBase) { - QWebEngineViewPrivate::bind(qobject_cast<QWebEngineView*>(view), this); + QWebEnginePagePrivate::bindPageAndView(this, qobject_cast<QWebEngineView *>(newViewBase)); } QWidget *QWebEnginePage::view() const @@ -1680,7 +1749,7 @@ void QWebEnginePagePrivate::allowCertificateError(const QSharedPointer<Certifica void QWebEnginePagePrivate::selectClientCert(const QSharedPointer<ClientCertSelectController> &controller) { -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) Q_Q(QWebEnginePage); QWebEngineClientCertificateSelection certSelection(controller); @@ -1690,7 +1759,7 @@ void QWebEnginePagePrivate::selectClientCert(const QSharedPointer<ClientCertSele #endif } -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) /*! \fn void QWebEnginePage::selectClientCertificate(QWebEngineClientCertificateSelection clientCertificateSelection) \since 5.12 diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index a6bad4f26..4fd195074 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -325,7 +325,7 @@ Q_SIGNALS: void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); void quotaRequested(QWebEngineQuotaRequest quotaRequest); void registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request); -#if QT_CONFIG(ssl) +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void selectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection); #endif diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 6d214adca..7b4e52f79 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -65,6 +65,7 @@ namespace QtWebEngineCore { class RenderWidgetHostViewQtDelegate; +class RenderWidgetHostViewQtDelegateWidget; class WebContentsAdapter; } @@ -100,7 +101,7 @@ public: qreal dpiScale() const override; QColor backgroundColor() const override; void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override; - void loadCommitted() override; + void loadCommitted() override { } void loadVisuallyCommitted() override { } void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) override; void focusContainer() override; @@ -141,6 +142,7 @@ public: void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override; void updateScrollPosition(const QPointF &position) override; void updateContentsSize(const QSizeF &size) override; + void updateNavigationActions() override; void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) override; bool supportsDragging() const override; @@ -150,12 +152,12 @@ public: const QObject *holdingQObject() const override; ClientType clientType() override { return QtWebEngineCore::WebContentsAdapterClient::WidgetsClient; } void interceptRequest(QWebEngineUrlRequestInfo &) override; + void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidget) override; QtWebEngineCore::ProfileAdapter *profileAdapter() override; QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override; void updateAction(QWebEnginePage::WebAction) const; - void updateNavigationActions(); void _q_webActionTriggered(bool checked); void wasShown(); @@ -167,6 +169,10 @@ public: void setFullScreenMode(bool); void ensureInitialized() const; + static void bindPageAndView(QWebEnginePage *page, QWebEngineView *view); + static void bindPageAndWidget(QWebEnginePage *page, + QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget); + QSharedPointer<QtWebEngineCore::WebContentsAdapter> adapter; QWebEngineHistory *history; QWebEngineProfile *profile; @@ -189,6 +195,7 @@ public: qreal defaultZoomFactor; QTimer wasShownTimer; QWebEngineUrlRequestInterceptor *requestInterceptor; + QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget = nullptr; mutable QtWebEngineCore::CallbackDirectory m_callbacks; mutable QAction *actions[QWebEnginePage::WebActionCount]; diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index e6f9fcb49..576baad17 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -41,6 +41,7 @@ #include "qwebengineview_p.h" #include "qwebenginepage_p.h" +#include "render_widget_host_view_qt_delegate_widget.h" #include "web_contents_adapter.h" #if QT_CONFIG(action) @@ -55,89 +56,61 @@ QT_BEGIN_NAMESPACE -void QWebEngineViewPrivate::notify(QWebEngineView *view, QWebEnginePage *oldPage, QWebEnginePage *newPage) +void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage) { - Q_ASSERT(view); + Q_Q(QWebEngineView); + + if (oldPage) { + oldPage->disconnect(q); + } + + if (newPage) { + QObject::connect(newPage, &QWebEnginePage::titleChanged, q, &QWebEngineView::titleChanged); + QObject::connect(newPage, &QWebEnginePage::urlChanged, q, &QWebEngineView::urlChanged); + QObject::connect(newPage, &QWebEnginePage::iconUrlChanged, q, &QWebEngineView::iconUrlChanged); + QObject::connect(newPage, &QWebEnginePage::iconChanged, q, &QWebEngineView::iconChanged); + QObject::connect(newPage, &QWebEnginePage::loadStarted, q, &QWebEngineView::loadStarted); + QObject::connect(newPage, &QWebEnginePage::loadProgress, q, &QWebEngineView::loadProgress); + QObject::connect(newPage, &QWebEnginePage::loadFinished, q, &QWebEngineView::loadFinished); + QObject::connect(newPage, &QWebEnginePage::selectionChanged, q, &QWebEngineView::selectionChanged); + QObject::connect(newPage, &QWebEnginePage::renderProcessTerminated, q, &QWebEngineView::renderProcessTerminated); + } auto oldUrl = oldPage ? oldPage->url() : QUrl(); auto newUrl = newPage ? newPage->url() : QUrl(); if (oldUrl != newUrl) - Q_EMIT view->urlChanged(newUrl); + Q_EMIT q->urlChanged(newUrl); auto oldTitle = oldPage ? oldPage->title() : QString(); auto newTitle = newPage ? newPage->title() : QString(); if (oldTitle != newTitle) - Q_EMIT view->titleChanged(newTitle); + Q_EMIT q->titleChanged(newTitle); auto oldIcon = oldPage ? oldPage->iconUrl() : QUrl(); auto newIcon = newPage ? newPage->iconUrl() : QUrl(); if (oldIcon != newIcon) { - Q_EMIT view->iconUrlChanged(newIcon); - Q_EMIT view->iconChanged(newPage ? newPage->icon() : QIcon()); + Q_EMIT q->iconUrlChanged(newIcon); + Q_EMIT q->iconChanged(newPage ? newPage->icon() : QIcon()); } if ((oldPage && oldPage->hasSelection()) || (newPage && newPage->hasSelection())) - Q_EMIT view->selectionChanged(); -} - -QWebEnginePage* QWebEngineViewPrivate::removeViewFromPage(QWebEngineView *view) -{ - Q_ASSERT(view); - QWebEnginePage *oldPage = view->d_func()->page; - - if (oldPage) { - oldPage->disconnect(view); - oldPage->d_func()->view = nullptr; - if (oldPage->parent() != view) - oldPage->d_func()->adapter->reattachRWHV(); - } - return oldPage; -} - -void QWebEngineViewPrivate::removePageFromView(QWebEnginePage *page) -{ - Q_ASSERT(page); - if (QWebEngineView *oldView = page->d_func()->view) { - page->disconnect(oldView); - page->d_func()->view = nullptr; - oldView->d_func()->page = nullptr; - notify(oldView, page, nullptr); - } + Q_EMIT q->selectionChanged(); } -void QWebEngineViewPrivate::bind(QWebEngineView *view, QWebEnginePage *page) +void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *oldWidget, + QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *newWidget) { - if (view && page == view->d_func()->page) - return; - - if (page) { - // Un-bind page from its current view. - removePageFromView(page); - page->d_func()->view = view; - page->d_func()->adapter->reattachRWHV(); - } - - if (view) { - // Un-bind view from its current page. - QWebEnginePage *oldPage = removeViewFromPage(view); - - view->d_func()->page = page; - notify(view, oldPage, page); + Q_Q(QWebEngineView); - if (oldPage && oldPage->parent() == view) - delete oldPage; + if (oldWidget) { + q->layout()->removeWidget(oldWidget); + oldWidget->hide(); } - if (view && page) { - QObject::connect(page, &QWebEnginePage::titleChanged, view, &QWebEngineView::titleChanged); - QObject::connect(page, &QWebEnginePage::urlChanged, view, &QWebEngineView::urlChanged); - QObject::connect(page, &QWebEnginePage::iconUrlChanged, view, &QWebEngineView::iconUrlChanged); - QObject::connect(page, &QWebEnginePage::iconChanged, view, &QWebEngineView::iconChanged); - QObject::connect(page, &QWebEnginePage::loadStarted, view, &QWebEngineView::loadStarted); - QObject::connect(page, &QWebEnginePage::loadProgress, view, &QWebEngineView::loadProgress); - QObject::connect(page, &QWebEnginePage::loadFinished, view, &QWebEngineView::loadFinished); - QObject::connect(page, &QWebEnginePage::selectionChanged, view, &QWebEngineView::selectionChanged); - QObject::connect(page, &QWebEnginePage::renderProcessTerminated, view, &QWebEngineView::renderProcessTerminated); + if (newWidget) { + q->layout()->addWidget(newWidget); + q->setFocusProxy(newWidget); + newWidget->show(); } } @@ -193,7 +166,8 @@ QWebEngineView::QWebEngineView(QWidget *parent) QWebEngineView::~QWebEngineView() { - QWebEngineViewPrivate::removeViewFromPage(this); + blockSignals(true); + QWebEnginePagePrivate::bindPageAndView(nullptr, this); } QWebEnginePage* QWebEngineView::page() const @@ -206,9 +180,9 @@ QWebEnginePage* QWebEngineView::page() const return d->page; } -void QWebEngineView::setPage(QWebEnginePage* page) +void QWebEngineView::setPage(QWebEnginePage *newPage) { - QWebEngineViewPrivate::bind(this, page); + QWebEnginePagePrivate::bindPageAndView(newPage, this); } void QWebEngineView::load(const QUrl& url) diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index 1845bfb60..28fb883aa 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -55,6 +55,10 @@ #include <QtWidgets/qaccessiblewidget.h> +namespace QtWebEngineCore { +class RenderWidgetHostViewQtDelegateWidget; +} + QT_BEGIN_NAMESPACE class QWebEngineView; @@ -65,10 +69,9 @@ public: Q_DECLARE_PUBLIC(QWebEngineView) QWebEngineView *q_ptr; - static void notify(QWebEngineView *view, QWebEnginePage *oldPage, QWebEnginePage *newPage); - static QWebEnginePage* removeViewFromPage(QWebEngineView *view); - static void removePageFromView(QWebEnginePage *page); - static void bind(QWebEngineView *view, QWebEnginePage *page); + void pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage); + void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *oldWidget, + QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *newWidget); QWebEngineViewPrivate(); diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 13c65f1ec..7bbd85091 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -165,15 +165,28 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_AlwaysShowToolTips); - if (parent) { - // Unset the popup parent if the parent is being destroyed, thus making sure a double - // delete does not happen. - // Also in case the delegate is destroyed before its parent (when a popup is simply - // dismissed), this connection will automatically be removed by ~QObject(), preventing - // a use-after-free. + setContent(QUrl(), nullptr, m_rootItem.data()); + + connectRemoveParentBeforeParentDelete(); +} + +RenderWidgetHostViewQtDelegateWidget::~RenderWidgetHostViewQtDelegateWidget() +{ + QWebEnginePagePrivate::bindPageAndWidget(nullptr, this); +} + +void RenderWidgetHostViewQtDelegateWidget::connectRemoveParentBeforeParentDelete() +{ + if (QWidget *parent = parentWidget()) connect(parent, &QObject::destroyed, this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); - } +} + +void RenderWidgetHostViewQtDelegateWidget::disconnectRemoveParentBeforeParentDelete() +{ + if (QWidget *parent = parentWidget()) + disconnect(parent, &QObject::destroyed, + this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); } void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() @@ -188,29 +201,9 @@ void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() close(); } -void RenderWidgetHostViewQtDelegateWidget::initAsChild(WebContentsAdapterClient* container) -{ - setContent(QUrl(), nullptr, m_rootItem.data()); - - QWebEnginePagePrivate *pagePrivate = static_cast<QWebEnginePagePrivate *>(container); - if (pagePrivate->view) { - if (parentWidget()) - disconnect(parentWidget(), &QObject::destroyed, - this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); - pagePrivate->view->layout()->addWidget(this); - if (QWidget *focusProxy = pagePrivate->view->focusProxy()) - if (focusProxy != this) - pagePrivate->view->layout()->removeWidget(focusProxy); - pagePrivate->view->setFocusProxy(this); - show(); - } else - setParent(0); -} - void RenderWidgetHostViewQtDelegateWidget::initAsPopup(const QRect& screenRect) { m_isPopup = true; - setContent(QUrl(), nullptr, m_rootItem.data()); // The keyboard events are supposed to go to the parent RenderHostView // so the WebUI popups should never have focus. Besides, if the parent view @@ -422,6 +415,18 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) { bool handled = false; + // Track parent to make sure we don't get deleted. + switch (event->type()) { + case QEvent::ParentAboutToChange: + disconnectRemoveParentBeforeParentDelete(); + break; + case QEvent::ParentChange: + connectRemoveParentBeforeParentDelete(); + break; + default: + break; + } + // Mimic QWidget::event() by ignoring mouse, keyboard, touch and tablet events if the widget is // disabled. if (!isEnabled()) { diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index 4dc47dfdd..74c9e3413 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -46,6 +46,11 @@ #include <QQuickItem> #include <QQuickWidget> +QT_BEGIN_NAMESPACE +class QWebEnginePage; +class QWebEnginePagePrivate; +QT_END_NAMESPACE + namespace QtWebEngineCore { // Useful information keyboard and mouse QEvent propagation. @@ -58,8 +63,8 @@ class RenderWidgetHostViewQtDelegateWidget : public QQuickWidget, public RenderW Q_OBJECT public: RenderWidgetHostViewQtDelegateWidget(RenderWidgetHostViewQtDelegateClient *client, QWidget *parent = 0); + ~RenderWidgetHostViewQtDelegateWidget(); - void initAsChild(WebContentsAdapterClient* container) override; void initAsPopup(const QRect&) override; QRectF screenRect() const override; QRectF contentsRect() const override; @@ -95,9 +100,13 @@ protected: private slots: void onWindowPosChanged(); + void connectRemoveParentBeforeParentDelete(); + void disconnectRemoveParentBeforeParentDelete(); void removeParentBeforeParentDelete(); private: + friend QWebEnginePagePrivate; + RenderWidgetHostViewQtDelegateClient *m_client; QScopedPointer<QQuickItem> m_rootItem; bool m_isPopup; @@ -105,6 +114,7 @@ private: QColor m_clearColor; QPoint m_lastGlobalPos; QList<QMetaObject::Connection> m_windowConnections; + QWebEnginePage *m_page = nullptr; }; } // namespace QtWebEngineCore diff --git a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/BLACKLIST b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/BLACKLIST new file mode 100644 index 000000000..a48edeeab --- /dev/null +++ b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/BLACKLIST @@ -0,0 +1,4 @@ +[javascriptClipboard:default] +opensuse-leap +[javascriptClipboard:canPaste] +opensuse-leap diff --git a/tests/auto/widgets/proxypac/proxy.pac b/tests/auto/widgets/proxypac/proxy.pac new file mode 100644 index 000000000..1d29847b9 --- /dev/null +++ b/tests/auto/widgets/proxypac/proxy.pac @@ -0,0 +1,7 @@ +function FindProxyForURL(url, host) +{ + if (shExpMatch(host, "*.proxy1.com")) return "PROXY localhost:5551"; + if (shExpMatch(host, "*.proxy2.com")) return "PROXY localhost:5552"; + return "PROXY proxy.url:8080"; +} + diff --git a/tests/auto/widgets/proxypac/proxypac.pro b/tests/auto/widgets/proxypac/proxypac.pro new file mode 100644 index 000000000..00ae90977 --- /dev/null +++ b/tests/auto/widgets/proxypac/proxypac.pro @@ -0,0 +1,28 @@ +include(../tests.pri) +QT += webengine +HEADERS += proxyserver.h +SOURCES += proxyserver.cpp + +# QTBUG-71229 +xgd_desktop.name=XDG_CURRENT_DESKTOP +xgd_desktop.value=KDE +QT_TOOL_ENV += xgd_desktop + +kde_home.name=KDEHOME +kde_home.value=$$OUT_PWD +QT_TOOL_ENV += kde_home + +PROXY_CONFIG= \ + "[Proxy Settings]" \ + "Proxy Config Script=$$PWD/proxy.pac" \ + "ProxyType=2" + +mkpath($$OUT_PWD/share/config) +KDE_FILE = $$OUT_PWD/share/config/kioslaverc + +!build_pass { + write_file($$KDE_FILE, PROXY_CONFIG) +} + +QMAKE_DISTCLEAN += $$KDE_FILE + diff --git a/tests/auto/widgets/proxypac/proxyserver.cpp b/tests/auto/widgets/proxypac/proxyserver.cpp new file mode 100644 index 000000000..4d38c87c9 --- /dev/null +++ b/tests/auto/widgets/proxypac/proxyserver.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "proxyserver.h" +#include <QDataStream> +#include <QTcpSocket> +#include <QDebug> + +ProxyServer::ProxyServer(QObject *parent) : QObject(parent), + m_port(5555) +{ + connect(&m_server, &QTcpServer::newConnection, this, &ProxyServer::handleNewConnection); +} + +void ProxyServer::setPort(int port) +{ + m_port = port; +} + +bool ProxyServer::isListening() +{ + return m_server.isListening(); +} + +void ProxyServer::run() +{ + if (!m_server.listen(QHostAddress::LocalHost, m_port)) + qFatal("Could not start the test server"); +} + +void ProxyServer::handleNewConnection() +{ + // do one connection at the time + Q_ASSERT(m_data.isEmpty()); + QTcpSocket *socket = m_server.nextPendingConnection(); + Q_ASSERT(socket); + connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); + connect(socket, &QAbstractSocket::readyRead, this, &ProxyServer::handleReadReady); +} + +void ProxyServer::handleReadReady() +{ + QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender()); + Q_ASSERT(socket); + + m_data.append(socket->readAll()); + + //simply wait for whole request + if (!m_data.endsWith("\r\n\r\n")) + return; + + // add fake proxy authetication + socket->write("HTTP/1.1 407 Proxy Auth Required\nProxy-Authenticate: " + "Basic realm=\"Proxy requires authentication\"\r\n\r\n"); + + m_data.clear(); + socket->disconnectFromHost(); + emit requestReceived(); +} diff --git a/tests/auto/widgets/proxypac/proxyserver.h b/tests/auto/widgets/proxypac/proxyserver.h new file mode 100644 index 000000000..ea68286a2 --- /dev/null +++ b/tests/auto/widgets/proxypac/proxyserver.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROXY_SERVER_H +#define PROXY_SERVER_H + +#include <QObject> +#include <QTcpServer> + +class ProxyServer : public QObject +{ + Q_OBJECT + +public: + explicit ProxyServer(QObject *parent = nullptr); + + void setPort(int port); + bool isListening(); + +signals: + void requestReceived(); + +public slots: + void run(); + +private slots: + void handleNewConnection(); + void handleReadReady(); + +private: + int m_port; + QByteArray m_data; + QTcpServer m_server; + +}; + +#endif // PROXY_SERVER_H diff --git a/tests/auto/widgets/proxypac/tst_proxypac.cpp b/tests/auto/widgets/proxypac/tst_proxypac.cpp new file mode 100644 index 000000000..f9340341b --- /dev/null +++ b/tests/auto/widgets/proxypac/tst_proxypac.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtwebengineglobal.h" +#include "proxyserver.h" +#include <QTest> +#include <QSignalSpy> +#include <QWebEngineProfile> +#include <QWebEnginePage> +#include <QNetworkProxy> + + +class tst_ProxyPac : public QObject { + Q_OBJECT +public: + tst_ProxyPac(){} + +private slots: + void proxypac(); +}; + +void tst_ProxyPac::proxypac() +{ + ProxyServer proxyServer1; + proxyServer1.setPort(5551); + proxyServer1.run(); + QSignalSpy proxySpy1(&proxyServer1, &ProxyServer::requestReceived); + + ProxyServer proxyServer2; + proxyServer2.setPort(5552); + proxyServer2.run(); + QSignalSpy proxySpy2(&proxyServer2, &ProxyServer::requestReceived); + + QTRY_VERIFY2(proxyServer1.isListening(), "Could not setup proxy server 1"); + QTRY_VERIFY2(proxyServer2.isListening(), "Could not setup proxy server 2"); + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + page.load(QUrl("http://test.proxy1.com")); + QTRY_COMPARE(proxySpy1.count() >= 1, true); + QVERIFY(proxySpy2.count() == 0); + page.load(QUrl("http://test.proxy2.com")); + QTRY_COMPARE(proxySpy2.count() >= 1 , true); +} + +#include "tst_proxypac.moc" +QTEST_MAIN(tst_ProxyPac) + diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp index 6ce4623d6..0fe0ec6cf 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -35,6 +35,7 @@ class tst_QWebEngineScript: public QObject { private Q_SLOTS: void domEditing(); void loadEvents(); + void scriptWorld_data(); void scriptWorld(); void scriptModifications(); #if QT_CONFIG(webengine_webchannel) @@ -185,8 +186,18 @@ void tst_QWebEngineScript::loadEvents() QCOMPARE(profile.pages.back().eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); } +void tst_QWebEngineScript::scriptWorld_data() +{ + QTest::addColumn<int>("worldId"); + + QTest::newRow("ApplicationWorld") << static_cast<int>(QWebEngineScript::ApplicationWorld); + QTest::newRow("UserWorld") << static_cast<int>(QWebEngineScript::UserWorld); + QTest::newRow("150") << 150; +} + void tst_QWebEngineScript::scriptWorld() { + QFETCH(int, worldId); QWebEnginePage page; QWebEngineScript script; script.setInjectionPoint(QWebEngineScript::DocumentCreation); @@ -197,14 +208,14 @@ void tst_QWebEngineScript::scriptWorld() QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "typeof(userScriptTest) != \"undefined\" && userScriptTest == 1;"), QVariant::fromValue(true)); - QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "typeof(userScriptTest) == \"undefined\"", QWebEngineScript::ApplicationWorld), QVariant::fromValue(true)); - script.setWorldId(QWebEngineScript::ApplicationWorld); + QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "typeof(userScriptTest) == \"undefined\"", worldId), QVariant::fromValue(true)); + script.setWorldId(worldId); page.scripts().clear(); page.scripts().insert(script); page.load(QUrl("about:blank")); QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "typeof(userScriptTest) == \"undefined\""), QVariant::fromValue(true)); - QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "typeof(userScriptTest) != \"undefined\" && userScriptTest == 1;", QWebEngineScript::ApplicationWorld), QVariant::fromValue(true)); + QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "typeof(userScriptTest) != \"undefined\" && userScriptTest == 1;", worldId), QVariant::fromValue(true)); } void tst_QWebEngineScript::scriptModifications() diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro index 05a4bfa59..eec8bb389 100644 --- a/tests/auto/widgets/widgets.pro +++ b/tests/auto/widgets/widgets.pro @@ -27,6 +27,9 @@ qtConfig(webengine-printing-and-pdf) { SUBDIRS += printing } +# QTBUG-71229 +linux:!boot2qt: SUBDIRS += proxypac + qtConfig(webengine-spellchecker):!cross_compile { !qtConfig(webengine-native-spellchecker) { SUBDIRS += spellchecking |