From 744915f243f5dcaaafc0e79f6194fbe811d4c757 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 2 Nov 2011 22:13:19 +0100 Subject: [PATCH] Remove thread from the pdf generator Generator already provides a nice way to thread requests so we don't need a custom one here. AFAIR it existed because this code predates the base generator threading mechanism --- generators/poppler/generator_pdf.cpp | 326 +-------------------------- generators/poppler/generator_pdf.h | 48 +--- 2 files changed, 11 insertions(+), 363 deletions(-) diff --git a/generators/poppler/generator_pdf.cpp b/generators/poppler/generator_pdf.cpp index 07937b331..d88da808a 100644 --- a/generators/poppler/generator_pdf.cpp +++ b/generators/poppler/generator_pdf.cpp @@ -298,12 +298,13 @@ static void PDFGeneratorPopplerDebugFunction(const QString &message, const QVari #endif PDFGenerator::PDFGenerator( QObject *parent, const QVariantList &args ) - : Generator( parent, args ), pdfdoc( 0 ), ready( true ), - pixmapRequest( 0 ), docInfoDirty( true ), docSynopsisDirty( true ), + : Generator( parent, args ), pdfdoc( 0 ), + docInfoDirty( true ), docSynopsisDirty( true ), docEmbeddedFilesDirty( true ), nextFontPage( 0 ), dpiX( 72.0 /*Okular::Utils::dpiX()*/ ), dpiY( 72.0 /*Okular::Utils::dpiY()*/ ), synctex_scanner(0) { + setFeature( Threaded ); setFeature( TextExtraction ); setFeature( FontInfo ); #ifdef Q_OS_WIN32 @@ -314,9 +315,6 @@ PDFGenerator::PDFGenerator( QObject *parent, const QVariantList &args ) if ( Okular::FilePrinter::ps2pdfAvailable() ) setFeature( PrintToFile ); setFeature( ReadRawData ); - // generate the pixmapGeneratorThread - generatorThread = new PDFPixmapGeneratorThread( this ); - connect(generatorThread, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection); #ifdef HAVE_POPPLER_0_16 // You only need to do it once not for each of the documents but it is cheap enough @@ -327,13 +325,6 @@ PDFGenerator::PDFGenerator( QObject *parent, const QVariantList &args ) PDFGenerator::~PDFGenerator() { - // stop and delete the generator thread - if ( generatorThread ) - { - generatorThread->wait(); - delete generatorThread; - } - delete pdfOptionsPage; } @@ -768,33 +759,11 @@ bool PDFGenerator::isAllowed( Okular::Permission permission ) const return b; } -bool PDFGenerator::canGeneratePixmap() const -{ - return ready; -} - -void PDFGenerator::generatePixmap( Okular::PixmapRequest * request ) +QImage PDFGenerator::image( Okular::PixmapRequest * request ) { -#ifndef NDEBUG - if ( !ready ) - kDebug(PDFDebug) << "calling generatePixmap() when not in READY state!"; -#endif - // update busy state (not really needed here, because the flag needs to - // be set only to prevent asking a pixmap while the thread is running) - ready = false; - // debug requests to this (xpdf) generator //kDebug(PDFDebug) << "id: " << request->id << " is requesting " << (request->async ? "ASYNC" : "sync") << " pixmap for page " << request->page->number() << " [" << request->width << " x " << request->height << "]."; - /** asynchronous requests (generation in PDFPixmapGeneratorThread::run() **/ - if ( request->asynchronous() ) - { - // start the generation into the thread - generatorThread->startGeneration( request ); - return; - } - - /** synchronous request: in-place generation **/ // compute dpi used to get an image with desired width and height Okular::Page * page = request->page(); @@ -807,10 +776,6 @@ void PDFGenerator::generatePixmap( Okular::PixmapRequest * request ) double fakeDpiX = request->width() * dpiX / pageWidth, fakeDpiY = request->height() * dpiY / pageHeight; - // setup Okular:: output device: text page is generated only if we are at 72dpi. - // since we can pre-generate the TextPage at the right res.. why not? - bool genTextPage = !page->hasTextPage() && (request->width() == page->width()) && - (request->height() == page->height()); // generate links rects only the first time bool genObjectRects = !rectsGenerated.at( page->number() ); @@ -822,19 +787,15 @@ void PDFGenerator::generatePixmap( Okular::PixmapRequest * request ) Poppler::Page *p = pdfdoc->page(page->number()); // 2. Take data from outputdev and attach it to the Page + QImage img; if (p) { - QImage img( p->renderToImage(fakeDpiX, fakeDpiY, -1, -1, -1, -1, Poppler::Page::Rotate0 ) ); - if ( !page->isBoundingBoxKnown() ) - updatePageBoundingBox( page->number(), Okular::Utils::imageBoundingBox( &img ) ); - - page->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( img ) ) ); + img = p->renderToImage(fakeDpiX, fakeDpiY, -1, -1, -1, -1, Poppler::Page::Rotate0 ); } else { - QPixmap *dummyPixmap = new QPixmap( request->width(), request->height() ); - dummyPixmap->fill( Qt::white ); - page->setPixmap( request->id(), dummyPixmap ); + img = QImage( request->width(), request->height(), QImage::Format_Mono ); + img.fill( Qt::white ); } if ( p && genObjectRects ) @@ -848,24 +809,10 @@ void PDFGenerator::generatePixmap( Okular::PixmapRequest * request ) // 3. UNLOCK [re-enables shared access] userMutex()->unlock(); - if ( p && genTextPage ) - { - QList textList = p->textList(); - const QSizeF s = p->pageSizeF(); - Okular::TextPage *tp = abstractTextPage(textList, s.height(), s.width(), request->page()->orientation()); - page->setTextPage( tp ); - qDeleteAll(textList); - - // notify the new generation - signalTextGenerationDone( page, tp ); - } + delete p; - // update ready state - ready = true; - - // notify the new generation - signalPixmapRequestDone( request ); + return img; } Okular::TextPage* PDFGenerator::textPage( Okular::Page *page ) @@ -1698,259 +1645,6 @@ bool PDFGenerator::save( const QString &fileName, SaveOptions options, QString * return success; } -void PDFGenerator::threadFinished() -{ -#if 0 - // check if thread is running (has to be stopped now) - if ( generatorThread->running() ) - { - // if so, wait for effective thread termination - if ( !generatorThread->wait( 9999 /*10s timeout*/ ) ) - { - kWarning(PDFDebug) << "PDFGenerator: thread sent 'data available' " - << "signal but had problems ending."; - return; - } -} -#endif - - // 1. the mutex must be unlocked now - bool isLocked = true; - if (userMutex()->tryLock()) { - userMutex()->unlock(); - isLocked = false; - } - if ( isLocked ) - { - kWarning(PDFDebug) << "PDFGenerator: 'data available' but mutex still " - << "held. Recovering."; - // synchronize GUI thread (must not happen) - userMutex()->lock(); - userMutex()->unlock(); - } - - // 2. put thread's generated data into the Okular::Page - Okular::PixmapRequest * request = generatorThread->request(); - QImage * outImage = generatorThread->takeImage(); - QList outText = generatorThread->takeText(); - QLinkedList< Okular::ObjectRect * > outRects = generatorThread->takeObjectRects(); - - if ( !request->page()->isBoundingBoxKnown() ) - updatePageBoundingBox( request->page()->number(), Okular::Utils::imageBoundingBox( outImage ) ); - request->page()->setPixmap( request->id(), new QPixmap( QPixmap::fromImage( *outImage ) ) ); - delete outImage; - if ( !outText.isEmpty() ) - { - Poppler::Page *pp = pdfdoc->page( request->page()->number() ); - const QSizeF s = pp->pageSizeF(); - Okular::TextPage *tp = abstractTextPage( outText, s.height(), - s.width(),request->page()->orientation()); - request->page()->setTextPage( tp ); - qDeleteAll(outText); - delete pp; - - // notify the new generation - signalTextGenerationDone( request->page(), tp ); - } - bool genObjectRects = !rectsGenerated.at( request->page()->number() ); - if (genObjectRects) - { - request->page()->setObjectRects( outRects ); - rectsGenerated[ request->page()->number() ] = true; - } - else - qDeleteAll( outRects ); - - // 3. tell generator that data has been taken - generatorThread->endGeneration(); - - // update ready state - ready = true; - // notify the new generation - signalPixmapRequestDone( request ); -} - - - -/** The PDF Pixmap Generator Thread **/ - -struct PPGThreadPrivate -{ - // reference to main objects - PDFGenerator * generator; - Okular::PixmapRequest * currentRequest; - - // internal temp stored items. don't delete this. - QImage * m_image; - QList m_textList; - QLinkedList< Okular::ObjectRect * > m_rects; - bool m_rectsTaken; -}; - -PDFPixmapGeneratorThread::PDFPixmapGeneratorThread( PDFGenerator * gen ) - : QThread(), d( new PPGThreadPrivate() ) -{ - d->generator = gen; - d->currentRequest = 0; - d->m_image = 0; - d->m_rectsTaken = true; -} - -PDFPixmapGeneratorThread::~PDFPixmapGeneratorThread() -{ - // delete internal objects if the class is deleted before the gui thread - // takes the data - delete d->m_image; - qDeleteAll(d->m_textList); - if ( !d->m_rectsTaken && d->m_rects.count() ) - { - qDeleteAll(d->m_rects); - } - delete d->currentRequest; - // delete internal storage structure - delete d; -} - -void PDFPixmapGeneratorThread::startGeneration( Okular::PixmapRequest * request ) -{ -#ifndef NDEBUG - // check if a generation is already running - if ( d->currentRequest ) - { - kDebug(PDFDebug) << "PDFPixmapGeneratorThread: requesting a pixmap " - << "when another is being generated."; - delete request; - return; - } - - // check if the mutex is already held - bool isLocked = true; - if (d->generator->userMutex()->tryLock()) { - d->generator->userMutex()->unlock(); - isLocked = false; - } - if ( isLocked ) - { - kDebug(PDFDebug) << "PDFPixmapGeneratorThread: requesting a pixmap " - << "with the mutex already held."; - delete request; - return; - } -#endif - // set generation parameters and run thread - d->currentRequest = request; - start( QThread::InheritPriority ); -} - -void PDFPixmapGeneratorThread::endGeneration() -{ -#ifndef NDEBUG - // check if a generation is already running - if ( !d->currentRequest ) - { - kDebug(PDFDebug) << "PDFPixmapGeneratorThread: 'end generation' called " - << "but generation was not started."; - return; - } -#endif - // reset internal members preparing for a new generation - d->currentRequest = 0; -} - -Okular::PixmapRequest *PDFPixmapGeneratorThread::request() const -{ - return d->currentRequest; -} - -QImage * PDFPixmapGeneratorThread::takeImage() const -{ - QImage * img = d->m_image; - d->m_image = 0; - return img; -} - -QList PDFPixmapGeneratorThread::takeText() -{ - QList tl = d->m_textList; - d->m_textList.clear(); - return tl; -} - -QLinkedList< Okular::ObjectRect * > PDFPixmapGeneratorThread::takeObjectRects() const -{ - d->m_rectsTaken = true; - QLinkedList< Okular::ObjectRect * > newrects = d->m_rects; - d->m_rects.clear(); - return newrects; -} - -void PDFPixmapGeneratorThread::run() -// perform contents generation, when the MUTEX is already LOCKED -// @see PDFGenerator::generatePixmap( .. ) (and be aware to sync the code) -{ - // compute dpi used to get an image with desired width and height - Okular::Page * page = d->currentRequest->page(); - int width = d->currentRequest->width(), - height = d->currentRequest->height(); - double pageWidth = page->width(), - pageHeight = page->height(); - - if ( page->rotation() % 2 ) - qSwap( pageWidth, pageHeight ); - - // setup Okular:: output device: text page is generated only if we are at 72dpi. - // since we can pre-generate the TextPage at the right res.. why not? - bool genTextPage = !page->hasTextPage() && - ( width == page->width() ) && - ( height == page->height() ); - - // generate links rects only the first time - bool genObjectRects = !d->generator->rectsGenerated.at( page->number() ); - - // 0. LOCK s[tart locking XPDF thread unsafe classes] - d->generator->userMutex()->lock(); - - // 1. set OutputDev parameters and Generate contents - Poppler::Page *pp = d->generator->pdfdoc->page( page->number() ); - - if (pp) - { - double fakeDpiX = width * d->generator->dpiX / pageWidth, - fakeDpiY = height * d->generator->dpiY / pageHeight; - - // 2. grab data from the OutputDev and store it locally (note takeIMAGE) -#ifndef NDEBUG - if ( d->m_image ) - kDebug(PDFDebug) << "PDFPixmapGeneratorThread: previous image not taken"; - if ( !d->m_textList.isEmpty() ) - kDebug(PDFDebug) << "PDFPixmapGeneratorThread: previous text not taken"; -#endif - d->m_image = new QImage( pp->renderToImage( fakeDpiX, fakeDpiY, -1, -1, -1, -1, Poppler::Page::Rotate0 ) ); - - if ( genObjectRects ) - { - d->m_rects = generateLinks(pp->links()); - } - else d->m_rectsTaken = false; - - if ( genTextPage ) - { - d->m_textList = pp->textList(); - } - delete pp; - } - else - { - d->m_image = new QImage( width, height, QImage::Format_ARGB32 ); - d->m_image->fill( Qt::white ); - } - - // 3. [UNLOCK] mutex - d->generator->userMutex()->unlock(); - - // by ending the thread notifies the GUI thread that data is pending and can be read -} - #include "generator_pdf.moc" /* kate: replace-tabs on; indent-width 4; */ diff --git a/generators/poppler/generator_pdf.h b/generators/poppler/generator_pdf.h index 64a52d848..f227abe4e 100644 --- a/generators/poppler/generator_pdf.h +++ b/generators/poppler/generator_pdf.h @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -33,7 +32,6 @@ class SourceReference; } class PDFOptionsPage; -class PDFPixmapGeneratorThread; /** * @short A generator that builds contents from a PDF document. @@ -46,8 +44,6 @@ class PDFPixmapGeneratorThread; * For generating page contents we tell PDFDoc to render a page and grab * contents from out OutputDevs when rendering finishes. * - * Background asynchronous contents providing is done via a QThread inherited - * class defined at the bottom of the file. */ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, public Okular::PrintInterface, public Okular::SaveInterface { @@ -75,8 +71,7 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p bool isAllowed( Okular::Permission permission ) const; // [INHERITED] perform actions on document / pages - bool canGeneratePixmap() const; - void generatePixmap( Okular::PixmapRequest * request ); + QImage image( Okular::PixmapRequest *page ); // [INHERITED] print page using an already configured kprinter bool print( QPrinter& printer ); @@ -108,16 +103,9 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p const Okular::SourceReference * dynamicSourceReference( int pageNr, double absX, double absY ); Okular::Generator::PrintError printError() const; - private slots: - // (async related) receive data from the generator thread - void threadFinished(); - private: bool init(QVector & pagesVector, const QString &walletKey); - // friend class to access private document related variables - friend class PDFPixmapGeneratorThread; - // create the document synopsis hieracy void addSynopsisChildren( QDomNode * parentSource, QDomNode * parentDestination ); // fetch annotations from the pdf file and add they to the page @@ -140,12 +128,8 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p // poppler dependant stuff Poppler::Document *pdfdoc; - // asynchronous generation related stuff - PDFPixmapGeneratorThread * generatorThread; // misc variables for document info and synopsis caching - bool ready; - Okular::PixmapRequest * pixmapRequest; bool docInfoDirty; Okular::DocumentInfo docInfo; bool docSynopsisDirty; @@ -165,36 +149,6 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p PrintError lastPrintError; }; - -/** - * @short A thread that builds contents for PDFGenerator in the background. - * - */ -class PDFPixmapGeneratorThread : public QThread -{ - public: - PDFPixmapGeneratorThread( PDFGenerator * generator ); - ~PDFPixmapGeneratorThread(); - - // set the request to the thread (it will be reparented) - void startGeneration( Okular::PixmapRequest * request ); - // end generation - void endGeneration(); - - Okular::PixmapRequest *request() const; - - // methods for getting contents from the GUI thread - QImage * takeImage() const; - QList takeText(); - QLinkedList< Okular::ObjectRect * > takeObjectRects() const; - - private: - // can't be called from the outside (but from startGeneration) - void run(); - - class PPGThreadPrivate * d; -}; - #endif /* kate: replace-tabs on; indent-width 4; */