diff options
-rw-r--r-- | examples/webenginewidgets/html2pdf/html2pdf.cpp | 14 | ||||
-rw-r--r-- | examples/webenginewidgets/printme/printhandler.cpp | 4 | ||||
-rw-r--r-- | src/core/api/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/core/api/qwebenginepage.cpp | 186 | ||||
-rw-r--r-- | src/core/api/qwebenginepage.h | 8 | ||||
-rw-r--r-- | src/core/api/qwebenginepage_p.h | 6 | ||||
-rw-r--r-- | src/core/printing/printer_worker.cpp | 52 | ||||
-rw-r--r-- | src/core/printing/printer_worker.h | 13 | ||||
-rw-r--r-- | src/webenginewidgets/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview.cpp | 126 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview.h | 7 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview_p.h | 8 | ||||
-rw-r--r-- | tests/auto/widgets/printing/tst_printing.cpp | 42 |
13 files changed, 215 insertions, 262 deletions
diff --git a/examples/webenginewidgets/html2pdf/html2pdf.cpp b/examples/webenginewidgets/html2pdf/html2pdf.cpp index e9fc69534..1b52d69b1 100644 --- a/examples/webenginewidgets/html2pdf/html2pdf.cpp +++ b/examples/webenginewidgets/html2pdf/html2pdf.cpp @@ -52,7 +52,7 @@ #include <QCommandLineParser> #include <QFile> #include <QTextStream> -#include <QWebEnginePage> +#include <QWebEngineView> #include <functional> @@ -73,23 +73,23 @@ private slots: private: QString m_inputPath; QString m_outputPath; - QScopedPointer<QWebEnginePage> m_page; + QScopedPointer<QWebEngineView> m_view; }; Html2PdfConverter::Html2PdfConverter(QString inputPath, QString outputPath) : m_inputPath(move(inputPath)) , m_outputPath(move(outputPath)) - , m_page(new QWebEnginePage) + , m_view(new QWebEngineView) { - connect(m_page.data(), &QWebEnginePage::loadFinished, + connect(m_view.data(), &QWebEngineView::loadFinished, this, &Html2PdfConverter::loadFinished); - connect(m_page.data(), &QWebEnginePage::pdfPrintingFinished, + connect(m_view.data(), &QWebEngineView::pdfPrintingFinished, this, &Html2PdfConverter::pdfPrintingFinished); } int Html2PdfConverter::run() { - m_page->load(QUrl::fromUserInput(m_inputPath)); + m_view->load(QUrl::fromUserInput(m_inputPath)); return QApplication::exec(); } @@ -102,7 +102,7 @@ void Html2PdfConverter::loadFinished(bool ok) return; } - m_page->printToPdf(m_outputPath); + m_view->printToPdf(m_outputPath); } void Html2PdfConverter::pdfPrintingFinished(const QString &filePath, bool success) diff --git a/examples/webenginewidgets/printme/printhandler.cpp b/examples/webenginewidgets/printme/printhandler.cpp index 3534c155b..58114a610 100644 --- a/examples/webenginewidgets/printme/printhandler.cpp +++ b/examples/webenginewidgets/printme/printhandler.cpp @@ -66,7 +66,7 @@ void PrintHandler::setView(QWebEngineView *view) { Q_ASSERT(!m_view); m_view = view; - connect(view->page(), &QWebEnginePage::printRequested, this, &PrintHandler::printPreview); + connect(view, &QWebEngineView::printRequested, this, &PrintHandler::printPreview); } void PrintHandler::print() @@ -83,7 +83,7 @@ void PrintHandler::printDocument(QPrinter *printer) QEventLoop loop; bool result; auto printPreview = [&](bool success) { result = success; loop.quit(); }; - m_view->page()->print(printer, std::move(printPreview)); + m_view->print(printer, std::move(printPreview)); loop.exec(); if (!result) { QPainter painter; diff --git a/src/core/api/CMakeLists.txt b/src/core/api/CMakeLists.txt index bf2008ebd..4074bdb51 100644 --- a/src/core/api/CMakeLists.txt +++ b/src/core/api/CMakeLists.txt @@ -2,7 +2,7 @@ if(NOT DEFINED WEBENGINE_ROOT_SOURCE_DIR) get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../.." REALPATH) endif() find_package(Qt6 ${PROJECT_VERSION} REQUIRED COMPONENTS Gui Network OpenGL Quick) -find_package(Qt6 ${PROJECT_VERSION} QUIET OPTIONAL_COMPONENTS PrintSupport WebChannel Positioning) +find_package(Qt6 ${PROJECT_VERSION} QUIET OPTIONAL_COMPONENTS WebChannel Positioning) include(${WEBENGINE_ROOT_SOURCE_DIR}/cmake/Functions.cmake) get_configure_mode(configureMode) @@ -65,10 +65,6 @@ qt_skip_warnings_are_errors(WebEngineCore) make_install_only(WebEngineCore) make_config_for_gn(WebEngineCore gn_config) -qt_internal_extend_target(WebEngineCore CONDITION QT_FEATURE_webengine_printing_and_pdf - PUBLIC_LIBRARIES - Qt::PrintSupport -) qt_internal_extend_target(WebEngineCore CONDITION QT_FEATURE_webengine_webchannel PUBLIC_LIBRARIES Qt::WebChannel diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp index 548457349..f04a0943c 100644 --- a/src/core/api/qwebenginepage.cpp +++ b/src/core/api/qwebenginepage.cpp @@ -48,9 +48,6 @@ #include "find_text_helper.h" #include "file_picker_controller.h" #include "javascript_dialog_controller.h" -#if QT_CONFIG(webengine_printing_and_pdf) -#include "printing/printer_worker.h" -#endif #include "qwebenginecertificateerror.h" #include "qwebenginefindtextresult.h" #include "qwebenginefullscreenrequest.h" @@ -79,13 +76,10 @@ #include <QIcon> #include <QLoggingCategory> #include <QMimeData> -#if QT_CONFIG(webengine_printing_and_pdf) -#include <QPrinter> -#include <QThread> -#endif #include <QTimer> #include <QUrl> + QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; @@ -182,9 +176,6 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) , webChannelWorldId(QWebEngineScript::MainWorld) , defaultAudioMuted(false) , defaultZoomFactor(1.0) -#if QT_CONFIG(webengine_printing_and_pdf) - , currentPrinter(nullptr) -#endif { memset(actions, 0, sizeof(actions)); @@ -340,8 +331,8 @@ void QWebEnginePagePrivate::loadFinished(bool success, const QUrl &url, bool isE void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool success) { - Q_Q(QWebEnginePage); - Q_EMIT q->pdfPrintingFinished(filePath, success); + if (view) + view->didPrintPageToPdf(filePath, success); } void QWebEnginePagePrivate::focusContainer() @@ -486,38 +477,8 @@ 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; - m_callbacks.invoke(requestId, *(result.data())); - return; - } - - QThread *printerThread = new QThread; - QObject::connect(printerThread, &QThread::finished, printerThread, &QThread::deleteLater); - printerThread->start(); - - PrinterWorker *printerWorker = new PrinterWorker(result, currentPrinter); - QObject::connect(printerWorker, &PrinterWorker::resultReady, q, [requestId, this](bool success) { - currentPrinter = nullptr; - m_callbacks.invoke(requestId, success); - }); - - QObject::connect(printerWorker, &PrinterWorker::resultReady, printerThread, &QThread::quit); - QObject::connect(printerThread, &QThread::finished, printerWorker, &PrinterWorker::deleteLater); - - printerWorker->moveToThread(printerThread); - QMetaObject::invokeMethod(printerWorker, "print"); - -#else - // we should never enter this branch, but just for safe-keeping... - Q_UNUSED(result); - m_callbacks.invoke(requestId, QByteArray()); -#endif + if (view) + view->didPrintPage(requestId, result); } bool QWebEnginePagePrivate::passOnFocus(bool reverse) @@ -780,15 +741,6 @@ QWebEnginePage::QWebEnginePage(QObject* parent) \sa findText() */ -/*! - \fn void QWebEnginePage::printRequested() - \since 5.12 - - This signal is emitted when the JavaScript \c{window.print()} method is called. - Typically, the signal handler can simply call printToPdf(). - - \sa printToPdf() -*/ /*! \enum QWebEnginePage::RenderProcessTerminationStatus @@ -854,19 +806,6 @@ QWebEnginePage::QWebEnginePage(QObject* parent) */ /*! - \fn void QWebEnginePage::pdfPrintingFinished(const QString &filePath, bool success) - \since 5.9 - - 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() -*/ - -/*! \property QWebEnginePage::scrollPosition \since 5.7 @@ -1752,10 +1691,8 @@ 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(); } void QWebEnginePagePrivate::lifecycleStateChanged(LifecycleState state) @@ -2268,115 +2205,6 @@ QSizeF QWebEnginePage::contentsSize() const } /*! - 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. - - 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. - \since 5.7 - \sa pdfPrintingFinished() -*/ -void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &pageLayout) -{ -#if QT_CONFIG(webengine_printing_and_pdf) - Q_D(const QWebEnginePage); - if (d->currentPrinter) { - qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); - return; - } - d->ensureInitialized(); - d->adapter->printToPDF(pageLayout, filePath); -#else - Q_UNUSED(filePath); - Q_UNUSED(pageLayout); -#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. - - 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. - - \since 5.7 -*/ -void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &pageLayout) -{ - Q_D(QWebEnginePage); -#if QT_CONFIG(webengine_printing_and_pdf) - if (d->currentPrinter) { - qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); - d->m_callbacks.invokeEmpty(resultCallback); - return; - } - d->ensureInitialized(); - quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout); - d->m_callbacks.registerCallback(requestId, resultCallback); -#else - Q_UNUSED(pageLayout); - d->m_callbacks.invokeEmpty(resultCallback); -#endif -} - -/*! - 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. - It is the users responsibility to ensure the \a printer remains valid until \a resultCallback - has been called. - - \note Printing runs on the browser process, which is by default not sandboxed. - - The \a resultCallback must take a boolean as parameter. If printing was successful, this - boolean will have the value \c true, otherwise, its value will be \c false. - - \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. - - \note This function rasterizes the result when rendering onto \a printer. Please consider raising - the default resolution of \a printer to at least 300 DPI or using printToPdf() to produce - PDF file output more effectively. - - \since 5.8 -*/ -void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback) -{ - Q_D(QWebEnginePage); -#if QT_CONFIG(webengine_printing_and_pdf) - if (d->currentPrinter) { - qWarning("Cannot print page on printer %ls: Already printing on %ls.", qUtf16Printable(printer->printerName()), qUtf16Printable(d->currentPrinter->printerName())); - d->m_callbacks.invokeDirectly(resultCallback, false); - return; - } - d->currentPrinter = printer; - d->ensureInitialized(); - quint64 requestId = d->adapter->printToPDFCallbackResult(printer->pageLayout(), - printer->colorMode() == QPrinter::Color, - false); - d->m_callbacks.registerCallback(requestId, resultCallback); -#else - Q_UNUSED(printer); - d->m_callbacks.invokeDirectly(resultCallback, false); -#endif -} - - -/*! \fn void QWebEnginePage::newWindowRequested(WebEngineNewViewRequest &request) \since 6.2 diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h index c0c970207..94a78aa67 100644 --- a/src/core/api/qwebenginepage.h +++ b/src/core/api/qwebenginepage.h @@ -55,7 +55,6 @@ QT_BEGIN_NAMESPACE class QMenu; -class QPrinter; class QContextMenuBuilder; class QWebChannel; @@ -302,10 +301,6 @@ public: bool recentlyAudible() const; qint64 renderProcessPid() const; - void printToPdf(const QString &filePath, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); - void printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); - void print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback); - void setInspectedPage(QWebEnginePage *page); QWebEnginePage *inspectedPage() const; void setDevToolsPage(QWebEnginePage *page); @@ -360,9 +355,6 @@ 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 d2c246397..a830028f8 100644 --- a/src/core/api/qwebenginepage_p.h +++ b/src/core/api/qwebenginepage_p.h @@ -104,6 +104,9 @@ 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 didPrintPageToPdf(const QString &filePath, bool success) = 0; + virtual void printRequested() = 0; }; class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient @@ -225,9 +228,6 @@ public: mutable QtWebEngineCore::CallbackDirectory m_callbacks; mutable QAction *actions[QWebEnginePage::WebActionCount]; -#if QT_CONFIG(webengine_printing_and_pdf) - QPrinter *currentPrinter; -#endif }; QT_END_NAMESPACE diff --git a/src/core/printing/printer_worker.cpp b/src/core/printing/printer_worker.cpp index cbd6b8da3..411e326c3 100644 --- a/src/core/printing/printer_worker.cpp +++ b/src/core/printing/printer_worker.cpp @@ -42,12 +42,12 @@ #include "printing/pdfium_document_wrapper_qt.h" #include <QPainter> -#include <QPrinter> +#include <QPagedPaintDevice> namespace QtWebEngineCore { -PrinterWorker::PrinterWorker(QSharedPointer<QByteArray> data, QPrinter *printer) - : m_data(data), m_printer(printer) +PrinterWorker::PrinterWorker(QSharedPointer<QByteArray> data, QPagedPaintDevice *device) + : m_data(data), m_device(device) { } @@ -56,16 +56,16 @@ PrinterWorker::~PrinterWorker() { } void PrinterWorker::print() { if (!m_data->size()) { - qWarning("Failure to print on printer %ls: Print result data is empty.", - qUtf16Printable(m_printer->printerName())); + qWarning("Failed to print: Print result data is empty."); Q_EMIT resultReady(false); return; } PdfiumDocumentWrapperQt pdfiumWrapper(m_data->constData(), m_data->size()); - int toPage = m_printer->toPage(); - int fromPage = m_printer->fromPage(); + const QPageRanges ranges = m_device->pageRanges(); + int toPage = ranges.firstPage(); + int fromPage = ranges.lastPage(); bool ascendingOrder = true; if (fromPage == 0 && toPage == 0) { @@ -75,62 +75,50 @@ void PrinterWorker::print() fromPage = qMax(1, fromPage); toPage = qMin(pdfiumWrapper.pageCount(), toPage); - if (m_printer->pageOrder() == QPrinter::LastPageFirst) { + if (!m_firstPageFirst) { qSwap(fromPage, toPage); ascendingOrder = false; } int pageCopies = 1; - int documentCopies = 1; - - if (!m_printer->supportsMultipleCopies()) - documentCopies = m_printer->copyCount(); - - if (m_printer->collateCopies()) { - pageCopies = documentCopies; - documentCopies = 1; + if (m_collateCopies) { + pageCopies = m_documentCopies; + m_documentCopies = 1; } - qreal resolution = m_printer->resolution() / 72.0; // pdfium uses points so 1/72 inch + qreal resolution = m_deviceResolution / 72.0; // pdfium uses points so 1/72 inch QPainter painter; - for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { + for (int printedDocuments = 0; printedDocuments < m_documentCopies; printedDocuments++) { if (printedDocuments > 0) - m_printer->newPage(); + m_device->newPage(); int currentPageIndex = fromPage; for (int i = 0; true; i++) { QSizeF documentSize = (pdfiumWrapper.pageSize(currentPageIndex - 1) * resolution); bool isLandscape = documentSize.width() > documentSize.height(); - m_printer->setPageOrientation(isLandscape ? QPageLayout::Landscape + m_device->setPageOrientation(isLandscape ? QPageLayout::Landscape : QPageLayout::Portrait); - QRectF pageRect = m_printer->pageRect(QPrinter::DevicePixel); + QRectF pageRect = m_device->pageLayout().pageSize().rectPixels(m_deviceResolution); documentSize = documentSize.scaled(pageRect.size(), Qt::KeepAspectRatio); // setPageOrientation has to be called before qpainter.begin() or before // qprinter.newPage() so correct metrics is used, therefore call begin now for only // first page - if (!painter.isActive() && !painter.begin(m_printer)) { - qWarning("Failure to print on printer %ls: Could not open printer for painting.", - qUtf16Printable(m_printer->printerName())); + if (!painter.isActive() && !painter.begin(m_device)) { + qWarning("Failure to print on device: Could not open printer for painting."); Q_EMIT resultReady(false); return; } if (i > 0) - m_printer->newPage(); + m_device->newPage(); for (int printedPages = 0; printedPages < pageCopies; printedPages++) { - if (m_printer->printerState() == QPrinter::Aborted - || m_printer->printerState() == QPrinter::Error) { - Q_EMIT resultReady(false); - return; - } - if (printedPages > 0) - m_printer->newPage(); + m_device->newPage(); QImage currentImage = pdfiumWrapper.pageAsQImage( currentPageIndex - 1, documentSize.width(), documentSize.height()); diff --git a/src/core/printing/printer_worker.h b/src/core/printing/printer_worker.h index 9d1192bd2..3681312a9 100644 --- a/src/core/printing/printer_worker.h +++ b/src/core/printing/printer_worker.h @@ -51,12 +51,12 @@ #ifndef PRINTER_WORKER_H #define PRINTER_WORKER_H -#include "qtwebenginecoreglobal_p.h" +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> #include <QSharedPointer> QT_BEGIN_NAMESPACE -class QPrinter; +class QPagedPaintDevice; QT_END_NAMESPACE namespace QtWebEngineCore { @@ -65,9 +65,14 @@ class Q_WEBENGINECORE_PRIVATE_EXPORT PrinterWorker : public QObject { Q_OBJECT public: - PrinterWorker(QSharedPointer<QByteArray> data, QPrinter *printer); + PrinterWorker(QSharedPointer<QByteArray> data, QPagedPaintDevice *device); virtual ~PrinterWorker(); + int m_deviceResolution; + bool m_firstPageFirst; + int m_documentCopies; + bool m_collateCopies; + public Q_SLOTS: void print(); @@ -78,7 +83,7 @@ private: Q_DISABLE_COPY(PrinterWorker) QSharedPointer<QByteArray> m_data; - QPrinter *m_printer; + QPagedPaintDevice *m_device; }; } // namespace QtWebEngineCore diff --git a/src/webenginewidgets/CMakeLists.txt b/src/webenginewidgets/CMakeLists.txt index f37948c8c..425eb1d73 100644 --- a/src/webenginewidgets/CMakeLists.txt +++ b/src/webenginewidgets/CMakeLists.txt @@ -29,3 +29,8 @@ qt_internal_add_module(WebEngineWidgets Qt::WebEngineCore ) make_install_only(WebEngineWidgets) + +qt_internal_extend_target(WebEngineWidgets CONDITION QT_FEATURE_webengine_printing_and_pdf + PUBLIC_LIBRARIES + Qt::PrintSupport +) diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 9ce954e06..a34c841e3 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -80,6 +80,13 @@ #include <QStyle> #include <QGuiApplication> +#if QT_CONFIG(webengine_printing_and_pdf) +#include "printing/printer_worker.h" + +#include <QPrinter> +#include <QThread> +#endif + QT_BEGIN_NAMESPACE void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage) @@ -344,7 +351,13 @@ static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *obje #endif // QT_NO_ACCESSIBILITY QWebEngineViewPrivate::QWebEngineViewPrivate() - : page(0), m_dragEntered(false), m_ownsPage(false), m_contextRequest(nullptr) + : page(0) + , 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); @@ -495,6 +508,61 @@ QObject *QWebEngineViewPrivate::accessibilityParentObject() return q; } +void QWebEngineViewPrivate::didPrintPage(quint64 requestId, 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; + page->d_ptr->m_callbacks.invoke(requestId, *(result.data())); + return; + } + + QThread *printerThread = new QThread; + QObject::connect(printerThread, &QThread::finished, printerThread, &QThread::deleteLater); + printerThread->start(); + + QtWebEngineCore::PrinterWorker *printerWorker = new QtWebEngineCore::PrinterWorker(result, currentPrinter); + printerWorker->m_deviceResolution = currentPrinter->resolution(); + printerWorker->m_firstPageFirst = currentPrinter->pageOrder() == QPrinter::FirstPageFirst; + printerWorker->m_documentCopies = currentPrinter->copyCount(); + printerWorker->m_collateCopies = currentPrinter->collateCopies(); + + QObject::connect(printerWorker, &QtWebEngineCore::PrinterWorker::resultReady, q, [requestId, this](bool success) { + currentPrinter = nullptr; + page->d_ptr->m_callbacks.invoke(requestId, success); + }); + + QObject::connect(printerWorker, &QtWebEngineCore::PrinterWorker::resultReady, printerThread, &QThread::quit); + QObject::connect(printerThread, &QThread::finished, printerWorker, &QtWebEngineCore::PrinterWorker::deleteLater); + + printerWorker->moveToThread(printerThread); + QMetaObject::invokeMethod(printerWorker, "print"); + +#else + // we should never enter this branch, but just for safe-keeping... + Q_UNUSED(result); + page->d_ptr->m_callbacks.invoke(requestId, QByteArray()); +#endif +} + +void QWebEngineViewPrivate::didPrintPageToPdf(const QString &filePath, bool success) +{ + Q_Q(QWebEngineView); + Q_EMIT q->pdfPrintingFinished(filePath, success); +} + +void QWebEngineViewPrivate::printRequested() +{ + Q_Q(QWebEngineView); + QTimer::singleShot(0, q, [q]() { + Q_EMIT q->printRequested(); + }); +} + bool QWebEngineViewPrivate::isVisible() const { Q_Q(const QWebEngineView); @@ -878,6 +946,62 @@ QWebEngineContextMenuRequest *QWebEngineView::lastContextMenuRequest() const return d->m_contextRequest; } +void QWebEngineView::printToPdf(const QString &filePath, const QPageLayout &layout) +{ +#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, filePath); +#else + Q_UNUSED(filePath); + Q_UNUSED(layout); +#endif +} + +void QWebEngineView::printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &layout) +{ +#if QT_CONFIG(webengine_printing_and_pdf) + Q_D(QWebEngineView); + if (d->currentPrinter) { + qWarning("Cannot print to PDF while printing at the same time."); + page()->d_ptr->m_callbacks.invokeEmpty(resultCallback); + return; + } + page()->d_ptr->ensureInitialized(); + quint64 requestId = page()->d_ptr->adapter->printToPDFCallbackResult(layout); + page()->d_ptr->m_callbacks.registerCallback(requestId, resultCallback); +#else + Q_UNUSED(layout); + page()->d_ptr->m_callbacks.invokeEmpty(resultCallback); +#endif +} + +void QWebEngineView::print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback) +{ +#if QT_CONFIG(webengine_printing_and_pdf) + Q_D(QWebEngineView); + if (d->currentPrinter) { + qWarning("Cannot print page on printer %ls: Already printing on a device.", qUtf16Printable(printer->printerName())); + page()->d_ptr->m_callbacks.invokeDirectly(resultCallback, false); + return; + } + + d->currentPrinter = printer; + page()->d_ptr->ensureInitialized(); + quint64 requestId = page()->d_ptr->adapter->printToPDFCallbackResult(printer->pageLayout(), + printer->colorMode() == QPrinter::Color, + false); + page()->d_ptr->m_callbacks.registerCallback(requestId, resultCallback); +#else + Q_UNUSED(printer); + page()->d_ptr->m_callbacks.invokeDirectly(resultCallback, false); +#endif +} + #ifndef QT_NO_ACCESSIBILITY bool QWebEngineViewAccessible::isValid() const { diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h index d7f9d6a45..136df0b93 100644 --- a/src/webenginewidgets/api/qwebengineview.h +++ b/src/webenginewidgets/api/qwebengineview.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE class QContextMenuEvent; +class QPrinter; class QUrl; class QWebEnginePage; class QWebEngineSettings; @@ -107,6 +108,10 @@ public: #endif QWebEngineContextMenuRequest *lastContextMenuRequest() const; + void printToPdf(const QString &filePath, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); + void printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); + void print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback); + public Q_SLOTS: void stop(); void back(); @@ -124,6 +129,8 @@ Q_SIGNALS: void iconChanged(const QIcon&); void renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode); + void pdfPrintingFinished(const QString &filePath, bool success); + void printRequested(); protected: virtual QWebEngineView *createWindow(QWebEnginePage::WebWindowType type); diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index 40f195522..71e7d04f7 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -58,6 +58,7 @@ #include <QtWidgets/qaccessiblewidget.h> namespace QtWebEngineCore { +class QPrinter; class RenderWidgetHostViewQtDelegateWidget; class RenderWidgetHostViewQtDelegate; } @@ -92,6 +93,10 @@ public: QWebEngineContextMenuRequest *lastContextMenuRequest() const override; QWebEnginePage *createPageForWindow(QWebEnginePage::WebWindowType type) override; QObject *accessibilityParentObject() override; + void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) override; + void didPrintPageToPdf(const QString &filePath, bool success) override; + void printRequested() override; + QWebEngineViewPrivate(); virtual ~QWebEngineViewPrivate(); static void bindPageAndView(QWebEnginePage *page, QWebEngineView *view); @@ -108,6 +113,9 @@ public: bool m_dragEntered; mutable bool m_ownsPage; QWebEngineContextMenuRequest *m_contextRequest; +#if QT_CONFIG(webengine_printing_and_pdf) + QPrinter *currentPrinter; +#endif }; #ifndef QT_NO_ACCESSIBILITY diff --git a/tests/auto/widgets/printing/tst_printing.cpp b/tests/auto/widgets/printing/tst_printing.cpp index d1542af23..3f1344ed4 100644 --- a/tests/auto/widgets/printing/tst_printing.cpp +++ b/tests/auto/widgets/printing/tst_printing.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> -#include <QWebEnginePage> +#include <QWebEngineView> #include <QTemporaryDir> #include <QTest> #include <QSignalSpy> @@ -53,15 +53,15 @@ void tst_Printing::printToPdfBasic() { QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); QVERIFY(tempDir.isValid()); - QWebEnginePage page; - QSignalSpy spy(&page, &QWebEnginePage::loadFinished); - page.load(QUrl("qrc:///resources/basic_printing_page.html")); + QWebEngineView view; + QSignalSpy spy(&view, &QWebEngineView::loadFinished); + view.load(QUrl("qrc:///resources/basic_printing_page.html")); QTRY_VERIFY(spy.count() == 1); - QSignalSpy savePdfSpy(&page, &QWebEnginePage::pdfPrintingFinished); + QSignalSpy savePdfSpy(&view, &QWebEngineView::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"; - page.printToPdf(path, layout); + view.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 - page.printToPdf(path, QPageLayout()); + view.printToPdf(path, QPageLayout()); QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); QList<QVariant> failedArguments = savePdfSpy.takeFirst(); @@ -81,29 +81,29 @@ void tst_Printing::printToPdfBasic() QVERIFY2(failedArguments.at(1).toBool() == false, "Printing to PDF file succeeded though it should fail"); CallbackSpy<QByteArray> successfulSpy; - page.printToPdf(successfulSpy.ref(), layout); + view.printToPdf(successfulSpy.ref(), layout); QVERIFY(successfulSpy.waitForResult().length() > 0); CallbackSpy<QByteArray> failedInvalidLayoutSpy; - page.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout()); + view.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout()); QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0); } void tst_Printing::printRequest() { - QWebEnginePage webPage; + QWebEngineView view; QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0)); - QSignalSpy loadFinishedSpy(&webPage, &QWebEnginePage::loadFinished); - QSignalSpy printRequestedSpy(&webPage, &QWebEnginePage::printRequested); - QSignalSpy savePdfSpy(&webPage, &QWebEnginePage::pdfPrintingFinished); + QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished); + QSignalSpy printRequestedSpy(&view, &QWebEngineView::printRequested); + QSignalSpy savePdfSpy(&view, &QWebEngineView::pdfPrintingFinished); CallbackSpy<QByteArray> resultSpy; - webPage.load(QUrl("qrc:///resources/basic_printing_page.html")); + view.load(QUrl("qrc:///resources/basic_printing_page.html")); QTRY_VERIFY(loadFinishedSpy.count() == 1); - webPage.runJavaScript("window.print()"); + view.page()->runJavaScript("window.print()"); QTRY_VERIFY(printRequestedSpy.count() == 1); //check if printing still works - webPage.printToPdf(resultSpy.ref(), layout); + view.printToPdf(resultSpy.ref(), layout); const QByteArray data = resultSpy.waitForResult(); QVERIFY(data.length() > 0); } @@ -113,16 +113,16 @@ void tst_Printing::printToPdfPoppler() { // check if generated pdf is correct by searching for a know string on the page using namespace poppler; - QWebEnginePage webPage; + QWebEngineView view; QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0)); - QSignalSpy spy(&webPage, &QWebEnginePage::loadFinished); - QSignalSpy savePdfSpy(&webPage, &QWebEnginePage::pdfPrintingFinished); + QSignalSpy spy(&view, &QWebEngineView::loadFinished); + QSignalSpy savePdfSpy(&view, &QWebEngineView::pdfPrintingFinished); CallbackSpy<QByteArray> resultSpy; - webPage.load(QUrl("qrc:///resources/basic_printing_page.html")); + view.load(QUrl("qrc:///resources/basic_printing_page.html")); QTRY_VERIFY(spy.count() == 1); - webPage.printToPdf(resultSpy.ref(), layout); + view.printToPdf(resultSpy.ref(), layout); const QByteArray data = resultSpy.waitForResult(); QVERIFY(data.length() > 0); |