browsercore/appfw/ThumbnailEngine/TnEngineGenerator.cpp
branchGCC_SURGE
changeset 8 2e16851ffecd
parent 2 bf4420e9fa4d
parent 6 1c3b8676e58c
equal deleted inserted replaced
2:bf4420e9fa4d 8:2e16851ffecd
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <QPainter>
       
    20 #include "qdebug.h"
       
    21 
       
    22 #include "TnEngineGenerator.h"
       
    23 #include "TnEngineHandler.h"
       
    24 
       
    25 const int KUnscaledBitmapSize = 1024*128; // pixels, = 128kB
       
    26 #if defined Q_WS_MAC || defined Q_WS_WIN || defined Q_WS_X11
       
    27 const int KBufferBitmapSize = 1024*2048;// pixels, = 2MB
       
    28 #else
       
    29 const int KBufferBitmapSize = 1024*374;// pixels, = 374kB
       
    30 #endif
       
    31 const int KMaxDocWidth = 1200; // limit the maximum width the TnEngine covers
       
    32 const int KExtraUpdateHeightTop = 100; // hq update this much pixels outsize the view
       
    33 const int KExtraUpdateHeightBottom = 300; // hq update this much pixels outsize the view
       
    34 const int KExtraLQUpdateHeight = 0; // lq update this much pixels outsize the view
       
    35 
       
    36 namespace WRT {
       
    37 
       
    38 TnEngineGenerator::TnEngineGenerator(TnEngineHandler& TnEngine)
       
    39 : m_TnEngine(&TnEngine),
       
    40 m_validLQRegion(QRegion()), m_validHQRegion(QRegion()), m_bufferPos(0, 0), m_docSize(0, 0), m_keepsBitmaps(false)
       
    41 {
       
    42     m_unscaledBitmap = 0;
       
    43     m_bufferBitmap = 0;
       
    44     m_asyncUpdateStarted = 0;
       
    45 }
       
    46 
       
    47 void TnEngineGenerator::init()
       
    48 {
       
    49     m_scaler = TnEngineScaler::initWithCallback(*this);
       
    50     m_asyncUpdateStarted = new QTimer;
       
    51     connect(m_asyncUpdateStarted, SIGNAL(timeout()), this, SLOT(startAsyncBufferUpdate()));
       
    52 }
       
    53 
       
    54 TnEngineGenerator* TnEngineGenerator::initWithTnEngine(TnEngineHandler& TnEngine)
       
    55 {
       
    56     TnEngineGenerator* self = new TnEngineGenerator(TnEngine);
       
    57     self->init();
       
    58     return self;
       
    59 }
       
    60 
       
    61 TnEngineGenerator::~TnEngineGenerator()
       
    62 {
       
    63 #ifdef __OOM__
       
    64     delete iOOMCollector;
       
    65 #endif    
       
    66     deleteUnscaledBitmap();
       
    67     deleteBufferBitmap();
       
    68     delete m_scaler;
       
    69     delete m_asyncUpdateStarted;
       
    70     m_validLQRegion = QRegion();
       
    71     m_validHQRegion = QRegion();
       
    72 }
       
    73 
       
    74 void TnEngineGenerator::scalingCompleted(QPixmap& result, const QRect& targetRect)
       
    75 {
       
    76     if (!m_bufferBitmap) {
       
    77         return;
       
    78     }
       
    79     QRect target(targetRect);
       
    80     QRect bufrect(bufferRect());
       
    81     // maybe the buffer has been scrolled out while scaling was going on?
       
    82     if (target.intersects(bufrect)) {
       
    83         // update the valid reqion
       
    84         m_validHQRegion += (target);
       
    85         m_validHQRegion = m_validHQRegion.intersected (bufrect);
       
    86         
       
    87         // blit the newly scaled area to correct position in buffer
       
    88         target.moveTo(target.topLeft()-m_bufferPos);
       
    89         QPainter painter(m_bufferBitmap);
       
    90         painter.drawPixmap(target.topLeft(), result);
       
    91     }
       
    92     // search for next stripe to update
       
    93     bool more = startAsyncBufferUpdate();
       
    94     
       
    95     // delete unscaled bitmap if nothing more to do
       
    96     if (!more && !m_keepsBitmaps) {
       
    97         deleteUnscaledBitmap();
       
    98     }
       
    99     
       
   100     // signal the update
       
   101     m_TnEngine->scaledPageChanged(m_TnEngine->theRect(), !more /*aReady*/, false);
       
   102 }
       
   103 
       
   104 
       
   105 void TnEngineGenerator::invalidate()
       
   106 {
       
   107     QSize docSize(m_TnEngine->documentSize());
       
   108     // if doc width changes, assume larger changes and invalidate low quality buffer too
       
   109     if (docSize.width()!=m_docSize.width() || (!m_TnEngine->isDocumentComplete() && m_TnEngine->isFullScreenMode()))
       
   110     {
       
   111         m_validLQRegion = QRegion();
       
   112     }
       
   113     m_docSize = docSize;
       
   114     // otherwise only invalidate high quality areas to avoid lq<->hq flicker
       
   115     m_validHQRegion = QRegion();
       
   116 }
       
   117 
       
   118 
       
   119 void TnEngineGenerator::update(bool scrolling)
       
   120 {
       
   121     bool changes = fastBufferUpdate();
       
   122     if (changes && m_scaler->isActive()) {
       
   123         // fastBufferUpdate uses the same bitmap, scaling op is no longer valid, have to cancel
       
   124         m_scaler->cancel();
       
   125     }
       
   126     // if scaler is already active no need to restart it
       
   127     if (m_TnEngine->isDocumentComplete() && !m_asyncUpdateStarted->isActive()
       
   128 #ifdef __OOM__
       
   129         && !iOOMCollector->IsCollecting()
       
   130 #endif        
       
   131         ) {
       
   132         m_asyncUpdateStarted->start(0);
       
   133     }
       
   134     if (changes) {
       
   135         m_TnEngine->scaledPageChanged(m_TnEngine->theRect(), true, scrolling);
       
   136     }
       
   137 }
       
   138 
       
   139 
       
   140 void TnEngineGenerator::scroll()
       
   141 {
       
   142     calcBufferPosition();
       
   143 }
       
   144 
       
   145 
       
   146 void TnEngineGenerator::clear()
       
   147 {
       
   148     m_scaler->cancel();
       
   149     m_validLQRegion = QRegion();
       
   150     m_validHQRegion = QRegion();
       
   151     if (m_bufferBitmap) {
       
   152         delete m_bufferBitmap;
       
   153         m_bufferBitmap = NULL;
       
   154     }
       
   155     if (m_unscaledBitmap) {
       
   156         delete m_unscaledBitmap;
       
   157     m_unscaledBitmap = NULL;
       
   158     }
       
   159     m_bufferPos = QPoint(0,0);
       
   160     m_docSize = QSize(0,0);
       
   161 }
       
   162 
       
   163 
       
   164 void TnEngineGenerator::calcBufferPosition()
       
   165 {
       
   166     if (!m_bufferBitmap) {
       
   167         return;
       
   168     }
       
   169     QRect vpr(m_TnEngine->viewportOnTnEngine());
       
   170     QPoint vpc(vpr.center());
       
   171     QRect bufrect(bufferRect());
       
   172     QSize bufsize(bufrect.size());
       
   173     QPoint newPos(bufrect.topLeft());
       
   174     QSize mmdocSize(m_TnEngine->fromDocCoords(m_docSize));
       
   175     
       
   176     // check if view is outside center 1/3 of the buffer
       
   177     if (vpc.y()<m_bufferPos.y()+bufsize.height()/3 ||
       
   178         vpc.y()>m_bufferPos.y()+bufsize.height()*2/3 ) {
       
   179         // recalc new pos
       
   180         newPos.setY(vpc.y() - bufsize.height()/2);
       
   181         if (newPos.y()+bufsize.height()>mmdocSize.height())
       
   182             newPos.setY(mmdocSize.height()-bufsize.height());
       
   183         if (newPos.y()<0)
       
   184             newPos.setY(0);
       
   185     }
       
   186     
       
   187     // scroll the buffer if needed
       
   188     int scrollAmount = newPos.y()-m_bufferPos.y();
       
   189     if (scrollAmount!=0) {
       
   190         // check if we need to move bitmap
       
   191         if (scrollAmount>0 && scrollAmount<bufsize.height()) {
       
   192             // scroll buffer down
       
   193             QRect from (QPoint(0,scrollAmount), QSize(bufsize.width(), bufsize.height()-scrollAmount));
       
   194             // copy area that remains in buffer to a new position
       
   195             QPainter painter(m_bufferBitmap);
       
   196             painter.drawPixmap(QPoint(0,0), *m_bufferBitmap, from);
       
   197         }
       
   198         else if (scrollAmount<0 && (-scrollAmount)<bufsize.height()) {
       
   199             // scroll buffer up
       
   200             QRect from (QPoint(0,0), QSize(bufsize.width(), bufsize.height()+scrollAmount));
       
   201             // copy area that remains in buffer to a new position
       
   202             QPainter painter(m_bufferBitmap);
       
   203             painter.drawPixmap(QPoint(0,-scrollAmount), *m_bufferBitmap, from);
       
   204         }
       
   205         // invalidate the areas that are out from the buffer due to scrolling
       
   206         m_validLQRegion = m_validLQRegion.intersected(bufrect);
       
   207         m_validHQRegion = m_validHQRegion.intersected(bufrect);
       
   208     }
       
   209     m_bufferPos = newPos;
       
   210 }
       
   211 
       
   212 bool TnEngineGenerator::fastBufferUpdate()
       
   213 {
       
   214     if (!checkAndCreateBitmaps()) {
       
   215         return false;
       
   216     }
       
   217     
       
   218     bool changes(false);
       
   219     
       
   220     QRect vp(m_TnEngine->viewportOnTnEngine());
       
   221     QRect bufrect(bufferRect());
       
   222     QSize unscaledSize(m_unscaledBitmap->size());
       
   223     
       
   224     QSize targetSize(m_TnEngine->fromDocCoords(unscaledSize));
       
   225     
       
   226     // divide to unscaled bitmap height stripes
       
   227     int ypos = ((vp.top() - KExtraLQUpdateHeight)/targetSize.height())*targetSize.height();
       
   228     int yend(vp.bottom() + KExtraLQUpdateHeight);
       
   229     
       
   230     if (ypos<0) {
       
   231         ypos = 0;
       
   232     }
       
   233     if (yend>bufrect.bottom()) {
       
   234         yend = bufrect.bottom();
       
   235     }
       
   236     // loop over the view area, checking if this stripe needs an update
       
   237     while (ypos<yend) {
       
   238         QRect target(QPoint(0,ypos),targetSize);
       
   239         QRect from(m_TnEngine->toDocCoords(target).topLeft(),unscaledSize);
       
   240         
       
   241         // check if this area is already valid
       
   242         QRegion tempR;
       
   243         tempR += (target);
       
   244         tempR = tempR.intersected(bufrect);
       
   245         tempR = tempR.subtracted (m_validLQRegion);
       
   246         tempR = tempR.subtracted (m_validHQRegion);
       
   247         
       
   248         if (!tempR.isEmpty()) {
       
   249             //  mark area valid
       
   250             m_validLQRegion += target;
       
   251             
       
   252             m_validLQRegion = m_validLQRegion.intersected(bufrect);
       
   253             
       
   254             // if not, get the bitmap from client
       
   255             QPainter unscaledPainter(m_unscaledBitmap);
       
   256             m_TnEngine->drawDocumentPart(unscaledPainter, from);
       
   257             // scale down
       
   258             target.moveTo(target.topLeft()-m_bufferPos);
       
   259             QPainter painter(m_bufferBitmap);
       
   260             painter.drawPixmap(target,*m_unscaledBitmap,QRect(QPoint(0,0), unscaledSize));
       
   261             changes = true;
       
   262         }
       
   263         tempR = QRegion();
       
   264         
       
   265         ypos += targetSize.height();
       
   266     }
       
   267     return changes;
       
   268 }
       
   269 
       
   270 bool TnEngineGenerator::startAsyncBufferUpdate()
       
   271 {
       
   272     m_asyncUpdateStarted->stop();
       
   273     
       
   274     if (!checkAndCreateBitmaps()) {
       
   275         return false;
       
   276     }
       
   277     
       
   278     QRect vp(m_TnEngine->viewportOnTnEngine());
       
   279     QRect bufrect(bufferRect());
       
   280     QSize unscaledSize(m_unscaledBitmap->size());
       
   281     
       
   282     QSize targetSize(m_TnEngine->fromDocCoords(unscaledSize));
       
   283     
       
   284     // divide to unscaled bitmap height stripes
       
   285     int ypos(((vp.top() - KExtraUpdateHeightTop)/targetSize.height())*targetSize.height());
       
   286     int yend(vp.bottom() + KExtraUpdateHeightBottom);
       
   287     if (ypos<bufrect.top()) {
       
   288         ypos = bufrect.top();
       
   289     }
       
   290     if (yend>bufrect.bottom()) {
       
   291         yend = bufrect.bottom();
       
   292     }
       
   293     // loop over the view area, searching for a stripe that needs an update
       
   294     while (ypos<yend) {
       
   295         // update this area
       
   296         QRect target(QPoint(0,ypos),targetSize);
       
   297         // from here
       
   298         QRect from(m_TnEngine->toDocCoords(target).topLeft(),unscaledSize);
       
   299         
       
   300         // check if this area is already valid in high quality region
       
   301         QRegion tempR;
       
   302         tempR += (target);
       
   303         tempR = tempR.intersected(bufrect);
       
   304         tempR = tempR.subtracted(m_validHQRegion);
       
   305         if (!tempR.isEmpty()) {
       
   306             tempR = QRegion();
       
   307             // if not, get the bitmap from client
       
   308             QPainter painter(m_unscaledBitmap);
       
   309             m_TnEngine->drawDocumentPart(painter, from);
       
   310             // scale asynchronously
       
   311             m_scaler->startScaling(*m_unscaledBitmap,target);
       
   312             // update started, get out
       
   313             return true;
       
   314         }
       
   315         tempR = QRegion();
       
   316         
       
   317         ypos += targetSize.height();
       
   318     }
       
   319     // nothing to do
       
   320     return false;
       
   321 }
       
   322 
       
   323 bool TnEngineGenerator::checkAndCreateBitmaps()
       
   324 {
       
   325 #ifdef __OOM__
       
   326     if( iOOMCollector->IsCollecting() ) return false;
       
   327 #endif
       
   328     
       
   329     QSize docSize(m_docSize);
       
   330     // minmap won't cover ridiculously wide document fully in horizontal
       
   331     // direction to avoid stripes from getting too wide/low
       
   332     if (docSize.width() > KMaxDocWidth) {
       
   333         docSize.setWidth(KMaxDocWidth);
       
   334     }
       
   335     QSize mmdocSize(m_TnEngine->fromDocCoords(docSize));
       
   336     QSize bufsize(0,0);
       
   337     QSize unscaledsize(0,0);
       
   338     if (mmdocSize.width()>0 && docSize.width()>0) {
       
   339       bufsize = QSize(mmdocSize.width(), qMin(mmdocSize.height(),KBufferBitmapSize/mmdocSize.width()));
       
   340       unscaledsize = QSize(docSize.width(), qMin(docSize.height(),KUnscaledBitmapSize/docSize.width()));
       
   341         if (!m_unscaledBitmap || unscaledsize != m_unscaledBitmap->size()) {
       
   342             // cancel scaling since we might delete the bitmap
       
   343             m_scaler->cancel();
       
   344         }
       
   345     }
       
   346     
       
   347     if (m_TnEngine->checkAndCreateBitmap(bufsize,m_bufferBitmap)) {
       
   348         m_TnEngine->checkAndCreateBitmap(unscaledsize,m_unscaledBitmap);
       
   349     }
       
   350     if( !m_bufferBitmap || !m_unscaledBitmap)
       
   351     {
       
   352         deleteUnscaledBitmap();
       
   353         deleteBufferBitmap();
       
   354     }
       
   355     return ( m_bufferBitmap!=0 ) && ( m_unscaledBitmap!=0 );
       
   356 }
       
   357 
       
   358 void TnEngineGenerator::deleteUnscaledBitmap()
       
   359 {
       
   360     // stop scaling
       
   361     m_scaler->cancel();
       
   362     delete m_unscaledBitmap;
       
   363     m_unscaledBitmap = 0;
       
   364 }
       
   365 
       
   366 void TnEngineGenerator::deleteBufferBitmap()
       
   367 {
       
   368     delete m_bufferBitmap;
       
   369     m_bufferBitmap = 0;
       
   370 }
       
   371 
       
   372 QRect TnEngineGenerator::bufferRect() const
       
   373 {
       
   374     return QRect(m_bufferPos, m_bufferBitmap->size());
       
   375 }
       
   376 
       
   377 void TnEngineGenerator::setKeepsBitmaps(bool keepsBitmaps)
       
   378 {
       
   379     m_keepsBitmaps = keepsBitmaps;
       
   380     // delete bitmap if no scaling active
       
   381     if (!m_keepsBitmaps && !m_scaler->isActive()) {
       
   382         deleteUnscaledBitmap();
       
   383     }
       
   384 }
       
   385 
       
   386 bool TnEngineGenerator::keepsBitmaps() const
       
   387 {
       
   388     return m_keepsBitmaps;
       
   389 }
       
   390 
       
   391 void TnEngineGenerator::draw(QPainter& gc, const QRect& to) const
       
   392 {
       
   393     if (!m_bufferBitmap) {
       
   394         return;
       
   395     }
       
   396     
       
   397     QRect vp(m_TnEngine->viewportOnTnEngine());
       
   398     
       
   399     QRect from(vp.topLeft()-m_bufferPos, to.size());
       
   400     
       
   401     gc.drawPixmap(to.topLeft(), *m_bufferBitmap, from);
       
   402 }
       
   403 
       
   404 }
       
   405