diff options
author | Michael BrĂ¼ning <michael.bruning@qt.io> | 2016-12-07 13:55:20 +0100 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2016-12-07 13:55:20 +0100 |
commit | c7f8e360da41df8b81004fe45f1582845a951c2b (patch) | |
tree | 32cf6ecb336af7d89a0a86153bb07ee49f23baa9 | |
parent | 3d000cfc013158f56c0b088c9ee99b03938ef50b (diff) | |
parent | 5ec330cec86cd7781ced295790ce93ac8748dcc4 (diff) |
Merge remote-tracking branch 'origin/5.8' into dev
Conflicts:
src/3rdparty
Change-Id: Ie7b7c469aa24716816a23b8fe7a8df9f477a9f67
58 files changed, 931 insertions, 530 deletions
diff --git a/dist/changes-5.7.1 b/dist/changes-5.7.1 new file mode 100644 index 000000000..bf5934320 --- /dev/null +++ b/dist/changes-5.7.1 @@ -0,0 +1,57 @@ +Qt 5.7.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.7.0. + +Qt 5.7.1 contains a merge from Qt 5.6.2 and all changes in Qt 5.6.2 are +also in Qt 5.7.1. For more see changes-5.6.2. + +Qt 5.7 introduces many new features and improvements as well as bugfixes +over the 5.6.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.7 series is binary compatible with the 5.6.x series. +Applications compiled for 5.6 will continue to run with 5.7. + +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: + * Security fixes from Chromium up to version 54.0.2840.87 + Including: CVE-2016-5133, CVE-2016-5147, CVE-2016-5153, CVE-2016-5155, + CVE-2016-5161, CVE-2016-5166, CVE-2016-5170, CVE-2016-5171, + CVE-2016-5172, CVE-2016-5181, CVE-2016-5185, CVE-2016-5186, + CVE-2016-5187, CVE-2016-5188, CVE-2016-5192, CVE-2016-5198 + * Support for macOS 10.12 Sierra + * Various backported crash and assert fixes + + - QtWebEngineCore: + * [QTBUG-51244, QTBUG-54795] Fixed select control issues + * Fixed several focus issues. + * Fixed regression with fine-grained wheel events. + * [QTBUG-54221] Fixed editing short-cuts in plugins. + * [QTBUG-54222] Fixed potential infinite loop on history load. + * Fixed Flash plugin clipboard access. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + + - Linux: + * [QTBUG-55367] Fixed reading timezone when running sandboxed + * Fixed crash when using Wayland QPA + * Improved OpenGL check, so EGL/GLES2 mode can be used with Desktop + OpenGL if the driver has th ARB_ES2_compatibility extension. + + - Windows: + * [QTBUG-52201, QTBUG-55501, QTBUG-56020] Fixed crashes and asserts + upon initialization of the global shared OpenGL context. diff --git a/dist/changes-5.8.0 b/dist/changes-5.8.0 new file mode 100644 index 000000000..abead3c38 --- /dev/null +++ b/dist/changes-5.8.0 @@ -0,0 +1,95 @@ +Qt 5.8 introduces many new features and improvements as well as bugfixes +over the 5.7.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.8 series is binary compatible with the 5.7.x series. +Applications compiled for 5.7 will continue to run with 5.8. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + +**************************************************************************** +* General * +**************************************************************************** + + - Important Changes: + * The enum value ResourceTypeUnknown has changed value because there was + a mismatch between 5.6 and 5.7+ definitions. In general any unknown + ResourceType value should be handled as unknown for forward + compatibility, because more types are and can be added in later + Qt versions. + + - Chromium Snapshot: + * The Chromium version has been updated to 53.0.2785.148. + + - General: + * Spellchecking support has been introduced. + * Build time options can now be controlled via arguments to the global + configure script or app. + * [QTBUG-52999] Added focusOnNavigationEnabled setting which allows + controlling whether a web view will receive focus on a navigation + request. Previously the view always received the focus. + * [QTBUG-54902] Added setting to allow secure content to run insecure + content. + * [QTBUG-54918] Printing will now include the CSS background of the + printed elements by default. This restores the default behavior from Qt + WebKit. It can be controlled via the PrintElementBackgrounds web + setting. + * Some chrome:// URLs are now supported. For instance chrome://gpu. + * [QTBUG-53042] Pepper Flash glyph draw is now supported. + * A DownloadType has been added to download items. + * Greasemonkey attributes are now supported in user scripts. + * [QTBUG-55766] Added support for colored underline and background + to InputMethodEvent. + * Qt no-opengl builds are now supported. + + +**************************************************************************** +* Qt WebEngine[QML] * +**************************************************************************** + + - General: + * [QTBUG-53467][QTBUG-51177] Qt WebEngine (QML) now optionally uses Qt + Quick 2 Controls to show standard dialogs. + * [QTBUG-51190] Added ability to provide custom dialogs for HTTP and + proxy authentication, JavaScript alerts, file and color picking, and + form validation messages. + * [QTBUG-52554] Added ability to show custom context menu. + + - QQuickWebEngineView: + * ToolTip (HTML title attributes) are now handled. + * View Source feature is now supported. + + +**************************************************************************** +* Qt WebEngineWidgets * +**************************************************************************** + + - Scenegraph Integration: + * Using the software rasterizing scenegraph backend is now supported. + + - Printing: + * Enables printing QWebPage content on a QPrinter. Currently does not + support previewing the document. Widgets only for the moment. + + - QWebEnginePage: + * Introduced a new save method to save a page to a predefined location. + + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + + - Linux: + * Pepper Flash is now also searched for in /usr/lib/adobe-flashplugin/ + + - Windows: + * MSVC2015 and Windows 10 SDK are now required. diff --git a/src/3rdparty b/src/3rdparty -Subproject f5a732820b31651bafc60cd64f85b85c7f82532 +Subproject 93b3786290ac16c95f15c95e2c2f3d8254171ab diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index bd2fecac2..a3806fc63 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -64,7 +64,7 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePing, content::RESOURCE ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker, content::RESOURCE_TYPE_SERVICE_WORKER) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeCspReport, content::RESOURCE_TYPE_CSP_REPORT) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePluginResource, content::RESOURCE_TYPE_PLUGIN_RESOURCE) -ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeUnknown, content::RESOURCE_TYPE_LAST_TYPE) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeLast, content::RESOURCE_TYPE_LAST_TYPE) ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::LinkNavigation, QWebEngineUrlRequestInfo::NavigationTypeLink) ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::TypedNavigation, QWebEngineUrlRequestInfo::NavigationTypeTyped) @@ -175,6 +175,9 @@ QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPriva HTTP POST requests to specified servers. (Added in Qt 5.7) \value ResourceTypePluginResource A resource requested by a plugin. (Added in Qt 5.7) \value ResourceTypeUnknown Unknown request type. + + \note For forward compatibility all values not matched should be treated as unknown, + not just \c ResourceTypeUnknown. */ /*! diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h index d75ceabf6..52463a1b3 100644 --- a/src/core/api/qwebengineurlrequestinfo.h +++ b/src/core/api/qwebengineurlrequestinfo.h @@ -75,7 +75,10 @@ public: ResourceTypeServiceWorker, // the main resource of a service worker. ResourceTypeCspReport, // Content Security Policy (CSP) violation report ResourceTypePluginResource, // A resource requested by a plugin - ResourceTypeUnknown +#ifndef Q_QDOC + ResourceTypeLast, +#endif + ResourceTypeUnknown = 255 }; enum NavigationType { diff --git a/src/core/common/qt_ipc_logging.cpp b/src/core/common/qt_ipc_logging.cpp new file mode 100644 index 000000000..124124de1 --- /dev/null +++ b/src/core/common/qt_ipc_logging.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED + +#if defined(IPC_MESSAGE_LOG_ENABLED) +#define IPC_MESSAGE_MACROS_LOG_ENABLED +#include "content/public/common/content_ipc_logging.h" +#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \ + content::RegisterIPCLogger(msg_id, logger) +#include "common/qt_messages.h" +#endif diff --git a/src/core/config/common.pri b/src/core/config/common.pri index 7a9656fca..b5bb23684 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -2,8 +2,6 @@ # Trigger Qt-specific build conditions. GYP_CONFIG += use_qt=1 -# Enable printing. We enable preview because we use preview logic even if we don't support preview. -GYP_CONFIG += enable_basic_printing=1 enable_print_preview=1 # We do not want to ship more external binary blobs, so let v8 embed its startup data. GYP_CONFIG += v8_use_external_startup_data=0 # WebSpeech requires Google API keys and adds dependencies on speex and flac. diff --git a/src/core/config/desktop_linux.pri b/src/core/config/desktop_linux.pri index e28d7eb7c..23044619b 100644 --- a/src/core/config/desktop_linux.pri +++ b/src/core/config/desktop_linux.pri @@ -5,6 +5,8 @@ include(linux.pri) GYP_CONFIG += \ desktop_linux=1 \ enable_widevine=1 \ + enable_basic_printing=1 \ + enable_print_preview=1 \ enable_pdf=1 clang { diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index be037cbde..4111236ed 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -26,6 +26,8 @@ GYP_CONFIG += \ make_clang_dir=\"$${QMAKE_CLANG_DIR}\" \ clang_use_chrome_plugins=0 \ enable_widevine=1 \ + enable_basic_printing=1 \ + enable_print_preview=1 \ enable_pdf=1 # Force touch API is used in 49-based Chromium, which is included starting with 10.10.3 SDK, so we diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index 9564cf9b7..a1c116ff8 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -7,6 +7,8 @@ GYP_CONFIG += \ remoting=0 \ use_ash=0 \ enable_widevine=1 \ + enable_basic_printing=1 \ + enable_print_preview=1 \ enable_pdf=1 # Libvpx build needs additional search path on Windows. diff --git a/src/core/core_common.pri b/src/core/core_common.pri index 721e8c71a..9c29aea71 100644 --- a/src/core/core_common.pri +++ b/src/core/core_common.pri @@ -10,4 +10,3 @@ CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() INCLUDEPATH += $$CHROMIUM_SRC_DIR qtHaveModule(positioning):QT += positioning -qtHaveModule(printsupport):QT += printsupport diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 2fae21c4d..a09683ba6 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -53,6 +53,7 @@ SOURCES = \ clipboard_qt.cpp \ color_chooser_qt.cpp \ color_chooser_controller.cpp \ + common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ content_client_qt.cpp \ @@ -74,6 +75,7 @@ SOURCES = \ native_web_keyboard_event_qt.cpp \ network_delegate_qt.cpp \ ozone_platform_eglfs.cpp \ + pdfium_document_wrapper_qt.cpp \ permission_manager_qt.cpp \ process_main.cpp \ proxy_config_service_qt.cpp \ @@ -154,6 +156,7 @@ HEADERS = \ media_capture_devices_dispatcher.h \ network_delegate_qt.h \ ozone_platform_eglfs.h \ + pdfium_document_wrapper_qt.h \ permission_manager_qt.h \ process_main.h \ proxy_config_service_qt.h \ @@ -210,8 +213,3 @@ qtHaveModule(positioning) { HEADERS += location_provider_qt.h DEFINES += QT_USE_POSITIONING=1 } - -qtHaveModule(printsupport) { - SOURCES += pdfium_printing_wrapper_qt.cpp - HEADERS += pdfium_printing_wrapper_qt.h -} diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index ed54f2ec8..9b4c415c9 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -58,7 +58,7 @@ namespace QtWebEngineCore { -int pageTransitionToNavigationType(ui::PageTransition transition) +WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition) { int32_t qualifier = ui::PageTransitionGetQualifier(transition); @@ -81,6 +81,18 @@ int pageTransitionToNavigationType(ui::PageTransition transition) } } +QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType) +{ + if (resourceType >= 0 && resourceType < content::ResourceType(QWebEngineUrlRequestInfo::ResourceTypeLast)) + return static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType); + return QWebEngineUrlRequestInfo::ResourceTypeUnknown; +} + +QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType) +{ + return static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType); +} + NetworkDelegateQt::NetworkDelegateQt(URLRequestContextGetterQt *requestContext) : m_requestContextGetter(requestContext) { @@ -94,7 +106,7 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C const content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request); content::ResourceType resourceType = content::RESOURCE_TYPE_LAST_TYPE; - int navigationType = QWebEngineUrlRequestInfo::NavigationTypeOther; + WebContentsAdapterClient::NavigationType navigationType = WebContentsAdapterClient::OtherNavigation; if (resourceInfo) { resourceType = resourceInfo->GetResourceType(); @@ -105,11 +117,11 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C QWebEngineUrlRequestInterceptor* interceptor = m_requestContextGetter->m_requestInterceptor; if (interceptor) { - QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType) - , static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType) - , qUrl - , toQt(request->first_party_for_cookies()) - , QByteArray::fromStdString(request->method())); + QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), + toQt(navigationType), + qUrl, + toQt(request->first_party_for_cookies()), + QByteArray::fromStdString(request->method())); QWebEngineUrlRequestInfo requestInfo(infoPrivate); interceptor->interceptRequest(requestInfo); if (requestInfo.changed()) { diff --git a/src/core/pdfium_printing_wrapper_qt.cpp b/src/core/pdfium_document_wrapper_qt.cpp index fceb381af..7c43c77db 100644 --- a/src/core/pdfium_printing_wrapper_qt.cpp +++ b/src/core/pdfium_document_wrapper_qt.cpp @@ -36,23 +36,22 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - -#include "pdfium_printing_wrapper_qt.h" +#if defined (ENABLE_PDF) +#include "pdfium_document_wrapper_qt.h" #include <QtCore/qhash.h> #include <QtGui/qimage.h> #include <QtGui/qpainter.h> -#include <QtPrintSupport/qprinter.h> #include "third_party/pdfium/public/fpdf_doc.h" #include "third_party/pdfium/public/fpdfview.h" namespace QtWebEngineCore { -int PdfiumPrintingWrapperQt::m_libraryUsers = 0; +int PdfiumDocumentWrapperQt::m_libraryUsers = 0; -class PDFiumPageWrapper { +class QWEBENGINE_EXPORT PdfiumPageWrapperQt { public: - PDFiumPageWrapper(void *data, int pageIndex, int targetWidth, int targetHeight) + PdfiumPageWrapperQt(void *data, int pageIndex, int targetWidth, int targetHeight) : m_pageData(FPDF_LoadPage(data, pageIndex)) , m_width(FPDF_GetPageWidth(m_pageData)) , m_height(FPDF_GetPageHeight(m_pageData)) @@ -61,7 +60,7 @@ public: { } - PDFiumPageWrapper() + PdfiumPageWrapperQt() : m_pageData(nullptr) , m_width(-1) , m_height(-1) @@ -70,7 +69,7 @@ public: { } - virtual ~PDFiumPageWrapper() + virtual ~PdfiumPageWrapperQt() { FPDF_ClosePage(m_pageData); } @@ -125,111 +124,49 @@ private: }; -PdfiumPrintingWrapperQt::PdfiumPrintingWrapperQt(const void *pdfData, size_t size, const char *password) +PdfiumDocumentWrapperQt::PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const QSize& imageSize, const char *password) + : m_imageSize(imageSize * 2.0) { - Q_ASSERT(pdfData); - Q_ASSERT(size); - if (m_libraryUsers++ == 0) - FPDF_InitLibrary(); + Q_ASSERT(pdfData); + Q_ASSERT(size); + if (m_libraryUsers++ == 0) + FPDF_InitLibrary(); - m_documentHandle = FPDF_LoadMemDocument(pdfData, static_cast<int>(size), password); - m_pageCount = FPDF_GetPageCount(m_documentHandle); + m_documentHandle = FPDF_LoadMemDocument(pdfData, static_cast<int>(size), password); + m_pageCount = FPDF_GetPageCount(m_documentHandle); } -bool PdfiumPrintingWrapperQt::printOnPrinter(QPrinter &printer) +QImage PdfiumDocumentWrapperQt::pageAsQImage(size_t index) { if (!m_documentHandle || !m_pageCount) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) - qWarning("Failure to print on printer %ls: invalid document.\n", qUtf16Printable(printer.printerName())); -#endif - return false; - } - - int toPage = printer.toPage(); - int fromPage = printer.fromPage(); - bool ascendingOrder = true; - - if (fromPage == 0 && toPage == 0) { - fromPage = 1; - toPage = m_pageCount; + qWarning("Failure to generate QImage from invalid or empty PDF document."); + return QImage(); } - fromPage = qMax(1, fromPage); - toPage = qMin(m_pageCount, toPage); - if (printer.pageOrder() == QPrinter::LastPageFirst) { - qSwap(fromPage, toPage); - ascendingOrder = false; + if (static_cast<int>(index) >= m_pageCount) { + qWarning("Failure to generate QImage from PDF data: index out of bounds."); + return QImage(); } - int documentCopies = printer.copyCount(); - int pageCopies = 1; - if (printer.collateCopies()) { - pageCopies = documentCopies; - documentCopies = 1; + PdfiumPageWrapperQt *pageWrapper = nullptr; + if (!m_cachedPages.contains(index)) { + pageWrapper = new PdfiumPageWrapperQt(m_documentHandle, index, + m_imageSize.width(), m_imageSize.height()); + m_cachedPages.insert(index, pageWrapper); + } else { + pageWrapper = m_cachedPages.value(index); } - QRect printerPageRect = printer.pageRect(); - int doubledPrinterWidth = 2 * printerPageRect.width(); - int doubledPrinterHeight = 2 * printerPageRect.height(); - - QPainter painter; - if (!painter.begin(&printer)) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) - qWarning("Failure to print on printer %ls: Could not open printer for painting.\n", qUtf16Printable(printer.printerName())); -#endif - return false; - } - - QHash<int, PDFiumPageWrapper*> cachedPages; - for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { - int currentPageIndex = fromPage; - while (true) { - for (int printedPages = 0; printedPages < pageCopies; printedPages++) { - if (printer.printerState() == QPrinter::Aborted - || printer.printerState() == QPrinter::Error) - return false; - - PDFiumPageWrapper *currentPageWrapper; - if (!cachedPages.contains(currentPageIndex - 1)) { - currentPageWrapper - = new PDFiumPageWrapper(m_documentHandle, currentPageIndex - 1 - , doubledPrinterWidth, doubledPrinterHeight); - cachedPages.insert(currentPageIndex - 1, currentPageWrapper); - } else { - currentPageWrapper = cachedPages.value(currentPageIndex - 1); - } - - QImage currentImage = currentPageWrapper->image(); - painter.drawImage(printerPageRect, currentImage, currentImage.rect()); - if (printedPages < pageCopies - 1) - printer.newPage(); - } - - if (currentPageIndex == toPage) - break; - - if (ascendingOrder) - currentPageIndex++; - else - currentPageIndex--; - - printer.newPage(); - } - if (printedDocuments < documentCopies - 1) - printer.newPage(); - } - painter.end(); - - qDeleteAll(cachedPages); - - return true; + return pageWrapper->image(); } -PdfiumPrintingWrapperQt::~PdfiumPrintingWrapperQt() +PdfiumDocumentWrapperQt::~PdfiumDocumentWrapperQt() { + qDeleteAll(m_cachedPages); FPDF_CloseDocument(m_documentHandle); if (--m_libraryUsers == 0) FPDF_DestroyLibrary(); } } +#endif // defined (ENABLE_PDF) diff --git a/src/core/pdfium_printing_wrapper_qt.h b/src/core/pdfium_document_wrapper_qt.h index 3aaf2b461..42ac94a28 100644 --- a/src/core/pdfium_printing_wrapper_qt.h +++ b/src/core/pdfium_document_wrapper_qt.h @@ -37,30 +37,35 @@ ** ****************************************************************************/ -#ifndef PDFIUM_PRINTING_WRAPPER_QT_H -#define PDFIUM_PRINTING_WRAPPER_QT_H +#ifndef PDFIUM_DOCUMENT_WRAPPER_QT_H +#define PDFIUM_DOCUMENT_WRAPPER_QT_H -#include <QtCore/qglobal.h> +#if defined(ENABLE_PDF) +#include "qtwebenginecoreglobal.h" -QT_BEGIN_NAMESPACE -class QPrinter; -QT_END_NAMESPACE +#include <QtCore/qglobal.h> +#include <QtCore/qhash.h> +#include <QtGui/qimage.h> namespace QtWebEngineCore { +class PdfiumPageWrapperQt; -class PdfiumPrintingWrapperQt +class QWEBENGINE_EXPORT PdfiumDocumentWrapperQt { public: - PdfiumPrintingWrapperQt(const void *pdfData, size_t size, const char *password = nullptr); - virtual ~PdfiumPrintingWrapperQt(); - bool printOnPrinter(QPrinter &printer); + PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const QSize &imageSize, const char *password = nullptr); + virtual ~PdfiumDocumentWrapperQt(); + QImage pageAsQImage(size_t index); int pageCount() const { return m_pageCount; } private: static int m_libraryUsers; - void *m_documentHandle; int m_pageCount; + void *m_documentHandle; + QSize m_imageSize; + QHash<int, PdfiumPageWrapperQt*> m_cachedPages; }; } // namespace QtWebEngineCore -#endif // PDFIUM_PRINTING_WRAPPER_QT_H +#endif // defined (ENABLE_PDF) +#endif // PDFIUM_DOCUMENT_WRAPPER_QT_H diff --git a/src/core/render_view_observer_host_qt.cpp b/src/core/render_view_observer_host_qt.cpp index c03cecb38..643eba007 100644 --- a/src/core/render_view_observer_host_qt.cpp +++ b/src/core/render_view_observer_host_qt.cpp @@ -71,8 +71,6 @@ bool RenderViewObserverHostQt::OnMessageReceived(const IPC::Message& message) onDidFetchDocumentMarkup) IPC_MESSAGE_HANDLER(RenderViewObserverHostQt_DidFetchDocumentInnerText, onDidFetchDocumentInnerText) - IPC_MESSAGE_HANDLER(RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout, - onDidFirstVisuallyNonEmptyLayout) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -89,11 +87,4 @@ void RenderViewObserverHostQt::onDidFetchDocumentInnerText(quint64 requestId, co m_adapterClient->didFetchDocumentInnerText(requestId, toQt(innerText)); } -void RenderViewObserverHostQt::onDidFirstVisuallyNonEmptyLayout() -{ - RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt*>(web_contents()->GetRenderWidgetHostView()); - if (rwhv) - rwhv->didFirstVisuallyNonEmptyLayout(); -} - } // namespace QtWebEngineCore diff --git a/src/core/render_view_observer_host_qt.h b/src/core/render_view_observer_host_qt.h index f352be7b9..42d232b01 100644 --- a/src/core/render_view_observer_host_qt.h +++ b/src/core/render_view_observer_host_qt.h @@ -63,7 +63,6 @@ private: bool OnMessageReceived(const IPC::Message& message) Q_DECL_OVERRIDE; void onDidFetchDocumentMarkup(quint64 requestId, const base::string16& markup); void onDidFetchDocumentInnerText(quint64 requestId, const base::string16& innerText); - void onDidFirstVisuallyNonEmptyLayout(); WebContentsAdapterClient *m_adapterClient; }; diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 097dda1cd..70ffe0dcb 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -236,7 +236,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget , m_touchMotionStarted(false) , m_chromiumCompositorData(new ChromiumCompositorData) , m_needsDelegatedFrameAck(false) - , m_didFirstVisuallyNonEmptyLayout(false) + , m_loadVisuallyCommittedState(NotCommitted) , m_adapterClient(0) , m_imeInProgress(false) , m_receivedEmptyImeText(false) @@ -676,9 +676,11 @@ void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32_t output_surface_id, c m_delegate->update(); - if (m_didFirstVisuallyNonEmptyLayout) { + if (m_loadVisuallyCommittedState == NotCommitted) { + m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; + } else if (m_loadVisuallyCommittedState == DidFirstVisuallyNonEmptyPaint) { m_adapterClient->loadVisuallyCommitted(); - m_didFirstVisuallyNonEmptyLayout = false; + m_loadVisuallyCommittedState = NotCommitted; } if (scrollOffsetChanged) @@ -1244,9 +1246,4 @@ void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) } } -void RenderWidgetHostViewQt::didFirstVisuallyNonEmptyLayout() -{ - m_didFirstVisuallyNonEmptyLayout = true; -} - } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index d6c77fada..0b2d7bc9d 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -104,6 +104,12 @@ class RenderWidgetHostViewQt #endif // QT_NO_ACCESSIBILITY { public: + enum LoadVisuallyCommittedState { + NotCommitted, + DidFirstVisuallyNonEmptyPaint, + DidFirstCompositorFrameSwap + }; + RenderWidgetHostViewQt(content::RenderWidgetHost* widget); ~RenderWidgetHostViewQt(); @@ -193,7 +199,8 @@ public: #ifndef QT_NO_ACCESSIBILITY virtual void accessibilityActiveChanged(bool active) Q_DECL_OVERRIDE; #endif // QT_NO_ACCESSIBILITY - void didFirstVisuallyNonEmptyLayout(); + LoadVisuallyCommittedState getLoadVisuallyCommittedState() const { return m_loadVisuallyCommittedState; } + void setLoadVisuallyCommittedState(LoadVisuallyCommittedState state) { m_loadVisuallyCommittedState = state; } gfx::SizeF lastContentsSize() const { return m_lastContentsSize; } @@ -218,7 +225,7 @@ private: QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; cc::ReturnedResourceArray m_resourcesToRelease; bool m_needsDelegatedFrameAck; - bool m_didFirstVisuallyNonEmptyLayout; + LoadVisuallyCommittedState m_loadVisuallyCommittedState; uint32_t m_pendingOutputSurfaceId; QMetaObject::Connection m_adapterClientDestroyedConnection; diff --git a/src/core/renderer/render_view_observer_qt.cpp b/src/core/renderer/render_view_observer_qt.cpp index 393b4752c..97485afad 100644 --- a/src/core/renderer/render_view_observer_qt.cpp +++ b/src/core/renderer/render_view_observer_qt.cpp @@ -83,11 +83,6 @@ void RenderViewObserverQt::onSetBackgroundColor(quint32 color) render_view()->GetWebFrameWidget()->setBaseBackgroundColor(color); } -void RenderViewObserverQt::OnFirstVisuallyNonEmptyLayout() -{ - Send(new RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout(routing_id())); -} - bool RenderViewObserverQt::OnMessageReceived(const IPC::Message& message) { bool handled = true; diff --git a/src/core/renderer/render_view_observer_qt.h b/src/core/renderer/render_view_observer_qt.h index b62c815af..538ebea8a 100644 --- a/src/core/renderer/render_view_observer_qt.h +++ b/src/core/renderer/render_view_observer_qt.h @@ -57,7 +57,6 @@ private: void onFetchDocumentInnerText(quint64 requestId); void onSetBackgroundColor(quint32 color); - void OnFirstVisuallyNonEmptyLayout() Q_DECL_OVERRIDE; void OnDestruct() Q_DECL_OVERRIDE { } virtual bool OnMessageReceived(const IPC::Message& message) Q_DECL_OVERRIDE; diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp index 887222285..d093efd0a 100644 --- a/src/core/url_request_custom_job.cpp +++ b/src/core/url_request_custom_job.cpp @@ -229,6 +229,9 @@ void URLRequestCustomJobShared::setReplyDevice(QIODevice *device) if (m_device && !m_device->isReadable()) m_device->open(QIODevice::ReadOnly); + qint64 size = m_device ? m_device->size() : -1; + if (size > 0) + m_job->set_expected_content_size(size); if (m_device && m_device->isReadable()) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobShared::notifyStarted, m_weakFactory.GetWeakPtr())); else diff --git a/src/core/url_request_qrc_job_qt.cpp b/src/core/url_request_qrc_job_qt.cpp index ffe9b6dc6..97460f0b7 100644 --- a/src/core/url_request_qrc_job_qt.cpp +++ b/src/core/url_request_qrc_job_qt.cpp @@ -120,6 +120,7 @@ void URLRequestQrcJobQt::startGetHead() // Open file if (m_file.open(QIODevice::ReadOnly)) { m_remainingBytes = m_file.size(); + set_expected_content_size(m_remainingBytes); // Notify that the headers are complete NotifyHeadersComplete(); } else { diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index fadbd6d2e..cafaad93d 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -50,7 +50,7 @@ #include "browser_context_qt.h" #include "download_manager_delegate_qt.h" #include "media_capture_devices_dispatcher.h" -#include "pdfium_printing_wrapper_qt.h" +#include "pdfium_document_wrapper_qt.h" #include "print_view_manager_qt.h" #include "qwebenginecallback_p.h" #include "renderer_host/web_channel_ipc_transport_host.h" @@ -92,9 +92,6 @@ #include <QtGui/qaccessible.h> #include <QtGui/qdrag.h> #include <QtGui/qpixmap.h> -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) -#include <QtPrintSupport/qprinter.h> -#endif // QT_NO_PRINTER #include <QtWebChannel/QWebChannel> namespace QtWebEngineCore { @@ -188,21 +185,9 @@ static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint6 static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, int requestId, const std::vector<char>& result) { - if (requestId) { + if (requestId) adapterClient->didPrintPage(requestId, QByteArray(result.data(), result.size())); - } -} - -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) -static void callbackOnPrintingOnPrinterFinished(WebContentsAdapterClient *adapterClient, int requestId, QPrinter *printer, const std::vector<char> &result) -{ - if (requestId) { - PdfiumPrintingWrapperQt printWrapper(result.data(), result.size()); - bool printerResult = printWrapper.printOnPrinter(*printer); - adapterClient->didPrintPageOnPrinter(requestId, printerResult); - } } -#endif // QT_NO_PRINTER static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient, content::BrowserContext *browserContext) { @@ -978,14 +963,14 @@ void WebContentsAdapter::printToPDF(const QPageLayout &pageLayout, const QString #endif // if defined(ENABLE_BASIC_PRINTING) } -quint64 WebContentsAdapter::printToPDFCallbackResult(const QPageLayout &pageLayout) +quint64 WebContentsAdapter::printToPDFCallbackResult(const QPageLayout &pageLayout, const bool colorMode) { #if defined(ENABLE_BASIC_PRINTING) Q_D(WebContentsAdapter); PrintViewManagerQt::PrintToPDFCallback callback = base::Bind(&callbackOnPrintingFinished , d->adapterClient , d->nextRequestId); - PrintViewManagerQt::FromWebContents(webContents())->PrintToPDFWithCallback(pageLayout, true + PrintViewManagerQt::FromWebContents(webContents())->PrintToPDFWithCallback(pageLayout, colorMode , callback); return d->nextRequestId++; #else @@ -993,23 +978,6 @@ quint64 WebContentsAdapter::printToPDFCallbackResult(const QPageLayout &pageLayo #endif // if defined(ENABLE_BASIC_PRINTING) } -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) -quint64 WebContentsAdapter::printOnPrinterCallbackResult(QPrinter *printer) -{ -#if defined(ENABLE_BASIC_PRINTING) - Q_D(WebContentsAdapter); - PrintViewManagerQt::PrintToPDFCallback callback - = base::Bind(&callbackOnPrintingOnPrinterFinished, d->adapterClient - , d->nextRequestId, printer); - PrintViewManagerQt::FromWebContents(webContents())->PrintToPDFWithCallback( - printer->pageLayout(), printer->colorMode() == QPrinter::Color, callback); - return d->nextRequestId++; -#else - return 0; -#endif // if defined(ENABLE_BASIC_PRINTING) -} -#endif // QT_NO_PRINTER - QPointF WebContentsAdapter::lastScrollOffset() const { Q_D(const WebContentsAdapter); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 7a109770e..3befe6d27 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -58,9 +58,6 @@ class QAccessibleInterface; class QDragEnterEvent; class QDragMoveEvent; class QPageLayout; -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) -class QPrinter; -#endif // QT_NO_PRINTER class QString; class QWebChannel; QT_END_NAMESPACE @@ -175,11 +172,7 @@ public: void leaveDrag(); void initUpdateDragCursorMessagePollingTimer(); void printToPDF(const QPageLayout&, const QString&); - quint64 printToPDFCallbackResult(const QPageLayout &); - -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) - quint64 printOnPrinterCallbackResult(QPrinter *printer); -#endif + quint64 printToPDFCallbackResult(const QPageLayout &, const bool colorMode = true); // meant to be used within WebEngineCore only content::WebContents *webContents() const; diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 85a379409..4e15df753 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -347,9 +347,6 @@ public: virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0; virtual void didFindText(quint64 requestId, int matchCount) = 0; virtual void didPrintPage(quint64 requestId, const QByteArray &result) = 0; -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) - virtual void didPrintPageOnPrinter(quint64 requestId, bool result) = 0; -#endif virtual void passOnFocus(bool reverse) = 0; // returns the last QObject (QWidget/QQuickItem) based object in the accessibility // hierarchy before going into the BrowserAccessibility tree diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 36acfe62e..87badc189 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -51,6 +51,7 @@ #include "file_picker_controller.h" #include "media_capture_devices_dispatcher.h" #include "network_delegate_qt.h" +#include "render_widget_host_view_qt.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" #include "web_contents_adapter_p.h" @@ -387,6 +388,21 @@ void WebContentsDelegateQt::WasShown() web_cache::WebCacheManager::GetInstance()->ObserveActivity(web_contents()->GetRenderProcessHost()->GetID()); } +void WebContentsDelegateQt::DidFirstVisuallyNonEmptyPaint() +{ + RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt*>(web_contents()->GetRenderWidgetHostView()); + if (!rwhv) + return; + + RenderWidgetHostViewQt::LoadVisuallyCommittedState loadVisuallyCommittedState = rwhv->getLoadVisuallyCommittedState(); + if (loadVisuallyCommittedState == RenderWidgetHostViewQt::NotCommitted) { + rwhv->setLoadVisuallyCommittedState(RenderWidgetHostViewQt::DidFirstVisuallyNonEmptyPaint); + } else if (loadVisuallyCommittedState == RenderWidgetHostViewQt::DidFirstCompositorFrameSwap) { + m_viewClient->loadVisuallyCommitted(); + rwhv->setLoadVisuallyCommittedState(RenderWidgetHostViewQt::NotCommitted); + } +} + void WebContentsDelegateQt::RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) { Q_UNUSED(user_gesture); @@ -422,7 +438,7 @@ void WebContentsDelegateQt::requestGeolocationPermission(const QUrl &requestingO m_viewClient->runGeolocationPermissionRequest(requestingOrigin); } -extern int pageTransitionToNavigationType(ui::PageTransition transition); +extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame) { diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index dad1e50f1..683b14ddf 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -135,6 +135,7 @@ public: virtual void DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) Q_DECL_OVERRIDE; virtual void DidNavigateAnyFrame(content::RenderFrameHost *render_frame_host, const content::LoadCommittedDetails &details, const content::FrameNavigateParams ¶ms) Q_DECL_OVERRIDE; virtual void WasShown() Q_DECL_OVERRIDE; + virtual void DidFirstVisuallyNonEmptyPaint() Q_DECL_OVERRIDE; void overrideWebPreferences(content::WebContents *, content::WebPreferences*); void allowCertificateError(const QSharedPointer<CertificateErrorController> &) ; diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 491835e45..152859bee 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -240,17 +240,15 @@ QObject *WebEngineContext::globalQObject() #define CHROMIUM_VERSION // This is solely to keep Qt Creator happy. #endif +const static char kChromiumFlagsEnv[] = "QTWEBENGINE_CHROMIUM_FLAGS"; +const static char kDisableSandboxEnv[] = "QTWEBENGINE_DISABLE_SANDBOX"; + WebEngineContext::WebEngineContext() : m_mainDelegate(new ContentMainDelegateQt) , m_contentRunner(content::ContentMainRunner::Create()) , m_browserRunner(content::BrowserMainRunner::Create()) , m_globalQObject(new QObject()) { - QStringList appArgs = QCoreApplication::arguments(); - bool useEmbeddedSwitches = appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); -#if defined(QTWEBENGINE_EMBEDDED_SWITCHES) - useEmbeddedSwitches = !appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); -#endif #ifdef Q_OS_LINUX // Call qputenv before BrowserMainRunnerImpl::Initialize is called. @@ -261,32 +259,35 @@ WebEngineContext::WebEngineContext() // Allow us to inject javascript like any webview toolkit. content::RenderFrameHost::AllowInjectingJavaScriptForAndroidWebView(); -#if defined(Q_OS_WIN) - // We must initialize the command line with the UTF-16 arguments vector we got from - // QCoreApplication. CommandLine::Init ignores its arguments on Windows and calls - // GetCommandLineW() instead. base::CommandLine::CreateEmpty(); base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); + QStringList appArgs = QCoreApplication::arguments(); + if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { + appArgs = appArgs.mid(0, 1); // Take application name and drop the rest + appArgs.append(QString::fromLocal8Bit(qgetenv(kChromiumFlagsEnv)).split(' ')); + } + + bool useEmbeddedSwitches = false; +#if defined(QTWEBENGINE_EMBEDDED_SWITCHES) + useEmbeddedSwitches = !appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); +#else + useEmbeddedSwitches = appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); +#endif base::CommandLine::StringVector argv; argv.resize(appArgs.size()); - std::transform(appArgs.constBegin(), appArgs.constEnd(), argv.begin(), &toString16); - parsedCommandLine->InitFromArgv(argv); +#if defined(Q_OS_WIN) + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = toString16(appArgs[i]); #else - QVector<QByteArray> args; - Q_FOREACH (const QString& arg, appArgs) - args << arg.toUtf8(); - - QVector<const char*> argv(args.size()); - for (int i = 0; i < args.size(); ++i) - argv[i] = args[i].constData(); - base::CommandLine::Init(argv.size(), argv.constData()); - base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = appArgs[i].toStdString(); #endif + parsedCommandLine->InitFromArgv(argv); parsedCommandLine->AppendSwitchPath(switches::kBrowserSubprocessPath, WebEngineLibraryInfo::getPath(content::CHILD_PROCESS_EXE)); // Enable sandboxing on OS X and Linux (Desktop / Embedded) by default. - bool disable_sandbox = qEnvironmentVariableIsSet("QTWEBENGINE_DISABLE_SANDBOX"); + bool disable_sandbox = qEnvironmentVariableIsSet(kDisableSandboxEnv); if (!disable_sandbox) { #if defined(Q_OS_WIN) parsedCommandLine->AppendSwitch(switches::kNoSandbox); @@ -328,7 +329,14 @@ WebEngineContext::WebEngineContext() #ifndef QT_NO_OPENGL if (!usingANGLE() && !usingSoftwareDynamicGL() && !usingQtQuick2DRenderer()) { if (qt_gl_global_share_context() && qt_gl_global_share_context()->isValid()) { - if (!strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), "QEGLNativeContext")) { + // If the native handle is QEGLNativeContext try to use GL ES/2, if there is no native handle + // assume we are using wayland and try GL ES/2, and finally Ozone demands GL ES/2 too. + if (qt_gl_global_share_context()->nativeHandle().isNull() +#ifdef USE_OZONE + || true +#endif + || !strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), "QEGLNativeContext")) + { if (qt_gl_global_share_context()->isOpenGLES()) { glType = gl::kGLImplementationEGLName; } else { diff --git a/src/webengine/api/qquickwebenginefaviconprovider.cpp b/src/webengine/api/qquickwebenginefaviconprovider.cpp index fe8436d6c..b5ad6960a 100644 --- a/src/webengine/api/qquickwebenginefaviconprovider.cpp +++ b/src/webengine/api/qquickwebenginefaviconprovider.cpp @@ -152,7 +152,7 @@ QQuickWebEngineView *QQuickWebEngineFaviconProvider::viewForIconUrl(const QUrl & // latest WebEngineView which was raised an iconChanged signal. if (m_latestView) { QList<QUrl> *iconUrls = m_iconUrlMap[m_latestView]; - if (iconUrls->contains(iconUrl)) + if (iconUrls && iconUrls->contains(iconUrl)) return m_latestView; } diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 6ca9954cf..f0811014b 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -1066,8 +1066,8 @@ void QQuickWebEngineView::setTestSupport(QQuickWebEngineTestSupport *testSupport { Q_D(QQuickWebEngineView); d->m_testSupport = testSupport; + Q_EMIT testSupportChanged(); } - #endif bool QQuickWebEngineView::activeFocusOnPress() const @@ -1302,16 +1302,23 @@ bool QQuickWebEngineView::recentlyAudible() const void QQuickWebEngineView::printToPdf(const QString& filePath, PrintedPageSizeId pageSizeId, PrintedPageOrientation orientation) { +#if defined(ENABLE_PDF) Q_D(const QQuickWebEngineView); QPageSize layoutSize(static_cast<QPageSize::PageSizeId>(pageSizeId)); QPageLayout::Orientation layoutOrientation = static_cast<QPageLayout::Orientation>(orientation); QPageLayout pageLayout(layoutSize, layoutOrientation, QMarginsF(0.0, 0.0, 0.0, 0.0)); d->adapter->printToPDF(pageLayout, filePath); +#else + Q_UNUSED(filePath); + Q_UNUSED(pageSizeId); + Q_UNUSED(orientation); +#endif } void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId pageSizeId, PrintedPageOrientation orientation) { +#if defined (ENABLE_PDF) Q_D(QQuickWebEngineView); QPageSize layoutSize(static_cast<QPageSize::PageSizeId>(pageSizeId)); QPageLayout::Orientation layoutOrientation = static_cast<QPageLayout::Orientation>(orientation); @@ -1322,6 +1329,16 @@ void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout); d->m_callbacks.insert(requestId, callback); +#else + Q_UNUSED(pageSizeId); + Q_UNUSED(orientation); + + // Call back with null result. + QJSValueList args; + args.append(QJSValue(QByteArray().data())); + QJSValue callbackCopy = callback; + callbackCopy.call(args); +#endif } void QQuickWebEngineView::replaceMisspelledWord(const QString &replacement) diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 16c4799b5..4f9e483bc 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -125,7 +125,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(uint webChannelWorld READ webChannelWorld WRITE setWebChannelWorld NOTIFY webChannelWorldChanged REVISION 3) #ifdef ENABLE_QML_TESTSUPPORT_API - Q_PROPERTY(QQuickWebEngineTestSupport *testSupport READ testSupport WRITE setTestSupport FINAL) + Q_PROPERTY(QQuickWebEngineTestSupport *testSupport READ testSupport WRITE setTestSupport NOTIFY testSupportChanged FINAL) #endif Q_FLAGS(FindFlags); @@ -513,6 +513,10 @@ Q_SIGNALS: Q_REVISION(4) void fileDialogRequested(QQuickWebEngineFileDialogRequest *request); Q_REVISION(4) void formValidationMessageRequested(QQuickWebEngineFormValidationMessageRequest *request); +#ifdef ENABLE_QML_TESTSUPPORT_API + void testSupportChanged(); +#endif + protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void itemChange(ItemChange, const ItemChangeData &) Q_DECL_OVERRIDE; diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index b111e92cd..d692140ef 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -123,9 +123,6 @@ public: virtual void didFetchDocumentInnerText(quint64, const QString&) Q_DECL_OVERRIDE { } virtual void didFindText(quint64, int) Q_DECL_OVERRIDE; virtual void didPrintPage(quint64 requestId, const QByteArray &result) Q_DECL_OVERRIDE; -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) - virtual void didPrintPageOnPrinter(quint64, bool) Q_DECL_OVERRIDE { } -#endif virtual void passOnFocus(bool reverse) Q_DECL_OVERRIDE; virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; virtual void authenticationRequired(QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) Q_DECL_OVERRIDE; diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc index c5ebe0f06..615e3eed0 100644 --- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc @@ -62,14 +62,14 @@ On all platforms, the following tools are required: \list - \li \l Python 2.7 or later + \li \l Python 2.7.5 or later \li Bison, Flex \li GPerf \endlist \section2 Windows - On Windows, Visual Studio 2013 or Visual Studio 2015 is required. + On Windows, Visual Studio 2015 and Windows 10 SDK are required. \section2 Linux diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 99b9c4e6f..2bbf82810 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -65,6 +65,10 @@ contains(WEBENGINE_CONFIG, use_spellchecker) { DEFINES += ENABLE_SPELLCHECK } +contains(WEBENGINE_CONFIG, enable_pdf) { + DEFINES += ENABLE_PDF +} + !build_pass { chromium_attributions.commands = \ cd $$shell_quote($$shell_path($$PWD/../3rdparty)) && \ diff --git a/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp b/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp index e47f135e8..a39c0e483 100644 --- a/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp +++ b/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp @@ -48,18 +48,26 @@ namespace QtWebEngineCore } QT_BEGIN_NAMESPACE + +#ifndef QT_NO_OPENGL +Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); +#endif + static void initialize() { - //On window/ANGLE, calling QtWebEngine::initialize from DllMain will result in a crash. - //To ensure it doesn't, we check that when loading the library - //QCoreApplication is not yet instantiated, ensuring the call will be deferred -#if defined(Q_OS_WIN) - if (QCoreApplication::instance() - && QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { +#ifndef QT_NO_OPENGL + if (QCoreApplication::instance()) { + //On window/ANGLE, calling QtWebEngine::initialize from DllMain will result in a crash. + if (!qt_gl_global_share_context()) { + qWarning("Qt WebEngine seems to be initialized from a plugin. Please " + "set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute " + "before constructing QGuiApplication."); + } return; } -#endif + //QCoreApplication is not yet instantiated, ensuring the call will be deferred qAddPreRoutine(QtWebEngineCore::initialize); +#endif // QT_NO_OPENGL } Q_CONSTRUCTOR_FUNCTION(initialize) diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index ca160c362..16e9438c9 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -47,6 +47,7 @@ #include "favicon_manager.h" #include "file_picker_controller.h" #include "javascript_dialog_controller.h" +#include "pdfium_document_wrapper_qt.h" #include "qwebenginefullscreenrequest.h" #include "qwebenginehistory.h" #include "qwebenginehistory_p.h" @@ -79,6 +80,9 @@ #include <QMenu> #include <QMessageBox> #include <QMimeData> +#ifndef QT_NO_PRINTER +#include <QPrinter> +#endif #include <QStandardPaths> #include <QStyle> #include <QTimer> @@ -92,6 +96,87 @@ using namespace QtWebEngineCore; static const int MaxTooltipLength = 1024; +#ifndef QT_NO_PRINTER +#if defined(ENABLE_PDF) +static bool printPdfDataOnPrinter(const QByteArray& data, QPrinter& printer) +{ + QRect printerPageRect = printer.pageRect(); + PdfiumDocumentWrapperQt pdfiumWrapper(data.constData(), data.size(), printerPageRect.size()); + + int toPage = printer.toPage(); + int fromPage = printer.fromPage(); + bool ascendingOrder = true; + + if (fromPage == 0 && toPage == 0) { + fromPage = 1; + toPage = pdfiumWrapper.pageCount(); + } + fromPage = qMax(1, fromPage); + toPage = qMin(pdfiumWrapper.pageCount(), toPage); + + if (printer.pageOrder() == QPrinter::LastPageFirst) { + qSwap(fromPage, toPage); + ascendingOrder = false; + } + + int pageCopies = 1; + int documentCopies = 1; + + if (!printer.supportsMultipleCopies()) + documentCopies = printer.copyCount(); + + if (printer.collateCopies()) { + pageCopies = documentCopies; + documentCopies = 1; + } + + QPainter painter; + if (!painter.begin(&printer)) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) + qWarning("Failure to print on printer %ls: Could not open printer for painting.", qUtf16Printable(printer.printerName())); +#else + qWarning("Failure to print on printer %s: Could not open printer for painting.", qPrintable(printer.printerName())); +#endif + return false; + } + + for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { + int currentPageIndex = fromPage; + while (true) { + for (int printedPages = 0; printedPages < pageCopies; printedPages++) { + if (printer.printerState() == QPrinter::Aborted + || printer.printerState() == QPrinter::Error) + return false; + + QImage currentImage = pdfiumWrapper.pageAsQImage(currentPageIndex - 1); + if (currentImage.isNull()) + return false; + + painter.drawImage(printerPageRect, currentImage, currentImage.rect()); + if (printedPages < pageCopies - 1) + printer.newPage(); + } + + if (currentPageIndex == toPage) + break; + + if (ascendingOrder) + currentPageIndex++; + else + currentPageIndex--; + + printer.newPage(); + } + if (printedDocuments < documentCopies - 1) + printer.newPage(); + } + painter.end(); + + return true; +} +#endif // defined(ENABLE_PDF) +#endif // QT_NO_PRINTER + static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::WindowOpenDisposition disposition) { switch (disposition) { @@ -142,6 +227,9 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) , fullscreenMode(false) , webChannel(nullptr) , webChannelWorldId(QWebEngineScript::MainWorld) +#ifndef QT_NO_PRINTER + , currentPrinter(nullptr) +#endif { memset(actions, 0, sizeof(actions)); } @@ -154,7 +242,16 @@ QWebEnginePagePrivate::~QWebEnginePagePrivate() RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) { - return new RenderWidgetHostViewQtDelegateWidget(client); + // Set the QWebEngineView as the parent for a popup delegate, so that the new popup window + // responds properly to clicks in case the QWebEngineView is inside a modal QDialog. Setting the + // parent essentially notifies the OS that the popup window is part of the modal session, and + // should allow interaction. + // The new delegate will not be deleted by the parent view though, because we unset the parent + // when the parent is destroyed. The delegate will be destroyed by Chromium when the popup is + // dismissed. + // If the delegate is not for a popup, but for a newly created QWebEngineView, the parent is 0 + // just like before. + return new RenderWidgetHostViewQtDelegateWidget(client, this->view); } void QWebEnginePagePrivate::titleChanged(const QString &title) @@ -380,15 +477,27 @@ void QWebEnginePagePrivate::didFindText(quint64 requestId, int matchCount) void QWebEnginePagePrivate::didPrintPage(quint64 requestId, const QByteArray &result) { - m_callbacks.invoke(requestId, result); -} - +#if defined(ENABLE_PDF) #ifndef QT_NO_PRINTER -void QWebEnginePagePrivate::didPrintPageOnPrinter(quint64 requestId, bool result) -{ + // If no currentPrinter is set that means that were printing to PDF only. + if (!currentPrinter) { + m_callbacks.invoke(requestId, result); + return; + } + + bool printerResult = printPdfDataOnPrinter(result, *currentPrinter); + + m_callbacks.invoke(requestId, printerResult); + currentPrinter = nullptr; +#else // If print support is disabled, only PDF printing is available. m_callbacks.invoke(requestId, result); +#endif // ifndef QT_NO_PRINTER +#else // defined(ENABLE_PDF) + // we should never enter this branch, but just for safe-keeping... + Q_UNUSED(result); + m_callbacks.invoke(requestId, QByteArray()); +#endif // defined(ENABLE_PDF) } -#endif void QWebEnginePagePrivate::passOnFocus(bool reverse) { @@ -1835,8 +1944,23 @@ QSizeF QWebEnginePage::contentsSize() const */ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &pageLayout) { +#if defined(ENABLE_PDF) Q_D(const QWebEnginePage); +#ifndef QT_NO_PRINTER + if (d->currentPrinter) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) + qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); +#else + qWarning("Cannot print to PDF while at the same time printing on printer %s", qPrintable(d->currentPrinter->printerName())); +#endif + return; + } +#endif d->adapter->printToPDF(pageLayout, filePath); +#else + Q_UNUSED(filePath); + Q_UNUSED(pageLayout); +#endif // if defined(ENABLE_PDF) } @@ -1854,8 +1978,24 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &page void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &pageLayout) { Q_D(QWebEnginePage); +#if defined(ENABLE_PDF) +#ifndef QT_NO_PRINTER + if (d->currentPrinter) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) + qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); +#else + qWarning("Cannot print to PDF while at the same time printing on printer %s", qPrintable(d->currentPrinter->printerName())); +#endif + d->m_callbacks.invokeEmpty(resultCallback); + return; + } +#endif // ifndef QT_NO_PRINTER quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout); d->m_callbacks.registerCallback(requestId, resultCallback); +#else // if defined(ENABLE_PDF) + Q_UNUSED(pageLayout); + d->m_callbacks.invokeEmpty(resultCallback); +#endif // if defined(ENABLE_PDF) } #ifndef QT_NO_PRINTER @@ -1875,8 +2015,23 @@ void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &res void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback) { Q_D(QWebEnginePage); - quint64 requestId = d->adapter->printOnPrinterCallbackResult(printer); +#if defined(ENABLE_PDF) + if (d->currentPrinter) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) + qWarning("Cannot print page on printer %ls: Already printing on %ls.", qUtf16Printable(printer->printerName()), qUtf16Printable(d->currentPrinter->printerName())); +#else + qWarning("Cannot print page on printer %s: Already printing on %s.", qPrintable(printer->printerName()), qPrintable(d->currentPrinter->printerName())); +#endif + d->m_callbacks.invokeDirectly(resultCallback, false); + return; + } + d->currentPrinter = printer; + quint64 requestId = d->adapter->printToPDFCallbackResult(printer->pageLayout(), printer->colorMode() == QPrinter::Color); d->m_callbacks.registerCallback(requestId, resultCallback); +#else // if defined(ENABLE_PDF) + Q_UNUSED(printer); + d->m_callbacks.invokeDirectly(resultCallback, false); +#endif // if defined(ENABLE_PDF) } #endif // QT_NO_PRINTER diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 8d78429d8..0ad077a0e 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -119,9 +119,6 @@ public: virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) Q_DECL_OVERRIDE; virtual void didFindText(quint64 requestId, int matchCount) Q_DECL_OVERRIDE; virtual void didPrintPage(quint64 requestId, const QByteArray &result) Q_DECL_OVERRIDE; -#ifndef QT_NO_PRINTER - virtual void didPrintPageOnPrinter(quint64 requestId, bool result) Q_DECL_OVERRIDE; -#endif virtual void passOnFocus(bool reverse) Q_DECL_OVERRIDE; virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; virtual void authenticationRequired(QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) Q_DECL_OVERRIDE; @@ -181,6 +178,9 @@ public: mutable QtWebEngineCore::CallbackDirectory m_callbacks; mutable QAction *actions[QWebEnginePage::WebActionCount]; +#ifndef QT_NO_PRINTER + QPrinter *currentPrinter; +#endif // QT_NO_PRINTER }; QT_END_NAMESPACE 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 eb3a3931a..27268d26b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -138,6 +138,21 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_AlwaysShowToolTips); + + if (parent) { + // Unset the popup parent if the parent is being destroyed, thus making sure a double + // delete does not happen. + // Also in case the delegate is destroyed before its parent (when a popup is simply + // dismissed), this connection will automatically be removed by ~QObject(), preventing + // a use-after-free. + connect(parent, &QObject::destroyed, + this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); + } +} + +void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() +{ + setParent(Q_NULLPTR); } void RenderWidgetHostViewQtDelegateWidget::initAsChild(WebContentsAdapterClient* container) @@ -164,7 +179,11 @@ void RenderWidgetHostViewQtDelegateWidget::initAsPopup(const QRect& screenRect) // to be destroyed. setAttribute(Qt::WA_ShowWithoutActivating); setFocusPolicy(Qt::NoFocus); - setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); + + // macOS doesn't like Qt::ToolTip when QWebEngineView is inside a modal dialog, specifically by + // not forwarding click events to the popup. So we use Qt::Tool which behaves the same way, but + // works on macOS too. + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); setGeometry(screenRect); show(); @@ -183,6 +202,13 @@ QRectF RenderWidgetHostViewQtDelegateWidget::contentsRect() const void RenderWidgetHostViewQtDelegateWidget::setKeyboardFocus() { + // If the corresponding window is inactive (for example, because of a popup), + // the active focus cannot be set. Sync up with the Window System to try to + // reactivate the window in time if the other window (possibly popup) which took + // the focus is already closed. + if (window() && !window()->isActive()) + QGuiApplication::sync(); + m_rootItem->forceActiveFocus(); } diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index 77907ec5a..68e6a176b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -87,6 +87,7 @@ protected: private slots: void onWindowPosChanged(); + void removeParentBeforeParentDelete(); private: RenderWidgetHostViewQtDelegateClient *m_client; diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 64e475422..b60de6e1e 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -52,4 +52,11 @@ contains(WEBENGINE_CONFIG, use_spellchecker) { DEFINES += ENABLE_SPELLCHECK } +contains(WEBENGINE_CONFIG, enable_pdf) { + DEFINES += ENABLE_PDF +} + +qtHaveModule(printsupport) { + QT += printsupport +} load(qt_module) diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp index 180953ed4..89ebbac62 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -192,21 +192,21 @@ void tst_QWebEngineUrlRequestInterceptor::requestedUrl() page.profile()->setRequestInterceptor(&interceptor); page.setUrl(QUrl("qrc:///resources/__placeholder__")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(spy.count(), 1); QCOMPARE(interceptor.observedUrls.at(0), QUrl("qrc:///resources/content.html")); QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__")); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); page.setUrl(QUrl("qrc:/non-existent.html")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(spy.count(), 2); QCOMPARE(interceptor.observedUrls.at(2), QUrl("qrc:/non-existent.html")); QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__")); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); page.setUrl(QUrl("http://abcdef.abcdef")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(spy.count(), 3); QCOMPARE(interceptor.observedUrls.at(3), QUrl("http://abcdef.abcdef/")); QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__")); @@ -222,23 +222,23 @@ void tst_QWebEngineUrlRequestInterceptor::setUrlSameUrl() QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); page.setUrl(QUrl("qrc:///resources/__placeholder__")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); QCOMPARE(spy.count(), 1); page.setUrl(QUrl("qrc:///resources/__placeholder__")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); QCOMPARE(spy.count(), 2); // Now a case without redirect. page.setUrl(QUrl("qrc:///resources/content.html")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); QCOMPARE(spy.count(), 3); page.setUrl(QUrl("qrc:///resources/__placeholder__")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(page.url(), QUrl("qrc:///resources/content.html")); QCOMPARE(spy.count(), 4); } @@ -252,7 +252,7 @@ void tst_QWebEngineUrlRequestInterceptor::firstPartyUrl() QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); page.setUrl(QUrl("qrc:///resources/firstparty.html")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(interceptor.observedUrls.at(0), QUrl("qrc:///resources/firstparty.html")); QCOMPARE(interceptor.observedUrls.at(1), QUrl("qrc:///resources/content.html")); QCOMPARE(interceptor.firstPartyUrls.at(0), QUrl("qrc:///resources/firstparty.html")); diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST index d281020df..2673c7eb2 100644 --- a/tests/auto/quick/qmltests/BLACKLIST +++ b/tests/auto/quick/qmltests/BLACKLIST @@ -1,9 +1,3 @@ -[DesktopWebEngineViewLinkHovered::test_linkHovered] -* - -[DesktopWebEngineViewLinkHovered::test_linkHoveredDoesntEmitRepeated] -* - [WebViewGeopermission::test_deniedGeolocationByUser] osx diff --git a/tests/auto/quick/qmltests/data/tst_linkHovered.qml b/tests/auto/quick/qmltests/data/tst_linkHovered.qml index b049f07a3..362130bab 100644 --- a/tests/auto/quick/qmltests/data/tst_linkHovered.qml +++ b/tests/auto/quick/qmltests/data/tst_linkHovered.qml @@ -29,6 +29,7 @@ import QtQuick 2.0 import QtTest 1.0 import QtWebEngine 1.2 +import QtWebEngine.testsupport 1.0 TestWebEngineView { id: webEngineView @@ -38,8 +39,16 @@ TestWebEngineView { property string lastUrl + testSupport: WebEngineTestSupport { } + + SignalSpy { + id: loadVisuallyCommittedSpy + target: webEngineView.testSupport + signalName: "loadVisuallyCommitted" + } + SignalSpy { - id: spy + id: linkHoveredSpy target: webEngineView signalName: "linkHovered" } @@ -61,53 +70,60 @@ TestWebEngineView { } function init() { - webEngineView.lastUrl = "" - spy.clear() + webEngineView.lastUrl = ""; + loadVisuallyCommittedSpy.clear(); + linkHoveredSpy.clear(); } function test_linkHovered() { - compare(spy.count, 0) + compare(linkHoveredSpy.count, 0); mouseMove(webEngineView, 100, 300) webEngineView.url = Qt.resolvedUrl("test2.html") verify(webEngineView.waitForLoadSucceeded()) // We get a linkHovered signal with empty hoveredUrl after page load - spy.wait() - compare(spy.count, 1) + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 1); compare(webEngineView.lastUrl, "") + // Wait for the page to be rendered before trying to test based on input events + loadVisuallyCommittedSpy.wait(); + mouseMove(webEngineView, 100, 100) - spy.wait() - compare(spy.count, 2) + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 2); compare(webEngineView.lastUrl, Qt.resolvedUrl("test1.html")) mouseMove(webEngineView, 100, 300) - spy.wait() - compare(spy.count, 3) + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 3); compare(webEngineView.lastUrl, "") } function test_linkHoveredDoesntEmitRepeated() { - compare(spy.count, 0) + compare(linkHoveredSpy.count, 0); webEngineView.url = Qt.resolvedUrl("test2.html") verify(webEngineView.waitForLoadSucceeded()) // We get a linkHovered signal with empty hoveredUrl after page load - spy.wait() - compare(spy.count, 1) + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 1); compare(webEngineView.lastUrl, "") + // Wait for the page to be rendered before trying to test based on input events + loadVisuallyCommittedSpy.wait(); + for (var i = 0; i < 100; i += 10) mouseMove(webEngineView, 100, 100 + i) - spy.wait() - compare(spy.count, 2) + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 2); compare(webEngineView.lastUrl, Qt.resolvedUrl("test1.html")) for (var i = 0; i < 100; i += 10) mouseMove(webEngineView, 100, 300 + i) - spy.wait() - compare(spy.count, 3) + linkHoveredSpy.wait(); + compare(linkHoveredSpy.count, 3); compare(webEngineView.lastUrl, "") } } diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 2d68fd744..2a43c9c1c 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -151,7 +151,8 @@ void tst_QQuickWebEngineView::stopEnabledAfterLoadStarted() LoadStartedCatcher catcher(webEngineView()); webEngineView()->setUrl(urlFromTestPath("html/basic_page.html")); - waitForSignal(&catcher, SIGNAL(finished())); + QSignalSpy spy(&catcher, &LoadStartedCatcher::finished); + QVERIFY(spy.wait()); QCOMPARE(webEngineView()->isLoading(), true); diff --git a/tests/auto/quick/shared/util.h b/tests/auto/quick/shared/util.h index 063caa766..674c2da34 100644 --- a/tests/auto/quick/shared/util.h +++ b/tests/auto/quick/shared/util.h @@ -91,45 +91,25 @@ private: QQuickWebEngineView *m_webEngineView; }; -/** - * Starts an event loop that runs until the given signal is received. - * Optionally the event loop - * can return earlier on a timeout. - * - * \return \p true if the requested signal was received - * \p false on timeout - */ -inline bool waitForSignal(QObject *obj, const char *signal, int timeout = 10000) -{ - QEventLoop loop; - QObject::connect(obj, signal, &loop, SLOT(quit())); - QTimer timer; - QSignalSpy timeoutSpy(&timer, SIGNAL(timeout())); - if (timeout > 0) { - QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - timer.setSingleShot(true); - timer.start(timeout); - } - loop.exec(); - return timeoutSpy.isEmpty(); -} - inline bool waitForLoadSucceeded(QQuickWebEngineView *webEngineView, int timeout = 10000) { LoadSpy loadSpy(webEngineView); - return waitForSignal(&loadSpy, SIGNAL(loadSucceeded()), timeout); + QSignalSpy spy(&loadSpy, &LoadSpy::loadSucceeded); + return spy.wait(timeout); } inline bool waitForLoadFailed(QQuickWebEngineView *webEngineView, int timeout = 10000) { LoadSpy loadSpy(webEngineView); - return waitForSignal(&loadSpy, SIGNAL(loadFailed()), timeout); + QSignalSpy spy(&loadSpy, &LoadSpy::loadFailed); + return spy.wait(timeout); } inline bool waitForViewportReady(QQuickWebEngineView *webEngineView, int timeout = 10000) { #ifdef ENABLE_QML_TESTSUPPORT_API - return waitForSignal(reinterpret_cast<QObject *>(webEngineView->testSupport()), SIGNAL(loadVisuallyCommitted()), timeout); + QSignalSpy spy(reinterpret_cast<QObject *>(webEngineView->testSupport()), SIGNAL(loadVisuallyCommitted())); + return spy.wait(timeout); #else Q_UNUSED(webEngineView) Q_UNUSED(timeout) diff --git a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp b/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp index 3ed4bcc71..85bfa80f3 100644 --- a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp +++ b/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp @@ -88,7 +88,8 @@ void tst_QWebEngineAccessibility::hierarchy() "<input type='text' value='some text'></input>" \ "</body></html>"); webView.show(); - ::waitForSignal(&webView, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView); QVERIFY(view); @@ -150,7 +151,8 @@ void tst_QWebEngineAccessibility::text() "<input type='text' value='Good day!' placeholder='day'></input>" \ "</body></html>"); webView.show(); - ::waitForSignal(&webView, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView); // Wait for accessibility to be fully initialized @@ -215,7 +217,8 @@ void tst_QWebEngineAccessibility::value() "<div class='progress' role='progressbar' aria-valuenow='77' aria-valuemin='22' aria-valuemax='99'></div>" \ "</body></html>"); webView.show(); - ::waitForSignal(&webView, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView); QTRY_COMPARE(view->child(0)->childCount(), 2); diff --git a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp index a329b7307..dffd995c9 100644 --- a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp +++ b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp @@ -370,22 +370,21 @@ void tst_QWebEngineHistory::saveAndRestore_crash_2() { QByteArray buffer; saveHistory(hist, &buffer); - QWebEnginePage* page2 = new QWebEnginePage(this); - QWebEngineHistory* hist2 = page2->history(); + QWebEnginePage page2(this); + QWebEngineHistory* hist2 = page2.history(); for (unsigned i = 0; i < 5; i++) { restoreHistory(hist2, &buffer); saveHistory(hist2, &buffer); } - delete page2; } void tst_QWebEngineHistory::saveAndRestore_crash_3() { QByteArray buffer; saveHistory(hist, &buffer); - QWebEnginePage* page2 = new QWebEnginePage(this); + QWebEnginePage page2(this); QWebEngineHistory* hist1 = hist; - QWebEngineHistory* hist2 = page2->history(); + QWebEngineHistory* hist2 = page2.history(); for (unsigned i = 0; i < 5; i++) { restoreHistory(hist1, &buffer); restoreHistory(hist2, &buffer); @@ -395,7 +394,6 @@ void tst_QWebEngineHistory::saveAndRestore_crash_3() saveHistory(hist2, &buffer); hist2->clear(); } - delete page2; } void tst_QWebEngineHistory::saveAndRestore_crash_4() @@ -406,18 +404,18 @@ void tst_QWebEngineHistory::saveAndRestore_crash_4() QByteArray buffer; saveHistory(hist, &buffer); - QWebEnginePage* page2 = new QWebEnginePage(this); + QScopedPointer<QWebEnginePage> page2(new QWebEnginePage(this)); // The initial crash was in PageCache. page2->settings()->setMaximumPagesInCache(3); // Load the history in a new page, waiting for the load to finish. QEventLoop waitForLoadFinished; - QObject::connect(page2, SIGNAL(loadFinished(bool)), &waitForLoadFinished, SLOT(quit()), Qt::QueuedConnection); + QObject::connect(page2.data(), SIGNAL(loadFinished(bool)), &waitForLoadFinished, SLOT(quit()), Qt::QueuedConnection); QDataStream load(&buffer, QIODevice::ReadOnly); load >> *page2->history(); waitForLoadFinished.exec(); - delete page2; + page2.reset(); // Give some time for the PageCache cleanup 0-timer to fire. QTest::qWait(50); #endif @@ -456,12 +454,11 @@ void tst_QWebEngineHistory::clear() QVERIFY(hist->count() == 1); // Leave current item. QVERIFY(!actionBack->isEnabled()); - QWebEnginePage* page2 = new QWebEnginePage(this); - QWebEngineHistory* hist2 = page2->history(); + QWebEnginePage page2(this); + QWebEngineHistory* hist2 = page2.history(); QVERIFY(hist2->count() == 0); hist2->clear(); QVERIFY(hist2->count() == 0); // Do not change anything. - delete page2; } void tst_QWebEngineHistory::historyItemFromDeletedPage() diff --git a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro index 70786e70f..df733c473 100644 --- a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro +++ b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro @@ -1,2 +1,4 @@ include(../tests.pri) QT *= core-private gui-private + +contains(WEBENGINE_CONFIG, enable_pdf): DEFINES+=QWEBENGINEPAGE_PDFPRINTINGENABLED diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index f16c42976..287af511f 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -333,25 +333,23 @@ protected: void tst_QWebEnginePage::acceptNavigationRequest() { - QWebEngineView *view = new QWebEngineView(); - QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); + QWebEngineView view; + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); - NavigationRequestOverride* newPage = new NavigationRequestOverride(view, false); - view->setPage(newPage); + NavigationRequestOverride* newPage = new NavigationRequestOverride(&view, false); + view.setPage(newPage); - view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>" + view.setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>" "<input type='text'><input type='submit'></form></body></html>"), QUrl()); QTRY_COMPARE(loadSpy.count(), 1); - evaluateJavaScriptSync(view->page(), "tstform.submit();"); + evaluateJavaScriptSync(view.page(), "tstform.submit();"); newPage->m_acceptNavigationRequest = true; - evaluateJavaScriptSync(view->page(), "tstform.submit();"); + evaluateJavaScriptSync(view.page(), "tstform.submit();"); QTRY_COMPARE(loadSpy.count(), 2); - QCOMPARE(toPlainTextSync(view->page()), QString("foo?")); - - delete view; + QCOMPARE(toPlainTextSync(view.page()), QString("foo?")); } class JSTestPage : public QWebEnginePage @@ -389,11 +387,10 @@ private: /* void tst_QWebEnginePage::infiniteLoopJS() { - JSTestPage* newPage = new JSTestPage(m_view); - m_view->setPage(newPage); + JSTestPage newPage(m_view); + m_view->setPage(&newPage); m_view->setHtml(QString("<html><body>test</body></html>"), QUrl()); m_view->page()->evaluateJavaScript("var run = true; var a = 1; while (run) { a++; }"); - delete newPage; } */ @@ -409,9 +406,9 @@ void tst_QWebEnginePage::geolocationRequestJS() { QFETCH(bool, allowed); QFETCH(int, errorCode); - QWebEngineView *view = new QWebEngineView; - JSTestPage *newPage = new JSTestPage(view); - newPage->setView(view); + QWebEngineView view; + JSTestPage *newPage = new JSTestPage(&view); + newPage->setView(&view); newPage->setGeolocationPermission(allowed); connect(newPage, SIGNAL(featurePermissionRequested(const QUrl&, QWebEnginePage::Feature)), @@ -420,10 +417,8 @@ void tst_QWebEnginePage::geolocationRequestJS() QSignalSpy spyLoadFinished(newPage, SIGNAL(loadFinished(bool))); newPage->setHtml(QString("<html><body>test</body></html>"), QUrl("qrc://secure/origin")); QTRY_COMPARE(spyLoadFinished.count(), 1); - if (evaluateJavaScriptSync(newPage, QLatin1String("!navigator.geolocation")).toBool()) { - delete view; + if (evaluateJavaScriptSync(newPage, QLatin1String("!navigator.geolocation")).toBool()) W_QSKIP("Geolocation is not supported.", SkipSingle); - } evaluateJavaScriptSync(newPage, "var errorCode = 0; var done = false; function error(err) { errorCode = err.code; done = true; } function success(pos) { done = true; } navigator.geolocation.getCurrentPosition(success, error)"); @@ -432,8 +427,6 @@ void tst_QWebEnginePage::geolocationRequestJS() if (result == 2) QEXPECT_FAIL("", "No location service available.", Continue); QCOMPARE(result, errorCode); - - delete view; } void tst_QWebEnginePage::loadFinished() @@ -490,7 +483,8 @@ void tst_QWebEnginePage::pasteImage() clipboard->setImage(origImage); QWebEnginePage *page = m_view->page(); page->load(QUrl("qrc:///resources/pasteimage.html")); - QVERIFY(waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); page->triggerAction(QWebEnginePage::Paste); QTRY_VERIFY(evaluateJavaScriptSync(page, "window.myImageDataURL ? window.myImageDataURL.length : 0").toInt() > 0); @@ -661,7 +655,8 @@ void tst_QWebEnginePage::userStyleSheet() m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64," + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64())); m_view->setHtml("<p>hello world</p>"); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(networkManager->requestedUrls.count() >= 1); QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); @@ -679,7 +674,8 @@ void tst_QWebEnginePage::userStyleSheetFromLocalFileUrl() QUrl styleSheetUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginepage/resources/user.css")); m_page->settings()->setUserStyleSheetUrl(styleSheetUrl); m_view->setHtml("<p>hello world</p>"); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(networkManager->requestedUrls.count() >= 1); QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); @@ -696,7 +692,8 @@ void tst_QWebEnginePage::userStyleSheetFromQrcUrl() m_page->settings()->setUserStyleSheetUrl(QUrl("qrc:///resources/user.css")); m_view->setHtml("<p>hello world</p>"); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(networkManager->requestedUrls.count() >= 1); QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); @@ -723,10 +720,12 @@ void tst_QWebEnginePage::modified() QSKIP("QWEBENGINEPAGE_ISMODIFIED"); #else m_page->setUrl(QUrl("data:text/html,<body>blub")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); m_page->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(!m_page->isModified()); @@ -750,7 +749,8 @@ void tst_QWebEnginePage::modified() QVERIFY(!m_page->history()->forwardItem().isValid()); m_page->history()->back(); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(!m_page->history()->canGoBack()); QVERIFY(m_page->history()->canGoForward()); @@ -772,7 +772,8 @@ void tst_QWebEnginePage::modified() m_page->setUrl(QUrl("data:text/html,<body>This is fourth page")); QCOMPARE(m_page->history()->count(), 2); m_page->setUrl(QUrl("data:text/html,<body>This is fifth page")); - QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebEngineFrame*,QWebEngineHistoryItem*)))); + QSignalSpy spy(m_page, &QWebEnginePage::saveFrameStateRequested); + QVERIFY(spy.wait()); #endif } @@ -1225,7 +1226,7 @@ void tst_QWebEnginePage::cursorMovements() #if !defined(QWEBENGINEPAGE_SELECTEDTEXT) QSKIP("QWEBENGINEPAGE_SELECTEDTEXT"); #else - CursorTrackedPage* page = new CursorTrackedPage; + QScopedPointer<CursorTrackedPage> page(new CursorTrackedPage); QString content("<html><body><p id=one>The quick brown fox</p><p id=two>jumps over the lazy dog</p><p>May the source<br/>be with you!</p></body></html>"); page->setHtml(content); @@ -1234,7 +1235,7 @@ void tst_QWebEnginePage::cursorMovements() "var node = document.getElementById(\"one\"); " \ "range.selectNode(node); " \ "getSelection().addRange(range);"; - evaluateJavaScriptSync(page, script); + evaluateJavaScriptSync(page.data(), script); QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); QRegExp regExp(" style=\".*\""); @@ -1415,20 +1416,18 @@ void tst_QWebEnginePage::cursorMovements() page->triggerAction(QWebEnginePage::MoveToNextWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 12); - - delete page; #endif } void tst_QWebEnginePage::textSelection() { - QWebEngineView *view = new QWebEngineView; - CursorTrackedPage *page = new CursorTrackedPage(view); + QWebEngineView view; + CursorTrackedPage *page = new CursorTrackedPage(&view); QString content("<html><body><p id=one>The quick brown fox</p>" \ "<p id=two>jumps over the lazy dog</p>" \ "<p>May the source<br/>be with you!</p></body></html>"); - page->setView(view); - QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); + page->setView(&view); + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); page->setHtml(content); QTRY_COMPARE(loadSpy.count(), 1); @@ -1522,8 +1521,6 @@ void tst_QWebEnginePage::textSelection() QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); #endif - - delete view; } void tst_QWebEnginePage::textEditing() @@ -1531,7 +1528,7 @@ void tst_QWebEnginePage::textEditing() #if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); #else - CursorTrackedPage* page = new CursorTrackedPage; + QScopedPointer<CursorTrackedPage> page(new CursorTrackedPage); QString content("<html><body><p id=one>The quick brown fox</p>" \ "<p id=two>jumps over the lazy dog</p>" \ "<p>May the source<br/>be with you!</p></body></html>"); @@ -1644,8 +1641,6 @@ void tst_QWebEnginePage::textEditing() // this is only true if there is an editable selection QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), true); - - delete page; #endif } @@ -1711,12 +1706,12 @@ void tst_QWebEnginePage::inputMethods() QFETCH(QString, viewType); QWebEnginePage* page = new QWebEnginePage; QObject* view = 0; - QObject* container = 0; + QScopedPointer<QObject> container(0); if (viewType == "QWebEngineView") { QWebEngineView* wv = new QWebEngineView; wv->setPage(page); view = wv; - container = view; + container.reset(view); } else if (viewType == "QGraphicsWebView") { QGraphicsWebView* wv = new QGraphicsWebView; wv->setPage(page); @@ -1728,7 +1723,7 @@ void tst_QWebEnginePage::inputMethods() scene->addItem(wv); wv->setGeometry(QRect(0, 0, 500, 500)); - container = gv; + container.reset(gv); } else QVERIFY2(false, "Unknown view type"); @@ -2396,8 +2391,6 @@ void tst_QWebEnginePage::inputMethods() QCOMPARE(inputValue2, QString("\n\nthird line")); // END - Newline test for textarea - - delete container; #endif } @@ -2736,22 +2729,19 @@ void tst_QWebEnginePage::screenshot() QDir::setCurrent(TESTS_SOURCE_DIR); QFETCH(QString, html); - QWebEnginePage* page = new QWebEnginePage; - page->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); - page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); - ::waitForSignal(page, SIGNAL(loadFinished(bool)), 2000); + QWebEnginePage page; + page.settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + page.setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); + QVERIFY(spyFinished.wait(2000)); // take screenshot without a view - takeScreenshot(page); + takeScreenshot(&page); - QWebEngineView* view = new QWebEngineView; - view->setPage(page); + QWebEngineView view; + view.setPage(&page); // take screenshot when attached to a view - takeScreenshot(page); - - delete page; - delete view; + takeScreenshot(&page); QDir::setCurrent(QApplication::applicationDirPath()); #endif @@ -2865,7 +2855,8 @@ void tst_QWebEnginePage::testStopScheduledPageRefresh() "<meta http-equiv=\"refresh\"content=\"0;URL=qrc:///resources/index.html\">" "</head><body><h1>Page redirects immediately...</h1>" "</body></html>"); - QVERIFY(::waitForSignal(&page1, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(&page1, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait(); QTest::qWait(500); QCOMPARE(page1.url(), QUrl(QLatin1String("qrc:///resources/index.html"))); @@ -3217,7 +3208,8 @@ void tst_QWebEnginePage::deleteQWebEngineViewTwice() mainWindow.setCentralWidget(webView); webView->load(QUrl("qrc:///resources/frame_a.html")); mainWindow.show(); - QVERIFY(::waitForSignal(webView, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); } } @@ -3272,7 +3264,8 @@ void tst_QWebEnginePage::renderOnRepaintRequestedShouldNotRecurse() page.setHtml("zalan loves trunk", QUrl()); - QVERIFY(::waitForSignal(&r, SIGNAL(finished()))); + QSignalSpy spyFinished(&r, &RepaintRequestedRenderer::finished); + QVERIFY(spyFinished.wait()); #endif } @@ -3323,9 +3316,10 @@ void tst_QWebEnginePage::loadSignalsOrder() QFETCH(QUrl, url); QWebEnginePage page; SpyForLoadSignalsOrder loadSpy(&page); - waitForSignal(&loadSpy, SIGNAL(started()), 500); + QSignalSpy spyLoadSpy(&loadSpy, &SpyForLoadSignalsOrder::started); + QVERIFY(spyLoadSpy.wait(500)); page.load(url); - QTRY_VERIFY_WITH_TIMEOUT(loadSpy.isFinished(), 500); + QTRY_VERIFY(loadSpy.isFinished()); } void tst_QWebEnginePage::undoActionHaveCustomText() @@ -3412,26 +3406,25 @@ private: void tst_QWebEnginePage::getUserMediaRequest() { - GetUserMediaTestPage *page = new GetUserMediaTestPage(); + GetUserMediaTestPage page; // We need to load content from a resource in order for the securityOrigin to be valid. - QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool))); - page->load(QUrl("qrc:///resources/content.html")); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + page.load(QUrl("qrc:///resources/content.html")); QTRY_COMPARE(loadSpy.count(), 1); - QVERIFY(evaluateJavaScriptSync(page, QStringLiteral("!!navigator.webkitGetUserMedia")).toBool()); - evaluateJavaScriptSync(page, QStringLiteral("navigator.webkitGetUserMedia({audio: true}, function() {}, function(){})")); - QTRY_VERIFY(page->gotFeatureRequest(QWebEnginePage::MediaAudioCapture)); + QVERIFY(evaluateJavaScriptSync(&page, QStringLiteral("!!navigator.webkitGetUserMedia")).toBool()); + evaluateJavaScriptSync(&page, QStringLiteral("navigator.webkitGetUserMedia({audio: true}, function() {}, function(){})")); + QTRY_VERIFY(page.gotFeatureRequest(QWebEnginePage::MediaAudioCapture)); // Might end up failing due to the lack of physical media devices deeper in the content layer, so the JS callback is not guaranteed to be called, // but at least we go through that code path, potentially uncovering failing assertions. - page->acceptPendingRequest(); + page.acceptPendingRequest(); - page->runJavaScript(QStringLiteral("errorCallbackCalled = false;")); - evaluateJavaScriptSync(page, QStringLiteral("navigator.webkitGetUserMedia({audio: true, video: true}, function() {}, function(){errorCallbackCalled = true;})")); - QTRY_VERIFY(page->gotFeatureRequest(QWebEnginePage::MediaAudioVideoCapture)); - page->rejectPendingRequest(); // Should always end up calling the error callback in JS. - QTRY_VERIFY(evaluateJavaScriptSync(page, QStringLiteral("errorCallbackCalled;")).toBool()); - delete page; + page.runJavaScript(QStringLiteral("errorCallbackCalled = false;")); + evaluateJavaScriptSync(&page, QStringLiteral("navigator.webkitGetUserMedia({audio: true, video: true}, function() {}, function(){errorCallbackCalled = true;})")); + QTRY_VERIFY(page.gotFeatureRequest(QWebEnginePage::MediaAudioVideoCapture)); + page.rejectPendingRequest(); // Should always end up calling the error callback in JS. + QTRY_VERIFY(evaluateJavaScriptSync(&page, QStringLiteral("errorCallbackCalled;")).toBool()); } void tst_QWebEnginePage::savePage() @@ -3449,7 +3442,8 @@ void tst_QWebEnginePage::savePage() const QString urlPrefix = QStringLiteral("data:text/html,<h1>"); const QString text = QStringLiteral("There is Thingumbob shouting!"); page->load(QUrl(urlPrefix + text)); - waitForSignal(page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(toPlainTextSync(page), text); // Save the loaded page as HTML. @@ -3460,12 +3454,12 @@ void tst_QWebEnginePage::savePage() // Load something else. page->load(QUrl(urlPrefix + QLatin1String("It's a Snark!"))); - waitForSignal(page, SIGNAL(loadFinished(bool))); + QVERIFY(spyFinished.wait()); QVERIFY(toPlainTextSync(page) != text); // Load the saved page and compare the contents. page->load(QUrl::fromLocalFile(filePath)); - waitForSignal(page, SIGNAL(loadFinished(bool))); + QVERIFY(spyFinished.wait()); QCOMPARE(toPlainTextSync(page), text); } @@ -3704,13 +3698,13 @@ void tst_QWebEnginePage::runJavaScript() void tst_QWebEnginePage::fullScreenRequested() { JavaScriptCallbackWatcher watcher; - QWebEngineView* view = new QWebEngineView; - QWebEnginePage* page = view->page(); - view->show(); + QWebEngineView view; + QWebEnginePage* page = view.page(); + view.show(); page->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); - QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); + QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); page->load(QUrl("qrc:///resources/fullscreen.html")); QTRY_COMPARE(loadSpy.count(), 1); @@ -3725,7 +3719,7 @@ void tst_QWebEnginePage::fullScreenRequested() if (acceptRequest) request.accept(); else request.reject(); }); - QTest::keyPress(view->focusProxy(), Qt::Key_Space); + QTest::keyPress(view.focusProxy(), Qt::Key_Space); QTRY_VERIFY(evaluateJavaScriptSync(page, "document.webkitIsFullScreen").toBool()); page->runJavaScript("document.webkitExitFullscreen()", JavaScriptCallbackUndefined()); QVERIFY(watcher.wait()); @@ -3733,12 +3727,10 @@ void tst_QWebEnginePage::fullScreenRequested() acceptRequest = false; page->runJavaScript("document.webkitFullscreenEnabled", JavaScriptCallback(true)); - QTest::keyPress(view->focusProxy(), Qt::Key_Space); + QTest::keyPress(view.focusProxy(), Qt::Key_Space); QVERIFY(watcher.wait()); page->runJavaScript("document.webkitIsFullScreen", JavaScriptCallback(false)); QVERIFY(watcher.wait()); - - delete view; } void tst_QWebEnginePage::symmetricUrl() @@ -3791,7 +3783,8 @@ void tst_QWebEnginePage::progressSignal() QUrl dataUrl("data:text/html,<h1>Test"); m_view->setUrl(dataUrl); - ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(progressSpy.size() >= 2); int previousValue = -1; @@ -3812,14 +3805,14 @@ void tst_QWebEnginePage::urlChange() QUrl dataUrl("data:text/html,<h1>Test"); m_view->setUrl(dataUrl); - ::waitForSignal(m_page, SIGNAL(urlChanged(QUrl))); + QVERIFY(urlSpy.wait()); QCOMPARE(urlSpy.size(), 1); QUrl dataUrl2("data:text/html,<html><head><title>title</title></head><body><h1>Test</body></html>"); m_view->setUrl(dataUrl2); - ::waitForSignal(m_page, SIGNAL(urlChanged(QUrl))); + QVERIFY(urlSpy.wait()); QCOMPARE(urlSpy.size(), 2); } @@ -3922,7 +3915,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() const QUrl first("http://abcdef.abcdef/"); page.setUrl(first); - ::waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(spy.count(), 1); QCOMPARE(page.url(), first); QCOMPARE(page.requestedUrl(), first); @@ -3932,7 +3925,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() QVERIFY(first != second); page.load(second); - ::waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(spy.count(), 2); QCOMPARE(page.url(), first); QCOMPARE(page.requestedUrl(), second); @@ -3941,13 +3934,13 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() void tst_QWebEnginePage::asyncAndDelete() { - QWebEnginePage *page = new QWebEnginePage; + QScopedPointer<QWebEnginePage> page(new QWebEnginePage); CallbackSpy<QString> plainTextSpy; CallbackSpy<QString> htmlSpy; page->toPlainText(plainTextSpy.ref()); page->toHtml(htmlSpy.ref()); - delete page; + page.reset(); // Pending callbacks should be called with an empty value in the page's destructor. QCOMPARE(plainTextSpy.waitForResult(), QString()); QVERIFY(plainTextSpy.wasCalled()); @@ -4016,14 +4009,15 @@ void tst_QWebEnginePage::setHtmlWithStylesheetResource() QWebEngineElement webElement; page.setHtml(html, QUrl(QLatin1String("qrc:///file"))); - waitForSignal(&page, SIGNAL(loadFinished(bool)), 200); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait(200)); webElement = page.documentElement().findFirst("p"); QCOMPARE(webElement.styleProperty("color", QWebEngineElement::CascadedStyle), QLatin1String("red")); // Now we test the opposite: without a baseUrl as a local file, we cannot request local resources. page.setHtml(html, QUrl(QLatin1String("http://www.example.com/"))); - waitForSignal(&page, SIGNAL(loadFinished(bool)), 200); + QVERIFY(spyFinished.wait(200)); webElement = page.documentElement().findFirst("p"); QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=118659", Continue); QCOMPARE(webElement.styleProperty("color", QWebEngineElement::CascadedStyle), QString()); @@ -4048,7 +4042,8 @@ void tst_QWebEnginePage::setHtmlWithBaseURL() QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); page.setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(spy.count(), 1); QCOMPARE(evaluateJavaScriptSync(&page, "document.images.length").toInt(), 1); @@ -4079,7 +4074,8 @@ void tst_QWebEnginePage::setHtmlWithJSAlert() QString html("<html><head></head><body><script>alert('foo');</script><p>hello world</p></body></html>"); MyPage page; page.setHtml(html, QUrl(QStringLiteral("http://test.origin.com/path#fragment"))); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(page.alerts, 1); QCOMPARE(toHtmlSync(&page), html); } @@ -4259,9 +4255,9 @@ void tst_QWebEnginePage::scrollbarsOff() "</body>"); - QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); + QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished); view.setHtml(html); - ::waitForSignal(&view, SIGNAL(loadFinished(bool)), 200); + QVERIFY(loadSpy.wait(200); QCOMPARE(loadSpy.count(), 1); mainFrame->evaluateJavaScript("checkScrollbar();"); @@ -4327,7 +4323,8 @@ void tst_QWebEnginePage::evaluateWillCauseRepaint() QTRY_COMPARE(loadSpy.count(), 1); evaluateJavaScriptSync(view.page(), "document.getElementById('junk').style.display = 'none';"); - ::waitForSignal(&view, SIGNAL(repaintRequested())); + QSignalSpy repaintSpy(&view, &WebView::repaintRequested); + QVERIFY(repaintSpy.wait()); } void tst_QWebEnginePage::setContent_data() @@ -4441,7 +4438,7 @@ void tst_QWebEnginePage::setUrlToEmpty() // Set existing url page.setUrl(url); expectedLoadFinishedCount++; - ::waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spy.wait()); QCOMPARE(spy.count(), expectedLoadFinishedCount); QCOMPARE(page.url(), url); @@ -4602,7 +4599,8 @@ void tst_QWebEnginePage::setUrlUsingStateObject() url = QUrl("qrc:/resources/test1.html"); m_page->setUrl(url); - waitForSignal(m_page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(m_page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); expectedUrlChangeCount++; QCOMPARE(urlChangedSpy.count(), expectedUrlChangeCount); QCOMPARE(m_page->url(), url); @@ -4802,39 +4800,37 @@ void tst_QWebEnginePage::loadInSignalHandlers() URLSetter setter(m_page, signal, type, urlForSetter); m_page->load(url); - waitForSignal(&setter, SIGNAL(finished())); + QSignalSpy spy(&setter, &URLSetter::finished); + QVERIFY(spy.wait()); QCOMPARE(m_page->url(), urlForSetter); } void tst_QWebEnginePage::restoreHistory() { - QWebChannel *channel = new QWebChannel; - QWebEnginePage *page = new QWebEnginePage; - page->setWebChannel(channel); + QWebChannel channel; + QWebEnginePage page; + page.setWebChannel(&channel); QWebEngineScript script; script.setName(QStringLiteral("script")); - page->scripts().insert(script); + page.scripts().insert(script); - QSignalSpy spy(page, SIGNAL(loadFinished(bool))); - page->load(QUrl(QStringLiteral("qrc:/resources/test1.html"))); + QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); + page.load(QUrl(QStringLiteral("qrc:/resources/test1.html"))); QTRY_COMPARE(spy.count(), 1); - QCOMPARE(page->webChannel(), channel); - QVERIFY(page->scripts().contains(script)); + QCOMPARE(page.webChannel(), &channel); + QVERIFY(page.scripts().contains(script)); QByteArray data; QDataStream out(&data, QIODevice::ReadWrite); - out << *page->history(); + out << *page.history(); QDataStream in(&data, QIODevice::ReadOnly); - in >> *page->history(); + in >> *page.history(); QTRY_COMPARE(spy.count(), 2); - QCOMPARE(page->webChannel(), channel); - QVERIFY(page->scripts().contains(script)); - - delete page; - delete channel; + QCOMPARE(page.webChannel(), &channel); + QVERIFY(page.scripts().contains(script)); } void tst_QWebEnginePage::toPlainTextLoadFinishedRace_data() @@ -4848,33 +4844,33 @@ void tst_QWebEnginePage::toPlainTextLoadFinishedRace() { QFETCH(bool, enableErrorPage); - QWebEnginePage *page = new QWebEnginePage; + QScopedPointer<QWebEnginePage> page(new QWebEnginePage); page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, enableErrorPage); - QSignalSpy spy(page, SIGNAL(loadFinished(bool))); + QSignalSpy spy(page.data(), SIGNAL(loadFinished(bool))); page->load(QUrl("data:text/plain,foobarbaz")); QTRY_VERIFY(spy.count() == 1); - QCOMPARE(toPlainTextSync(page), QString("foobarbaz")); + QCOMPARE(toPlainTextSync(page.data()), QString("foobarbaz")); page->load(QUrl("fail:unknown/scheme")); QTRY_VERIFY(spy.count() == 2); - QString s = toPlainTextSync(page); + QString s = toPlainTextSync(page.data()); QVERIFY(s.contains("foobarbaz") == !enableErrorPage); page->load(QUrl("data:text/plain,lalala")); QTRY_VERIFY(spy.count() == 3); - QCOMPARE(toPlainTextSync(page), QString("lalala")); - delete page; + QCOMPARE(toPlainTextSync(page.data()), QString("lalala")); + page.reset(); QVERIFY(spy.count() == 3); } void tst_QWebEnginePage::setZoomFactor() { - QWebEnginePage *page = new QWebEnginePage; + QWebEnginePage page; - QVERIFY(qFuzzyCompare(page->zoomFactor(), 1.0)); - page->setZoomFactor(2.5); - QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + QVERIFY(qFuzzyCompare(page.zoomFactor(), 1.0)); + page.setZoomFactor(2.5); + QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); const QUrl urlToLoad("qrc:/resources/test1.html"); @@ -4882,19 +4878,20 @@ void tst_QWebEnginePage::setZoomFactor() m_page->setUrl(urlToLoad); QTRY_COMPARE(finishedSpy.count(), 1); QVERIFY(finishedSpy.at(0).first().toBool()); - QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); - page->setZoomFactor(5.5); - QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + page.setZoomFactor(5.5); + QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); - page->setZoomFactor(0.1); - QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); - - delete page; + page.setZoomFactor(0.1); + QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); } void tst_QWebEnginePage::printToPdf() { +#if !defined(QWEBENGINEPAGE_PDFPRINTINGENABLED) + QSKIP("QWEBENGINEPAGE_PDFPRINTINGENABLED"); +#else QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); QVERIFY(tempDir.isValid()); QWebEnginePage page; @@ -4922,14 +4919,15 @@ void tst_QWebEnginePage::printToPdf() CallbackSpy<QByteArray> failedInvalidLayoutSpy; page.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout()); QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0); +#endif } void tst_QWebEnginePage::mouseButtonTranslation() { - QWebEngineView *view = new QWebEngineView; + QWebEngineView view; - QSignalSpy spy(view, SIGNAL(loadFinished(bool))); - view->setHtml(QStringLiteral( + QSignalSpy spy(&view, SIGNAL(loadFinished(bool))); + view.setHtml(QStringLiteral( "<html><head><script>\ var lastEvent = { 'button' : -1 }; \ function saveLastEvent(event) { console.log(event); lastEvent = event; }; \ @@ -4938,25 +4936,23 @@ void tst_QWebEnginePage::mouseButtonTranslation() <div style=\"height:600px;\" onmousedown=\"saveLastEvent(event)\">\ </div>\ </body></html>")); - view->show(); - QTest::qWaitForWindowExposed(view); + view.show(); + QTest::qWaitForWindowExposed(&view); QTRY_VERIFY(spy.count() == 1); - QVERIFY(view->focusProxy() != nullptr); - - QMouseEvent evpres(QEvent::MouseButtonPress, view->rect().center(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); - QGuiApplication::sendEvent(view->focusProxy(), &evpres); + QVERIFY(view.focusProxy() != nullptr); - QTRY_COMPARE(evaluateJavaScriptSync(view->page(), "lastEvent.button").toInt(), 0); - QCOMPARE(evaluateJavaScriptSync(view->page(), "lastEvent.buttons").toInt(), 1); + QMouseEvent evpres(QEvent::MouseButtonPress, view.rect().center(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QGuiApplication::sendEvent(view.focusProxy(), &evpres); - QMouseEvent evpres2(QEvent::MouseButtonPress, view->rect().center(), Qt::RightButton, Qt::LeftButton | Qt::RightButton, Qt::NoModifier); - QGuiApplication::sendEvent(view->focusProxy(), &evpres2); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.button").toInt(), 0); + QCOMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.buttons").toInt(), 1); - QTRY_COMPARE(evaluateJavaScriptSync(view->page(), "lastEvent.button").toInt(), 2); - QCOMPARE(evaluateJavaScriptSync(view->page(), "lastEvent.buttons").toInt(), 3); + QMouseEvent evpres2(QEvent::MouseButtonPress, view.rect().center(), Qt::RightButton, Qt::LeftButton | Qt::RightButton, Qt::NoModifier); + QGuiApplication::sendEvent(view.focusProxy(), &evpres2); - delete view; + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.button").toInt(), 2); + QCOMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.buttons").toInt(), 3); } QPoint tst_QWebEnginePage::elementCenter(QWebEnginePage *page, const QString &id) @@ -5035,20 +5031,18 @@ void tst_QWebEnginePage::viewSourceURL() QFETCH(QUrl, requestedUrl); QFETCH(QString, title); - QWebEnginePage *page = new QWebEnginePage; - QSignalSpy loadFinishedSpy(page, SIGNAL(loadFinished(bool))); + QWebEnginePage page; + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); - page->load(userInputUrl); + page.load(userInputUrl); QTRY_COMPARE(loadFinishedSpy.count(), 1); QList<QVariant> arguments = loadFinishedSpy.takeFirst(); QCOMPARE(arguments.at(0).toBool(), loadSucceed); - QCOMPARE(page->url(), url); - QCOMPARE(page->requestedUrl(), requestedUrl); - QCOMPARE(page->title(), title); - QVERIFY(!page->action(QWebEnginePage::ViewSource)->isEnabled()); - - delete page; + QCOMPARE(page.url(), url); + QCOMPARE(page.requestedUrl(), requestedUrl); + QCOMPARE(page.title(), title); + QVERIFY(!page.action(QWebEnginePage::ViewSource)->isEnabled()); } QTEST_MAIN(tst_QWebEnginePage) diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp index d5ecd8841..c10ae2886 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -62,7 +62,8 @@ void tst_QWebEngineScript::domEditing() page.scripts().insert(s); page.load(QUrl("about:blank")); view.show(); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "document.getElementById(\"banner\").innerText"), QVariant(QStringLiteral("Injected banner"))); // elementFromPoint only works for exposed elements QTest::qWaitForWindowExposed(&view); @@ -85,7 +86,8 @@ void tst_QWebEngineScript::injectionPoint() document.body.innerText = contents;\ }, 550));\ </script></head><body></body></html>")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QTRY_COMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS"))); } @@ -116,14 +118,15 @@ void tst_QWebEngineScript::scriptWorld() script.setSourceCode(QStringLiteral("var userScriptTest = 1;")); page.scripts().insert(script); page.load(QUrl("about:blank")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "typeof(userScriptTest) != \"undefined\" && userScriptTest == 1;"), QVariant::fromValue(true)); QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "typeof(userScriptTest) == \"undefined\"", QWebEngineScript::ApplicationWorld), QVariant::fromValue(true)); script.setWorldId(QWebEngineScript::ApplicationWorld); page.scripts().clear(); page.scripts().insert(script); page.load(QUrl("about:blank")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "typeof(userScriptTest) == \"undefined\""), QVariant::fromValue(true)); QCOMPARE(evaluateJavaScriptSyncInWorld(&page, "typeof(userScriptTest) != \"undefined\" && userScriptTest == 1;", QWebEngineScript::ApplicationWorld), QVariant::fromValue(true)); } @@ -141,11 +144,12 @@ void tst_QWebEngineScript::scriptModifications() document.body.innerText = foo;});\ </script></head><body></body></html>")); QVERIFY(page.scripts().count() == 1); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS"))); script.setSourceCode("var foo = \"FAILURE\""); page.triggerAction(QWebEnginePage::ReloadAndBypassCache); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS"))); QVERIFY(page.scripts().count() == 1); QWebEngineScript s = page.scripts().findScript(QStringLiteral("String1")); @@ -209,11 +213,12 @@ void tst_QWebEngineScript::webChannel() script.setSourceCode(QString::fromLatin1(scriptSrc)); page.scripts().insert(script); page.setHtml(QStringLiteral("<html><body></body></html>")); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); if (reloadFirst) { // Check that the transport is also reinstalled on navigation page.triggerAction(QWebEnginePage::Reload); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QVERIFY(spyFinished.wait()); } page.runJavaScript(QLatin1String( "new QWebChannel(qt.webChannelTransport," @@ -221,7 +226,8 @@ void tst_QWebEngineScript::webChannel() " channel.objects.object.text = 'test';" " }" ");"), worldId); - waitForSignal(&testObject, SIGNAL(textChanged(QString))); + QSignalSpy spyTextChanged(&testObject, &TestObject::textChanged); + QVERIFY(spyTextChanged.wait()); QCOMPARE(testObject.text(), QStringLiteral("test")); if (worldId != QWebEngineScript::MainWorld) @@ -235,7 +241,8 @@ void tst_QWebEngineScript::noTransportWithoutWebChannel() QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid)); page.triggerAction(QWebEnginePage::Reload); - waitForSignal(&page, SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid)); } diff --git a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp index 4db5b9477..c7b083660 100644 --- a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp +++ b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp @@ -103,7 +103,9 @@ void tst_QWebEngineSpellcheck::load() { m_view->page()->load(QUrl("qrc:///resources/index.html")); m_view->show(); - waitForSignal(m_view->page(), SIGNAL(loadFinished(bool))); + QSignalSpy spyFinished(m_view->page(), &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); + } void tst_QWebEngineSpellcheck::cleanup() @@ -170,7 +172,8 @@ void tst_QWebEngineSpellcheck::spellcheck() // open menu on misspelled word m_view->activateMenu(m_view->focusWidget(), rect.center()); - waitForSignal(m_view, SIGNAL(menuReady())); + QSignalSpy spyMenuReady(m_view, &WebView::menuReady); + QVERIFY(spyMenuReady.wait()); // check if menu is valid QVERIFY(m_view->data().isValid()); diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST new file mode 100644 index 000000000..0a909d0f6 --- /dev/null +++ b/tests/auto/widgets/qwebengineview/BLACKLIST @@ -0,0 +1,2 @@ +[doNotSendMouseKeyboardEventsWhenDisabled] +windows diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 9966ad9ee..2baadd869 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -31,8 +31,11 @@ #include <qdiriterator.h> #include <qstackedlayout.h> #include <qtemporarydir.h> +#include <QCompleter> #include <QLineEdit> #include <QHBoxLayout> +#include <QQuickItem> +#include <QQuickWidget> #define VERIFY_INPUTMETHOD_HINTS(actual, expect) \ QVERIFY(actual == expect); @@ -83,6 +86,7 @@ private Q_SLOTS: void inputMethodsTextFormat_data(); void inputMethodsTextFormat(); void keyboardEvents(); + void keyboardFocusAfterPopup(); }; // This will be called before the first test function is executed. @@ -177,7 +181,8 @@ void tst_QWebEngineView::reusePage() page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); if (html.contains("</embed>")) { // some reasonable time for the PluginStream to feed test.swf to flash and start painting - waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000); + QSignalSpy spyFinished(view1, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait(2000)); } view1->show(); @@ -281,7 +286,8 @@ void tst_QWebEngineView::focusInputTypes() webView.load(url); mainFrame->setFocus(); - QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); // 'text' type QWebEngineElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); @@ -400,7 +406,8 @@ void tst_QWebEngineView::horizontalScrollbarTest() webView.page()->load(url); webView.page()->setFocus(); - QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(webView.page()->scrollPosition() == QPoint(0, 0)); @@ -562,7 +569,8 @@ void tst_QWebEngineView::renderingAfterMaxAndBack() QWebEngineView view; view.page()->load(url); - QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(&view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); view.show(); view.page()->settings()->setMaximumPagesInCache(3); @@ -584,7 +592,7 @@ void tst_QWebEngineView::renderingAfterMaxAndBack() "</html>"); view.page()->load(url2); - QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); + QVERIFY(spyFinished.wait()); view.showMaximized(); @@ -840,25 +848,29 @@ void tst_QWebEngineView::changeLocale() QWebEngineView viewDE; viewDE.setUrl(url); - QVERIFY(waitForSignal(&viewDE, SIGNAL(titleChanged(QString)))); - QVERIFY(waitForSignal(&viewDE, SIGNAL(loadFinished(bool)))); + QSignalSpy spyTitleChangedDE(&viewDE, &QWebEngineView::titleChanged); + QVERIFY(spyTitleChangedDE.wait()); + QSignalSpy spyFinishedDE(&viewDE, &QWebEngineView::loadFinished); + QVERIFY(spyFinishedDE.wait()); QCOMPARE(viewDE.title(), QStringLiteral("Nicht verf\u00FCgbar: %1").arg(url.toString())); QLocale::setDefault(QLocale("en")); QWebEngineView viewEN; viewEN.setUrl(url); - QVERIFY(waitForSignal(&viewEN, SIGNAL(titleChanged(QString)))); - QVERIFY(waitForSignal(&viewEN, SIGNAL(loadFinished(bool)))); + QSignalSpy spyTitleChangedEN(&viewEN, &QWebEngineView::titleChanged); + QVERIFY(spyTitleChangedEN.wait()); + QSignalSpy spyFinishedEN(&viewEN, &QWebEngineView::loadFinished); + QVERIFY(spyFinishedEN.wait()); QCOMPARE(viewEN.title(), QStringLiteral("%1 is not available").arg(url.toString())); viewDE.setUrl(QUrl("about:blank")); - QVERIFY(waitForSignal(&viewDE, SIGNAL(loadFinished(bool)))); + QVERIFY(spyFinishedDE.wait()); viewDE.setUrl(url); - QVERIFY(waitForSignal(&viewDE, SIGNAL(titleChanged(QString)))); - QVERIFY(waitForSignal(&viewDE, SIGNAL(loadFinished(bool)))); + QVERIFY(spyTitleChangedDE.wait()); + QVERIFY(spyFinishedDE.wait()); QCOMPARE(viewDE.title(), QStringLiteral("Nicht verf\u00FCgbar: %1").arg(url.toString())); } @@ -1014,5 +1026,60 @@ void tst_QWebEngineView::keyboardEvents() QVERIFY(loadFinishedSpy.wait()); } +void tst_QWebEngineView::keyboardFocusAfterPopup() +{ + QScopedPointer<QWidget> containerWidget(new QWidget); + + QLineEdit *urlLine = new QLineEdit(containerWidget.data()); + QStringList urlList; + urlList << "test"; + QCompleter *completer = new QCompleter(urlList, urlLine); + completer->setCompletionMode(QCompleter::PopupCompletion); + urlLine->setCompleter(completer); + urlLine->setFocus(); + + QWebEngineView *webView = new QWebEngineView(containerWidget.data()); + QSignalSpy loadFinishedSpy(webView, SIGNAL(loadFinished(bool))); + + connect(urlLine, &QLineEdit::editingFinished, [=] { + webView->setHtml("<html><body onload=\"document.getElementById('input1').focus()\">" + " <input type='text' id='input1' />" + "</body></html>"); + + // Check whether the RenderWidgetHostView has the keyboard focus + QQuickWidget *rwhv = qobject_cast<QQuickWidget *>(webView->focusProxy()); + QVERIFY(rwhv); + QVERIFY(rwhv->hasFocus()); + QVERIFY(rwhv->rootObject()->hasFocus()); + QVERIFY(rwhv->window()->windowHandle()->isActive()); + QVERIFY(rwhv->rootObject()->hasActiveFocus()); + }); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(urlLine); + layout->addWidget(webView); + + containerWidget->setLayout(layout); + containerWidget->show(); + QTest::qWaitForWindowExposed(containerWidget.data()); + + // Trigger completer's popup and select the first suggestion + QTest::keyClick(urlLine, Qt::Key_T); + qApp->processEvents(); + QTRY_VERIFY(qApp->activePopupWidget()); + QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Down); + qApp->processEvents(); + QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Enter); + qApp->processEvents(); + + // After the load the focused window should forward the keyboard events to the webView + QVERIFY(loadFinishedSpy.wait()); + // Wait for active focus on the input field + QTRY_COMPARE(evaluateJavaScriptSync(webView->page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + QTest::keyClick(qApp->focusWindow(), Qt::Key_X); + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(webView->page(), "document.getElementById('input1').value").toString(), QStringLiteral("x")); +} + QTEST_MAIN(tst_QWebEngineView) #include "tst_qwebengineview.moc" diff --git a/tests/auto/widgets/tests.pri b/tests/auto/widgets/tests.pri index ca19a9496..14074cd08 100644 --- a/tests/auto/widgets/tests.pri +++ b/tests/auto/widgets/tests.pri @@ -12,7 +12,7 @@ INCLUDEPATH += $$PWD RESOURCES += ../resources/tests.qrc exists($$_PRO_FILE_PWD_/$${TARGET}.qrc): RESOURCES += $${TARGET}.qrc -QT += testlib network webenginewidgets widgets +QT += testlib network webenginewidgets widgets quick quickwidgets macx: CONFIG -= app_bundle # This define is used by some tests to look up resources in the source tree diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h index 770579f1f..356cf6ebb 100644 --- a/tests/auto/widgets/util.h +++ b/tests/auto/widgets/util.h @@ -42,29 +42,6 @@ #endif /** - * Starts an event loop that runs until the given signal is received. - * Optionally the event loop - * can return earlier on a timeout. - * - * \return \p true if the requested signal was received - * \p false on timeout - */ -static inline bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000) -{ - QEventLoop loop; - QObject::connect(obj, signal, &loop, SLOT(quit())); - QTimer timer; - QSignalSpy timeoutSpy(&timer, SIGNAL(timeout())); - if (timeout > 0) { - QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - timer.setSingleShot(true); - timer.start(timeout); - } - loop.exec(); - return timeoutSpy.isEmpty(); -} - -/** * Just like QSignalSpy but facilitates sync and async * signal emission. For example if you want to verify that * page->foo() emitted a signal, it could be that the diff --git a/tools/qmake/mkspecs/features/configure.prf b/tools/qmake/mkspecs/features/configure.prf index c6f07e39d..bb4c56cae 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/tools/qmake/mkspecs/features/configure.prf @@ -78,6 +78,9 @@ defineTest(runConfigure) { else: log("System NSS not found, BoringSSL will be used.$${EOL}") } } + !cross_compile { + WEBENGINE_CONFIG += enable_pdf + } isQtMinimum(5, 8) { include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) QT_FOR_CONFIG += webengine-private diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index fbd92b133..8191f7589 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -292,7 +292,7 @@ defineReplace(getConfigDir) { } defineReplace(getChromiumSrcDir) { - git_chromium_src_dir = $$system("git config qtwebengine.chromiumsrcdir") + exists($$QTWEBENGINE_ROOT/.git): git_chromium_src_dir = $$system("git config qtwebengine.chromiumsrcdir") # Fall back to the snapshot path if git does not know about chromium sources (i.e. init-repository.py has not been used) isEmpty(git_chromium_src_dir): git_chromium_src_dir = "src/3rdparty/chromium" return($$git_chromium_src_dir) |