/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Symbian Foundation License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Implementation of class CAknIconSrv.
*
*/



// INCLUDE FILES

#include <e32svr.h>
#include <e32property.h>
#include <fbs.h>
#include <gdi.h>
#include <bitdev.h>
#include <mifconvdefs.h>

#ifdef PRECACHELOG
#include <flogger.h>
#endif
#include "AknIconSrv.h"
#include "AknIconSrvScheduler.h"
#include "AknIconSrvSession.h"
#include "AknIconSrvDef.h"
#include "AknIconSrvIconItem.h"
#include "AknIconFormatHandler.h"
#include "AknIconFormatHandlerFactory.h"
#include "AknIconLoader.h"
#include "AknIconSrvCache.h"
#include "AknIconSrvPanic.h"
#include "AknIconUtils.h"
#include "AknIconDataPreserver.h"
#include "AknIconDataItem.h"
#include "AknIconSrvUtils.h"
#include "AknIconFileNameCache.h"
#include "akniconconfig.h"
#include "AknIconTraces.h"

#include "AknBitmap.h"
#include <centralrepository.h>
#include <UikonInternalPSKeys.h>    // KUikLayoutState
#include <AvkonInternalCRKeys.h>    // KAknQwertyInputModeActive
#include <avkondomainpskeys.h>      // KAknPowerMenuStatus
#include <bitdev.h>
// CONSTANTS

const TUid KZiUdbProterty = {0x101F8614};
const TInt KZiUdbPropertyKey = 1;
const TUid KT9UdbProterty = {0x101F8615};
const TInt KT9UdbPropertyKey = 1;

const TInt KIconItemArrayGranularity = 4;

// Value -1 is used to indicate 'automatic' layout ID detection.        
const TInt KAvkonAutomaticLayoutDetectionValue = -1;

_LIT( KAvkonIconFileName, "z:\\resource\\apps\\avkon2.mif" );
_LIT( KAknIconServerStartupSemaphore, "AknIconSem" );

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

CAknIconServer::CAknIconServer()
    : CServer2( CActive::EPriorityStandard ),
    iIconItems( KIconItemArrayGranularity )
    {
    }

// Create and start a new server.
CAknIconServer* CAknIconServer::NewL()
    {
    CAknIconServer* server = new( ELeave ) CAknIconServer;
    CleanupStack::PushL( server );
    server->ConstructL();
    CleanupStack::Pop();
    return server;
    }

void CAknIconServer::ConstructL()
    {    
    User::LeaveIfError( iFsSession.Connect() );
    User::LeaveIfError( RFbsSession::Connect() );
    User::LeaveIfError( Start( KAknIconSrvName ) );

    iFileNameCache = CAknIconFileNameCache::NewL();
    iIconDataPreserver = CAknIconDataPreserver::NewL( *this );

    
    _LIT_SECURITY_POLICY_PASS(KPassReadPolicy);
    _LIT_SECURITY_POLICY_PASS(KPassWritePolicy);

    _LIT_SECURITY_POLICY_C1(KWriteDDPolicy, ECapabilityWriteDeviceData);
    _LIT_SECURITY_POLICY_C1(KWriteTUPolicy, ECapabilityTrustedUI);
    
    TInt err1  = RProperty::Define(KCRUidAvkon,       KAknQwertyInputModeActive, RProperty::EInt, KPassReadPolicy, KWriteDDPolicy);
    TInt err2  = RProperty::Define(KPSUidUikon,       KUikLayoutState,           RProperty::EInt, KPassReadPolicy, KWriteDDPolicy);
    TInt err3  = RProperty::Define(KPSUidUikon,       KUikOOMWatchdogStatus,     RProperty::EInt, KPassReadPolicy, KPassWritePolicy);
    TInt err4  = RProperty::Define(KPSUidUikon,       KUikVideoCallTopApp,       RProperty::EInt, KPassReadPolicy, KWriteDDPolicy);
    TInt err5  = RProperty::Define(KPSUidUikon,       KUikFFSFreeLevel,          RProperty::EInt, KPassReadPolicy, KWriteTUPolicy);
    TInt err6  = RProperty::Define(KPSUidUikon,       KUikMmcFFSFreeLevel,       RProperty::EInt, KPassReadPolicy, KWriteTUPolicy);
    TInt err7  = RProperty::Define(KPSUidUikon,       KUikGlobalNotesAllowed,    RProperty::EInt, KPassReadPolicy, KWriteDDPolicy);
    TInt err8  = RProperty::Define(KZiUdbProterty,    KZiUdbPropertyKey,         RProperty::EInt, KPassReadPolicy, KPassWritePolicy);
    TInt err9  = RProperty::Define(KT9UdbProterty,    KT9UdbPropertyKey,         RProperty::EInt, KPassReadPolicy, KPassWritePolicy);
    TInt err10 = RProperty::Define(KPSUidAvkonDomain, KAknPowerMenuStatus,       RProperty::EInt, KPassReadPolicy, KWriteDDPolicy);
    TInt err11 = RProperty::Define(KPSUidAvkonDomain, KAknEndKeyEvent,           RProperty::EInt, KPassReadPolicy, KWriteDDPolicy);         

#ifdef _DEBUG
    RDebug::Print(_L("xxxx KAknQwertyInputModeActive err=%d"), err1);
    RDebug::Print(_L("xxxx KUikLayoutState           err=%d"), err2);
    RDebug::Print(_L("xxxx KUikOOMWatchdogStatus     err=%d"), err3);
    RDebug::Print(_L("xxxx KUikVideoCallTopApp       err=%d"), err4);
    RDebug::Print(_L("xxxx KUikFFSFreeLevel          err=%d"), err5);
    RDebug::Print(_L("xxxx KUikMmcFFSFreeLevel       err=%d"), err6);
    RDebug::Print(_L("xxxx KUikGlobalNotesAllowed    err=%d"), err7);
    RDebug::Print(_L("xxxx KZiUdbProterty            err=%d"), err8);
    RDebug::Print(_L("xxxx KT9UdbProterty            err=%d"), err9);
    RDebug::Print(_L("xxxx KAknPowerMenuStatus       err=%d"), err10);
    RDebug::Print(_L("xxxx KAknEndKeyEvent           err=%d"), err11);
#endif
    
    CRepository* repository = NULL;
    TRAPD(ret, repository = CRepository::NewL(KCRUidAvkon));
    if (ret == KErrNone)
        {
        // Reset value of KAknLayoutId on the boot.
        // Return value ignored.
        ret = repository->Set(KAknLayoutId, KAvkonAutomaticLayoutDetectionValue); 
        }
    delete repository;
    repository = NULL;     
         
#ifdef _NGATESTING

    do {

    iConfigIconType = -1;

    TRAPD(leaveError, LoadConfigurationL(iFsSession));

		if(leaveError!=KErrNone)
		{
			#ifdef _DEBUG
		RDebug::Print(_L("xxxx LoadConfigurationL err=%d"), leaveError);
		#endif
		}

    } while (0);

#endif
    iThreadLaunchStatus = KRequestPending;
    // This launches SVG precache thread, if required.

    iCache = CAknIconSrvCache::NewL( *this );
    User::WaitForRequest( iThreadLaunchStatus );
    }

CAknIconServer::~CAknIconServer()
    {
    iIconItems.ResetAndDestroy();

    delete iAvkonIconLoader;
    delete iOtherIconLoader;
    delete iCurrentIconFile;
    delete iCache;
    delete iIconDataPreserver;    
    delete iFileNameCache;
    
    iHandlerList.ResetAndDestroy();
    RFbsSession::Disconnect();
    iFsSession.Close();
    }

// -----------------------------------------------------------------------------
// CAknIconServer::NewSessionL()
// -----------------------------------------------------------------------------

CSession2* CAknIconServer::NewSessionL(
    const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
    {
    return new( ELeave ) CAknIconSrvSession( );
    }

// -----------------------------------------------------------------------------
// CAknIconServer::RetrieveOrCreateSharedIconL
// -----------------------------------------------------------------------------
//
const CAknIconSrvIconItem* CAknIconServer::RetrieveOrCreateSharedIconL()
    {
    #ifdef __AKNICON_TRACES
    RDebug::Print(_L("AKNICON start"));
    #endif
    
    TAknIconParams info;
    TPckg<TAknIconParams> infoPack( info );
    TRAPD( err, Message().ReadL( 0, infoPack ) );
	if ( err != KErrNone ) 
    	{
    	((CAknIconSrvSession*)(Message().Session()))->SetClientPanicCode(EBadDescriptor);
    	User::Leave(KAknIconSrvCodePanicClient);
    	}
	
    TAknIconSrvReturnData retData;
    TPckg<TAknIconSrvReturnData> dataPack( retData );

    CAknIconSrvIconItem* item = NULL;

#ifdef __AKNICON_TRACES
    info.PrintInfo();
#endif     
#ifdef PRECACHE2
     // bitmap handles of precached icons need to be duplicated
     while(iNewPrecachedItems.Count())
        {
        #ifdef __AKNICON_TRACES
        RDebug::Printf("Precache add,%d",iNewPrecachedItems.Count());
        #endif
        
        CAknIconSrvIconItem* item = iNewPrecachedItems[0];
        CFbsBitmap* bitmap = new (ELeave) CFbsBitmap;
        CleanupStack::PushL(bitmap);
        TInt err1 = bitmap->Duplicate(item->iBitmap->Handle());
        iFreePrecacheBitmapHandles.AppendL(item->iBitmap);
        CleanupStack::Pop();
        
        item->iBitmap = bitmap;
        CFbsBitmap* mask = NULL;
        if (item->iMask)
            {
            mask = new (ELeave) CFbsBitmap;
            CleanupStack::PushL(mask);
            TInt err2 = mask->Duplicate(item->iMask->Handle());
            iFreePrecacheBitmapHandles.AppendL(item->iMask);
            CleanupStack::Pop();
            item->iMask = mask;
            }

            
        err1 = iIconItems.InsertInOrder( item, CAknIconSrvIconItem::LinearOrder );
        if (err1 == KErrAlreadyExists)
            {
            iNewPrecachedItems.Remove(0);
                    
            #ifdef __AKNICON_TRACES
            RDebug::Printf("precache warning, already exists!");
            #endif
            
            TInt index = iIconItems.FindInOrder(item, CAknIconSrvIconItem::LinearOrder );
            CAknIconSrvIconItem* foundItem = iIconItems[index];
            
            foundItem->iPrecacheItem = ETrue;
            
            //Set this item to be cached
            if(foundItem->IsExcludedFromCache())
                {
                foundItem->SetCached();
                }
            
            //Item not in use and hence in Dynamic cache
            //Move item from dynamic cache to precache    
            if( foundItem->iUserCount == 0)
                {
                iCache->DynamicToPrecache( *foundItem);    
                }
            else
                {
                }
            delete item;
            }
        else if (err1 == KErrNone)
            {
            iNewPrecachedItems.Remove(0);
            
            #ifdef __AKNICON_TRACES
            RDebug::Print(_L("precache load,%S,%d,%d,%d,%d,%d,%d,%d"),
                 item->iFileName,
                 item->iBitmapId,
                 item->iMaskId,
                 item->iSize.iWidth,
                 item->iSize.iHeight,
                 item->iModeAndFlags & 0xffff,
                 item->iRotationAngle,
                 item->iColor.Internal());
            #endif    
                 
            iCurrentIndex = iIconItems.FindInOrder(item, CAknIconSrvIconItem::LinearOrder );
            // delete icon, so it will be moved to icon cache
            if (DeleteOrCacheUnusedIcon(item) == EFalse)
                {
                AknIconConfig::CompressIfPreferred(bitmap, mask,iCompression);
                }
            else
                {
	            #ifdef __AKNICON_TRACES
	            RDebug::Printf("Did not insert into dynamic cache, deleting item");
	            #endif
                }
            }
        else
            {
            
            #ifdef __AKNICON_TRACES
            RDebug::Printf("precache warning, Unable to insert into iIconItems");
            #endif
            // No point continuing if one item insertion fails, as
            // following requests would result in same error.
            break;
            }
        }
        
     if (iPrecacheComplete)
        {
        iPreCacheThread.Resume();
        iPrecacheComplete = EFalse;
        }
#endif
    TInt index = RetrieveIcon( info );
    if ( index >= 0 )
        {
        item = iIconItems[index];

        item->iUserCount++;
        if ( info.iMaskId >= 0 )
            {
            // Also mask increases user count.
            item->iUserCount++;
            }

#ifdef __AKNICON_TRACES
    RDebug::Print( _L("AknIcon: %x CAknIconServer::RetrieveOrCreateSharedIconL: existing item=%x, info=%x"), this, item, &info);
#endif   
            
        }
    // Not found in current icon item list
    else
        {
        // MBM icon case
        if ( info.IsMbmIcon() )
            {
            Message().ReadL( 1, dataPack );
            item = CreateMbmIconL( info, retData );
            }

        // MIF icon case
        else
            {

            item = iIconDataPreserver->CreateIconL( info );

            if ( !item )
                {
                item = CreateIconL( info );
                }
            
             //PrecacheCache tool
            #ifdef PRECACHELOG                 

            
            _LIT( KFileLoggingDir, "AknIconPreCacher" );
            _LIT( KFileLog, "Traces.txt" );
                     


            _LIT(lMsg, "AKNICON load,%S,%d,%d,%d,%d,%d,%d,%d,%d");
            RFileLogger::WriteFormat(KFileLoggingDir, KFileLog, EFileLoggingModeAppend, lMsg,
            &info.iFileName,
                     info.iBitmapId,
                     info.iMaskId,
                     info.iSize.iWidth,
                     info.iSize.iHeight,
                     info.iMode,
                     info.iRotationAngle,
                     info.iColor.Internal(),
                     info.IsCompressionDisabled());                 
                     
                
               
                    
            #endif
            //PrecacheCache tool
                }
       
       
        if ( info.iAppIcon )
            {
            if ( info.IsMbmIcon() )
                {
                AknIconSrvUtils::EnsureValidSizeL(item->iBitmap, item->iMask);   
                }
           #ifndef __NVG
		else 
		    {
		    ReCreateSvgL(info,item);
		    } 
           #endif /*__NVG*/
            }
       
#ifdef __AKNICON_TRACES
    RDebug::Print( _L("AknIcon: %x CAknIconServer::RetrieveOrCreateSharedIconL: new item=%x, info=%x"), this, item, &info);
#endif   
        CleanupStack::PushL( item );

        // Apply icon color here, if requested.
        ApplyIconColorL( item, info.iColor );

        // Call CompressIfPreferred if bitmap compression is not
        // disabled for the icon
        if (!item->IsCompressionDisabled())
            {
            AknIconConfig::CompressIfPreferred(item->iBitmap, item->iMask,iCompression);     
            }               

        User::LeaveIfError( 
            iIconItems.InsertInOrder( item, CAknIconSrvIconItem::LinearOrder ) );

        CleanupStack::Pop(); // item
        }

    // No leaving code allowed in the end of the function!
    // Otherwise icon item's user count is increased but never decreased,
    // because an error code is returned to the client.

    retData.iBitmapHandle = item->iBitmap->Handle();
    if ( item->iMask )
        {
        retData.iMaskHandle = item->iMask->Handle();
        }

    retData.iContentDimensions = item->iDimensions;

    // Remove item from cache because it is now used by someone.
    iCache->RemoveIfCached( *item );
    
    #ifdef __AKNICON_TRACES
    RDebug::Print(_L("AKNICON loaded,%S,%d,%d"),&info.iFileName,info.iBitmapId,item->iBitmap->Handle());
    #endif
    // Set if the icon will be cached dynamically after it is not used
    // Note that if the icon was excluded from cache earlier it will remain
    // excluded for its lifetime.
    if (info.IsExcludedFromCache())
        {
        item->ExcludeFromCache();    
        }

    // This does not leave as long as the descriptor is valid in the client side.
    Message().WriteL( 1, dataPack );

    return item;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::FreeBitmapL
//
// Note: This function can only leave when an ASSERT fails. During normal 
//       conditions it should never leave.
// -----------------------------------------------------------------------------
//
const CAknIconSrvIconItem* CAknIconServer::FreeBitmapL()
    {
    TAknIconParams info;
    TPckg<TAknIconParams> paramPack( info );
    TRAPD( err, Message().ReadL( 0, paramPack ) );

    __ASSERT_ALWAYS( err == KErrNone, 
       (
       ((CAknIconSrvSession*)(Message().Session()))->SetClientPanicCode(EBadDescriptor),
       User::Leave( KAknIconSrvCodePanicClient ) // leave to prevent possible server crash
       ));
       

    iCurrentIndex = RetrieveIcon( info );

    __ASSERT_ALWAYS( iCurrentIndex >= 0, 
        (
        ((CAknIconSrvSession*)(Message().Session()))->SetClientPanicCode(EIconNotFound),
        User::Leave( KAknIconSrvCodePanicClient ) // leave to prevent possible server crash
        ));

    CAknIconSrvIconItem* item = iIconItems[iCurrentIndex];
		  if (info.IsExcludedFromCache())
        {
        item->ExcludeFromCache();    
        }    

    item->iUserCount--;
    
#ifdef __AKNICON_TRACES
    RDebug::Print( _L("AknIcon: %x CAknIconServer::FreeBitmapL: item=%x, user count=%d"), this, item, item->iUserCount);
#endif 
    
    DeleteOrCacheUnusedIcon( item );

    // It is safe to return also a pointer to a deleted item.
    return item;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::PreserveIconDataL
// -----------------------------------------------------------------------------
//
const CAknIconDataItem* CAknIconServer::PreserveIconDataL()
    {
    TAknIconParams params;
    TPckg<TAknIconParams> paramsPack( params );
    TRAPD( err, Message().ReadL( 0, paramsPack ) );
	if ( err != KErrNone ) 
    	{
    	((CAknIconSrvSession*)(Message().Session()))->SetClientPanicCode(EBadDescriptor);
    	User::Leave(KAknIconSrvCodePanicClient);
    	}

    return iIconDataPreserver->PreserveIconDataL( params );
    }

// -----------------------------------------------------------------------------
// CAknIconServer::UnpreserveIconDataL
//
// Note: This function can only leave when an ASSERT fails. During normal 
//       conditions it should never leave.
// -----------------------------------------------------------------------------
//
const CAknIconDataItem* CAknIconServer::UnpreserveIconDataL()
    {
    TAknIconParams params;
    TPckg<TAknIconParams> paramsPack( params );

    TRAPD( err, Message().ReadL( 0, paramsPack ) );
	if ( err != KErrNone ) 
    	{
    	((CAknIconSrvSession*)(Message().Session()))->SetClientPanicCode(EBadDescriptor);
    	User::Leave(KAknIconSrvCodePanicClient);
    	}
    	

    return iIconDataPreserver->UnpreserveIconData( params, 1, Message());
    }

// -----------------------------------------------------------------------------
// CAknIconServer::GetContentDimensionsL
// -----------------------------------------------------------------------------
//
void CAknIconServer::GetContentDimensionsL()
    {
    TAknIconParams params;
    TPckg<TAknIconParams> paramsPack( params );
    TRAPD( err, Message().ReadL( 0, paramsPack ) );
	if ( err != KErrNone ) 
    	{
    	((CAknIconSrvSession*)(Message().Session()))->SetClientPanicCode(EBadDescriptor);
    	User::Leave(KAknIconSrvCodePanicClient);
    	}

    TAknContentDimensions dimensions;

    iIconDataPreserver->GetContentDimensionsL( params, dimensions );

    TPckg<TAknContentDimensions> dimensionsPack( dimensions );
    Message().WriteL( 1, dimensionsPack );
    }

// -----------------------------------------------------------------------------
// CAknIconServer::CleanupSessionIconItem
// -----------------------------------------------------------------------------
//
void CAknIconServer::CleanupSessionIconItem( 
    const TAknIconSrvSessionIconItem& aItem )
    {
    TAknIconParams info;
    aItem.iIcon->GetInfo( info );

    iCurrentIndex = RetrieveIcon( info );

    // The icon must be found otherwise there is a coding error
    // in server side.
    __ASSERT_DEBUG( iCurrentIndex >= 0, 
        User::Panic( KAknIconPanicCategory, EIconNotFound ));

    if (iCurrentIndex >= 0)
        {
    CAknIconSrvIconItem* item = iIconItems[iCurrentIndex];

    item->iUserCount -= aItem.iUserCount; 
    DeleteOrCacheUnusedIcon( item );
        }
    }

// -----------------------------------------------------------------------------
// CAknIconServer::CleanupSessionPreservedItem
// -----------------------------------------------------------------------------
//
void CAknIconServer::CleanupSessionPreservedItem( 
    const TAknIconSrvSessionPreservedItem& aItem )
    {
    TAknIconParams info;
    aItem.iDataItem->GetInfo( info );
    iIconDataPreserver->UnpreserveIconData( info, aItem.iUserCount, Message() );
    }

// -----------------------------------------------------------------------------
// CAknIconServer::RemoveCachedItem
// -----------------------------------------------------------------------------
//
void CAknIconServer::RemoveCachedItem( const CAknIconSrvIconItem& aItem )
    {
    TInt index = iIconItems.FindInOrder(
        &aItem, CAknIconSrvIconItem::LinearOrder );

    __ASSERT_DEBUG( index >= 0,
        User::Panic( KAknIconSrvPanicCategory, ESrvPanicIconNotFound ) );

    __ASSERT_DEBUG( aItem.iUserCount == 0,
        User::Panic( KAknIconSrvPanicCategory, ESrvPanicCachedItemUserCountNonZero ) );

    __ASSERT_DEBUG( index != iCurrentIndex,
        User::Panic( KAknIconSrvPanicCategory, ESrvPanicCurrentIconItemDeleted ) );

    iIconItems.Remove( index );
    delete &aItem;

    // Array has changed, so have to keep iCurrentIndex valid. It is used in
    // another function, which calls this function.
    if ( index < iCurrentIndex )
        {
        iCurrentIndex--;
        }
    }



// -----------------------------------------------------------------------------
// CAknIconServer::InvalidateItemsCachedFromSkin
// -----------------------------------------------------------------------------
//
void CAknIconServer::InvalidateItemsCachedFromSkin()
    {
    for ( TInt i = iIconItems.Count() - 1 ; i >= 0 ; i-- )
        {
        CAknIconSrvIconItem* item = iIconItems[i];

        if ( item->IsCachedFromSkin() )
            {
            item->ClearPermanentlyCached();

            if ( item->iUserCount == 0 )
                {
                iIconItems.Remove( i );
                delete item;
                }
            }
        }
    }



// -----------------------------------------------------------------------------
// CAknIconServer::ResetDynamicallyChangingAllocations
// -----------------------------------------------------------------------------
//
void CAknIconServer::ResetDynamicallyChangingAllocations()
    {
#ifdef _DEBUG
    // Reset dynamic cache
    iCurrentIndex = -1;
    iCache->ResetDynamicCache();

    // Reset dynamically changing icon loader
    delete iCurrentIconFile;
    iCurrentIconFile = NULL;
    delete iOtherIconLoader;
    iOtherIconLoader = NULL;

#endif // _DEBUG
    }

// -----------------------------------------------------------------------------
// CAknIconServer::SetPreferredIconDisplayMode
// -----------------------------------------------------------------------------
//
#ifdef _DEBUG
void CAknIconServer::SetPreferredIconDisplayMode( TDisplayMode aMode )
    {
    iIconMode = aMode;
    }
#else
void CAknIconServer::SetPreferredIconDisplayMode( TDisplayMode /*aMode*/ )
    {
    }
#endif

// -----------------------------------------------------------------------------
// CAknIconServer::GetInitData
// -----------------------------------------------------------------------------
//
void CAknIconServer::GetInitData(
    TAknIconInitData& aData ) const
    {
    aData.iCompression = iCompression;
    aData.iIconMode = iIconMode;
    aData.iIconMaskMode = iIconMaskMode;
    aData.iPhotoMode = iPhotoMode;
    aData.iVideoMode = iVideoMode;
    aData.iOffscreenMode = iOffscreenMode;
    aData.iOffscreenMaskMode = iOffscreenMaskMode;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::RetrieveIcon
// -----------------------------------------------------------------------------
//
TInt CAknIconServer::RetrieveIcon( const TAknIconParams& aInfo )
    {
    // Can be constructed in stack with this constructor.
    CAknIconSrvIconItem compareItem( aInfo );

    return iIconItems.FindInOrder(
        &compareItem, CAknIconSrvIconItem::LinearOrder );
    }



// -----------------------------------------------------------------------------
// CAknIconServer::CreateIconL
// -----------------------------------------------------------------------------
//
CAknIconSrvIconItem* CAknIconServer::CreateIconL(
    const TAknIconParams& aInfo )
    {
    CFbsBitmap* bitmap = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( bitmap );

    CFbsBitmap* mask = NULL;

    if ( aInfo.iMaskId >= 0 )
        {
        mask = new (ELeave) CFbsBitmap;
        CleanupStack::PushL( mask );
        }
    MAknIconFormatHandler* handler = NULL;
    CAknIconLoader* loader = NULL;

    TInt handle;

    TDisplayMode bitmapDepth;    

    // Makes sure that the icon loader is released when required.

    CleanupStack::PushL( TCleanupItem( CleanupIconLoader, this ) );    

    TPtrC8 iconData = InitIconDataAndHandlerLC(aInfo, loader, handler);        

    bitmapDepth = (TDisplayMode)loader->IconDepthL( aInfo.iBitmapId );    

    handler->PrepareIconL( iconData, handle );

    // CleanupIconLoader, InitIconDataAndHandlerLC
    CleanupStack::PopAndDestroy( 2 ); 

    TAknContentDimensions dimensions;

    TRAPD( err,
        {
        handler->UsePreparedIconL( handle );

            dimensions = AknIconSrvUtils::RenderPreparedIconL(

                    *handler,

                    bitmap,

                    mask,

                    bitmapDepth,

                    iIconMode,

                    aInfo.iSize,

                    (TScaleMode)aInfo.iMode,

                    aInfo.iRotationAngle,

                    aInfo.iColor,

                    aInfo.iBitmapId,

                    aInfo.iMaskId,

                    aInfo.iAppIcon);

            } );

    

    // Below is the code to retrieve the actual rendering size of the icon as per normalizations done above in RenderPreparedIconL

    TSize iconSize(aInfo.iSize);

    if ( aInfo.iMode == EAspectRatioPreservedAndUnusedSpaceRemoved )

        {

        if ( iconSize.iWidth!=0 && iconSize.iHeight!=0 )

            {

            AknIconSrvUtils::GetAspectRatioPreservedSize( dimensions, iconSize );

            }

        }        

    

    handler->UnprepareIcon( handle );

    User::LeaveIfError( err );

    // Create item definition and insert in the array.
    CAknIconSrvIconItem* item = 
        CAknIconSrvIconItem::NewL( aInfo, bitmap, mask, dimensions, IconFileNameCache() );

    CleanupStack::Pop(); // bitmap
    if ( mask )
        {
        CleanupStack::Pop(); // mask
        }

    return item;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::CreateMbmIconL
// -----------------------------------------------------------------------------
//
CAknIconSrvIconItem* CAknIconServer::CreateMbmIconL( 
    const TAknIconParams& aInfo,
    const TAknIconSrvReturnData& aRetData )
    {
    // Create a new bitmap to be stretched to the given size.
    CFbsBitmap* bitmap = new (ELeave) CFbsBitmap;
    CleanupStack::PushL( bitmap );

    CFbsBitmap* loadedBitmap = new( ELeave ) CFbsBitmap;
    CleanupStack::PushL( loadedBitmap );

    // Duplicate the loaded bitmap in this thread.
    User::LeaveIfError( loadedBitmap->Duplicate( aRetData.iBitmapHandle ) );

    CFbsBitmap* mask = NULL;
    CFbsBitmap* loadedMask = NULL;

    if ( aInfo.iMaskId >= 0 )
        {
        // Create a new mask to be stretched to the given size.
        mask = new (ELeave) CFbsBitmap;
        CleanupStack::PushL( mask );

        loadedMask = new( ELeave ) CFbsBitmap;
        CleanupStack::PushL( loadedMask );

        User::LeaveIfError( loadedMask->Duplicate( aRetData.iMaskHandle ) );
        }

    // Perform scaling and color filling if required
    TBool colorIcon = AknIconSrvUtils::ScaleBitmapIconL(
        aInfo.iSize,
        (TScaleMode)aInfo.iMode,
        aInfo.iRotationAngle,
        aInfo.iColor,
        loadedBitmap,
        loadedMask,
        bitmap,
        mask );

    // Create item definition and insert in the array.
    // Content dimensions of bitmap icons are not stored in server side,
    // so use (-1,-1).
    CAknIconSrvIconItem* item = 
        CAknIconSrvIconItem::NewL( aInfo, 
                                   bitmap,
                                   mask,
                                   TAknContentDimensions( -1, -1 ),
                                   IconFileNameCache() );

    // Set information of the applied color.
    if ( colorIcon )
        {
        item->iColor = aInfo.iColor;
        }

    // Set info that this is an MBM icon. They are not cached the same
    // way SVG icons are.
    item->SetMbmIcon();

    CleanupStack::PopAndDestroy(); // loadedBitmap
    CleanupStack::Pop(); // bitmap
    if ( mask )
        {
        CleanupStack::PopAndDestroy(); // loadedMask
        CleanupStack::Pop(); // mask
        }

    return item;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::ApplyIconColorL()
// -----------------------------------------------------------------------------
//
void CAknIconServer::ApplyIconColorL(
    CAknIconSrvIconItem* aItem, const TRgb aColor )
    {
    // If a color is defined in given parameters,
    // create a new icon with that color, if not already done.
    if ( aColor != KColorNotDefined && 
         aColor != aItem->iColor )
        {
#if 0        
        TSize size = aItem->iBitmap->SizeInPixels();

        CFbsBitmap* colorBitmap = new (ELeave) CFbsBitmap;
        CleanupStack::PushL( colorBitmap );
        User::LeaveIfError( colorBitmap->Create( size, EColor64K ) );

        CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( colorBitmap );
        CleanupStack::PushL( dev );
        CFbsBitGc* gc = NULL;
        User::LeaveIfError( dev->CreateContext( gc ) );
        CleanupStack::PushL( gc );
        
        gc->SetBrushColor( aColor );
        gc->SetPenStyle( CGraphicsContext::ENullPen );
        gc->SetBrushStyle( CGraphicsContext::ESolidBrush );
        // Fill icon with the given color, mask defines the icon shape.
        gc->DrawRect( TRect( TPoint( 0, 0 ), size ) );

        CleanupStack::PopAndDestroy( 2 ); // dev, gc

        // Change color bitmap in item.
        delete aItem->iBitmap;
        aItem->iBitmap = colorBitmap;
        CleanupStack::Pop(); // colorBitmap

#endif
        // Update information of the applied color in the item
        aItem->iColor = aColor;
        }
    }
    
// -----------------------------------------------------------------------------
// CAknIconServer::DeleteOrCacheUnusedIcon()
//
// Note: iCurrentIndex must be set to the index of aItem in array iIconItems
//       before using this function.
// -----------------------------------------------------------------------------
//
TBool CAknIconServer::DeleteOrCacheUnusedIcon(CAknIconSrvIconItem* aItem)
    {
#ifdef __AKNICON_TRACES
    RDebug::Print( _L("AknIcon: %x CAknIconServer::DeleteOrCacheUnusedIcon: item=%x"), this, aItem);
#endif       
    
    TBool ret = EFalse;
    if ( aItem->iUserCount == 0  && !aItem->IsPermanentlyCached() )
        {
        // Note, CacheUnusedIcon potentially changes iIconItems,
        // but it takes care of modifying iCurrentIndex accordingly.
        
        if ( aItem->IsExcludedFromCache() || // Do not cache if the icon is excluded from cache...
             aItem->IsMbmIcon() || // Do not cache bitmap icons...
             aItem->iRotationAngle != 0 || // Do not cache rotated icons...
             !iCache->CacheUnusedIcon( *aItem ) )
            {
            iIconItems.Remove( iCurrentIndex );
            delete aItem;
            ret = ETrue;
            }
        }
#ifdef __AKNICON_TRACES
    RDebug::Print( _L("AknIcon: %x CAknIconServer::DeleteOrCacheUnusedIcon: item=%x, ret=%d"), this, aItem,ret);
#endif       
        
    return ret;       
    }

// -----------------------------------------------------------------------------
// CAknIconServer::RetrieveFileHandleL()
// -----------------------------------------------------------------------------
//
RFile& CAknIconServer::RetrieveFileHandleL()
    {
    CSession2* session = Message().Session();
    return static_cast<CAknIconSrvSession*>( session )->AdoptedFileHandle(); 
    }

// -----------------------------------------------------------------------------
// CAknIconServer::ThreadStart()
// -----------------------------------------------------------------------------

EXPORT_C TInt CAknIconServer::ThreadStart()
    {
    // Rename own thread
	User::RenameThread( KAknIconSrvName );

    CAknIconServer* server = NULL;

    CTrapCleanup* cleanup = CTrapCleanup::New();
    CActiveScheduler* scheduler = new CAknIconSrvScheduler;

    TInt err = KErrNone;

    if ( cleanup && scheduler )
        {
        CActiveScheduler::Install( scheduler );
        TRAP( err,
            {
            server = CAknIconServer::NewL(); // adds server in scheduler
            } );
        }
    else
        {
        err = KErrNoMemory;
        }

    if ( err != KErrNone )
        {
        delete cleanup;
        delete scheduler;
        }

    // signal that we've started
    SignalClient();
    
    // start fielding requests from clients
    if ( err == KErrNone )
        {
        CActiveScheduler::Start();

        // comes here if server gets shut down
        delete scheduler;
        delete cleanup;
        delete server;
        }

    // thread/process exit
    return err;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::InitIconLoaderL
// -----------------------------------------------------------------------------
//
CAknIconLoader* CAknIconServer::InitIconLoaderL(
    const TDesC& aFileName, RFile* aFile )
    {
    CAknIconLoader* loader = NULL;

    if ( aFileName.CompareF( KAvkonIconFileName ) == 0 )
        {
        if ( !iAvkonIconLoader )
            {
            iAvkonIconLoader = CAknIconLoader::NewL( iFsSession, KAvkonIconFileName );
#ifdef _NGATESTING

            iAvkonIconLoader->SetIconTypeConfig(iConfigIconType, iNGADirectory);

#endif
            }
        loader = iAvkonIconLoader;
        }

    // If not Avkon icon file, check that we got the correct file open.
    else if ( !iCurrentIconFile || iCurrentIconFile->CompareF( aFileName ) != 0 )
        {
        delete iCurrentIconFile;
        iCurrentIconFile = NULL;

        delete iOtherIconLoader;
        iOtherIconLoader = NULL;
        
        if ( aFile )
            {
            iOtherIconLoader = CAknIconLoader::NewL( *aFile );
            }
        else
            {
            iOtherIconLoader = CAknIconLoader::NewL( iFsSession, aFileName );
            }

#ifdef _NGATESTING

        iOtherIconLoader->SetIconTypeConfig(iConfigIconType, iNGADirectory);

#endif
        iCurrentIconFile = aFileName.AllocL();
        loader = iOtherIconLoader;
        }

    else
        {
        // Icon file loader exists.

        loader = iOtherIconLoader;
        
        // Re-open the file if it is not ROM based file
        if (iCurrentIconFile->Left(KDriveLength).CompareF(KDriveZ))
            {
            if ( aFile )
                {
                loader->OpenFileL( *aFile );
                }
            else
                {
                loader->OpenFileL( iFsSession, aFileName );
                }
            }
        }

    return loader;
    }

// -----------------------------------------------------------------------------
// CAknIconServer::IconLoaderUsed
// -----------------------------------------------------------------------------
//
void CAknIconServer::IconLoaderUsed()
    {
    // Close the file only if it is not ROM based file
    if ( iOtherIconLoader && (!iCurrentIconFile ||
         iCurrentIconFile->Left(KDriveLength).CompareF(KDriveZ)))
        {
        iOtherIconLoader->CloseFile();        
        }
    }   

// -----------------------------------------------------------------------------
// CAknIconServer::CleanupIconLoader
// -----------------------------------------------------------------------------
//
void CAknIconServer::CleanupIconLoader( TAny* aServer )
    {
    static_cast<CAknIconServer*>( aServer )->IconLoaderUsed();
    }

// -----------------------------------------------------------------------------
// CAknIconServer::EnableCache
// -----------------------------------------------------------------------------
//
void CAknIconServer::EnableCache(TBool aEnable)
	{
#ifdef __AKNICON_TRACES
    RDebug::Print( _L("AknIcon: %x CAknIconServer::EnableCache: %d"), this, aEnable);
#endif   
	
    iCurrentIndex = -1;
	iCache->EnableCache(aEnable);
	}

// -----------------------------------------------------------------------------
// CAknIconServer::InitIconDataAndHandlerLC
// -----------------------------------------------------------------------------
//
TPtrC8 CAknIconServer::InitIconDataAndHandlerLC(
    const TAknIconParams& aParams,
    CAknIconLoader*& aLoader,
    MAknIconFormatHandler*& aHandler  )
    {
    TFileName filename;
    if ( aParams.IsDefaultIconDirUsed() )
        {
        filename = KAknIconDefaultDir;
        }

    filename.Append( aParams.iFileName );

    // Adopt file handle if supplied by client.    
    RFile* filePtr = NULL;
    RFile& file = RetrieveFileHandleL();
    
    if ( file.SubSessionHandle() )
        {
        filePtr = &file;
        }
    
    aLoader = InitIconLoaderL( filename, filePtr );

    MAknIconFormatHandler* lHandler = NULL;
    TPtrC8 iconData = AknIconSrvUtils::InitIconDataAndHandlerLC(
        aLoader,
        iHandlerList,
        lHandler,
            aParams,
        EFalse );
    aHandler = lHandler;
    return iconData;
    }


// -----------------------------------------------------------------------------
// ThreadFunction()
// Needed only in WINS build
// -----------------------------------------------------------------------------

#if defined(__WINS__) && !defined(EKA2)

GLDEF_C TInt ThreadFunction( TAny* /*aThreadParams*/ )
    {
    // increase dll's user count so it can't get unloaded when the client
    // application terminates

    RLibrary lib;
    lib.Load( KAknIconLibName );

    return CAknIconServer::ThreadStart();
    }

#endif

// -----------------------------------------------------------------------------
// StartServer()
// Create the server thread/process
// -----------------------------------------------------------------------------
//
GLDEF_C TInt StartServer()
    {
    TInt ret = KErrNone;

    RSemaphore startupSemaphore;
    ret = startupSemaphore.CreateGlobal( KAknIconServerStartupSemaphore, 0 );

    if ( ret == KErrAlreadyExists )
        {
        // The server is starting up, but has not yet started 
        if ( startupSemaphore.OpenGlobal( KAknIconServerStartupSemaphore ) == 
             KErrNone )
            {
            startupSemaphore.Wait(); // wait until the server has started up.
            startupSemaphore.Close();
            }

        // Return info to the client that the server was already started.
        return ret;
        }

    // launch server process
    RProcess server;
    ret = server.Create(
        KAknIconSrvExe,
        KNullDesC,
        TUidType( KNullUid, KNullUid, KNullUid ),
        EOwnerThread );

    if ( ret == KErrNone )
        {        	    
        server.Resume();
        server.Close();

        startupSemaphore.Wait(); // wait until the server has started up.
        }

    startupSemaphore.Close();
    return ret;
    }

// -----------------------------------------------------------------------------
// SignalClient()
// -----------------------------------------------------------------------------
//
GLDEF_C void SignalClient()
    {
    RSemaphore startupSemaphore;
    if ( startupSemaphore.OpenGlobal(
         KAknIconServerStartupSemaphore ) == KErrNone )
        {
        //Signal the client:The server might have started up successfully or not
        startupSemaphore.Signal();
        startupSemaphore.Close();
        }
    else
        {
        // Something fundamentally wrong.
        User::Invariant();
        }
    }

	

void CAknIconServer::ReCreateSvgL( TAknIconParams& aInfo, CAknIconSrvIconItem *& aItem)   	
    {
    
    if ( !aItem )
        {
        return;
        }
    
    CFbsBitmap* iBitmap = aItem->iBitmap;
	CFbsBitmap* iMask = NULL;
	if ( aItem->iMask )
	    {
	    iMask = aItem->iMask;
	    }
	TInt  validHeight;
	if(iMask != NULL)
		{
		SEpocBitmapHeader lBmpHeaderMask = iMask->Header();
		if ( lBmpHeaderMask.iBitsPerPixel != 8 ) 	
			{
			return;
		    }
		validHeight = AknIconSrvUtils::CheckMaskTransparencyL(iMask);
		}
	else
		{
		SEpocBitmapHeader lBmpHeaderBitmap = iBitmap->Header();
		if ( lBmpHeaderBitmap.iBitsPerPixel != 32 )
			{
			return;
			}
		validHeight = AknIconSrvUtils::CheckAlphaTransparencyL(iBitmap);
		}
	
	const TSize& size = iBitmap->SizeInPixels();
				
	if(validHeight == size.iHeight)
		return;
	
	const TInt KOffSet = 16;
	
	//scale image down, leaving margins on sides
	//then using fixed point math to get width
	const TInt hmul = (validHeight << KOffSet) / size.iHeight;
	const TInt validWidth =  (size.iWidth * hmul + (1 << (KOffSet - 1))) >> KOffSet;  // sz * mul + 0.5
	        
    TSize lActual = aInfo.iSize;  // store the original size request by clien  
	const TSize sz(validHeight, validWidth);
    aInfo.iSize = sz;    // valid size after doing transparency operations
    
 //   TRect rect(TPoint((size.iWidth - sz.iWidth) >> 1, 0), sz);
    TRect rect(TPoint((size.iWidth - sz.iWidth) >> 1, (size.iHeight - sz.iHeight) >> 1), sz);
//	TRect rect(TPoint((size.iWidth - validWidth) >> 1, (size.iHeight - validHeight) >> 1), sz);

	//it look better if even when centrified
	rect.iTl.iX &= ~1; 
	rect.iBr.iX |= 1;
	
    CAknIconSrvIconItem *lItem = CreateIconL(aInfo); // recreate the svg bmp with valid size.
    if ( !lItem )
    	{
    	return;
    	}
    CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(aItem->iBitmap);
	CleanupStack::PushL(dev);
	CFbsBitGc* con = NULL;
	dev->CreateContext(con);
	CleanupStack::PushL(con);
	con->SetBrushColor( 0 );
	con->Clear();
	con->SetPenStyle(CGraphicsContext::ESolidPen);
	con->SetBrushStyle(CGraphicsContext::ESolidBrush);
	TUint32 lFillColor = 0xFF000000;
	con->SetPenColor(lFillColor);
	con->SetBrushColor(lFillColor);
	con->DrawRect(TRect(TPoint(0, 0), aItem->iBitmap->SizeInPixels()));
	con->BitBlt(rect.iTl, lItem->iBitmap);
	CleanupStack::PopAndDestroy(2);
    
    if ( lItem->iMask )
    	{
    	CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(aItem->iMask);
		CleanupStack::PushL(dev);
		CFbsBitGc* con = NULL;
		dev->CreateContext(con);
		CleanupStack::PushL(con);
		con->SetBrushColor( 0 );
		con->Clear();
		con->SetPenStyle(CGraphicsContext::ESolidPen);
		con->SetBrushStyle(CGraphicsContext::ESolidBrush);
		lFillColor = lItem->iMask->DisplayMode() != EGray256 ? 0xFFFFFFFFF : 0x0;
		con->SetPenColor(lFillColor);
		con->SetBrushColor(lFillColor);			
		con->DrawRect(TRect(TPoint(0, 0), aItem->iMask->SizeInPixels()));
		con->BitBlt(rect.iTl, lItem->iMask);
		CleanupStack::PopAndDestroy(2);	
    	}
   
    delete lItem;
    lItem = NULL;
    aItem->iSize = lActual; // store actual size requested by the client
                                // so that search can be done successfully.
    }

#ifdef _NGATESTING

void CAknIconServer::LoadConfigurationL(RFs& aFs)
    {
    // if the icon type is svg, check if NGA enabled and set type as EIconFormatNGA
#ifdef __ONLYNGAICON
    iConfigIconType = EIconFormatNGA;
    (void)aFs;
#else
    // check for the configuration files
    _LIT(KICONTYPECONFIGFILE, "c:\\icontype.cfg"); // TODO: find appropriate place
    /*
     * sample configuration files is attached below
     * 
     * ICONTYPE=3
     * NGAICONDIR=c:\Data\nvg_mif
     */
    RFile   lFile;
    
    if (lFile.Open(aFs, KICONTYPECONFIGFILE , EFileRead) == KErrNone)
        {
        CleanupClosePushL(lFile);
        TInt sekpoint = 0;
        lFile.Seek( ESeekStart, sekpoint );
        TInt fileSize = 0;
        User::LeaveIfError(lFile.Size( fileSize ));
        
        HBufC8 * lConfigData = HBufC8::NewLC( fileSize );
        
        TPtr8 lptr = lConfigData->Des();
        lFile.Read(lptr, fileSize);
        
        TLex8 lLexObj(lptr);
        lLexObj.SkipSpaceAndMark();
        
        TChar aChar;
        
        do
            {
            aChar = lLexObj.Get();
            }
        while ( aChar != '\n' &&
                aChar != ' '  &&
                aChar != '\r' &&
                aChar != '\t' &&
                aChar != '=');
        
        lLexObj.UnGet();
        TPtrC8 kw1 = lLexObj.MarkedToken();
        lLexObj.SkipSpace();
        if (lLexObj.Get() != '=')
            {
            User::Leave(KErrCorrupt);
            }
        
        lLexObj.SkipSpace();
        lLexObj.Val(iConfigIconType);
        
        lLexObj.SkipSpaceAndMark();
        do
            {
            aChar = lLexObj.Get();
            }
        while ( aChar != '\n' &&
                aChar != ' '  &&
                aChar != '\r' &&
                aChar != '\t' &&
                aChar != '=');
        
        lLexObj.UnGet();
        TPtrC8 kw2 = lLexObj.MarkedToken();
        lLexObj.SkipSpace();
        if (lLexObj.Get() != '=')
            {
            User::Leave(KErrCorrupt);
            }
        lLexObj.SkipSpace();
        
        iNGADirectory.Copy(lLexObj.NextToken());
        CleanupStack::PopAndDestroy();
        CleanupStack::PopAndDestroy();
        }
    else
        {
        iConfigIconType = EIconFormatNGA;
        }
#endif
    }
#endif
