--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imagehandlinglib/Src/CIHLImageViewer.cpp Tue Jan 26 15:18:05 2010 +0200
@@ -0,0 +1,1369 @@
+/*
+* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: Implementation of Image Viewer class.
+*
+*/
+
+
+// INCLUDE FILES
+#include "CIHLImageViewer.h"
+
+#include "CIHLBitmap.h"
+#include "CIHLBitmapProcessor.h"
+#include "IHLImplementationIds.h"
+#include "IHLDebugPrint.h" // Debug print
+#include <IHLInterfaceIds.h>
+#include <MIHLViewerObserver.h>
+#include <MIHLFileImage.h>
+#include <fbs.h>
+#include <e32math.h>
+
+// Private namespace for constants and functions
+namespace
+ {
+ // Panic function
+ _LIT( KIHLPanicString, "IHLImageViewer" );
+ void Panic( TInt aPanicCode ) { User::Panic( KIHLPanicString, aPanicCode ); }
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+//
+// C++ constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+CIHLImageViewer::CIHLImageViewer( const TSize& aViewerSize,
+ MIHLFileImage& aSource,
+ MIHLBitmap& aDestination,
+ MIHLViewerObserver& aObserver,
+ const TUint32 aOptions )
+:CTimer( EPriorityNormal ), iObserver( aObserver ),
+iSource( aSource ), iDestination( aDestination ),
+iOptions( aOptions ), iViewerSize( aViewerSize ), iSrcBitmapScaleFactor(1)
+ {
+ CActiveScheduler::Add( this );
+ iAnimDelay = 0;
+ iAnimLastFrameDrawTime = 0;
+ iAnimDrawStartFastTime = 0;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+CIHLImageViewer* CIHLImageViewer::NewL( const TSize& aViewerSize,
+ MIHLFileImage& aSource,
+ MIHLBitmap& aDestination,
+ MIHLViewerObserver& aObserver,
+ const TUint32 aOptions )
+ {
+ CIHLImageViewer* self = new( ELeave ) CIHLImageViewer(
+ aViewerSize, aSource, aDestination, aObserver, aOptions );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// Symbian constructor can leave.
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::ConstructL()
+ {
+ CTimer::ConstructL();
+
+ HAL::Get(HALData::EFastCounterFrequency, iTickPeriod);
+
+ iCacheSource = CIHLBitmap::NewL();
+ iCacheDestination = CIHLBitmap::NewL();
+ iProcessor = CIHLBitmapProcessor::NewL( iOptions );
+
+ // Initialize settings and start load (default is zoom to fit)
+ iSourceSize = iSource.Size();
+ CalculateZoomToFitRatio();
+ User::LeaveIfError( SetZoomRatio( iZoomToFitRatio ) );
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+CIHLImageViewer::~CIHLImageViewer()
+ {
+ Cancel();
+ delete iProcessor;
+ delete iCacheDestination;
+ delete iCacheSource;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::Id
+// -----------------------------------------------------------------------------
+TIHLInterfaceType CIHLImageViewer::Type() const
+ {
+ return TIHLInterfaceType( KIHLInterfaceIdImageViewer, KIHLImplementationIdImageViewer );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::IsAnimation
+// -----------------------------------------------------------------------------
+TBool CIHLImageViewer::IsAnimation() const
+ {
+ return iSource.IsAnimation();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SheduleNextFrame
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::SheduleNextFrame(TTimeIntervalMicroSeconds32 aDelay)
+ {
+ TInt delay=aDelay.Int();
+
+ if (delay == 0) // 0 second deleay set in GIF file
+ {
+ iAnimDelay = TTimeIntervalMicroSeconds32(100000-iAnimLastFrameDrawTime);
+ }
+ else
+ {
+ iAnimDelay = delay - iAnimLastFrameDrawTime;
+ }
+
+ if (iAnimDelay.Int() <=0) //last frame drawn longer than animation frame interval.
+ {
+ iAnimDelay = KMinimumInterval;
+ }
+ iAnimInitFastTime=User::FastCounter(); //store the start time
+ HighRes(iAnimDelay);
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::Play
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::Play()
+ {
+ if( iSource.IsAnimation() )
+ {
+ iIsPlaying = ETrue;
+ if( iViewerState == EInactive)
+ {
+ iViewerState = EAnimation;
+ SheduleNextFrame( iSource.AnimationFrameDelay( iAnimationIndex ) );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::Stop
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::Stop()
+ {
+ iIsPlaying = EFalse;
+ if( iViewerState == EAnimation )
+ {
+ Cancel();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::IsPlaying
+// -----------------------------------------------------------------------------
+TBool CIHLImageViewer::IsPlaying() const
+ {
+ return iIsPlaying;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::AnimationFrameCount
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::AnimationFrameCount() const
+ {
+ return iSource.AnimationFrameCount();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::AnimationFrame
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::AnimationFrame() const
+ {
+ return iAnimationIndex;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetAnimationFrame
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetAnimationFrame( TInt aFrameIndex )
+ {
+ // Public API, boundary check -> panic also on hardware
+ __ASSERT_ALWAYS( aFrameIndex >= 0 &&
+ aFrameIndex < iSource.AnimationFrameCount(), Panic( KErrArgument ) );
+
+ // Save new index and clear old source cache to force load new frame
+ iAnimationIndex = aFrameIndex;
+ iCacheSource->Reset();
+
+ // Start load
+ return ApplySettings();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetViewerSize
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetViewerSize( const TSize& aViewerSize, int aSrcBitmapScaleFactor )
+ {
+ // Public API, negative value check -> panic also on hardware
+ __ASSERT_ALWAYS( aViewerSize.iWidth >= 0 &&
+ aViewerSize.iHeight >= 0, Panic( KErrArgument ) );
+
+ iSrcBitmapScaleFactor = aSrcBitmapScaleFactor;
+
+ // Save new viewer size
+ iViewerSize = aViewerSize;
+
+ // Recalculate source rect and destination size
+ CalculateSourceRectAndDestinationSize();
+
+ // Recalculate zoom to fit ratio
+ CalculateZoomToFitRatio();
+
+ // Start load
+ return ApplySettings();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::ViewerSize
+// -----------------------------------------------------------------------------
+TSize CIHLImageViewer::ViewerSize() const
+ {
+ return iViewerSize;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::MoveSourceRect
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::MoveSourceRect( TInt aDx, TInt aDy )
+ {
+ TInt dx( aDx );
+ TInt dy( aDy );
+ switch( iRotationAngle )
+ {
+ case ERotationAngle0:
+ {
+ break;
+ }
+ case ERotationAngle90:
+ {
+ dx = aDy;
+ dy = -aDx;
+ break;
+ }
+ case ERotationAngle180:
+ {
+ dx = -aDx;
+ dy = -aDy;
+ break;
+ }
+ case ERotationAngle270:
+ {
+ dx = -aDy;
+ dy = aDx;
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+ if( iHorizontalMirroring )
+ {
+ dx = -dx;
+ }
+ if( iVerticalMirroring )
+ {
+ dy = -dy;
+ }
+
+ if( iSourceRect.iTl.iX + dx < 0 ||
+ iSourceRect.iBr.iX + dx > iSourceSize.iWidth ||
+ iSourceRect.iTl.iY + dy < 0 ||
+ iSourceRect.iBr.iY + dy > iSourceSize.iHeight )
+ {
+ return KErrArgument;
+ }
+
+ iSourceRect.Move( dx, dy );
+
+ // Start load
+ return ApplySettings();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetSourceRectPosition
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetSourceRectPosition( const TPoint& aPosition )
+ {
+ TPoint newPosition( aPosition );
+ TSize sourceRectSize( iSourceRect.Size() );
+ switch( iRotationAngle )
+ {
+ case ERotationAngle0:
+ {
+ break;
+ }
+ case ERotationAngle90:
+ {
+ newPosition.iX = aPosition.iY;
+ newPosition.iY = iSourceSize.iHeight - sourceRectSize.iHeight - aPosition.iX;
+ break;
+ }
+ case ERotationAngle180:
+ {
+ newPosition.iX = iSourceSize.iWidth - sourceRectSize.iWidth - aPosition.iX;
+ newPosition.iY = iSourceSize.iHeight - sourceRectSize.iHeight - aPosition.iY;
+ break;
+ }
+ case ERotationAngle270:
+ {
+ newPosition.iX = iSourceSize.iWidth - sourceRectSize.iWidth - aPosition.iY;
+ newPosition.iY = aPosition.iX;
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+ if( iHorizontalMirroring )
+ {
+ newPosition.iX = iSourceSize.iWidth - sourceRectSize.iWidth - newPosition.iX;
+ }
+ if( iVerticalMirroring )
+ {
+ newPosition.iY = iSourceSize.iHeight - sourceRectSize.iHeight - newPosition.iY;
+ }
+
+ if( newPosition.iX < 0 ||
+ newPosition.iX > ( iSourceSize.iWidth - sourceRectSize.iWidth ) ||
+ newPosition.iY < 0 ||
+ newPosition.iY > ( iSourceSize.iHeight - sourceRectSize.iHeight ) )
+ {
+ return KErrArgument;
+ }
+
+ iSourceRect = TRect( newPosition, sourceRectSize );
+
+ // Start load
+ return ApplySettings();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SourceRect
+// -----------------------------------------------------------------------------
+TRect CIHLImageViewer::SourceRect() const
+ {
+ TRect mirroredSourceRect( iSourceRect );
+ if( iHorizontalMirroring )
+ {
+ mirroredSourceRect.iTl.iX = iSourceSize.iWidth - iSourceRect.iBr.iX;
+ mirroredSourceRect.iBr.iX = iSourceSize.iWidth - iSourceRect.iTl.iX;
+ }
+ if( iVerticalMirroring )
+ {
+ mirroredSourceRect.iTl.iY = iSourceSize.iHeight - iSourceRect.iBr.iY;
+ mirroredSourceRect.iBr.iY = iSourceSize.iHeight - iSourceRect.iTl.iY;
+ }
+
+ TRect rotatedSourceRect( mirroredSourceRect );
+ switch( iRotationAngle )
+ {
+ case ERotationAngle0:
+ {
+ break;
+ }
+ case ERotationAngle90:
+ {
+ rotatedSourceRect.iTl.iX = iSourceSize.iHeight - mirroredSourceRect.iBr.iY;
+ rotatedSourceRect.iTl.iY = mirroredSourceRect.iTl.iX;
+ rotatedSourceRect.iBr.iX = iSourceSize.iHeight - mirroredSourceRect.iTl.iY;
+ rotatedSourceRect.iBr.iY = mirroredSourceRect.iBr.iX;
+ break;
+ }
+ case ERotationAngle180:
+ {
+ rotatedSourceRect.iTl.iX = iSourceSize.iWidth - mirroredSourceRect.iBr.iX;
+ rotatedSourceRect.iTl.iY = iSourceSize.iHeight - mirroredSourceRect.iBr.iY;
+ rotatedSourceRect.iBr.iX = iSourceSize.iWidth - mirroredSourceRect.iTl.iX;
+ rotatedSourceRect.iBr.iY = iSourceSize.iHeight - mirroredSourceRect.iTl.iY;
+ break;
+ }
+ case ERotationAngle270:
+ {
+ rotatedSourceRect.iTl.iX = mirroredSourceRect.iTl.iY;
+ rotatedSourceRect.iTl.iY = iSourceSize.iWidth - mirroredSourceRect.iBr.iX;
+ rotatedSourceRect.iBr.iX = mirroredSourceRect.iBr.iY;
+ rotatedSourceRect.iBr.iY = iSourceSize.iWidth - mirroredSourceRect.iTl.iX;
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+
+ return rotatedSourceRect;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SourceSize
+// -----------------------------------------------------------------------------
+TSize CIHLImageViewer::SourceSize() const
+ {
+ if( iRotationAngle == ERotationAngle90 ||
+ iRotationAngle == ERotationAngle270 )
+ {
+ return TSize( iSourceSize.iHeight, iSourceSize.iWidth );
+ }
+ else
+ {
+ return iSourceSize;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetZoomRatio
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetZoomRatio( TReal aZoomRatio )
+ {
+ if( aZoomRatio <= 0 || Math::IsInfinite( aZoomRatio ) )
+ {
+ return KErrArgument;
+ }
+
+ iZoomRatio = aZoomRatio;
+
+ // Recalculate source rect and destination size
+ CalculateSourceRectAndDestinationSize();
+
+ // Start load
+ return ApplySettings();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::ZoomRatio
+// -----------------------------------------------------------------------------
+TReal CIHLImageViewer::ZoomRatio() const
+ {
+ return iZoomRatio;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::ZoomToFitRatio
+// -----------------------------------------------------------------------------
+TReal CIHLImageViewer::ZoomToFitRatio() const
+ {
+ return iZoomToFitRatio;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::RotateClockwise
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::RotateClockwise()
+ {
+ TInt rotationAngle( iRotationAngle + ERotationAngle90 );
+ if( rotationAngle > ERotationAngle270 )
+ {
+ rotationAngle = ERotationAngle0;
+ }
+
+ return SetRotationAngle( rotationAngle );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::RotateCounterClockwise
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::RotateCounterClockwise()
+ {
+ TInt rotationAngle( iRotationAngle - ERotationAngle90 );
+ if( rotationAngle < ERotationAngle0 )
+ {
+ rotationAngle = ERotationAngle270;
+ }
+
+ return SetRotationAngle( rotationAngle );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetRotationAngle
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetRotationAngle( TInt aRotationAngle )
+ {
+ if( aRotationAngle != ERotationAngle0 &&
+ aRotationAngle != ERotationAngle90 &&
+ aRotationAngle != ERotationAngle180 &&
+ aRotationAngle != ERotationAngle270 )
+ {
+ return KErrArgument;
+ }
+
+ iRotationAngle = aRotationAngle;
+
+ // Recalculate source rect and destination size
+ CalculateSourceRectAndDestinationSize();
+
+ // Recalculate zoom to fit ratio
+ CalculateZoomToFitRatio();
+
+ // Start load
+ return ApplySettings();
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::RotationAngle
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::RotationAngle() const
+ {
+ return iRotationAngle;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetVerticalMirroring
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetVerticalMirroring( TBool aValue )
+ {
+ if( iVerticalMirroring != aValue )
+ {
+ iVerticalMirroring = aValue;
+
+ // Start load
+ return ApplySettings();
+ }
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::VerticalMirroring
+// -----------------------------------------------------------------------------
+TBool CIHLImageViewer::VerticalMirroring() const
+ {
+ return iVerticalMirroring;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetHorizontalMirroring
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SetHorizontalMirroring( TBool aValue )
+ {
+ if( iHorizontalMirroring != aValue )
+ {
+ iHorizontalMirroring = aValue;
+ return ApplySettings();
+ }
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::HorizontalMirroring
+// -----------------------------------------------------------------------------
+TBool CIHLImageViewer::HorizontalMirroring() const
+ {
+ return iHorizontalMirroring;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SetFilter
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::SetFilter( MIHLFilter* /*aFilter*/ )
+ {
+ // Not in use
+ }
+
+
+
+// Private methods
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::DoCancel
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::DoCancel()
+ {
+ CTimer::DoCancel();
+ switch( iViewerState )
+ {
+ case ELoad:
+ {
+ // Cancel asynchronous source loading
+ iSource.CancelLoad();
+ iCacheSource->Reset();
+ break;
+ }
+ case EProcess:
+ {
+ // Cancel asynchronous processing
+ iProcessor->CancelProcess();
+ iCacheDestination->Reset();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ // Set state to inactive
+ iViewerState = EInactive;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::RunL
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::RunL()
+ {
+ User::LeaveIfError( iStatus.Int() );
+
+
+ TInt err( KErrNone );
+ switch( iViewerState )
+ {
+ case ELoad:
+ {
+ // Async load successful; start async processing if needed
+ if( NeedAsyncProcess() )
+ {
+ err = AsyncProcess();
+ if( !err )
+ {
+ iViewerState = EProcess;
+ SetActive();
+ }
+ break;
+ }
+ else
+ {
+ iViewerState=EInactive;
+ // Flowtrough to EProcess if no error
+ err = SyncProcess();
+ if( err )
+ {
+ break;
+ }
+ }
+ }
+ case EProcess:
+ {
+ // Process successful; finish and check if animation is needed
+ err = Finish();
+ if( !err )
+ {
+ TInt64 currentTime = User::FastCounter();
+ if(iAnimDrawStartFastTime > 0)
+ {
+ iAnimLastFrameDrawTime=(currentTime-iAnimDrawStartFastTime)*1000000/iTickPeriod;
+ }
+
+ if( iIsPlaying )
+ {
+ iViewerState = EAnimation;
+ SheduleNextFrame(iSource.AnimationFrameDelay( iAnimationIndex ));
+ }
+ else
+ {
+ iViewerState = EInactive;
+ }
+ // Notify client
+ // NOTE! client may call any API method in this point!
+ iObserver.ViewerBitmapChangedL();
+ }
+ break;
+ }
+ case EAnimation:
+ {
+ // Check if still playing..
+ iAnimDrawStartFastTime = User::FastCounter();
+ if( iIsPlaying )
+ {
+ // Change animation frame + 1
+ UpdateAnimationIndex();
+ err = AsyncLoad();
+ if( !err )
+ {
+ iViewerState = ELoad;
+ SetActive();
+ }
+ else
+ {
+ iViewerState = EInactive;
+ }
+ }
+ else
+ {
+ iViewerState = EInactive;
+ }
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+
+
+ User::LeaveIfError( err );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::RunError
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::RunError( TInt aError )
+ {
+ switch( iViewerState )
+ {
+ case ELoad:
+ {
+ // Cleanup cached source if load has been failed
+ iCacheSource->Reset();
+ break;
+ }
+ case EProcess:
+ {
+ // Cleanup cached destination if process has been failed
+ iCacheDestination->Reset();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ iViewerState = EInactive;
+ iObserver.ViewerError( aError );
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::Set
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::ApplySettings()
+ {
+ // Assert source rect and destination, debug build only
+#ifdef _DEBUG
+ AssertSourceRectAndDestinationSize();
+#endif
+
+ // Cancel current process if any
+ Cancel();
+
+ // Check if cached source bitmap is already valid for processing..
+ TBool validSourceCache( EFalse );
+ const CFbsBitmap& cacheSource = iCacheSource->Bitmap();
+ if( cacheSource.Handle() )
+ {
+ const TSize cacheSize( cacheSource.SizeInPixels() );
+ const TSize minLoadSize( MinimumSourceLoadSize() );
+ if( cacheSize.iWidth >= minLoadSize.iWidth &&
+ cacheSize.iHeight >= minLoadSize.iHeight )
+ {
+ validSourceCache = ETrue;
+ }
+ }
+
+ // Start async load/process..
+ TInt err( KErrNone );
+ if( validSourceCache )
+ {
+ if( NeedAsyncProcess() )
+ {
+ err = AsyncProcess();
+ if( !err )
+ {
+ iViewerState = EProcess;
+ SetActive();
+ }
+ }
+ else
+ {
+ err = SyncProcess();
+ if( !err )
+ {
+ iViewerState = EProcess;
+ SelfComplete();
+ }
+ }
+ }
+ else
+ {
+ err = AsyncLoad();
+ if( !err )
+ {
+ iViewerState = ELoad;
+ SetActive();
+ }
+ }
+
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::AsyncLoad
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::AsyncLoad()
+ {
+ // Internal state check, debug panic only
+ __ASSERT_DEBUG( !iCacheDestination->Bitmap().Handle(), Panic( KErrGeneral ) );
+
+ TInt err( KErrNone );
+ if( !iSource.IsAnimation() )
+ {
+ // Do not reset animation frame because loading
+ // might be faster if previous frame can be utilized
+ iCacheSource->Reset();
+ }
+ if( !iCacheSource->Bitmap().Handle() )
+ {
+ TDisplayMode transparency( iSource.MaskDisplayMode() );
+ if( transparency )
+ {
+ err = iCacheSource->Create( MinimumSourceLoadSize(),
+ iSource.DisplayMode(),
+ transparency );
+ }
+ else
+ {
+ err = iCacheSource->Create( MinimumSourceLoadSize(),
+ iSource.DisplayMode() );
+ }
+ }
+
+ // Load source bitmap
+ if( !err )
+ {
+ if( iSource.IsAnimation() )
+ {
+ err = iSource.LoadAnimation( iStatus, *iCacheSource, iAnimationIndex );
+ }
+ else
+ {
+ err = iSource.Load( iStatus, *iCacheSource, iSource.ImageIndex() );
+ }
+
+ }
+
+ // Error cleanup if needed
+ if( err )
+ {
+ iCacheSource->Reset();
+ }
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::NeedAsyncProcess
+// -----------------------------------------------------------------------------
+TBool CIHLImageViewer::NeedAsyncProcess()
+ {
+ // Internal state check, debug panic only
+ __ASSERT_DEBUG( iCacheSource->Bitmap().Handle(), Panic( KErrGeneral ) );
+ __ASSERT_DEBUG( !iCacheDestination->Bitmap().Handle(), Panic( KErrGeneral ) );
+
+ // First check if destination size differs from source size
+ // (=scaling needed)
+ TSize scaledSrcSize( iCacheSource->Bitmap().SizeInPixels() );
+ if( scaledSrcSize.iWidth != iDestinationSize.iWidth ||
+ scaledSrcSize.iHeight != iDestinationSize.iHeight )
+ {
+ return ETrue;
+ }
+
+ // Then check if source rect and source size differs
+ // (=clipping needed)
+ if( iSourceRect.iTl != TPoint( 0,0 ) ||
+ iSourceRect.iBr != iSource.Size().AsPoint() )
+ {
+ return ETrue;
+ }
+
+ // Finally check rotation and mirroring
+ if( iRotationAngle == ERotationAngle0 &&
+ !iHorizontalMirroring &&
+ !iVerticalMirroring )
+ {
+ return EFalse;
+ }
+ else if( iRotationAngle == ERotationAngle180 &&
+ iHorizontalMirroring &&
+ iVerticalMirroring )
+ {
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::AsyncProcess
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::AsyncProcess()
+ {
+ IHL_DEBUG1( KIHLDebug, "IHL - CIHLImageViewer - AsyncProcess" );
+
+ // Internal state check, debug panic only
+ __ASSERT_DEBUG( iCacheSource->Bitmap().Handle(), Panic( KErrGeneral ) );
+ __ASSERT_DEBUG( !iCacheDestination->Bitmap().Handle(), Panic( KErrGeneral ) );
+
+ const CFbsBitmap& srcBitmap = iCacheSource->Bitmap();
+ const CFbsBitmap& srcMask = iCacheSource->Mask();
+ TInt err( KErrNone );
+
+ // Create new cached destination
+ if( srcMask.Handle() )
+ {
+ err = iCacheDestination->Create( iDestinationSize,
+ srcBitmap.DisplayMode(), srcMask.DisplayMode() );
+ }
+ else
+ {
+ err = iCacheDestination->Create( iDestinationSize, srcBitmap.DisplayMode() );
+ }
+
+ // Scale and clip bitmap from cached source to new cached destination
+ if( !err )
+ {
+ TRect scaledSourceRect(
+ CalculateProcessSourceRect( srcBitmap.SizeInPixels() ) );
+
+ TRect destinationRect( CalculateProcessDestinationRect() );
+
+ err = iProcessor->Process( iStatus, *iCacheSource, scaledSourceRect,
+ *iCacheDestination, destinationRect );
+ }
+
+ // Error cleanup if needed
+ if( err )
+ {
+ iCacheDestination->Reset();
+ }
+
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SyncProcess
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::SyncProcess()
+ {
+ IHL_DEBUG1( KIHLDebug, "IHL - CIHLImageViewer - SyncProcess" );
+
+ // Internal state check, debug panic only
+ __ASSERT_DEBUG( iCacheSource->Bitmap().Handle(), Panic( KErrGeneral ) );
+ __ASSERT_DEBUG( !iCacheDestination->Bitmap().Handle(), Panic( KErrGeneral ) );
+
+ // Duplicate destination cache to destination bitmap
+ TInt err( iCacheDestination->Copy( *iCacheSource, EFalse ) );
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::Finish
+// -----------------------------------------------------------------------------
+TInt CIHLImageViewer::Finish()
+ {
+ // Internal state check, debug panic only
+ __ASSERT_DEBUG( iCacheDestination->Bitmap().Handle(), Panic( KErrGeneral ) );
+
+ // Duplicate destination cache to destination bitmap
+ TInt err( iDestination.Copy( *iCacheDestination, ETrue ) );
+ iCacheDestination->Reset();
+
+ // Error cleanup if needed
+ if( err )
+ {
+ iDestination.Reset();
+ }
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::UpdateAnimationIndex
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::UpdateAnimationIndex()
+ {
+ // Internal state check, debug panic only
+ __ASSERT_DEBUG( iIsPlaying, Panic( KErrGeneral ) );
+
+ // Check if animation is in last frame
+ if( iAnimationIndex == iSource.AnimationFrameCount() - 1 )
+ {
+ iAnimationIndex = 0;
+ }
+ else
+ {
+ // Not in last frame; move to next frame
+ iAnimationIndex++;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::SelfComplete
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::SelfComplete()
+ {
+ SetActive();
+ iStatus = KRequestPending;
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::MinimumSourceLoadSize
+// -----------------------------------------------------------------------------
+TSize CIHLImageViewer::MinimumSourceLoadSize()
+ {
+ TSize minumumLoadSize( iSource.Size() );
+
+ if( iSource.IsFullyScaleable() )
+ {
+ const TSize originalSize( iSource.Size() );
+ switch( iRotationAngle )
+ {
+ case ERotationAngle0:
+ case ERotationAngle180:
+ {
+ minumumLoadSize.iWidth = originalSize.iWidth * iDestinationSize.iWidth / Abs( iSourceRect.Width() );
+ minumumLoadSize.iHeight = originalSize.iHeight * iDestinationSize.iHeight / Abs( iSourceRect.Height() );
+ break;
+ }
+ case ERotationAngle90:
+ case ERotationAngle270:
+ {
+ minumumLoadSize.iWidth = originalSize.iWidth * iDestinationSize.iWidth / Abs( iSourceRect.Height() );
+ minumumLoadSize.iHeight = originalSize.iHeight * iDestinationSize.iHeight / Abs( iSourceRect.Width() );
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+
+ // Limit fully scaleable loadsize to original size
+ if( minumumLoadSize.iWidth > originalSize.iWidth ||
+ minumumLoadSize.iHeight > originalSize.iHeight )
+ {
+ minumumLoadSize = originalSize;
+ }
+ }
+ else
+ {
+ const RArray<TSize>& loadSizeArray = iSource.CustomLoadSizeArray();
+ const TInt count( loadSizeArray.Count() );
+
+ if( count )
+ {
+ TRect loadRect;
+ TSize loadRectSize;
+ TBool indexFound( EFalse );
+ for( TInt i( 0 ); ( i < count ) && !indexFound; ++i )
+ {
+ loadRect = CalculateProcessSourceRect( loadSizeArray[ i ] );
+ loadRectSize = loadRect.Size();
+ loadRectSize.iWidth = Abs( loadRectSize.iWidth );
+ loadRectSize.iHeight = Abs( loadRectSize.iHeight );
+
+ if( iDestinationSize.iWidth <= loadRectSize.iWidth &&
+ iDestinationSize.iHeight <= loadRectSize.iHeight )
+ {
+ minumumLoadSize = loadSizeArray[ i ];
+ indexFound = ETrue;
+ }
+ }
+ }
+ }
+
+ return minumumLoadSize;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::CalculateProcessSourceRect
+// -----------------------------------------------------------------------------
+TRect CIHLImageViewer::CalculateProcessSourceRect( const TSize& aLoadSize )
+ {
+ const TSize originalSize( iSource.Size() );
+ TRect loadRect;
+ if ( aLoadSize.iWidth > KErrNone && aLoadSize.iHeight > KErrNone )
+ {
+ loadRect.iTl.iX = iSourceRect.iTl.iX * aLoadSize.iWidth / originalSize.iWidth;
+ loadRect.iTl.iY = iSourceRect.iTl.iY * aLoadSize.iHeight / originalSize.iHeight;
+ loadRect.iBr.iX = iSourceRect.iBr.iX * aLoadSize.iWidth / originalSize.iWidth;
+ loadRect.iBr.iY = iSourceRect.iBr.iY * aLoadSize.iHeight / originalSize.iHeight;
+ }
+ else
+ {
+ loadRect.SetRect(0,0,0,0);
+ return loadRect;
+ }
+
+ switch( iRotationAngle )
+ {
+ case ERotationAngle0:
+ {
+ break;
+ }
+ case ERotationAngle90:
+ {
+ TInt tmp( loadRect.iTl.iY );
+ loadRect.iTl.iY = loadRect.iBr.iY;
+ loadRect.iBr.iY = tmp;
+ break;
+ }
+ case ERotationAngle180:
+ {
+ TPoint tmp( loadRect.iTl );
+ loadRect.iTl = loadRect.iBr;
+ loadRect.iBr = tmp;
+ break;
+ }
+ case ERotationAngle270:
+ {
+ TInt tmp( loadRect.iTl.iX );
+ loadRect.iTl.iX = loadRect.iBr.iX;
+ loadRect.iBr.iX = tmp;
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+
+ return loadRect;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::CalculateProcessDestinationRect
+// -----------------------------------------------------------------------------
+TRect CIHLImageViewer::CalculateProcessDestinationRect()
+ {
+ TRect dstRect( iDestinationSize );
+ switch( iRotationAngle )
+ {
+ case ERotationAngle0:
+ case ERotationAngle180:
+ {
+ if( iHorizontalMirroring )
+ {
+ TInt tmp( dstRect.iTl.iX );
+ dstRect.iTl.iX = dstRect.iBr.iX;
+ dstRect.iBr.iX = tmp;
+ }
+ if( iVerticalMirroring )
+ {
+ TInt tmp( dstRect.iTl.iY );
+ dstRect.iTl.iY = dstRect.iBr.iY;
+ dstRect.iBr.iY = tmp;
+ }
+ break;
+ }
+ case ERotationAngle90:
+ case ERotationAngle270:
+ {
+ if( iHorizontalMirroring )
+ {
+ TInt tmp( dstRect.iTl.iY );
+ dstRect.iTl.iY = dstRect.iBr.iY;
+ dstRect.iBr.iY = tmp;
+ }
+ if( iVerticalMirroring )
+ {
+ TInt tmp( dstRect.iTl.iX );
+ dstRect.iTl.iX = dstRect.iBr.iX;
+ dstRect.iBr.iX = tmp;
+ }
+ break;
+ }
+ default:
+ {
+ // Internal state error, debug panic only
+ #ifdef _DEBUG
+ Panic( KErrGeneral );
+ #endif
+ }
+ }
+ return dstRect;
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::CalculateZoomToFitRatio
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::CalculateZoomToFitRatio()
+ {
+ TSize sourceSize( SourceSize() );
+ TReal widthRatio( TReal( iViewerSize.iWidth ) / TReal( sourceSize.iWidth ) );
+ TReal heightRatio( TReal( iViewerSize.iHeight ) / TReal( sourceSize.iHeight ) );
+
+ if( iOptions & MIHLImageViewer::EOptionIgnoreAspectRatio )
+ {
+ iZoomToFitRatio = ( widthRatio > heightRatio ) ? widthRatio : heightRatio;
+ }
+ else
+ {
+ iZoomToFitRatio = ( widthRatio < heightRatio ) ? widthRatio : heightRatio;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::CalculateSourceRectAndDestinationSize
+// -----------------------------------------------------------------------------
+void CIHLImageViewer::CalculateSourceRectAndDestinationSize()
+ {
+ // Calculate new source rect
+ TSize oldSourceRectSize( iSourceRect.Size() );
+
+ TReal newSourceRectWidth;
+ TReal newSourceRectHeight;
+ TReal widthZoomRatio( iZoomRatio );
+ TReal heightZoomRatio( iZoomRatio );
+
+ if( iOptions & MIHLImageViewer::EOptionIgnoreAspectRatio )
+ {
+ TReal widthRatio( TReal( iViewerSize.iWidth ) / TReal( iSourceSize.iWidth ) );
+ TReal heightRatio( TReal( iViewerSize.iHeight ) / TReal( iSourceSize.iHeight ) );
+ if( widthRatio < heightRatio )
+ {
+ widthZoomRatio = widthZoomRatio * widthRatio / heightRatio;
+ }
+ else
+ {
+ heightZoomRatio = heightZoomRatio * heightRatio / widthRatio;
+ }
+ }
+
+ if( iRotationAngle == ERotationAngle90 ||
+ iRotationAngle == ERotationAngle270 )
+ {
+ newSourceRectWidth = iSrcBitmapScaleFactor * iViewerSize.iHeight / heightZoomRatio; //widthZoomRatio
+ newSourceRectHeight = iSrcBitmapScaleFactor * iViewerSize.iWidth / widthZoomRatio; //heightZoomRatio
+ }
+ else
+ {
+ newSourceRectWidth = iSrcBitmapScaleFactor * iViewerSize.iWidth / widthZoomRatio;
+ newSourceRectHeight = iSrcBitmapScaleFactor * iViewerSize.iHeight / heightZoomRatio;
+ }
+
+ // Check if source rect is not larger than source area
+ if( newSourceRectWidth > iSourceSize.iWidth )
+ {
+ newSourceRectWidth = iSourceSize.iWidth;
+ }
+ if( newSourceRectHeight > iSourceSize.iHeight )
+ {
+ newSourceRectHeight = iSourceSize.iHeight;
+ }
+
+ // Rounding the results
+ TReal roundedWidth;
+ Math::Round( roundedWidth, newSourceRectWidth, 0 );
+ TReal roundedHeight;
+ Math::Round( roundedHeight, newSourceRectHeight, 0 );
+
+ iSourceRect.SetWidth( (TInt)roundedWidth );
+ iSourceRect.SetHeight( (TInt)roundedHeight );
+
+ // Calculate actual destination size (always same or smaller than iViewerSize !)
+ if( iRotationAngle == ERotationAngle90 ||
+ iRotationAngle == ERotationAngle270 )
+ {
+ iDestinationSize.iWidth = (TInt)( newSourceRectHeight * widthZoomRatio ); //heightZoomRatio
+ iDestinationSize.iHeight = (TInt)( newSourceRectWidth * heightZoomRatio ); //widthZoomRatio
+ }
+ else
+ {
+ iDestinationSize.iWidth = (TInt)( newSourceRectWidth * widthZoomRatio );
+ iDestinationSize.iHeight = (TInt)( newSourceRectHeight * heightZoomRatio );
+ }
+ // Check that destination size is not rounded to zero
+ if( iDestinationSize.iWidth == 0 )
+ {
+ iDestinationSize.iWidth = 1;
+ }
+ if( iDestinationSize.iHeight == 0 )
+ {
+ iDestinationSize.iHeight = 1;
+ }
+
+ // Move source rect keeping center point in same location
+ iSourceRect.Move( ( oldSourceRectSize.iWidth - (TInt)newSourceRectWidth ) / 2,
+ ( oldSourceRectSize.iHeight - (TInt)newSourceRectHeight ) / 2 );
+
+ // Move rect if partially out of source area
+ TPoint moveOffset( 0, 0 );
+ if( iSourceRect.iTl.iX < 0 )
+ {
+ moveOffset.iX = -iSourceRect.iTl.iX;
+ }
+ else if( iSourceRect.iBr.iX > iSourceSize.iWidth )
+ {
+ moveOffset.iX = iSourceSize.iWidth - iSourceRect.iBr.iX;
+ }
+ if( iSourceRect.iTl.iY < 0 ) //lint !e961
+ {
+ moveOffset.iY = -iSourceRect.iTl.iY;
+ }
+ else if( iSourceRect.iBr.iY > iSourceSize.iHeight )
+ {
+ moveOffset.iY = iSourceSize.iHeight - iSourceRect.iBr.iY;
+ }
+ iSourceRect.Move( moveOffset ); //lint !e961
+
+ // Assert that rectangle is valid, debug build only
+#ifdef _DEBUG
+ AssertSourceRectAndDestinationSize();
+#endif
+ }
+
+// -----------------------------------------------------------------------------
+// CIHLImageViewer::AssertSourceRectAndDestinationSize
+// Used in debug build only
+// -----------------------------------------------------------------------------
+#ifdef _DEBUG
+void CIHLImageViewer::AssertSourceRectAndDestinationSize()
+ {
+ if( iSourceRect.iTl.iX < 0 ||
+ iSourceRect.iBr.iX > iSourceSize.iWidth ||
+ iSourceRect.iTl.iY < 0 ||
+ iSourceRect.iBr.iY > iSourceSize.iHeight ||
+ iDestinationSize.iWidth <= 0 || iDestinationSize.iHeight <= 0 )
+ {
+ Panic( KErrGeneral );
+ }
+ }
+#endif
+
+// End of File