--- /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