webengine/pagescaler/src/minimapgenerator.cpp
changeset 0 dd21522fd290
child 37 cb62a4f66ebe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/pagescaler/src/minimapgenerator.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,735 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "minimapgenerator.h"
+
+#include <fbs.h>
+#include <gdi.h>
+#include <bitstd.h>
+#include <w32std.h>
+
+#include "minimap.h"
+#include "minimaptimer.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+const TInt KUnscaledBitmapSize = 1024*128; // pixels, = 256kB
+const TInt KBufferBitmapSize = 1024*256; // pixels, = 512kB
+const TInt KMaxDocWidth = 1600; // limit the maximum width the minimap covers
+const TInt KExtraUpdateHeightTop = 100; // hq update this much pixels outsize the view
+const TInt KExtraUpdateHeightBottom = 300; // hq update this much pixels outsize the view
+const TInt KExtraLQUpdateHeight = 0; // lq update this much pixels outsize the view
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+#ifdef __OOM__
+#include <oom.h>
+
+class CMinimapOOMCollector : public CBase, MMemoryCollector
+    {
+    public:
+        CMinimapOOMCollector( CMinimapGenerator* aGenerator )
+                : iIsCollecting(EFalse), iGenerator( aGenerator )       { MemoryManager::AddCollector( this ); }
+        ~CMinimapOOMCollector()                                         { MemoryManager::RemoveCollector( this ); }
+    	TBool IsCollecting()                                            { return iIsCollecting; }
+
+    	TUint Collect(TUint aRequired = 0);
+    	void Restore()                                                  { iIsCollecting = EFalse; }
+    	TOOMPriority Priority()                                         { return EOOM_PriorityLow; }
+
+    private:
+        TBool iIsCollecting;
+        CMinimapGenerator* iGenerator;
+    };
+
+TUint CMinimapOOMCollector::Collect( TUint /*aRequired*/ )
+    {
+    iIsCollecting = ETrue;
+    iGenerator->CollectMemory();
+    return 0;
+    }
+#endif
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+TInt StartAsyncUpdateCb(
+    TAny* aPtr )
+    {
+    TRAP_IGNORE(static_cast<CMinimapGenerator*>(aPtr)->StartAsyncBufferUpdateL());
+    return EFalse;
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::CMinimapGenerator
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMinimapGenerator::CMinimapGenerator(CMinimap& aMinimap)
+    : iMinimap(&aMinimap)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::ConstructL()
+    {
+    iScaler = CMinimapScaler::NewL(*this);
+    iAsyncUpdateStarted = CIdle::NewL(CActive::EPriorityIdle);
+#ifdef __OOM__
+    iOOMCollector = new (ELeave) CMinimapOOMCollector( this );
+#endif
+  }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CMinimapGenerator* CMinimapGenerator::NewL(CMinimap& aMinimap)
+    {
+    CMinimapGenerator* self = new( ELeave ) CMinimapGenerator(aMinimap);
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+
+// Destructor
+CMinimapGenerator::~CMinimapGenerator()
+    {
+    DeleteUnscaledBitmap();
+    DeleteBufferBitmap();
+    delete iScaler;
+    delete iAsyncUpdateStarted;
+    iValidLQRegion.Close();
+    iValidHQRegion.Close();
+    iVisitedRegion.Close();
+#ifdef __OOM__
+    delete iOOMCollector;
+#endif
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::ScalingCompletedL
+//
+// This callback is called when a scaling operation completes
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::ScalingCompletedL(CFbsBitmap& aResult, const TRect& aTargetRect)
+    {
+    if (!iBufferBitmap)
+        {
+        return;
+        }
+    TRect target(aTargetRect);
+    TRect bufrect(BufferRect());
+    // maybe the buffer has been scrolled out while scaling was going on?
+    if (target.Intersects(bufrect))
+        {
+        // update the valid reqion
+        iValidHQRegion.AddRect(target);
+        iValidHQRegion.ClipRect(bufrect);
+        iValidHQRegion.Tidy();
+
+        // blit the newly scaled area to correct position in buffer
+        target.Move(-iBufferPos);
+        iBufferBitmapGc->BitBlt(target.iTl, &aResult);
+        }
+    // search for next stripe to update
+    TBool more = StartAsyncBufferUpdateL();
+
+    // delete unscaled bitmap if nothing more to do
+    if (!more && !iKeepsBitmaps)
+        {
+        DeleteUnscaledBitmap();
+        }
+
+    // signal the update
+    iMinimap->Callback().ScaledPageChanged(iMinimap->Rect(), !more /*aReady*/, EFalse);
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::Invalidate
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::Invalidate()
+    {
+    TSize docSize(iMinimap->Callback().DocumentSize());
+    // if doc width changes, assume larger changes and invalidate low quality buffer too
+    if (docSize.iWidth!=iDocSize.iWidth || (!iMinimap->IsDocumentComplete() && iMinimap->FullScreenMode()))
+        {
+        iValidLQRegion.Clear();
+//        iVisitedRegion.Clear();
+        }
+    iDocSize = docSize;
+    // otherwise only invalidate high quality areas to avoid lq<->hq flicker
+    iValidHQRegion.Clear();
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::UpdateL
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::UpdateL(TBool aScrolling)
+    {
+    TBool changes = FastBufferUpdateL();
+
+    if( !iMinimap->LowQuality() )
+        {
+        if (changes && iScaler->IsActive())
+            {
+            // FastBufferUpdateL uses the same bitmap, scaling op is no longer valid, have to cancel
+            iScaler->Cancel();
+            }
+        // if scaler is already active no need to restart it
+        if (iMinimap->IsDocumentComplete() && !iAsyncUpdateStarted->IsActive()
+    #ifdef __OOM__
+            && !iOOMCollector->IsCollecting()
+    #endif
+            )
+            {
+            iAsyncUpdateStarted->Start(TCallBack( &StartAsyncUpdateCb, this));
+            }
+        }
+
+    if (changes)
+        {
+        iMinimap->Callback().ScaledPageChanged(iMinimap->Rect(), ETrue, aScrolling);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::ScrollL
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::ScrollL()
+    {
+    CalcBufferPosition();
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::Clear
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::Clear()
+    {
+    iScaler->Cancel();
+    iValidLQRegion.Clear();
+    iValidHQRegion.Clear();
+    iVisitedRegion.Clear();
+    if (iBufferBitmapGc)
+        {
+        iBufferBitmapGc->Clear();
+        }
+    if (iUnscaledBitmapGc)
+        {
+        iUnscaledBitmapGc->Clear();
+        }
+    iBufferPos = TPoint(0,0);
+    iDocSize = TSize();
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::CalcBufferPosition
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::CalcBufferPosition()
+    {
+    if (!iBufferBitmap)
+        {
+        return;
+        }
+    TRect vpr(iMinimap->ViewportOnMinimap());
+    TPoint vpc(vpr.Center());
+    TRect bufrect(BufferRect());
+    TSize bufsize(bufrect.Size());
+    TPoint newPos(bufrect.iTl);
+    TSize mmdocSize(iMinimap->FromDocCoords(iDocSize));
+
+    // check if view is outside center 1/3 of the buffer
+    if (vpc.iY<iBufferPos.iY+bufsize.iHeight/3 ||
+        vpc.iY>iBufferPos.iY+bufsize.iHeight*2/3 )
+        {
+        // recalc new pos
+        newPos.iY = vpc.iY - bufsize.iHeight/2;
+        if (newPos.iY+bufsize.iHeight>mmdocSize.iHeight)
+            newPos.iY=mmdocSize.iHeight-bufsize.iHeight;
+        if (newPos.iY<0)
+            newPos.iY=0;
+        }
+
+    // scroll the buffer if needed
+    TInt scrollAmount = newPos.iY-iBufferPos.iY;
+    if (scrollAmount!=0)
+        {
+        // check if we need to move bitmap
+        if (scrollAmount>0 && scrollAmount<bufsize.iHeight)
+            {
+            // scroll buffer down
+            TRect from (TPoint(0,scrollAmount), TSize(bufsize.iWidth, bufsize.iHeight-scrollAmount));
+            // copy area that remains in buffer to a new position
+            iBufferBitmapGc->CopyRect(TPoint(0,-scrollAmount), from);
+            }
+        else if (scrollAmount<0 && (-scrollAmount)<bufsize.iHeight)
+            {
+            // scroll buffer up
+            TRect from (TPoint(0,0), TSize(bufsize.iWidth, bufsize.iHeight+scrollAmount));
+            // copy area that remains in buffer to a new position
+            iBufferBitmapGc->CopyRect(TPoint(0,-scrollAmount), from);
+            }
+        // invalidate the areas that are out from the buffer due to scrolling
+        iValidLQRegion.ClipRect(bufrect);
+        iValidHQRegion.ClipRect(bufrect);
+        }
+    iBufferPos = newPos;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::FastBufferUpdate
+//
+//
+// -----------------------------------------------------------------------------
+//
+TBool CMinimapGenerator::FastBufferUpdateL()
+    {
+    if (!CheckAndCreateBitmapsL())
+        {
+        return EFalse;
+        }
+
+    TBool changes(EFalse);
+
+    TRect vp(iMinimap->ViewportOnMinimap());
+    TRect bufrect(BufferRect());
+    TSize unscaledSize(iUnscaledBitmap->SizeInPixels());
+
+    TSize targetSize(iMinimap->FromDocCoords(unscaledSize));
+
+    // divide to unscaled bitmap height stripes
+    TInt ypos = ((vp.iTl.iY - KExtraLQUpdateHeight)/targetSize.iHeight)*targetSize.iHeight;
+    TInt yend(vp.iBr.iY + KExtraLQUpdateHeight);
+    if (ypos<0)
+        {
+        ypos = 0;
+        }
+    if (yend>bufrect.iBr.iY)
+        {
+        yend = bufrect.iBr.iY;
+        }
+    // loop over the view area, checking if this stripe needs an update
+    while (ypos<yend)
+        {
+        TRect target(TPoint(0,ypos),targetSize);
+        TRect from(iMinimap->ToDocCoords(target).iTl,unscaledSize);
+
+        // check if this area is already valid
+        RRegion tempR;
+        tempR.AddRect(target);
+        tempR.ClipRect(bufrect);
+        tempR.SubRegion(iValidLQRegion);
+        tempR.SubRegion(iValidHQRegion);
+        if (!tempR.IsEmpty())
+            {
+            //  mark area valid
+            iValidLQRegion.AddRect(target);
+            iValidLQRegion.ClipRect(bufrect);
+            iValidLQRegion.Tidy();
+
+            // if not, get the bitmap from client
+            iMinimap->Callback().DrawDocumentPart(*iUnscaledBitmapGc,iUnscaledBitmap,from);
+            // scale down
+            target.Move(-iBufferPos);
+            iBufferBitmapGc->DrawBitmap(target,iUnscaledBitmap,TRect(unscaledSize));
+
+            changes = ETrue;
+            }
+        tempR.Close();
+
+        ypos += targetSize.iHeight;
+        }
+    return changes;
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::StartAsyncBufferUpdateL
+//
+//
+// -----------------------------------------------------------------------------
+//
+TBool CMinimapGenerator::StartAsyncBufferUpdateL()
+    {
+
+    if (!CheckAndCreateBitmapsL())
+        {
+        return EFalse;
+        }
+
+    TRect vp(iMinimap->ViewportOnMinimap());
+    TRect bufrect(BufferRect());
+    TSize unscaledSize(iUnscaledBitmap->SizeInPixels());
+
+    TSize targetSize(iMinimap->FromDocCoords(unscaledSize));
+
+    // divide to unscaled bitmap height stripes
+    TInt ypos(((vp.iTl.iY - KExtraUpdateHeightTop)/targetSize.iHeight)*targetSize.iHeight);
+    TInt yend(vp.iBr.iY + KExtraUpdateHeightBottom);
+    if (ypos<bufrect.iTl.iY)
+        {
+        ypos = bufrect.iTl.iY;
+        }
+    if (yend>bufrect.iBr.iY)
+        {
+        yend = bufrect.iBr.iY;
+        }
+    // loop over the view area, searching for a stripe that needs an update
+    while (ypos<yend)
+        {
+        // update this area
+        TRect target(TPoint(0,ypos),targetSize);
+        // from here
+        TRect from(iMinimap->ToDocCoords(target).iTl,unscaledSize);
+
+        // check if this area is already valid in high quality region
+        RRegion tempR;
+        tempR.AddRect(target);
+        tempR.ClipRect(bufrect);
+        tempR.SubRegion(iValidHQRegion);
+        if (!tempR.IsEmpty())
+            {
+            tempR.Close();
+            // if not, get the bitmap from client
+            iMinimap->Callback().DrawDocumentPart(*iUnscaledBitmapGc,iUnscaledBitmap,from);
+            // scale asynchronously
+            iScaler->StartScalingL(*iUnscaledBitmap,target);
+            // update started, get out
+            return ETrue;
+            }
+        tempR.Close();
+
+        ypos += targetSize.iHeight;
+        }
+    // nothing to do
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::CheckAndCreateBitmapsL
+//
+//
+// -----------------------------------------------------------------------------
+//
+TBool CMinimapGenerator::CheckAndCreateBitmapsL()
+    {
+#ifdef __OOM__
+    if( iOOMCollector->IsCollecting() ) return EFalse;
+#endif
+    TSize docSize(iDocSize);
+    // minmap won't cover ridiculously wide document fully in horizontal
+    // direction to avoid stripes from getting too wide/low
+    if (docSize.iWidth > KMaxDocWidth)
+        {
+        docSize.iWidth = KMaxDocWidth;
+        }
+    TSize mmdocSize(iMinimap->FromDocCoords(docSize));
+    TSize bufsize;
+    TSize unscaledsize;
+    if (mmdocSize.iWidth!=0 && docSize.iWidth!=0)
+        {
+        bufsize = TSize(mmdocSize.iWidth, Min(mmdocSize.iHeight,KBufferBitmapSize/mmdocSize.iWidth));
+        unscaledsize = TSize(docSize.iWidth, Min(docSize.iHeight,KUnscaledBitmapSize/docSize.iWidth));
+        if (!iUnscaledBitmap || unscaledsize != iUnscaledBitmap->SizeInPixels())
+            {
+            // cancel scaling since we might delete the bitmap
+            iScaler->Cancel();
+            }
+        }
+    TRAPD(err,
+        if (iMinimap->CheckAndCreateBitmapL(bufsize,iBufferBitmap,iBufferBitmapDevice,iBufferBitmapGc))
+			{
+            iMinimap->CheckAndCreateBitmapL(unscaledsize,iUnscaledBitmap,iUnscaledBitmapDevice,iUnscaledBitmapGc);
+			}
+	)
+
+    if( err != KErrNone )
+        {
+        DeleteUnscaledBitmap();
+        DeleteBufferBitmap();
+        }
+
+    return iBufferBitmap!=0 && iUnscaledBitmap!=0;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::DeleteUnscaledBitmap
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::DeleteUnscaledBitmap()
+    {
+    delete iUnscaledBitmapGc;
+    delete iUnscaledBitmapDevice;
+    delete iUnscaledBitmap;
+    iUnscaledBitmapGc = 0;
+    iUnscaledBitmapDevice = 0;
+    iUnscaledBitmap = 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::DeleteBufferBitmap
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::DeleteBufferBitmap()
+    {
+    delete iBufferBitmapGc;
+    delete iBufferBitmapDevice;
+    delete iBufferBitmap;
+    iBufferBitmapGc = 0;
+    iBufferBitmapDevice = 0;
+    iBufferBitmap = 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::BufferRect
+//
+//
+// -----------------------------------------------------------------------------
+//
+TRect CMinimapGenerator::BufferRect() const
+    {
+    return TRect(iBufferPos, iBufferBitmap->SizeInPixels());
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::SetKeepsBitmaps
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::SetKeepsBitmaps(TBool aKeepsBitmaps)
+    {
+    iKeepsBitmaps = aKeepsBitmaps;
+    // delete bitmap if no scaling active
+    if (!iKeepsBitmaps && !iScaler->IsActive())
+        {
+        DeleteUnscaledBitmap();
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::KeepsBitmaps
+//
+//
+// -----------------------------------------------------------------------------
+//
+TBool CMinimapGenerator::KeepsBitmaps() const
+    {
+    return iKeepsBitmaps;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::DrawT
+//
+// Template to support both CWindowGc and CFbsBitGc
+// -----------------------------------------------------------------------------
+//
+template<class GC> void CMinimapGenerator::DrawT(GC& aGc, const TRect& aTo) const
+    {
+    if (!iBufferBitmap)
+        {
+        return;
+        }
+
+    TRect vp(iMinimap->ViewportOnMinimap());
+
+    TRect from(vp.iTl-iBufferPos, aTo.Size());
+    from.Intersection(TRect(iBufferBitmap->SizeInPixels()));
+
+    if (aTo.Size()!=from.Size())
+        {
+        aGc.SetBrushColor(TRgb(0xff,0xff,0xff));
+        aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+        aGc.SetPenStyle(CGraphicsContext::ENullPen);
+        aGc.DrawRect(aTo);
+        }
+
+    if (!from.IsEmpty())
+        {
+        aGc.BitBlt(aTo.iTl, iBufferBitmap, from);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::Draw
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::Draw(CFbsBitGc& aGc, const TRect& aTo) const
+    {
+    DrawT(aGc,aTo);
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::Draw
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::Draw(CWindowGc& aGc, const TRect& aTo) const
+    {
+    DrawT(aGc,aTo);
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::DrawColoringMaskT
+//
+// Template to support both CWindowGc and CFbsBitGc
+// -----------------------------------------------------------------------------
+//
+template<class GC> void CMinimapGenerator::DrawColoringMaskT(GC& aGc, const TRect& aMinimapViewportOnDoc) const
+    {
+    RRegion temp;
+    temp.Copy(iVisitedRegion);
+    temp.ClipRect(aMinimapViewportOnDoc);
+    aGc.SetBrushColor(TRgb(0, 0, 0));
+
+    for(TInt i = 0; i<temp.Count(); i++)
+        {
+        TRect vp(temp[i]);
+        TRect minimapVp(iMinimap->ViewportOnDocument());
+        vp.Move(-minimapVp.iTl); //make vp relative to minimapVp
+        TRect res = iMinimap->FromDocCoords(vp); //translate vp to mmap coords
+        // borders
+        res.Move(1,1);
+        // so that view area is within the indicator
+        res.Grow(1,1);
+
+        aGc.DrawRect(res);
+        }
+    temp.Close();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::DrawColoringMask
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::DrawColoringMask(CFbsBitGc& aGc, const TRect& aMinimapViewportOnDoc) const
+    {
+    DrawColoringMaskT(aGc,aMinimapViewportOnDoc);
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::DrawColoringMask
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::DrawColoringMask(CWindowGc& aGc, const TRect& aMinimapViewportOnDoc) const
+    {
+    DrawColoringMaskT(aGc,aMinimapViewportOnDoc);
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimapGenerator::VisitArea
+//
+//
+// -----------------------------------------------------------------------------
+//
+void CMinimapGenerator::VisitArea(const TRect &aArea)
+    {
+    iVisitedRegion.AddRect(aArea);
+    iVisitedRegion.Tidy();
+    }
+
+// -----------------------------------------------------------------------------
+// CMinimap::ScaledPage
+//
+// Scaled Page
+// -----------------------------------------------------------------------------
+//
+CFbsBitmap* CMinimapGenerator::ScaledPage() const
+    {
+    return iBufferBitmap;
+    }
+
+#ifdef __OOM__
+TBool CMinimapGenerator::IsCollectingMemory()
+    {
+    return iOOMCollector->IsCollecting();
+    }
+
+void CMinimapGenerator::CollectMemory()
+    {
+    if( iScaler->IsActive() ) iScaler->Cancel();
+    DeleteUnscaledBitmap();
+    DeleteBufferBitmap();
+
+    iMinimap->DeleteMinimapBitmap();
+    }
+#endif
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+
+//  End of File