mirror of
https://invent.kde.org/graphics/okular
synced 2024-08-27 11:40:07 +00:00
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
This commit is contained in:
parent
01ce40b955
commit
a2f5560c00
|
@ -1,6 +1,9 @@
|
|||
/***************************************************************************
|
||||
* 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
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/***************************************************************************
|
||||
* 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)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/***************************************************************************
|
||||
* 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;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
/***************************************************************************
|
||||
* 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
|
||||
|
|
Loading…
Reference in a new issue