startupservices/startupanimation/sanimihlplugin/src/sanimihlctrl.cpp
changeset 0 2e3d3ce01487
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/startupservices/startupanimation/sanimihlplugin/src/sanimihlctrl.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,619 @@
+/*
+* Copyright (c) 2007-2008 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 CSAnimIhlCtrl class
+*
+*/
+
+
+#include <IHLImageFactory.h>
+#include <MIHLBitmap.h>
+#include <MIHLFileImage.h>
+#include <IHLViewerFactory.h>
+#include <MIHLImageViewer.h>
+#include "sanimobserver.h"
+
+#include "sanimihlctrl.h"
+#include "assert.h"
+#include "trace.h"
+
+/** Some GIF animations have all frame delays set to zero. */
+const TInt KDefaultFrameDelay = 300000;
+
+// ======== LOCAL FUNCTIONS ========
+
+static TBool operator<=( const TSize& aLhs, const TSize& aRhs )
+    {
+    return aLhs.iWidth <= aRhs.iWidth && aLhs.iHeight <= aRhs.iHeight;
+    }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::NewL
+//
+// ---------------------------------------------------------------------------
+//
+CSAnimIhlCtrl* CSAnimIhlCtrl::NewL(
+    MSAnimObserver& aObserver,
+    RFs& aFs,
+    const TDesC& aFileName,
+    const TDisplayMode aDisplayMode,
+    const TSize& aSize,
+    const TTimeIntervalMicroSeconds32& aFrameDelay,
+    const TBool aScalingEnabled )
+    {
+    FUNC_LOG;
+
+    CSAnimIhlCtrl* self = new( ELeave ) CSAnimIhlCtrl( aObserver, aFrameDelay );
+    CleanupStack::PushL( self );
+    self->ConstructL( aFs, aFileName, aDisplayMode, aSize, aScalingEnabled );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::~CSAnimIhlCtrl
+//
+// ---------------------------------------------------------------------------
+//
+CSAnimIhlCtrl::~CSAnimIhlCtrl()
+    {
+    FUNC_LOG;
+
+    Cancel();
+    iTimer.Close();
+    delete iViewer;
+    iFrames.ResetAndDestroy();
+    delete iImage;
+    iFile.Close();
+    delete iBuffer;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::BackroundColour
+//
+// ---------------------------------------------------------------------------
+//
+TRgb CSAnimIhlCtrl::BackroundColour() const
+    {
+    FUNC_LOG;
+
+    return iImage->BackgroundColor();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::Load
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::Load( const TCallBack& aCallBack )
+    {
+    FUNC_LOG;
+    ASSERT_TRACE( iState == EInitial, SAnimPanic::EInternalError );
+
+    if ( iState == EInitial )
+        {
+        iState = ELoading;
+        iCallBack = aCallBack;
+        iSuccessCode = KErrNone;
+        delete iViewer;
+        iViewer = NULL;
+    
+        if ( ( iType == EAnimation || iType == EStillImage ) && iFrames.Count() > 0 )
+            {
+            MIHLBitmap& frame = *( iFrames[ 0 ] );
+            TRAP( iSuccessCode, iViewer = IHLViewerFactory::CreateImageViewerL(
+                iViewerSize, *iImage, frame, *this ) );
+            if ( iSuccessCode != KErrNone )
+                {
+                Notify( iSuccessCode, EFailed );
+                }
+            }
+        else if ( iType == EMultiFrame && iFrameIndex < iFrameCount - 1 )
+            {
+            LoadNextSubImage();
+            }
+        else
+            {
+            Notify( KErrNotFound, EFailed );
+            }
+        }
+    else
+        {
+        iSuccessCode = KErrAlreadyExists;
+        aCallBack.CallBack();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::Play
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::Play( const TCallBack& aCallBack )
+    {
+    FUNC_LOG;
+    ASSERT_TRACE( iState == ELoaded, SAnimPanic::EInternalError );
+
+    if ( iState == ELoaded )
+        {
+        iState = EPlaying;
+        iCallBack = aCallBack;
+        iSuccessCode = KErrNone;
+        iFrameIndex = -1;
+        ShowNextFrame();
+        }
+    else
+        {
+        iSuccessCode = KErrNotReady;
+        aCallBack.CallBack();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::SuccessCode
+//
+// ---------------------------------------------------------------------------
+//
+TInt CSAnimIhlCtrl::SuccessCode() const
+    {
+    FUNC_LOG;
+    INFO_1( "Success code: %d", iSuccessCode );
+
+    return iSuccessCode;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::Stop
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::Stop()
+    {
+    FUNC_LOG;
+    INFO_1( "Stop: state %d", iState );
+
+    if ( iState == ELoading || iState == EPlaying )
+        {
+        StopAndNotify( KErrCancel, EFailed );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::DoCancel
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::DoCancel()
+    {
+    FUNC_LOG;
+
+    iImage->CancelLoad();
+    iTimer.Cancel();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::RunL
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::RunL()
+    {
+    FUNC_LOG;
+    ERROR( iStatus.Int(), "Timer completed with error" );
+
+    if ( iStatus.Int() == KErrNone )
+        {
+        if ( iState == ELoading )
+            {
+            if ( iType == EMultiFrame && iFrameIndex < iFrameCount - 1 )
+                {
+                LoadNextSubImage();
+                }
+            else
+                {
+                iFrameIndex = -1;
+                Notify( KErrNone, ELoaded );
+                }
+            }
+        else if ( iState == EPlaying )
+            {
+            ShowNextFrame();
+            }
+        }
+    else
+        {
+        Notify( iStatus.Int(), EFailed );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::CSAnimIhlCtrl
+//
+// ---------------------------------------------------------------------------
+//
+CSAnimIhlCtrl::CSAnimIhlCtrl(
+    MSAnimObserver& aObserver,
+    const TTimeIntervalMicroSeconds32& aFrameDelay )
+  : CActive( EPriorityStandard ),
+    iObserver( aObserver ),
+    iFrameDelay( aFrameDelay ),
+    iFrameIndex( -1 ),
+    iSuccessCode( KErrNone ),
+    iType( EStillImage ),
+    iState( EInitial )
+    {
+    FUNC_LOG;
+
+    CActiveScheduler::Add( this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::ConstructL
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::ConstructL(
+    RFs& aFs,
+    const TDesC& aFileName,
+    const TDisplayMode /*aDisplayMode*/,
+    const TSize& aSize,
+    const TBool aScalingEnabled )
+    {
+    FUNC_LOG;
+
+    User::LeaveIfError( iTimer.CreateLocal() );
+    User::LeaveIfError( iFile.Open(
+        aFs, aFileName, EFileRead | EFileShareReadersOnly ) );
+	
+    TInt fileSize;
+    iFile.Size( fileSize );
+    iBuffer = HBufC8::NewL( fileSize );
+    
+    TPtr8 fileDes = iBuffer->Des();
+    iFile.Read( fileDes, fileSize );
+    iImage = IHLImageFactory::OpenBufferedFileImageL(aFs,*iBuffer );
+
+    iFrameCount = 1; // If it is not an animation, frame count is 1.
+    if ( iImage->IsAnimation() )
+        {
+        iFrameCount = iImage->AnimationFrameCount();
+        iType = EAnimation;
+        }
+    else if ( iImage->ImageCount() > 1 )
+        {
+        iFrameCount = iImage->ImageCount();
+        iType = EMultiFrame;
+        }
+
+    INFO_2( "Type: %d, frame count: %d", iType, iFrameCount );
+
+    iViewerSize = SelectSize( aSize, aScalingEnabled );
+    if ( iType == EAnimation || iType == EStillImage )
+        {
+        MIHLBitmap* frame = IHLBitmap::CreateL();
+        CleanupStack::PushL( frame );
+        iFrames.AppendL( frame );
+        CleanupStack::Pop( frame );
+        }
+    else if ( iType == EMultiFrame )
+        {
+        for ( TInt i = 0; i < iFrameCount; i++ )
+            {
+            MIHLBitmap* frame = IHLBitmap::CreateL();
+            CleanupStack::PushL( frame );
+            User::LeaveIfError( frame->Create( iViewerSize, iImage->DisplayMode(), EGray256 ) );
+            iFrames.AppendL( frame );
+            CleanupStack::Pop( frame );
+            }
+        }
+    else
+        {
+        ERROR_GEN_1( "ConstructL: type %d unexpected", iType );
+        User::Leave( KErrGeneral );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::SelectSize
+//
+// ---------------------------------------------------------------------------
+//
+TSize CSAnimIhlCtrl::SelectSize(
+    const TSize& aSize,
+    const TBool aScalingEnabled ) const
+    {
+    FUNC_LOG;
+
+    TSize imageSize = iImage->Size(); // Default for all elses
+    if ( aScalingEnabled && aSize != TSize( 0, 0 ) ) // Scaling requested
+        {
+        if ( iImage->IsFullyScaleable() )
+            {
+            INFO( "Image is fully scaleable" );
+
+            imageSize = aSize;
+            }
+        else
+            {
+            const RArray<TSize>& loadSizeArray = iImage->CustomLoadSizeArray();
+            if ( loadSizeArray.Count() > 0 )
+                {
+                INFO( "Image has custom load size array" );
+
+                imageSize = FindClosestMatch( aSize, imageSize, loadSizeArray );
+                }
+            }
+        }
+
+    return imageSize;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::FindClosestMatch
+//
+// ---------------------------------------------------------------------------
+//
+TSize CSAnimIhlCtrl::FindClosestMatch(
+    const TSize& aTarget,
+    const TSize& aOptimalSize,
+    const RArray<TSize>& aOptions ) const
+    {
+    FUNC_LOG;
+    INFO_2( "Target size: (%d, %d)", aTarget.iWidth, aTarget.iHeight );
+    INFO_2( "Optimal size: (%d, %d)", aOptimalSize.iWidth, aOptimalSize.iHeight );
+
+    TSize selected( 0, 0 );
+    if ( aOptimalSize <= aTarget )
+        {
+        selected = aOptimalSize;
+        }
+
+    TInt count = aOptions.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        TSize item = aOptions[i];
+
+        INFO_3( "Option %d: (%d, %d)", i, item.iWidth, item.iHeight );
+
+        if ( item.iHeight <= aTarget.iHeight && item.iWidth <= aTarget.iWidth ) // Acceptable
+            {
+            if ( ( aTarget.iHeight - item.iHeight ) <
+                 ( aTarget.iHeight - selected.iHeight ) )
+                {
+                selected = item;
+                }
+            }
+        }
+
+    if ( selected == TSize( 0, 0 ) ) // No match found
+        {
+        selected = aOptimalSize;
+        }
+
+    INFO_2( "Selected option: (%d, %d)", selected.iWidth, selected.iHeight );
+    return selected;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::LoadNextSubImage
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::LoadNextSubImage()
+    {
+    FUNC_LOG;
+    ASSERT_TRACE( iState == ELoading && !IsActive(), SAnimPanic::EInternalError );
+
+    iFrameIndex++;
+
+    INFO_2( "LoadNextSubImage: index: %d, frame count: %d", iFrameIndex, iFrameCount );
+
+    ASSERT_TRACE( iFrameIndex < iFrames.Count(), SAnimPanic::EInternalError );
+    MIHLBitmap* nextFrame = iFrames[ iFrameIndex ];
+
+    iSuccessCode = iImage->Load( iStatus, *nextFrame, iFrameIndex );
+
+    if ( iSuccessCode == KErrNone )
+        {
+        SetActive();
+        }
+    else
+        {
+        Notify( iSuccessCode, EFailed );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::ShowNextFrame
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::ShowNextFrame()
+    {
+    FUNC_LOG;
+    ASSERT_TRACE( iState == EPlaying, SAnimPanic::EInternalError );
+
+    if ( iFrameIndex < iFrameCount - 1 )
+        {
+        iFrameIndex++;
+
+        INFO_2( "ShowNextFrame: index: %d, frame count: %d", iFrameIndex, iFrameCount );
+
+        if ( iType == EAnimation && iViewer )
+            {
+            UpdateFrameToScreen( 0 );
+            iViewer->Play();
+            }
+        else if ( iType == EStillImage )
+            {
+            UpdateFrameToScreen( 0 );
+            StartFrameTimer();
+            }
+        else if ( iType == EMultiFrame )
+            {
+            UpdateFrameToScreen( iFrameIndex );
+            StartFrameTimer();
+            }
+        else
+            {
+            ERROR_GEN_1( "ShowNextFrame: type %d unexpected", iType );
+            Notify( KErrGeneral, EFailed );
+            }
+        }
+    else
+        {
+        StopAndNotify( KErrNone, EFinished );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::UpdateFrameToScreen
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::UpdateFrameToScreen( TInt aFrameIndex ) const
+    {
+    FUNC_LOG;
+
+    if ( aFrameIndex >= 0 && aFrameIndex < iFrames.Count() )
+        {
+        MIHLBitmap& frame = *( iFrames[ aFrameIndex ] );
+        if ( frame.HasMask() )
+            {
+            iObserver.UpdateScreen( frame.Bitmap(), frame.Mask() );
+            }
+        else
+            {
+            iObserver.UpdateScreen( frame.Bitmap() );
+            }
+        }
+    else
+        {
+        ERROR_GEN_1( "UpdateFrameToScreen: aFrameIndex %d out of bounds", aFrameIndex );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::StartFrameTimer
+//
+// ---------------------------------------------------------------------------
+//
+
+void CSAnimIhlCtrl::StartFrameTimer()
+    {
+    FUNC_LOG;
+    ASSERT_TRACE( !IsActive(), SAnimPanic::EInternalError );
+
+    if ( !IsActive() )
+        {
+        TTimeIntervalMicroSeconds32 delay = ( iFrameDelay.Int() == 0 ?
+            KDefaultFrameDelay : iFrameDelay );
+        INFO_2( "Frame delay: %d, default delay: %d", delay.Int(), iFrameDelay.Int() );
+        iTimer.Cancel();
+        iTimer.After( iStatus, delay );
+        SetActive();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::StopAndNotify
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::StopAndNotify( TInt aError, TInt aNextState )
+    {
+    FUNC_LOG;
+
+    Cancel();
+    if ( iViewer )
+        {
+        iViewer->Stop();
+        }
+    Notify( aError, aNextState );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::Notify
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::Notify( TInt aError, TInt aNextState )
+    {
+    FUNC_LOG;
+    ERROR_1( aError, "Notify: state %d", aNextState );
+
+    iSuccessCode = aError;
+    iState = aNextState;
+    iCallBack.CallBack();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::ViewerBitmapChangedL
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::ViewerBitmapChangedL()
+    {
+    FUNC_LOG;
+    INFO_1( "ViewerBitmapChangedL: state %d", iState );
+
+    if ( iState == ELoading )
+        {
+        iFrameIndex = -1;
+        Notify( KErrNone, ELoaded );
+        }
+    else if ( iState == EPlaying )
+        {
+        ShowNextFrame();
+        }
+    else
+        {
+        StopAndNotify( KErrGeneral, EFailed );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSAnimIhlCtrl::ViewerError
+//
+// ---------------------------------------------------------------------------
+//
+void CSAnimIhlCtrl::ViewerError( TInt aError )
+    {
+    FUNC_LOG;
+
+    StopAndNotify( aError, EFailed );
+    }
+