homesync/contentmanager/cmserver/cmmemorymanager/src/cmmmshrinker.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:00 +0200
changeset 0 7f85d04be362
permissions -rw-r--r--
Revision: 200947 Kit: 200951

/*
* Copyright (c) 2006-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:  CCmShrinker class in the Memory manager component
*
*/


#include <e32std.h>
#include <imageconversion.h> // CImageDecoder, CImageEncoder
#include <bitmaptransforms.h> // CBitmapScaler
#include <fbs.h> // CFbsBitmap
#include <w32std.h> // RWsSession, CWsScreenDevice

#include "cmdmmain.h"
#include "msdebug.h"
#include "cmmmimagemetadataresolver.h"
#include "cmmmobserver.h"
#include "cmmmshrinker.h"

// CONSTANTS
const TInt KScreenWidth = 128;
const TInt KScreenHeight = 128;


// ---------------------------------------------------------------------------
// CCmMmShrinker::NewL
// ---------------------------------------------------------------------------
//
CCmMmShrinker* CCmMmShrinker::NewL( CCmDmMain& aDbManager )
    {
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::NewL() start"));
    CCmMmShrinker* self = CCmMmShrinker::NewLC( aDbManager );
    CleanupStack::Pop( self );
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::NewL() end"));
    return self;
    }

// ---------------------------------------------------------------------------
// CCmMmShrinker::NewLC
// ---------------------------------------------------------------------------
//
CCmMmShrinker* CCmMmShrinker::NewLC( CCmDmMain& aDbManager )
    {
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::NewLC() start"));
    CCmMmShrinker* self = new ( ELeave ) CCmMmShrinker( aDbManager );
    CleanupStack::PushL( self );
    self->ConstructL();
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::NewLC() end"));
    return self;
    }

// ---------------------------------------------------------------------------
// C++ constructor
// ---------------------------------------------------------------------------
//
CCmMmShrinker::CCmMmShrinker( CCmDmMain& aDbManager ) :
    CActive( EPriorityIdle ),
    iShrinkIndex( 0 ),
    iState( EIdle ),
    iDbManager( aDbManager )
    {
    
    CActiveScheduler::Add( this );
    }


// ---------------------------------------------------------------------------
// CCmMmShrinker::ConstructL
// ---------------------------------------------------------------------------
//
void CCmMmShrinker::ConstructL()
    {
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::ConstructL() start"));

    User::LeaveIfError( iFileSession.Connect() );
    User::LeaveIfError( RFbsSession::Connect() );

    // Get the screen size
    iScreenSize = ScreenSizeL();
    
    iImageMetadataResolver = CCmMmImageMetadataResolver::NewL( iFileSession );

    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::ConstructL() end"));
    }


// ---------------------------------------------------------------------------
// C++ destructor
// ---------------------------------------------------------------------------
//
CCmMmShrinker::~CCmMmShrinker()
    {
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::~CCmMmShrinker() start"));
    Cancel();
    delete iBitmap;
    iFileSession.Close();
    
    delete iBitmapScaler;
    delete iFiles;
    delete iImageDecoder;
    delete iImageEncoder;
    RFbsSession::Disconnect();
    delete iImageMetadataResolver;
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::~CCmMmShrinker() end"));
    }

// ---------------------------------------------------------------------------
// CCmMmShrinker::DoCancel
// ---------------------------------------------------------------------------
//
void CCmMmShrinker::DoCancel()
    {
    ClearShrinker();
    }

// ---------------------------------------------------------------------------
// CCmMmShrinker::RunError
// ---------------------------------------------------------------------------
//
#ifdef _DEBUG
TInt CCmMmShrinker::RunError( TInt aError )
#else //_DEBUG
TInt CCmMmShrinker::RunError( TInt /*aError*/ )
#endif // _DEBÚG
    {
    TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker::RunError error = %d"),
                                                             aError ));
                                                                    
    // NOTE!!!
    // Should we continue from the next file, if there's error in the 
    // middle of the shrinking operation
    iShrinkIndex++;
    iState = EIdle;
    SetActive();
    TRequestStatus* status = &iStatus;
    User::RequestComplete( status, KErrNone );
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CCmMmShrinker::ShrinkImagesL
// ---------------------------------------------------------------------------
//
void CCmMmShrinker::ShrinkImagesL( CDesCArray& aFiles )
    {
    // Cancel 1st
    Cancel();
    
    // Add processed files 
    if ( &aFiles )
        {
        delete iFiles; 
        iFiles = NULL;
        iFiles = new ( ELeave ) CDesC16ArrayFlat( aFiles.Count() );
        for (TInt i = 0; i < aFiles.Count(); i++)
            {
            iFiles->AppendL( aFiles[i] );
            }
        }
    // Start the action
    iShrinkIndex = 0;
    iState = EIdle;
    SetActive();
    TRequestStatus* status = &iStatus;
    User::RequestComplete( status, KErrNone);    
    }
    
// ---------------------------------------------------------------------------
// CCmMmShrinker::SetObserver
// ---------------------------------------------------------------------------
//
void CCmMmShrinker::SetObserver( MCmMmObserver* aObserver )
    {
    iObserver = aObserver;
    }

// ---------------------------------------------------------------------------
// CCmMmShrinker::RunL
// ---------------------------------------------------------------------------
//
void CCmMmShrinker::RunL()
    {
    TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker::RunL status = %d"),
                                                             iStatus.Int() ));

    // If all files have been processed, notify the observer.
    if ( iShrinkIndex >= iFiles->Count() )
        {
        if ( iObserver )
            {
            iObserver->ShrinkCompleteL( KErrNone );
            }
        }
    else 
        {
        if ( iState == EIdle )
            {
            const TDesC& origFilename = (*iFiles)[iShrinkIndex];
            iImageMetadataResolver->CaptureOrginalMetadataL( origFilename );
            // Check that file exists (entry is not actually used)
            TEntry entry;
            User::LeaveIfError( iFileSession.Entry( origFilename, entry ));
            iStartTime.HomeTime();
            CImageDecoder* imageDecoder = NULL;
            TRAPD( error, 
                   imageDecoder = CImageDecoder::FileNewL( 
                        iFileSession,
                        origFilename,
                        CImageDecoder::EOptionNone ) );
            if ( error )
                {
                if ( iObserver )
                    {
                    iObserver->ShrinkCompleteL( error );
                    }
                }
            else
            	{
            	TUid imageType = KNullUid;
	            TUid imageSubType = KNullUid;
	            imageDecoder->ImageType( 0, imageType, imageSubType );

	            if (  imageType == KImageTypeBMPUid )
	                {
	                iState = EScale;
	                }
	            else if ( imageType == KImageTypeGIFUid ||
	                      imageType == KImageTypePNGUid ||
	                      imageType == KImageTypeJPGUid )
	                {
	                iState = EDecode;
	                }
	            else
	                {
	                if ( iObserver )
	                    {
	                    iObserver->ShrinkCompleteL( KErrNone );
	                    }
	                }

	            delete imageDecoder;
	            imageDecoder = NULL;
            	}
            }

        TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker: status = %d"),
            iStatus.Int() ));

        switch ( iState )
            {
            case EDecode:
                {
                const TDesC& origFilename = (*iFiles)[iShrinkIndex];
                TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker: Decoding file \
                    %S"), &origFilename ));

                delete iImageDecoder;
                iImageDecoder = NULL;
                delete iBitmap;
                iBitmap = NULL;

                iImageDecoder = CImageDecoder::FileNewL( iFileSession,
                                                         origFilename, CImageDecoder::EOptionNone );
                iBitmap = new (ELeave) CFbsBitmap();
                TInt error = iBitmap->Create(
                    iImageDecoder->FrameInfo().iOverallSizeInPixels,
                    iImageDecoder->FrameInfo().iFrameDisplayMode );
                if ( error != KErrNone )
                    {
                    TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker::RunL \
                        error: %d"), error ));
                    if ( iObserver )
                        {
                        TRACE(Print(_L("[MEMORY MNGR]\t Clearing shrinker" )));                        
                        ClearShrinker();
                        iObserver->ShrinkCompleteL( error );
                        }
                    Cancel();
                    }
                else 
                    {
                    iImageDecoder->Convert( &iStatus, *iBitmap );

                    iState = EScale;
                    SetActive();
                    }
                break;
                }
            case EScale:
                {
                const TDesC& origFilename = (*iFiles)[iShrinkIndex];
                TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker: Scaling file \
                    %S"), &origFilename ));

                // If converting is still ongoing we should continue it
                if ( iStatus == KErrUnderflow )
                    {
                    TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker: \
    Still decoding file %S"), &origFilename ));
                    iImageDecoder->ContinueConvert( &iStatus );
                    SetActive();
                    }
                else 
                    {
                    delete iBitmapScaler;
                    iBitmapScaler = NULL;
                    iBitmapScaler = CBitmapScaler::NewL();

                    iBitmapScaler->Scale( &iStatus, *iBitmap, iScreenSize );
                    iState = EEncode;
                    SetActive();

                    delete iImageDecoder;
                    iImageDecoder = NULL;
                    }

                break;
                }
            case EEncode:
                {
                const TDesC& origFilename = (*iFiles)[iShrinkIndex];
                TRACE(Print(_L("[MEMORY MNGR]\t CCmMmShrinker: Encoding file \
                    %S"), &origFilename ));

                delete iImageEncoder;
                iImageEncoder = NULL;
                
                // Shrink into private directory
                PrivatePath( iFileSession, iTempFilename, origFilename );
                
                // Check that if the file already exists somehow...
                if ( iTempFilename == origFilename )
                    {
                    // Delete the original
                    iFileSession.Delete( origFilename );
                    }
                iImageEncoder = CImageEncoder::FileNewL(
                    iFileSession,
                    iTempFilename,
                    CImageEncoder::EOptionNone,
                    KImageTypeJPGUid );

                iImageEncoder->Convert( &iStatus, *iBitmap );
                iState = EReplace;

                SetActive();
                break;
                }
            case EReplace:
                {
                const TDesC& origFilename = (*iFiles)[iShrinkIndex];
                TRACE( Print(
                    _L("[MEMORY MNGR]\t CCmMmShrinker: Replacing file %S"),
                    &origFilename) );                                                 
                                                        
                TInt error = iFileSession.Replace( 
                    iTempFilename, 
                    origFilename );                                       
                    
                TRACE( Print(
                    _L("[MEMORY MNGR]\t CCmMmShrinker: Replace done err: %d"),
                    error ) );
                    
                // Resolve orginal image metadata!!!
                TRAPD( mdError, iImageMetadataResolver->ResolveMetadataL(
                        origFilename ) );
                if( mdError )
                    {
                    TRACE( Print(
                        _L("[MEMORY MNGR]\t Metadata resolving error : %d"),
                        mdError ) );                    
                    }
                    
                iStopTime.HomeTime();

                TTimeIntervalMicroSeconds t =
                    iStartTime.MicroSecondsFrom( iStopTime );
                error =  iDbManager.IncrementShrinkTimeL(
                    iFiles->Count(),
                    iStartTime.MicroSecondsFrom( iStopTime ).Int64() / 1000 );
                    
                iState = EIdle;
                iShrinkIndex++;
                SetActive();
                TRequestStatus* status = &iStatus;
                User::RequestComplete( status, KErrNone );
                break;
                }
            case EIdle:
            	{
            	TRACE( Print(_L("[MEMORY MNGR]\t CCmMmShrinker::RunL() \
                Idle state")) );
                break;
                }
            default:
                {
                TRACE( Print(_L("[MEMORY MNGR]\t CCmMmShrinker::RunL() \
                Incorrect state")) );
                if ( iObserver )
                    {
                    iObserver->ShrinkCompleteL( iStatus.Int() );
                    }
                Cancel();
                break;
                }
            }
        }
    }


// ---------------------------------------------------------------------------
// CCmMmShrinker::ScreenSizeL
// ---------------------------------------------------------------------------
//
TSize CCmMmShrinker::ScreenSizeL()
    {
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::ScreenSizeL() start"));

    TSize screenSize( KScreenWidth, KScreenHeight );
    RWsSession session;

    TInt error = session.Connect() ;
    CleanupClosePushL( session );
    if ( !error )
        {
        CWsScreenDevice* screenDevice = 
            new ( ELeave ) CWsScreenDevice( session );
        if ( screenDevice && !screenDevice->Construct() )
            {
            TSize temp( KScreenWidth, KScreenHeight );
            temp = screenDevice->SizeInPixels();
            // Use landscape mode in shrinking
            TRACE(Print(_L("[MEMORY MNGR]\t Image height = %d"),temp.iWidth));
            TRACE(Print(_L("[MEMORY MNGR]\t Image width = %d"),temp.iHeight)); 
            screenSize.iHeight = temp.iWidth;
            screenSize.iWidth = temp.iHeight;
            }
        delete screenDevice;
        screenDevice = NULL;
        }

    CleanupStack::PopAndDestroy( &session );

    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::ScreenSizeL() end"));
    return screenSize;
    }

// ---------------------------------------------------------------------------
// CCmMmShrinker::PrivatePath
// ---------------------------------------------------------------------------
//   
void CCmMmShrinker::PrivatePath( RFs& aFs, 
                                 TFileName& aPrivatePath, 
                                 const TFileName& aOriginal )
    {
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::PrivatePath() start"));
    
    aPrivatePath.Zero();
    
    TParse nameParse;
    nameParse.Set( aOriginal, NULL, NULL );
        
    aPrivatePath.Append( nameParse.Drive() );
    TFileName privatePath;
    TInt err = aFs.PrivatePath( privatePath );
    if ( !err )
        {
        aPrivatePath.Append( privatePath );
        
        // Now the path contains everything but filename and extension
        // => check that the directory exists. If not, it will be created.
        // Possible error is ignored at the moment 
        // (normal case is KErrAlreadyExists)
        err = aFs.MkDirAll( aPrivatePath );
        
        
        aPrivatePath.Append( nameParse.NameAndExt() );
        }
    LOG(_L("[MEMORY MNGR]\t CCmMmShrinker::PrivatePath() end"));
    }
    
// ---------------------------------------------------------------------------
// CCmMmShrinker::ClearShrinker
// ---------------------------------------------------------------------------
//
void CCmMmShrinker::ClearShrinker()
    {
    if ( iImageDecoder )
        {
        iImageDecoder->Cancel();
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    if ( iBitmapScaler )
        {
        iBitmapScaler->Cancel();
        delete iBitmapScaler;
        iBitmapScaler = NULL;        
        }
    if ( iImageEncoder )
        {
        iImageEncoder->Cancel();
        delete iImageEncoder;
        iImageEncoder = NULL;        
        }
    if( iBitmap )
        {
        delete iBitmap;
        iBitmap = NULL;
        }
    }
    
// End of file