Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit a2f5560c authored by Albert Astals Cid's avatar Albert Astals Cid Committed by Albert Astals Cid

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
parent 01ce40b9
/***************************************************************************
* Copyright (C) 2004-2005 by Enrico Ros <eros.kde@email.it> *
* Copyright (C) 2004-2008 by Albert Astals Cid <aacid@kde.org> *
* Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
* company, info@kdab.com. 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
......
/***************************************************************************
* Copyright (C) 2005 by Piotr Szymanski <niedakh@gmail.com> *
* Copyright (C) 2008 by Albert Astals Cid <aacid@kde.org> *
* Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
* company, info@kdab.com. 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);
......
......@@ -2,6 +2,9 @@
* Copyright (C) 2004-5 by Enrico Ros <eros.kde@email.it> *
* Copyright (C) 2005 by Piotr Szymanski <niedakh@gmail.com> *
* Copyright (C) 2008 by Albert Astals Cid <aacid@kde.org> *
* Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
* company, info@kdab.com. 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)
......
/***************************************************************************
* Copyright (C) 2007 Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
* company, info@kdab.com. 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;
};
......
/***************************************************************************
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
* company, info@kdab.com. 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;
}
......
......@@ -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
......
......@@ -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
......@@ -2,6 +2,9 @@
* Copyright (C) 2004-2008 by Albert Astals Cid <aacid@kde.org> *
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
* Copyright (C) 2012 by Guillermo A. Amaral B. <gamaral@kde.org> *
* Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group *
* company, info@kdab.com. 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment