From a7cecb51731d054a89b458d8343e896e8dd9e620 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 15 Dec 2014 12:50:13 +0100 Subject: Implement basic document loading from a file --- src/pdf/jsbridge.cpp | 42 ++++++++++++ src/pdf/pdf.pro | 25 ++++++++ src/pdf/qpdfdocument.cpp | 96 ++++++++++++++++++++++++++++ src/pdf/qpdfdocument.h | 35 ++++++++++ src/pdf/qpdfdocument_p.h | 20 ++++++ src/pdf/qtpdfglobal.h | 23 +++++++ src/qpdf/jsbridge.cpp | 42 ------------ src/qpdf/qpdf.pro | 19 ------ src/src.pro | 2 +- sync.profile | 2 +- tests/auto/auto.pro | 2 + tests/auto/qpdfdocument/qpdfdocument.pro | 6 ++ tests/auto/qpdfdocument/tst_qpdfdocument.cpp | 46 +++++++++++++ tests/tests.pro | 2 + 14 files changed, 299 insertions(+), 63 deletions(-) create mode 100644 src/pdf/jsbridge.cpp create mode 100644 src/pdf/pdf.pro create mode 100644 src/pdf/qpdfdocument.cpp create mode 100644 src/pdf/qpdfdocument.h create mode 100644 src/pdf/qpdfdocument_p.h create mode 100644 src/pdf/qtpdfglobal.h delete mode 100644 src/qpdf/jsbridge.cpp delete mode 100644 src/qpdf/qpdf.pro create mode 100644 tests/auto/auto.pro create mode 100644 tests/auto/qpdfdocument/qpdfdocument.pro create mode 100644 tests/auto/qpdfdocument/tst_qpdfdocument.cpp create mode 100644 tests/tests.pro diff --git a/src/pdf/jsbridge.cpp b/src/pdf/jsbridge.cpp new file mode 100644 index 0000000..3959c3e --- /dev/null +++ b/src/pdf/jsbridge.cpp @@ -0,0 +1,42 @@ + +#include + +#include "fsdk_mgr.h" +#include "javascript/IJavaScript.h" + +CJS_RuntimeFactory::~CJS_RuntimeFactory() +{ +} + +IFXJS_Runtime* CJS_RuntimeFactory::NewJSRuntime(CPDFDoc_Environment* pApp) +{ + Q_UNUSED(pApp); + return 0; +} + +void CJS_RuntimeFactory::DeleteJSRuntime(IFXJS_Runtime* pRuntime) +{ + Q_UNUSED(pRuntime); +} + +void CJS_RuntimeFactory::AddRef() +{ + m_nRef++; +} + +void CJS_RuntimeFactory::Release() +{ + if (--m_nRef) { + // ### Shutdown + } +} + +CJS_GlobalData* CJS_RuntimeFactory::NewGlobalData(CPDFDoc_Environment* pApp) +{ + Q_UNUSED(pApp); + return 0; +} + +void CJS_RuntimeFactory::ReleaseGlobalData() +{ +} diff --git a/src/pdf/pdf.pro b/src/pdf/pdf.pro new file mode 100644 index 0000000..4c3244c --- /dev/null +++ b/src/pdf/pdf.pro @@ -0,0 +1,25 @@ +TARGET = QtQPdf +QT = gui core network +TEMPLATE = lib +CONFIG += c++11 +INCLUDEPATH += ../3rdparty/pdfium/fpdfsdk/include +load(qt_module) + +LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lqtpdfium$$qtPlatformTargetSuffix() + +gcc { + QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter +} + +msvc { + QMAKE_CXXFLAGS_WARN_ON += -wd"4100" +} + +SOURCES += \ + jsbridge.cpp \ + qpdfdocument.cpp + +HEADERS += \ + qpdfdocument.h \ + qpdfdocument_p.h \ + qtpdfglobal.h diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp new file mode 100644 index 0000000..f05310d --- /dev/null +++ b/src/pdf/qpdfdocument.cpp @@ -0,0 +1,96 @@ +#include "qpdfdocument.h" + +#include "qpdfdocument_p.h" + +#include +#include +#include + +static int libraryRefCount; +static QMutex libraryInitializerMutex; + +// PDFium stores the error code when loading a document in a global +// variable, but that is only set from the FPDF_Load*Document functions. +// Therefore this mutex serializes access to the loading. +static QMutex documentLoadMutex; + +QPdfDocumentPrivate::QPdfDocumentPrivate() + : doc(0) +{ + { + QMutexLocker lock(&libraryInitializerMutex); + if (libraryRefCount == 0) + FPDF_InitLibrary(); + ++libraryRefCount; + } +} + +QPdfDocumentPrivate::~QPdfDocumentPrivate() +{ + if (doc) + FPDF_CloseDocument(doc); + doc = 0; + + { + QMutexLocker lock(&libraryInitializerMutex); + if (!--libraryRefCount) + FPDF_DestroyLibrary(); + } +} + +QPdfDocument::QPdfDocument(QObject *parent) + : QObject(parent) + , d(new QPdfDocumentPrivate) +{ +} + +QPdfDocument::~QPdfDocument() +{ +} + +static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size) +{ + QIODevice *dev = reinterpret_cast(param); + dev->seek(position); + return dev->read(reinterpret_cast(pBuf), size); +} + +QPdfDocument::Error QPdfDocument::load(const QString &fileName, const QString &password) +{ + if (d->doc) + FPDF_CloseDocument(d->doc); + + QFile *file = new QFile(fileName); + d->device.reset(file); + + if (!d->device->open(QIODevice::ReadOnly)) + return FileNotFoundError; + + FPDF_FILEACCESS access; + access.m_FileLen = file->size(); + access.m_GetBlock = fpdf_GetBlock; + access.m_Param = d->device.data(); + + d->password = password.toUtf8(); + + QMutexLocker loadLocker(&documentLoadMutex); + d->doc = FPDF_LoadCustomDocument(&access, d->password.constData()); + switch (FPDF_GetLastError()) { + case FPDF_ERR_SUCCESS: return NoError; + case FPDF_ERR_UNKNOWN: return UnknownError; + case FPDF_ERR_FILE: return FileNotFoundError; + case FPDF_ERR_FORMAT: return InvalidFileFormatError; + case FPDF_ERR_PASSWORD: return IncorrectPasswordError; + case FPDF_ERR_SECURITY: return UnsupportedSecuritySchemeError; + default: + Q_UNREACHABLE(); + } + return UnknownError; +} + +int QPdfDocument::pageCount() const +{ + if (!d->doc) + return 0; + return FPDF_GetPageCount(d->doc); +} diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h new file mode 100644 index 0000000..32baebb --- /dev/null +++ b/src/pdf/qpdfdocument.h @@ -0,0 +1,35 @@ +#ifndef QPDFDOCUMENT_H +#define QPDFDOCUMENT_H + +#include +#include "qtpdfglobal.h" + +class QPdfDocumentPrivate; + +class Q_PDF_EXPORT QPdfDocument : public QObject +{ + Q_OBJECT + Q_PROPERTY(int pageCount READ pageCount FINAL) +public: + + enum Error { + NoError, + UnknownError, + FileNotFoundError, + InvalidFileFormatError, + IncorrectPasswordError, + UnsupportedSecuritySchemeError + }; + + explicit QPdfDocument(QObject *parent = 0); + ~QPdfDocument(); + + Error load(const QString &fileName, const QString &password = QString()); + + int pageCount() const; + +private: + QScopedPointer d; +}; + +#endif // QPDFDOCUMENT_H diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h new file mode 100644 index 0000000..5a30b1f --- /dev/null +++ b/src/pdf/qpdfdocument_p.h @@ -0,0 +1,20 @@ +#ifndef QPDFDOCUMENT_P_H +#define QPDFDOCUMENT_P_H + +#include "fpdfview.h" + +#include + +class QPdfDocumentPrivate +{ +public: + QPdfDocumentPrivate(); + ~QPdfDocumentPrivate(); + + FPDF_DOCUMENT doc; + QScopedPointer device; + QByteArray password; +}; + +#endif // QPDFDOCUMENT_P_H + diff --git a/src/pdf/qtpdfglobal.h b/src/pdf/qtpdfglobal.h new file mode 100644 index 0000000..a4b6d53 --- /dev/null +++ b/src/pdf/qtpdfglobal.h @@ -0,0 +1,23 @@ +#ifndef QTPDFGLOBAL_H +#define QTPDFGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef Q_PDF_EXPORT +# ifndef QT_STATIC +# if defined(QT_BUILD_PDF_LIB) +# define Q_PDF_EXPORT Q_DECL_EXPORT +# else +# define Q_PDF_EXPORT Q_DECL_IMPORT +# endif +# else +# define Q_PDF_EXPORT +# endif +#endif + +QT_END_NAMESPACE + +#endif // QTPDFGLOBAL_H + diff --git a/src/qpdf/jsbridge.cpp b/src/qpdf/jsbridge.cpp deleted file mode 100644 index 3959c3e..0000000 --- a/src/qpdf/jsbridge.cpp +++ /dev/null @@ -1,42 +0,0 @@ - -#include - -#include "fsdk_mgr.h" -#include "javascript/IJavaScript.h" - -CJS_RuntimeFactory::~CJS_RuntimeFactory() -{ -} - -IFXJS_Runtime* CJS_RuntimeFactory::NewJSRuntime(CPDFDoc_Environment* pApp) -{ - Q_UNUSED(pApp); - return 0; -} - -void CJS_RuntimeFactory::DeleteJSRuntime(IFXJS_Runtime* pRuntime) -{ - Q_UNUSED(pRuntime); -} - -void CJS_RuntimeFactory::AddRef() -{ - m_nRef++; -} - -void CJS_RuntimeFactory::Release() -{ - if (--m_nRef) { - // ### Shutdown - } -} - -CJS_GlobalData* CJS_RuntimeFactory::NewGlobalData(CPDFDoc_Environment* pApp) -{ - Q_UNUSED(pApp); - return 0; -} - -void CJS_RuntimeFactory::ReleaseGlobalData() -{ -} diff --git a/src/qpdf/qpdf.pro b/src/qpdf/qpdf.pro deleted file mode 100644 index ebe3c73..0000000 --- a/src/qpdf/qpdf.pro +++ /dev/null @@ -1,19 +0,0 @@ -TARGET = QtQPdf -QT = gui core network -TEMPLATE = lib -CONFIG += c++11 -INCLUDEPATH += ../3rdparty/pdfium/fpdfsdk/include -load(qt_module) - -LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lqtpdfium$$qtPlatformTargetSuffix() - -gcc { - QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter -} - -msvc { - QMAKE_CXXFLAGS_WARN_ON += -wd"4100" -} - -SOURCES += \ - jsbridge.cpp diff --git a/src/src.pro b/src/src.pro index d2216d4..f1d52eb 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = 3rdparty lib qpdf +SUBDIRS = 3rdparty lib pdf diff --git a/sync.profile b/sync.profile index c9d0e17..0fe0418 100644 --- a/sync.profile +++ b/sync.profile @@ -1,5 +1,5 @@ %modules = ( # path to module name map - "QtQPdf" => "$basedir/src/qpdf", + "QtQPdf" => "$basedir/src/pdf", ); # Module dependencies. # Every module that is required to build this module should have one entry. diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro new file mode 100644 index 0000000..41c081c --- /dev/null +++ b/tests/auto/auto.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = qpdfdocument diff --git a/tests/auto/qpdfdocument/qpdfdocument.pro b/tests/auto/qpdfdocument/qpdfdocument.pro new file mode 100644 index 0000000..28e56e0 --- /dev/null +++ b/tests/auto/qpdfdocument/qpdfdocument.pro @@ -0,0 +1,6 @@ +CONFIG += testcase +TARGET = tst_qpdfdocument +QT += pdf printsupport testlib +macx:CONFIG -= app_bundle +SOURCES += tst_qpdfdocument.cpp + diff --git a/tests/auto/qpdfdocument/tst_qpdfdocument.cpp b/tests/auto/qpdfdocument/tst_qpdfdocument.cpp new file mode 100644 index 0000000..080f808 --- /dev/null +++ b/tests/auto/qpdfdocument/tst_qpdfdocument.cpp @@ -0,0 +1,46 @@ + +#include + +#include +#include +#include +#include + +class tst_QPdfDocument: public QObject +{ + Q_OBJECT +public: + +private slots: + void pageCount(); +}; + + +void tst_QPdfDocument::pageCount() +{ + QTemporaryFile tempPdf; + tempPdf.setAutoRemove(true); + QVERIFY(tempPdf.open()); + { + QPrinter printer; + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setOutputFileName(tempPdf.fileName()); + + { + QPainter painter(&printer); + painter.drawText(0, 0, QStringLiteral("Hello Page 1")); + printer.newPage(); + painter.drawText(0, 0, QStringLiteral("Hello Page 2")); + } + } + + QPdfDocument doc; + QCOMPARE(doc.pageCount(), 0); + QCOMPARE(doc.load(tempPdf.fileName()), QPdfDocument::NoError); + QCOMPARE(doc.pageCount(), 2); +} + +QTEST_MAIN(tst_QPdfDocument) + +#include "tst_qpdfdocument.moc" + diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..7fbc8a9 --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = auto -- cgit v1.2.3