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