summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-07-21 11:32:35 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-08-10 09:15:57 +0000
commit41e1ac9e6e1f1d98a5901253e89d7b524d3cdf6b (patch)
tree670da9c340426fad3ddcd226ecfe4ba7e696792e
parent36ef2b73fb5b8ba75ec0926dc3ffde2f0487c5d5 (diff)
Return printToPdf to QWebEnginePage
It doesn't use QPrinter and can be done using QtGui classes only. Change-Id: I0e14563c1bb5e93d9803bb1a807f702b1a2a5315 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Kirill Burtsev <kirill.burtsev@qt.io> (cherry picked from commit b405ed26336a44ad4f359cdb4e1909e31c113cd4) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/core/api/qwebenginepage.cpp96
-rw-r--r--src/core/api/qwebenginepage.h12
-rw-r--r--src/core/api/qwebenginepage_p.h7
-rw-r--r--src/webenginewidgets/api/qwebengineview.cpp59
-rw-r--r--src/webenginewidgets/api/qwebengineview_p.h6
-rw-r--r--tests/auto/widgets/printing/tst_printing.cpp12
6 files changed, 130 insertions, 62 deletions
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp
index c17276a1f..17e138920 100644
--- a/src/core/api/qwebenginepage.cpp
+++ b/src/core/api/qwebenginepage.cpp
@@ -321,6 +321,8 @@ void QWebEnginePagePrivate::loadFinished(QWebEngineLoadingInfo info)
void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool success)
{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->pdfPrintingFinished(filePath, success);
if (view)
view->didPrintPageToPdf(filePath, success);
}
@@ -470,8 +472,28 @@ void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const Q
void QWebEnginePagePrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result)
{
+#if QT_CONFIG(webengine_printing_and_pdf)
+ Q_Q(QWebEnginePage);
+
+ // If no currentPrinter is set that means that were printing to PDF only.
+ if (!currentPrinter) {
+ if (!result.data())
+ return;
+ if (auto callback = m_pdfResultCallbacks.take(requestId))
+ callback(*(result.data()));
+ return;
+ }
+
if (view)
- view->didPrintPage(requestId, result);
+ view->didPrintPage(currentPrinter, result);
+ else
+ currentPrinter = nullptr;
+#else
+ // we should never enter this branch, but just for safe-keeping...
+ Q_UNUSED(result);
+ if (auto callback = m_pdfResultCallbacks.take(requestId))
+ callback(QByteArray());
+#endif
}
bool QWebEnginePagePrivate::passOnFocus(bool reverse)
@@ -1688,6 +1710,10 @@ void QWebEnginePagePrivate::setToolTip(const QString &toolTipText)
void QWebEnginePagePrivate::printRequested()
{
+ Q_Q(QWebEnginePage);
+ QTimer::singleShot(0, q, [q]() {
+ Q_EMIT q->printRequested();
+ });
if (view)
view->printRequested();
}
@@ -2234,6 +2260,74 @@ QSizeF QWebEnginePage::contentsSize() const
*/
/*!
+ \fn void QWebEnginePage::pdfPrintingFinished(const QString &filePath, bool success)
+
+ This signal is emitted when printing the web page into a PDF file has
+ finished.
+ \a filePath will contain the path the file was requested to be created
+ at, and \a success will be \c true if the file was successfully created and
+ \c false otherwise.
+
+ \sa printToPdf()
+*/
+
+/*!
+ Renders the current content of the page into a PDF document and saves it
+ in the location specified in \a filePath.
+ The page size and orientation of the produced PDF document are taken from
+ the values specified in \a pageLayout, while the range of pages printed is
+ taken from \a ranges with the default being printing all pages.
+
+ This method issues an asynchronous request for printing the web page into
+ a PDF and returns immediately.
+ To be informed about the result of the request, connect to the signal
+ pdfPrintingFinished().
+
+ If a file already exists at the provided file path, it will be overwritten.
+ \sa pdfPrintingFinished()
+*/
+void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &layout, const QPageRanges &ranges)
+{
+#if QT_CONFIG(webengine_printing_and_pdf)
+ Q_D(QWebEnginePage);
+ d->ensureInitialized();
+ d->adapter->printToPDF(layout, ranges, filePath);
+#else
+ Q_UNUSED(filePath);
+ Q_UNUSED(layout);
+ Q_UNUSED(ranges);
+#endif
+}
+
+/*!
+ Renders the current content of the page into a PDF document and returns a byte array containing the PDF data
+ as parameter to \a resultCallback.
+ The page size and orientation of the produced PDF document are taken from the values specified in \a pageLayout,
+ while the range of pages printed is taken from \a ranges with the default being printing all pages.
+
+ The \a resultCallback must take a const reference to a QByteArray as parameter. If printing was successful, this byte array
+ will contain the PDF data, otherwise, the byte array will be empty.
+
+ \warning We guarantee that the callback (\a resultCallback) is always called, but it might be done
+ during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid
+ value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it.
+*/
+void QWebEnginePage::printToPdf(const std::function<void(const QByteArray&)> &resultCallback, const QPageLayout &layout, const QPageRanges &ranges)
+{
+ Q_D(QWebEnginePage);
+#if QT_CONFIG(webengine_printing_and_pdf)
+ d->ensureInitialized();
+ quint64 requestId = d->adapter->printToPDFCallbackResult(layout, ranges);
+ d->m_pdfResultCallbacks.insert(requestId, resultCallback);
+#else
+ Q_UNUSED(layout);
+ Q_UNUSED(ranges);
+ if (resultCallback)
+ resultCallback(QByteArray());
+#endif
+}
+
+/*!
\internal
*/
void QWebEnginePage::acceptAsNewWindow(QWebEngineNewWindowRequest &request)
diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h
index 1bdcf6539..9f35cffeb 100644
--- a/src/core/api/qwebenginepage.h
+++ b/src/core/api/qwebenginepage.h
@@ -49,6 +49,8 @@
#include <QtCore/qurl.h>
#include <QtCore/qvariant.h>
#include <QtGui/qaction.h>
+#include <QtGui/qpagelayout.h>
+#include <QtGui/qpageranges.h>
#include <functional>
@@ -301,6 +303,13 @@ public:
bool recentlyAudible() const;
qint64 renderProcessPid() const;
+ void printToPdf(const QString &filePath,
+ const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()),
+ const QPageRanges &ranges = {});
+ void printToPdf(const std::function<void(const QByteArray&)> &resultCallback,
+ const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()),
+ const QPageRanges &ranges = {});
+
void setInspectedPage(QWebEnginePage *page);
QWebEnginePage *inspectedPage() const;
void setDevToolsPage(QWebEnginePage *page);
@@ -355,6 +364,9 @@ Q_SIGNALS:
void recentlyAudibleChanged(bool recentlyAudible);
void renderProcessPidChanged(qint64 pid);
+ void pdfPrintingFinished(const QString &filePath, bool success);
+ void printRequested();
+
void visibleChanged(bool visible);
void lifecycleStateChanged(LifecycleState state);
diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h
index f9eb2ad71..40b6ddd29 100644
--- a/src/core/api/qwebenginepage_p.h
+++ b/src/core/api/qwebenginepage_p.h
@@ -70,6 +70,7 @@ class WebContentsAdapter;
}
QT_BEGIN_NAMESPACE
+class QPrinter;
class QWebEngineFindTextResult;
class QWebEngineHistory;
class QWebEnginePage;
@@ -102,7 +103,7 @@ public:
virtual void unhandledKeyEvent(QKeyEvent *event) = 0;
virtual bool passOnFocus(bool reverse) = 0;
virtual QObject *accessibilityParentObject() = 0;
- virtual void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) = 0;
+ virtual void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) = 0;
virtual void didPrintPageToPdf(const QString &filePath, bool success) = 0;
virtual void printRequested() = 0;
};
@@ -222,9 +223,13 @@ public:
qreal defaultZoomFactor;
QTimer wasShownTimer;
QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget = nullptr;
+#if QT_CONFIG(webengine_printing_and_pdf)
+ QPrinter *currentPrinter = nullptr;
+#endif
mutable QMap<quint64, std::function<void(const QVariant &)>> m_variantCallbacks;
mutable QMap<quint64, std::function<void(const QString &)>> m_stringCallbacks;
+ QMap<quint64, std::function<void(const QByteArray&)>> m_pdfResultCallbacks;
mutable QAction *actions[QWebEnginePage::WebActionCount];
};
diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp
index aed80427c..d312fe70c 100644
--- a/src/webenginewidgets/api/qwebengineview.cpp
+++ b/src/webenginewidgets/api/qwebengineview.cpp
@@ -359,9 +359,6 @@ QWebEngineViewPrivate::QWebEngineViewPrivate()
, m_dragEntered(false)
, m_ownsPage(false)
, m_contextRequest(nullptr)
-#if QT_CONFIG(webengine_printing_and_pdf)
- , currentPrinter(nullptr)
-#endif
{
#ifndef QT_NO_ACCESSIBILITY
QAccessible::installFactory(&webAccessibleFactory);
@@ -512,19 +509,12 @@ QObject *QWebEngineViewPrivate::accessibilityParentObject()
return q;
}
-void QWebEngineViewPrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result)
+void QWebEngineViewPrivate::didPrintPage(QPrinter *&currentPrinter, QSharedPointer<QByteArray> result)
{
#if QT_CONFIG(webengine_printing_and_pdf)
Q_Q(QWebEngineView);
- // If no currentPrinter is set that means that were printing to PDF only.
- if (!currentPrinter) {
- if (!result.data())
- return;
- if (auto callback = m_pdfResultCallbacks.take(requestId))
- callback(*(result.data()));
- return;
- }
+ Q_ASSERT(currentPrinter);
QThread *printerThread = new QThread;
QObject::connect(printerThread, &QThread::finished, printerThread, &QThread::deleteLater);
@@ -536,7 +526,7 @@ void QWebEngineViewPrivate::didPrintPage(quint64 requestId, QSharedPointer<QByte
printerWorker->m_documentCopies = currentPrinter->copyCount();
printerWorker->m_collateCopies = currentPrinter->collateCopies();
- QObject::connect(printerWorker, &QtWebEngineCore::PrinterWorker::resultReady, q, [this, q](bool success) {
+ QObject::connect(printerWorker, &QtWebEngineCore::PrinterWorker::resultReady, q, [q, &currentPrinter](bool success) {
currentPrinter = nullptr;
Q_EMIT q->printFinished(success);
});
@@ -548,17 +538,15 @@ void QWebEngineViewPrivate::didPrintPage(quint64 requestId, QSharedPointer<QByte
QMetaObject::invokeMethod(printerWorker, "print");
#else
- // we should never enter this branch, but just for safe-keeping...
+ Q_UNUSED(currentPrinter);
Q_UNUSED(result);
- if (auto callback = m_pdfResultCallbacks.take(requestId))
- callback(QByteArray());
#endif
}
void QWebEngineViewPrivate::didPrintPageToPdf(const QString &filePath, bool success)
{
Q_Q(QWebEngineView);
- Q_EMIT q->pdfPrintingFinished(filePath, success);
+ Q_EMIT q->pdfPrintingFinished(filePath, success);
}
void QWebEngineViewPrivate::printRequested()
@@ -1000,19 +988,7 @@ QWebEngineContextMenuRequest *QWebEngineView::lastContextMenuRequest() const
*/
void QWebEngineView::printToPdf(const QString &filePath, const QPageLayout &layout, const QPageRanges &ranges)
{
-#if QT_CONFIG(webengine_printing_and_pdf)
- Q_D(QWebEngineView);
- if (d->currentPrinter) {
- qWarning("Cannot print to PDF while printing at the same time.");
- return;
- }
- page()->d_ptr->ensureInitialized();
- page()->d_ptr->adapter->printToPDF(layout, ranges, filePath);
-#else
- Q_UNUSED(filePath);
- Q_UNUSED(layout);
- Q_UNUSED(ranges);
-#endif
+ page()->printToPdf(filePath, layout, ranges);
}
/*!
@@ -1032,23 +1008,7 @@ void QWebEngineView::printToPdf(const QString &filePath, const QPageLayout &layo
*/
void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &resultCallback, const QPageLayout &layout, const QPageRanges &ranges)
{
- Q_D(QWebEngineView);
-#if QT_CONFIG(webengine_printing_and_pdf)
- if (d->currentPrinter) {
- qWarning("Cannot print to PDF while printing at the same time.");
- if (resultCallback)
- resultCallback(QByteArray());
- return;
- }
- page()->d_ptr->ensureInitialized();
- quint64 requestId = page()->d_ptr->adapter->printToPDFCallbackResult(layout, ranges);
- d->m_pdfResultCallbacks.insert(requestId, resultCallback);
-#else
- Q_UNUSED(layout);
- Q_UNUSED(ranges);
- if (resultCallback)
- resultCallback(QByteArray());
-#endif
+ page()->printToPdf(resultCallback, layout, ranges);
}
/*!
@@ -1093,13 +1053,12 @@ void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &re
void QWebEngineView::print(QPrinter *printer)
{
#if QT_CONFIG(webengine_printing_and_pdf)
- Q_D(QWebEngineView);
- if (d->currentPrinter) {
+ if (page()->d_ptr->currentPrinter) {
qWarning("Cannot print page on printer %ls: Already printing on a device.", qUtf16Printable(printer->printerName()));
return;
}
- d->currentPrinter = printer;
+ page()->d_ptr->currentPrinter = printer;
page()->d_ptr->ensureInitialized();
page()->d_ptr->adapter->printToPDFCallbackResult(printer->pageLayout(),
printer->pageRanges(),
diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h
index db22c95b5..13b346df9 100644
--- a/src/webenginewidgets/api/qwebengineview_p.h
+++ b/src/webenginewidgets/api/qwebengineview_p.h
@@ -94,7 +94,7 @@ public:
QWebEngineContextMenuRequest *lastContextMenuRequest() const override;
QWebEnginePage *createPageForWindow(QWebEnginePage::WebWindowType type) override;
QObject *accessibilityParentObject() override;
- void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) override;
+ void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) override;
void didPrintPageToPdf(const QString &filePath, bool success) override;
void printRequested() override;
@@ -114,10 +114,6 @@ public:
bool m_dragEntered;
mutable bool m_ownsPage;
QWebEngineContextMenuRequest *m_contextRequest;
-#if QT_CONFIG(webengine_printing_and_pdf)
- QPrinter *currentPrinter;
-#endif
- QMap<quint64, std::function<void(const QByteArray&)>> m_pdfResultCallbacks;
};
#ifndef QT_NO_ACCESSIBILITY
diff --git a/tests/auto/widgets/printing/tst_printing.cpp b/tests/auto/widgets/printing/tst_printing.cpp
index 3f1344ed4..0559fb787 100644
--- a/tests/auto/widgets/printing/tst_printing.cpp
+++ b/tests/auto/widgets/printing/tst_printing.cpp
@@ -58,10 +58,10 @@ void tst_Printing::printToPdfBasic()
view.load(QUrl("qrc:///resources/basic_printing_page.html"));
QTRY_VERIFY(spy.count() == 1);
- QSignalSpy savePdfSpy(&view, &QWebEngineView::pdfPrintingFinished);
+ QSignalSpy savePdfSpy(view.page(), &QWebEnginePage::pdfPrintingFinished);
QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0));
QString path = tempDir.path() + "/print_1_success.pdf";
- view.printToPdf(path, layout);
+ view.page()->printToPdf(path, layout);
QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal");
QList<QVariant> successArguments = savePdfSpy.takeFirst();
@@ -73,7 +73,7 @@ void tst_Printing::printToPdfBasic()
#else
path = tempDir.path() + "/print_|2_failed.pdf";
#endif
- view.printToPdf(path, QPageLayout());
+ view.page()->printToPdf(path, QPageLayout());
QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal");
QList<QVariant> failedArguments = savePdfSpy.takeFirst();
@@ -81,11 +81,11 @@ void tst_Printing::printToPdfBasic()
QVERIFY2(failedArguments.at(1).toBool() == false, "Printing to PDF file succeeded though it should fail");
CallbackSpy<QByteArray> successfulSpy;
- view.printToPdf(successfulSpy.ref(), layout);
+ view.page()->printToPdf(successfulSpy.ref(), layout);
QVERIFY(successfulSpy.waitForResult().length() > 0);
CallbackSpy<QByteArray> failedInvalidLayoutSpy;
- view.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout());
+ view.page()->printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout());
QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0);
}
@@ -95,6 +95,7 @@ void tst_Printing::printRequest()
QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0));
QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished);
QSignalSpy printRequestedSpy(&view, &QWebEngineView::printRequested);
+ QSignalSpy printRequestedSpy2(view.page(), &QWebEnginePage::printRequested);
QSignalSpy savePdfSpy(&view, &QWebEngineView::pdfPrintingFinished);
CallbackSpy<QByteArray> resultSpy;
@@ -102,6 +103,7 @@ void tst_Printing::printRequest()
QTRY_VERIFY(loadFinishedSpy.count() == 1);
view.page()->runJavaScript("window.print()");
QTRY_VERIFY(printRequestedSpy.count() == 1);
+ QVERIFY(printRequestedSpy2.count() == 1);
//check if printing still works
view.printToPdf(resultSpy.ref(), layout);
const QByteArray data = resultSpy.waitForResult();