diff -r 000000000000 -r 2014ca87e772 imagehandlinglib/Src/CIHLImageViewer.cpp --- /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 +#include +#include +#include +#include + +// 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& 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