startupservices/startupanimation/sanimihlplugin/src/sanimihlctrl.cpp
author fimarlaht2 <>
Mon, 18 Oct 2010 15:01:14 +0300
branchRCL_3
changeset 85 32f887d619a0
parent 0 2e3d3ce01487
permissions -rw-r--r--
Bug 3556 - Not possible to restore factory settings

/*
* 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 );
    }