startupservices/startupanimation/sanimsvgplugin/src/sanimmifplugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 10:12:00 +0200
changeset 0 2e3d3ce01487
permissions -rw-r--r--
Revision: 201002 Kit: 201005

/*
* Copyright (c) 2007 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 CSAnimMifPlugin class
*
*/


#include <SVGEngineInterfaceImpl.h>

#include "sanimmifplugin.h"
#include "assert.h"
#include "trace.h"

/** MIF header contents. */
class TMifHeader
    {
public:
    TInt32 iUID;
    TInt32 iVersion;
    TInt32 iArrayOffset;
    TInt32 iArrayLength;
    };

typedef TPckgBuf<TMifHeader> TMifHeaderPckg;

/** Icon offset element from MIF file. */
class TIconOffsetElement
    {
public:
    TInt32 iOffset;
    TInt32 iLength;
    };

typedef TPckgBuf<TIconOffsetElement> TIconOffsetElementPckg;

/** Icon header contents. */
class TIconHeader
    {
public:
    TInt32 iUID;
    TInt32 iVersion;
    TInt32 iDataOffset;
    TInt32 iDataLength;
    TInt32 iType;
    TInt32 iDepth;
    TInt32 iAnimated;
    TInt32 iMaskDepth;
    };

typedef TPckgBuf<TIconHeader> TIconHeaderPckg;

/** Type identifier for SVG. */
const TInt KSvgType = 1;

/** Number of array elements one frame occupies (bitmap & mask = 2). */
const TInt KArrElementsPerFrame = 2;

/** Step through icon array with this granularity. */
const TInt KIconArrStep = 2;

// ======== LOCAL FUNCTIONS ========

static TInt TimerCallBack( TAny* aPtr )
    {
    FUNC_LOG;

    static_cast<CSAnimMifPlugin*>( aPtr )->TimerExpired();
    return KErrNone;
    }


// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CSAnimMifPlugin::NewL
//
// ---------------------------------------------------------------------------
//
CSAnimMifPlugin* CSAnimMifPlugin::NewL( TAny* aConstructionParameters )
    {
    FUNC_LOG;

    CSAnimMifPlugin* self =
        new( ELeave ) CSAnimMifPlugin( aConstructionParameters );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::~CSAnimMifPlugin
//
// ---------------------------------------------------------------------------
//
CSAnimMifPlugin::~CSAnimMifPlugin()
    {
    FUNC_LOG;

    delete iDummy;
    delete iTimer;
    iFrames.ResetAndDestroy();
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::TimerExpired
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::TimerExpired()
    {
    FUNC_LOG;

    if ( iCurrentFrame < iFrames.Count() - KArrElementsPerFrame )
        {
        iCurrentFrame += KArrElementsPerFrame; // Each other array element is a mask
        RefreshView();
        }
    else
        {
        iTimer->Cancel();
        CompleteClientRequest( KErrNone );
        }
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::Load
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::Load(
    RFs& aFs,
    const TDesC& aFileName,
    TRequestStatus& aStatus )
    {
    FUNC_LOG;
    INFO_1( "File name: %S", &aFileName );

    iTimer->Cancel();
    iFrames.ResetAndDestroy();
    iCurrentFrame = -1;

    TRAPD( errorCode, LoadL( aFs, aFileName ) );
    ERROR( errorCode, "Failed to load image file" );
    SetClientRequest( aStatus );
    CompleteClientRequest( errorCode );
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::Start
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::Start( TRequestStatus& aStatus )
    {
    FUNC_LOG;
    ASSERT_TRACE( iEngine, SAnimPanic::ENotInitialized );
    ASSERT_TRACE( !( iTimer->IsActive() ), SAnimPanic::EInternalError );

    SetClientRequest( aStatus );

    iCurrentFrame = 0;
    if ( iCurrentFrame < iFrames.Count() - 1 ) // Last one is a mask
        {
        RefreshView();
        iTimer->Start(
            iFrameDelay, iFrameDelay, TCallBack( TimerCallBack, this ) );
        }
    else
        {
        CompleteClientRequest( KErrNone );
        }
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::Cancel
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::Cancel()
    {
    FUNC_LOG;

    CompleteClientRequest( KErrCancel );

    iTimer->Cancel();
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::BackroundColour
//
// ---------------------------------------------------------------------------
//
TRgb CSAnimMifPlugin::BackroundColour() const
    {
    FUNC_LOG;

    return KRgbWhite;
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::UpdateScreen
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::UpdateScreen()
    {
    FUNC_LOG;
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::CSAnimMifPlugin
//
// ---------------------------------------------------------------------------
//
CSAnimMifPlugin::CSAnimMifPlugin( TAny* aConstructionParameters )
  : CSAnimSvgPluginBase( aConstructionParameters ),
    iCurrentFrame( -1 )
    {
    FUNC_LOG;
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::ConstructL
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::ConstructL()
    {
    FUNC_LOG;

    iTimer = CPeriodic::NewL( CActive::EPriorityHigh );
    iDummy = new ( ELeave ) CFbsBitmap();
    User::LeaveIfError( iDummy->Create( TSize( 0, 0 ), EGray256 ) );
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::LoadL
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::LoadL( RFs& aFs, const TDesC& aFileName )
    {
    FUNC_LOG;

    delete iEngine;
    iEngine = NULL;
    iEngine = CSvgEngineInterfaceImpl::NewL( iDummy, this, iFontSpec );
    iEngine->SetBackgroundColor( KRgbWhite.Internal() );
    iEngine->SetDRMMode( EFalse );

    RFile file;
    CleanupClosePushL( file );
    User::LeaveIfError( file.Open(
        aFs, aFileName, EFileRead | EFileShareReadersOnly ) );

    TMifHeaderPckg header;
    TInt errorCode = file.Read( header );
    ERROR( errorCode, "CSAnimMifPlugin::LoadL: failed to read file" );
    INFO_2( "CSAnimMifPlugin::LoadL: arr pos %d, arr length %d",
             header().iArrayOffset, header().iArrayLength );
    User::LeaveIfError( errorCode );
    TInt fileSize( 0 );
    errorCode = file.Size( fileSize );
    ERROR( errorCode, "CSAnimMifPlugin::LoadL: failed to read file size" );
    User::LeaveIfError( errorCode );

    if ( header().iArrayOffset < 0 || header().iArrayLength <= 0 ||
         header().iArrayOffset + header().iArrayLength <= 0 ||
         header().iArrayOffset + header().iArrayLength > fileSize )
        {
        User::Leave( KErrCorrupt );
        }

    ReadIconArrayL( file, header().iArrayOffset, header().iArrayLength );

    CleanupStack::PopAndDestroy( &file );
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::ReadIconArrayL
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::ReadIconArrayL(
    RFile& aFile,
    const TInt32 aPosition,
    const TInt32 aLength )
    {
    FUNC_LOG;

    const TInt elementSize = sizeof( TIconOffsetElementPckg ) / 2;
    INFO_1( "Reserving %d bytes", aLength * elementSize );

    HBufC8* iconArray = HBufC8::NewLC( aLength * elementSize );
    TPtr8 iconArrayPtr = iconArray->Des();
    TInt errorCode = aFile.Read( aPosition, iconArrayPtr, aLength * elementSize );
    ERROR( errorCode, "CSAnimMifPlugin::ReadIconArrayL failed to read from file" );
    User::LeaveIfError( errorCode );

    INFO_1( "Read %d bytes", iconArrayPtr.Length() );

    for ( TInt i = 0; i < ( iconArrayPtr.Length() / elementSize ); i += KIconArrStep )
        {
        INFO_1( "Read icon %d", i );

        ReadIconOffsetElementL(
            aFile, iconArrayPtr.MidTPtr( i * elementSize, elementSize ) );
        }

    CleanupStack::PopAndDestroy( iconArray );
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::ReadIconOffsetElementL
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::ReadIconOffsetElementL(
    RFile& aFile,
    const TDesC8& aData )
    {
    FUNC_LOG;

    TIconOffsetElementPckg element;
    element.Copy( aData );
    INFO_2( "Offset %d, length %d", element().iOffset, element().iLength );

    TIconHeaderPckg header;
    TInt errorCode = aFile.Read( element().iOffset, header );
    ERROR( errorCode, "CSAnimMifPlugin::ReadIconOffsetElementL failed to read from file" );
    User::LeaveIfError( errorCode );

    INFO_2( "Data pos %d, data length %d", header().iDataOffset, header().iDataLength );
    INFO_3( "Type %d, depth %d, mask depth %d", header().iType, header().iDepth, header().iMaskDepth );

    if ( header().iType != KSvgType )
        {
        ERROR_1( KErrNotSupported, "Unsupported file type: %d", header().iType );

        User::Leave( KErrNotSupported );
        }

    HBufC8* data = HBufC8::NewLC( header().iDataLength );
    TPtr8 dataPtr = data->Des();
    errorCode = aFile.Read( element().iOffset + header().iDataOffset, dataPtr );
    ERROR( errorCode, "CSAnimMifPlugin::ReadIconOffsetElementL failed to read from file" );
    User::LeaveIfError( errorCode );

    CFbsBitmap* mask = new ( ELeave ) CFbsBitmap();
    CleanupStack::PushL( mask );
    User::LeaveIfError( mask->Create( iSize, EGray256 ) );

    CFbsBitmap* bmp = new ( ELeave ) CFbsBitmap();
    CleanupStack::PushL( bmp );
    User::LeaveIfError(
        bmp->Create( iSize, static_cast<TDisplayMode>( header().iDepth ) ) );

    TInt handle( 0 );
    errorCode = SvgToSymbianErr( iEngine->PrepareDom( dataPtr, handle ) );
    ERROR( errorCode, "Failed to prepare DOM" );
    User::LeaveIfError( errorCode );

    errorCode = SvgToSymbianErr( iEngine->UseDom( handle, bmp, mask ) );
    ERROR( errorCode, "Failed to use DOM" );
    User::LeaveIfError( errorCode );

    iEngine->SetPreserveAspectRatio(
        NULL, ESvgPreserveAspectRatio_XmidYmid, ESvgMeetOrSlice_Meet, ETrue );

    MSvgError* error = NULL;
    iEngine->Start( error );
    errorCode = SvgToSymbianErr( error );
    ERROR( errorCode, "Failed to start engine" );
    User::LeaveIfError( errorCode );

    errorCode = SvgToSymbianErr( iEngine->UseDom( handle, NULL, NULL ) );
    ERROR( errorCode, "Failed to use DOM (empty)" );
    User::LeaveIfError( errorCode );

    iEngine->DeleteDom( handle );

    iFrames.AppendL( bmp );
    CleanupStack::Pop( bmp ); // It's now in the array.

    iFrames.AppendL( mask );
    CleanupStack::Pop( mask ); // It's now in the array.

    CleanupStack::PopAndDestroy( data );
    }


// ---------------------------------------------------------------------------
// CSAnimMifPlugin::RefreshView
//
// ---------------------------------------------------------------------------
//
void CSAnimMifPlugin::RefreshView()
    {
    FUNC_LOG;
    ASSERT_TRACE( iCurrentFrame < iFrames.Count() - 1, SAnimPanic::EInternalError );

    iObserver.UpdateScreen(
        *( iFrames[iCurrentFrame] ), *( iFrames[iCurrentFrame + 1] ) );
    }