diff options
| -rw-r--r-- | src/core/api/qwebenginepage.cpp | 13 | ||||
| -rw-r--r-- | src/core/api/qwebenginepage_p.h | 4 | ||||
| -rw-r--r-- | src/core/printing/printer_worker.cpp | 6 | ||||
| -rw-r--r-- | src/webenginewidgets/api/qwebengineview.cpp | 9 | ||||
| -rw-r--r-- | src/webenginewidgets/api/qwebengineview_p.h | 2 | ||||
| -rw-r--r-- | tests/auto/widgets/printing/tst_printing.cpp | 54 |
6 files changed, 78 insertions, 10 deletions
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp index 8b1a1d968..9dfa1dbaf 100644 --- a/src/core/api/qwebenginepage.cpp +++ b/src/core/api/qwebenginepage.cpp @@ -52,6 +52,7 @@ #include <QMimeData> #include <QtCore/QPointer> #include <QRect> +#include <QThread> #include <QTimer> #include <QUrl> #include <QVariant> @@ -131,6 +132,10 @@ QWebEnginePagePrivate::~QWebEnginePagePrivate() { delete history; delete settings; +#if QT_CONFIG(webengine_printing_and_pdf) + if (printerThread) + printerThread->requestInterruption(); +#endif profile->d_ptr->removeWebContentsAdapterClient(this); } @@ -539,10 +544,12 @@ void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const Q void QWebEnginePagePrivate::didPrintPage(QSharedPointer<QByteArray> result) { #if QT_CONFIG(webengine_printing_and_pdf) + Q_Q(QWebEnginePage); Q_ASSERT(currentPrinter); - if (view) - view->didPrintPage(currentPrinter, result); - else + if (view) { + printerThread = view->didPrintPage(currentPrinter, result); + QObject::connect(printerThread, &QThread::finished, q, [this]() { printerThread = nullptr; }); + } else currentPrinter = nullptr; #else // should not get here diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h index ba1fbc6d5..917b8aaa0 100644 --- a/src/core/api/qwebenginepage_p.h +++ b/src/core/api/qwebenginepage_p.h @@ -38,6 +38,7 @@ class WebContentsAdapter; QT_BEGIN_NAMESPACE class QPrinter; +class QThread; class QWebEngineFindTextResult; class QWebEngineHistory; class QWebEnginePage; @@ -72,7 +73,7 @@ public: virtual void unhandledKeyEvent(QKeyEvent *event) = 0; virtual bool passOnFocus(bool reverse) = 0; virtual QObject *accessibilityParentObject() = 0; - virtual void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) = 0; + virtual QThread *didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) = 0; virtual void didPrintPageToPdf(const QString &filePath, bool success) = 0; virtual void printRequested() = 0; virtual void printRequestedByFrame(QWebEngineFrame frame) = 0; @@ -220,6 +221,7 @@ public: QtWebEngineCore::RenderWidgetHostViewQtDelegateItem *delegateItem = nullptr; #if QT_CONFIG(webengine_printing_and_pdf) QPrinter *currentPrinter = nullptr; + QThread *printerThread = nullptr; #endif mutable QMap<quint64, std::function<void(const QString &)>> m_stringCallbacks; diff --git a/src/core/printing/printer_worker.cpp b/src/core/printing/printer_worker.cpp index 564865386..53b1b7b0f 100644 --- a/src/core/printing/printer_worker.cpp +++ b/src/core/printing/printer_worker.cpp @@ -8,6 +8,7 @@ #include <QPainter> #include <QPagedPaintDevice> +#include <QThread> namespace QtWebEngineCore { @@ -89,6 +90,11 @@ void PrinterWorker::print() m_device->newPage(); for (int printedPages = 0; printedPages < pageCopies; printedPages++) { + // The page being printed requests interruption when it is destroyed; this lets + // us return early and avoid doing extra work in the background. + if (QThread::currentThread()->isInterruptionRequested()) + return finish(false); + if (printedPages > 0) m_device->newPage(); diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 9745654ac..8857e5336 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -849,7 +849,7 @@ QObject *QWebEngineViewPrivate::accessibilityParentObject() return q; } -void QWebEngineViewPrivate::didPrintPage(QPrinter *¤tPrinter, QSharedPointer<QByteArray> result) +QThread* QWebEngineViewPrivate::didPrintPage(QPrinter *¤tPrinter, QSharedPointer<QByteArray> result) { #if QT_CONFIG(webengine_printing_and_pdf) Q_Q(QWebEngineView); @@ -881,9 +881,11 @@ void QWebEngineViewPrivate::didPrintPage(QPrinter *¤tPrinter, QSharedPoint printerWorker->moveToThread(printerThread); QMetaObject::invokeMethod(printerWorker, "print"); + return printerThread; #else Q_UNUSED(currentPrinter); Q_UNUSED(result); + return nullptr; #endif } @@ -1479,13 +1481,16 @@ void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &re /*! Renders the current content of the page into a temporary PDF document, then prints it using \a printer. + The settings for creating and printing the PDF document will be retrieved from the \a printer object. When finished the signal printFinished() is emitted with the \c true for success or \c false for failure. It is the user's responsibility to ensure the \a printer remains valid until printFinished() - has been emitted. + has been emitted. If the page is destroyed before printFinished() is emitted, printing will + continue to run in the background for a short while. Users should ensure the printer remains + valid until its state is no longer active. \note Printing runs on the browser process, which is by default not sandboxed. diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index 27ad6db71..900210c64 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -71,7 +71,7 @@ public: QWebEngineContextMenuRequest *lastContextMenuRequest() const override; QWebEnginePage *createPageForWindow(QWebEnginePage::WebWindowType type) override; QObject *accessibilityParentObject() override; - void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) override; + QThread *didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) override; void didPrintPageToPdf(const QString &filePath, bool success) override; void printRequested() override; void printRequestedByFrame(QWebEngineFrame frame) override; diff --git a/tests/auto/widgets/printing/tst_printing.cpp b/tests/auto/widgets/printing/tst_printing.cpp index 58ad8a59c..1fcdae1b0 100644 --- a/tests/auto/widgets/printing/tst_printing.cpp +++ b/tests/auto/widgets/printing/tst_printing.cpp @@ -2,11 +2,14 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtWebEngineCore/qtwebenginecore-config.h> -#include <QWebEngineSettings> -#include <QWebEngineView> + +#include <QPrinter> +#include <QSignalSpy> #include <QTemporaryDir> #include <QTest> -#include <QSignalSpy> +#include <QWebEngineSettings> +#include <QWebEngineView> + #include <util.h> #ifdef QTPDF_SUPPORT @@ -26,6 +29,8 @@ private slots: void printHeaderAndFooter_data(); void printHeaderAndFooter(); void interruptPrinting(); + void printOnQPrinterBasic(); + void interruptPrintingOnQPrinter(); }; void tst_Printing::printToPdfBasic() @@ -252,5 +257,48 @@ void tst_Printing::interruptPrinting() view.page()->triggerAction(QWebEnginePage::Stop); } +void tst_Printing::printOnQPrinterBasic() +{ + QWebEngineView view; + loadSync(view.page(), QUrl("qrc:///resources/basic_printing_page.html")); + + QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); + QVERIFY(tempDir.isValid()); + + QPrinter printer; + printer.setOutputFileName(tempDir.path() + "/file.pdf"); + QVERIFY(printer.isValid()); + QCOMPARE(printer.outputFormat(), QPrinter::PdfFormat); + + QSignalSpy printSpy(&view, &QWebEngineView::printFinished); + view.print(&printer); + QTRY_VERIFY(printSpy.size() == 1); + QVERIFY(printSpy.takeFirst().takeFirst().toBool()); +} + +void tst_Printing::interruptPrintingOnQPrinter() +{ + QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); + QVERIFY(tempDir.isValid()); + + QPrinter printer; + printer.setOutputFileName(tempDir.path() + "/file.pdf"); + printer.setCopyCount(100000); + QVERIFY(printer.isValid()); + QCOMPARE(printer.outputFormat(), QPrinter::PdfFormat); + + { + QWebEngineView view; + loadSync(view.page(), QUrl("qrc:///resources/basic_printing_page.html")); + view.print(&printer); + QTRY_COMPARE(printer.printerState(), QPrinter::Active); + QTRY_COMPARE(printer.paintingActive(), true); + // Destroying the view here should interrupt immediately instead of waiting for all + // pages to print. + } + + QTRY_COMPARE(printer.printerState(), QPrinter::Idle); +} + QTEST_MAIN(tst_Printing) #include "tst_printing.moc" |
