From 9968e2578f96081d2a242340620fcb2b96d9a1d3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 26 Aug 2019 10:13:55 +0200 Subject: Add QtQuick.Pdf module with QQuickPdfDocument; manual tests QQuickPdfDocument is a wrapper for QPdfDocument providing appropriate QML API. Task-number: QTBUG-77506 Change-Id: Ifa2ef50d3d31179f1955c2f673495e727b962bd1 Reviewed-by: Michal Klocek --- src/pdf/api/qpdfdocument.h | 1 + src/pdf/pdf.pro | 4 +- src/pdf/qpdfdocument.cpp | 27 ++++- src/pdf/quick/plugin.cpp | 87 ++++++++++++++++ src/pdf/quick/plugins.qmltypes | 52 ++++++++++ src/pdf/quick/qmldir | 4 + src/pdf/quick/qquickpdfdocument.cpp | 202 ++++++++++++++++++++++++++++++++++++ src/pdf/quick/qquickpdfdocument_p.h | 125 ++++++++++++++++++++++ src/pdf/quick/quick.pro | 17 +++ 9 files changed, 514 insertions(+), 5 deletions(-) create mode 100644 src/pdf/quick/plugin.cpp create mode 100644 src/pdf/quick/plugins.qmltypes create mode 100644 src/pdf/quick/qmldir create mode 100644 src/pdf/quick/qquickpdfdocument.cpp create mode 100644 src/pdf/quick/qquickpdfdocument_p.h create mode 100644 src/pdf/quick/quick.pro (limited to 'src/pdf') diff --git a/src/pdf/api/qpdfdocument.h b/src/pdf/api/qpdfdocument.h index 50525eb9d..a0a2a21be 100644 --- a/src/pdf/api/qpdfdocument.h +++ b/src/pdf/api/qpdfdocument.h @@ -68,6 +68,7 @@ public: enum DocumentError { NoError, UnknownError, + DataNotYetAvailableError, FileNotFoundError, InvalidFileFormatError, IncorrectPasswordError, diff --git a/src/pdf/pdf.pro b/src/pdf/pdf.pro index 251b10a1b..c5513ce93 100644 --- a/src/pdf/pdf.pro +++ b/src/pdf/pdf.pro @@ -5,10 +5,12 @@ gn_run.file = gn_run.pro gn_run.depends = pdfcore_generator pdfcore.depends = gn_run +quick.depends = pdfcore SUBDIRS += \ pdfcore_generator \ gn_run \ - pdfcore + pdfcore \ + quick diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index 5c6a9e078..690953691 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -39,7 +39,12 @@ #include "third_party/pdfium/public/fpdf_doc.h" +#include +#include +#include #include +#include +#include #include QT_BEGIN_NAMESPACE @@ -47,6 +52,7 @@ QT_BEGIN_NAMESPACE // The library is not thread-safe at all, it has a lot of global variables. Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive)); static int libraryRefCount; +Q_LOGGING_CATEGORY(qLcDoc, "qt.pdf.document") QPdfMutexLocker::QPdfMutexLocker() : QMutexLocker(pdfMutex()) @@ -237,9 +243,19 @@ void QPdfDocumentPrivate::_q_copyFromSequentialSourceDevice() void QPdfDocumentPrivate::tryLoadDocument() { QPdfMutexLocker lock; - - if (!FPDFAvail_IsDocAvail(avail, this)) - return; + switch (FPDFAvail_IsDocAvail(avail, this)) { + case PDF_DATA_ERROR: + qCDebug(qLcDoc) << "error loading"; + break; + case PDF_DATA_NOTAVAIL: + qCDebug(qLcDoc) << "data not yet available"; + lastError = QPdfDocument::DataNotYetAvailableError; + setStatus(QPdfDocument::Error); + break; + case PDF_DATA_AVAIL: + // all good + break; + } Q_ASSERT(!doc); @@ -570,6 +586,9 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions const QPdfMutexLocker lock; + QElapsedTimer timer; + if (Q_UNLIKELY(qLcDoc().isDebugEnabled())) + timer.start(); FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); if (!pdfPage) return QImage(); @@ -616,7 +635,7 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions FPDFBitmap_Destroy(bitmap); FPDF_ClosePage(pdfPage); - + qCDebug(qLcDoc) << "page" << page << imageSize << "took" << timer.elapsed() << "ms"; return result; } diff --git a/src/pdf/quick/plugin.cpp b/src/pdf/quick/plugin.cpp new file mode 100644 index 000000000..59aca576b --- /dev/null +++ b/src/pdf/quick/plugin.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "qquickpdfdocument_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmlmodule QtQuick.Pdf 5.15 + \title Qt Quick PDF QML Types + \ingroup qmlmodules + \brief Provides QML types for handling PDF documents. + + This QML module contains types for handling PDF documents. + + To use the types in this module, import the module with the following line: + + \code + import QtQuick.Pdf 5.15 + \endcode +*/ + +class QtQuick2PdfPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) + +public: + QtQuick2PdfPlugin() : QQmlExtensionPlugin() { } + + void initializeEngine(QQmlEngine *engine, const char *uri) override { + Q_UNUSED(uri); +#ifndef QT_STATIC + engine->addImportPath(QStringLiteral("qrc:/")); +#endif + } + + void registerTypes(const char *uri) override { + Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Pdf")); + + // Register the latest version, even if there are no new types or new revisions for existing types yet. + qmlRegisterModule(uri, 2, QT_VERSION_MINOR); + + qmlRegisterType(uri, 5, 15, "PdfDocument"); + } +}; + +QT_END_NAMESPACE + +#include "plugin.moc" diff --git a/src/pdf/quick/plugins.qmltypes b/src/pdf/quick/plugins.qmltypes new file mode 100644 index 000000000..a30361d33 --- /dev/null +++ b/src/pdf/quick/plugins.qmltypes @@ -0,0 +1,52 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -nonrelocatable QtQuick.Pdf 5.14' + +Module { + dependencies: [ + "QtGraphicalEffects 1.12", + "QtQuick 2.14", + "QtQuick.Controls 2.14", + "QtQuick.Controls.Fusion 2.14", + "QtQuick.Controls.Fusion.impl 2.14", + "QtQuick.Controls.Imagine 2.14", + "QtQuick.Controls.Imagine.impl 2.14", + "QtQuick.Controls.Material 2.14", + "QtQuick.Controls.Material.impl 2.14", + "QtQuick.Controls.Universal 2.14", + "QtQuick.Controls.Universal.impl 2.12", + "QtQuick.Controls.impl 2.14", + "QtQuick.Shapes 1.14", + "QtQuick.Templates 2.14", + "QtQuick.Window 2.2" + ] + Component { + name: "QQuickPdfDocument" + prototype: "QObject" + exports: ["QtQuick.Pdf/PdfDocument 5.14"] + exportMetaObjectRevisions: [0] + Property { name: "source"; type: "QUrl" } + Property { name: "pageCount"; type: "int"; isReadonly: true } + Property { name: "password"; type: "string" } + Property { name: "status"; type: "QPdfDocument::Status"; isReadonly: true } + Property { name: "title"; type: "string"; isReadonly: true } + Property { name: "subject"; type: "string"; isReadonly: true } + Property { name: "author"; type: "string"; isReadonly: true } + Property { name: "keywords"; type: "string"; isReadonly: true } + Property { name: "producer"; type: "string"; isReadonly: true } + Property { name: "creator"; type: "string"; isReadonly: true } + Property { name: "creationDate"; type: "QDateTime"; isReadonly: true } + Property { name: "modificationDate"; type: "QDateTime"; isReadonly: true } + Signal { name: "passwordRequired" } + Signal { name: "metaDataLoaded" } + Method { + name: "pagePointSize" + type: "QSizeF" + Parameter { name: "page"; type: "int" } + } + } +} diff --git a/src/pdf/quick/qmldir b/src/pdf/quick/qmldir new file mode 100644 index 000000000..65fa95cda --- /dev/null +++ b/src/pdf/quick/qmldir @@ -0,0 +1,4 @@ +module QtQuick.Pdf +plugin pdfplugin +classname QtQuick2PdfPlugin +typeinfo plugins.qmltypes diff --git a/src/pdf/quick/qquickpdfdocument.cpp b/src/pdf/quick/qquickpdfdocument.cpp new file mode 100644 index 000000000..f0f40c227 --- /dev/null +++ b/src/pdf/quick/qquickpdfdocument.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpdfdocument_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Document + \instantiates QQuickPdfDocument + \inqmlmodule QtQuick.Pdf + \ingroup pdf + \brief A representation of a PDF document. + \since 5.15 + + A Document provides access to PDF document meta-information. + It is not necessary for rendering, as it is enough to use an + \l Image with source set to the URL of the PDF. +*/ + +/*! + Constructs a PDF document. +*/ +QQuickPdfDocument::QQuickPdfDocument(QObject *parent) + : QObject(parent) +{ + connect(&m_doc, &QPdfDocument::passwordChanged, this, &QQuickPdfDocument::passwordChanged); + connect(&m_doc, &QPdfDocument::passwordRequired, this, &QQuickPdfDocument::passwordRequired); + connect(&m_doc, &QPdfDocument::statusChanged, [=] (QPdfDocument::Status status) { + emit statusChanged(); + if (status == QPdfDocument::Ready) + emit metaDataChanged(); + }); + connect(&m_doc, &QPdfDocument::pageCountChanged, this, &QQuickPdfDocument::pageCountChanged); +} + +void QQuickPdfDocument::componentComplete() +{ + if (m_doc.error() == QPdfDocument::IncorrectPasswordError) + emit passwordRequired(); +} + +/*! + \qmlproperty url Document::source + + This property holds a URL pointing to the PDF file to be loaded. + + \note At this time, only local filesystem URLs are supported. +*/ +void QQuickPdfDocument::setSource(QUrl source) +{ + if (m_source == source) + return; + + m_source = source; + emit sourceChanged(); + m_doc.load(source.path()); +} + +/*! + \qmlproperty bool Document::password + + This property holds the document password. If the passwordRequired() + signal is emitted, the UI should prompt the user and then set this + property so that document opening can continue. +*/ +void QQuickPdfDocument::setPassword(const QString &password) +{ + if (m_doc.password() == password) + return; + m_doc.setPassword(password); + if (source().isValid() && source().isLocalFile()) + m_doc.load(source().path()); +} + +/*! + \qmlproperty int Document::pageCount + + This property holds the number of pages the PDF contains. +*/ + +/*! + \qmlsignal Document::passwordRequired() + + This signal is emitted when the PDF requires a password in order to open. + The UI in a typical PDF viewer should prompt the user for the password + and then set the password property when the user has provided it. +*/ + +/*! + \qmlmethod size Document::pagePointSize(int page) + + Returns the size of the given \a page in points. +*/ +QSizeF QQuickPdfDocument::pagePointSize(int page) const +{ + return m_doc.pageSize(page); +} + +/*! + \qmlproperty string Document::title + + This property holds the document's title. A typical viewer UI can bind this + to the \c Window.title property. +*/ + +/*! + \qmlproperty string Document::author + + This property holds the name of the person who created the document. +*/ + +/*! + \qmlproperty string Document::subject + + This property holds the subject of the document. +*/ + +/*! + \qmlproperty string Document::keywords + + This property holds the keywords associated with the document. +*/ + +/*! + \qmlproperty string Document::creator + + If the document was converted to PDF from another format, this property + holds the name of the software that created the original document. +*/ + +/*! + \qmlproperty string Document::producer + + If the document was converted to PDF from another format, this property + holds the name of the software that converted it to PDF. +*/ + +/*! + \qmlproperty string Document::creationDate + + This property holds the date and time the document was created. +*/ + +/*! + \qmlproperty string Document::modificationDate + + This property holds the date and time the document was most recently + modified. +*/ + +/*! + \qmlproperty enum Document::status + + This property tells the current status of the document. The possible values are: + + \value PdfDocument.Null The initial status after the document has been created or after it has been closed. + \value PdfDocument.Loading The status after load() has been called and before the document is fully loaded. + \value PdfDocument.Ready The status when the document is fully loaded and its data can be accessed. + \value PdfDocument.Unloading The status after close() has been called on an open document. + At this point the document is still valid and all its data can be accessed. + \value PdfDocument.Error The status after Loading, if loading has failed. +*/ + +QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfdocument_p.h b/src/pdf/quick/qquickpdfdocument_p.h new file mode 100644 index 000000000..ee6195679 --- /dev/null +++ b/src/pdf/quick/qquickpdfdocument_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPDFDOCUMENT_P_H +#define QQUICKPDFDOCUMENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickPdfDocument : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL) + Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL) + Q_PROPERTY(QPdfDocument::Status status READ status NOTIFY statusChanged FINAL) + + Q_PROPERTY(QString title READ title NOTIFY metaDataChanged) + Q_PROPERTY(QString subject READ subject NOTIFY metaDataChanged) + Q_PROPERTY(QString author READ author NOTIFY metaDataChanged) + Q_PROPERTY(QString keywords READ keywords NOTIFY metaDataChanged) + Q_PROPERTY(QString producer READ producer NOTIFY metaDataChanged) + Q_PROPERTY(QString creator READ creator NOTIFY metaDataChanged) + Q_PROPERTY(QDateTime creationDate READ creationDate NOTIFY metaDataChanged) + Q_PROPERTY(QDateTime modificationDate READ modificationDate NOTIFY metaDataChanged) + +public: + explicit QQuickPdfDocument(QObject *parent = nullptr); + + void classBegin() override {} + void componentComplete() override; + + QUrl source() const { return m_source; } + void setSource(QUrl source); + + int pageCount() const { return m_doc.pageCount(); } + QPdfDocument::Status status() const { return m_doc.status(); } + + QString password() const { return m_doc.password(); } + void setPassword(const QString &password); + + QString title() { return m_doc.metaData(QPdfDocument::Title).toString(); } + QString author() { return m_doc.metaData(QPdfDocument::Author).toString(); } + QString subject() { return m_doc.metaData(QPdfDocument::Subject).toString(); } + QString keywords() { return m_doc.metaData(QPdfDocument::Keywords).toString(); } + QString producer() { return m_doc.metaData(QPdfDocument::Producer).toString(); } + QString creator() { return m_doc.metaData(QPdfDocument::Creator).toString(); } + QDateTime creationDate() { return m_doc.metaData(QPdfDocument::CreationDate).toDateTime(); } + QDateTime modificationDate() { return m_doc.metaData(QPdfDocument::ModificationDate).toDateTime(); } + + Q_INVOKABLE QSizeF pagePointSize(int page) const; + +Q_SIGNALS: + void sourceChanged(); + void passwordChanged(); + void passwordRequired(); + void statusChanged(); + void pageCountChanged(); + void metaDataChanged(); + +private: + QPdfDocument &document() { return m_doc; } + +private: + QUrl m_source; + QPdfDocument m_doc; + + friend class QQuickPdfSelection; + + Q_DISABLE_COPY(QQuickPdfDocument) +}; + +QT_END_NAMESPACE + +#endif // QQUICKPDFDOCUMENT_P_H diff --git a/src/pdf/quick/quick.pro b/src/pdf/quick/quick.pro new file mode 100644 index 000000000..eb88bc003 --- /dev/null +++ b/src/pdf/quick/quick.pro @@ -0,0 +1,17 @@ +CXX_MODULE = qml +TARGET = pdfplugin +TARGETPATH = QtQuick/Pdf +IMPORT_VERSION = 1.0 + +#QMAKE_DOCS = $$PWD/doc/qtquickpdf.qdocconf + +SOURCES += \ + qquickpdfdocument.cpp \ + plugin.cpp + +HEADERS += \ + qquickpdfdocument_p.h + +QT += pdf quick-private gui gui-private core core-private qml qml-private + +load(qml_plugin) -- cgit v1.2.3