Rendering with a tiles manager

Currently it's only available for PDFs and does not support rotation.
remotes/origin/KDE/4.10
Mailson Menezes 14 years ago
parent 48d105672f
commit 9f3cf45e37
  1. 1
      CMakeLists.txt
  2. 51
      core/page.cpp
  3. 11
      core/page.h
  4. 2
      core/page_p.h
  5. 132
      core/tilesmanager.cpp
  6. 42
      core/tilesmanager.h
  7. 70
      ui/pagepainter.cpp
  8. 25
      ui/pageview.cpp

@ -60,6 +60,7 @@ set(okularcore_SRCS
core/sourcereference.cpp
core/textdocumentgenerator.cpp
core/textpage.cpp
core/tilesmanager.cpp
core/utils.cpp
core/view.cpp
core/fileprinter.cpp

@ -134,6 +134,7 @@ Page::Page( uint page, double w, double h, Rotation o )
Page::~Page()
{
deletePixmaps();
deleteTilesManagers();
deleteRects();
d->deleteHighlights();
deleteAnnotations();
@ -203,6 +204,26 @@ void Page::setBoundingBox( const NormalizedRect& bbox )
bool Page::hasPixmap( int id, int width, int height, const NormalizedRect &rect ) const
{
if ( id == 3 )
{
TilesManager *tm = tilesManager( id );
if ( !tm )
{
tm = new TilesManager( width, height );
d->m_tilesManagers.insert( id, tm );
}
// TODO: mark tiles as dirty
if ( width != tm->width || height != tm->height )
{
tm->width = width;
tm->height = height;
return false;
}
return tm->hasPixmap( rect );
}
QMap< int, PagePrivate::PixmapObject >::const_iterator it = d->m_pixmaps.constFind( id );
if ( it == d->m_pixmaps.constEnd() )
return false;
@ -467,6 +488,13 @@ QLinkedList< FormField * > Page::formFields() const
void Page::setPixmap( int id, QPixmap *pixmap, const NormalizedRect &rect )
{
TilesManager *tm = tilesManager( id );
if ( tm )
{
tm->setPixmap( pixmap, rect );
return;
}
if ( d->m_rotation == Rotation0 ) {
QMap< int, PagePrivate::PixmapObject >::iterator it = d->m_pixmaps.find( id );
if ( it != d->m_pixmaps.end() )
@ -922,3 +950,26 @@ const QPixmap * Page::_o_nearestPixmap( int pixID, int w, int h ) const
return pixmap;
}
TilesManager *Page::tilesManager( int id ) const
{
TilesManager *tilesManager = 0;
QMap< int, TilesManager* >::iterator itTilesManager = d->m_tilesManagers.find( id );
if ( itTilesManager != d->m_tilesManagers.end() )
tilesManager = *itTilesManager;
return tilesManager;
}
void Page::deleteTilesManagers()
{
QMap< int, TilesManager* >::iterator itTilesManager = d->m_tilesManagers.begin();
while ( itTilesManager != d->m_tilesManagers.end() )
{
delete (*itTilesManager);
itTilesManager++;
}
d->m_tilesManagers.clear();
}

@ -31,6 +31,7 @@ class PagePrivate;
class PageTransition;
class SourceReference;
class TextSelection;
class TilesManager;
/**
* @short Collector for all the data belonging to a page.
@ -357,6 +358,16 @@ class OKULAR_EXPORT Page
*/
void deleteAnnotations();
/**
* Returns the tile manager for the observer with the given @p id.
*/
TilesManager *tilesManager( int id ) const;
/**
* Deletes all tiles managers
*/
void deleteTilesManagers();
private:
PagePrivate* const d;
/// @cond PRIVATE

@ -20,6 +20,7 @@
// local includes
#include "global.h"
#include "area.h"
#include "tilesmanager.h"
class QColor;
class QDomDocument;
@ -107,6 +108,7 @@ class PagePrivate
Rotation m_rotation;
};
QMap< int, PixmapObject > m_pixmaps;
QMap< int, TilesManager* > m_tilesManagers;
Page *m_page;
int m_number;

@ -0,0 +1,132 @@
#include "tilesmanager.h"
#include <QPixmap>
#include <QtCore/qmath.h>
using namespace Okular;
TilesManager::TilesManager( int width, int height )
: width( width ), height( height )
{
for ( int i = 0; i < 16; ++i )
{
mTiles[ i ] = 0;
}
}
TilesManager::~TilesManager()
{
for ( int i = 0; i < 16; ++i )
{
if ( mTiles[ i ] )
{
delete mTiles[ i ];
mTiles[ i ] = 0;
}
}
}
void TilesManager::setPixmap( QPixmap *pixmap, const NormalizedRect &rect )
{
const double dim = 0.25;
int left = qCeil( rect.left/dim );
int top = qCeil( rect.top/dim );
int right = rect.right/dim;
int bottom = rect.bottom/dim;
const QRect pixmapRect = rect.geometry( width, height );
for ( int y = top; y < bottom; y++ )
{
for ( int x = left; x < right; x++ )
{
const NormalizedRect tileRect( x*dim, y*dim, x*dim+dim, y*dim+dim );
int index = 4*y+x;
if ( !mTiles[ index ] )
mTiles[ index ] = new Tile();
Tile *tile = mTiles[ index ];
tile->rect = tileRect;
if ( tile->pixmap )
delete (tile->pixmap);
tile->pixmap = new QPixmap( pixmap->copy( tileRect.geometry( width, height ).translated( -pixmapRect.topLeft() ) ) );
}
}
delete pixmap;
}
bool TilesManager::hasPixmap( const NormalizedRect &rect )
{
const double dim = 0.25;
int left = rect.left/dim;
int top = rect.top/dim;
int right = qCeil( rect.right/dim );
int bottom = qCeil( rect.bottom/dim );
for ( int y = top; y < bottom; y++ )
{
for ( int x = left; x < right; x++ )
{
int index = 4*y + x;
if ( !mTiles[ index ] )
return false;
if ( !mTiles[ index ]->pixmap )
return false;
const NormalizedRect tileRect( x*dim, y*dim, x*dim+dim, y*dim+dim );
QRect tileQRect = tileRect.geometry( width, height );
if ( tileQRect.width() != mTiles[ index ]->pixmap->width() )
return false;
if ( tileQRect.height() != mTiles[ index ]->pixmap->height() )
return false;
}
}
return true;
}
QList<Tile*> TilesManager::tilesAt( const NormalizedRect &rect ) const
{
QList<Tile*> result;
const double dim = 0.25;
int left = rect.left/dim;
int top = rect.top/dim;
int right = qCeil( rect.right/dim );
int bottom = qCeil( rect.bottom/dim );
for ( int y = top; y < bottom; y++ )
{
for ( int x = left; x < right; x++ )
{
int index = 4*y + x;
if ( mTiles[ index ] )
{
if ( !mTiles[ index ]->pixmap )
continue;
const NormalizedRect tileRect( x*dim, y*dim, x*dim+dim, y*dim+dim );
QRect tileQRect = tileRect.geometry( width, height );
if ( tileQRect.width() == mTiles[ index ]->pixmap->width()
&& tileQRect.height() == mTiles[ index ]->pixmap->height() )
{
result.append( mTiles[ index ] );
}
}
}
}
return result;
}
Tile::Tile()
: pixmap( 0 )
{
}
Tile::~Tile() {
delete pixmap;
}

@ -0,0 +1,42 @@
#ifndef _OKULAR_TILES_MANAGER_H_
#define _OKULAR_TILES_MANAGER_H_
#include "okular_export.h"
#include "area.h"
class QPixmap;
namespace Okular {
class Tile;
class OKULAR_EXPORT TilesManager
{
public:
TilesManager( int width, int height );
virtual ~TilesManager();
void setPixmap( QPixmap *pixmap, const NormalizedRect &rect );
bool hasPixmap( const NormalizedRect &rect );
QList<Tile*> tilesAt( const NormalizedRect &rect ) const;
int width;
int height;
private:
Tile *mTiles[16];
};
class OKULAR_EXPORT Tile
{
public:
Tile();
virtual ~Tile();
NormalizedRect rect;
QPixmap *pixmap;
};
}
#endif // _OKULAR_TILES_MANAGER_H_

@ -30,6 +30,7 @@
#include "core/utils.h"
#include "guiutils.h"
#include "settings.h"
#include "core/tilesmanager.h"
K_GLOBAL_STATIC_WITH_ARGS( QPixmap, busyPixmap, ( KIconLoader::global()->loadIcon("okular", KIconLoader::NoGroup, 32, KIconLoader::DefaultState, QStringList(), 0, true) ) )
@ -63,9 +64,6 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
int croppedWidth = scaledCrop.width();
int croppedHeight = scaledCrop.height();
/** 1 - RETRIEVE THE 'PAGE+ID' PIXMAP OR A SIMILAR 'PAGE' ONE **/
const QPixmap * pixmap = page->_o_nearestPixmap( pixID, scaledWidth, scaledHeight );
QColor color = Qt::white;
if ( Okular::Settings::changeColors() )
{
@ -85,24 +83,32 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
}
destPainter->fillRect( limits, color );
/** 1B - IF NO PIXMAP, DRAW EMPTY PAGE **/
double pixmapRescaleRatio = pixmap ? limits.width() / (double)pixmap->width() : -1;
long pixmapPixels = pixmap ? (long)pixmap->width() * (long)pixmap->height() : 0;
if ( !pixmap || pixmapRescaleRatio > 20.0 || pixmapRescaleRatio < 0.25 ||
(limits.width() != pixmap->width() && pixmapPixels > 6000000L) )
Okular::TilesManager *tilesManager = page->tilesManager( pixID );
const QPixmap *pixmap = 0;
if ( !tilesManager )
{
// draw something on the blank page: the okular icon or a cross (as a fallback)
if ( !busyPixmap->isNull() )
/** 1 - RETRIEVE THE 'PAGE+ID' PIXMAP OR A SIMILAR 'PAGE' ONE **/
pixmap = page->_o_nearestPixmap( pixID, scaledWidth, scaledHeight );
/** 1B - IF NO PIXMAP, DRAW EMPTY PAGE **/
double pixmapRescaleRatio = pixmap ? scaledWidth / (double)pixmap->width() : -1;
long pixmapPixels = pixmap ? (long)pixmap->width() * (long)pixmap->height() : 0;
if ( !pixmap || pixmapRescaleRatio > 20.0 || pixmapRescaleRatio < 0.25 ||
(scaledWidth != pixmap->width() && pixmapPixels > 6000000L) )
{
destPainter->drawPixmap( QPoint( 10, 10 ), *busyPixmap );
}
else
{
destPainter->setPen( Qt::gray );
destPainter->drawLine( 0, 0, croppedWidth-1, croppedHeight-1 );
destPainter->drawLine( 0, croppedHeight-1, croppedWidth-1, 0 );
// draw something on the blank page: the okular icon or a cross (as a fallback)
if ( !busyPixmap->isNull() )
{
destPainter->drawPixmap( QPoint( 10, 10 ), *busyPixmap );
}
else
{
destPainter->setPen( Qt::gray );
destPainter->drawLine( 0, 0, croppedWidth-1, croppedHeight-1 );
destPainter->drawLine( 0, croppedHeight-1, croppedWidth-1, 0 );
}
return;
}
return;
}
/** 2 - FIND OUT WHAT TO PAINT (Flags + Configuration + Presence) **/
@ -230,8 +236,32 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
/** 4A -- REGULAR FLOW. PAINT PIXMAP NORMAL OR RESCALED USING GIVEN QPAINTER **/
if ( !useBackBuffer )
{
// 4A.1. if size is ok, draw the page pixmap using painter
destPainter->drawPixmap( limits.topLeft(), *pixmap );
if ( tilesManager )
{
QList<Okular::Tile*> tiles = tilesManager->tilesAt( crop );
QList<Okular::Tile*>::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd();
while ( tIt != tEnd )
{
Okular::Tile *tile = *tIt;
destPainter->drawPixmap( tile->rect.geometry( scaledWidth, scaledHeight ).topLeft(), *(tile->pixmap) );
tIt++;
}
}
else
{
// 4A.1. if size is ok, draw the page pixmap using painter
if ( pixmap->width() == scaledWidth && pixmap->height() == scaledHeight )
destPainter->drawPixmap( limits.topLeft(), *pixmap, limitsInPixmap );
// else draw a scaled portion of the magnified pixmap
else
{
QImage destImage;
scalePixmapOnImage( destImage, pixmap, scaledWidth, scaledHeight, limitsInPixmap );
destPainter->drawImage( limits.left(), limits.top(), destImage, 0, 0,
limits.width(),limits.height() );
}
}
// 4A.2. active painter is the one passed to this method
mixedPainter = destPainter;

@ -3983,10 +3983,27 @@ void PageView::slotRequestVisiblePixmaps( int newValue )
#ifdef PAGEVIEW_DEBUG
kWarning() << "rerequesting visible pixmaps for page" << i->pageNumber() << "!";
#endif
Okular::PixmapRequest * p = new Okular::PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->uncroppedWidth(), i->uncroppedHeight(), PAGEVIEW_PRIO, true );
p->setNormalizedRect( vItem->rect );
requestedPixmaps.push_back( p );
const double dim = 0.25;
int left = vItem->rect.left/dim;
int top = vItem->rect.top/dim;
int right = ceil( vItem->rect.right/dim );
int bottom = ceil( vItem->rect.bottom/dim );
for ( int y = top; y < bottom; y++ )
{
for ( int x = left; x < right; x++ )
{
const Okular::NormalizedRect tileRect( x*dim, y*dim, x*dim+dim, y*dim+dim );
if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->uncroppedWidth(), i->uncroppedHeight(), tileRect ) )
{
Okular::PixmapRequest * p = new Okular::PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->uncroppedWidth(), i->uncroppedHeight(), PAGEVIEW_PRIO, true );
p->setNormalizedRect( tileRect );
requestedPixmaps.push_back( p );
}
}
}
}
// look for the item closest to viewport center and the relative

Loading…
Cancel
Save