summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-15 17:40:41 +0100
committerMichal Klocek <michal.klocek@qt.io>2019-11-25 12:01:38 +0100
commit09ad4d74cea40dd3d88c0a39b1dcbc8db5347c6e (patch)
tree2fcbecba988dabb521c6fe2ff6feb7b497a77b32 /src
parentaf10ffdc4cf31c29a15a83ed7dd9b7ed516585ea (diff)
Provide async loading through QNetworkReply
Diffstat (limited to 'src')
-rw-r--r--src/pdf/pdf.pro3
-rw-r--r--src/pdf/qpdfdocument.cpp168
-rw-r--r--src/pdf/qpdfdocument.h17
-rw-r--r--src/pdf/qpdfdocument_p.h23
4 files changed, 189 insertions, 22 deletions
diff --git a/src/pdf/pdf.pro b/src/pdf/pdf.pro
index 4c3244c87..811a9468d 100644
--- a/src/pdf/pdf.pro
+++ b/src/pdf/pdf.pro
@@ -1,5 +1,6 @@
TARGET = QtQPdf
-QT = gui core network
+QT += gui core
+QT_PRIVATE += network
TEMPLATE = lib
CONFIG += c++11
INCLUDEPATH += ../3rdparty/pdfium/fpdfsdk/include
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp
index d6aed7451..3eeef297f 100644
--- a/src/pdf/qpdfdocument.cpp
+++ b/src/pdf/qpdfdocument.cpp
@@ -11,7 +11,9 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive));
static int libraryRefCount;
QPdfDocumentPrivate::QPdfDocumentPrivate()
- : doc(0)
+ : avail(0)
+ , doc(0)
+ , lastError(QPdfDocument::NoError)
{
QMutexLocker lock(pdfMutex());
if (libraryRefCount == 0)
@@ -21,25 +23,58 @@ QPdfDocumentPrivate::QPdfDocumentPrivate()
// FPDF_FILEACCESS setup
m_Param = this;
m_GetBlock = fpdf_GetBlock;
+
+ // FX_FILEAVAIL setup
+ FX_FILEAVAIL::version = 1;
+ IsDataAvail = fpdf_IsDataAvail;
+
+ // FX_DOWNLOADHINTS setup
+ FX_DOWNLOADHINTS::version = 1;
+ AddSegment = fpdf_AddSegment;
}
QPdfDocumentPrivate::~QPdfDocumentPrivate()
{
QMutexLocker lock(pdfMutex());
- if (doc)
- FPDF_CloseDocument(doc);
- doc = 0;
+
+ clear();
if (!--libraryRefCount)
FPDF_DestroyLibrary();
}
-QPdfDocument::Error QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership, const QString &documentPassword)
+void QPdfDocumentPrivate::clear()
{
- QMutexLocker lock(pdfMutex());
-
if (doc)
FPDF_CloseDocument(doc);
+ doc = 0;
+
+ if (avail)
+ FPDFAvail_Destroy(avail);
+ avail = 0;
+
+ asyncBuffer.close();
+ asyncBuffer.setData(QByteArray());
+ asyncBuffer.open(QIODevice::ReadWrite);
+}
+
+void QPdfDocumentPrivate::setErrorCode()
+{
+ switch (FPDF_GetLastError()) {
+ case FPDF_ERR_SUCCESS: lastError = QPdfDocument::NoError; break;
+ case FPDF_ERR_UNKNOWN: lastError = QPdfDocument::UnknownError; break;
+ case FPDF_ERR_FILE: lastError = QPdfDocument::FileNotFoundError; break;
+ case FPDF_ERR_FORMAT: lastError = QPdfDocument::InvalidFileFormatError; break;
+ case FPDF_ERR_PASSWORD: lastError = QPdfDocument::IncorrectPasswordError; break;
+ case FPDF_ERR_SECURITY: lastError = QPdfDocument::UnsupportedSecuritySchemeError; break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+QPdfDocument::Error QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership, const QString &documentPassword)
+{
+ clear();
if (transferDeviceOwnership)
ownDevice.reset(newDevice);
@@ -56,17 +91,66 @@ QPdfDocument::Error QPdfDocumentPrivate::load(QIODevice *newDevice, bool transfe
password = documentPassword.toUtf8();
doc = FPDF_LoadCustomDocument(this, password.constData());
- switch (FPDF_GetLastError()) {
- case FPDF_ERR_SUCCESS: return QPdfDocument::NoError;
- case FPDF_ERR_UNKNOWN: return QPdfDocument::UnknownError;
- case FPDF_ERR_FILE: return QPdfDocument::FileNotFoundError;
- case FPDF_ERR_FORMAT: return QPdfDocument::InvalidFileFormatError;
- case FPDF_ERR_PASSWORD: return QPdfDocument::IncorrectPasswordError;
- case FPDF_ERR_SECURITY: return QPdfDocument::UnsupportedSecuritySchemeError;
- default:
- Q_UNREACHABLE();
+ setErrorCode();
+ return lastError;
+}
+
+void QPdfDocumentPrivate::_q_initiateAsyncLoad()
+{
+ QMutexLocker lock(pdfMutex());
+ if (avail)
+ return;
+
+ QVariant contentLength = remoteDevice->header(QNetworkRequest::ContentLengthHeader);
+ if (!contentLength.isValid())
+ return;
+
+ // FPDF_FILEACCESS setup
+ m_FileLen = contentLength.toULongLong();
+
+ QObject::connect(remoteDevice, SIGNAL(readyRead()), q, SLOT(_q_readFromDevice()));
+
+ avail = FPDFAvail_Create(this, this);
+
+ if (remoteDevice->bytesAvailable())
+ _q_readFromDevice();
+}
+
+void QPdfDocumentPrivate::_q_readFromDevice()
+{
+ QMutexLocker lock(pdfMutex());
+ QByteArray data = remoteDevice->read(remoteDevice->bytesAvailable());
+ if (data.isEmpty())
+ return;
+ asyncBuffer.seek(asyncBuffer.size());
+ asyncBuffer.write(data);
+
+ if (!doc) {
+ tryLoadDocument();
+ }
+}
+
+void QPdfDocumentPrivate::tryLoadDocument()
+{
+ if (!FPDFAvail_IsDocAvail(avail, this))
+ return;
+
+ Q_ASSERT(!doc);
+
+ doc = FPDFAvail_GetDocument(avail, password);
+ if (!doc) {
+ setErrorCode();
+ if (lastError == QPdfDocument::IncorrectPasswordError)
+ emit q->passwordRequired();
}
- return QPdfDocument::UnknownError;
+ if (doc)
+ emit q->documentReady();
+}
+
+bool QPdfDocumentPrivate::fpdf_IsDataAvail(_FX_FILEAVAIL *pThis, size_t offset, size_t size)
+{
+ QPdfDocumentPrivate *d = static_cast<QPdfDocumentPrivate*>(pThis);
+ return offset + size <= static_cast<quint64>(d->asyncBuffer.size());
}
int QPdfDocumentPrivate::fpdf_GetBlock(void *param, unsigned long position, unsigned char *pBuf, unsigned long size)
@@ -77,10 +161,18 @@ int QPdfDocumentPrivate::fpdf_GetBlock(void *param, unsigned long position, unsi
}
+void QPdfDocumentPrivate::fpdf_AddSegment(_FX_DOWNLOADHINTS *pThis, size_t offset, size_t size)
+{
+ Q_UNUSED(pThis);
+ Q_UNUSED(offset);
+ Q_UNUSED(size);
+}
+
QPdfDocument::QPdfDocument(QObject *parent)
: QObject(parent)
, d(new QPdfDocumentPrivate)
{
+ d->q = this;
}
QPdfDocument::~QPdfDocument()
@@ -89,14 +181,54 @@ QPdfDocument::~QPdfDocument()
QPdfDocument::Error QPdfDocument::load(const QString &fileName, const QString &password)
{
+ QMutexLocker lock(pdfMutex());
return d->load(new QFile(fileName), /*transfer ownership*/true, password);
}
QPdfDocument::Error QPdfDocument::load(QIODevice *device, const QString &password)
{
+ QMutexLocker lock(pdfMutex());
return d->load(device, /*transfer ownership*/false, password);
}
+void QPdfDocument::loadAsynchronously(QNetworkReply *device)
+{
+ QMutexLocker lock(pdfMutex());
+ d->clear();
+
+ d->ownDevice.reset();
+ d->device = &d->asyncBuffer;
+
+ if (d->remoteDevice)
+ d->remoteDevice->disconnect(this);
+
+ d->remoteDevice = device;
+
+ if (d->remoteDevice->header(QNetworkRequest::ContentLengthHeader).isValid())
+ d->_q_initiateAsyncLoad();
+ else
+ connect(d->remoteDevice, SIGNAL(metaDataChanged()), this, SLOT(_q_initiateAsyncLoad()));
+}
+
+void QPdfDocument::setPassword(const QString &password)
+{
+ QMutexLocker lock(pdfMutex());
+ d->password = password.toUtf8();
+
+ if (!d->doc && d->avail)
+ d->tryLoadDocument();
+}
+
+QString QPdfDocument::password() const
+{
+ return QString::fromUtf8(d->password);
+}
+
+QPdfDocument::Error QPdfDocument::error() const
+{
+ return d->lastError;
+}
+
int QPdfDocument::pageCount() const
{
if (!d->doc)
@@ -135,3 +267,5 @@ QImage QPdfDocument::render(int page, const QSizeF &pageSize)
FPDFBitmap_Destroy(bitmap);
return result;
}
+
+#include "moc_qpdfdocument.cpp"
diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h
index b33f0fe29..df6e69fd9 100644
--- a/src/pdf/qpdfdocument.h
+++ b/src/pdf/qpdfdocument.h
@@ -6,11 +6,13 @@
#include "qtpdfglobal.h"
class QPdfDocumentPrivate;
+class QNetworkReply;
class Q_PDF_EXPORT QPdfDocument : public QObject
{
Q_OBJECT
- Q_PROPERTY(int pageCount READ pageCount FINAL)
+ Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL)
+ Q_PROPERTY(QString password READ password WRITE setPassword FINAL)
public:
enum Error {
@@ -28,13 +30,26 @@ public:
Error load(const QString &fileName, const QString &password = QString());
Error load(QIODevice *device, const QString &password = QString());
+ void loadAsynchronously(QNetworkReply *device);
+ void setPassword(const QString &password);
+ QString password() const;
+
+ Error error() const;
+
int pageCount() const;
QSizeF pageSize(int page) const;
QImage render(int page, const QSizeF &pageSize);
+Q_SIGNALS:
+ void passwordRequired();
+ void documentReady();
+ void pageCountChanged();
+
private:
+ Q_PRIVATE_SLOT(d, void _q_initiateAsyncLoad())
+ Q_PRIVATE_SLOT(d, void _q_readFromDevice())
QScopedPointer<QPdfDocumentPrivate> d;
};
diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h
index 7f9b10220..ec9e2e3ae 100644
--- a/src/pdf/qpdfdocument_p.h
+++ b/src/pdf/qpdfdocument_p.h
@@ -5,24 +5,41 @@
#include "fpdf_dataavail.h"
#include "qpdfdocument.h"
-#include <qiodevice.h>
+#include <qbuffer.h>
+#include <qnetworkreply.h>
-class QPdfDocumentPrivate: public FPDF_FILEACCESS
+class QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS
{
public:
QPdfDocumentPrivate();
~QPdfDocumentPrivate();
+ QPdfDocument *q;
+
+ FPDF_AVAIL avail;
FPDF_DOCUMENT doc;
- QIODevice *device;
+ QPointer<QIODevice> device;
QScopedPointer<QIODevice> ownDevice;
+ QBuffer asyncBuffer;
+ QPointer<QNetworkReply> remoteDevice;
QByteArray password;
+ QPdfDocument::Error lastError;
+
+ void clear();
+
QPdfDocument::Error load(QIODevice *device, bool ownDevice, const QString &documentPassword);
+ void loadAsync(QIODevice *device);
+
+ void _q_initiateAsyncLoad();
+ void _q_readFromDevice();
+ void tryLoadDocument();
static bool fpdf_IsDataAvail(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size);
static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size);
+ static void fpdf_AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size);
+ void setErrorCode();
};
#endif // QPDFDOCUMENT_P_H