diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-12-06 10:27:32 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-12-06 09:28:33 +0000 |
commit | 15ddeed8251f5253f71c05800cc4c45f791e890b (patch) | |
tree | 6cf32ab7a113323e9734a660c60603cdf352946a | |
parent | 8df5daf60b8b7eedf743430f8afbcb99eca27fbc (diff) | |
parent | ca08e3ab5dd250581911f2a58185443aed91ee92 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Fixes: QTBUG-80555
Change-Id: I4c7f69f697c09526f5f927948e6a6bf1c43fac17
55 files changed, 483 insertions, 265 deletions
diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0 new file mode 100644 index 000000000..b7df882ad --- /dev/null +++ b/dist/changes-5.14.0 @@ -0,0 +1,88 @@ +Qt 5.14 introduces many new features and improvements as well as bugfixes +over the 5.13.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* General * +**************************************************************************** + +Chromium Snapshot +----------------- + + - Updated the Chromium version to 77.0.3865.129 + - Applied security fixes from Chrome up to version 78.0.3904.108 + +General +------- + + - [QTBUG-71885] Qt WebEngine will now use the Viz Display Compositor by + default when multithreaded OpenGL is available. Can be turned off using + the command line flag --disable-viz-display-compositor. + - [QTBUG-68448] WebRTC devices now have persistent IDs. + - [QTBUG-76173] Support qrc protocol in UrlPattern. + - [QTBUG-78280] Fixed permissions preventing Flash from showing. + - [QTBUG-79319] Fixed loading script as modules over custom schemes. + - [QTBUG-80352] Updated paths to look for Chrome's Widevine plugin. + +Platforms +--------- + + - [QTBUG-78911] Fixed building with newer system ICU. Minimum is now 64. + - [QTBUG-79347] Fixed support for prefers-color-scheme CSS query. + - [QTBUG-80055] Re-enabled X11 WebRTC support for desktop sharing. + - [QTBUG-77072,QTBUG-78084] Fixed flashing when closing popup on macOS. + + +**************************************************************************** +* Libraries * +**************************************************************************** + +QtWebEngineCore +---------------- + + - [QTBUG-75651] Added the QWebEngineUrlScheme::CorsEnabled flag for enabling + cross-origin resource sharing with custom schemes. + + +QtWebEngine + QtWebEngineWidgets +-------------------------------- + + - [QTBUG-55079,QTBUG-74166] Added lifecycle API to WebEngineView and + QWebEnginePage that can be used to reduce CPU and memory consumption + of non-visible views. + - [QTBUG-56978] Added functions and property to get the suggested download + file name. + - [QTBUG-56978] Added functions and property to change the download + directory and file name in QWebEngineDownloadItem and + QQuickWebEngineDownloadItem and deprecate the path() and setPath(). + - [QTBUG-74490] Redirects now have a separate navigation type. + + +Qt WebEngine (QML) +------------------ + + - [QTBUG-50420] Introduced findTextFinished signal and FindTextResult + type to provide extra information about the result of a text search. + + +Qt WebEngineWidgets +------------------- + + - QWebEngineCertificateError: + * [QTBUG-51176] New method to get the peer's chain of digital certificates. + * [QTBUG-55110] New methods for asynchronous decision on certificate error + during load. + - [QTBUG-78998] Store favicon URL when serializing QWebEngineHistory. diff --git a/examples/webengine/customdialogs/doc/src/customdialogs.qdoc b/examples/webengine/customdialogs/doc/src/customdialogs.qdoc index 6319ce53b..16eab0b6c 100644 --- a/examples/webengine/customdialogs/doc/src/customdialogs.qdoc +++ b/examples/webengine/customdialogs/doc/src/customdialogs.qdoc @@ -57,11 +57,10 @@ \section1 Triggering Dialogs - As mentioned, the \l {webengine/customdialogs/index.html}{index.html} file - is responsible for triggering the dialogs from the side of HTML and - JavaScript. Additionally, the example program starts a localhost TCP server - returning the mocked HTTP responses needed to trigger proxy and HTTP - authentication dialogs. + As mentioned, the \c index.html file is responsible for triggering the + dialogs from the side of HTML and JavaScript. Additionally, the example + program starts a localhost TCP server returning the mocked HTTP responses + needed to trigger proxy and HTTP authentication dialogs. \section1 Custom Dialogs diff --git a/examples/webengine/lifecycle/WebTab.qml b/examples/webengine/lifecycle/WebTab.qml index 645758104..8649da3cb 100644 --- a/examples/webengine/lifecycle/WebTab.qml +++ b/examples/webengine/lifecycle/WebTab.qml @@ -53,7 +53,7 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Controls.Material 2.12 import QtQuick.Layouts 1.12 -import QtWebEngine 1.11 +import QtWebEngine 1.10 ColumnLayout { id: root diff --git a/examples/webengine/lifecycle/WebTabButton.qml b/examples/webengine/lifecycle/WebTabButton.qml index 815e2fb09..68057412b 100644 --- a/examples/webengine/lifecycle/WebTabButton.qml +++ b/examples/webengine/lifecycle/WebTabButton.qml @@ -52,7 +52,7 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Controls.Material 2.12 import QtQuick.Layouts 1.12 -import QtWebEngine 1.11 +import QtWebEngine 1.10 TabButton { id: root diff --git a/examples/webengine/lifecycle/main.cpp b/examples/webengine/lifecycle/main.cpp index 83907cbaf..bb93d64a7 100644 --- a/examples/webengine/lifecycle/main.cpp +++ b/examples/webengine/lifecycle/main.cpp @@ -58,8 +58,8 @@ int main(int argc, char *argv[]) { QCoreApplication::setOrganizationName("QtExamples"); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QGuiApplication app(argc, argv); QtWebEngine::initialize(); + QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/WebBrowser.qml"))); return app.exec(); diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp index c1d0ea359..12a1e6844 100644 --- a/examples/webenginewidgets/simplebrowser/browserwindow.cpp +++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp @@ -66,7 +66,9 @@ #include <QStatusBar> #include <QToolBar> #include <QVBoxLayout> +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) #include <QWebEngineFindTextResult> +#endif #include <QWebEngineProfile> BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools) @@ -130,7 +132,9 @@ BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() { m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text())); }); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) connect(m_tabWidget, &TabWidget::findTextFinished, this, &BrowserWindow::handleFindTextFinished); +#endif QAction *focusUrlLineEditAction = new QAction(this); addAction(focusUrlLineEditAction); @@ -462,7 +466,14 @@ void BrowserWindow::handleFindActionTriggered() m_lastSearch, &ok); if (ok && !search.isEmpty()) { m_lastSearch = search; +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) currentTab()->findText(m_lastSearch); +#else + currentTab()->findText(m_lastSearch, 0, [this](bool found) { + if (!found) + statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch)); + }); +#endif } } @@ -526,6 +537,7 @@ void BrowserWindow::handleDevToolsRequested(QWebEnginePage *source) source->triggerAction(QWebEnginePage::InspectElement); } +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) void BrowserWindow::handleFindTextFinished(const QWebEngineFindTextResult &result) { if (result.numberOfMatches() == 0) { @@ -536,3 +548,4 @@ void BrowserWindow::handleFindTextFinished(const QWebEngineFindTextResult &resul QString::number(result.numberOfMatches()))); } } +#endif diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.h b/examples/webenginewidgets/simplebrowser/browserwindow.h index 11a655469..ea12ad9df 100644 --- a/examples/webenginewidgets/simplebrowser/browserwindow.h +++ b/examples/webenginewidgets/simplebrowser/browserwindow.h @@ -88,7 +88,9 @@ private slots: void handleWebViewTitleChanged(const QString &title); void handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled); void handleDevToolsRequested(QWebEnginePage *source); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) void handleFindTextFinished(const QWebEngineFindTextResult &result); +#endif private: QMenu *createFileMenu(TabWidget *tabWidget); diff --git a/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp b/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp index b6f9e9c13..2c8831429 100644 --- a/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp +++ b/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp @@ -69,12 +69,20 @@ void DownloadManagerWidget::downloadRequested(QWebEngineDownloadItem *download) { Q_ASSERT(download && download->state() == QWebEngineDownloadItem::DownloadRequested); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QString path = QFileDialog::getSaveFileName(this, tr("Save as"), QDir(download->downloadDirectory()).filePath(download->downloadFileName())); +#else + QString path = QFileDialog::getSaveFileName(this, tr("Save as"), download->path()); +#endif if (path.isEmpty()) return; +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) download->setDownloadDirectory(QFileInfo(path).path()); download->setDownloadFileName(QFileInfo(path).fileName()); +#else + download->setPath(path); +#endif download->accept(); add(new DownloadWidget(download)); diff --git a/examples/webenginewidgets/simplebrowser/downloadwidget.cpp b/examples/webenginewidgets/simplebrowser/downloadwidget.cpp index ddddc5e5d..c4e3cd805 100644 --- a/examples/webenginewidgets/simplebrowser/downloadwidget.cpp +++ b/examples/webenginewidgets/simplebrowser/downloadwidget.cpp @@ -61,7 +61,11 @@ DownloadWidget::DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent { m_timeAdded.start(); setupUi(this); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) m_dstName->setText(m_download->downloadFileName()); +#else + m_dstName->setText(QFileInfo(m_download->path()).fileName()); +#endif m_srcUrl->setText(m_download->url().toDisplayString()); connect(m_cancelButton, &QPushButton::clicked, diff --git a/examples/webenginewidgets/simplebrowser/main.cpp b/examples/webenginewidgets/simplebrowser/main.cpp index 7b77a4bd2..ddc8b4d01 100644 --- a/examples/webenginewidgets/simplebrowser/main.cpp +++ b/examples/webenginewidgets/simplebrowser/main.cpp @@ -75,8 +75,10 @@ int main(int argc, char **argv) app.setWindowIcon(QIcon(QStringLiteral(":AppLogoColor.png"))); QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, true); QWebEngineProfile::defaultProfile()->setUseForGlobalCertificateVerification(); +#endif QUrl url = commandLineUrlArgument(); diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp index 3b6d84ebe..d7a69e61f 100644 --- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp +++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp @@ -200,10 +200,12 @@ void TabWidget::setupView(WebView *webView) closeTab(index); }); connect(webView, &WebView::devToolsRequested, this, &TabWidget::devToolsRequested); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) connect(webPage, &QWebEnginePage::findTextFinished, [this, webView](const QWebEngineFindTextResult &result) { if (currentIndex() == indexOf(webView)) emit findTextFinished(result); }); +#endif } WebView *TabWidget::createTab() diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.h b/examples/webenginewidgets/simplebrowser/tabwidget.h index fba61d44f..bf65c9505 100644 --- a/examples/webenginewidgets/simplebrowser/tabwidget.h +++ b/examples/webenginewidgets/simplebrowser/tabwidget.h @@ -78,7 +78,9 @@ signals: void favIconChanged(const QIcon &icon); void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled); void devToolsRequested(QWebEnginePage *source); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) void findTextFinished(const QWebEngineFindTextResult &result); +#endif public slots: // current tab/page slots diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp index 2e49f651f..9f7038cdb 100644 --- a/examples/webenginewidgets/simplebrowser/webpage.cpp +++ b/examples/webenginewidgets/simplebrowser/webpage.cpp @@ -76,6 +76,7 @@ bool WebPage::certificateError(const QWebEngineCertificateError &error) { QWidget *mainWindow = view()->window(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QWebEngineCertificateError deferredError = error; deferredError.defer(); @@ -83,6 +84,9 @@ bool WebPage::certificateError(const QWebEngineCertificateError &error) if (!error.deferred()) { QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription()); } else { +#else + if (error.isOverridable()) { +#endif QDialog dialog(mainWindow); dialog.setModal(true); dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -95,6 +99,7 @@ bool WebPage::certificateError(const QWebEngineCertificateError &error) certificateDialog.m_errorLabel->setText(error.errorDescription()); dialog.setWindowTitle(tr("Certificate Error")); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) if (dialog.exec() == QDialog::Accepted) error.ignoreCertificateError(); else @@ -102,6 +107,13 @@ bool WebPage::certificateError(const QWebEngineCertificateError &error) } }); return true; +#else + return dialog.exec() == QDialog::Accepted; + } + + QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription()); + return false; +#endif } void WebPage::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth) diff --git a/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc b/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc index 5c455345b..256a69baf 100644 --- a/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc +++ b/examples/webenginewidgets/videoplayer/doc/src/videoplayer.qdoc @@ -113,7 +113,7 @@ request will be denied. Finally, we load some HTML (see - \l{webenginewidgets/videoplayer/data/index.html}{index.html} included with + \c webenginewidgets/videoplayer/data/index.html included with the example) into our \l QWebEngineView: \printline load diff --git a/src/3rdparty b/src/3rdparty -Subproject d61464c1e69fa96a47ab731f0ee4549890ae465 +Subproject 939daf833fff3a9901afb6fd65d02e0f057a494 diff --git a/src/buildtools/config/linux.pri b/src/buildtools/config/linux.pri index f3c4fc953..ee08f81bc 100644 --- a/src/buildtools/config/linux.pri +++ b/src/buildtools/config/linux.pri @@ -195,6 +195,7 @@ host_build { qtConfig(webengine-ozone-x11) { gn_args += ozone_platform_x11=true packagesExist(xscrnsaver): gn_args += use_xscrnsaver=true + qtConfig(webengine-webrtc): gn_args += rtc_use_x11=true } qtConfig(webengine-system-libevent): gn_args += use_system_libevent=true diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index 554ee3e12..22f3f548f 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -129,7 +129,8 @@ static QString getLocalAppDataDir() static const int32_t kPepperFlashPermissions = ppapi::PERMISSION_DEV | ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_BYPASS_USER_GESTURE | - ppapi::PERMISSION_FLASH; + ppapi::PERMISSION_FLASH | + ppapi::PERMISSION_SOCKET; namespace switches { const char kPpapiFlashPath[] = "ppapi-flash-path"; @@ -286,11 +287,11 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path, pluginPaths << ppapiPluginsPath() + QStringLiteral("/") + QString::fromLatin1(kWidevineCdmFileName); #endif #if defined(Q_OS_OSX) - QDir potentialWidevineDir("/Applications/Google Chrome.app/Contents/Versions"); + QDir potentialWidevineDir("/Applications/Google Chrome.app/Contents/Frameworks"); if (potentialWidevineDir.exists()) { QFileInfoList widevineVersionDirs = potentialWidevineDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed); - const QString library = QLatin1String("/Google Chrome Framework.framework/Versions/A/Libraries/" + const QString library = QLatin1String("/Versions/Current/Libraries/" "WidevineCdm/_platform_specific/mac_x64/libwidevinecdm.dylib"); for (const QFileInfo &info : widevineVersionDirs) pluginPaths << info.absoluteFilePath() + library; @@ -320,7 +321,12 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path, } } #elif defined(Q_OS_LINUX) - pluginPaths << QStringLiteral("/opt/google/chrome/libwidevinecdm.so") // Google Chrome + pluginPaths << QStringLiteral("/opt/google/chrome/libwidevinecdm.so") // Old Google Chrome +#if Q_PROCESSOR_WORDSIZE == 8 + << QStringLiteral("/opt/google/chrome/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so") +#else + << QStringLiteral("/opt/google/chrome/WidevineCdm/_platform_specific/linux_x86/libwidevinecdm.so") +#endif << QStringLiteral("/usr/lib/chromium/libwidevinecdm.so") // Arch << QStringLiteral("/usr/lib/chromium-browser/libwidevinecdm.so") // Ubuntu/neon << QStringLiteral("/usr/lib64/chromium/libwidevinecdm.so"); // OpenSUSE style diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index 34e290317..7049b8273 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -298,7 +298,7 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content ProfileAdapterClient::NoReason, adapterClient, QFileInfo(suggestedFilePath).fileName(), - time_t(QDateTime::currentMSecsSinceEpoch()) + QDateTime::currentMSecsSinceEpoch() }; for (ProfileAdapterClient *client : qAsConst(clients)) { diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp index 63b93c502..13e9437d2 100644 --- a/src/core/file_picker_controller.cpp +++ b/src/core/file_picker_controller.cpp @@ -46,10 +46,11 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/file_select_listener.h" -#include <QFileInfo> #include <QDir> -#include <QVariant> +#include <QFileInfo> +#include <QMimeDatabase> #include <QStringList> +#include <QVariant> namespace QtWebEngineCore { @@ -165,4 +166,51 @@ QString FilePickerController::defaultFileName() const return m_defaultFileName; } +QStringList FilePickerController::nameFilters(const QStringList &acceptedMimeTypes) +{ + QStringList nameFilters; + QStringList acceptedGlobs; + QMimeDatabase mimeDatabase; + + for (QString type : acceptedMimeTypes) { + if (type.startsWith(".")) { + // A single suffix + // Filename.type doesn't have to exist and mimeTypeForFile() supports + // custom suffixes as valid (but unknown) MIME types. + const QMimeType &mimeType = mimeDatabase.mimeTypeForFile("filename" + type); + if (mimeType.isValid()) { + QString glob = "*" + type; + acceptedGlobs.append(glob); + nameFilters.append(mimeType.comment() + " (" + glob + ")"); + } + } else if (type.contains("/") && !type.endsWith("*")) { + // All suffixes for a given MIME type + const QMimeType &mimeType = mimeDatabase.mimeTypeForName(type); + if (mimeType.isValid() && !mimeType.globPatterns().isEmpty()) { + QString globs = mimeType.globPatterns().join(" "); + acceptedGlobs.append(globs); + nameFilters.append(mimeType.comment() + " (" + globs + ")"); + } + } else if (type.endsWith("/*")) { + // All MIME types for audio/*, image/* or video/* + // as separate filters as Chrome does + static const QList<QMimeType> &allMimeTypes = mimeDatabase.allMimeTypes(); + type = type.remove("/*"); + for (const QMimeType &m : allMimeTypes) { + if (m.name().startsWith(type) && !m.globPatterns().isEmpty()) { + QString globs = m.globPatterns().join(" "); + acceptedGlobs.append(globs); + nameFilters.append(m.comment() + " (" + globs + ")"); + } + } + } else { + NOTREACHED(); + } + } + + nameFilters.prepend(QObject::tr("Accepted types") + " (" + acceptedGlobs.join(" ") + ")"); + + return nameFilters; +} + } // namespace diff --git a/src/core/file_picker_controller.h b/src/core/file_picker_controller.h index dc8c0eddf..0b680161a 100644 --- a/src/core/file_picker_controller.h +++ b/src/core/file_picker_controller.h @@ -80,6 +80,8 @@ public: QString defaultFileName() const; FileChooserMode mode() const; + static QStringList nameFilters(const QStringList &acceptedMimeTypes); + public Q_SLOTS: void accepted(const QStringList &files); void accepted(const QVariant &files); diff --git a/src/core/find_text_helper.cpp b/src/core/find_text_helper.cpp index 065fed38f..da9d7f352 100644 --- a/src/core/find_text_helper.cpp +++ b/src/core/find_text_helper.cpp @@ -108,6 +108,7 @@ void FindTextHelper::startFinding(const QString &findText, bool caseSensitively, // waiting for it forever. // Assume that any unfinished find has been unsuccessful when a new one is started // to cover that case. + m_lastCompletedFindRequestId = m_currentFindRequestId; m_viewClient->findTextFinished(QWebEngineFindTextResult()); invokeResultCallback(m_currentFindRequestId, 0); } diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index c94ff7eee..7bf499917 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -126,7 +126,7 @@ content::DesktopMediaID getDefaultScreenId() // // [1]: webrtc::InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread -#if QT_CONFIG(webengine_webrtc) && !defined(USE_X11) +#if QT_CONFIG(webengine_webrtc) && !defined(WEBRTC_USE_X11) // Source id patterns are different across platforms. // On Linux, the hardcoded value "0" is used. // On Windows, the screens are enumerated consecutively in increasing order from 0. diff --git a/src/core/net/url_request_notification.cpp b/src/core/net/url_request_notification.cpp index eb48160bf..74c56254e 100644 --- a/src/core/net/url_request_notification.cpp +++ b/src/core/net/url_request_notification.cpp @@ -51,6 +51,8 @@ #include "web_contents_adapter_client.h" #include "web_contents_view_qt.h" +#include <QVariant> + namespace QtWebEngineCore { // Calls cancel() when the URLRequest is destroyed. diff --git a/src/core/printing/pdfium_document_wrapper_qt.cpp b/src/core/printing/pdfium_document_wrapper_qt.cpp index 6f415b50b..dae6ec44b 100644 --- a/src/core/printing/pdfium_document_wrapper_qt.cpp +++ b/src/core/printing/pdfium_document_wrapper_qt.cpp @@ -48,64 +48,6 @@ namespace QtWebEngineCore { int PdfiumDocumentWrapperQt::m_libraryUsers = 0; -class PdfiumPageWrapperQt { -public: - PdfiumPageWrapperQt(FPDF_DOCUMENT data, int pageIndex) - : m_pageData(FPDF_LoadPage(data, pageIndex)) - , m_width(FPDF_GetPageWidth(m_pageData)) - , m_height(FPDF_GetPageHeight(m_pageData)) - , m_image(createImage()) - { - } - - PdfiumPageWrapperQt() - : m_pageData(nullptr) - , m_width(-1) - , m_height(-1) - , m_image(QImage()) - { - } - - virtual ~PdfiumPageWrapperQt() - { - FPDF_ClosePage(m_pageData); - } - - QImage image() - { - return m_image; - } - -private: - QImage createImage() - { - Q_ASSERT(m_pageData); - - QImage image(m_width * 2, m_height * 2, QImage::Format_ARGB32); - Q_ASSERT(!image.isNull()); - image.fill(0xFFFFFFFF); - - FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(image.width(), image.height(), - FPDFBitmap_BGRA, - image.scanLine(0), image.bytesPerLine()); - Q_ASSERT(bitmap); - - FPDF_RenderPageBitmap(bitmap, m_pageData, - 0, 0, image.width(), image.height(), - 0, 0); - FPDFBitmap_Destroy(bitmap); - bitmap = nullptr; - return image; - } - -private: - FPDF_PAGE m_pageData; - int m_width; - int m_height; - QImage m_image; -}; - - PdfiumDocumentWrapperQt::PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const char *password) { @@ -118,27 +60,41 @@ PdfiumDocumentWrapperQt::PdfiumDocumentWrapperQt(const void *pdfData, size_t siz m_pageCount = FPDF_GetPageCount((FPDF_DOCUMENT)m_documentHandle); } -QImage PdfiumDocumentWrapperQt::pageAsQImage(size_t index) +QImage PdfiumDocumentWrapperQt::pageAsQImage(size_t pageIndex,int width , int height) { if (!m_documentHandle || !m_pageCount) { qWarning("Failure to generate QImage from invalid or empty PDF document."); return QImage(); } - if (static_cast<int>(index) >= m_pageCount) { + if (static_cast<int>(pageIndex) >= m_pageCount) { qWarning("Failure to generate QImage from PDF data: index out of bounds."); return QImage(); } - PdfiumPageWrapperQt pageWrapper((FPDF_DOCUMENT)m_documentHandle, index); - return pageWrapper.image(); + FPDF_PAGE pageData(FPDF_LoadPage((FPDF_DOCUMENT)m_documentHandle, pageIndex)); + QImage image(width, height, QImage::Format_ARGB32); + Q_ASSERT(!image.isNull()); + image.fill(0xFFFFFFFF); + + FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(width, height, + FPDFBitmap_BGRA, + image.scanLine(0), image.bytesPerLine()); + Q_ASSERT(bitmap); + FPDF_RenderPageBitmap(bitmap, pageData, + 0, 0, width, height, + 0, 0); + FPDFBitmap_Destroy(bitmap); + bitmap = nullptr; + FPDF_ClosePage(pageData); + return image; } -bool PdfiumDocumentWrapperQt::pageIsLandscape(size_t index) +QSizeF PdfiumDocumentWrapperQt::pageSize(size_t index) { - double width = 0, height = 0; - FPDF_GetPageSizeByIndex((FPDF_DOCUMENT)m_documentHandle, index, &width, &height); - return (width > height); + QSizeF size; + FPDF_GetPageSizeByIndex((FPDF_DOCUMENT)m_documentHandle, index, &size.rwidth(), &size.rheight()); + return size; } PdfiumDocumentWrapperQt::~PdfiumDocumentWrapperQt() @@ -147,5 +103,4 @@ PdfiumDocumentWrapperQt::~PdfiumDocumentWrapperQt() if (--m_libraryUsers == 0) FPDF_DestroyLibrary(); } - } diff --git a/src/core/printing/pdfium_document_wrapper_qt.h b/src/core/printing/pdfium_document_wrapper_qt.h index 121742aa3..e0778c32b 100644 --- a/src/core/printing/pdfium_document_wrapper_qt.h +++ b/src/core/printing/pdfium_document_wrapper_qt.h @@ -56,15 +56,14 @@ #include <QtGui/qimage.h> namespace QtWebEngineCore { -class PdfiumPageWrapperQt; class Q_WEBENGINECORE_PRIVATE_EXPORT PdfiumDocumentWrapperQt { public: PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const char *password = nullptr); virtual ~PdfiumDocumentWrapperQt(); - QImage pageAsQImage(size_t index); - bool pageIsLandscape(size_t index); + QImage pageAsQImage(size_t index, int width , int height); + QSizeF pageSize(size_t index); int pageCount() const { return m_pageCount; } private: diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index 3f6d03b2e..ba2f97475 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -712,13 +712,6 @@ QString ProfileAdapter::determineDownloadPath(const QString &downloadDirectory, return suggestedFilePath; } -QString ProfileAdapter::updateDownloadPath(int downloadId, const QString &directory, const QString &fileName) -{ - download::DownloadItem *download = m_downloadManagerDelegate->findDownloadById(downloadId); - Q_ASSERT(download); - return determineDownloadPath(directory, fileName, download->GetStartTime().ToTimeT()); -} - #if QT_CONFIG(ssl) QWebEngineClientCertificateStore *ProfileAdapter::clientCertificateStore() { diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index 01477d0d9..1b89a8004 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -214,7 +214,6 @@ public: { return m_persistentNotifications; } QString determineDownloadPath(const QString &downloadDirectory, const QString &suggestedFilename, const time_t &startTime); - QString updateDownloadPath(int downloadId, const QString &directory, const QString &filename); private: void updateCustomUrlSchemeHandlers(); diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h index dc0f508a1..394f92270 100644 --- a/src/core/profile_adapter_client.h +++ b/src/core/profile_adapter_client.h @@ -140,7 +140,7 @@ public: int downloadInterruptReason; WebContentsAdapterClient *page; QString suggestedFileName; - time_t startTime; + qint64 startTime; }; virtual ~ProfileAdapterClient() { } diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index e2fd074ae..15cc5174e 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -340,7 +340,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget // May call SetNeedsBeginFrames host()->SetView(this); - host()->GetProcess()->AddObserver(this); } RenderWidgetHostViewQt::~RenderWidgetHostViewQt() @@ -354,7 +353,6 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt() if (text_input_manager_) text_input_manager_->RemoveObserver(this); - host()->GetProcess()->RemoveObserver(this); m_touchSelectionController.reset(); m_touchSelectionControllerClient.reset(); @@ -704,18 +702,6 @@ void RenderWidgetHostViewQt::ImeCompositionRangeChanged(const gfx::Range&, const QT_NOT_YET_IMPLEMENTED } -void RenderWidgetHostViewQt::RenderProcessExited(content::RenderProcessHost *host, - const content::ChildProcessTerminationInfo &info) -{ - Q_UNUSED(host); - // RenderProcessHost::FastShutdownIfPossible results in TERMINATION_STATUS_STILL_RUNNING - if (m_adapterClient && info.status != base::TERMINATION_STATUS_STILL_RUNNING) { - m_adapterClient->renderProcessTerminated( - m_adapterClient->renderProcessExitStatus(info.status), - info.exit_code); - } -} - void RenderWidgetHostViewQt::RenderProcessGone() { Destroy(); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 76807b37a..0e9d54b19 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -102,7 +102,6 @@ struct MultipleMouseClickHelper class RenderWidgetHostViewQt : public content::RenderWidgetHostViewBase - , public content::RenderProcessHostObserver , public ui::GestureProviderClient , public RenderWidgetHostViewQtDelegateClient , public base::SupportsWeakPtr<RenderWidgetHostViewQt> @@ -176,10 +175,6 @@ public: void DidStopFlinging() override; std::unique_ptr<content::SyntheticGestureTarget> CreateSyntheticGestureTarget() override; - // RenderProcessHostObserver implementation. - void RenderProcessExited(content::RenderProcessHost *host, - const content::ChildProcessTerminationInfo &info) override; - // Overridden from ui::GestureProviderClient. void OnGestureEvent(const ui::GestureEventData& gesture) override; diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 4bdb55b4c..75fb112c6 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -125,7 +125,9 @@ public: QUrl linkUrl; QUrl unfilteredLinkUrl; QUrl mediaUrl; + QString altText; QString linkText; + QString titleText; QString selectedText; QString suggestedFileName; QString misspelledWord; @@ -215,6 +217,14 @@ public: return d->unfilteredLinkUrl; } + void setAltText(const QString &text) { + d->altText = text; + } + + QString altText() const { + return d->altText; + } + void setLinkText(const QString &text) { d->linkText = text; } @@ -223,6 +233,14 @@ public: return d->linkText; } + void setTitleText(const QString &text) { + d->titleText = text; + } + + QString titleText() const { + return d->titleText; + } + void setSelectedText(const QString &text) { d->selectedText = text; } diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 255ff0034..2a89556cf 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -286,10 +286,17 @@ void WebContentsDelegateQt::RenderFrameDeleted(content::RenderFrameHost *render_ void WebContentsDelegateQt::RenderProcessGone(base::TerminationStatus status) { + // RenderProcessHost::FastShutdownIfPossible results in TERMINATION_STATUS_STILL_RUNNING + if (status != base::TERMINATION_STATUS_STILL_RUNNING) { + m_viewClient->renderProcessTerminated( + m_viewClient->renderProcessExitStatus(status), + web_contents()->GetCrashedErrorCode()); + } + // Based one TabLoadTracker::RenderProcessGone - if (status == base::TerminationStatus::TERMINATION_STATUS_NORMAL_TERMINATION - || status == base::TerminationStatus::TERMINATION_STATUS_STILL_RUNNING) { + if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION + || status == base::TERMINATION_STATUS_STILL_RUNNING) { return; } diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index ef7c09665..e50835f74 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -195,6 +195,8 @@ static inline WebEngineContextMenuData fromParams(const content::ContextMenuPara ret.setPosition(QPoint(params.x, params.y)); ret.setLinkUrl(toQt(params.link_url)); ret.setLinkText(toQt(params.link_text.data())); + ret.setAltText(toQt(params.alt_text.data())); + ret.setTitleText(toQt(params.title_text.data())); ret.setUnfilteredLinkUrl(toQt(params.unfiltered_link_url)); ret.setSelectedText(toQt(params.selection_text.data())); ret.setMediaUrl(toQt(params.src_url)); diff --git a/src/webengine/api/qquickwebenginedownloaditem.cpp b/src/webengine/api/qquickwebenginedownloaditem.cpp index 878dddadb..6abd89910 100644 --- a/src/webengine/api/qquickwebenginedownloaditem.cpp +++ b/src/webengine/api/qquickwebenginedownloaditem.cpp @@ -521,9 +521,9 @@ void QQuickWebEngineDownloadItem::setDownloadDirectory(const QString &directory) Q_EMIT downloadDirectoryChanged(); } - QString newFileName = QFileInfo(d->profile->d_ptr->profileAdapter()->updateDownloadPath(d->downloadId, - d->downloadDirectory, - d->suggestedFileName)).fileName(); + QString newFileName = QFileInfo(d->profile->d_ptr->profileAdapter()->determineDownloadPath(d->downloadDirectory, + d->suggestedFileName, + d->startTime)).fileName(); if (d->downloadFileName != newFileName) { d->downloadFileName = newFileName; Q_EMIT pathChanged(); diff --git a/src/webengine/api/qquickwebenginedownloaditem_p_p.h b/src/webengine/api/qquickwebenginedownloaditem_p_p.h index 51deee18b..1be6434ec 100644 --- a/src/webengine/api/qquickwebenginedownloaditem_p_p.h +++ b/src/webengine/api/qquickwebenginedownloaditem_p_p.h @@ -71,6 +71,7 @@ public: ~QQuickWebEngineDownloadItemPrivate(); quint32 downloadId; + qint64 startTime; QQuickWebEngineDownloadItem::DownloadState downloadState; QQuickWebEngineDownloadItem::SavePageFormat savePageFormat; QQuickWebEngineDownloadItem::DownloadType type; diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index edad7ec44..834bb6a05 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -245,6 +245,7 @@ void QQuickWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info) QQuickWebEngineDownloadItemPrivate *itemPrivate = new QQuickWebEngineDownloadItemPrivate(q, info.url); itemPrivate->downloadId = info.id; itemPrivate->downloadState = QQuickWebEngineDownloadItem::DownloadRequested; + itemPrivate->startTime = info.startTime; itemPrivate->totalBytes = info.totalBytes; itemPrivate->mimeType = info.mimeType; itemPrivate->downloadDirectory = QFileInfo(info.path).path(); diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 8a1a3c516..b05bbfdbc 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -1766,10 +1766,14 @@ void QQuickWebEngineView::triggerWebAction(WebAction action) case CopyLinkToClipboard: if (!d->m_contextMenuData.unfilteredLinkUrl().isEmpty()) { QString urlString = d->m_contextMenuData.unfilteredLinkUrl().toString(QUrl::FullyEncoded); - QString title = d->m_contextMenuData.linkText().toHtmlEscaped(); + QString linkText = d->m_contextMenuData.linkText().toHtmlEscaped(); + QString title = d->m_contextMenuData.titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); QMimeData *data = new QMimeData(); data->setText(urlString); - QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>"); + QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral(">") + + linkText + QStringLiteral("</a>"); data->setHtml(html); data->setUrls(QList<QUrl>() << d->m_contextMenuData.unfilteredLinkUrl()); qApp->clipboard()->setMimeData(data); @@ -1791,12 +1795,15 @@ void QQuickWebEngineView::triggerWebAction(WebAction action) case CopyImageUrlToClipboard: if (d->m_contextMenuData.mediaUrl().isValid() && d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeImage) { QString urlString = d->m_contextMenuData.mediaUrl().toString(QUrl::FullyEncoded); - QString title = d->m_contextMenuData.linkText(); + QString alt = d->m_contextMenuData.altText(); + if (!alt.isEmpty()) + alt = QStringLiteral(" alt=\"%1\"").arg(alt.toHtmlEscaped()); + QString title = d->m_contextMenuData.titleText(); if (!title.isEmpty()) - title = QStringLiteral(" alt=\"%1\"").arg(title.toHtmlEscaped()); + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); QMimeData *data = new QMimeData(); data->setText(urlString); - QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral("></img>"); + QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + alt + QStringLiteral("></img>"); data->setHtml(html); data->setUrls(QList<QUrl>() << d->m_contextMenuData.mediaUrl()); qApp->clipboard()->setMimeData(data); @@ -1814,12 +1821,17 @@ void QQuickWebEngineView::triggerWebAction(WebAction action) d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo)) { QString urlString = d->m_contextMenuData.mediaUrl().toString(QUrl::FullyEncoded); + QString title = d->m_contextMenuData.titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); QMimeData *data = new QMimeData(); data->setText(urlString); if (d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio) - data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"></audio>")); + data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"") + title + + QStringLiteral("></audio>")); else - data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"></video>")); + data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"") + title + + QStringLiteral("></video>")); data->setUrls(QList<QUrl>() << d->m_contextMenuData.mediaUrl()); qApp->clipboard()->setMimeData(data); } diff --git a/src/webengine/doc/src/qtwebengine-features.qdoc b/src/webengine/doc/src/qtwebengine-features.qdoc index 22eb72408..954992de1 100644 --- a/src/webengine/doc/src/qtwebengine-features.qdoc +++ b/src/webengine/doc/src/qtwebengine-features.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -37,6 +37,7 @@ \li \l{Audio and Video Codecs} \li \l{Chromium DevTools} \li \l{Client Certificates} + \li \l{Custom Schemes} \li \l{Drag and Drop} \li \l{Fullscreen} \li \l{HTML5 DRM} @@ -128,7 +129,7 @@ To activate support for client certificates, an application needs to listen to the QWebEnginePage::selectClientCertificate or - \l{WebEnginePage::selectClientCertificate}{WebEnginePage.selectClientCertificate} + \l{WebEngineView::selectClientCertificate}{WebEngineView.selectClientCertificate} signals and select one of the offered certificates. For applications that can navigate to untrusted web sites, it is recommended to always give the user a choice before uniquely identifying them diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc index df956f03e..6e349dfb3 100644 --- a/src/webengine/doc/src/webengineview_lgpl.qdoc +++ b/src/webengine/doc/src/webengineview_lgpl.qdoc @@ -1520,7 +1520,7 @@ \qmlsignal WebEngineView::tooltipRequested(TooltipRequest request) \since QtWebEngine 1.10 - This signal is emitted when the web page wants to show a tooltip at + This signal is emitted when the web page sends a \a request to show a tooltip at a specified position. \note Signal handlers need to call \c{request.accepted = true} to prevent a default tooltip from showing up. diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 19274bedf..756b3429e 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -486,6 +486,8 @@ void UIDelegatesManager::showFilePicker(QSharedPointer<FilePickerController> con Q_UNREACHABLE(); } + filePicker->setProperty("nameFilters", FilePickerController::nameFilters(controller->acceptedMimeTypes())); + QQmlProperty filesPickedSignal(filePicker, QStringLiteral("onFilesSelected")); CHECK_QML_SIGNAL_PROPERTY(filesPickedSignal, filePickerComponent->url()); QQmlProperty rejectSignal(filePicker, QStringLiteral("onRejected")); diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp index 724249208..fd7d90704 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.cpp +++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp @@ -599,9 +599,9 @@ void QWebEngineDownloadItem::setDownloadDirectory(const QString &directory) if (!directory.isEmpty() && d->downloadDirectory != directory) d->downloadDirectory = directory; - d->downloadFileName = QFileInfo(d->profile->profileAdapter()->updateDownloadPath(d->downloadId, - d->downloadDirectory, - d->suggestedFileName)).fileName(); + d->downloadFileName = QFileInfo(d->profile->profileAdapter()->determineDownloadPath(d->downloadDirectory, + d->suggestedFileName, + d->startTime)).fileName(); } /*! diff --git a/src/webenginewidgets/api/qwebenginedownloaditem_p.h b/src/webenginewidgets/api/qwebenginedownloaditem_p.h index 08e478736..034684a00 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem_p.h +++ b/src/webenginewidgets/api/qwebenginedownloaditem_p.h @@ -70,6 +70,7 @@ public: bool downloadFinished; quint32 downloadId; + qint64 startTime; QWebEngineDownloadItem::DownloadState downloadState; QWebEngineDownloadItem::SavePageFormat savePageFormat; QWebEngineDownloadItem::DownloadType type; diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 524df0425..958238c9d 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -1426,10 +1426,14 @@ void QWebEnginePage::triggerAction(WebAction action, bool) case CopyLinkToClipboard: if (menuData && !menuData->unfilteredLinkUrl().isEmpty()) { QString urlString = menuData->unfilteredLinkUrl().toString(QUrl::FullyEncoded); - QString title = menuData->linkText().toHtmlEscaped(); + QString linkText = menuData->linkText().toHtmlEscaped(); + QString title = menuData->titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); QMimeData *data = new QMimeData(); data->setText(urlString); - QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>"); + QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral(">") + + linkText + QStringLiteral("</a>"); data->setHtml(html); data->setUrls(QList<QUrl>() << menuData->unfilteredLinkUrl()); qApp->clipboard()->setMimeData(data); @@ -1452,12 +1456,15 @@ void QWebEnginePage::triggerAction(WebAction action, bool) case CopyImageUrlToClipboard: if (menuData && menuData->mediaUrl().isValid() && menuData->mediaType() == WebEngineContextMenuData::MediaTypeImage) { QString urlString = menuData->mediaUrl().toString(QUrl::FullyEncoded); - QString title = menuData->linkText(); + QString alt = menuData->altText(); + if (!alt.isEmpty()) + alt = QStringLiteral(" alt=\"%1\"").arg(alt.toHtmlEscaped()); + QString title = menuData->titleText(); if (!title.isEmpty()) - title = QStringLiteral(" alt=\"%1\"").arg(title.toHtmlEscaped()); + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); QMimeData *data = new QMimeData(); data->setText(urlString); - QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral("></img>"); + QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + alt + QStringLiteral("></img>"); data->setHtml(html); data->setUrls(QList<QUrl>() << menuData->mediaUrl()); qApp->clipboard()->setMimeData(data); @@ -1475,12 +1482,17 @@ void QWebEnginePage::triggerAction(WebAction action, bool) menuData->mediaType() == WebEngineContextMenuData::MediaTypeVideo)) { QString urlString = menuData->mediaUrl().toString(QUrl::FullyEncoded); + QString title = menuData->titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); QMimeData *data = new QMimeData(); data->setText(urlString); if (menuData->mediaType() == WebEngineContextMenuData::MediaTypeAudio) - data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"></audio>")); + data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"") + title + + QStringLiteral("></audio>")); else - data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"></video>")); + data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"") + title + + QStringLiteral("></video>")); data->setUrls(QList<QUrl>() << menuData->mediaUrl()); qApp->clipboard()->setMimeData(data); } @@ -2292,14 +2304,12 @@ ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, QWebEnginePage::FileSelec QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) { #if QT_CONFIG(filedialog) - // FIXME: Should we expose this in QWebPage's API ? Right now it is very open and can contain a mix and match of file extensions (which QFileDialog - // can work with) and mimetypes ranging from text/plain or images/* to application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - Q_UNUSED(acceptedMimeTypes); + const QStringList &filter = FilePickerController::nameFilters(acceptedMimeTypes); QStringList ret; QString str; switch (static_cast<FilePickerController::FileChooserMode>(mode)) { case FilePickerController::OpenMultiple: - ret = QFileDialog::getOpenFileNames(view(), QString()); + ret = QFileDialog::getOpenFileNames(view(), QString(), QString(), filter.join(";;"), nullptr, QFileDialog::HideNameFilterDetails); break; // Chromium extension, not exposed as part of the public API for now. case FilePickerController::UploadFolder: @@ -2313,7 +2323,7 @@ QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringLis ret << str; break; case FilePickerController::Open: - str = QFileDialog::getOpenFileName(view(), QString(), oldFiles.first()); + str = QFileDialog::getOpenFileName(view(), QString(), oldFiles.first(), filter.join(";;"), nullptr, QFileDialog::HideNameFilterDetails); if (!str.isNull()) ret << str; break; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 09f5ce2fd..470babf8f 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -227,6 +227,7 @@ void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info) itemPrivate->downloadId = info.id; itemPrivate->downloadState = info.accepted ? QWebEngineDownloadItem::DownloadInProgress : QWebEngineDownloadItem::DownloadRequested; + itemPrivate->startTime = info.startTime; itemPrivate->downloadDirectory = QFileInfo(info.path).path(); itemPrivate->downloadFileName = QFileInfo(info.path).fileName(); itemPrivate->suggestedFileName = info.suggestedFileName; diff --git a/src/webenginewidgets/printer_worker.cpp b/src/webenginewidgets/printer_worker.cpp index 94a862cda..8e1c2a985 100644 --- a/src/webenginewidgets/printer_worker.cpp +++ b/src/webenginewidgets/printer_worker.cpp @@ -94,17 +94,9 @@ void PrinterWorker::print() documentCopies = 1; } - bool isLandscape = pdfiumWrapper.pageIsLandscape(0); - QPageLayout::Orientation prevOrientation = m_printer->pageLayout().orientation(); - m_printer->setPageOrientation(isLandscape ? QPageLayout::Landscape : QPageLayout::Portrait); + qreal resolution = m_printer->resolution() / 72.0; // pdfium uses points so 1/72 inch QPainter painter; - if (!painter.begin(m_printer)) { - qWarning("Failure to print on printer %ls: Could not open printer for painting.", - qUtf16Printable(m_printer->printerName())); - Q_EMIT resultReady(false); - return; - } for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { if (printedDocuments > 0) @@ -113,11 +105,20 @@ void PrinterWorker::print() int currentPageIndex = fromPage; for (int i = 0; true; i++) { - prevOrientation = m_printer->pageLayout().orientation(); - isLandscape = pdfiumWrapper.pageIsLandscape(currentPageIndex - 1); + QSizeF documentSize = (pdfiumWrapper.pageSize(currentPageIndex - 1) * resolution); + bool isLandscape = documentSize.width() > documentSize.height(); m_printer->setPageOrientation(isLandscape ? QPageLayout::Landscape : QPageLayout::Portrait); - - QSize pageSize = m_printer->pageRect().size(); + QRectF pageRect = m_printer->pageRect(QPrinter::DevicePixel); + documentSize = documentSize.scaled(pageRect.size(), Qt::KeepAspectRatio); + + // setPageOrientation has to be called before qpainter.begin() or before qprinter.newPage() so correct metrics is used, + // therefore call begin now for only first page + if (!painter.isActive() && !painter.begin(m_printer)) { + qWarning("Failure to print on printer %ls: Could not open printer for painting.", + qUtf16Printable(m_printer->printerName())); + Q_EMIT resultReady(false); + return; + } if (i > 0) m_printer->newPage(); @@ -132,21 +133,12 @@ void PrinterWorker::print() if (printedPages > 0) m_printer->newPage(); - QImage currentImage = pdfiumWrapper.pageAsQImage(currentPageIndex - 1); + QImage currentImage = pdfiumWrapper.pageAsQImage(currentPageIndex - 1,documentSize.width(),documentSize.height()); if (currentImage.isNull()) { Q_EMIT resultReady(false); return; } - - QRect targetRect = currentImage.rect(); - // Scale down currentImage by both width and height to fit into the drawable area of the page. - float scaleFactor = (float)pageSize.width() / (float)targetRect.width(); - targetRect = QRect(0, 0, targetRect.width() * scaleFactor, targetRect.height() * scaleFactor); - scaleFactor = (float)pageSize.height() / (float)targetRect.height(); - targetRect = QRect(0, 0, targetRect.width() * scaleFactor, targetRect.height() * scaleFactor); - - // Painting operations are automatically clipped to the bounds of the drawable part of the page. - painter.drawImage(targetRect, currentImage, currentImage.rect()); + painter.drawImage(0,0, currentImage); } if (currentPageIndex == toPage) @@ -156,8 +148,6 @@ void PrinterWorker::print() currentPageIndex++; else currentPageIndex--; - - m_printer->setPageOrientation(prevOrientation); } } painter.end(); diff --git a/tests/auto/quick/qmltests/data/accepttypes.html b/tests/auto/quick/qmltests/data/accepttypes.html new file mode 100644 index 000000000..aff39f96e --- /dev/null +++ b/tests/auto/quick/qmltests/data/accepttypes.html @@ -0,0 +1,21 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title>Default title</title> +</head> + +<body> +<input type="file" name="file" id="upfile" accept=""> + +<script> +window.onload = function() { + document.getElementById("upfile").focus(); +} + +function setAcceptType(acceptType) { + document.getElementById("upfile").accept = acceptType; + document.title = acceptType; +} +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/tst_filePicker.qml b/tests/auto/quick/qmltests/data/tst_filePicker.qml index fad81273c..c9572224e 100644 --- a/tests/auto/quick/qmltests/data/tst_filePicker.qml +++ b/tests/auto/quick/qmltests/data/tst_filePicker.qml @@ -61,6 +61,7 @@ TestWebEngineView { FilePickerParams.filePickerOpened = false FilePickerParams.selectFiles = false FilePickerParams.selectedFilesUrl = [] + FilePickerParams.nameFilters = [] titleSpy.clear() terminationSpy.clear() } @@ -260,5 +261,33 @@ TestWebEngineView { tryCompare(webEngineView, "title", row.expected); webEngineView.fileDialogRequested.disconnect(acceptedFileHandler); } + + function test_acceptFileTypes_data() { + return [ + { tag: "CustomSuffix", input: ".pug", expected: ".pug", exactMatch: false}, + { tag: "CustomMime", input: "dog/pug", expected: "Accepted types ()", exactMatch: true}, + { tag: "CustomGlob", input: "dog/*", expected: "Accepted types ()", exactMatch: true}, + { tag: "Invalid", input: "---", expected: "Accepted types ()", exactMatch: true}, + { tag: "Jpeg", input: "image/jpeg", expected: ".jpeg", exactMatch: false} + ]; + } + + function test_acceptFileTypes(row) { + var expectedFileName; + + webEngineView.url = Qt.resolvedUrl("accepttypes.html"); + verify(webEngineView.waitForLoadSucceeded()); + + webEngineView.runJavaScript("setAcceptType('" + row.input + "');"); + tryCompare(webEngineView, "title", row.input); + + keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + + if (row.exactMatch) + compare(FilePickerParams.nameFilters[0], row.expected); + else + verify(FilePickerParams.nameFilters[0].includes(row.expected)); + } } } diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/Controls1Delegates/FilePicker.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/Controls1Delegates/FilePicker.qml index 5d78807df..745f533f5 100644 --- a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/Controls1Delegates/FilePicker.qml +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/Controls1Delegates/FilePicker.qml @@ -33,12 +33,14 @@ QtObject { property bool selectMultiple: false; property bool selectExisting: false; property bool selectFolder: false; + property var nameFilters: []; signal filesSelected(var fileList); signal rejected(); function open() { FilePickerParams.filePickerOpened = true; + FilePickerParams.nameFilters = nameFilters; if (FilePickerParams.selectFiles) filesSelected(FilePickerParams.selectedFilesUrl) else diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml index 83ac8a66e..02b0da1d4 100644 --- a/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml @@ -33,4 +33,5 @@ QtObject { property var selectedFilesUrl: []; property bool selectFiles: false; property bool filePickerOpened: false; + property var nameFilters: []; } diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 00e884e11..071795d96 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -6,6 +6,7 @@ IMPORTPATH += $$PWD/data OTHER_FILES += \ $$PWD/data/TestWebEngineView.qml \ + $$PWD/data/accepttypes.html \ $$PWD/data/alert.html \ $$PWD/data/append-document-title.js \ $$PWD/data/big-user-script.js \ diff --git a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp index b587f3b27..c9abe9cfe 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp +++ b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp @@ -34,9 +34,10 @@ #include <QQuickItem> #include <QPainter> #include <qtwebengineglobal.h> -#include <private/qquickwebenginetestsupport_p.h> #include <private/qquickwebengineview_p.h> +#include <map> + class TestView : public QQuickView { Q_OBJECT public: @@ -59,91 +60,57 @@ Q_SIGNALS: class tst_QQuickWebEngineViewGraphics : public QObject { Q_OBJECT -public: - tst_QQuickWebEngineViewGraphics(); - virtual ~tst_QQuickWebEngineViewGraphics(); - -public Q_SLOTS: - void initTestCase(); - void init(); - void cleanup(); - private Q_SLOTS: void simpleGraphics(); - void renderMultipleTimes(); - void renderAfterNodeCleanup(); void showHideShow(); void simpleAcceleratedLayer(); void reparentToOtherWindow(); private: void setHtml(const QString &html); - QScopedPointer<TestView> m_view; - QScopedPointer<QQuickWebEngineTestSupport> m_testSupport; + QScopedPointer<TestView> m_view{new TestView}; }; static const QString greenSquare("<div style=\"background-color: #00ff00; position:absolute; left:50px; top: 50px; width: 50px; height: 50px;\"></div>"); static const QString acLayerGreenSquare("<div style=\"background-color: #00ff00; position:absolute; left:50px; top: 50px; width: 50px; height: 50px; transform: translateZ(0); -webkit-transform: translateZ(0);\"></div>"); -static QImage get150x150GreenReferenceImage() +static QImage makeGreenSquare(QImage::Format format) { - static QImage reference; - if (reference.isNull()) { - reference = QImage(150, 150, QImage::Format_RGB32); - reference.fill(Qt::white); - QPainter painter(&reference); - painter.fillRect(50, 50, 50, 50, QColor("#00ff00")); - } - return reference; + QImage image(150, 150, format); + image.fill(Qt::white); + QPainter painter(&image); + painter.fillRect(50, 50, 50, 50, QColor("#00ff00")); + return image; } -tst_QQuickWebEngineViewGraphics::tst_QQuickWebEngineViewGraphics() +static QImage getGreenSquare(QImage::Format format) { + static std::map<QImage::Format, QImage> images; + auto it = images.find(format); + if (it == images.end()) + it = images.emplace(format, makeGreenSquare(format)).first; + return it->second; } -tst_QQuickWebEngineViewGraphics::~tst_QQuickWebEngineViewGraphics() -{ -} - -// This will be called before the first test function is executed. -// It is only called once. -void tst_QQuickWebEngineViewGraphics::initTestCase() -{ - QtWebEngine::initialize(); - m_testSupport.reset(new QQuickWebEngineTestSupport); -} - -void tst_QQuickWebEngineViewGraphics::init() -{ - m_view.reset(new TestView); -} - -void tst_QQuickWebEngineViewGraphics::cleanup() +static void verifyGreenSquare(QQuickWindow *window) { + QImage actual, expected; + bool ok = QTest::qWaitFor([&](){ + actual = window->grabWindow(); + expected = getGreenSquare(actual.format()); + return actual == expected; + }, 10000); + if (!ok) { + // actual.save("actual.png"); + // expected.save("expected.png"); + QFAIL("expected green square to be rendered"); + } } void tst_QQuickWebEngineViewGraphics::simpleGraphics() { setHtml(greenSquare); - QCOMPARE(m_view->grabWindow(), get150x150GreenReferenceImage()); -} - -void tst_QQuickWebEngineViewGraphics::renderMultipleTimes() -{ - // This test is for loadVisuallyCommitted signal. - // The setHtml() should not fail after multiple page load. - setHtml(greenSquare); - setHtml(greenSquare); -} - -void tst_QQuickWebEngineViewGraphics::renderAfterNodeCleanup() -{ - setHtml(greenSquare); - - // Do it twice in a row, if the window isn't visible, the scene graph is going to be trashed by QQuickWindow::grabWindow after the first render. - QVERIFY(!m_view->isVisible()); - QCOMPARE(m_view->grabWindow(), get150x150GreenReferenceImage()); - QCOMPARE(m_view->grabWindow(), get150x150GreenReferenceImage()); + verifyGreenSquare(m_view.data()); } void tst_QQuickWebEngineViewGraphics::showHideShow() @@ -152,19 +119,19 @@ void tst_QQuickWebEngineViewGraphics::showHideShow() QSignalSpy exposeSpy(m_view.data(), SIGNAL(exposeChanged())); m_view->show(); QVERIFY(exposeSpy.wait()); - QCOMPARE(m_view->grabWindow(), get150x150GreenReferenceImage()); + verifyGreenSquare(m_view.data()); m_view->hide(); QVERIFY(exposeSpy.wait()); m_view->show(); QVERIFY(exposeSpy.wait()); - QCOMPARE(m_view->grabWindow(), get150x150GreenReferenceImage()); + verifyGreenSquare(m_view.data()); } void tst_QQuickWebEngineViewGraphics::simpleAcceleratedLayer() { setHtml(acLayerGreenSquare); - QCOMPARE(m_view->grabWindow(), get150x150GreenReferenceImage()); + verifyGreenSquare(m_view.data()); } void tst_QQuickWebEngineViewGraphics::reparentToOtherWindow() @@ -175,7 +142,7 @@ void tst_QQuickWebEngineViewGraphics::reparentToOtherWindow() window.create(); m_view->rootObject()->setParentItem(window.contentItem()); - QCOMPARE(window.grabWindow(), get150x150GreenReferenceImage()); + verifyGreenSquare(&window); } void tst_QQuickWebEngineViewGraphics::setHtml(const QString &html) @@ -187,10 +154,8 @@ void tst_QQuickWebEngineViewGraphics::setHtml(const QString &html) QQuickWebEngineView *webEngineView = static_cast<QQuickWebEngineView *>(m_view->rootObject()); webEngineView->setProperty("url", QUrl(QStringLiteral("data:text/html,%1").arg(htmlData))); - webEngineView->setTestSupport(m_testSupport.data()); - QVERIFY(waitForViewportReady(webEngineView)); - QCOMPARE(m_view->rootObject()->property("loading"), QVariant(false)); + QTRY_COMPARE_WITH_TIMEOUT(m_view->rootObject()->property("loading"), QVariant(false), 30000); } -QTEST_MAIN(tst_QQuickWebEngineViewGraphics) +W_QTEST_MAIN(tst_QQuickWebEngineViewGraphics) #include "tst_qquickwebengineviewgraphics.moc" diff --git a/tests/auto/quick/shared/util.h b/tests/auto/quick/shared/util.h index bc5ae445b..fbce8bfa7 100644 --- a/tests/auto/quick/shared/util.h +++ b/tests/auto/quick/shared/util.h @@ -107,21 +107,6 @@ inline bool waitForLoadFailed(QQuickWebEngineView *webEngineView, int timeout = return spy.wait(timeout); } -inline bool waitForViewportReady(QQuickWebEngineView *webEngineView, int timeout = 10000) -{ -#if QT_CONFIG(webengine_testsupport) - QSignalSpy spy(reinterpret_cast<QObject *>(webEngineView->testSupport()), SIGNAL(loadVisuallyCommitted())); - return spy.wait(timeout); -#else - Q_UNUSED(webEngineView) - Q_UNUSED(timeout) - qFatal("Test Support API is disabled. The result is not reliable.\ - Use the following command to build Test Support module and rebuild WebEngineView API:\ - qmake -r -- --feature-testsupport=yes && make"); - return false; -#endif -} - inline QVariant evaluateJavaScriptSync(QQuickWebEngineView *view, const QString &script) { QQmlEngine *engine = qmlEngine(view); diff --git a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp index 1469ddb15..46038cdc6 100644 --- a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp +++ b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp @@ -522,10 +522,10 @@ void tst_FaviconManager::touchIconWithSameURL() "<link rel='icon' type='image/png' href='" + icon + "'/>" "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>" "</html>"); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); // The default favicon has to be loaded even if its URL is also set as a touch icon while touch icons are disabled. - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 1); QCOMPARE(m_page->iconUrl().toString(), icon); QTRY_COMPARE(iconChangedSpy.count(), 1); diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp index d34e3cefe..bbcef2226 100644 --- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp +++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp @@ -622,14 +622,17 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks() void tst_QWebEngineDownloadItem::downloadPage_data() { + QTest::addColumn<bool>("saveWithPageAction"); QTest::addColumn<QWebEngineDownloadItem::SavePageFormat>("savePageFormat"); - QTest::newRow("SingleHtmlSaveFormat") << QWebEngineDownloadItem::SingleHtmlSaveFormat; - QTest::newRow("CompleteHtmlSaveFormat") << QWebEngineDownloadItem::CompleteHtmlSaveFormat; - QTest::newRow("MimeHtmlSaveFormat") << QWebEngineDownloadItem::MimeHtmlSaveFormat; + QTest::newRow("SingleHtmlSaveFormat") << false << QWebEngineDownloadItem::SingleHtmlSaveFormat; + QTest::newRow("CompleteHtmlSaveFormat") << false << QWebEngineDownloadItem::CompleteHtmlSaveFormat; + QTest::newRow("MimeHtmlSaveFormat") << false << QWebEngineDownloadItem::MimeHtmlSaveFormat; + QTest::newRow("SavePageAction") << true << QWebEngineDownloadItem::MimeHtmlSaveFormat; } void tst_QWebEngineDownloadItem::downloadPage() { + QFETCH(bool, saveWithPageAction); QFETCH(QWebEngineDownloadItem::SavePageFormat, savePageFormat); // Set up HTTP server @@ -649,12 +652,12 @@ void tst_QWebEngineDownloadItem::downloadPage() // Set up profile and download handler QTemporaryDir tmpDir; QVERIFY(tmpDir.isValid()); - QString downloadPath = tmpDir.path() + QStringLiteral("/test.html"); + QString downloadFileName("test.html"), downloadPath = tmpDir.filePath(downloadFileName); QUrl downloadUrl = m_server->url("/"); int acceptedCount = 0; int finishedCount = 0; ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { - QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadInProgress); + QCOMPARE(item->state(), saveWithPageAction ? QWebEngineDownloadItem::DownloadRequested : QWebEngineDownloadItem::DownloadInProgress); QCOMPARE(item->isFinished(), false); QCOMPARE(item->totalBytes(), -1); QCOMPARE(item->receivedBytes(), 0); @@ -663,11 +666,19 @@ void tst_QWebEngineDownloadItem::downloadPage() QCOMPARE(item->isSavePageDownload(), true); // FIXME(juvaldma): why is mimeType always the same? QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive")); - QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); QCOMPARE(item->savePageFormat(), savePageFormat); QCOMPARE(item->url(), downloadUrl); QCOMPARE(item->page(), m_page); - // no need to call item->accept() + + if (saveWithPageAction) { + QVERIFY(!item->downloadDirectory().isEmpty()); + QVERIFY(!item->downloadFileName().isEmpty()); + item->setDownloadDirectory(tmpDir.path()); + item->setDownloadFileName(downloadFileName); + item->accept(); + } // save with explicit path accepts download automatically + + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); @@ -697,7 +708,11 @@ void tst_QWebEngineDownloadItem::downloadPage() QCOMPARE(indexRequestCount, 1); // Save some HTML - m_page->save(downloadPath, savePageFormat); + if (saveWithPageAction) + m_page->triggerAction(QWebEnginePage::SavePage); + else + m_page->save(downloadPath, savePageFormat); + QTRY_COMPARE(acceptedCount, 1); QTRY_COMPARE(finishedCount, 1); QFile file(downloadPath); diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 27aa7a1f7..d8c1a5360 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -225,6 +225,7 @@ private Q_SLOTS: void editActionsWithoutSelection(); void customUserAgentInNewTab(); + void renderProcessCrashed(); private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); @@ -991,6 +992,19 @@ void tst_QWebEnginePage::findText() QTRY_COMPARE(signalSpy.count(), 1); QTRY_COMPARE(m_view->selectedText(), QString("foo")); } + + // Invoking startFinding operation for the same text twice. Without any wait, the second one + // should interrupt the first one. + { + QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); + m_view->findText("foo", 0); + m_view->findText("foo", 0); + QTRY_COMPARE(signalSpy.count(), 2); + QTRY_VERIFY(m_view->selectedText().isEmpty()); + + QCOMPARE(signalSpy.at(0).value(0).value<QWebEngineFindTextResult>().numberOfMatches(), 0); + QCOMPARE(signalSpy.at(1).value(0).value<QWebEngineFindTextResult>().numberOfMatches(), 1); + } } void tst_QWebEnginePage::findTextResult() @@ -4410,6 +4424,26 @@ void tst_QWebEnginePage::customUserAgentInNewTab() QCOMPARE(lastUserAgent, profile2.httpUserAgent().toUtf8()); } +void tst_QWebEnginePage::renderProcessCrashed() +{ + using Status = QWebEnginePage::RenderProcessTerminationStatus; + QWebEngineProfile profile; + QWebEnginePage page(&profile); + bool done = false; + Status status; + connect(&page, &QWebEnginePage::renderProcessTerminated, [&](Status newStatus) { + status = newStatus; + done = true; + }); + page.load(QUrl("chrome://crash")); + QTRY_VERIFY_WITH_TIMEOUT(done, 20000); + // The status depends on whether stack traces are enabled. With + // --disable-in-process-stack-traces we get an AbnormalTerminationStatus, + // otherwise a CrashedTerminationStatus. + QVERIFY(status == QWebEnginePage::CrashedTerminationStatus || + status == QWebEnginePage::AbnormalTerminationStatus); +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) |