diff options
60 files changed, 693 insertions, 181 deletions
diff --git a/.cmake.conf b/.cmake.conf index 8aab1909f..391d9ba0c 100644 --- a/.cmake.conf +++ b/.cmake.conf @@ -1,3 +1,3 @@ -set(QT_REPO_MODULE_VERSION "6.3.1") +set(QT_REPO_MODULE_VERSION "6.3.3") set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_WEBENGINE "3.19") diff --git a/CHROMIUM_VERSION b/CHROMIUM_VERSION index 2ec45229b..91e8e4401 100644 --- a/CHROMIUM_VERSION +++ b/CHROMIUM_VERSION @@ -1,3 +1,3 @@ Based on Chromium version: 94.0.4606.126 -Patched with security patches up to Chromium version: 99.0.4844.84 +Patched with security patches up to Chromium version: 104.0.5112.81 diff --git a/cmake/Functions.cmake b/cmake/Functions.cmake index 89f4cdd39..a5209e260 100644 --- a/cmake/Functions.cmake +++ b/cmake/Functions.cmake @@ -300,7 +300,7 @@ function(get_install_config result) set(${result} "Release" PARENT_SCOPE) elseif("RelWithDebInfo" IN_LIST CMAKE_CONFIGURATION_TYPES) set(${result} "RelWithDebInfo" PARENT_SCOPE) - elseif("Debug" IN_LIST CMAKE_CONFIGURATION_TYPE) + elseif("Debug" IN_LIST CMAKE_CONFIGURATION_TYPES) set(${result} "Debug" PARENT_SCOPE) else() # assume MinSizeRel ? @@ -408,7 +408,18 @@ function(get_copy_of_response_file result target rsp) add_dependencies(${cmakeTarget} ${cmakeTarget}_${rsp}_copy_${config}) endfunction() -function(extend_cmake_target target buildDir completeStatic) +function(add_archiver_options target buildDir completeStatic) + get_target_property(config ${target} CONFIG) + string(TOUPPER ${config} cfg) + get_target_property(ninjaTarget ${target} NINJA_TARGET) + get_target_property(cmakeTarget ${target} CMAKE_TARGET) + set(objects_out "${buildDir}/${cmakeTarget}_objects.o") + add_library(GnObject_${cmakeTarget}_${config} OBJECT IMPORTED GLOBAL) + target_link_libraries(${cmakeTarget} PRIVATE $<$<CONFIG:${config}>:GnObject_${cmakeTarget}_${config}>) + set_property(TARGET GnObject_${cmakeTarget}_${config} PROPERTY IMPORTED_OBJECTS_${cfg} ${objects_out}) +endfunction() + +function(add_linker_options target buildDir completeStatic) get_target_property(config ${target} CONFIG) get_target_property(ninjaTarget ${target} NINJA_TARGET) get_target_property(cmakeTarget ${target} CMAKE_TARGET) @@ -419,6 +430,10 @@ function(extend_cmake_target target buildDir completeStatic) set(libs_rsp "${buildDir}/${ninjaTarget}_libs.rsp") set_target_properties(${cmakeTarget} PROPERTIES STATIC_LIBRARY_OPTIONS "@${objects_rsp}") if(LINUX) + get_gn_arch(cpu ${TEST_architecture_arch}) + if(CMAKE_CROSSCOMPILING AND cpu STREQUAL "arm" AND ${config} STREQUAL "Debug") + target_link_options(${cmakeTarget} PRIVATE "LINKER:--long-plt") + endif() target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") if(NOT completeStatic) target_link_libraries(${cmakeTarget} PRIVATE @@ -429,7 +444,6 @@ function(extend_cmake_target target buildDir completeStatic) target_link_libraries(${cmakeTarget} PRIVATE "$<1:-Wl,--no-fatal-warnings $<$<CONFIG:${config}>:@${libs_rsp}> -Wl,--no-fatal-warnings>" ) - endif() if(MACOS) target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") @@ -440,6 +454,7 @@ function(extend_cmake_target target buildDir completeStatic) endif() if(WIN32) get_copy_of_response_file(objects_rsp ${target} objects) + target_link_options(${cmakeTarget} PRIVATE /DELAYLOAD:mf.dll /DELAYLOAD:mfplat.dll /DELAYLOAD:mfreadwrite.dll) target_link_options(${cmakeTarget} PRIVATE "$<$<CONFIG:${config}>:@${objects_rsp}>") if(NOT completeStatic) get_copy_of_response_file(archives_rsp ${target} archives) @@ -452,7 +467,7 @@ function(extend_cmake_target target buildDir completeStatic) endif() endfunction() -function(add_rsp_command target buildDir completeStatic) +function(add_intermediate_archive target buildDir completeStatic) get_target_property(config ${target} CONFIG) get_target_property(arch ${target} ARCH) get_target_property(ninjaTarget ${target} NINJA_TARGET) @@ -493,13 +508,15 @@ function(add_rsp_command target buildDir completeStatic) ) endfunction() -function(add_ios_rsp_command target buildDir completeStatic) +function(add_intermediate_object target buildDir completeStatic) get_target_property(config ${target} CONFIG) get_target_property(arch ${target} ARCH) get_target_property(ninjaTarget ${target} NINJA_TARGET) get_target_property(cmakeTarget ${target} CMAKE_TARGET) string(TOUPPER ${config} cfg) - get_ios_target_triple_and_sysroot(args ${arch}) + if(IOS) + get_ios_target_triple_and_sysroot(args ${arch}) + endif() set(objects_rsp "${buildDir}/${ninjaTarget}_objects.rsp") set(objects_out "${buildDir}/${cmakeTarget}_objects.o") add_custom_command( @@ -628,8 +645,10 @@ function(get_v8_arch result targetArch hostArch) set(${result} "mipsel" PARENT_SCOPE) elseif(hostArch STREQUAL "mipsel64") set(${result} "mipsel" PARENT_SCOPE) + elseif(hostArch IN_LIST list32) + set(${result} "${hostArch}" PARENT_SCOPE) else() - message(DEBUG "Unsupported architecture: ${hostArch}") + message(FATAL_ERROR "Unsupported architecture: ${hostArch}") endif() else() # assume 64bit target which matches 64bit host @@ -1081,11 +1100,17 @@ function(add_gn_build_aritfacts_to_target cmakeTarget ninjaTarget module buildDi LINK_DEPENDS ${buildDir}/${config}/${arch}/${ninjaTarget}.stamp ) if(QT_IS_MACOS_UNIVERSAL) - add_rsp_command(${target} ${buildDir}/${config}/${arch} ${completeStatic}) + add_intermediate_archive(${target} ${buildDir}/${config}/${arch} ${completeStatic}) elseif(IOS) - add_ios_rsp_command(${target} ${buildDir}/${config}/${arch} ${completeStatic}) + add_intermediate_object(${target} ${buildDir}/${config}/${arch} ${completeStatic}) else() - extend_cmake_target(${target} ${buildDir}/${config}/${arch} ${completeStatic}) + if(MACOS AND QT_FEATURE_static) + # mac archiver does not support @file notation, do intermediate object istead + add_intermediate_object(${target} ${buildDir}/${config}/${arch} ${completeStatic}) + add_archiver_options(${target} ${buildDir}/${config}/${arch} ${completeStatic}) + else() + add_linker_options(${target} ${buildDir}/${config}/${arch} ${completeStatic}) + endif() endif() unset(target) endforeach() diff --git a/coin/module_config.yaml b/coin/module_config.yaml index 01da49996..f1d69a277 100644 --- a/coin/module_config.yaml +++ b/coin/module_config.yaml @@ -4,6 +4,12 @@ accept_configuration: property: features not_contains_value: Disable +machine_type: + Build: + cores: 8 + Test: + cores: 4 + instructions: Build: - type: EnvironmentVariable diff --git a/conanfile.py b/conanfile.py index 9e2685877..6cf05b5d3 100644 --- a/conanfile.py +++ b/conanfile.py @@ -33,10 +33,29 @@ from typing import Dict, Any _qtwebengine_features = [ "qtpdf-build", + "qtpdf-quick-build", + "qtpdf-widgets-build", "qtwebengine-build", + "qtwebengine-core-build", "qtwebengine-quick-build", "qtwebengine-widgets-build", "webengine-developer-build", + "webengine-embedded-build", + "webengine-extensions", + "webengine-full-debug-info", + "webengine-jumbo-build", + "webengine-kerberos", + "webengine-native-spellchecker", + "webengine-pepper-plugins", + "webengine-printing-and-pdf", + "webengine-proprietary-codecs", + "webengine-sanitizer", + "webengine-spellchecker", + "webengine-webchannel", + "webengine-webrtc", + "webengine-webrtc-pipewire", + "system-webengine-ffmpeg", + "system-webengine-icu", ] @@ -76,3 +95,20 @@ class QtWebEngine(ConanFile): def get_qt_leaf_module_default_options(self) -> Dict[str, Any]: """Implements abstractmethod from qt-conan-common.QtLeafModule""" return self._shared.convert_qt_features_to_default_conan_options(_qtwebengine_features) + + def package_env_info(self) -> Dict[str, Any]: + """Implements abstractmethod from qt-conan-common.QtLeafModule""" + # this will be called only after a successful build + _f = lambda p: True + if tools.os_info.is_windows: + ptrn = "**/QtWebEngineProcess.exe" + elif tools.os_info.is_macos: + ptrn = "**/QtWebEngineProcess.app/**/QtWebEngineProcess" + _f = lambda p: not any(".dSYM" in item for item in p.parts) + else: + ptrn = "**/QtWebEngineProcess" + ret = [str(p) for p in Path(self.package_folder).rglob(ptrn) if p.is_file() and _f(p)] + if len(ret) != 1: + print("Expected to find one 'QtWebEngineProcess'. Found: {0}".format(ret)) + return {"QTWEBENGINEPROCESS_PATH": ret.pop() if ret else ""} + diff --git a/configure.cmake b/configure.cmake index 89f8cc07a..6124dd1dc 100644 --- a/configure.cmake +++ b/configure.cmake @@ -373,7 +373,6 @@ qt_feature("webengine-qt-libjpeg" PRIVATE AND TARGET Qt::Gui AND QT_FEATURE_jpeg AND NOT QT_FEATURE_system_jpeg - AND FALSE # FIXME requires qtbase dep update ) qt_feature("webengine-system-harfbuzz" PRIVATE LABEL "harfbuzz" diff --git a/dependencies.yaml b/dependencies.yaml index 57ebaa507..fe7bc5e2a 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -1,13 +1,13 @@ dependencies: ../qtdeclarative: - ref: 5233b0630496130b89a1bbaeba7c6cd46ed879e4 + ref: 17af1433bfab54091051fa2b336a4c0866d4cc14 required: true ../qtpositioning: - ref: a27e2d1abaca86011ccfaf544b393b848eefadd2 + ref: 263c64a5cf5ccb68cfb1ba3060a87b8aa43d099c required: false ../qttools: - ref: beb81aec75f5548136b24eb1412131063b2cefee + ref: e24042be0fd018e40b8746d8d8f311fab034df3e required: false ../qtwebchannel: - ref: 88f76a364df3818bcb4c397e6bd1abec96d75e34 + ref: 2090e6b7e89c5b387b8233afbf71cc44d0442090 required: false diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp index b9d746de7..a3c7bec48 100644 --- a/examples/webenginewidgets/simplebrowser/browserwindow.cpp +++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp @@ -153,7 +153,11 @@ QSize BrowserWindow::sizeHint() const QMenu *BrowserWindow::createFileMenu(TabWidget *tabWidget) { QMenu *fileMenu = new QMenu(tr("&File")); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) fileMenu->addAction(tr("&New Window"), QKeySequence::New, this, &BrowserWindow::handleNewWindowTriggered); +#else + fileMenu->addAction(tr("&New Window"), this, &BrowserWindow::handleNewWindowTriggered, QKeySequence::New); +#endif fileMenu->addAction(tr("New &Incognito Window"), this, &BrowserWindow::handleNewIncognitoWindowTriggered); QAction *newTabAction = new QAction(tr("New &Tab"), this); @@ -164,7 +168,11 @@ QMenu *BrowserWindow::createFileMenu(TabWidget *tabWidget) }); fileMenu->addAction(newTabAction); +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) fileMenu->addAction(tr("&Open File..."), QKeySequence::Open, this, &BrowserWindow::handleFileOpenTriggered); +#else + fileMenu->addAction(tr("&Open File..."), this, &BrowserWindow::handleFileOpenTriggered, QKeySequence::Open); +#endif fileMenu->addSeparator(); QAction *closeTabAction = new QAction(tr("&Close Tab"), this); diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp index 268ad9a34..044e456b7 100644 --- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp +++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp @@ -115,7 +115,11 @@ void TabWidget::handleCurrentChanged(int index) void TabWidget::handleContextMenuRequested(const QPoint &pos) { QMenu menu; +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) menu.addAction(tr("New &Tab"), QKeySequence::AddTab, this, &TabWidget::createTab); +#else + menu.addAction(tr("New &Tab"), this, &TabWidget::createTab, QKeySequence::AddTab); +#endif int index = tabBar()->tabAt(pos); if (index != -1) { QAction *action = menu.addAction(tr("Clone Tab")); diff --git a/src/3rdparty b/src/3rdparty -Subproject 5cd4e9af5765778abc0380fc0fc6e06c43fcdfe +Subproject cee5373e6119a7ee20ba5e941185f4a22104d46 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 921871bee..eef368ddb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,6 +144,9 @@ if(NOT Gn_FOUND) if(QT_FEATURE_qtpdf_build) add_dependencies(run_pdf_GnReady gn) endif() +endif() + +if(NOT Gn_FOUND OR Gn_EXECUTABLE MATCHES "^${installDir}") set(INSTALL_GN 1 CACHE INTERNAL "") endif() @@ -188,5 +191,22 @@ if((LINUX OR MACOS) AND INSTALL_GN) CONFIGURATIONS ${installConfig} RUNTIME DESTINATION "${INSTALL_LIBEXECDIR}" ) + if(NOT QT_WILL_INSTALL) + add_custom_target(copy-gn ALL DEPENDS + ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/gn + ) + if(Gn_FOUND) + set(copyDep ${Gn_EXECUTABLE}) + else() + set(copyDep gn) + endif() + add_custom_command( + OUTPUT ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/gn + COMMAND ${CMAKE_COMMAND} -E copy ${installDir}/bin/gn + ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR} + DEPENDS ${copyDep} + USES_TERMINAL + ) + endif() endif() diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9fd27d877..9e6370260 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -303,6 +303,10 @@ foreach(arch ${archs}) CONDITION QT_FEATURE_webengine_printing_and_pdf ) extend_gn_list(gnArgArg + ARGS use_cups + CONDITION QT_FEATURE_webengine_printing_and_pdf AND NOT WIN32 + ) + extend_gn_list(gnArgArg ARGS enable_plugins CONDITION QT_FEATURE_webengine_pepper_plugins ) diff --git a/src/core/api/configure.cmake b/src/core/api/configure.cmake index 375aee727..e2543cfac 100644 --- a/src/core/api/configure.cmake +++ b/src/core/api/configure.cmake @@ -81,7 +81,8 @@ qt_feature("webengine-printing-and-pdf" PRIVATE LABEL "Printing and PDF" PURPOSE "Provides printing and output to PDF." AUTODETECT NOT QT_FEATURE_webengine_embedded_build - CONDITION TARGET Qt::PrintSupport AND QT_FEATURE_printer AND (CUPS_FOUND OR NOT LINUX) + CONDITION TARGET Qt::PrintSupport AND QT_FEATURE_printer AND + (CUPS_FOUND OR WIN32) ) qt_feature("webengine-webchannel" PUBLIC SECTION "WebEngine" diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index 5215f7ce7..fc4e23963 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -233,7 +233,10 @@ static void initialize() #if QT_CONFIG(opengl) if (QCoreApplication::instance()) { // On window/ANGLE, calling QtWebEngineQuick::initialize from DllMain will result in a crash. - if (!qt_gl_global_share_context()) { + if (!qt_gl_global_share_context() && + !(QCoreApplication::testAttribute(Qt::AA_ShareOpenGLContexts) && + QQuickWindow::graphicsApi() == QSGRendererInterface::OpenGLRhi) + ) { qWarning("Qt WebEngine seems to be initialized from a plugin. Please " "set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute and " "QSGRendererInterface::OpenGLRhi using QQuickWindow::setGraphicsApi " diff --git a/src/core/api/qwebengineprofile.cpp b/src/core/api/qwebengineprofile.cpp index 5e48f4dd1..85ae00501 100644 --- a/src/core/api/qwebengineprofile.cpp +++ b/src/core/api/qwebengineprofile.cpp @@ -183,6 +183,8 @@ QWebEngineProfilePrivate::~QWebEngineProfilePrivate() if (m_profileAdapter != QtWebEngineCore::ProfileAdapter::defaultProfileAdapter()) delete m_profileAdapter; + else if (m_profileAdapter) + m_profileAdapter->releaseAllWebContentsAdapterClients(); delete m_settings; } diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index 7b4a02647..b3f0c6fa2 100644 --- a/src/core/browser_accessibility_qt.cpp +++ b/src/core/browser_accessibility_qt.cpp @@ -802,12 +802,13 @@ void BrowserAccessibilityInterface::init() { if (m_id) return; - Q_ASSERT(parent()); - Q_ASSERT(parent()->object()); - m_object = new QObject(parent()->object()); - QString name = toQt(q->GetAuthorUniqueId()); - if (!name.isEmpty()) - m_object->setObjectName(name); + + if (parent() && parent()->object()) { + m_object = new QObject(parent()->object()); + QString name = toQt(q->GetAuthorUniqueId()); + if (!name.isEmpty()) + m_object->setObjectName(name); + } m_id = QAccessible::registerAccessibleInterface(this); } diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp index 4be528f58..7a5ea3737 100644 --- a/src/core/chromium_overrides.cpp +++ b/src/core/chromium_overrides.cpp @@ -37,10 +37,11 @@ ** ****************************************************************************/ +#include "type_conversion.h" #include "ozone/gl_context_qt.h" #include "qtwebenginecoreglobal_p.h" #include "web_contents_view_qt.h" - +#include "web_engine_library_info.h" #include "base/values.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -92,14 +93,20 @@ WebContentsView* CreateWebContentsView(WebContentsImpl *web_contents, return rv; } -#if defined(Q_OS_MACOS) -std::string getQtPrefix() +#if defined(OS_MAC) +#if defined(QT_MAC_FRAMEWORK_BUILD) +base::FilePath getSandboxPath() +{ + return WebEngineLibraryInfo::getPath(QT_FRAMEWORK_BUNDLE); +} +#else +base::FilePath getSandboxPath() { const QString prefix = QLibraryInfo::location(QLibraryInfo::PrefixPath); - return prefix.toStdString(); + return QtWebEngineCore::toFilePath(prefix); } #endif - +#endif } // namespace content #if defined(USE_AURA) || defined(USE_OZONE) diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 6201bab27..f6ecb31b4 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -823,10 +823,6 @@ static bool navigationThrottleCallback(content::WebContents *source, if (params.is_external_protocol() && !profile->profileAdapter()->urlSchemeHandler(toQByteArray(params.url().scheme()))) return false; - WebContentsViewQt *view = WebContentsViewQt::from(static_cast<content::WebContentsImpl *>(source)->GetView()); - if (!view->client()) - return false; - bool navigationAccepted = true; WebContentsAdapterClient *client = diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index 90e604e7b..6f7a6c785 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -53,6 +53,7 @@ #include "extensions/common/constants.h" #include "media/base/media_switches.h" #include "media/base/video_codecs.h" +#include "media/cdm/supported_audio_codecs.h" #include "media/media_buildflags.h" #include "ui/base/layout.h" #include "ui/base/l10n/l10n_util.h" @@ -250,15 +251,56 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path, } } #elif defined(Q_OS_LINUX) - pluginPaths << QStringLiteral("/opt/google/chrome/libwidevinecdm.so") // Old Google Chrome + QList<QDir> potentialWidevineVersionDirs; + + // Google Chrome widevine modules + QDir chromeWidevineDir(QDir::homePath() + "/.config/google-chrome/WidevineCdm"); + if (chromeWidevineDir.exists()) + potentialWidevineVersionDirs << chromeWidevineDir; + + // Firefox widevine modules + QDir firefoxPotentialProfilesDir(QDir::homePath() + "/.mozilla/firefox"); + if (firefoxPotentialProfilesDir.exists()) { + QFileInfoList firefoxProfileDirs = firefoxPotentialProfilesDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed); + for (const QFileInfo &info : firefoxProfileDirs) { + QDir widevinePluginsDir(info.absoluteFilePath() + "/gmp-widevinecdm"); + if (widevinePluginsDir.exists()) + potentialWidevineVersionDirs << widevinePluginsDir; + } + } + + // Chromium widevine modules (might not work with proprietary codecs) + QDir chromiumWidevineDir(QDir::homePath() + "/.config/chromium/WidevineCdm"); + if (chromiumWidevineDir.exists()) + potentialWidevineVersionDirs << chromiumWidevineDir; + + // Search for widewine versions + for (const QDir &dir : potentialWidevineVersionDirs) { + QFileInfoList widevineVersionDirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed); + // ### alternatively look up in the manifest.json and take the path from there. #if Q_PROCESSOR_WORDSIZE == 8 - << QStringLiteral("/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so") + const QString library = QLatin1String("/_platform_specific/linux_x64/libwidevinecdm.so"); #else - << QStringLiteral("/opt/google/chrome/WidevineCdm/_platform_specific/linux_x86/libwidevinecdm.so") + const QString library = QLatin1String("/_platform_specific/linux_x86/libwidevinecdm.so"); #endif - << QStringLiteral("/usr/lib/chromium/libwidevinecdm.so") // Arch + for (const QFileInfo &info : widevineVersionDirs) { + pluginPaths << info.absoluteFilePath() + "/libwidevinecdm.so"; + pluginPaths << info.absoluteFilePath() + library; + } + } + + // Fixed paths: + pluginPaths << QStringLiteral("/usr/lib/chromium/libwidevinecdm.so") // Arch << QStringLiteral("/usr/lib/chromium-browser/libwidevinecdm.so") // Ubuntu/neon - << QStringLiteral("/usr/lib64/chromium/libwidevinecdm.so"); // OpenSUSE style + << QStringLiteral("/usr/lib64/chromium/libwidevinecdm.so") // OpenSUSE style +#if Q_PROCESSOR_WORDSIZE == 8 + << QStringLiteral("/usr/lib64/chromium-browser/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so") // Gentoo + << QStringLiteral("/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so") // Old Google Chrome +#else + << QStringLiteral("/usr/lib/chromium-browser/WidevineCdm/_platform_specific/linux_x86/libwidevinecdm.so") // Gentoo + << QStringLiteral("/opt/google/chrome/WidevineCdm/_platform_specific/linux_x86/libwidevinecdm.so") // Old Google Chrome +#endif + << QStringLiteral("/opt/google/chrome/libwidevinecdm.so"); // Older Google Chrome #endif } @@ -274,6 +316,7 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path, #if BUILDFLAG(USE_PROPRIETARY_CODECS) capability->video_codecs.emplace(media::VideoCodec::kCodecH264, kAllProfiles); #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) + capability->audio_codecs = media::GetCdmSupportedAudioCodecs(); // Add the supported encryption schemes as if they came from the // component manifest. This list must match the CDM that is being diff --git a/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc b/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc index 43421bafb..ba23c8887 100644 --- a/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc +++ b/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc @@ -35,6 +35,6 @@ QT += webenginecore //! [1] //! [2] -find_package(Qt6 COMPONENTS WebEngineCore REQUIRED) +find_package(Qt6 REQUIRED COMPONENTS WebEngineCore) target_link_libraries(target PRIVATE Qt::WebEngineCore) //! [2] diff --git a/src/core/doc/src/qtwebengine-deploying.qdoc b/src/core/doc/src/qtwebengine-deploying.qdoc index 7b9f3fd4a..505d38e62 100644 --- a/src/core/doc/src/qtwebengine-deploying.qdoc +++ b/src/core/doc/src/qtwebengine-deploying.qdoc @@ -129,8 +129,12 @@ \li On Linux and Windows: the \c resources directory in the directory specified by QLibraryInfo::location(QLibraryInfo::DataPath) \li On \macos: \c .app/Content/Resources + \li The application directory specified by QCoreApplication::applicationDirPath() \endlist + Alternatively, a resources directory path can be set as a value of the + \c QTWEBENGINE_RESOURCES_PATH environment variable. + \section2 Translations Locale data (such as \c en-US.pak) is searched form the following locations: @@ -142,6 +146,9 @@ QLibraryInfo::location(QLibraryInfo::TranslationsPath) \endlist + Alternatively, a locales directory path can be set as a value of the + \c QTWEBENGINE_LOCALES_PATH environment variable. + \section2 JavaScript Files in Qt Resource Files If your WebEngine application is built using the Qt Quick Compiler, and the application ships diff --git a/src/core/doc/src/qtwebengine-platform-notes.qdoc b/src/core/doc/src/qtwebengine-platform-notes.qdoc index d13fb2471..7c8f4d472 100644 --- a/src/core/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/core/doc/src/qtwebengine-platform-notes.qdoc @@ -35,7 +35,7 @@ Static builds are not supported. - The requirements for building Qt 5 modules from source are listed separately for each supported + The requirements for building Qt modules from source are listed separately for each supported platform: \list @@ -78,14 +78,15 @@ \QWE can only be built on 64-bit Windows, with a x64-bit toolchain. For building \QWE for x86 applications, you need to configure - and compile Qt with the Visual Studio 2017 x64 to x86 cross-compile + and compile Qt with the Visual Studio x64 to x86 cross-compile toolchain. This toolchain can be set up on the command line by running \c{vcvarsall.bat amd64_x86}. + \note It is not recommended to use tools form \c msys2 or \c cygwin to build \QWE as it may result in build errors. + \section2 Linux On Linux, Clang or GCC version 9 or later is required. - Supported QMake configurations are \c linux-g++, \c{linux-clang} and \c{linux-clang-libc++} \QWE requires \c pkg-config to detect most of its dependencies. The following \c pkg-config files are required: @@ -219,7 +220,7 @@ Due to some limitations, the Linux QPA plugin almost always reports that accessibility should be activated. On big HTML pages, this can cause a significant slowdown in rendering speed. - Because of that, from Qt 5.9 onwards, \QWE accessibility support is disabled by default + Because of that, \QWE accessibility support is disabled by default on Linux. It can be re-enabled by setting the \c QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment variable to a non-empty value. diff --git a/src/core/doc/src/qwebenginesettings_lgpl.qdoc b/src/core/doc/src/qwebenginesettings_lgpl.qdoc index 6a7f1f958..01965c7a3 100644 --- a/src/core/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/core/doc/src/qwebenginesettings_lgpl.qdoc @@ -97,7 +97,8 @@ Enables support for the HTML 5 local storage feature. Enabled by default. \value LocalContentCanAccessRemoteUrls Allows local origin documents to access remote resources that would normally be blocked. - Disabled by default. + Disabled by default. Note DnsPrefetchEnabled below operates independently of this setting, + and can if enabled, cause remote accesses from local content. \value XSSAuditingEnabled Obsolete and has no effect. \value SpatialNavigationEnabled diff --git a/src/core/favicon_driver_qt.cpp b/src/core/favicon_driver_qt.cpp index 73c79fc1f..be5f7267e 100644 --- a/src/core/favicon_driver_qt.cpp +++ b/src/core/favicon_driver_qt.cpp @@ -300,15 +300,15 @@ void FaviconDriverQt::DidStartNavigation(content::NavigationHandle *navigation_h return; m_faviconUrls.reset(); - m_completedHandlersCount = 0; - m_latestFavicon = FaviconStatusQt(); if (!navigation_handle->IsSameDocument()) { + m_completedHandlersCount = 0; + m_latestFavicon = FaviconStatusQt(); m_documentOnLoadCompleted = false; m_manifestUrl = GURL(); - } - m_viewClient->iconChanged(QUrl()); + m_viewClient->iconChanged(QUrl()); + } content::ReloadType reload_type = navigation_handle->GetReloadType(); if (reload_type == content::ReloadType::NONE || IsOffTheRecord()) diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp index 140cb7dba..a40aefe49 100644 --- a/src/core/file_picker_controller.cpp +++ b/src/core/file_picker_controller.cpp @@ -245,6 +245,10 @@ void FilePickerController::filesSelectedInChooser(const QStringList &filesList) else d_ptr->fileSystemAccessDialogListener->MultiFilesSelected(files, nullptr); } + + // release the fileSelectListener manually because it blocks fullscreen requests in chromium + // see QTBUG-106975 + d_ptr->fileDialogListener.reset(); } QStringList FilePickerController::acceptedMimeTypes() const diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index c976798ae..9a3295363 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -181,7 +181,7 @@ content::DesktopMediaID getDefaultScreenId() GetMonitorsFunc getMonitors = reinterpret_cast<GetMonitorsFunc>(dlsym(RTLD_DEFAULT, "XRRGetMonitors")); typedef void (*FreeMonitorsFunc)(XRRMonitorInfo*); FreeMonitorsFunc freeMonitors = reinterpret_cast<FreeMonitorsFunc>(dlsym(RTLD_DEFAULT, "XRRFreeMonitors")); - if (!getMonitors && !freeMonitors) { + if (!getMonitors || !freeMonitors) { qWarning("Unable to link XRandR monitor functions."); return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0); } diff --git a/src/core/native_web_keyboard_event_qt.cpp b/src/core/native_web_keyboard_event_qt.cpp index c90b3c9e8..9942ecf17 100644 --- a/src/core/native_web_keyboard_event_qt.cpp +++ b/src/core/native_web_keyboard_event_qt.cpp @@ -70,28 +70,31 @@ using blink::WebKeyboardEvent; namespace content { -NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebKeyboardEvent const&, gfx::NativeView) - : os_event(0) +NativeWebKeyboardEvent::NativeWebKeyboardEvent(const blink::WebKeyboardEvent &web_event, gfx::NativeView) + : WebKeyboardEvent(web_event) + , os_event(nullptr) , skip_in_browser(false) { } -NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type, int, base::TimeTicks) - : os_event(0) +NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type type, int modifiers, + base::TimeTicks timestamp) + : WebKeyboardEvent(type, modifiers, timestamp) + , os_event(nullptr) , skip_in_browser(false) { } NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event) - : os_event(CopyEvent(native_event)), - skip_in_browser(false) + : os_event(CopyEvent(native_event)) + , skip_in_browser(false) { } NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& other) - : WebKeyboardEvent(other), - os_event(CopyEvent(other.os_event)), - skip_in_browser(other.skip_in_browser) + : WebKeyboardEvent(other) + , os_event(CopyEvent(other.os_event)) + , skip_in_browser(other.skip_in_browser) { } diff --git a/src/core/net/custom_url_loader_factory.cpp b/src/core/net/custom_url_loader_factory.cpp index 6cb272b1c..892f21dac 100644 --- a/src/core/net/custom_url_loader_factory.cpp +++ b/src/core/net/custom_url_loader_factory.cpp @@ -326,15 +326,14 @@ private: m_client->OnStartLoadingResponseBody(std::move(m_pipeConsumerHandle)); m_head = nullptr; - if (readAvailableData()) // May delete this - return; - m_watcher = std::make_unique<mojo::SimpleWatcher>( - FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC, m_taskRunner); + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, m_taskRunner); m_watcher->Watch(m_pipeProducerHandle.get(), MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_WATCH_CONDITION_SATISFIED, base::BindRepeating(&CustomURLLoader::notifyReadyWrite, m_weakPtrFactory.GetWeakPtr())); + + readAvailableData(); // May delete this } void notifyCanceled() override { @@ -402,8 +401,10 @@ private: uint32_t bufferSize = 0; MojoResult beginResult = m_pipeProducerHandle->BeginWriteData( &buffer, &bufferSize, MOJO_BEGIN_WRITE_DATA_FLAG_NONE); - if (beginResult == MOJO_RESULT_SHOULD_WAIT) + if (beginResult == MOJO_RESULT_SHOULD_WAIT) { + m_watcher->ArmOrNotify(); return false; // Wait for pipe watcher + } if (beginResult != MOJO_RESULT_OK) break; if (m_maxBytesToRead > 0 && m_maxBytesToRead <= int64_t{std::numeric_limits<uint32_t>::max()}) @@ -415,13 +416,20 @@ private: m_totalBytesRead += bytesRead; m_client->OnTransferSizeUpdated(m_totalBytesRead); - if (m_device->atEnd() || (m_maxBytesToRead > 0 && m_totalBytesRead >= m_maxBytesToRead)) { + const bool deviceAtEnd = m_device->atEnd(); + if ((deviceAtEnd && !m_device->isSequential()) + || (m_maxBytesToRead > 0 && m_totalBytesRead >= m_maxBytesToRead)) { OnTransferComplete(MOJO_RESULT_OK); return true; // Done with reading } if (readResult == 0) return false; // Wait for readyRead + if (readResult < 0 && deviceAtEnd && m_device->isSequential()) { + // Failure on read, and sequential device claiming to be at end, so treat it as a successful end-of-data. + OnTransferComplete(MOJO_RESULT_OK); + return true; // Done with reading + } if (readResult < 0) break; } diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp index 39630cf2d..ba2051d60 100644 --- a/src/core/net/proxying_url_loader_factory_qt.cpp +++ b/src/core/net/proxying_url_loader_factory_qt.cpp @@ -280,10 +280,23 @@ void InterceptedRequest::Restart() // Check if non-local access is allowed if (!allow_remote_ && remote_access_) { - target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED)); - delete this; - return; + bool granted_special_access = false; + switch (ui::PageTransition(request_.transition_type)) { + case ui::PAGE_TRANSITION_LINK: + case ui::PAGE_TRANSITION_TYPED: + if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame && request_.has_user_gesture) + granted_special_access = true; // allow normal explicit navigation + break; + default: + break; + } + if (!granted_special_access) { + target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED)); + delete this; + return; + } } + // Check if local access is allowed if (!allow_local_ && local_access_) { bool granted_special_access = false; diff --git a/src/core/net/qrc_url_scheme_handler.cpp b/src/core/net/qrc_url_scheme_handler.cpp index 73bf24f1d..0a9943431 100644 --- a/src/core/net/qrc_url_scheme_handler.cpp +++ b/src/core/net/qrc_url_scheme_handler.cpp @@ -67,7 +67,10 @@ void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job) QFileInfo fileInfo(*file); QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileInfo); - job->reply(mimeType.name().toUtf8(), file.take()); + if (mimeType.name() == QStringLiteral("application/x-extension-html")) + job->reply("text/html", file.take()); + else + job->reply(mimeType.name().toUtf8(), file.take()); } } // namespace QtWebEngineCore diff --git a/src/core/net/system_network_context_manager.cpp b/src/core/net/system_network_context_manager.cpp index 962266d78..f6e7cb630 100644 --- a/src/core/net/system_network_context_manager.cpp +++ b/src/core/net/system_network_context_manager.cpp @@ -292,7 +292,15 @@ void SystemNetworkContextManager::ConfigureDefaultNetworkContextParams(network:: // respect prefs::kEnableReferrers from the appropriate pref store. network_context_params->enable_referrers = false; - network_context_params->proxy_resolver_factory = ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver(); + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + if (command_line.HasSwitch(switches::kSingleProcess)) { + LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode."; + } else { + network_context_params->proxy_resolver_factory = + ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver(); + } // Use the SystemNetworkContextManager to populate and update SSL // configuration. The SystemNetworkContextManager is owned by the diff --git a/src/core/ozone/gl_surface_egl_qt.cpp b/src/core/ozone/gl_surface_egl_qt.cpp index f7d162923..52ab53c38 100644 --- a/src/core/ozone/gl_surface_egl_qt.cpp +++ b/src/core/ozone/gl_surface_egl_qt.cpp @@ -144,12 +144,12 @@ void GLSurfaceEGL::ShutdownOneOff() const char *GLSurfaceEGL::GetEGLClientExtensions() { - return GLSurfaceQt::g_client_extensions; + return GLSurfaceQt::g_client_extensions.c_str(); } const char *GLSurfaceEGL::GetEGLExtensions() { - return GLSurfaceQt::g_extensions; + return GLSurfaceQt::g_extensions.c_str(); } bool GLSurfaceEGL::HasEGLClientExtension(const char *name) @@ -223,7 +223,7 @@ bool GLSurfaceEGLQt::InitializeOneOff() g_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); g_extensions = eglQueryString(g_display, EGL_EXTENSIONS); - g_egl_surfaceless_context_supported = ExtensionsContain(g_extensions, "EGL_KHR_surfaceless_context"); + g_egl_surfaceless_context_supported = ExtensionsContain(g_extensions.c_str(), "EGL_KHR_surfaceless_context"); if (g_egl_surfaceless_context_supported) { scoped_refptr<GLSurface> surface = new GLSurfacelessQtEGL(gfx::Size(1, 1)); gl::GLContextAttribs attribs; diff --git a/src/core/ozone/gl_surface_glx_qt.cpp b/src/core/ozone/gl_surface_glx_qt.cpp index 5ccf5037a..79a084941 100644 --- a/src/core/ozone/gl_surface_glx_qt.cpp +++ b/src/core/ozone/gl_surface_glx_qt.cpp @@ -54,7 +54,7 @@ void GLSurfaceGLX::ShutdownOneOff() bool GLSurfaceGLX::IsCreateContextSupported() { - return ExtensionsContain(GLSurfaceQt::g_extensions, "GLX_ARB_create_context"); + return HasGLXExtension("GLX_ARB_create_context"); } bool GLSurfaceGLX::IsCreateContextRobustnessSupported() @@ -79,7 +79,7 @@ bool GLSurfaceGLX::IsCreateContextProfileSupported() bool GLSurfaceGLX::IsCreateContextES2ProfileSupported() { - return ExtensionsContain(GLSurfaceQt::g_extensions, "GLX_ARB_create_context_es2_profile"); + return HasGLXExtension("GLX_ARB_create_context_es2_profile"); } bool GLSurfaceGLX::IsOMLSyncControlSupported() @@ -89,12 +89,12 @@ bool GLSurfaceGLX::IsOMLSyncControlSupported() bool GLSurfaceGLX::HasGLXExtension(const char *name) { - return ExtensionsContain(GLSurfaceQt::g_extensions, name); + return ExtensionsContain(GLSurfaceQt::g_extensions.c_str(), name); } bool GLSurfaceGLX::IsTextureFromPixmapSupported() { - return ExtensionsContain(GLSurfaceQt::g_extensions, "GLX_EXT_texture_from_pixmap"); + return HasGLXExtension("GLX_EXT_texture_from_pixmap"); } bool GLSurfaceGLX::IsRobustnessVideoMemoryPurgeSupported() @@ -104,7 +104,7 @@ bool GLSurfaceGLX::IsRobustnessVideoMemoryPurgeSupported() const char* GLSurfaceGLX::GetGLXExtensions() { - return GLSurfaceQt::g_extensions; + return GLSurfaceQt::g_extensions.c_str(); } @@ -162,7 +162,7 @@ bool GLSurfaceGLXQt::InitializeExtensionSettingsOneOff() Display* display = static_cast<Display*>(g_display); GLSurfaceQt::g_extensions = glXQueryExtensionsString(display, 0); - g_driver_glx.InitializeExtensionBindings(g_extensions); + g_driver_glx.InitializeExtensionBindings(g_extensions.c_str()); return true; } diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp index 8af3bd3c1..9bf16c960 100644 --- a/src/core/ozone/gl_surface_qt.cpp +++ b/src/core/ozone/gl_surface_qt.cpp @@ -64,8 +64,8 @@ namespace gl { void *GLSurfaceQt::g_display = nullptr; void *GLSurfaceQt::g_config = nullptr; -const char *GLSurfaceQt::g_client_extensions = nullptr; -const char *GLSurfaceQt::g_extensions = nullptr; +std::string GLSurfaceQt::g_client_extensions; +std::string GLSurfaceQt::g_extensions; GLSurfaceQt::~GLSurfaceQt() { @@ -86,7 +86,7 @@ GLSurfaceQt::GLSurfaceQt(const gfx::Size& size) bool GLSurfaceQt::HasEGLExtension(const char* name) { - return ExtensionsContain(g_extensions, name); + return ExtensionsContain(g_extensions.c_str(), name); } bool GLSurfaceQt::IsOffscreen() diff --git a/src/core/ozone/gl_surface_qt.h b/src/core/ozone/gl_surface_qt.h index 055b27875..8689c3a19 100644 --- a/src/core/ozone/gl_surface_qt.h +++ b/src/core/ozone/gl_surface_qt.h @@ -37,11 +37,11 @@ ** ****************************************************************************/ - - #ifndef GL_SURFACE_QT_H_ #define GL_SURFACE_QT_H_ +#include <string> + #include "ui/gfx/geometry/size.h" #include "ui/gl/gl_surface.h" @@ -71,8 +71,8 @@ protected: public: static void* g_config; static void* g_display; - static const char* g_extensions; - static const char* g_client_extensions; + static std::string g_extensions; + static std::string g_client_extensions; private: DISALLOW_COPY_AND_ASSIGN(GLSurfaceQt); diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index 6e902ff5a..8d2138867 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -39,7 +39,9 @@ #include "profile_adapter.h" +#include "base/files/file_util.h" #include "base/task/cancelable_task_tracker.h" +#include "base/time/time_to_iso8601.h" #include "components/favicon/core/favicon_service.h" #include "components/history/content/browser/history_database_helper.h" #include "components/history/core/browser/history_database_params.h" @@ -48,9 +50,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/download_manager.h" -#include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/browser/storage_partition.h" -#include "services/network/public/cpp/cors/origin_access_list.h" #include "services/network/public/mojom/network_context.mojom.h" #include "url/url_util.h" @@ -65,12 +65,8 @@ #include "renderer_host/user_resource_controller_host.h" #include "type_conversion.h" #include "visited_links_manager_qt.h" -#include "web_engine_context.h" #include "web_contents_adapter_client.h" - -#include "base/files/file_util.h" -#include "base/time/time_to_iso8601.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "web_engine_context.h" #if BUILDFLAG(ENABLE_EXTENSIONS) #include "extensions/browser/extension_system.h" @@ -120,9 +116,8 @@ ProfileAdapter::~ProfileAdapter() { m_cancelableTaskTracker->TryCancelAll(); m_profile->NotifyWillBeDestroyed(); - while (!m_webContentsAdapterClients.isEmpty()) { - m_webContentsAdapterClients.first()->releaseProfile(); - } + releaseAllWebContentsAdapterClients(); + WebEngineContext::current()->removeProfileAdapter(this); if (m_downloadManagerDelegate) { m_profile->GetDownloadManager()->Shutdown(); @@ -655,6 +650,12 @@ void ProfileAdapter::removeWebContentsAdapterClient(WebContentsAdapterClient *cl m_webContentsAdapterClients.removeAll(client); } +void ProfileAdapter::releaseAllWebContentsAdapterClients() +{ + while (!m_webContentsAdapterClients.isEmpty()) + m_webContentsAdapterClients.first()->releaseProfile(); +} + void ProfileAdapter::resetVisitedLinksManager() { m_visitedLinksManager.reset(new VisitedLinksManagerQt(m_profile.data(), persistVisitedLinks())); diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index 373d6e2a9..140891150 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -53,10 +53,11 @@ #include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> -#include <QEnableSharedFromThis> +#include <QHash> #include <QList> #include <QPointer> #include <QScopedPointer> +#include <QSharedPointer> #include <QString> #include <QtWebEngineCore/qwebengineclientcertificatestore.h> @@ -137,6 +138,7 @@ public: void addWebContentsAdapterClient(WebContentsAdapterClient *client); void removeWebContentsAdapterClient(WebContentsAdapterClient *client); + void releaseAllWebContentsAdapterClients(); // KEEP IN SYNC with API or add mapping layer enum HttpCacheType { diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 9727efab1..e99726d7a 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -185,14 +185,21 @@ static bool usingSupportedSGBackend() bool usingSoftwareDynamicGL() { + const char openGlVar[] = "QT_OPENGL"; if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) return true; + + if (qEnvironmentVariableIsSet(openGlVar)) { + const QByteArray requested = qgetenv(openGlVar); + if (requested == "software") + return true; + } #if defined(Q_OS_WIN) HMODULE handle = QNativeInterface::QWGLContext::openGLModuleHandle(); wchar_t path[MAX_PATH]; DWORD size = GetModuleFileName(handle, path, MAX_PATH); QFileInfo openGLModule(QString::fromWCharArray(path, size)); - return !openGLModule.fileName().compare(QLatin1String("opengl32sw.dll"),Qt::CaseInsensitive); + return openGLModule.fileName().contains(QLatin1String("opengl32sw"),Qt::CaseInsensitive); #else return false; #endif @@ -250,7 +257,7 @@ static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu) return glType; } #else -static const char *getGLType(bool enableGLSoftwareRendering) +static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu) { return gl::kGLImplementationDisabledName; } @@ -687,6 +694,8 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(sandbox::policy::switches::kNoSandbox); qInfo() << "Sandboxing disabled by user."; } + // Do not try to be clever with device-scale-factor, it messes up scaling in accessibility for us + parsedCommandLine->AppendSwitchASCII(switches::kEnableUseZoomForDSF, "false"); parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing); @@ -918,7 +927,7 @@ const char *qWebEngineChromiumVersion() noexcept } const char *qWebEngineChromiumSecurityPatchVersion() noexcept { - return "99.0.4844.84"; // FIXME: Remember to update + return "104.0.5112.81"; // FIXME: Remember to update } QT_END_NAMESPACE diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 8f580e53a..151918bd7 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -59,6 +59,7 @@ #include <QFileInfo> #include <QLibraryInfo> #include <QLocale> +#include <QLoggingCategory> #include <QStandardPaths> #if defined(OS_WIN) @@ -71,6 +72,8 @@ using namespace QtWebEngineCore; +Q_LOGGING_CATEGORY(webEngineLibraryInfoLog, "qt.webengine.libraryinfo") + namespace { QString fallbackDir() { @@ -84,7 +87,7 @@ static inline CFBundleRef frameworkBundle() return CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.QtWebEngineCore")); } -static QString getPath(CFBundleRef frameworkBundle) +static QString getBundlePath(CFBundleRef frameworkBundle) { QString path; // The following is a fix for QtWebEngineProcess crashes on OS X 10.7 and before. @@ -109,11 +112,11 @@ static QString getResourcesPath(CFBundleRef frameworkBundle) // We use it for the other OS X versions as well to make sure it works and because // the directory structure should be the same. if (qApp->applicationName() == QLatin1String(QTWEBENGINEPROCESS_NAME)) { - path = getPath(frameworkBundle) % QLatin1String("/Resources"); + path = getBundlePath(frameworkBundle) % QLatin1String("/Resources"); } else if (frameworkBundle) { CFURLRef resourcesRelativeUrl = CFBundleCopyResourcesDirectoryURL(frameworkBundle); CFStringRef resourcesRelativePath = CFURLCopyFileSystemPath(resourcesRelativeUrl, kCFURLPOSIXPathStyle); - path = getPath(frameworkBundle) % QLatin1Char('/') % QString::fromCFString(resourcesRelativePath); + path = getBundlePath(frameworkBundle) % QLatin1Char('/') % QString::fromCFString(resourcesRelativePath); CFRelease(resourcesRelativePath); CFRelease(resourcesRelativeUrl); } @@ -166,7 +169,7 @@ QString subProcessPath() candidatePaths << fromEnv; } else { #if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) - candidatePaths << getPath(frameworkBundle()) + candidatePaths << getBundlePath(frameworkBundle()) % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME); #else candidatePaths << QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) @@ -181,11 +184,25 @@ QString subProcessPath() for (const QString &candidate : qAsConst(candidatePaths)) { if (QFileInfo::exists(candidate)) { processPath = candidate; + qCDebug(webEngineLibraryInfoLog, "Qt WebEngine process path: %s", + qPrintable(candidate)); break; } } - if (processPath.isEmpty()) - qFatal("Could not find %s", processBinary.toUtf8().constData()); + if (processPath.isEmpty()) { + QStringList errorMessage; + errorMessage.append( + QStringLiteral("The following paths were searched for Qt WebEngine Process:")); + for (const QString &candidate : qAsConst(candidatePaths)) + errorMessage.append(QStringLiteral(" ") % candidate); + errorMessage.append(QStringLiteral("but could not find it.")); + if (fromEnv.isEmpty()) { + errorMessage.append( + QStringLiteral("You may override the default search path by using " + "QTWEBENGINEPROCESS_PATH environment variable.")); + } + qFatal("%s", qPrintable(errorMessage.join('\n'))); + } #if defined(OS_WIN) base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess(); @@ -203,23 +220,55 @@ QString subProcessPath() QString localesPath() { - static bool initialized = false; - static QString potentialLocalesPath = -#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) - getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_locales"); + static QString potentialLocalesPath; + if (potentialLocalesPath.isEmpty()) { + QStringList candidatePaths; + const QString translationPakFilename = +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) + QLatin1String(WebEngineLibraryInfo::getResolvedLocale() + ".pak"); #else - QLibraryInfo::path(QLibraryInfo::TranslationsPath) % QDir::separator() % QLatin1String("qtwebengine_locales"); + QLatin1String((WebEngineLibraryInfo::getResolvedLocale() + ".pak").c_str()); #endif + const QString fromEnv = qEnvironmentVariable("QTWEBENGINE_LOCALES_PATH"); + if (!fromEnv.isEmpty()) { + // Only search in QTWEBENGINE_LOCALES_PATH if set + candidatePaths << fromEnv; + } else { +#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) + candidatePaths << getResourcesPath(frameworkBundle()) % QDir::separator() + % QLatin1String("qtwebengine_locales"); +#endif + candidatePaths << QLibraryInfo::path(QLibraryInfo::TranslationsPath) % QDir::separator() + % QLatin1String("qtwebengine_locales"); + candidatePaths << fallbackDir(); + } - if (!initialized) { - initialized = true; - if (!QFileInfo::exists(potentialLocalesPath)) { - qWarning("Installed Qt WebEngine locales directory not found at location %s. Trying application directory...", qPrintable(potentialLocalesPath)); - potentialLocalesPath = QCoreApplication::applicationDirPath() % QDir::separator() % QLatin1String("qtwebengine_locales"); + for (const QString &candidate : qAsConst(candidatePaths)) { + if (QFileInfo::exists(candidate % QDir::separator() % translationPakFilename)) { + potentialLocalesPath = candidate; + qCDebug(webEngineLibraryInfoLog, "Qt WebEngine locales path: %s", + qPrintable(candidate)); + break; + } } - if (!QFileInfo::exists(potentialLocalesPath)) { - qWarning("Qt WebEngine locales directory not found at location %s. Trying fallback directory... Translations MAY NOT not be correct.", qPrintable(potentialLocalesPath)); - potentialLocalesPath = fallbackDir(); + + if (potentialLocalesPath.isEmpty()) { + QStringList warningMessage; + warningMessage.append( + QStringLiteral("The following paths were searched for Qt WebEngine locales:")); + for (const QString &candidate : qAsConst(candidatePaths)) + warningMessage.append(QStringLiteral(" ") % candidate); + warningMessage.append( + QStringLiteral( + "but could not find the translation file for the current locale: ") + % translationPakFilename); + if (fromEnv.isEmpty()) { + warningMessage.append( + QStringLiteral("You may override the default search paths by using " + "QTWEBENGINE_LOCALES_PATH environment variable.")); + } + warningMessage.append(QStringLiteral("Translations WILL NOT be correct.")); + qWarning("%s", qPrintable(warningMessage.join('\n'))); } } @@ -265,6 +314,8 @@ QString dictionariesPath() for (const QString &candidate : qAsConst(candidatePaths)) { if (QFileInfo::exists(candidate)) { potentialDictionariesPath = candidate; + qCDebug(webEngineLibraryInfoLog, "Qt WebEngine dictionaries path: %s", + qPrintable(candidate)); break; } } @@ -274,28 +325,49 @@ QString dictionariesPath() } #endif // QT_CONFIG(webengine_spellchecker) -QString resourcesDataPath() +QString resourcesPath() { - static bool initialized = false; - static QString potentialResourcesPath = + static QString potentialResourcesPath; + if (potentialResourcesPath.isEmpty()) { + QStringList candidatePaths; + const QString resourcesPakFilename = QLatin1String("qtwebengine_resources.pak"); + const QString fromEnv = qEnvironmentVariable("QTWEBENGINE_RESOURCES_PATH"); + if (!fromEnv.isEmpty()) { + // Only search in QTWEBENGINE_RESOURCES_PATH if set + candidatePaths << fromEnv; + } else { #if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) - getResourcesPath(frameworkBundle()); -#else - QLibraryInfo::path(QLibraryInfo::DataPath) % QLatin1String("/resources"); + candidatePaths << getResourcesPath(frameworkBundle()); #endif - if (!initialized) { - initialized = true; - if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { - qWarning("Qt WebEngine resources not found at %s. Trying parent directory...", qPrintable(potentialResourcesPath)); - potentialResourcesPath = QLibraryInfo::path(QLibraryInfo::DataPath); + candidatePaths << QLibraryInfo::path(QLibraryInfo::DataPath) % QDir::separator() + % QLatin1String("resources"); + candidatePaths << QLibraryInfo::path(QLibraryInfo::DataPath); + candidatePaths << QCoreApplication::applicationDirPath(); + candidatePaths << fallbackDir(); } - if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { - qWarning("Qt WebEngine resources not found at %s. Trying application directory...", qPrintable(potentialResourcesPath)); - potentialResourcesPath = QCoreApplication::applicationDirPath(); + + for (const QString &candidate : qAsConst(candidatePaths)) { + if (QFileInfo::exists(candidate % QDir::separator() % resourcesPakFilename)) { + potentialResourcesPath = candidate; + qCDebug(webEngineLibraryInfoLog, "Qt WebEngine resources path: %s", + qPrintable(candidate)); + break; + } } - if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { - qWarning("Qt WebEngine resources not found at %s. Trying fallback directory... The application MAY NOT work.", qPrintable(potentialResourcesPath)); - potentialResourcesPath = fallbackDir(); + + if (potentialResourcesPath.isEmpty()) { + QStringList errorMessage; + errorMessage.append(QStringLiteral( + "The following paths were searched for Qt WebEngine resources:")); + for (const QString &candidate : qAsConst(candidatePaths)) + errorMessage.append(QStringLiteral(" ") % candidate); + errorMessage.append(QStringLiteral("but could not find any.")); + if (fromEnv.isEmpty()) { + errorMessage.append( + QStringLiteral("You may override the default search paths by using " + "QTWEBENGINE_RESOURCES_PATH environment variable.")); + } + qFatal("%s", qPrintable(errorMessage.join('\n'))); } } @@ -308,13 +380,17 @@ base::FilePath WebEngineLibraryInfo::getPath(int key) QString directory; switch (key) { case QT_RESOURCES_PAK: - return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_resources.pak")); + return toFilePath(resourcesPath() % QLatin1String("/qtwebengine_resources.pak")); case QT_RESOURCES_100P_PAK: - return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_resources_100p.pak")); + return toFilePath(resourcesPath() % QLatin1String("/qtwebengine_resources_100p.pak")); case QT_RESOURCES_200P_PAK: - return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_resources_200p.pak")); + return toFilePath(resourcesPath() % QLatin1String("/qtwebengine_resources_200p.pak")); case QT_RESOURCES_DEVTOOLS_PAK: - return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_devtools_resources.pak")); + return toFilePath(resourcesPath() % QLatin1String("/qtwebengine_devtools_resources.pak")); +#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) + case QT_FRAMEWORK_BUNDLE: + return toFilePath(getBundlePath(frameworkBundle())); +#endif case base::FILE_EXE: case content::CHILD_PROCESS_EXE: return toFilePath(subProcessPath()); @@ -330,7 +406,7 @@ base::FilePath WebEngineLibraryInfo::getPath(int key) directory = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); break; case base::DIR_QT_LIBRARY_DATA: - return toFilePath(resourcesDataPath()); + return toFilePath(resourcesPath()); case ui::DIR_LOCALES: return toFilePath(localesPath()); #if QT_CONFIG(webengine_spellchecker) @@ -355,14 +431,16 @@ std::u16string WebEngineLibraryInfo::getApplicationName() std::string WebEngineLibraryInfo::getResolvedLocale() { base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess(); - if (parsedCommandLine->HasSwitch(switches::kLang)) { - return parsedCommandLine->GetSwitchValueASCII(switches::kLang); - } else { - const QString &locale = QLocale().bcp47Name(); - std::string resolvedLocale; - if (l10n_util::CheckAndResolveLocale(locale.toStdString(), &resolvedLocale)) - return resolvedLocale; - } + std::string locale; + if (parsedCommandLine->HasSwitch(switches::kLang)) + locale = parsedCommandLine->GetSwitchValueASCII(switches::kLang); + else + locale = QLocale().bcp47Name().toStdString(); + + std::string resolvedLocale; + if (l10n_util::CheckAndResolveLocale(locale, &resolvedLocale)) + return resolvedLocale; + return "en-US"; } diff --git a/src/core/web_engine_library_info.h b/src/core/web_engine_library_info.h index 2926365bf..10542a99e 100644 --- a/src/core/web_engine_library_info.h +++ b/src/core/web_engine_library_info.h @@ -48,7 +48,8 @@ enum { QT_RESOURCES_PAK = 5000, QT_RESOURCES_100P_PAK = 5001, QT_RESOURCES_200P_PAK = 5002, - QT_RESOURCES_DEVTOOLS_PAK = 5003 + QT_RESOURCES_DEVTOOLS_PAK = 5003, + QT_FRAMEWORK_BUNDLE = 5004 }; class WebEngineLibraryInfo { diff --git a/src/gn/CMakeLists.txt b/src/gn/CMakeLists.txt index a76d1dcee..37665465d 100644 --- a/src/gn/CMakeLists.txt +++ b/src/gn/CMakeLists.txt @@ -36,6 +36,7 @@ add_custom_command( --cc ${CMAKE_C_COMPILER} --cxx ${CMAKE_CXX_COMPILER} --ld ${CMAKE_CXX_COMPILER} + --ar ${CMAKE_AR} --qt-version "${QT_REPO_MODULE_VERSION}.qtwebengine.qt.io" $<$<PLATFORM_ID:Darwin>:--isysroot> $<$<PLATFORM_ID:Darwin>:${CMAKE_OSX_SYSROOT}> diff --git a/src/pdf/configure.cmake b/src/pdf/configure.cmake index a252d7da6..8d1a07183 100644 --- a/src/pdf/configure.cmake +++ b/src/pdf/configure.cmake @@ -1,6 +1,7 @@ qt_feature("pdf-v8" PRIVATE LABEL "Support V8" PURPOSE "Enables javascript support." + AUTODETECT FALSE CONDITION NOT IOS ) qt_feature("pdf-xfa" PRIVATE diff --git a/src/pdf/doc/qtpdf.qdocconf b/src/pdf/doc/qtpdf.qdocconf index 24f7d8b51..85d0a7c4d 100644 --- a/src/pdf/doc/qtpdf.qdocconf +++ b/src/pdf/doc/qtpdf.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtwebengine.qdocconf) project = QtPdf description = Qt Pdf Reference Documentation diff --git a/src/webenginequick/api/qquickwebengineprofile.cpp b/src/webenginequick/api/qquickwebengineprofile.cpp index ec7365064..63e2b84fe 100644 --- a/src/webenginequick/api/qquickwebengineprofile.cpp +++ b/src/webenginequick/api/qquickwebengineprofile.cpp @@ -181,6 +181,8 @@ QQuickWebEngineProfilePrivate::~QQuickWebEngineProfilePrivate() if (m_profileAdapter != QtWebEngineCore::ProfileAdapter::defaultProfileAdapter()) delete m_profileAdapter; + else if (m_profileAdapter) + m_profileAdapter->releaseAllWebContentsAdapterClients(); } void QQuickWebEngineProfilePrivate::addWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) diff --git a/src/webenginequick/api/qquickwebenginesingleton.cpp b/src/webenginequick/api/qquickwebenginesingleton.cpp index 6c4e6fb68..bffa923de 100644 --- a/src/webenginequick/api/qquickwebenginesingleton.cpp +++ b/src/webenginequick/api/qquickwebenginesingleton.cpp @@ -117,6 +117,7 @@ QWebEngineScript QQuickWebEngineSingleton::script() const return QWebEngineScript(); } +QT_END_NAMESPACE + #include "moc_qquickwebenginesingleton_p.cpp" -QT_END_NAMESPACE diff --git a/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc b/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc index b21efbdf9..ac3526540 100644 --- a/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc +++ b/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc @@ -35,6 +35,6 @@ QT += webenginequick //! [1] //! [2] -find_package(Qt6 COMPONENTS WebEngineQuick REQUIRED) +find_package(Qt6 REQUIRED COMPONENTS WebEngineQuick) target_link_libraries(target PRIVATE Qt::WebEngineQuick) //! [2] diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 6a22a887e..0ed67edab 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -267,6 +267,10 @@ void QWebEngineViewPrivate::showColorDialog( QColorDialog::connect(dialog, SIGNAL(colorSelected(QColor)), dialog, SLOT(deleteLater())); QColorDialog::connect(dialog, SIGNAL(rejected()), dialog, SLOT(deleteLater())); +#if defined(Q_OS_MACOS) + dialog->setOption(QColorDialog::DontUseNativeDialog); +#endif + dialog->open(); #else Q_UNUSED(controller); diff --git a/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc b/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc index f48932eae..e598f7746 100644 --- a/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc +++ b/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc @@ -35,6 +35,6 @@ QT += webenginewidgets //! [1] //! [2] -find_package(Qt6 COMPONENTS WebEngineWidgets REQUIRED) +find_package(Qt6 REQUIRED COMPONENTS WebEngineWidgets) target_link_libraries(target PRIVATE Qt::WebEngineWidgets) //! [2] 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 986c1e650..ef2549bb5 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -282,6 +282,10 @@ void RenderWidgetHostViewQtDelegateWidget::show() // want to show anything else than popups as top-level. if (parent() || m_isPopup) { QQuickWidget::show(); + + QWebEngineView *view = static_cast<QWebEngineView *>(parent()); + if (view && view->isWindow()) + update(); } } diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp index 14d045613..614d05d75 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -727,7 +727,7 @@ void tst_QWebEngineUrlRequestInterceptor::jsServiceWorker() server.setResourceDirs({ QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + "/resources" }); QVERIFY(server.start()); - QWebEngineProfile profile(QStringLiteral("Test")); + QWebEngineProfile profile; std::unique_ptr<ConsolePage> page; page.reset(new ConsolePage(&profile)); TestRequestInterceptor interceptor(/* intercept */ false); diff --git a/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp b/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp index a0f73bb88..a77906d9b 100644 --- a/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp +++ b/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp @@ -89,7 +89,7 @@ struct TemporaryPdf: public QTemporaryFile }; -TemporaryPdf::TemporaryPdf() +TemporaryPdf::TemporaryPdf():QTemporaryFile(QStringLiteral("qpdfdocument")) { open(); pageLayout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()); diff --git a/tests/auto/quick/CMakeLists.txt b/tests/auto/quick/CMakeLists.txt index d44d67d38..48a83e7de 100644 --- a/tests/auto/quick/CMakeLists.txt +++ b/tests/auto/quick/CMakeLists.txt @@ -2,7 +2,10 @@ add_subdirectory(dialogs) add_subdirectory(publicapi) add_subdirectory(qquickwebenginedefaultsurfaceformat) add_subdirectory(qtbug-70248) -add_subdirectory(uidelegates) +# Re-enable if QTBUG-101744 and QTBUG-103354 have been fixed. +if(NOT MACOS) + add_subdirectory(uidelegates) +endif() add_subdirectory(inspectorserver) add_subdirectory(qmltests) add_subdirectory(qquickwebengineview) diff --git a/tests/auto/quick/qmltests/data/tst_favicon.qml b/tests/auto/quick/qmltests/data/tst_favicon.qml index 79c835c70..ce4a2aa3c 100644 --- a/tests/auto/quick/qmltests/data/tst_favicon.qml +++ b/tests/auto/quick/qmltests/data/tst_favicon.qml @@ -165,6 +165,38 @@ TestWebEngineView { compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) } + function test_faviconLoadPushState_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoadPushState(row) { + webEngineView.profile = row.profile; + compare(iconChangedSpy.count, 0); + + var iconUrl; + + webEngineView.url = Qt.resolvedUrl("favicon.html"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(iconChangedSpy, "count", 1); + iconUrl = removeFaviconProviderPrefix(webEngineView.icon); + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")); + + iconChangedSpy.clear(); + + // pushState() is a same document navigation and should not reset or + // update favicon. + compare(webEngineView.history.items.rowCount(), 1); + runJavaScript("history.pushState('', '')"); + tryVerify(function() { return webEngineView.history.items.rowCount() === 2; }); + + // Favicon change is not expected. + compare(iconChangedSpy.count, 0); + iconUrl = removeFaviconProviderPrefix(webEngineView.icon); + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")); + } function test_noFavicon_data() { return [ diff --git a/tests/auto/widgets/favicon/tst_favicon.cpp b/tests/auto/widgets/favicon/tst_favicon.cpp index d8b4803c0..6b5ae3c02 100644 --- a/tests/auto/widgets/favicon/tst_favicon.cpp +++ b/tests/auto/widgets/favicon/tst_favicon.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <util.h> +#include <QWebEngineHistory> #include <QWebEnginePage> #include <QWebEngineProfile> #include <QWebEngineSettings> @@ -49,6 +50,7 @@ private Q_SLOTS: void faviconLoadFromResources(); void faviconLoadEncodedUrl(); void faviconLoadAfterHistoryNavigation(); + void faviconLoadPushState(); void noFavicon(); void aboutBlank(); void unavailableFavicon(); @@ -222,6 +224,41 @@ void tst_Favicon::faviconLoadAfterHistoryNavigation() QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qtmulti.ico")); } +void tst_Favicon::faviconLoadPushState() +{ + QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); + QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); + QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); + + QUrl url("qrc:/resources/favicon-single.html"); + m_page->load(url); + + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 1); + QTRY_COMPARE(iconChangedSpy.count(), 1); + + QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); + QCOMPARE(iconUrl, m_page->iconUrl()); + QCOMPARE(iconUrl, QUrl("qrc:/resources/icons/qt32.ico")); + + const QIcon &icon = m_page->icon(); + QVERIFY(!icon.isNull()); + + iconUrlChangedSpy.clear(); + iconChangedSpy.clear(); + + // pushState() is a same document navigation and should not reset or + // update favicon. + QCOMPARE(m_page->history()->count(), 1); + evaluateJavaScriptSync(m_page, "history.pushState('', '')"); + QTRY_COMPARE(m_page->history()->count(), 2); + + // Favicon change is not expected. + QCOMPARE(iconUrlChangedSpy.count(), 0); + QCOMPARE(iconChangedSpy.count(), 0); + QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qt32.ico")); +} + void tst_Favicon::noFavicon() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) diff --git a/tests/auto/widgets/proxypac/CMakeLists.txt b/tests/auto/widgets/proxypac/CMakeLists.txt index 1dd2c8bec..d3ddfd0c5 100644 --- a/tests/auto/widgets/proxypac/CMakeLists.txt +++ b/tests/auto/widgets/proxypac/CMakeLists.txt @@ -21,6 +21,22 @@ set_tests_properties(tst_proxypac_file PROPERTIES ENVIRONMENT QTWEBENGINE_CHROMIUM_FLAGS=${fileEnvArg} ) +if(NOT (LINUX AND CMAKE_CROSSCOMPILING)) + set(fileEnvArg "--single-process ${fileEnvArg}") + + qt_internal_add_test(tst_proxypac_single_process + SOURCES + tst_proxypac.cpp + LIBRARIES + Qt::WebEngineCore + Test::HttpServer + ) + + set_tests_properties(tst_proxypac_single_process PROPERTIES + ENVIRONMENT QTWEBENGINE_CHROMIUM_FLAGS=${fileEnvArg} + ) +endif() + qt_internal_add_test(tst_proxypac_qrc SOURCES tst_proxypac.cpp @@ -40,8 +56,6 @@ set_tests_properties(tst_proxypac_qrc PROPERTIES ) qt_internal_add_resource(tst_proxypac_qrc "proxypac" - PREFIX - "/" - FILES - "proxy.pac" + PREFIX "/" + FILES "proxy.pac" ) diff --git a/tests/auto/widgets/proxypac/proxy.pac b/tests/auto/widgets/proxypac/proxy.pac index 1d29847b9..966c37ba5 100644 --- a/tests/auto/widgets/proxypac/proxy.pac +++ b/tests/auto/widgets/proxypac/proxy.pac @@ -2,6 +2,6 @@ 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"; + return "DIRECT"; } diff --git a/tests/auto/widgets/proxypac/tst_proxypac.cpp b/tests/auto/widgets/proxypac/tst_proxypac.cpp index 223c995e0..0b218aef9 100644 --- a/tests/auto/widgets/proxypac/tst_proxypac.cpp +++ b/tests/auto/widgets/proxypac/tst_proxypac.cpp @@ -33,7 +33,6 @@ #include <QWebEnginePage> #include <QNetworkProxy> - class tst_ProxyPac : public QObject { Q_OBJECT public: @@ -64,11 +63,20 @@ void tst_ProxyPac::proxypac() QWebEngineProfile profile; QWebEnginePage page(&profile); + + const bool v8_proxy_resolver_enabled = !fromEnv.contains("--single-process"); page.load(QUrl("http://test.proxy1.com")); - QTRY_COMPARE(proxySpy1.count() >= 1, true); + QTRY_COMPARE(proxySpy1.count() >= 1, v8_proxy_resolver_enabled); QVERIFY(proxySpy2.count() == 0); page.load(QUrl("http://test.proxy2.com")); - QTRY_COMPARE(proxySpy2.count() >= 1 , true); + QTRY_COMPARE(proxySpy2.count() >= 1, v8_proxy_resolver_enabled); + + // check for crash + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + page.load(QUrl("https://contribute.qt-project.org")); + + QTRY_VERIFY_WITH_TIMEOUT(!spyFinished.isEmpty(), 100000); + } #include "tst_proxypac.moc" diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 227f33c17..32f866810 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -257,6 +257,8 @@ private Q_SLOTS: void testChooseFilesParameters(); void fileSystemAccessDialog(); + void localToRemoteNavigation(); + private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); static bool isFalseJavaScriptResult(QWebEnginePage *page, const QString &javaScript); @@ -328,6 +330,14 @@ void tst_QWebEnginePage::initTestCase() QWebEngineUrlScheme echo("echo"); echo.setSyntax(QWebEngineUrlScheme::Syntax::Path); QWebEngineUrlScheme::registerScheme(echo); + + QWebEngineUrlScheme local("local"); + local.setFlags(QWebEngineUrlScheme::LocalScheme); + QWebEngineUrlScheme::registerScheme(local); + + QWebEngineUrlScheme remote("remote"); + remote.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(remote); } void tst_QWebEnginePage::cleanupTestCase() @@ -5010,6 +5020,61 @@ void tst_QWebEnginePage::isSafeRedirect() spy.clear(); } +class LocalRemoteUrlSchemeHandler : public QWebEngineUrlSchemeHandler +{ +public: + LocalRemoteUrlSchemeHandler(QObject *parent = nullptr) + : QWebEngineUrlSchemeHandler(parent) + { + } + ~LocalRemoteUrlSchemeHandler() = default; + + void requestStarted(QWebEngineUrlRequestJob *job) override + { + QBuffer *buffer = new QBuffer(job); + buffer->setData("<html><body><a href='remote://test.html' id='link'>Click link</a></body></html>"); + job->reply("text/html", buffer); + loaded = true; + } + bool loaded = false; +}; + +void tst_QWebEnginePage::localToRemoteNavigation() +{ + LocalRemoteUrlSchemeHandler local; + LocalRemoteUrlSchemeHandler remote; + QWebEngineProfile profile; + profile.installUrlSchemeHandler("local", &local); + profile.installUrlSchemeHandler("remote", &remote); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + QWebEngineView view; + view.resize(640, 480); + view.show(); + view.setPage(&page); + page.setUrl(QUrl("local://test.html")); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QVERIFY(local.loaded); + + // Should navigate: + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 2, 20000); + QVERIFY(remote.loaded); + local.loaded = false; + remote.loaded = false; + + page.setUrl(QUrl("local://test.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 3, 20000); + QVERIFY(local.loaded && !remote.loaded); + + // Should not navigate: + page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()")); + QTest::qWait(500); + QVERIFY(!remote.loaded); +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp index c09f3b51a..ee4f5990e 100644 --- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -66,6 +66,7 @@ private Q_SLOTS: void urlSchemeHandlerFailRequest(); void urlSchemeHandlerFailOnRead(); void urlSchemeHandlerStreaming(); + void urlSchemeHandlerStreaming2(); void urlSchemeHandlerRequestHeaders(); void urlSchemeHandlerInstallation(); void urlSchemeHandlerXhrStatus(); @@ -289,10 +290,12 @@ public: QList<QPointer<QBuffer>> m_buffers; }; -class StreamingIODevice : public QIODevice { +// an evil version constantly claiming to be at end, similar to QNetworkReply +class StreamingIODeviceBasic : public QIODevice +{ Q_OBJECT public: - StreamingIODevice(QObject *parent) : QIODevice(parent), m_bytesRead(0), m_bytesAvailable(0) + StreamingIODeviceBasic(QObject *parent) : QIODevice(parent), m_bytesRead(0), m_bytesAvailable(0) { setOpenMode(QIODevice::ReadOnly); m_timer.start(100, this); @@ -303,12 +306,11 @@ public: const std::lock_guard<QRecursiveMutex> lock(m_mutex); return m_bytesAvailable; } - bool atEnd() const override +protected: + bool internalAtEnd() const { - const std::lock_guard<QRecursiveMutex> lock(m_mutex); return (m_data.size() >= 1000 && m_bytesRead >= 1000); } -protected: void timerEvent(QTimerEvent *) override { const std::lock_guard<QRecursiveMutex> lock(m_mutex); @@ -329,7 +331,7 @@ protected: memcpy(data, m_data.constData() + m_bytesRead, len); m_bytesAvailable -= len; m_bytesRead += len; - } else if (atEnd()) + } else if (internalAtEnd()) return -1; return len; @@ -339,14 +341,26 @@ protected: return 0; } -private: mutable QRecursiveMutex m_mutex; +private: QByteArray m_data; QBasicTimer m_timer; int m_bytesRead; int m_bytesAvailable; }; +// A nicer version implementing atEnd +class StreamingIODevice : public StreamingIODeviceBasic +{ +public: + StreamingIODevice(QObject *parent) : StreamingIODeviceBasic(parent) {} + bool atEnd() const override + { + const std::lock_guard<QRecursiveMutex> lock(m_mutex); + return internalAtEnd(); + } +}; + class StreamingUrlSchemeHandler : public QWebEngineUrlSchemeHandler { public: @@ -361,6 +375,20 @@ public: } }; +class StreamingUrlSchemeHandler2 : public QWebEngineUrlSchemeHandler +{ +public: + StreamingUrlSchemeHandler2(QObject *parent = nullptr) + : QWebEngineUrlSchemeHandler(parent) + { + } + + void requestStarted(QWebEngineUrlRequestJob *job) override + { + job->reply("text/plain;charset=utf-8", new StreamingIODeviceBasic(job)); + } +}; + void tst_QWebEngineProfile::urlSchemeHandlers() { RedirectingUrlSchemeHandler lettertoHandler; @@ -502,6 +530,23 @@ void tst_QWebEngineProfile::urlSchemeHandlerStreaming() QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result)); } +void tst_QWebEngineProfile::urlSchemeHandlerStreaming2() +{ + StreamingUrlSchemeHandler2 handler; + QWebEngineProfile profile; + profile.installUrlSchemeHandler("stream", &handler); + QWebEngineView view; + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setPage(new QWebEnginePage(&profile, &view)); + view.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); + view.load(QUrl(QStringLiteral("stream://whatever"))); + view.show(); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); + QByteArray result; + result.append(1000, 'c'); + QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result)); +} + class ExtraHeaderInterceptor : public QWebEngineUrlRequestInterceptor { public: diff --git a/tests/auto/widgets/touchinput/tst_touchinput.cpp b/tests/auto/widgets/touchinput/tst_touchinput.cpp index 957f3e74c..e3ee9f933 100644 --- a/tests/auto/widgets/touchinput/tst_touchinput.cpp +++ b/tests/auto/widgets/touchinput/tst_touchinput.cpp @@ -81,17 +81,17 @@ private: auto target = view.focusProxy(); QPoint p(target->width() / 2, target->height() / 4 * (down ? 3 : 1)); - QTest::touchEvent(target, s_touchDevice).press(42, p, target); + QTest::touchEvent(target, s_touchDevice).press(1, p, target); QSignalSpy spy(view.page(), &QWebEnginePage::scrollPositionChanged); for (int i = 0; i < 3; ++i) { down ? p -= QPoint(5, 15) : p += QPoint(5, 15); QTest::qWait(100); // too fast and events are recognized as fling gesture - QTest::touchEvent(target, s_touchDevice).move(42, p, target); + QTest::touchEvent(target, s_touchDevice).move(1, p, target); spy.wait(); } - QTest::touchEvent(target, s_touchDevice).release(42, p, target); + QTest::touchEvent(target, s_touchDevice).release(1, p, target); } void gesturePinch(bool zoomIn, bool tapOneByOne = false) { @@ -100,10 +100,10 @@ private: auto t1 = p - QPoint(zoomIn ? 50 : 150, 10), t2 = p + QPoint(zoomIn ? 50 : 150, 10); if (tapOneByOne) { - QTest::touchEvent(target, s_touchDevice).press(42, t1, target); - QTest::touchEvent(target, s_touchDevice).stationary(42).press(24, t2, target); + QTest::touchEvent(target, s_touchDevice).press(0, t1, target); + QTest::touchEvent(target, s_touchDevice).stationary(0).press(1, t2, target); } else { - QTest::touchEvent(target, s_touchDevice).press(42, t1, target).press(24, t2, target); + QTest::touchEvent(target, s_touchDevice).press(0, t1, target).press(1, t2, target); } for (int i = 0; i < 3; ++i) { @@ -115,14 +115,14 @@ private: t2 -= QPoint(35, 5); } QTest::qWait(100); // too fast and events are recognized as fling gesture - QTest::touchEvent(target, s_touchDevice).move(24, t1, target).move(42, t2, target); + QTest::touchEvent(target, s_touchDevice).move(1, t1, target).move(0, t2, target); } if (tapOneByOne) { - QTest::touchEvent(target, s_touchDevice).stationary(42).release(24, t2, target); - QTest::touchEvent(target, s_touchDevice).release(42, t1, target); + QTest::touchEvent(target, s_touchDevice).stationary(0).release(1, t2, target); + QTest::touchEvent(target, s_touchDevice).release(0, t1, target); } else { - QTest::touchEvent(target, s_touchDevice).release(42, t1, target).release(24, t2, target); + QTest::touchEvent(target, s_touchDevice).release(0, t1, target).release(1, t2, target); } } |