diff --git a/active/components/documentitem.cpp b/active/components/documentitem.cpp index aaf98b317..1f992a714 100644 --- a/active/components/documentitem.cpp +++ b/active/components/documentitem.cpp @@ -207,7 +207,6 @@ Observer *DocumentItem::pageviewObserver() { if (!m_pageviewObserver) { m_pageviewObserver = new Observer(this); - m_document->d->m_tiledObserver = m_pageviewObserver; } return m_pageviewObserver; diff --git a/core/document.cpp b/core/document.cpp index 19eaa70e1..3b635a05e 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -339,52 +339,59 @@ void DocumentPrivate::cleanupPixmapMemory() void DocumentPrivate::cleanupPixmapMemory( qulonglong memoryToFree ) { - if ( memoryToFree > 0 ) + if ( memoryToFree < 1 ) + return; + + const int currentViewportPage = (*m_viewportIterator).pageNumber; + + // Create a QMap of visible rects, indexed by page number + QMap< int, VisiblePageRect * > visibleRects; + QVector< Okular::VisiblePageRect * >::const_iterator vIt = m_pageRects.constBegin(), vEnd = m_pageRects.constEnd(); + for ( ; vIt != vEnd; ++vIt ) + visibleRects.insert( (*vIt)->pageNumber, (*vIt) ); + + // Free memory starting from pages that are farthest from the current one + int pagesFreed = 0; + while ( memoryToFree > 0 ) { - const int currentViewportPage = (*m_viewportIterator).pageNumber; + AllocatedPixmap * p = searchLowestPriorityPixmap( true, true ); + if ( !p ) // No pixmap to remove + break; - // Create a QMap of visible rects, indexed by page number - QMap< int, VisiblePageRect * > visibleRects; - QVector< Okular::VisiblePageRect * >::const_iterator vIt = m_pageRects.constBegin(), vEnd = m_pageRects.constEnd(); - for ( ; vIt != vEnd; ++vIt ) - visibleRects.insert( (*vIt)->pageNumber, (*vIt) ); + kDebug().nospace() << "Evicting cache pixmap observer=" << p->observer << " page=" << p->page; - // Free memory starting from pages that are farthest from the current one - int pagesFreed = 0; - while ( memoryToFree > 0 ) + // m_allocatedPixmapsTotalMemory can't underflow because we always add or remove + // the memory used by the AllocatedPixmap so at most it can reach zero + m_allocatedPixmapsTotalMemory -= p->memory; + // Make sure memoryToFree does not underflow + if ( p->memory > memoryToFree ) + memoryToFree = 0; + else + memoryToFree -= p->memory; + pagesFreed++; + // delete pixmap + m_pagesVector.at( p->page )->deletePixmap( p->observer ); + // delete allocation descriptor + delete p; + } + + // If we're still on low memory, try to free individual tiles + + // Store pages that weren't completely removed + + QLinkedList< AllocatedPixmap * > pixmapsToKeep; + while (memoryToFree > 0) + { + int clean_hits = 0; + foreach (DocumentObserver *observer, m_observers) { - AllocatedPixmap * p = searchLowestPriorityPixmap( true, true ); + AllocatedPixmap * p = searchLowestPriorityPixmap( false, true, observer ); if ( !p ) // No pixmap to remove - break; + continue; - kDebug().nospace() << "Evicting cache pixmap observer=" << p->observer << " page=" << p->page; + clean_hits++; - // m_allocatedPixmapsTotalMemory can't underflow because we always add or remove - // the memory used by the AllocatedPixmap so at most it can reach zero - m_allocatedPixmapsTotalMemory -= p->memory; - // Make sure memoryToFree does not underflow - if ( p->memory > memoryToFree ) - memoryToFree = 0; - else - memoryToFree -= p->memory; - pagesFreed++; - // delete pixmap - m_pagesVector.at( p->page )->deletePixmap( p->observer ); - // delete allocation descriptor - delete p; - } - - // If we're still on low memory, try to free individual tiles - - // Store pages that weren't completely removed - QLinkedList< AllocatedPixmap * > pixmapsToKeep; - while ( memoryToFree > 0 ) - { - AllocatedPixmap * p = searchLowestPriorityPixmap( false, true, m_tiledObserver ); - if ( !p ) // No pixmap to remove - break; - - TilesManager *tilesManager = m_pagesVector.at( p->page )->d->tilesManager(); + TilesManager *tilesManager = m_pagesVector.at( p->page )->d->tilesManager( observer ); if ( tilesManager && tilesManager->totalMemory() > 0 ) { qulonglong memoryDiff = p->memory; @@ -409,9 +416,11 @@ void DocumentPrivate::cleanupPixmapMemory( qulonglong memoryToFree ) pixmapsToKeep.append( p ); } - m_allocatedPixmaps += pixmapsToKeep; - //p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmaps.count() + pagesFreed, pagesFreed, m_allocatedPixmaps.count() ); + if (clean_hits == 0) break; } + + m_allocatedPixmaps += pixmapsToKeep; + //p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmaps.count() + pagesFreed, pagesFreed, m_allocatedPixmaps.count() ); } /* Returns the next pixmap to evict from cache, or NULL if no suitable pixmap @@ -1321,7 +1330,7 @@ void DocumentPrivate::sendGeneratorPixmapRequest() } QRect requestRect = r->isTile() ? r->normalizedRect().geometry( r->width(), r->height() ) : QRect( 0, 0, r->width(), r->height() ); - TilesManager *tilesManager = ( r->observer() == m_tiledObserver ) ? r->page()->d->tilesManager() : 0; + TilesManager *tilesManager = r->d->tilesManager(); // If it's a preload but the generator is not threaded no point in trying to preload if ( r->preload() && !m_generator->hasFeature( Generator::Threaded ) ) @@ -1349,7 +1358,7 @@ void DocumentPrivate::sendGeneratorPixmapRequest() delete r; } // If the requested area is above 8000000 pixels, switch on the tile manager - else if ( !tilesManager && r->observer() == m_tiledObserver && m_generator->hasFeature( Generator::TiledRendering ) && (long)r->width() * (long)r->height() > 8000000L ) + else if ( !tilesManager && m_generator->hasFeature( Generator::TiledRendering ) && (long)r->width() * (long)r->height() > 8000000L ) { // if the image is too big. start using tiles kDebug(OkularDebug).nospace() << "Start using tiles on page " << r->pageNumber() @@ -1370,7 +1379,7 @@ void DocumentPrivate::sendGeneratorPixmapRequest() } tilesManager->setRequest( r->normalizedRect(), r->width(), r->height() ); r->page()->deletePixmap( r->observer() ); - r->page()->d->setTilesManager( tilesManager ); + r->page()->d->setTilesManager( r->observer(), tilesManager ); r->setTile( true ); // Change normalizedRect to the smallest rect that contains all @@ -1443,7 +1452,7 @@ void DocumentPrivate::sendGeneratorPixmapRequest() // [MEM] preventive memory freeing qulonglong pixmapBytes = 0; - TilesManager * tm = ( request->observer() == m_tiledObserver ) ? request->page()->d->tilesManager() : 0; + TilesManager * tm = request->d->tilesManager(); if ( tm ) pixmapBytes = tm->totalMemory(); else @@ -1571,39 +1580,43 @@ void DocumentPrivate::refreshPixmaps( int pageNumber ) requestedPixmaps.push_back( p ); } - TilesManager *tilesManager = page->d->tilesManager(); - if ( tilesManager ) + foreach (DocumentObserver *observer, m_observers) { - tilesManager->markDirty(); - - PixmapRequest * p = new PixmapRequest( m_tiledObserver, pageNumber, tilesManager->width(), tilesManager->height(), 1, PixmapRequest::Asynchronous ); - - NormalizedRect tilesRect; - - // Get the visible page rect - NormalizedRect visibleRect; - QVector< Okular::VisiblePageRect * >::const_iterator vIt = m_pageRects.constBegin(), vEnd = m_pageRects.constEnd(); - for ( ; vIt != vEnd; ++vIt ) + TilesManager *tilesManager = page->d->tilesManager( observer ); + if ( tilesManager ) { - if ( (*vIt)->pageNumber == pageNumber ) + tilesManager->markDirty(); + + PixmapRequest * p = new PixmapRequest( observer, pageNumber, tilesManager->width(), tilesManager->height(), 1, PixmapRequest::Asynchronous ); + + NormalizedRect tilesRect; + + // Get the visible page rect + NormalizedRect visibleRect; + QVector< Okular::VisiblePageRect * >::const_iterator vIt = m_pageRects.constBegin(), vEnd = m_pageRects.constEnd(); + for ( ; vIt != vEnd; ++vIt ) { - visibleRect = (*vIt)->rect; - break; + if ( (*vIt)->pageNumber == pageNumber ) + { + visibleRect = (*vIt)->rect; + break; + } + } + + if ( !visibleRect.isNull() ) + { + p->setNormalizedRect( visibleRect ); + p->setTile( true ); + p->d->mForce = true; + requestedPixmaps.push_back( p ); + } + else + { + delete p; } } - - if ( !visibleRect.isNull() ) - { - p->setNormalizedRect( visibleRect ); - p->setTile( true ); - p->d->mForce = true; - requestedPixmaps.push_back( p ); - } - else - { - delete p; - } } + if ( !requestedPixmaps.isEmpty() ) m_parent->requestPixmaps( requestedPixmaps, Okular::Document::NoOption ); } @@ -2045,7 +2058,6 @@ Document::Document( QWidget *widget ) d->m_bookmarkManager = new BookmarkManager( d ); d->m_viewportIterator = d->m_viewportHistory.insert( d->m_viewportHistory.end(), DocumentViewport() ); d->m_undoStack = new QUndoStack(this); - d->m_tiledObserver = 0; connect( SettingsCore::self(), SIGNAL(configChanged()), this, SLOT(_o_configChanged()) ); connect( d->m_undoStack, SIGNAL( canUndoChanged(bool) ), this, SIGNAL( canUndoChanged(bool))); @@ -2888,7 +2900,7 @@ void Document::requestPixmaps( const QLinkedList< PixmapRequest * > & requests, // Change the current request rect so that only invalid tiles are // requested. Also make sure the rect is tile-aligned. NormalizedRect tilesRect; - const QList tiles = request->page()->d->tilesManager()->tilesAt( request->normalizedRect(), TilesManager::TerminalTile ); + const QList tiles = request->d->tilesManager()->tilesAt( request->normalizedRect(), TilesManager::TerminalTile ); QList::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd(); while ( tIt != tEnd ) { @@ -4371,7 +4383,7 @@ void DocumentPrivate::requestDone( PixmapRequest * req ) { // [MEM] 1.2 append memory allocation descriptor to the FIFO qulonglong memoryBytes = 0; - const TilesManager *tm = ( req->observer() == m_tiledObserver ) ? req->page()->d->tilesManager() : 0; + const TilesManager *tm = req->d->tilesManager(); if ( tm ) memoryBytes = tm->totalMemory(); else diff --git a/core/document.h b/core/document.h index fe296e049..db76969c9 100644 --- a/core/document.h +++ b/core/document.h @@ -964,7 +964,6 @@ class OKULAR_EXPORT Document : public QObject private: /// @cond PRIVATE friend class DocumentPrivate; - friend class Part; friend class ::DocumentItem; friend class EditAnnotationContentsCommand; friend class EditFormTextCommand; diff --git a/core/document_p.h b/core/document_p.h index ef2516974..025f705d0 100644 --- a/core/document_p.h +++ b/core/document_p.h @@ -216,9 +216,6 @@ class DocumentPrivate // observers / requests / allocator stuff QSet< DocumentObserver * > m_observers; - // FIXME This is a hack, we need to support - // multiple tiled observers, but for the moment we only support one - DocumentObserver *m_tiledObserver; QLinkedList< PixmapRequest * > m_pixmapRequestsStack; QLinkedList< PixmapRequest * > m_executingPixmapRequests; QMutex m_pixmapRequestsMutex; diff --git a/core/generator.cpp b/core/generator.cpp index 23b274b1d..52b602af6 100644 --- a/core/generator.cpp +++ b/core/generator.cpp @@ -22,6 +22,7 @@ #include "document.h" #include "document_p.h" #include "page.h" +#include "page_p.h" #include "textpage.h" #include "utils.h" @@ -517,6 +518,11 @@ const NormalizedRect& PixmapRequest::normalizedRect() const return d->mNormalizedRect; } +Okular::TilesManager* PixmapRequestPrivate::tilesManager() const +{ + return mPage->d->tilesManager(mObserver); +} + void PixmapRequestPrivate::swap() { qSwap( mWidth, mHeight ); diff --git a/core/generator_p.h b/core/generator_p.h index 902176385..8a8603776 100644 --- a/core/generator_p.h +++ b/core/generator_p.h @@ -30,6 +30,7 @@ class PixmapGenerationThread; class PixmapRequest; class TextPage; class TextPageGenerationThread; +class TilesManager; class GeneratorPrivate { @@ -72,6 +73,7 @@ class PixmapRequestPrivate { public: void swap(); + TilesManager *tilesManager() const; DocumentObserver *mObserver; int mPageNumber; diff --git a/core/page.cpp b/core/page.cpp index e19452323..b48f21067 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -66,7 +66,7 @@ static void deleteObjectRects( QLinkedList< ObjectRect * >& rects, const QSetobserver() == m_doc->m_tiledObserver ) ? m_tilesManager : 0; + TilesManager *tm = tilesManager( job->observer() ); if ( tm ) { QPixmap *pixmap = new QPixmap( QPixmap::fromImage( job->image() ) ); @@ -201,7 +201,7 @@ void Page::setBoundingBox( const NormalizedRect& bbox ) bool Page::hasPixmap( DocumentObserver *observer, int width, int height, const NormalizedRect &rect ) const { - TilesManager *tm = ( observer == d->m_doc->m_tiledObserver ) ? d->m_tilesManager : 0; + TilesManager *tm = d->tilesManager( observer ); if ( tm ) { if ( width != tm->width() || height != tm->height() ) @@ -379,8 +379,14 @@ void PagePrivate::rotateAt( Rotation orientation ) /** * Rotate tiles manager */ - if ( m_tilesManager ) - m_tilesManager->setRotation( m_rotation ); + QMapIterator i(m_tilesManagers); + while (i.hasNext()) { + i.next(); + + TilesManager *tm = i.value(); + if ( tm ) + tm->setRotation( m_rotation ); + } /** * Rotate the object rects on the page. @@ -501,7 +507,7 @@ QLinkedList< FormField * > Page::formFields() const void Page::setPixmap( DocumentObserver *observer, QPixmap *pixmap, const NormalizedRect &rect ) { if ( d->m_rotation == Rotation0 ) { - TilesManager *tm = ( observer == d->m_doc->m_tiledObserver ) ? d->m_tilesManager : 0; + TilesManager *tm = d->tilesManager( observer ); if ( tm ) { tm->setPixmap( pixmap, rect ); @@ -705,10 +711,11 @@ void Page::setFormFields( const QLinkedList< FormField * >& fields ) void Page::deletePixmap( DocumentObserver *observer ) { - if ( observer == d->m_doc->m_tiledObserver && d->m_tilesManager ) + TilesManager *tm = d->tilesManager( observer ); + if ( tm ) { - delete d->m_tilesManager; - d->m_tilesManager = 0; + delete tm; + d->m_tilesManagers.remove(observer); } else { @@ -726,8 +733,9 @@ void Page::deletePixmaps() } d->m_pixmaps.clear(); - delete d->m_tilesManager; - d->m_tilesManager = 0; + + qDeleteAll(d->m_tilesManagers); + d->m_tilesManagers.clear(); } void Page::deleteRects() @@ -982,27 +990,29 @@ const QPixmap * Page::_o_nearestPixmap( DocumentObserver *observer, int w, int h return pixmap; } -bool Page::hasTilesManager() const +bool Page::hasTilesManager( const DocumentObserver *observer ) const { - return d->m_tilesManager != 0; + return d->tilesManager( observer ) != 0; } -QList Page::tilesAt( const NormalizedRect &rect ) const +QList Page::tilesAt( const DocumentObserver *observer, const NormalizedRect &rect ) const { - if ( d->m_tilesManager ) - return d->m_tilesManager->tilesAt( rect, TilesManager::PixmapTile ); + TilesManager *tm = d->m_tilesManagers.value( observer ); + if ( tm ) + return tm->tilesAt( rect, TilesManager::PixmapTile ); else return QList(); } -TilesManager *PagePrivate::tilesManager() const +TilesManager *PagePrivate::tilesManager( const DocumentObserver *observer ) const { - return m_tilesManager; + return m_tilesManagers.value( observer ); } -void PagePrivate::setTilesManager( TilesManager *tm ) +void PagePrivate::setTilesManager( const DocumentObserver *observer, TilesManager *tm ) { - delete m_tilesManager; - m_tilesManager = tm; -} + TilesManager *old = m_tilesManagers.value( observer ); + delete old; + m_tilesManagers.insert(observer, tm); +} diff --git a/core/page.h b/core/page.h index bc8c09ea9..3d1817a36 100644 --- a/core/page.h +++ b/core/page.h @@ -372,18 +372,18 @@ class OKULAR_EXPORT Page * Returns whether pixmaps for the tiled observer are handled by a * tile manager. * - * @since 0.16 (KDE 4.10) + * @since 0.19 (KDE 4.13) */ - bool hasTilesManager() const; + bool hasTilesManager( const DocumentObserver *observer ) const; /** * Returns a list of all tiles intersecting with @p rect. * * The list contains only tiles with a pixmap * - * @since 0.16 (KDE 4.10) + * @since 0.19 (KDE 4.13) */ - QList tilesAt( const NormalizedRect &rect ) const; + QList tilesAt( const DocumentObserver *observer, const NormalizedRect &rect ) const; private: PagePrivate* const d; @@ -391,6 +391,7 @@ class OKULAR_EXPORT Page friend class PagePrivate; friend class Document; friend class DocumentPrivate; + friend class PixmapRequestPrivate; /** * To improve performance PagePainter accesses the following diff --git a/core/page_p.h b/core/page_p.h index 63d4da159..69a2c66c2 100644 --- a/core/page_p.h +++ b/core/page_p.h @@ -105,10 +105,14 @@ class PagePrivate void deleteTextSelections(); /** - * Get/set the tiles manager for the tiled observer + * Get the tiles manager for the tiled @observer */ - TilesManager *tilesManager() const; - void setTilesManager( TilesManager *tm ); + TilesManager *tilesManager( const DocumentObserver *observer ) const; + + /** + * Set the tiles manager for the tiled @observer + */ + void setTilesManager( const DocumentObserver *observer, TilesManager *tm ); class PixmapObject { @@ -117,7 +121,7 @@ class PagePrivate Rotation m_rotation; }; QMap< DocumentObserver*, PixmapObject > m_pixmaps; - TilesManager* m_tilesManager; + QMap< const DocumentObserver*, TilesManager *> m_tilesManagers; Page *m_page; int m_number; diff --git a/part.cpp b/part.cpp index 283e91a73..f2dd66e8d 100644 --- a/part.cpp +++ b/part.cpp @@ -89,7 +89,6 @@ #include "core/annotations.h" #include "core/bookmarkmanager.h" #include "core/document.h" -#include "core/document_p.h" #include "core/generator.h" #include "core/page.h" #include "core/fileprinter.h" @@ -432,7 +431,6 @@ m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentW m_formsMessage = new PageViewTopMessage( rightContainer ); rightLayout->addWidget( m_formsMessage ); m_pageView = new PageView( rightContainer, m_document ); - m_document->d->m_tiledObserver = m_pageView; QMetaObject::invokeMethod( m_pageView, "setFocus", Qt::QueuedConnection ); //usability setting // m_splitter->setFocusProxy(m_pageView); connect( m_pageView, SIGNAL(urlDropped(KUrl)), SLOT(openUrlFromDocument(KUrl))); diff --git a/ui/pagepainter.cpp b/ui/pagepainter.cpp index d5d9c3e03..7399d4a47 100644 --- a/ui/pagepainter.cpp +++ b/ui/pagepainter.cpp @@ -89,7 +89,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula } destPainter->fillRect( limits, backgroundColor ); - const bool hasTilesManager = ( page->d->m_doc->m_tiledObserver == observer && page->hasTilesManager() ); + const bool hasTilesManager = page->hasTilesManager( observer ); const QPixmap *pixmap = 0; if ( !hasTilesManager ) @@ -246,7 +246,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula if ( hasTilesManager ) { const Okular::NormalizedRect normalizedLimits( limitsInPixmap, scaledWidth, scaledHeight ); - const QList tiles = page->tilesAt( normalizedLimits ); + const QList tiles = page->tilesAt( observer, normalizedLimits ); QList::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd(); while ( tIt != tEnd ) { @@ -301,7 +301,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula backImage.fill( paperColor.rgb() ); QPainter p( &backImage ); const Okular::NormalizedRect normalizedLimits( limitsInPixmap, scaledWidth, scaledHeight ); - const QList tiles = page->tilesAt( normalizedLimits ); + const QList tiles = page->tilesAt( observer, normalizedLimits ); QList::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd(); while ( tIt != tEnd ) { diff --git a/ui/pageview.cpp b/ui/pageview.cpp index 1ee2a5b7d..7c7f785a3 100644 --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -4147,7 +4147,7 @@ static void slotRequestPreloadPixmap( Okular::DocumentObserver * observer, const { Okular::PixmapRequest::PixmapRequestFeatures requestFeatures = Okular::PixmapRequest::Preload; requestFeatures |= Okular::PixmapRequest::Asynchronous; - const bool pageHasTilesManager = i->page()->hasTilesManager(); + const bool pageHasTilesManager = i->page()->hasTilesManager( observer ); if ( pageHasTilesManager && !preRenderRegion.isNull() ) { Okular::PixmapRequest * p = new Okular::PixmapRequest( observer, i->pageNumber(), i->uncroppedWidth(), i->uncroppedHeight(), PAGEVIEW_PRELOAD_PRIO, requestFeatures ); @@ -4240,7 +4240,7 @@ void PageView::slotRequestVisiblePixmaps( int newValue ) #endif Okular::NormalizedRect expandedVisibleRect = vItem->rect; - if ( i->page()->hasTilesManager() && Okular::Settings::memoryLevel() != Okular::Settings::EnumMemoryLevel::Low ) + if ( i->page()->hasTilesManager( this ) && Okular::Settings::memoryLevel() != Okular::Settings::EnumMemoryLevel::Low ) { double rectMargin = pixelsToExpand/(double)i->uncroppedHeight(); expandedVisibleRect.left = qMax( 0.0, vItem->rect.left - rectMargin ); @@ -4258,7 +4258,7 @@ void PageView::slotRequestVisiblePixmaps( int newValue ) Okular::PixmapRequest * p = new Okular::PixmapRequest( this, i->pageNumber(), i->uncroppedWidth(), i->uncroppedHeight(), PAGEVIEW_PRIO, Okular::PixmapRequest::Asynchronous ); requestedPixmaps.push_back( p ); - if ( i->page()->hasTilesManager() ) + if ( i->page()->hasTilesManager( this ) ) { p->setNormalizedRect( expandedVisibleRect ); p->setTile( true );