pictographs/AknPictograph/tools/AknPictoBitmapBuilder/src/BitmapBuilder.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:35:27 +0300
changeset 114 a0ce86df2348
parent 0 05e9090e2422
child 78 0b86c25b743a
permissions -rw-r--r--
Revision: 201035 Kit: 201037

/*
* 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 "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:  Pictograph drawer
*
*/



// INCLUDE FILES

#include <fbs.h>
#include <gdi.h>
#include <bitdev.h>
#include <mmfcontrollerpluginresolver.h> // For CleanupResetAndDestroyPushL

#include "BitmapBuilder.h"
#include "aknpictographconfig.h" // KBitmapDisplayMode, KMaskDisplayMode
								 // KBitmapTag, KMaskTag
								 
// CONSTANTS

// The root is mapped to parent of dir AknPictograph
_LIT( KDefaultPath, "a:\\" ); 

// This should be carefully selected beacuse adding support
// for new height will need about 40 KB more
TUint KBufferSizeForHeaderGeneration = 300000;

// WINC platform - paths mapped directly in PC file system
// on EKA2 drive a: is mapped to the PC file system
_LIT( KConfigPathEpoc, "\\AknPictograph\\config\\" );
_LIT( KConfigFile, "picto%u.ini" );

_LIT( KGeneratedPathEpoc, "\\AknPictograph\\generated\\" );

// String for inserting in batch files
_LIT( KGeneratedPath, "..\\generated\\" );

_LIT( KBmconvFile, "bmconv%u.txt" );

_LIT( KMultiBitmapFile, "AknPictograph_multi%u.mbm" );
_LIT( KBitmapFile, "AknPictograph%u.mbm" );
_LIT( KMaskFile, "AknPictographMask%u.mbm" );

_LIT( KDefinitionsFile, "AknPictographDefinitions.h" );
_LIT( KRangeFile, "AknPictographRange.h" );
_LIT( KBuildBitmapsFile, "BuildBitmaps.cmd" );

_LIT8( KGeneratedInfo, "// This file is generated by AknPictoBitmapBuilder.\r\n\r\n" );

// Bmconv command file strings
_LIT8( KBmconvParameters, "/q " );
_LIT8( KBmpDefaultPath, "..\\..\\AknPictographBitmaps\\data\\" );

// Definition header strings
_LIT8( KDefinitionHeaderStart,
"#include <e32std.h>\r\n"
"#include \"AknPictographDrawerInterface.h\"\r\n"
"#include \"AknPictographConstants.h\"\r\n\r\n" );


// TAknPictographSupportedHeights array
_LIT8( KAknPictographSupportedHeightsStart,
"const TAknPictographHeight TAknPictographSupportedHeights[] =\r\n" );

_LIT8( KAknPictographSupportedHeightsArrayRow,
"    EHeight%u,\r\n" );

// TAknPictographSupportedHeightsNumbers array
_LIT8( KAknPictographSupportedHeightsNumbersStart,
"const TUint TAknPictographSupportedHeightsNumbers[] =\r\n" );

_LIT8( KAknPictographSupportedHeightsNumbersArrayRow,
"    %u,\r\n" );

// KAknPictographSupportedHeightsCount row
_LIT8( KAknPictographSupportedHeightsCount,
"const TInt KAknPictographSupportedHeightsCount = sizeof(TAknPictographSupportedHeights)/sizeof(TAknPictographHeight);\r\n\r\n" );


// Animation definitions
_LIT8( KAnimationDefinitionStart, 
"const TAknPictographMetrics P_%x_%u[] =\r\n" );

_LIT8( KAnimationFrame,
"    {%u, %u, %u},\r\n" );

// Animation frames definitions
_LIT8( KAnimationFramesDefinitionStart, 
"const TAknAnimatedPictographFramesDefinition Frames_%x[] =\r\n" );

_LIT8( KAnimationFramesDefinitionRow,
"    {%u, P_%x_%u},\r\n" );

// Animated pictograph table
_LIT8( KAnimatedTableStart,
"const TAknAnimatedPictographDefinition TheAnimatedPictographDefinitions[] =\r\n" );

_LIT8( KAnimatedTableRow,
"    { 0x%x, %u, Frames_%x },\r\n" );

_LIT8( KAnimatedTableDummyRow,
"    { 0x0000, 0, NULL }\r\n" );

// KAknPictographAnimatedPictographsCount row
_LIT8( KAknPictographAnimatedPictographsCount,
"const TInt KAknPictographAnimatedPictographsCount = sizeof(TheAnimatedPictographDefinitions)/sizeof(TAknAnimatedPictographDefinition) - %u;\r\n\r\n" );


// Static definitions
_LIT8( KStaticDefinitionStart, 
"const TAknPictographMetrics Static_%x[] =\r\n" );

_LIT8( KStaticDefinitionRow,
"    {%u, %u, %u},\r\n" );

// Static pictograph table
_LIT8( KStaticTableStart,
"const TAknStaticPictographDefinition TheStaticPictographDefinitions[] =\r\n" );

_LIT8( KStaticTableRow,
"    { 0x%x, Static_%x },\r\n" );

_LIT8( KStaticTableDummyRow,
"    { 0x0000, NULL }\r\n" );

// KAknPictographAnimatedPictographsCount row
_LIT8( KAknPictographStaticPictographsCount,
"const TInt KAknPictographStaticPictographsCount = sizeof(TheStaticPictographDefinitions)/sizeof(TAknStaticPictographDefinition) - %u;\r\n\r\n" );

// Range header strings
_LIT8( KRangeHeaderStart,
"#ifndef AKN_PICTOGRAPH_RANGE_H\r\n"
"#define AKN_PICTOGRAPH_RANGE_H\r\n\r\n"
"#include <e32std.h>\r\n\r\n" );

_LIT8( KRangeStart,
"const TText KPictographRangeStart = 0x%x;\r\n" );

_LIT8( KRangeEnd,
"const TText KPictographRangeEnd = 0x%x;\r\n\r\n" );

_LIT8( KEndIf, "#endif\r\n\r\n" );

// Common for all arrays
_LIT8( KArrayStart, "    {\r\n" );
_LIT8( KArrayEnd, "    };\r\n\r\n" );
_LIT8( KHeaderEnd, "// End of File" );



// BuildBitmaps.cmd strings
_LIT8( KBuildBitmapsFileStart,
"@echo off\r\n"
"rem\r\n"
"rem This file is generated by AknPictoBitmapBuilder.\r\n"
"rem\r\n\r\n"
"if %1==xip goto xip_rom\r\n"
"if %1==XIP goto xip_rom\r\n\r\n"
"set bmconv_params=/q\r\n"
"goto main\r\n\r\n"
":xip_rom\r\n"
"set bmconv_params=/q /r\r\n\r\n"
":main\r\n\r\n");

_LIT8( KBuildBitmapsRow,
"bmconv ..\\generated\\bmconv%u.txt&&^\r\n");

_LIT8( KBuildFinalBitmaps,
"\\epoc32\\release\\winscw\\urel\\AknPictoBitmapBuilder.exe  -Dnogui -D_epoc_drive_a=%~pd2 -- 2&&^\r\n"
"cd ..\\generated&&^\r\n");

_LIT8( KCompressFinalBitmapsRow,
"bmconv %%bmconv_params%% AknPictograph%u_rom.mbm /mAknPictograph%u.mbm&&^\r\n"
"bmconv %%bmconv_params%% AknPictographMask%u_rom.mbm /mAknPictographMask%u.mbm&&^\r\n");

_LIT8( KMoveFinalBitmapsRow,
"move AknPictograph%u_rom.mbm %%3\\AknPictograph%u.mbm&&^\r\n"
"move AknPictographMask%u_rom.mbm %%3\\AknPictographMask%u.mbm&&^\r\n");

_LIT8( KBuildBitmapsFileEnd,
"cd ..\\group\r\n");

_LIT8( KLongCommandLineSeparator,
"rem\r\n");






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

CPictographIniData* CPictographIniData::NewLC()
    {
    CPictographIniData* self = new( ELeave ) CPictographIniData;
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

void CPictographIniData::ConstructL()
    {
    }

CPictographIniFileData* CPictographIniFileData::NewLC()
    {
    CPictographIniFileData* self = new( ELeave ) CPictographIniFileData;
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

void CPictographIniFileData::ConstructL()
    {
    }

CPictographBitmapsData* CPictographBitmapsData::NewLC(TInt aBitmapSizesGranularity)
    {
    CPictographBitmapsData* self = new( ELeave ) CPictographBitmapsData(aBitmapSizesGranularity);
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

CPictographBitmapsData::CPictographBitmapsData(TInt aBitmapSizesGranularity):
    iBitmapSizes(aBitmapSizesGranularity)
    {
    }

CPictographBitmapsData::~CPictographBitmapsData()
    {
    iBitmapSizes.Reset();
    delete iOffsets;
    }

void CPictographBitmapsData::ConstructL()
    {
    iOffsets = new( ELeave ) CArrayFixFlat<TInt>( 32 );
    }


// -----------------------------------------------------------------------------
// CBitmapBuilder::CBitmapBuilder
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CBitmapBuilder::CBitmapBuilder()
	{
	}

CBitmapBuilder* CBitmapBuilder::NewLC()
    {
    CBitmapBuilder* self = new( ELeave ) CBitmapBuilder;
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::ConstructL()
    {
    User::LeaveIfError( iFs.Connect() );
    User::LeaveIfError( iFs.SetSessionPath(KDefaultPath) );   
    User::LeaveIfError( iFs.ShareProtected() );      
    }

// Destructor
CBitmapBuilder::~CBitmapBuilder()
    {
    iBitmapsData.ResetAndDestroy();
    iIniFilesData.ResetAndDestroy();
    iFs.Close();
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::EnsurePathsL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::EnsurePathsL()
    {
    iFs.MkDirAll( KGeneratedPathEpoc );
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::ParseIniFilesL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::ParseIniFilesL()
    {
    TFileName name;
    TFileName temp;

    for (TInt i = 0; i < KAknPictographMaxSetOfSupportedHeightsCount; i++)
        {
        // prepare ini file name
        temp.Zero();
        temp.Format( KConfigFile, TAknPictographMaxSetOfSupportedHeights[i] );
        name = KConfigPathEpoc;
        name.Append( temp );
        CPictographIniFileData* iniFileData = NULL;
        TRAPD(err, ParseIniFileL( name, iniFileData ));
        if (err != KErrNotFound)
            {
            // Leave if the reason of leave in ParseIniFileL is not because
            // of the ini file was not found
            User::LeaveIfError(err);
            }
        if (iniFileData)
            {
            CleanupStack::PushL( iniFileData );
            // The parsing was successful
            iniFileData->iHeightIndex = i;
            User::LeaveIfError( iIniFilesData.Append(iniFileData));
            CleanupStack::Pop( iniFileData );
            }
        }
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::ParseIniFileL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::ParseIniFileL(
    const TDesC& aFilename,
    CPictographIniFileData*& aIniFileData )
    {
    RFile file;
    User::LeaveIfError( file.Open( iFs, aFilename, EFileRead ) );
    CleanupClosePushL( file );
    aIniFileData = CPictographIniFileData::NewLC();

    TInt pos = 0;
    // go in the beginning of the file
    User::LeaveIfError( file.Seek( ESeekStart, pos ) );

    TInt size = 0;
    file.Size( size );

    HBufC8* buffer = HBufC8::NewMaxLC( size );
    TPtr8 ptr = buffer->Des();

    file.Read( ptr );

    TLex8 lex( ptr );

    TPtrC8 token( lex.NextToken() );

	while ( token.Length() )
	    {
        // code tag first
        if ( token.Length() != 8 ||
             token[0] != '[' ||
             token[1] != '0' ||
             ( token[2] != 'x' && token[2] != 'X' ) ||
             token[7] != ']' )
            {
            User::Leave( KErrCorrupt );
            }
        
        CPictographIniData* data = CPictographIniData::NewLC();

        TLex8 codeLex( token.Mid( 3, 4 ) );
        User::LeaveIfError( codeLex.Val( data->iCode, EHex ) );

        // filename parameters then
        
        for ( token.Set( lex.NextToken() ) ; 
              token.Length() && token[0] != '[' ; 
              token.Set( lex.NextToken() ) )
            {
            HBufC8* filename = token.AllocLC();
            User::LeaveIfError( data->iFilenameArray.Append( filename ) );
            CleanupStack::Pop( filename );
            aIniFileData->iBmps++;
            }

        // Must be even number because each bitmap must have mask
        if ( data->iFilenameArray.Count() % 2 != 0 )
            {
            User::Leave( KErrCorrupt );
            }

        User::LeaveIfError( aIniFileData->iIniData.Append( data ) );
        CleanupStack::Pop( data );
        }

    CleanupStack::PopAndDestroy( buffer ); 
    CleanupStack::Pop( aIniFileData ); 
    CleanupStack::PopAndDestroy(); // file
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateBmconvCommandFilesL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateBmconvCommandFilesL()
    {
    TFileName cmdFile;
    TFileName bitmapFile;
    TFileName temp;

    for (TInt i = 0; i < iIniFilesData.Count(); i++)
        {
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[i]->iHeightIndex];

        // prepare cmdFile name
        temp.Zero();
        temp.Format( KBmconvFile, height );
        cmdFile = KGeneratedPathEpoc;
        cmdFile.Append( temp );

        // prepare bitmapFile name
        temp.Zero();
        temp.Format( KMultiBitmapFile, height );
        bitmapFile = KGeneratedPath;
        bitmapFile.Append( temp );

        GenerateBmconvCommandFileL( cmdFile, bitmapFile, iIniFilesData[i]->iIniData );
        }
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateBmconvCommandFilesL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateBuildBitmapsCommandFileL()
    {
    TFileName aCmdFileName;
    TBuf8<256> temp;

    // prepare cmdFile name
    aCmdFileName = KGeneratedPathEpoc;
    aCmdFileName.Append( KBuildBitmapsFile );

    RFile file;
    User::LeaveIfError( file.Replace( iFs, aCmdFileName, EFileWrite ) );
    CleanupClosePushL( file );

    TInt pos = 0;
    // go in the beginning of the file
    User::LeaveIfError( file.Seek( ESeekStart, pos ) );

    file.Write( KBuildBitmapsFileStart );

    // generate bitmaps building section
    for (TInt i = 0; i < iIniFilesData.Count(); i++)
        {
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[i]->iHeightIndex];

        temp.Zero();
        temp.Format( KBuildBitmapsRow, height );
        file.Write( temp );
        }
    file.Write( KLongCommandLineSeparator );
    file.Write( KBuildFinalBitmaps );

    // generate compress final bitmaps section
    for (TInt j = 0; j < iIniFilesData.Count(); j++)
        {
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[j]->iHeightIndex];

        temp.Zero();
        temp.Format( KCompressFinalBitmapsRow, height, height, height, height );
        file.Write( temp );
        }
    file.Write( KLongCommandLineSeparator );

    // generate move final bitmaps section
    for (TInt k = 0; k < iIniFilesData.Count(); k++)
        {
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[k]->iHeightIndex];

        temp.Zero();
        temp.Format( KMoveFinalBitmapsRow, height, height, height, height );
        file.Write( temp );
        }
    file.Write( KLongCommandLineSeparator );
    file.Write( KBuildBitmapsFileEnd );

    CleanupStack::PopAndDestroy(); // file
    }


// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateBmconvCommandFileL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateBmconvCommandFileL(
    const TDesC& aCmdFileName,
    const TDesC& aBitmapFileName,
    RPointerArray<CPictographIniData>& aArray )
    {
    RFile file;
    User::LeaveIfError( file.Replace( iFs, aCmdFileName, EFileWrite ) );
    CleanupClosePushL( file );

    TInt pos = 0;
    // go in the beginning of the file
    User::LeaveIfError( file.Seek( ESeekStart, pos ) );

    file.Write( KGeneratedInfo );
    file.Write( KBmconvParameters );

    TBuf8<400> buf8;
    buf8.Copy( aBitmapFileName );
    buf8.Append( _L8("\r\n\r\n") );
    file.Write( buf8 );

    // write bmp parameters

    for ( TInt i = 0 ; i < aArray.Count() ; i++ )
        {
        CPictographIniData* data = aArray[i];

        for ( TInt ii = 0 ; ii < data->iFilenameArray.Count() ; ii += 2 )
            {
            // bitmap
            buf8.Zero();
            buf8.Append( KBitmapTag );

            TFileName filename;
            // 8-bit to 16-bit copy
            filename.Copy( *(data->iFilenameArray[ii]) );
            TParse parse;
            parse.Set( filename, NULL, NULL );

            if ( !parse.PathPresent() )
                {
                buf8.Append( KBmpDefaultPath );
                }

            // 16-bit to 8-bit append
            buf8.Append( parse.FullName() );
            buf8.Append( _L8("\r\n") );

            file.Write( buf8 );

            // mask

            buf8.Zero();
            buf8.Append( KMaskTag );

            // 8-bit to 16-bit copy
            filename.Copy( *(data->iFilenameArray[ii + 1]) );
            parse.Set( filename, NULL, NULL );

            if ( !parse.PathPresent() )
                {
                buf8.Append( KBmpDefaultPath );
                }

            // 16-bit to 8-bit append
            buf8.Append( parse.FullName() );
            buf8.Append( _L8("\r\n") );

            file.Write( buf8 );
            }
        }

    CleanupStack::PopAndDestroy(); // file
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::BuildFinalBitmapsL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::BuildFinalBitmapsL()
    {
    TFileName* multiBitmapFile = new( ELeave ) TFileName;
    CleanupStack::PushL( multiBitmapFile );
    TFileName* finalBitmapFile = new( ELeave ) TFileName;
    CleanupStack::PushL( finalBitmapFile );
    TFileName* finalMaskFile = new( ELeave ) TFileName;
    CleanupStack::PushL( finalMaskFile );
    TFileName* temp = new( ELeave ) TFileName;
    CleanupStack::PushL( temp );

    for (TInt i = 0; i < iIniFilesData.Count(); i++)
        {
        // set proper value for granularity
        CPictographBitmapsData* bitmapsData = CPictographBitmapsData::NewLC(iIniFilesData[i]->iBmps/2);

        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[i]->iHeightIndex];

        // prepare multiBitmapFile name
        temp->Zero();
        temp->Format( KMultiBitmapFile, height );
        multiBitmapFile->Copy( KGeneratedPathEpoc );
        multiBitmapFile->Append( *temp );

        // prepare finalBitmapFile name
        temp->Zero();
        temp->Format( KBitmapFile, height );
        finalBitmapFile->Copy( KGeneratedPathEpoc );
        finalBitmapFile->Append( *temp );

        // prepare finalMaskFile name
        temp->Zero();
        temp->Format( KMaskFile, height );
        finalMaskFile->Copy( KGeneratedPathEpoc );
        finalMaskFile->Append( *temp );

        BuildFinalBitmapL(
            *multiBitmapFile,
            *finalBitmapFile,
            *finalMaskFile,
            iIniFilesData[i]->iBmps,
            *bitmapsData);
        User::LeaveIfError( iBitmapsData.Append(bitmapsData) );
        CleanupStack::Pop(bitmapsData);
        }
    // multiBitmapFile, finalBitmapFile, finalMaskFile, temp
    CleanupStack::PopAndDestroy( 4 );
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::BuildFinalBitmapL
// -----------------------------------------------------------------------------
//

void CBitmapBuilder::BuildFinalBitmapL(
    const TDesC& aMultiBitmapFile,
    const TDesC& aFinalBitmapFile,
    const TDesC& aFinalMaskFile,
    TInt aBmps,
    CPictographBitmapsData& aBitmapsData )
    {
    TInt totalWidth = 0;
    TInt maxHeight = 0;

    // set proper granularity values
    RPointerArray<CFbsBitmap> bitmaps(aBmps/2);
    RPointerArray<CFbsBitmap> masks(aBmps/2);
    CleanupResetAndDestroyPushL(bitmaps);
    CleanupResetAndDestroyPushL(masks);

    // First bitmap has x-offset 0
    aBitmapsData.iOffsets->AppendL( 0 );

 	RFile multiBitmapfile;
    User::LeaveIfError( multiBitmapfile.Open( iFs, aMultiBitmapFile, EFileRead ) );
    CleanupClosePushL( multiBitmapfile );
    
    // Load bitmaps and masks in arrays
    for ( TInt i = 0 ; i <  aBmps ; i += 2 )
        {
        CFbsBitmap* bitmap = new( ELeave ) CFbsBitmap;
        CleanupStack::PushL( bitmap );

        User::LeaveIfError( bitmap->Load( multiBitmapfile, i ) );
        User::LeaveIfError( bitmaps.Append( bitmap ) );
        CleanupStack::Pop( bitmap );

        // Update total width and max height
        TSize size = bitmap->SizeInPixels();
        User::LeaveIfError( aBitmapsData.iBitmapSizes.Append( size ) );

        totalWidth += size.iWidth;

        aBitmapsData.iOffsets->AppendL( totalWidth );

        if ( size.iHeight > maxHeight )
            {
            maxHeight = size.iHeight;
            }

        CFbsBitmap* mask = new( ELeave ) CFbsBitmap;
        CleanupStack::PushL( mask );
        User::LeaveIfError( mask->Load( multiBitmapfile, i + 1 ) );
        User::LeaveIfError( masks.Append( mask ) );
        CleanupStack::Pop( mask );
        }

    // new size for one large bitmap
    TSize newSize( totalWidth, maxHeight );

    // bitgdi objects for large bitmap
    CFbsBitmap* largeBitmap = new( ELeave ) CFbsBitmap;
    CleanupStack::PushL( largeBitmap );

    User::LeaveIfError( largeBitmap->Create( newSize, KBitmapDisplayMode ) );

    CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( largeBitmap );
    CleanupStack::PushL( bitmapDevice );

    CFbsBitGc* bitmapGc = NULL;
    User::LeaveIfError( bitmapDevice->CreateContext( bitmapGc ) );    
    CleanupStack::PushL( bitmapGc );

    // bitgdi objects for large mask
    CFbsBitmap* largeMask = new( ELeave ) CFbsBitmap;
    CleanupStack::PushL( largeMask );

    User::LeaveIfError( largeMask->Create( newSize, KMaskDisplayMode ) );

    CFbsBitmapDevice* maskDevice = CFbsBitmapDevice::NewL( largeMask );
    CleanupStack::PushL( maskDevice );

    CFbsBitGc* maskGc = NULL;
    User::LeaveIfError( maskDevice->CreateContext( maskGc ) );    
    CleanupStack::PushL( maskGc );

    // fill with black color
    bitmapGc->SetBrushColor( KRgbBlack );
    bitmapGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
    bitmapGc->Clear();

    maskGc->SetBrushColor( KRgbBlack );
    maskGc->SetBrushStyle( CGraphicsContext::ESolidBrush );
    maskGc->Clear();

    TPoint point( 0, 0 );

    for ( TInt j = 0 ; j < aBmps / 2 ; j++ )
        {
        // bitmap
        bitmapGc->BitBlt( point, bitmaps[j] );
        // mask
        maskGc->BitBlt( point, masks[j] );

        point.iX += bitmaps[j]->SizeInPixels().iWidth;

        // Mask must be same size as the corresponding bitmap!
        __ASSERT_ALWAYS( aBitmapsData.iBitmapSizes[j] == masks[j]->SizeInPixels(),
            User::Invariant() );
        }
           
  	RFile finalBitmapFile;
    User::LeaveIfError( finalBitmapFile.Replace( iFs, aFinalBitmapFile, EFileWrite ) );
    CleanupClosePushL( finalBitmapFile );
    
    User::LeaveIfError( largeBitmap->Save( finalBitmapFile ) );
    
   	RFile finalMaskFile;
    User::LeaveIfError( finalMaskFile.Replace( iFs, aFinalMaskFile, EFileWrite ) );
    CleanupClosePushL( finalMaskFile );
  
    User::LeaveIfError( largeMask->Save( finalMaskFile ) );

     // bitmaps, masks, multiBitmapfile, largeBitmap, largeMask, bitmapDevice, bitmapGc, maskDevice, maskGc, 
     // finalBitmapFile, finalMaskFile
    CleanupStack::PopAndDestroy( 11 );
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GeneratePictographDefinitionsL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GeneratePictographDefinitionsL()
    {
    TFileName name;
    name = KGeneratedPathEpoc;
    name.Append( KDefinitionsFile );

    RFile file;
    User::LeaveIfError( file.Replace( iFs, name, EFileWrite ) );
    CleanupClosePushL( file );

    TInt pos = 0;
    // go in the beginning of the file
    User::LeaveIfError( file.Seek( ESeekStart, pos ) );

    HBufC8* buffer = HBufC8::NewLC( KBufferSizeForHeaderGeneration );
    TPtr8 data = buffer->Des();

    data.Append( KGeneratedInfo );
    data.Append( KDefinitionHeaderStart );


    // TAknPictographSupportedHeights array
    GenerateTAknPictographSupportedHeightsArrayL( data );

    // TAknPictographSupportedHeightsNumbers array
    GenerateTAknPictographSupportedHeightsNumbersArrayL( data );
    data.Append( KAknPictographSupportedHeightsCount );

    // Animation definitions
    GenerateAnimationDefinitionsL( data );

    // Animation frames definitions
    GenerateAnimationFramesDefinitionsL( data );

    // Animated pictograph table
    GenerateAnimatedPictographTableL( data );

    // Static definitions
    GenerateStaticDefinitionsL( data );

    // Static pictorah table
    GenerateStaticPictographTableL( data );
    
    data.Append( KHeaderEnd );

    User::LeaveIfError( file.Write( data ) );
    CleanupStack::PopAndDestroy( 2 ); // file, buffer
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateTAknPictographSupportedHeightsArrayL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateTAknPictographSupportedHeightsArrayL(TPtr8& aData)
    {
    TBuf8<128> temp;

    // TAknPictographSupportedHeights array
    aData.Append( KAknPictographSupportedHeightsStart );
    aData.Append( KArrayStart );

    // any rows added in the array?
    TBool rowsAdded = EFalse;

    for (TInt i = 0; i < iIniFilesData.Count(); i++)
        {
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[i]->iHeightIndex];

        // prepare and append array row
        temp.Zero();
        temp.Format( KAknPictographSupportedHeightsArrayRow, height );
        aData.Append( temp );

        rowsAdded = ETrue;
        }
    if ( !rowsAdded )
        {
        // At least one height must be supported
        User::Leave( KErrGeneral );
        }
    else
        {
        aData.Delete( aData.Length() - 3, 1 ); // remove last comma
        aData.Append( KArrayEnd );
        }
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateTAknPictographSupportedHeightsNumbersArrayL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::
    GenerateTAknPictographSupportedHeightsNumbersArrayL(TPtr8& aData)
    {
    TBuf8<128> temp;

    // TAknPictographSupportedHeights array
    aData.Append( KAknPictographSupportedHeightsNumbersStart );
    aData.Append( KArrayStart );

    // any rows added in the array?
    TBool rowsAdded = EFalse;

    for (TInt i = 0; i < iIniFilesData.Count(); i++)
        {
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[i]->iHeightIndex];

        // prepare and append array row
        temp.Zero();
        temp.Format( KAknPictographSupportedHeightsNumbersArrayRow, height );
        aData.Append( temp );

        rowsAdded = ETrue;
        }
    if ( !rowsAdded )
        {
        // At least one height must be supported
        User::Leave( KErrGeneral );
        }
    else
        {
        aData.Delete( aData.Length() - 3, 1 ); // remove last comma
        aData.Append( KArrayEnd );
        }
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateAnimationDefinitionsL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateAnimationDefinitionsL(TPtr8& aData)
    {
    TBuf8<128> temp;

    // Generate Animation definitions for each supported height
    for (TInt z = 0; z < iIniFilesData.Count(); z++)
        {
        TInt index = 0;
        // get current height
        TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[z]->iHeightIndex];

        for ( TInt i = 0 ; i < iIniFilesData[z]->iIniData.Count() ; i++ )
            {
            RPointerArray<HBufC8>& filenameArray =
                iIniFilesData[z]->iIniData[i]->iFilenameArray;

            // if more than 2 bmps (bitmap and mask), it is animated
            if ( filenameArray.Count() > 2 )
                {
                temp.Zero();
                temp.Format( KAnimationDefinitionStart, iIniFilesData[z]->iIniData[i]->iCode, height);
                aData.Append( temp );
                aData.Append( KArrayStart );

                for ( TInt ii = 0 ; ii < filenameArray.Count() ; ii += 2 )
                    {
                    TSize size = iBitmapsData[z]->iBitmapSizes[index + ii/2];
                    TInt offset = (*iBitmapsData[z]->iOffsets)[index + ii/2];

                    temp.Zero();
                    temp.Format( KAnimationFrame, offset, size.iWidth, size.iHeight );
                    aData.Append( temp );
                    }

                aData.Delete( aData.Length() - 3, 1 ); // remove last comma
                aData.Append( KArrayEnd );
                }

            index += filenameArray.Count() / 2;
            }
        }
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateAnimationFramesDefinitionsL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateAnimationFramesDefinitionsL(TPtr8& aData)
    {
    TBuf8<128> temp;

    // Generate Animation Frames definitions for each for each
    // animated pictograph
    if (iIniFilesData.Count())
        {
        for ( TInt i = 0 ; i < iIniFilesData[0]->iIniData.Count() ; i++ )
            {

            // Check if the pictograph is animated and 
            // if yes it must be animated for all supported heights
            TInt rowCount = 0;
            for (TInt z = 0; z < iIniFilesData.Count(); z++)
                {
                RPointerArray<HBufC8>& array =
                    iIniFilesData[z]->iIniData[i]->iFilenameArray;

                // If more than 2 bmps (bitmap and mask), it is animated
                if ( array.Count() > 2 )
                    {
                    if (!rowCount)
                        {
                        // Only insert table header before the first row
                        // Animation Frames definition table
                        temp.Zero();
                        temp.Format( KAnimationFramesDefinitionStart,
                                     iIniFilesData[0]->iIniData[i]->iCode);

                        aData.Append( temp );
                        aData.Append( KArrayStart );
                        }
                    // get current height
                    TInt height = TAknPictographMaxSetOfSupportedHeights[iIniFilesData[z]->iHeightIndex];
                    temp.Zero();
                    temp.Format( KAnimationFramesDefinitionRow,
                                 array.Count() / 2,
                                 iIniFilesData[0]->iIniData[i]->iCode,
                                 height);
                    aData.Append( temp );
                    rowCount++;
                    }
                }
            if ( rowCount > 0 )
                {
                if ( rowCount != iIniFilesData.Count() )
                    {
                    // If it is animated pictograph then it must be for all heights
                    User::Leave( KErrGeneral );
                    }
                else
                    {
                    aData.Delete( aData.Length() - 3, 1 ); // remove last comma
                    aData.Append( KArrayEnd );
                    }
                }
            }
        }
    else
        {
        // At least one height must be supported
        User::Leave( KErrGeneral );
        }
    }


// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateAnimatedPictographTableL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateAnimatedPictographTableL(TPtr8& aData)
    {
    TBuf8<256> temp;
    
    if (iIniFilesData.Count())
        {
        aData.Append( KAnimatedTableStart );
        aData.Append( KArrayStart );

        // any rows added in the array?
        TBool rowsAdded = EFalse;

        for ( TInt i = 0 ; i < iIniFilesData[0]->iIniData.Count() ; i++ )
            {
            RPointerArray<HBufC8>& array =
                iIniFilesData[0]->iIniData[i]->iFilenameArray;
            // if more than 2 bmps (bitmap and mask), it is animated
            if ( array.Count() > 2 )
                {
                // Checking if the pictograph is animated for all heights
                // is done in function GenerateAnimationFramesDefinitionsL.
                // It is enough to be done in one place.
                temp.Zero();
                temp.Format( KAnimatedTableRow,
                             iIniFilesData[0]->iIniData[i]->iCode,
                             /*rate*/1,
                             iIniFilesData[0]->iIniData[i]->iCode);
          
                aData.Append( temp );

                rowsAdded = ETrue;
                }
            }

        TInt decCount = 0;
        if ( !rowsAdded )
            {
            aData.Append( KAnimatedTableDummyRow );
            decCount = 1; // This will adjust the real animated pictograph count to 0
            }
        else
            {
            aData.Delete( aData.Length() - 3, 1 ); // remove last comma
            }
        aData.Append( KArrayEnd );

        // Append KAknPictographAnimatedPictographsCount row
        temp.Zero();
        temp.Format( KAknPictographAnimatedPictographsCount, decCount );
        aData.Append( temp );
        }
    else
        {
        // At least one height must be supported
        User::Leave( KErrGeneral );
        }
    }


// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateStaticDefinitionsL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateStaticDefinitionsL(TPtr8& aData)
    {
    TBuf8<128> temp;

    // Generate Static definitions for each static pictograph
    if (iIniFilesData.Count())
        {
        RArray<TUint> indexArray = RArray<TUint>(iIniFilesData.Count());
        CleanupClosePushL( indexArray );

        // Init indexes for each supported height
        for (TInt k = 0; k < iIniFilesData.Count(); k++)
            {
            indexArray.Append(0);
            }

        for ( TInt i = 0 ; i < iIniFilesData[0]->iIniData.Count() ; i++ )
            {
            // Check if the pictograph is static and 
            // if yes it must be static for all supported heights
            TInt rowCount = 0;
            for (TInt z = 0; z < iIniFilesData.Count(); z++)
                {
                RPointerArray<HBufC8>& array =
                    iIniFilesData[z]->iIniData[i]->iFilenameArray;

                // if only 2 bmps (bitmap and mask), it is static
                if ( array.Count() == 2 )
                    {
                    if (!rowCount)
                        {
                        // Only insert table header before the first row
                        // Static definition table
                        temp.Zero();
                        temp.Format( KStaticDefinitionStart,
                                     iIniFilesData[0]->iIniData[i]->iCode);

                        aData.Append( temp );
                        aData.Append( KArrayStart );
                        }
                    TSize size = iBitmapsData[z]->iBitmapSizes[indexArray[z]];
                    TInt offset = (*iBitmapsData[z]->iOffsets)[indexArray[z]];

                    temp.Zero();
                    temp.Format( KStaticDefinitionRow, offset, size.iWidth, size.iHeight );
                    aData.Append( temp );
                    rowCount++;
                    }
                indexArray[z] += array.Count() / 2;
                }
            if ( rowCount > 0 )
                {
                if ( rowCount != iIniFilesData.Count() )
                    {
                    // If it is static pictograph then it must be for all heights
                    User::Leave( KErrGeneral );
                    }
                else
                    {
                    aData.Delete( aData.Length() - 3, 1 ); // remove last comma
                    aData.Append( KArrayEnd );
                    }
                }
            }
        CleanupStack::PopAndDestroy(); // indexArray
        }
    else
        {
        // At least one height must be supported
        User::Leave( KErrGeneral );
        }
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GenerateStaticPictographTableL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GenerateStaticPictographTableL( TPtr8& aData )
    {
    TBuf8<256> temp;

    aData.Append( KStaticTableStart );
    aData.Append( KArrayStart );

    // any rows added in the array?
    TBool rowsAdded = EFalse;

    for ( TInt i = 0 ; i < iIniFilesData[0]->iIniData.Count() ; i++ )
        {
        RPointerArray<HBufC8>& array =
            iIniFilesData[0]->iIniData[i]->iFilenameArray;
        // if only 2 bmps (bitmap and mask), it is static
        if ( array.Count() == 2 )
            {
            // Checking if the pictograph is static for all heights
            // is done in function GenerateStaticDefinitionsL.
            // It is enough to be done in one place.
            temp.Zero();
            temp.Format( KStaticTableRow,
                         iIniFilesData[0]->iIniData[i]->iCode,
                         iIniFilesData[0]->iIniData[i]->iCode );
            aData.Append( temp );
            rowsAdded = ETrue;
            }
        }
    TInt decCount = 0;
    if ( !rowsAdded )
        {
        aData.Append( KStaticTableDummyRow );
        decCount = 1; // This will adjust the real static pictograph count to 0
        }
    else
        {
        aData.Delete( aData.Length() - 3, 1 ); // remove last comma
        }
    aData.Append( KArrayEnd );

    // Append KAknPictographStaticPictographsCount row
    temp.Zero();
    temp.Format( KAknPictographStaticPictographsCount, decCount );
    aData.Append( temp );
    }

// -----------------------------------------------------------------------------
// CBitmapBuilder::GeneratePictographRangeL
// -----------------------------------------------------------------------------
//
void CBitmapBuilder::GeneratePictographRangeL()
    {
    if (iIniFilesData.Count() && iIniFilesData[0]->iIniData.Count())
        {
        TFileName name;
        name = KGeneratedPathEpoc;
        name.Append( KRangeFile );

        RFile file;
        User::LeaveIfError( file.Replace( iFs, name, EFileWrite ) );
        CleanupClosePushL( file );

        TInt pos = 0;
        // go in the beginning of the file
        User::LeaveIfError( file.Seek( ESeekStart, pos ) );

        HBufC8* buffer = HBufC8::NewLC( 4000 );
        TPtr8 data = buffer->Des();

        TBuf8<128> temp;

        data.Append( KGeneratedInfo );
        data.Append( KRangeHeaderStart );

        temp.Format( KRangeStart, iIniFilesData[0]->iIniData[0]->iCode );
        data.Append( temp );

        temp.Format( KRangeEnd, iIniFilesData[0]->iIniData[iIniFilesData[0]->iIniData.Count() - 1]->iCode );
        data.Append( temp );

        data.Append( KEndIf );
        data.Append( KHeaderEnd );

        User::LeaveIfError( file.Write( data ) );
        CleanupStack::PopAndDestroy( 2 ); // file, buffer
        }
    else
        {
        // At least one height and one pictograph must be supported
        User::Leave( KErrGeneral );
        }
    }

//  End of File