Multiple Tiles Managers per Page

It's straighforward implementation. Every single place, where there were call for (or with) TilesManager, now has a DocumentObserver as companion. The m_tiledManager reference in PagePrivate was changed to QMap<DocumentObserver, TilesManager>.

REVIEW: 113986
This commit is contained in:
Michal Humpula 2014-02-19 23:40:43 +01:00 committed by Albert Astals Cid
parent 41d55ee477
commit c07ee043a3
12 changed files with 146 additions and 118 deletions

View file

@ -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;

View file

@ -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<Tile> tiles = request->page()->d->tilesManager()->tilesAt( request->normalizedRect(), TilesManager::TerminalTile );
const QList<Tile> tiles = request->d->tilesManager()->tilesAt( request->normalizedRect(), TilesManager::TerminalTile );
QList<Tile>::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

View file

@ -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;

View file

@ -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;

View file

@ -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 );

View file

@ -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;

View file

@ -66,7 +66,7 @@ static void deleteObjectRects( QLinkedList< ObjectRect * >& rects, const QSet<Ob
}
PagePrivate::PagePrivate( Page *page, uint n, double w, double h, Rotation o )
: m_tilesManager( 0 ), m_page( page ), m_number( n ), m_orientation( o ),
: m_page( page ), m_number( n ), m_orientation( o ),
m_width( w ), m_height( h ), m_doc( 0 ), m_boundingBox( 0, 0, 1, 1 ),
m_rotation( Rotation0 ),
m_text( 0 ), m_transition( 0 ), m_textSelections( 0 ),
@ -93,7 +93,7 @@ PagePrivate::~PagePrivate()
void PagePrivate::imageRotationDone( RotationJob * job )
{
TilesManager *tm = ( job->observer() == 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<const DocumentObserver *, TilesManager *> 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<Tile> Page::tilesAt( const NormalizedRect &rect ) const
QList<Tile> 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<Tile>();
}
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);
}

View file

@ -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<Tile> tilesAt( const NormalizedRect &rect ) const;
QList<Tile> 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

View file

@ -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;

View file

@ -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)));

View file

@ -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<Okular::Tile> tiles = page->tilesAt( normalizedLimits );
const QList<Okular::Tile> tiles = page->tilesAt( observer, normalizedLimits );
QList<Okular::Tile>::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<Okular::Tile> tiles = page->tilesAt( normalizedLimits );
const QList<Okular::Tile> tiles = page->tilesAt( observer, normalizedLimits );
QList<Okular::Tile>::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd();
while ( tIt != tEnd )
{

View file

@ -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 );