From f4815cebae99bc27f6880e3281eda81078821d08 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 11 Oct 2016 13:56:31 +0200 Subject: Fix crash in WebEngineContext when using Wayland For some reason the OpenGL context wayland QPA sets has no nativeHandle, so we end up crashing in strcmp. Assume a context without nativeHandle is Wayland or other GLES2 platform and also force GLES2 when using Ozone. Change-Id: Ia3fc524f3ffbb278d86f9153ec96c7258ef86656 Reviewed-by: Michal Klocek --- src/core/web_engine_context.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 7d1e5d609..ceb14f843 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -311,8 +311,15 @@ WebEngineContext::WebEngineContext() const char *glType = 0; if (!usingANGLE() && !usingSoftwareDynamicGL() && !usingQtQuick2DRenderer()) { - if (qt_gl_global_share_context()) { - if (!strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), "QEGLNativeContext")) { + if (qt_gl_global_share_context() && qt_gl_global_share_context()->isValid()) { + // 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 = gfx::kGLImplementationEGLName; } else { -- cgit v1.2.3 From afedaaf2492ea4899198cb9886f9e249c6cbe119 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 10 Oct 2016 14:05:43 +0200 Subject: Update Chromium Change-Id: I6803569bd7bee4bf8eb94f61771ea2a318eb752b Reviewed-by: Kai Koehne --- src/3rdparty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty b/src/3rdparty index 881a7672e..b82d94c4f 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit 881a7672e23192eaf7e1ac2f94e086b560104f10 +Subproject commit b82d94c4f82330ed64ccb639985312198a9cda7a -- cgit v1.2.3 From d82fb129145f933659f0315ca6203ab51c24937a Mon Sep 17 00:00:00 2001 From: Viktor Engelmann Date: Thu, 6 Oct 2016 16:08:30 +0200 Subject: Fix nullpointer dereferencing error Check whether iconUrls is NULL before calling contains(iconUrl) on it, which, under certain circumstances, caused a SEGFAULT. Task-number: QTBUG-56330 Change-Id: Ia167d68a4c4d62af4740a8cbab2686bfbc975455 Reviewed-by: Peter Varga --- src/webengine/api/qquickwebenginefaviconprovider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 *iconUrls = m_iconUrlMap[m_latestView]; - if (iconUrls->contains(iconUrl)) + if (iconUrls && iconUrls->contains(iconUrl)) return m_latestView; } -- cgit v1.2.3 From 330de004cfab4651e7c3c8f105d530e41eb5a939 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 13 Oct 2016 10:30:51 +0200 Subject: Add changes for 5.7.1 Change-Id: Iec54a4a3a117ce5f6bca8ff22218eb8fea0008e8 Reviewed-by: Leena Miettinen --- dist/changes-5.7.1 | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 dist/changes-5.7.1 diff --git a/dist/changes-5.7.1 b/dist/changes-5.7.1 new file mode 100644 index 000000000..ece3095df --- /dev/null +++ b/dist/changes-5.7.1 @@ -0,0 +1,51 @@ +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 53.0.2785.143. + 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 + * Support for macOS 10.12 Sierra + + - 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. -- cgit v1.2.3 From 99a2a538eba5e3c351e3118b3c6f71458af91886 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 13 Oct 2016 13:59:08 +0200 Subject: Update Chromium Pulls in security fixes from the Chromium 54.0.2840.59 release, Changes included: - Fix renderer crash on null family strings - [Backport] Blink-in-JS should not run micro tasks - [Backport] Disallow reentrance of FrameView::updateLifecyclePhasesInternal() - [Backport] Check CORS policy on redirect in TextTrackLoader - [Backport] Keep top controls visible if SHOW is called right after HIDE. - [Backport] Merge to 2840 "[DevTools] Avoid current_ and pending_ being the same host in RenderFrameDevToolsAgentHost." - [Backport] Enable do not allow default action for untrusted events. - [Backport] Compare font-feature-settings as part of Font::operator==(). - Stop the flood of accessibility messages - [Backport] Fix for hitting an assert when refreshing a page with an image - [Backport] Report the decoded size to ImageObserver, instead of deltas Change-Id: I142cc070ba7fb215e4a5b9c162852b583dab9784 Reviewed-by: Kai Koehne --- dist/changes-5.7.1 | 6 ++++-- src/3rdparty | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dist/changes-5.7.1 b/dist/changes-5.7.1 index ece3095df..5e0953ee6 100644 --- a/dist/changes-5.7.1 +++ b/dist/changes-5.7.1 @@ -26,11 +26,13 @@ information about a particular change. **************************************************************************** - Chromium Snapshot: - * Security fixes from Chromium up to version 53.0.2785.143. + * Security fixes from Chromium up to version 54.0.2840.59 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-5172, CVE-2016-5181, CVE-2016-5185, CVE-2016-5186, + CVE-2016-5187, CVE-2016-5188, CVE-2016-5192 * Support for macOS 10.12 Sierra + * Various backported crash and assert fixes - QtWebEngineCore: * [QTBUG-51244, QTBUG-54795] Fixed select control issues diff --git a/src/3rdparty b/src/3rdparty index b82d94c4f..d3651e09c 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit b82d94c4f82330ed64ccb639985312198a9cda7a +Subproject commit d3651e09c34202cc83e32c200fd50cc1f90ab169 -- cgit v1.2.3 From e2541ebdfadea0fe43baac748cfa9e07f3b57215 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Mon, 26 Sep 2016 20:26:01 +0200 Subject: Do not call QOpenGLContext::openGLModuleType() from MainDll In case of dynamic OpenGL on Windows this ends on calling QWindowsIntegration::staticOpenGLContext() from MainDll which in case of angle will end up badly. Add warning message when webengine is loaded from plugin and context is not initialized. Task-number: QTBUG-52201 Task-number: QTBUG-55501 Task-number: QTBUG-56020 Change-Id: I03570cad5f686c4a63910c71136bf3eb9499f223 Reviewed-by: Kai Koehne --- src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp b/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp index e47f135e8..bf3514f71 100644 --- a/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp +++ b/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp @@ -48,17 +48,22 @@ namespace QtWebEngineCore } QT_BEGIN_NAMESPACE + +Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); + 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) { + 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); } -- cgit v1.2.3 From 37c8cc637d8f2e06b715362d5b8fa491e1ce93ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Br=C3=BCning?= Date: Thu, 27 Oct 2016 11:01:53 +0200 Subject: Update changes file for 5.7.1 Change-Id: Ib683ecda4c4bb2d58f36ad92f703d58f00e9d445 Reviewed-by: Michal Klocek --- dist/changes-5.7.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/changes-5.7.1 b/dist/changes-5.7.1 index 5e0953ee6..7ba4fd2ff 100644 --- a/dist/changes-5.7.1 +++ b/dist/changes-5.7.1 @@ -51,3 +51,7 @@ information about a particular change. * 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. -- cgit v1.2.3 From 15ded5ca62f53a01f85a52326f0b335a8a012bbd Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 8 Nov 2016 10:55:05 +0100 Subject: Update Chromium MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pulls in the security fix from Chrome 54.0.2840.87 Change-Id: I70064927cba01b7978742951ba0636b780d9eb68 Reviewed-by: Michael Brüning Reviewed-by: Joerg Bornemann --- dist/changes-5.7.1 | 4 ++-- src/3rdparty | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/changes-5.7.1 b/dist/changes-5.7.1 index 7ba4fd2ff..bf5934320 100644 --- a/dist/changes-5.7.1 +++ b/dist/changes-5.7.1 @@ -26,11 +26,11 @@ information about a particular change. **************************************************************************** - Chromium Snapshot: - * Security fixes from Chromium up to version 54.0.2840.59 + * 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-5187, CVE-2016-5188, CVE-2016-5192, CVE-2016-5198 * Support for macOS 10.12 Sierra * Various backported crash and assert fixes diff --git a/src/3rdparty b/src/3rdparty index d3651e09c..b3c79e92f 160000 --- a/src/3rdparty +++ b/src/3rdparty @@ -1 +1 @@ -Subproject commit d3651e09c34202cc83e32c200fd50cc1f90ab169 +Subproject commit b3c79e92f0a631273b639af171e59f4c367ae02e -- cgit v1.2.3 From 58467ed1950ee070d0907cbdabb8466aba277305 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Tue, 13 Sep 2016 18:17:43 +0200 Subject: Fix select tag interaction when the web view is inside a modal dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously when a QWebEngineView was inside a modal QDialog, trying to click on a select tag option did not properly select the option. It either focused the new option without closing the popup, or didn't focus it at all. Fix consists in making sure the newly created popup QWindow and RenderWidgetHostViewQtDelegateWidget are marked as children of the QWebEngineView, so that they are considered part of the current modal session by the OS, thus allowing user interaction with them. Because the ownership of the delegate widget should still be retained by its respective RenderWidgetHostViewQt instance, the QObject parent of the delegate is unset before the parent is destroyed. Also to make it work on macOS, the window attribute has to be set to Qt::Tool instead of Qt::ToolTip. Change-Id: I56d6f446254a624428a0c661ac3c49eb409c931e Task-number: QTBUG-54836 Reviewed-by: Qt CI Bot Reviewed-by: Michael Brüning --- src/webenginewidgets/api/qwebenginepage.cpp | 11 ++++++++++- .../render_widget_host_view_qt_delegate_widget.cpp | 21 ++++++++++++++++++++- .../render_widget_host_view_qt_delegate_widget.h | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index df96f4c17..a9a908e13 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -144,7 +144,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) 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 5bc1671df..a3ad898ad 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -103,6 +103,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) @@ -125,7 +140,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(); 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 ecf2d2d33..aa9495105 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -92,6 +92,7 @@ protected: private slots: void onWindowPosChanged(); + void removeParentBeforeParentDelete(); private: RenderWidgetHostViewQtDelegateClient *m_client; -- cgit v1.2.3 From 5fc3be56ea6c1d7b1b7567ce429774e92859dd14 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 9 Nov 2016 10:30:04 +0100 Subject: Check if the .git directory exists before invoking git If .git does not exist then this is not from a git build and therefore there is no reason to invoke git (which might not even exist on the system anyway). This prevents an error appearing due to trying to invoke git on Windows when it does not exist. Change-Id: I8c0b5b237cfdaffdbb33efdd16cf20cd1560f1a1 Reviewed-by: Joerg Bornemann --- tools/qmake/mkspecs/features/functions.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index a5481e2b9..2fbbb1b42 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -102,7 +102,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) -- cgit v1.2.3 From 7a4324f5e4c3927b51e4176daf0d8ae6599c984a Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 15 Nov 2016 17:44:19 +0100 Subject: Pass size to URLRequestJob If QIODevice has a size we can pass that on as expected size. This fixes media playback where Chromium does not always support streaming outside of HTTP or HTTPS. Task-number: QTBUG-57139 Change-Id: Ie8bf96b1f7f6af80fe707936055620d154c3ef2d Reviewed-by: Michal Klocek Reviewed-by: Milian Wolff --- src/core/url_request_custom_job.cpp | 3 +++ 1 file changed, 3 insertions(+) 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 -- cgit v1.2.3 From db1f77b2c44baa8426d0a5911b6c234704e9cc90 Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Mon, 21 Nov 2016 14:52:05 +0100 Subject: Fix IPC message logging Register Qt IPC messages for logging. The usage of content::RegisterIPCLogger function adds the content_common.content_ipc_logging.o to the link dependency. Thus it will register the Chromium Content IPC messages too. Task-number: QTBUG-57224 Change-Id: I2c45691feb22a34f6074940cc35b8a4ba7804370 Reviewed-by: Allan Sandfeld Jensen --- src/core/common/qt_ipc_logging.cpp | 48 ++++++++++++++++++++++++++++++++++++++ src/core/core_gyp_generator.pro | 1 + 2 files changed, 49 insertions(+) create mode 100644 src/core/common/qt_ipc_logging.cpp 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/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index ec180d38e..4b0f6d90a 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -44,6 +44,7 @@ SOURCES = \ chromium_gpu_helper.cpp \ chromium_overrides.cpp \ clipboard_qt.cpp \ + common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ content_client_qt.cpp \ -- cgit v1.2.3 From 95435bbef3102727759e826bed63fe3d0a6ce057 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 23 Nov 2016 15:20:41 +0100 Subject: Blacklist doNotSendMouseKeyboardEventsWhenDisabled on Windows It fails occasionally and blocks integration Task-number: QTBUG-57117 Change-Id: I7266ccf4fe7e0905dc31e5e7c085be6f90d0aa03 Reviewed-by: Alexandru Croitor --- tests/auto/widgets/qwebengineview/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/widgets/qwebengineview/BLACKLIST 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 -- cgit v1.2.3 From 95a22234a4671e6e79ce1cecbd720551a185d278 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 16 Nov 2016 13:46:56 +0100 Subject: ResourceType ABI/API fixup [ChangeLog][Important Changes] The enum value ResourceTypeUnknown has changed value since there was a mismatch between 5.6 and 5.7+ definitions. In general any unknown ResourceType value should handled as unknown for forward compatibility, since more types are and can be added in later Qt versions. Change-Id: I0a9f8a2129d4549deeae01e199f432fbbf1bbb9e Reviewed-by: Leena Miettinen Reviewed-by: Kai Koehne --- src/core/api/qwebengineurlrequestinfo.cpp | 5 ++++- src/core/api/qwebengineurlrequestinfo.h | 5 ++++- src/core/network_delegate_qt.cpp | 26 +++++++++++++++++++------- src/core/web_contents_delegate_qt.cpp | 2 +- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index f229a9748..93cdf012f 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -59,7 +59,7 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeFavicon, content::RESOU ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeXhr, content::RESOURCE_TYPE_XHR) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePing, content::RESOURCE_TYPE_PING) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker, content::RESOURCE_TYPE_SERVICE_WORKER) -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) @@ -166,6 +166,9 @@ QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPriva \value ResourceTypePing A ping request for . \value ResourceTypeServiceWorker The main resource of a service worker. \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 9a13b3faf..c7af45375 100644 --- a/src/core/api/qwebengineurlrequestinfo.h +++ b/src/core/api/qwebengineurlrequestinfo.h @@ -70,7 +70,10 @@ public: ResourceTypeXhr, // a XMLHttpRequest ResourceTypePing, // a ping request for ResourceTypeServiceWorker, // the main resource of a service worker. - ResourceTypeUnknown +#ifndef Q_QDOC + ResourceTypeLast, +#endif + ResourceTypeUnknown = 255 }; enum NavigationType { diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index fd79917f4..e14180ae6 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -55,7 +55,7 @@ namespace QtWebEngineCore { -int pageTransitionToNavigationType(ui::PageTransition transition) +WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition) { int32 qualifier = ui::PageTransitionGetQualifier(transition); @@ -78,6 +78,18 @@ int pageTransitionToNavigationType(ui::PageTransition transition) } } +QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType) +{ + if (resourceType >= 0 && resourceType < content::ResourceType(QWebEngineUrlRequestInfo::ResourceTypeLast)) + return static_cast(resourceType); + return QWebEngineUrlRequestInfo::ResourceTypeUnknown; +} + +QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType) +{ + return static_cast(navigationType); +} + NetworkDelegateQt::NetworkDelegateQt(URLRequestContextGetterQt *requestContext) : m_requestContextGetter(requestContext) { @@ -91,7 +103,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(); @@ -102,11 +114,11 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C QWebEngineUrlRequestInterceptor* interceptor = m_requestContextGetter->m_requestInterceptor; if (interceptor) { - QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(static_cast(resourceType) - , static_cast(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/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 5e9157069..95a66f622 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -393,7 +393,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) { -- cgit v1.2.3 From 6766290699acd0d73c81cf690012d52729e518b9 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 24 Nov 2016 10:58:43 +0100 Subject: Increase timeout in loadSignalsOrder tests Use a standard QTRY_VERIFY. Apparently launching the web-process might sometimes take more than 500ms on the CI under load. Task-number: QTBUG-57119 Change-Id: Icb7706b5aed3cf72f026af6d1d2f9430c4942a2a Reviewed-by: Peter Varga Reviewed-by: Joerg Bornemann --- tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 518713b51..1629ec617 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -3410,7 +3410,7 @@ void tst_QWebEnginePage::loadSignalsOrder() SpyForLoadSignalsOrder loadSpy(&page); waitForSignal(&loadSpy, SIGNAL(started()), 500); page.load(url); - QTRY_VERIFY_WITH_TIMEOUT(loadSpy.isFinished(), 500); + QTRY_VERIFY(loadSpy.isFinished()); } void tst_QWebEnginePage::undoActionHaveCustomText() -- cgit v1.2.3 From 41eddfaa4af8aba3820c8401993600e83633f9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Br=C3=BCning?= Date: Wed, 21 Sep 2016 18:02:51 +0200 Subject: Move the QPrinter and QtWidgets related code out of the PDFium wrapper This moves the actual printing using QPrinter to the WebEngineWidgets part of the API. The printsupport module depends on the widgets module and therefore QtWebEngineCore also had a dependency to widgets. This is removed by this change. Change-Id: If6e5745709a59de18f2123b930cbe6e64390c867 Reviewed-by: Michal Klocek --- src/core/config/common.pri | 2 - src/core/config/desktop_linux.pri | 2 + src/core/config/mac_osx.pri | 2 + src/core/config/windows.pri | 2 + src/core/core_common.pri | 1 - src/core/core_gyp_generator.pro | 7 +- src/core/pdfium_document_wrapper_qt.cpp | 172 +++++++++++++++ src/core/pdfium_document_wrapper_qt.h | 71 +++++++ src/core/pdfium_printing_wrapper_qt.cpp | 235 --------------------- src/core/pdfium_printing_wrapper_qt.h | 66 ------ src/core/web_contents_adapter.cpp | 40 +--- src/core/web_contents_adapter.h | 9 +- src/core/web_contents_adapter_client.h | 3 - src/webengine/api/qquickwebengineview.cpp | 10 + src/webengine/api/qquickwebengineview_p_p.h | 3 - src/webengine/webengine.pro | 4 + src/webenginewidgets/api/qwebenginepage.cpp | 151 ++++++++++++- src/webenginewidgets/api/qwebenginepage_p.h | 6 +- src/webenginewidgets/webenginewidgets.pro | 7 + .../auto/widgets/qwebenginepage/qwebenginepage.pro | 2 + .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 4 + tools/qmake/mkspecs/features/configure.prf | 3 + 22 files changed, 433 insertions(+), 369 deletions(-) create mode 100644 src/core/pdfium_document_wrapper_qt.cpp create mode 100644 src/core/pdfium_document_wrapper_qt.h delete mode 100644 src/core/pdfium_printing_wrapper_qt.cpp delete mode 100644 src/core/pdfium_printing_wrapper_qt.h 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 5b9551b5a..7f87e885d 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 81dea855a..a09683ba6 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -75,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 \ @@ -155,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 \ @@ -211,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/pdfium_document_wrapper_qt.cpp b/src/core/pdfium_document_wrapper_qt.cpp new file mode 100644 index 000000000..7c43c77db --- /dev/null +++ b/src/core/pdfium_document_wrapper_qt.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#if defined (ENABLE_PDF) +#include "pdfium_document_wrapper_qt.h" + +#include +#include +#include + +#include "third_party/pdfium/public/fpdf_doc.h" +#include "third_party/pdfium/public/fpdfview.h" + +namespace QtWebEngineCore { +int PdfiumDocumentWrapperQt::m_libraryUsers = 0; + +class QWEBENGINE_EXPORT PdfiumPageWrapperQt { +public: + 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)) + , m_index(pageIndex) + , m_image(createImage(targetWidth, targetHeight)) + { + } + + PdfiumPageWrapperQt() + : m_pageData(nullptr) + , m_width(-1) + , m_height(-1) + , m_index(-1) + , m_image(QImage()) + { + } + + virtual ~PdfiumPageWrapperQt() + { + FPDF_ClosePage(m_pageData); + } + + QImage image() + { + return m_image; + } + +private: + QImage createImage(int targetWidth, int targetHeight) + { + Q_ASSERT(m_pageData); + if (targetWidth <= 0) + targetWidth = m_width; + + if (targetHeight <= 0) + targetHeight = m_height; + + QImage image(targetWidth, targetHeight, QImage::Format_RGBA8888); + Q_ASSERT(!image.isNull()); + image.fill(0xFFFFFFFF); + + FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(image.width(), image.height(), + FPDFBitmap_BGRA, + image.scanLine(0), image.bytesPerLine()); + Q_ASSERT(bitmap); + + FPDF_RenderPageBitmap(bitmap, m_pageData, + 0, 0, image.width(), image.height(), + 0, 0); + FPDFBitmap_Destroy(bitmap); + bitmap = nullptr; + + // Map BGRA to RGBA as PDFium currently does not support RGBA bitmaps directly + for (int i = 0; i < image.height(); i++) { + uchar *pixels = image.scanLine(i); + for (int j = 0; j < image.width(); j++) { + qSwap(pixels[0], pixels[2]); + pixels += 4; + } + } + return image; + } + +private: + void *m_pageData; + int m_width; + int m_height; + int m_index; + QImage m_image; +}; + + +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(); + + m_documentHandle = FPDF_LoadMemDocument(pdfData, static_cast(size), password); + m_pageCount = FPDF_GetPageCount(m_documentHandle); +} + +QImage PdfiumDocumentWrapperQt::pageAsQImage(size_t index) +{ + if (!m_documentHandle || !m_pageCount) { + qWarning("Failure to generate QImage from invalid or empty PDF document."); + return QImage(); + } + + if (static_cast(index) >= m_pageCount) { + qWarning("Failure to generate QImage from PDF data: index out of bounds."); + return QImage(); + } + + 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); + } + + return pageWrapper->image(); +} + +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_document_wrapper_qt.h b/src/core/pdfium_document_wrapper_qt.h new file mode 100644 index 000000000..42ac94a28 --- /dev/null +++ b/src/core/pdfium_document_wrapper_qt.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef PDFIUM_DOCUMENT_WRAPPER_QT_H +#define PDFIUM_DOCUMENT_WRAPPER_QT_H + +#if defined(ENABLE_PDF) +#include "qtwebenginecoreglobal.h" + +#include +#include +#include + +namespace QtWebEngineCore { +class PdfiumPageWrapperQt; + +class QWEBENGINE_EXPORT PdfiumDocumentWrapperQt +{ +public: + 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; + int m_pageCount; + void *m_documentHandle; + QSize m_imageSize; + QHash m_cachedPages; +}; + +} // namespace QtWebEngineCore +#endif // defined (ENABLE_PDF) +#endif // PDFIUM_DOCUMENT_WRAPPER_QT_H diff --git a/src/core/pdfium_printing_wrapper_qt.cpp b/src/core/pdfium_printing_wrapper_qt.cpp deleted file mode 100644 index fceb381af..000000000 --- a/src/core/pdfium_printing_wrapper_qt.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/**************************************************************************** -** -** 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 "pdfium_printing_wrapper_qt.h" - -#include -#include -#include -#include - -#include "third_party/pdfium/public/fpdf_doc.h" -#include "third_party/pdfium/public/fpdfview.h" - -namespace QtWebEngineCore { -int PdfiumPrintingWrapperQt::m_libraryUsers = 0; - -class PDFiumPageWrapper { -public: - PDFiumPageWrapper(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)) - , m_index(pageIndex) - , m_image(createImage(targetWidth, targetHeight)) - { - } - - PDFiumPageWrapper() - : m_pageData(nullptr) - , m_width(-1) - , m_height(-1) - , m_index(-1) - , m_image(QImage()) - { - } - - virtual ~PDFiumPageWrapper() - { - FPDF_ClosePage(m_pageData); - } - - QImage image() - { - return m_image; - } - -private: - QImage createImage(int targetWidth, int targetHeight) - { - Q_ASSERT(m_pageData); - if (targetWidth <= 0) - targetWidth = m_width; - - if (targetHeight <= 0) - targetHeight = m_height; - - QImage image(targetWidth, targetHeight, QImage::Format_RGBA8888); - Q_ASSERT(!image.isNull()); - image.fill(0xFFFFFFFF); - - FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(image.width(), image.height(), - FPDFBitmap_BGRA, - image.scanLine(0), image.bytesPerLine()); - Q_ASSERT(bitmap); - - FPDF_RenderPageBitmap(bitmap, m_pageData, - 0, 0, image.width(), image.height(), - 0, 0); - FPDFBitmap_Destroy(bitmap); - bitmap = nullptr; - - // Map BGRA to RGBA as PDFium currently does not support RGBA bitmaps directly - for (int i = 0; i < image.height(); i++) { - uchar *pixels = image.scanLine(i); - for (int j = 0; j < image.width(); j++) { - qSwap(pixels[0], pixels[2]); - pixels += 4; - } - } - return image; - } - -private: - void *m_pageData; - int m_width; - int m_height; - int m_index; - QImage m_image; -}; - - -PdfiumPrintingWrapperQt::PdfiumPrintingWrapperQt(const void *pdfData, size_t size, const char *password) -{ - Q_ASSERT(pdfData); - Q_ASSERT(size); - if (m_libraryUsers++ == 0) - FPDF_InitLibrary(); - - m_documentHandle = FPDF_LoadMemDocument(pdfData, static_cast(size), password); - m_pageCount = FPDF_GetPageCount(m_documentHandle); -} - -bool PdfiumPrintingWrapperQt::printOnPrinter(QPrinter &printer) -{ - 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; - } - fromPage = qMax(1, fromPage); - toPage = qMin(m_pageCount, toPage); - - if (printer.pageOrder() == QPrinter::LastPageFirst) { - qSwap(fromPage, toPage); - ascendingOrder = false; - } - - int documentCopies = printer.copyCount(); - int pageCopies = 1; - if (printer.collateCopies()) { - pageCopies = documentCopies; - documentCopies = 1; - } - - 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 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; -} - -PdfiumPrintingWrapperQt::~PdfiumPrintingWrapperQt() -{ - FPDF_CloseDocument(m_documentHandle); - if (--m_libraryUsers == 0) - FPDF_DestroyLibrary(); -} - -} diff --git a/src/core/pdfium_printing_wrapper_qt.h b/src/core/pdfium_printing_wrapper_qt.h deleted file mode 100644 index 3aaf2b461..000000000 --- a/src/core/pdfium_printing_wrapper_qt.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef PDFIUM_PRINTING_WRAPPER_QT_H -#define PDFIUM_PRINTING_WRAPPER_QT_H - -#include - -QT_BEGIN_NAMESPACE -class QPrinter; -QT_END_NAMESPACE - -namespace QtWebEngineCore { - -class PdfiumPrintingWrapperQt -{ -public: - PdfiumPrintingWrapperQt(const void *pdfData, size_t size, const char *password = nullptr); - virtual ~PdfiumPrintingWrapperQt(); - bool printOnPrinter(QPrinter &printer); - int pageCount() const { return m_pageCount; } - -private: - static int m_libraryUsers; - void *m_documentHandle; - int m_pageCount; -}; - -} // namespace QtWebEngineCore -#endif // PDFIUM_PRINTING_WRAPPER_QT_H 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 #include #include -#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) -#include -#endif // QT_NO_PRINTER #include namespace QtWebEngineCore { @@ -188,21 +185,9 @@ static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint6 static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, int requestId, const std::vector& 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 &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/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 6ca9954cf..3830a3ea2 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -1302,16 +1302,19 @@ 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(pageSizeId)); QPageLayout::Orientation layoutOrientation = static_cast(orientation); QPageLayout pageLayout(layoutSize, layoutOrientation, QMarginsF(0.0, 0.0, 0.0, 0.0)); d->adapter->printToPDF(pageLayout, filePath); +#endif } void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId pageSizeId, PrintedPageOrientation orientation) { +#if defined (ENABLE_PDF) Q_D(QQuickWebEngineView); QPageSize layoutSize(static_cast(pageSizeId)); QPageLayout::Orientation layoutOrientation = static_cast(orientation); @@ -1322,6 +1325,13 @@ void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout); d->m_callbacks.insert(requestId, callback); +#else + // 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_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) Q_DECL_OVERRIDE; 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/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 0188cfef8..0b15731cf 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 #include #include +#ifndef QT_NO_PRINTER +#include +#endif #include #include #include @@ -92,6 +96,83 @@ 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 documentCopies = printer.copyCount(); + int pageCopies = 1; + 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 +223,9 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) , fullscreenMode(false) , webChannel(nullptr) , webChannelWorldId(QWebEngineScript::MainWorld) +#ifndef QT_NO_PRINTER + , currentPrinter(nullptr) +#endif { memset(actions, 0, sizeof(actions)); } @@ -389,15 +473,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) { @@ -1844,8 +1940,20 @@ 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); +#endif // if defined(ENABLE_PDF) } @@ -1863,8 +1971,23 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &page void QWebEnginePage::printToPdf(const QWebEngineCallback &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) + d->m_callbacks.invokeEmpty(resultCallback); +#endif // if defined(ENABLE_PDF) } #ifndef QT_NO_PRINTER @@ -1884,8 +2007,22 @@ void QWebEnginePage::printToPdf(const QWebEngineCallback &res void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback &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) + 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) 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/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/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 0b6354cc2..1377c9a52 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -4895,6 +4895,9 @@ void tst_QWebEnginePage::setZoomFactor() 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,6 +4925,7 @@ void tst_QWebEnginePage::printToPdf() CallbackSpy failedInvalidLayoutSpy; page.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout()); QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0); +#endif } void tst_QWebEnginePage::mouseButtonTranslation() 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 -- cgit v1.2.3 From 5bd02ef363a7fcfdb0c34dcd75938c54163bf10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Br=C3=BCning?= Date: Thu, 24 Nov 2016 11:47:53 +0100 Subject: Fix multiple copy handling while printing Both the printer code and the webengine printing code were producing the number of requested copies. So if n copies were requested, n*n copies of the document were printed. Task-number: QTBUG-56722 Change-Id: I34bce2d61041e1234139139dcd70b7b3d1c7cd7b Reviewed-by: Allan Sandfeld Jensen --- src/webenginewidgets/api/qwebenginepage.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 0b15731cf..f769ea0f4 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -119,8 +119,12 @@ static bool printPdfDataOnPrinter(const QByteArray& data, QPrinter& printer) ascendingOrder = false; } - int documentCopies = printer.copyCount(); int pageCopies = 1; + int documentCopies = 1; + + if (!printer.supportsMultipleCopies()) + documentCopies = printer.copyCount(); + if (printer.collateCopies()) { pageCopies = documentCopies; documentCopies = 1; -- cgit v1.2.3 From 9894a46ced4e760a90b8e0508ca1452f5d2fd7ef Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Thu, 24 Nov 2016 15:02:34 +0100 Subject: Rework and fix loadVisuallyCommitted signal - Remove RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout message and use WebContentsObserver::DidFirstVisuallyNonEmptyPaint instead. - The order of the DidFirstVisuallyNonEmptyPaint and OnSwapCompositorFrame events is not guaranteed. Check for both events to do not miss to send any loadVisuallyCommitted signal. Change-Id: Ic733b3e9a6fae64b1d827e8e07514f180273cf8c Reviewed-by: Allan Sandfeld Jensen --- src/core/render_view_observer_host_qt.cpp | 9 --------- src/core/render_view_observer_host_qt.h | 1 - src/core/render_widget_host_view_qt.cpp | 13 +++++-------- src/core/render_widget_host_view_qt.h | 11 +++++++++-- src/core/renderer/render_view_observer_qt.cpp | 5 ----- src/core/renderer/render_view_observer_qt.h | 1 - src/core/web_contents_delegate_qt.cpp | 16 ++++++++++++++++ src/core/web_contents_delegate_qt.h | 1 + 8 files changed, 31 insertions(+), 26 deletions(-) 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(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 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/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 0f7808e51..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(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); 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 &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 &) ; -- cgit v1.2.3 From a79fd91391c489ea1cd7baf717778b75e4847b92 Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Thu, 24 Nov 2016 16:09:47 +0100 Subject: Fix DesktopWebEngineViewLinkHovered QML tests The linkHovered signal can be emitted only if the page is rendered. Waiting for rendering and for the UpdateTargetURL event may exceed the time limit so add wait for the rendering too. Task-number: QTBUG-55870 Change-Id: I3aa8e323a3bf8ff3f4a85c3de9efd3ab0f459f62 Reviewed-by: Allan Sandfeld Jensen --- tests/auto/quick/qmltests/BLACKLIST | 6 ------ tests/auto/quick/qmltests/data/tst_linkHovered.qml | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) 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..0b99ffa7f 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,6 +39,20 @@ TestWebEngineView { property string lastUrl + testSupport: WebEngineTestSupport { + property bool loadVisuallyCommittedSignalEmitted: false + + function waitForLoadVisuallyCommitted() { + return _waitFor(function() { + return testSupport.loadVisuallyCommittedSignalEmitted; + }); + } + + onLoadVisuallyCommitted: { + loadVisuallyCommittedSignalEmitted = true; + } + } + SignalSpy { id: spy target: webEngineView @@ -61,6 +76,7 @@ TestWebEngineView { } function init() { + webEngineView.testSupport.loadVisuallyCommittedSignalEmitted = false; webEngineView.lastUrl = "" spy.clear() } @@ -76,6 +92,9 @@ TestWebEngineView { compare(spy.count, 1) compare(webEngineView.lastUrl, "") + // Wait for the page to be rendered before trying to test based on input events + verify(webEngineView.testSupport.waitForLoadVisuallyCommitted()); + mouseMove(webEngineView, 100, 100) spy.wait() compare(spy.count, 2) @@ -96,6 +115,9 @@ TestWebEngineView { compare(spy.count, 1) compare(webEngineView.lastUrl, "") + // Wait for the page to be rendered before trying to test based on input events + verify(webEngineView.testSupport.waitForLoadVisuallyCommitted()); + for (var i = 0; i < 100; i += 10) mouseMove(webEngineView, 100, 100 + i) -- cgit v1.2.3 From 79649acb80e4bc1bc343dfeb70545400915eaa8e Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Tue, 15 Nov 2016 12:12:02 +0100 Subject: Doc: update platform notes Change-Id: I2482a570f7c22b5cff5ce217dbece1746441961e Reviewed-by: Kai Koehne --- src/webengine/doc/src/qtwebengine-platform-notes.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 -- cgit v1.2.3 From 01c029fd90162bdbbcf9534537f26138a333c570 Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Tue, 8 Nov 2016 10:34:31 +0100 Subject: Fix keyboard focus of RWHVQDW after popup Task-number: QTBUG-56652 Change-Id: I1a6655587a9104dd817332e2eb5f886c057d8f64 Reviewed-by: Allan Sandfeld Jensen --- .../render_widget_host_view_qt_delegate_widget.cpp | 7 +++ .../widgets/qwebengineview/tst_qwebengineview.cpp | 59 ++++++++++++++++++++++ tests/auto/widgets/tests.pri | 2 +- 3 files changed, 67 insertions(+), 1 deletion(-) 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 8c8e9fb71..27268d26b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -202,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/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 9966ad9ee..829f11586 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -31,8 +31,11 @@ #include #include #include +#include #include #include +#include +#include #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. @@ -1014,5 +1018,60 @@ void tst_QWebEngineView::keyboardEvents() QVERIFY(loadFinishedSpy.wait()); } +void tst_QWebEngineView::keyboardFocusAfterPopup() +{ + QScopedPointer 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("" + " " + ""); + + // Check whether the RenderWidgetHostView has the keyboard focus + QQuickWidget *rwhv = qobject_cast(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 -- cgit v1.2.3 From c0950098f3a7d4994ff07b06b8ff32e2a60ee7bf Mon Sep 17 00:00:00 2001 From: David Faure Date: Sun, 23 Oct 2016 20:22:52 +0200 Subject: Port autotests from own waitForSignal() to QSignalSpy::wait() I added QSignalSpy::wait() in Qt 5.0 exactly for this purpose. Change-Id: I895a92f5f7e4e8554e00f6668e6973cc2c903adf Reviewed-by: Peter Varga Reviewed-by: Allan Sandfeld Jensen --- .../tst_qwebengineurlrequestinterceptor.cpp | 16 ++--- .../tst_qquickwebengineview.cpp | 3 +- tests/auto/quick/shared/util.h | 32 ++------- .../tst_qwebengineaccessibility.cpp | 9 ++- .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 83 ++++++++++++++-------- .../qwebenginescript/tst_qwebenginescript.cpp | 27 ++++--- .../tst_qwebenginespellcheck.cpp | 7 +- .../widgets/qwebengineview/tst_qwebengineview.cpp | 32 +++++---- tests/auto/widgets/util.h | 23 ------ 9 files changed, 116 insertions(+), 116 deletions(-) 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/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(webEngineView->testSupport()), SIGNAL(loadVisuallyCommitted()), timeout); + QSignalSpy spy(reinterpret_cast(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() "" \ ""); 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() "" \ ""); 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() "
" \ ""); 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/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 1377c9a52..a35252081 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -490,7 +490,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 +662,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("

hello world

"); - 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 +681,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("

hello world

"); - 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 +699,8 @@ void tst_QWebEnginePage::userStyleSheetFromQrcUrl() m_page->settings()->setUserStyleSheetUrl(QUrl("qrc:///resources/user.css")); m_view->setHtml("

hello world

"); - 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 +727,12 @@ void tst_QWebEnginePage::modified() QSKIP("QWEBENGINEPAGE_ISMODIFIED"); #else m_page->setUrl(QUrl("data:text/html,blub")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); m_page->setUrl(QUrl("data:text/html,blah")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); QVERIFY(!m_page->isModified()); @@ -750,7 +756,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 +779,8 @@ void tst_QWebEnginePage::modified() m_page->setUrl(QUrl("data:text/html,This is fourth page")); QCOMPARE(m_page->history()->count(), 2); m_page->setUrl(QUrl("data:text/html,This is fifth page")); - QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebEngineFrame*,QWebEngineHistoryItem*)))); + QSignalSpy spy(m_page, &QWebEnginePage::saveFrameStateRequested); + QVERIFY(spy.wait()); #endif } @@ -2739,7 +2747,8 @@ void tst_QWebEnginePage::screenshot() QWebEnginePage* page = new QWebEnginePage; page->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); - ::waitForSignal(page, SIGNAL(loadFinished(bool)), 2000); + QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait(2000)); // take screenshot without a view takeScreenshot(page); @@ -2865,7 +2874,8 @@ void tst_QWebEnginePage::testStopScheduledPageRefresh() "" "

Page redirects immediately...

" ""); - 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 +3227,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 +3283,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,7 +3335,8 @@ 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(loadSpy.isFinished()); } @@ -3449,7 +3462,8 @@ void tst_QWebEnginePage::savePage() const QString urlPrefix = QStringLiteral("data:text/html,

"); 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 +3474,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); } @@ -3791,7 +3805,8 @@ void tst_QWebEnginePage::progressSignal() QUrl dataUrl("data:text/html,

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 +3827,14 @@ void tst_QWebEnginePage::urlChange() QUrl dataUrl("data:text/html,

Test"); m_view->setUrl(dataUrl); - ::waitForSignal(m_page, SIGNAL(urlChanged(QUrl))); + QVERIFY(urlSpy.wait()); QCOMPARE(urlSpy.size(), 1); QUrl dataUrl2("data:text/html,title

Test"); m_view->setUrl(dataUrl2); - ::waitForSignal(m_page, SIGNAL(urlChanged(QUrl))); + QVERIFY(urlSpy.wait()); QCOMPARE(urlSpy.size(), 2); } @@ -3922,7 +3937,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 +3947,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); @@ -4016,14 +4031,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 +4064,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 +4096,8 @@ void tst_QWebEnginePage::setHtmlWithJSAlert() QString html("

hello world

"); 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 +4277,9 @@ void tst_QWebEnginePage::scrollbarsOff() ""); - 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 +4345,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 +4460,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 +4621,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,7 +4822,8 @@ 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); } 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));\ ")); - 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;});\ ")); 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("")); - 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/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 829f11586..2baadd869 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -181,7 +181,8 @@ void tst_QWebEngineView::reusePage() page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); if (html.contains("")) { // 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(); @@ -285,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]")); @@ -404,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)); @@ -566,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); @@ -588,7 +592,7 @@ void tst_QWebEngineView::renderingAfterMaxAndBack() ""); view.page()->load(url2); - QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); + QVERIFY(spyFinished.wait()); view.showMaximized(); @@ -844,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())); } 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 @@ -41,29 +41,6 @@ #define TESTS_SOURCE_DIR "" #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 -- cgit v1.2.3 From a40688a63d131bb024e46d817a388011ccab3ca2 Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Tue, 29 Nov 2016 09:24:41 +0100 Subject: Wait for loadVisuallyCommitted signal with SignalSpy Change-Id: Ic200807246c5feb8e1f33215cbc6194b03765359 Reviewed-by: Allan Sandfeld Jensen --- src/webengine/api/qquickwebengineview.cpp | 2 +- src/webengine/api/qquickwebengineview_p.h | 6 ++- tests/auto/quick/qmltests/data/tst_linkHovered.qml | 56 ++++++++++------------ 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 3830a3ea2..547be2246 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 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/tests/auto/quick/qmltests/data/tst_linkHovered.qml b/tests/auto/quick/qmltests/data/tst_linkHovered.qml index 0b99ffa7f..362130bab 100644 --- a/tests/auto/quick/qmltests/data/tst_linkHovered.qml +++ b/tests/auto/quick/qmltests/data/tst_linkHovered.qml @@ -39,22 +39,16 @@ TestWebEngineView { property string lastUrl - testSupport: WebEngineTestSupport { - property bool loadVisuallyCommittedSignalEmitted: false + testSupport: WebEngineTestSupport { } - function waitForLoadVisuallyCommitted() { - return _waitFor(function() { - return testSupport.loadVisuallyCommittedSignalEmitted; - }); - } - - onLoadVisuallyCommitted: { - loadVisuallyCommittedSignalEmitted = true; - } + SignalSpy { + id: loadVisuallyCommittedSpy + target: webEngineView.testSupport + signalName: "loadVisuallyCommitted" } SignalSpy { - id: spy + id: linkHoveredSpy target: webEngineView signalName: "linkHovered" } @@ -76,60 +70,60 @@ TestWebEngineView { } function init() { - webEngineView.testSupport.loadVisuallyCommittedSignalEmitted = false; - 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 - verify(webEngineView.testSupport.waitForLoadVisuallyCommitted()); + 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 - verify(webEngineView.testSupport.waitForLoadVisuallyCommitted()); + 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, "") } } -- cgit v1.2.3 From 04bf324fe80a81359c3e8aa6d25d56374c3d19ff Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 28 Nov 2016 16:18:08 +0100 Subject: Add environment variable to set chromium flags It is not always possible to pass random flags to any QtWebEngine application, so we should allow another way of setting Chromium flags. Among other things this makes it easy to set flags when running auto tests. Change-Id: I7ffb3bf8c9ceafc7d6b1bd2ba135643a687e480f Reviewed-by: Alexandru Croitor --- src/core/web_engine_context.cpp | 43 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 227918d51..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 args; - Q_FOREACH (const QString& arg, appArgs) - args << arg.toUtf8(); - - QVector 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); -- cgit v1.2.3 From 16e3472de276d5f0d5bab9ef7d9aec1031d68d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Br=C3=BCning?= Date: Tue, 29 Nov 2016 10:46:50 +0100 Subject: Fix build with -no-opengl configured Qt Commit e2541ebdfadea0fe43baac748cfa9e07f3b57215 introduced an unguarded reference to QOpenGLContext. Guard it with the appropriate flags. Task-number: QTBUG-57374 Change-Id: Ic9f0cc3c99aabd52813d8b828f1a51ca6871d4b4 Reviewed-by: Allan Sandfeld Jensen --- src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp b/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp index bf3514f71..a39c0e483 100644 --- a/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp +++ b/src/webenginewidgets/api/qtwebenginewidgetsglobal.cpp @@ -49,10 +49,13 @@ namespace QtWebEngineCore QT_BEGIN_NAMESPACE +#ifndef QT_NO_OPENGL Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); +#endif static void initialize() { +#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()) { @@ -62,9 +65,9 @@ static void initialize() } return; } - //QCoreApplication is not yet instantiated, ensuring the call will be deferred qAddPreRoutine(QtWebEngineCore::initialize); +#endif // QT_NO_OPENGL } Q_CONSTRUCTOR_FUNCTION(initialize) -- cgit v1.2.3 From 000b58022c9f7b2d7af2d5c6fa8ca1609dc2a5bd Mon Sep 17 00:00:00 2001 From: Peter Varga Date: Mon, 28 Nov 2016 11:19:50 +0100 Subject: Fix build when PDF support is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrap unused parameters. Change-Id: Iac550783a55b3fc585db6f7b8241aa2ae89fdf2e Reviewed-by: Michael Brüning Reviewed-by: Allan Sandfeld Jensen --- src/webengine/api/qquickwebengineview.cpp | 7 +++++++ src/webenginewidgets/api/qwebenginepage.cpp | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 3830a3ea2..f5350f535 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -1309,6 +1309,10 @@ void QQuickWebEngineView::printToPdf(const QString& filePath, PrintedPageSizeId 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 } @@ -1326,6 +1330,9 @@ 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())); diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index f769ea0f4..16e9438c9 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -1957,6 +1957,9 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &page } #endif d->adapter->printToPDF(pageLayout, filePath); +#else + Q_UNUSED(filePath); + Q_UNUSED(pageLayout); #endif // if defined(ENABLE_PDF) } @@ -1990,6 +1993,7 @@ void QWebEnginePage::printToPdf(const QWebEngineCallback &res 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) } @@ -2025,6 +2029,7 @@ void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback &re 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) } -- cgit v1.2.3 From 265bbb01766ca06f64624f20b1396b6a68b59028 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 1 Dec 2016 10:51:46 +0100 Subject: Add changes file for 5.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Listing important changes and bug-fixes. Change-Id: Ief57951009b59dc0c0b861315b2dfa35543dd960 Reviewed-by: Michael Brüning Reviewed-by: Leena Miettinen --- dist/changes-5.8.0 | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 dist/changes-5.8.0 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. -- cgit v1.2.3 From bb85301877aa4599af75f3993af484fa8b957948 Mon Sep 17 00:00:00 2001 From: Szabolcs David Date: Tue, 22 Nov 2016 05:42:20 -0800 Subject: Ensure the deletion of testing pages If a test fails it may trigger an assert in debug mode because the delete wasn't performed. Move QWebEngine* objects to the stack or use QScopedPointers to avoid these assertion fails. Change-Id: Ic44c3fddc7cd9cf57a0e2d1c57e0a6fd99033e02 Reviewed-by: Peter Varga --- .../qwebenginehistory/tst_qwebenginehistory.cpp | 21 +- .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 229 +++++++++------------ 2 files changed, 108 insertions(+), 142 deletions(-) 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 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/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index a35252081..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("
" + view.setHtml(QString("" "
"), 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("test"), 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("test"), 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() @@ -1233,7 +1226,7 @@ void tst_QWebEnginePage::cursorMovements() #if !defined(QWEBENGINEPAGE_SELECTEDTEXT) QSKIP("QWEBENGINEPAGE_SELECTEDTEXT"); #else - CursorTrackedPage* page = new CursorTrackedPage; + QScopedPointer page(new CursorTrackedPage); QString content("

The quick brown fox

jumps over the lazy dog

May the source
be with you!

"); page->setHtml(content); @@ -1242,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=\".*\""); @@ -1423,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("

The quick brown fox

" \ "

jumps over the lazy dog

" \ "

May the source
be with you!

"); - 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); @@ -1530,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() @@ -1539,7 +1528,7 @@ void tst_QWebEnginePage::textEditing() #if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); #else - CursorTrackedPage* page = new CursorTrackedPage; + QScopedPointer page(new CursorTrackedPage); QString content("

The quick brown fox

" \ "

jumps over the lazy dog

" \ "

May the source
be with you!

"); @@ -1652,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 } @@ -1719,12 +1706,12 @@ void tst_QWebEnginePage::inputMethods() QFETCH(QString, viewType); QWebEnginePage* page = new QWebEnginePage; QObject* view = 0; - QObject* container = 0; + QScopedPointer 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); @@ -1736,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"); @@ -2404,8 +2391,6 @@ void tst_QWebEnginePage::inputMethods() QCOMPARE(inputValue2, QString("\n\nthird line")); // END - Newline test for textarea - - delete container; #endif } @@ -2744,23 +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)); - QSignalSpy spyFinished(m_view, &QWebEngineView::loadFinished); + 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 @@ -3425,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() @@ -3718,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); @@ -3739,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()); @@ -3747,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() @@ -3956,13 +3934,13 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() void tst_QWebEnginePage::asyncAndDelete() { - QWebEnginePage *page = new QWebEnginePage; + QScopedPointer page(new QWebEnginePage); CallbackSpy plainTextSpy; CallbackSpy 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()); @@ -4829,33 +4807,30 @@ void tst_QWebEnginePage::loadInSignalHandlers() 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() @@ -4869,33 +4844,33 @@ void tst_QWebEnginePage::toPlainTextLoadFinishedRace() { QFETCH(bool, enableErrorPage); - QWebEnginePage *page = new QWebEnginePage; + QScopedPointer 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"); @@ -4903,15 +4878,13 @@ 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() @@ -4951,10 +4924,10 @@ void tst_QWebEnginePage::printToPdf() 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( "