summaryrefslogtreecommitdiffstats
path: root/src/pdf/qpdfdocument.cpp
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/pdf/qpdfdocument.cpp
parentaf10ffdc4cf31c29a15a83ed7dd9b7ed516585ea (diff)
Provide async loading through QNetworkReply
Diffstat (limited to 'src/pdf/qpdfdocument.cpp')
-rw-r--r--src/pdf/qpdfdocument.cpp168
1 files changed, 151 insertions, 17 deletions
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"