summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Astals Cid <[email protected]>2017-10-03 09:29:18 +0200
committerAlbert Astals Cid <[email protected]>2017-11-09 17:28:54 +0100
commita2f5560c007648ffe753851fbb575d5c8afee6e1 (patch)
tree216edf9c8c6ad5aa43d324b57f48204a87a49b71
parent01ce40b955f9ec9554fa488a8b4e0c307e5e1a31 (diff)
PDF: Support the poppler 0.62 renderToImage with update callback
Summary: This way pages that take more than 500ms to render get updated every so often so that the user can see that the program didn't hang, it's just that it's taking long to render Tags: incremental rendering, partial updates BUGS: 344081 Subscribers: #okular Tags: #okular Differential Revision: https://phabricator.kde.org/D8379
-rw-r--r--core/document.cpp5
-rw-r--r--core/generator.cpp22
-rw-r--r--core/generator.h25
-rw-r--r--core/generator_p.h4
-rw-r--r--core/page.cpp22
-rw-r--r--generators/poppler/CMakeLists.txt13
-rw-r--r--generators/poppler/config-okular-poppler.h.cmake3
-rw-r--r--generators/poppler/generator_pdf.cpp68
8 files changed, 154 insertions, 8 deletions
diff --git a/core/document.cpp b/core/document.cpp
index 9f64d7f..3ac8de1 100644
--- a/core/document.cpp
+++ b/core/document.cpp
@@ -1,6 +1,9 @@
/***************************************************************************
* Copyright (C) 2004-2005 by Enrico Ros <[email protected]> *
* Copyright (C) 2004-2008 by Albert Astals Cid <[email protected]> *
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
+ * company, [email protected] Work sponsored by the *
+ * LiMux project of the city of Munich *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -1426,6 +1429,8 @@ void DocumentPrivate::sendGeneratorPixmapRequest()
request->setNormalizedRect( TilesManager::fromRotatedRect(
request->normalizedRect(), m_rotation ) );
+ request->setPartialUpdatesWanted( request->asynchronous() && !request->page()->hasPixmap( request->observer() ) );
+
// we always have to unlock _before_ the generatePixmap() because
// a sync generation would end with requestDone() -> deadlock, and
// we can not really know if the generator can do async requests
diff --git a/core/generator.cpp b/core/generator.cpp
index 7ab6d17..8e88855 100644
--- a/core/generator.cpp
+++ b/core/generator.cpp
@@ -1,6 +1,9 @@
/***************************************************************************
* Copyright (C) 2005 by Piotr Szymanski <[email protected]> *
* Copyright (C) 2008 by Albert Astals Cid <[email protected]> *
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
+ * company, [email protected] Work sponsored by the *
+ * LiMux project of the city of Munich *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -403,6 +406,14 @@ void Generator::signalTextGenerationDone( Page *page, TextPage *textPage )
delete textPage;
}
+void Generator::signalPartialPixmapRequest( PixmapRequest *request, const QImage &image )
+{
+ request->page()->setPixmap( request->observer(), new QPixmap( QPixmap::fromImage( image ) ), request->normalizedRect() );
+
+ const int pageNumber = request->page()->number();
+ request->observer()->notifyPageChanged( pageNumber, Okular::DocumentObserver::Pixmap );
+}
+
const Document * Generator::document() const
{
Q_D( const Generator );
@@ -500,6 +511,7 @@ PixmapRequest::PixmapRequest( DocumentObserver *observer, int pageNumber, int wi
d->mForce = false;
d->mTile = false;
d->mNormalizedRect = NormalizedRect();
+ d->mPartialUpdatesWanted = false;
}
PixmapRequest::~PixmapRequest()
@@ -570,6 +582,16 @@ const NormalizedRect& PixmapRequest::normalizedRect() const
return d->mNormalizedRect;
}
+void PixmapRequest::setPartialUpdatesWanted(bool partialUpdatesWanted)
+{
+ d->mPartialUpdatesWanted = partialUpdatesWanted;
+}
+
+bool PixmapRequest::partialUpdatesWanted() const
+{
+ return d->mPartialUpdatesWanted;
+}
+
Okular::TilesManager* PixmapRequestPrivate::tilesManager() const
{
return mPage->d->tilesManager(mObserver);
diff --git a/core/generator.h b/core/generator.h
index 23bbd51..5209093 100644
--- a/core/generator.h
+++ b/core/generator.h
@@ -2,6 +2,9 @@
* Copyright (C) 2004-5 by Enrico Ros <[email protected]> *
* Copyright (C) 2005 by Piotr Szymanski <[email protected]> *
* Copyright (C) 2008 by Albert Astals Cid <[email protected]> *
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
+ * company, [email protected] Work sponsored by the *
+ * LiMux project of the city of Munich *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -576,6 +579,13 @@ class OKULARCORE_EXPORT Generator : public QObject
*/
Okular::Generator::PrintError printError() const;
+ /**
+ * This method can be called to trigger a partial pixmap update for the given request
+ * Make sure you call it in a way it's executed in the main thread.
+ * @since 1.3
+ */
+ void signalPartialPixmapRequest( Okular::PixmapRequest *request, const QImage &image );
+
protected:
/// @cond PRIVATE
Generator(GeneratorPrivate &dd, QObject *parent, const QVariantList &args);
@@ -703,6 +713,20 @@ class OKULARCORE_EXPORT PixmapRequest
*/
const NormalizedRect& normalizedRect() const;
+ /**
+ * Sets whether the request should report back updates if possible
+ *
+ * @since 1.3
+ */
+ void setPartialUpdatesWanted(bool partialUpdatesWanted);
+
+ /**
+ * Should the request report back updates if possible?
+ *
+ * @since 1.3
+ */
+ bool partialUpdatesWanted() const;
+
private:
Q_DISABLE_COPY( PixmapRequest )
@@ -713,6 +737,7 @@ class OKULARCORE_EXPORT PixmapRequest
}
Q_DECLARE_METATYPE(Okular::Generator::PrintError)
+Q_DECLARE_METATYPE(Okular::PixmapRequest*)
#define OkularGeneratorInterface_iid "org.kde.okular.Generator"
Q_DECLARE_INTERFACE(Okular::Generator, OkularGeneratorInterface_iid)
diff --git a/core/generator_p.h b/core/generator_p.h
index 6457e7b..616e8fc 100644
--- a/core/generator_p.h
+++ b/core/generator_p.h
@@ -1,5 +1,8 @@
/***************************************************************************
* Copyright (C) 2007 Tobias Koenig <[email protected]> *
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
+ * company, [email protected] Work sponsored by the *
+ * LiMux project of the city of Munich *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -85,6 +88,7 @@ class PixmapRequestPrivate
int mFeatures;
bool mForce : 1;
bool mTile : 1;
+ bool mPartialUpdatesWanted : 1;
Page *mPage;
NormalizedRect mNormalizedRect;
};
diff --git a/core/page.cpp b/core/page.cpp
index ccc05fd..72890e5 100644
--- a/core/page.cpp
+++ b/core/page.cpp
@@ -1,5 +1,9 @@
/***************************************************************************
* Copyright (C) 2004 by Enrico Ros <[email protected]> *
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
+ * company, [email protected] Work sponsored by the *
+ * LiMux project of the city of Munich *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
@@ -210,7 +214,11 @@ bool Page::hasPixmap( DocumentObserver *observer, int width, int height, const N
{
if ( width != tm->width() || height != tm->height() )
{
- tm->setSize( width, height );
+ // FIXME hasPixmap should not be calling setSize on the TilesManager this is not very "const"
+ // as this function claims to be
+ if ( width != -1 && height != -1 ) {
+ tm->setSize( width, height );
+ }
return false;
}
@@ -531,10 +539,14 @@ void Page::setPixmap( DocumentObserver *observer, QPixmap *pixmap, const Normali
it.value().m_pixmap = pixmap;
it.value().m_rotation = d->m_rotation;
} else {
- RotationJob *job = new RotationJob( pixmap->toImage(), Rotation0, d->m_rotation, observer );
- job->setPage( d );
- job->setRect( TilesManager::toRotatedRect( rect, d->m_rotation ) );
- d->m_doc->m_pageController->addRotationJob(job);
+ // it can happen that we get a setPixmap while closing and thus the page controller is gone
+ if ( d->m_doc->m_pageController )
+ {
+ RotationJob *job = new RotationJob( pixmap->toImage(), Rotation0, d->m_rotation, observer );
+ job->setPage( d );
+ job->setRect( TilesManager::toRotatedRect( rect, d->m_rotation ) );
+ d->m_doc->m_pageController->addRotationJob(job);
+ }
delete pixmap;
}
diff --git a/generators/poppler/CMakeLists.txt b/generators/poppler/CMakeLists.txt
index d32f987..a5ad027 100644
--- a/generators/poppler/CMakeLists.txt
+++ b/generators/poppler/CMakeLists.txt
@@ -19,7 +19,7 @@ if (Poppler_VERSION VERSION_GREATER "0.36.99")
set (HAVE_POPPLER_0_37 1)
endif()
-set(CMAKE_REQUIRED_LIBRARIES Poppler::Qt5 Qt5::Core)
+set(CMAKE_REQUIRED_LIBRARIES Poppler::Qt5 Qt5::Core Qt5::Gui)
check_cxx_source_compiles("
#include <poppler-qt5.h>
@@ -50,6 +50,17 @@ int main()
}
" HAVE_POPPLER_0_60)
+check_cxx_source_compiles("
+#include <poppler-qt5.h>
+#include <QImage>
+int main()
+{
+ Poppler::Page *p;
+ p->renderToImage(0, 0, 0, 0, 0, 0, Poppler::Page::Rotate0, nullptr, nullptr, QVariant());
+ return 0;
+}
+" HAVE_POPPLER_0_62)
+
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/config-okular-poppler.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config-okular-poppler.h
diff --git a/generators/poppler/config-okular-poppler.h.cmake b/generators/poppler/config-okular-poppler.h.cmake
index 24878d2..9b8da50 100644
--- a/generators/poppler/config-okular-poppler.h.cmake
+++ b/generators/poppler/config-okular-poppler.h.cmake
@@ -18,3 +18,6 @@
/* Defined if we have the 0.60 version of the Poppler library */
#cmakedefine HAVE_POPPLER_0_60 1
+
+/* Defined if we have the 0.62 version of the Poppler library */
+#cmakedefine HAVE_POPPLER_0_62 1
diff --git a/generators/poppler/generator_pdf.cpp b/generators/poppler/generator_pdf.cpp
index c29f96b..465c3e2 100644
--- a/generators/poppler/generator_pdf.cpp
+++ b/generators/poppler/generator_pdf.cpp
@@ -2,6 +2,9 @@
* Copyright (C) 2004-2008 by Albert Astals Cid <[email protected]> *
* Copyright (C) 2004 by Enrico Ros <[email protected]> *
* Copyright (C) 2012 by Guillermo A. Amaral B. <[email protected]> *
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
+ * company, [email protected] Work sponsored by the *
+ * LiMux project of the city of Munich *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -25,6 +28,7 @@
#include <qtextstream.h>
#include <QPrinter>
#include <QPainter>
+#include <QTimer>
#include <QtCore/QDebug>
#include <KAboutData>
@@ -894,6 +898,44 @@ bool PDFGenerator::isAllowed( Okular::Permission permission ) const
return b;
}
+#ifdef HAVE_POPPLER_0_62
+struct PartialUpdatePayload
+{
+ PartialUpdatePayload(PDFGenerator *g, Okular::PixmapRequest *r) :
+ generator(g), request(r)
+ {
+ // Don't report partial updates for the first 500 ms
+ timer.setInterval(500);
+ timer.setSingleShot(true);
+ timer.start();
+ }
+
+ PDFGenerator *generator;
+ Okular::PixmapRequest *request;
+ QTimer timer;
+};
+Q_DECLARE_METATYPE(PartialUpdatePayload*)
+
+static bool shouldDoPartialUpdateCallback(const QVariant &vPayload)
+{
+ auto payload = vPayload.value<PartialUpdatePayload *>();
+
+ // Since the timer lives in a thread without an event loop we need to stop it ourselves
+ // when the remaining time has reached 0
+ if (payload->timer.isActive() && payload->timer.remainingTime() == 0) {
+ payload->timer.stop();
+ }
+
+ return !payload->timer.isActive();
+}
+
+static void partialUpdateCallback(const QImage &image, const QVariant &vPayload)
+{
+ auto payload = vPayload.value<PartialUpdatePayload *>();
+ QMetaObject::invokeMethod(payload->generator, "signalPartialPixmapRequest", Qt::QueuedConnection, Q_ARG(Okular::PixmapRequest*, payload->request), Q_ARG(QImage, image));
+}
+#endif
+
QImage PDFGenerator::image( Okular::PixmapRequest * request )
{
// debug requests to this (xpdf) generator
@@ -928,11 +970,33 @@ QImage PDFGenerator::image( Okular::PixmapRequest * request )
if ( request->isTile() )
{
QRect rect = request->normalizedRect().geometry( request->width(), request->height() );
- img = p->renderToImage( fakeDpiX, fakeDpiY, rect.x(), rect.y(), rect.width(), rect.height(), Poppler::Page::Rotate0 );
+#ifdef HAVE_POPPLER_0_62
+ if ( request->partialUpdatesWanted() )
+ {
+ PartialUpdatePayload payload( this, request );
+ img = p->renderToImage( fakeDpiX, fakeDpiY, rect.x(), rect.y(), rect.width(), rect.height(), Poppler::Page::Rotate0,
+ partialUpdateCallback, shouldDoPartialUpdateCallback, QVariant::fromValue( &payload ) );
+ }
+ else
+#endif
+ {
+ img = p->renderToImage( fakeDpiX, fakeDpiY, rect.x(), rect.y(), rect.width(), rect.height(), Poppler::Page::Rotate0 );
+ }
}
else
{
- img = p->renderToImage(fakeDpiX, fakeDpiY, -1, -1, -1, -1, Poppler::Page::Rotate0 );
+#ifdef HAVE_POPPLER_0_62
+ if ( request->partialUpdatesWanted() )
+ {
+ PartialUpdatePayload payload(this, request);
+ img = p->renderToImage( fakeDpiX, fakeDpiY, -1, -1, -1, -1, Poppler::Page::Rotate0,
+ partialUpdateCallback, shouldDoPartialUpdateCallback, QVariant::fromValue( &payload ) );
+ }
+ else
+#endif
+ {
+ img = p->renderToImage(fakeDpiX, fakeDpiY, -1, -1, -1, -1, Poppler::Page::Rotate0 );
+ }
}
}
else