summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-15 12:50:13 +0100
committerSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-15 12:50:13 +0100
commita7cecb51731d054a89b458d8343e896e8dd9e620 (patch)
treef65e7956769aa5133980fde8f177dd799f2dab9f
parent3c152e3703c74f468edb3ea7de9992bfc612dc04 (diff)
Implement basic document loading from a file
-rw-r--r--src/pdf/jsbridge.cpp (renamed from src/qpdf/jsbridge.cpp)0
-rw-r--r--src/pdf/pdf.pro (renamed from src/qpdf/qpdf.pro)8
-rw-r--r--src/pdf/qpdfdocument.cpp96
-rw-r--r--src/pdf/qpdfdocument.h35
-rw-r--r--src/pdf/qpdfdocument_p.h20
-rw-r--r--src/pdf/qtpdfglobal.h23
-rw-r--r--src/src.pro2
-rw-r--r--sync.profile2
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/qpdfdocument/qpdfdocument.pro6
-rw-r--r--tests/auto/qpdfdocument/tst_qpdfdocument.cpp46
-rw-r--r--tests/tests.pro2
12 files changed, 239 insertions, 3 deletions
diff --git a/src/qpdf/jsbridge.cpp b/src/pdf/jsbridge.cpp
index 3959c3e..3959c3e 100644
--- a/src/qpdf/jsbridge.cpp
+++ b/src/pdf/jsbridge.cpp
diff --git a/src/qpdf/qpdf.pro b/src/pdf/pdf.pro
index ebe3c73..4c3244c 100644
--- a/src/qpdf/qpdf.pro
+++ b/src/pdf/pdf.pro
@@ -16,4 +16,10 @@ msvc {
}
SOURCES += \
- jsbridge.cpp
+ 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 <QFile>
+#include <QIODevice>
+#include <QMutex>
+
+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<QIODevice*>(param);
+ dev->seek(position);
+ return dev->read(reinterpret_cast<char *>(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 <QObject>
+#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<QPdfDocumentPrivate> 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 <qiodevice.h>
+
+class QPdfDocumentPrivate
+{
+public:
+ QPdfDocumentPrivate();
+ ~QPdfDocumentPrivate();
+
+ FPDF_DOCUMENT doc;
+ QScopedPointer<QIODevice> 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 <QtCore/qglobal.h>
+
+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/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 <QtTest/QtTest>
+
+#include <QPainter>
+#include <QPdfDocument>
+#include <QPrinter>
+#include <QTemporaryFile>
+
+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