// Copyright (c) 1995-2009 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:
//

#include <s32file.h>
#include <bitmap.h>
#include <graphicsaccelerator.h>
#include <fbs.h>
#include <graphics/bitmapuid.h>
#include "fbsdefs.h"
#include "UTILS.H"
#include "fbshelper.h"
#include "fbsrasterizer.h"
#include "BitwiseBitmap.inl"
#include "FbsMessage.H"
#include "bitmapconst.h"

const TInt KMaxPixelSize = KMaxTInt / 4; // Maximum pixel size to avoid some overflow problems
const TInt KMaxBitmapHandleBufferSize = KNumBytesPerBitmapHandle * 2000; 	// Maximum size of buffer to store all bitmap handles.

GLREF_C void Panic(TFbsPanic aPanic);

//If we have to handle RAM located file with an embedded ROM mbm file section - 
//KRomMBMInRamRSC should be ETrue.
//If it is not allowed to do that - KRomMBMInRamRSC should be EFalse.
//The same constant is defined into TDefect test app. It should be changed too.
#pragma warning(disable : 4127)   //conditional expression is constant
LOCAL_D const TBool KRomMBMInRamRSC = EFalse;

//Cleanup function used by CFbsBitmap::LoadShiftedRomBmpL(...)
LOCAL_D void FreeMem(TAny* aMem)
	{
	delete[] static_cast<TUint8*>(aMem);
	}

// Fbs style bitmap client class for font bitmap server
/** @publishedAll */
EXPORT_C CFbsBitmap::CFbsBitmap():
	CBase(),
	iFbs(RFbsSession::GetSession()),
	iAddressPointer(NULL),
	iFlags(0),
	iUseCount(0),
	iHandle(0),
	iServerHandle(0)
	{
	}
	
/** Destructor. Calls Reset().
@see Reset()
@publishedAll 
@released
*/
EXPORT_C CFbsBitmap::~CFbsBitmap()
	{
	Reset();
	}
	
/** Gets the physical length in bytes of a scanline in memory. 
This is aligned to a 4 byte (DWORD) boundary for performance reasons.

@param aLength The length of a scanline in pixels. 
@param aDispMode The display mode of the bitmap. 
@return Number of bytes in the scanline in memory. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::ScanLineLength(TInt aLength,TDisplayMode aDispMode)
	{
	if (aDispMode == ERgb)
		return aLength * 4;
	else if (aDispMode == ENone)
		return 0;

	return CBitwiseBitmap::ByteWidth(aLength,aDispMode);
	}

/** Releases the bitmap's handle from the font and bitmap server and decrements 
its access count.
The server-side bitmap is only deleted when the access count for the bitmap 
decrements to zero. 
@publishedAll
@released
*/
EXPORT_C void CFbsBitmap::Reset()
	{
	if (iHandle && !(iFlags & EIsRomBitmap))
		{
		iFbs->SendCommand(EFbsMessClose, iHandle, Handle());
		iFbs->iHelper->RemoveBitmap(*this);
		}
	if (KRomMBMInRamRSC && (iFlags & EIsRomBitmap))
		{
		// If it is a ROM bitmap, we have to check, is it a ROM bitmap located
		// in RAM? If yes, then we have to deallocate the bitmap memory.
		TBool isInRom = EFalse;
		TInt ret = User::IsRomAddress(isInRom, iAddressPointer);
		if (ret == KErrNone && !isInRom)
			delete[] reinterpret_cast<TUint8*>(iAddressPointer);
		}
	iAddressPointer = NULL;
	iFlags = 0;
	iUseCount = 0;
	iHandle = 0;
	iServerHandle = 0;
	}
	
/** Tests whether or not the bitmap is read-only.
@return ETrue if the bitmap is read-only, EFalse otherwise.
@publishedAll
@released
*/
EXPORT_C TBool CFbsBitmap::IsRomBitmap() const
	{
	return (iFlags & EIsReadOnlyBitmapMask) > 0;
	}

/**  Sets the bitmap to use a bitmap image stored in ROM.
@param aRomBitmapPointer Pointer to a bitmap stored in ROM.
@param aBitmapSizeInBytes On return, indicates the size of 
the bitmap in bytes. 
@leave KErrUnknown aRomBitmapPointer is not in ROM, or has an invalid UID.
@publishedAll
@released
*/	
EXPORT_C void CFbsBitmap::SetRomBitmapL(CBitwiseBitmap* aRomBitmapPointer,TInt& aBitmapSizeInBytes)
    {
	TBool isInRom = EFalse;
	TInt ret = User::IsRomAddress(isInRom,(TAny*)aRomBitmapPointer);
	if (ret != KErrNone || !isInRom || aRomBitmapPointer->Uid() != KCBitwiseBitmapUid)
		User::Leave(KErrUnknown);

	Reset();
	iAddressPointer = aRomBitmapPointer;
	iFlags = EIsRomBitmap;
	iHandle = 1;

	User::LeaveIfError(iFbs->AllocScanLineBuffer(aRomBitmapPointer->iByteWidth + 4));
	aBitmapSizeInBytes = Align4(aRomBitmapPointer->iHeader.iBitmapSize + 28);
	}

CBitwiseBitmap* CFbsBitmap::Address() const
	{
	if (!iHandle)
		return NULL;
	return iAddressPointer;
	}

EXPORT_C CBitwiseBitmap* CFbsBitmap::CleanAddress() const
	{
	if (!iHandle)
		return NULL;
	// Don't try to clean a dirty bitmap between calls to BeginDataAccess() and EndDataAccess(), i.e. iUseCount > 0
	// ROM bitmaps can never be dirty
	if (!(iFlags & EIsReadOnlyBitmapMask) && iUseCount == 0 && iAddressPointer->iSettings.IsDirtyBitmap())
		{
		TPckgBuf<TBmpHandles> handlebuf;
		TIpcArgs args(iHandle, &handlebuf);
		if (iFbs->SendCommand(EFbsMessBitmapClean, args) == KErrNone)
			{
			const_cast<CFbsBitmap*>(this)->iHandle = handlebuf().iHandle;
			const_cast<CFbsBitmap*>(this)->iServerHandle = handlebuf().iServerHandle;
			const_cast<CFbsBitmap*>(this)->iAddressPointer = (CBitwiseBitmap*)(iFbs->HeapBase() + handlebuf().iAddressOffset);
			}
		}
	return iAddressPointer;
	}

inline CBitwiseBitmap* CFbsBitmap::BeginDataAccessAndGetCleanAddress(TUint32*& aDataAddress) const
	{
	BeginDataAccess();
	CBitwiseBitmap* bmp = Address();
	// aDataAddress should be consistent with bmp since after the call to BeginDataAccess()
	// the call to DataAddress() will not clean the bitmap again
	aDataAddress = DataAddress();
	return bmp;
	}

/** Gets the address of the first pixel in the bitmap. 
The first pixel is at the top-left. Access to the pixel data of a bitmap
should be surrounded by calls to BeginDataAccess() and EndDataAccess(),
otherwise performance may be degraded on certain platforms.

Note: Performing a Resize() or Compress() operation changes the value returned by this function.
@return The address of the first pixel of the bitmap.
@publishedAll
@released
@see CFbsBitmap::BeginDataAccess()
@see CFbsBitmap::EndDataAccess()
*/
EXPORT_C TUint32* CFbsBitmap::DataAddress() const
	{
	if(!iHandle) return(NULL);
	CBitwiseBitmap* bmp = CleanAddress();

	if (!(iFlags & EIsReadOnlyBitmapMask) && (iUseCount == 0))
		bmp->iSettings.SetVolatileBitmap();
		
	if(bmp->iUid.iUid==KCBitwiseBitmapHardwareUid.iUid)   // RHardwareBitmap
		{
		RHardwareBitmap hwb(bmp->iDataOffset);	// iDataOffset = handle for hardware bitmap
		TAcceleratedBitmapInfo info;
		const TInt ret = hwb.GetInfo(info);
		return ret!=KErrNone ? NULL : (reinterpret_cast<TUint32*>(info.iAddress));
		}

	if (bmp->iHeap == NULL)
		return(reinterpret_cast<TUint32*>((TUint8*)bmp+bmp->iDataOffset));
	return(reinterpret_cast<TUint32*>(iFbs->iLargeBitmapChunk.Base()+bmp->iDataOffset));
	}

/** Gets the length in bytes between scanlines in memory.
@return The length in bytes between scanlines in memory. 
@internalAll
@released
*/
EXPORT_C TInt CFbsBitmap::DataStride() const
	{
	if (!iHandle)
		{
		return 0;
		}
		
	CBitwiseBitmap* bmp = CleanAddress();
	if (bmp==NULL)
		{
		return 0;
		}
		
	return bmp->DataStride();	
	}

/** Creates a bitmap with the specified size and display mode. The bitmap is 
created on the font and bitmap server's shared heap.
@param aSizeInPixels The size of the bitmap to be created. 
@param aDispMode The display mode of the bitmap to be created. 
@return KErrNone if successful; KErrCouldNotConnect if no connection to the 
font and bitmap server could be made; KErrArgument if either the width or height specified 
in aSizeInPixels are negative or if the requested display mode is invalid; KErrTooBig 
if the requested size is too big. 
@publishedAll
@released
*/
EXPORT_C TInt CFbsBitmap::Create(const TSize& aSizeInPixels,TDisplayMode aDispMode)
	{
	return DoCreate(aSizeInPixels,aDispMode,KUidCFbsBitmapCreation);
	}

TInt CFbsBitmap::DoCreate(const TSize& aSizeInPixels, TDisplayMode aDispMode, TUid aUid, TInt aDataSize)
	{
	if(!iFbs) return(KErrCouldNotConnect);
	if (aDispMode <= ENone || aDispMode == ERgb || aDispMode >= EColorLast) return KErrArgument;
	if(aSizeInPixels.iWidth<0 || aSizeInPixels.iHeight<0) return(KErrArgument);
	if (aDataSize < 0) return KErrArgument;
	Reset();
	TBmpSpec bmpspec;
	bmpspec.iSizeInPixels=aSizeInPixels;
	bmpspec.iDispMode=aDispMode;
	bmpspec.iHandle = aUid.iUid;	// Use iHandle to pass UID
	bmpspec.iServerHandle = aDataSize;	// Use iServerHandle to pass data size
	TPckgBuf<TBmpSpec> b;
	b=bmpspec;
	TIpcArgs args(&b);
	TInt ret=iFbs->SendCommand(EFbsMessBitmapCreate,args);
	if(ret!=KErrNone) return(ret);
	iHandle=b().iHandle;
	iServerHandle=b().iServerHandle;
	iAddressPointer=(CBitwiseBitmap*)(iFbs->HeapBase()+b().iAddressOffset);
	if (aDataSize > 0) // explicitly specified data size means extended bitmap
		{
		iFlags = EIsExtendedBitmap;
		}
	ret = iFbs->iHelper->AddBitmap(*this);
	if (ret != KErrNone)
		return ret;
	return iFbs->AllocScanLineBuffer(CBitwiseBitmap::ByteWidth(aSizeInPixels.iWidth, aDispMode)+4);
	}

/** Creates a hardware bitmap with a size and display mode.
@param aSizeInPixels The bitmap's width and height in pixels.
@param aDispMode The bitmap's display mode.
@param aCreatorUid The UID of the application calling this function. This is 
used to allow segregation of the memory used for hardware bitmaps. For instance, 
if a device has video memory attached to display and graphics accelerator 
hardware, this UID is used to determine whether any video memory is pre-allocated 
for that application's use.
@return KErrNone if successful, otherwise one of the system wide error codes. 
These include KErrCouldNotConnect if no connection has been made to the font 
and bitmap server, KErrArgument if either the width or height specified in 
aSizeInPixels are negative or if the requested display mode is invalid, or KErrNotSupported 
if hardware bitmaps are not supported on the device. 
@publishedAll
@released
*/
EXPORT_C TInt CFbsBitmap::CreateHardwareBitmap(const TSize& aSizeInPixels,TDisplayMode aDispMode,TUid aCreatorUid)
	{
	return DoCreate(aSizeInPixels,aDispMode,aCreatorUid);
	}

/** Resets the pixel-size of the bitmap.
If the new size is bigger than the old, the original bitmap is still situated 
at (0,0), but pixels outside the range of the old pixel-size are set to zero.
@param aSizeInPixels The new size of the bitmap. 
@return KErrNone if successful; KErrArgument if the new size is illegal; 
KErrGeneral if the bitmap has not yet been created; KErrAccessDenied if the 
bitmap is in ROM or is an extended bitmap; otherwise another of the system-wide error codes. 
@publishedAll
@released
*/
EXPORT_C TInt CFbsBitmap::Resize(const TSize& aSizeInPixels)
	{
	if(aSizeInPixels.iWidth<0 || aSizeInPixels.iHeight<0) 
		return(KErrArgument);
	if(aSizeInPixels.iWidth>KMaxPixelSize || aSizeInPixels.iHeight>KMaxPixelSize)
		return(KErrTooBig);	
	if(!iHandle) 
		return(KErrGeneral);
	if (iFlags & EIsReadOnlyBitmapMask)
		return(KErrAccessDenied);	
	TPckgBuf<TBmpHandles> handlebuf;
	TIpcArgs args(iHandle, aSizeInPixels.iWidth, aSizeInPixels.iHeight, &handlebuf);
	TInt err = iFbs->SendCommand(EFbsMessBitmapResize, args);
	if (err != KErrNone)
		return (err);
	iHandle = handlebuf().iHandle;
	iServerHandle = handlebuf().iServerHandle;
	iAddressPointer = (CBitwiseBitmap*)(iFbs->HeapBase() + handlebuf().iAddressOffset);
	return iFbs->AllocScanLineBuffer(CBitwiseBitmap::ByteWidth(aSizeInPixels.iWidth, DisplayMode())+4);
	}

/** Gets the display mode of the bitmap.
@return The display mode of the bitmap. 
@publishedAll
@released
*/
EXPORT_C TDisplayMode CFbsBitmap::DisplayMode() const
	{
	if(iHandle==NULL) return(ENone);
	return CleanAddress()->DisplayMode();
	}

/** Returns the display mode that was used to create the bitmap.
@return The display mode used to create the bitmap.
@publishedAll
@released
*/
EXPORT_C TDisplayMode CFbsBitmap::InitialDisplayMode() const
	{
	if(iHandle == NULL) 
		{
		return ENone;
		}
	return CleanAddress()->InitialDisplayMode();
	}

/**
Changes the display mode of the bitmap.
The requested display mode cannot be greater (in bpp value) than the initial display mode.
This method cannot leave, for instance because of an out of memory condition. No 
additional memory is allocated or leaving methods called.
The bitmap's content is preserved when converting it to the requested display mode,
but there may be some loss of quality.
@publishedAll
@released
@param aDisplayMode The requested display mode.
@return KErrArgument if the requested mode is invalid, or has a greater bpp value 
than the initial mode. KErrNotSupported if the bitmap is compressed, or is a
ROM bitmap, an extended bitmap or a hardware bitmap. KErrGeneral if the bitmap
handle is NULL. KErrNone if the method call is successful.
@see CFbsBitmap::InitialDisplayMode()
*/
EXPORT_C TInt CFbsBitmap::SetDisplayMode(TDisplayMode aDisplayMode)
	{
	if(!iHandle) 
		{
		return KErrGeneral;
		}	
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);
	TInt err = bmp->SetDisplayMode(aDisplayMode, data);
	EndDataAccess(EFalse);
	return err;
	}

/** Duplicates a bitmap.
This function does not create a copy of the bitmap. It just assigns another 
handle to the bitmap in the font and bitmap server, and sets this object's 
handle to that. If the specified bitmap is in the ROM, it just assigns a pointer 
to it.
@param aHandle The handle to an existing bitmap.
@return KErrNone if successful; KErrCouldNotConnect if no connection to the 
font and bitmap server could be made; KErrUnknown if no bitmap could be found 
with the specified handle number.
@publishedAll
@released
@see CFbsBitmap::Handle()
*/
EXPORT_C TInt CFbsBitmap::Duplicate(TInt aBitmapHandle)
		{
	if(!iFbs) 
		{
		return(KErrCouldNotConnect);
		}
	if(!aBitmapHandle) 
		{
		return(KErrUnknown);
		}
	Reset();
	TBool isinrom=EFalse;
	TInt ret=User::IsRomAddress(isinrom,(TAny*)aBitmapHandle);
	if(ret!=KErrNone) 
		{
		return(KErrUnknown);
		}
	if(isinrom)
		{
		if (((CBitwiseBitmap*)aBitmapHandle)->Uid() != KCBitwiseBitmapUid)
			return(KErrUnknown);
		iAddressPointer = (CBitwiseBitmap*)aBitmapHandle;
		iFlags = EIsRomBitmap;
		iHandle=1;
		return iFbs->AllocScanLineBuffer(iAddressPointer->iByteWidth + 4);
		}
	TPckgBuf<TBmpHandles> b;
	TIpcArgs args(aBitmapHandle,&b);
	ret=iFbs->SendCommand(EFbsMessBitmapDuplicate,args);
	if(ret!=KErrNone) 
		{
		return(ret);
		}
	iHandle=b().iHandle;
	iServerHandle=b().iServerHandle;
	iAddressPointer=(CBitwiseBitmap*)(iFbs->HeapBase()+b().iAddressOffset);
	if (iAddressPointer->iUid.iUid != KCBitwiseBitmapUid.iUid && iAddressPointer->iUid.iUid != KCBitwiseBitmapHardwareUid.iUid)
		{
		iFlags = EIsExtendedBitmap;
		}
	ret = iFbs->iHelper->AddBitmap(*this);
	if (ret != KErrNone)
		{
		return ret;
		}
	return iFbs->AllocScanLineBuffer(iAddressPointer->iByteWidth+4);
	}

/** Loads a specific bitmap from a multi-bitmap file.
The bitmap may be shared by other font and bitmap server clients.
@param aFileName The filename of the multi-bitmap (.mbm) file. 
@param aId The bitmap identifier.
@param aShareIfLoaded Specifies whether or not the loaded bitmap will be made 
available for sharing between font and bitmap server clients. 
@return KErrNone if successful, otherwise another of the system error 
codes. 
@publishedAll
@released
*/	
EXPORT_C TInt CFbsBitmap::Load(const TDesC& aFileName,TInt32 aId,TBool aShareIfLoaded)
	{
	return Load(aFileName,aId,aShareIfLoaded,0);
	}

/**  Loads a specific bitmap from a multi-bitmap file.
The bitmap may be shared by other font and bitmap server clients.
@param aFileName The filename of the multi-bitmap (.mbm) file.
@param aId The bitmap identifier.
@param aShareIfLoaded  Specifies whether or not the loaded bitmap will be made 
available for sharing between FBSERV clients.
@param aFileOffset Bitmap file section offset within the file.
@return KErrNone if successful, otherwise another of the system error codes.
@publishedAll
@released
*/	
EXPORT_C TInt CFbsBitmap::Load(const TDesC& aFileName,TInt32 aId,TBool aShareIfLoaded,TUint aFileOffset)
	{
	if(!iFbs)
		{
		return(KErrCouldNotConnect);
		}
	Reset();
	TUint32* rompointer = NULL;
	//access using filename has the advantage of using rom address lookup cache
	IsFileInRom(aFileName, rompointer);
	TBool romPointerValid;
	TInt err = DoLoadFromRom(rompointer, aId, aFileOffset, romPointerValid);
	if(romPointerValid)
		{
		return err;
		}
	_LIT(KResourcePath, "?:\\Resource\\*");
	TInt match = aFileName.MatchF(KResourcePath);
	//if the file is in the resource directory we don't need to check capabilities and the file can just be opened on the server side.
	if (match == 0)
		{
		err = DoLoad(aFileName,aId,aShareIfLoaded,aFileOffset);
		}
	else
		{
		RFile file;
		err = file.Open(iFbs->FileServer(),aFileName,EFileShareReadersOnly);
		if (err!=KErrNone)
			{
			return err;
			}
		err = DoLoad(file,aId,aShareIfLoaded,aFileOffset);
		file.Close();
		}
	return err;
	}

/** Loads and compresses a specific bitmap from a multi-bitmap file.
The bitmap may be shared by other font and bitmap server clients.
If the bitmap is loaded from ROM then compression is not allowed.
@param aFileName The filename of the multi-bitmap (.mbm) file.
@param aId The bitmap identifier.
@param aShareIfLoaded Specifies whether or not the loaded bitmap will be
made available for sharing between FBSERV clients.
@return KErrNone if successful, otherwise another of the system-wide error 
codes. 
@publishedAll 
@released
*/	
EXPORT_C TInt CFbsBitmap::LoadAndCompress(const TDesC& aFileName,TInt32 aId,TBool aShareIfLoaded)
    {	
    return LoadAndCompress(aFileName, aId, aShareIfLoaded, 0);
	}

/** Loads and compresses a specific bitmap from a multi-bitmap file.
The bitmap may be shared by other font and bitmap server clients. If the 
bitmap is loaded from ROM then compression is not allowed.
@param aFileName The filename of the multi-bitmap (.mbm) file.
@param aId The bitmap identifier.
@param aShareIfLoaded Specifies whether or not the loaded bitmap will be made 
available for sharing between FBSERV clients.
@param aFileOffset Bitmap file section offset within the file.
@return KErrNone if successful, otherwise another of the system-wide error 
codes. 
@publishedAll 
@released
*/	
EXPORT_C TInt CFbsBitmap::LoadAndCompress(const TDesC& aFileName,TInt32 aId,TBool aShareIfLoaded,TUint aFileOffset)
    {	
	TInt err = Load(aFileName,aId,aShareIfLoaded,aFileOffset);
	if (err == KErrNone)
		{
		err = !(iFlags & EIsRomBitmap) ? Compress() : KErrAccessDenied;
		}
	return err;
	}

/** Saves the bitmap as a direct file store.
The file store overwrites any existing file with the same name.
@param aFilename The name of the file. 
@return KErrNone if successful, KErrNotSupported if this CFbsBitmap is an 
extended bitmap, otherwise another of the system-wide error codes. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::Save(const TDesC& aFilename)
	{
	if (!iHandle)
		{
		return(KErrGeneral);
		}
	RFile file;
	TInt ret=file.Replace(iFbs->FileServer(),aFilename,EFileWrite);
	if(ret!=KErrNone) return(ret);
	TRAP(ret,DoSaveL(file));
	file.Close();
	return(ret);
	}

/** Saves the bitmap as a direct file store using an opened file handle.
The file store overwrites any existing file with the same name.
@param aFile The opened file handle
@return KErrNone if successful, KErrNotSupported if this CFbsBitmap is an 
extended bitmap, otherwise another of the system-wide error codes. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::Save(RFile& aFile)
	{
	if (!iHandle)
		{
		return KErrGeneral;
		}
	TRAPD(ret,DoSaveL(aFile));
	return ret;
	}

void CFbsBitmap::DoSaveL(RFile& aFile)
	{
	CDirectFileStore* filestore=CDirectFileStore::NewLC(aFile); // create from open file
	TUidType uidtype(KDirectFileStoreLayoutUid,KMultiBitmapFileImageUid);
	filestore->SetTypeL(uidtype);
	RStoreWriteStream bmpstream;
	TStreamId bmpstreamid=bmpstream.CreateLC(*filestore); // create bitmap stream
	ExternalizeL(bmpstream);
	bmpstream.CommitL();
	CleanupStack::PopAndDestroy(); // bitmap stream
	RStoreWriteStream rootstream;
	TStreamId rootstreamid=rootstream.CreateLC(*filestore); // create root stream
	rootstream.WriteInt32L(1); // number of bitmaps
	rootstream<<bmpstreamid; // stream id of bitmap
	rootstream.CommitL();
	CleanupStack::PopAndDestroy(); // root stream
	filestore->SetRootL(rootstreamid);
	filestore->CommitL();
	CleanupStack::PopAndDestroy(); // file store
	}

/** Constructs a multi-bitmap file.
@param aFilename The name of the multi-bitmap file to be created.
@param aNumSources The number of bitmaps to store in the file.
@param aSources  An array of pointers to bitmaps to be stored.
@param aSourceIds An array of identifiers for the bitmaps to be stored. 
@publishedAll
@released
*/	
EXPORT_C void CFbsBitmap::StoreL(const TDesC& aFilename,TInt aNumSources,const TDesC* aSources[],TInt32 aSourceIds[])
	{
	CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
	CleanupStack::PushL(bitmap);
	CDirectFileStore* filestore = CDirectFileStore::ReplaceLC(bitmap->iFbs->FileServer(),aFilename,EFileWrite);
	DoStoreL(filestore,bitmap,aNumSources,aSources,aSourceIds);
	CleanupStack::PopAndDestroy(2,bitmap);	
	}

/** Constructs a multi-bitmap file using an opened file handle.
@param aFile The opened file handle of multi-bitmap file
@param aNumSources The number of bitmaps to store in the file.
@param aSources  An array of pointers to bitmaps to be stored.
@param aSourceIds An array of identifiers for the bitmaps to be stored. 
@publishedAll
@released
*/	
EXPORT_C void CFbsBitmap::StoreL(RFile& aFile,TInt aNumSources,const TDesC* aSources[],TInt32 aSourceIds[])
	{
	CDirectFileStore* filestore = CDirectFileStore::NewLC(aFile);
	DoStoreL(filestore,NULL,aNumSources,aSources,aSourceIds);
	CleanupStack::PopAndDestroy(filestore);	
	}

/**
@internalComponent
*/
void CFbsBitmap::DoStoreL(CDirectFileStore* aFileStore,CFbsBitmap* aBitmap,TInt aNumSources,const TDesC* aSources[],TInt32 aSourceIds[])
	{
	if(aNumSources<1 || aSources==NULL) User::Leave(KErrArgument);
	TInt count=0;
	for(;count<aNumSources;count++)
		if(aSources[count]==NULL) User::Leave(KErrArgument);
	TStreamId* ids=new(ELeave) TStreamId[aNumSources];
	CleanupArrayDeletePushL(ids);
	TInt nPushed=1;
	if (!aBitmap)
		{
		aBitmap=new(ELeave) CFbsBitmap;
		CleanupStack::PushL(aBitmap);
		++nPushed;
		}
	TUidType uidtype(KDirectFileStoreLayoutUid,KMultiBitmapFileImageUid);
	aFileStore->SetTypeL(uidtype);
	for(count=0;count<aNumSources;count++)
		{
		User::LeaveIfError(aBitmap->Load(*aSources[count],aSourceIds[count]));
		RStoreWriteStream bmpstream;
		ids[count]=bmpstream.CreateLC(*aFileStore); // create bitmap stream
		aBitmap->ExternalizeL(bmpstream);
		bmpstream.Close();
		CleanupStack::Pop(); // bitmap stream
		}
	RStoreWriteStream rootstream;
	TStreamId rootstreamid=rootstream.CreateLC(*aFileStore); // create root stream
	rootstream.WriteInt32L(aNumSources); // number of bitmaps
	for(count=0;count<aNumSources;count++)
		rootstream<<ids[count]; // stream ids of bitmaps
	rootstream.Close();
	CleanupStack::Pop(); // root stream
	aFileStore->SetRootL(rootstreamid);
	CleanupStack::PopAndDestroy(nPushed); // ids [and bitmap]
	}

/** Gets the bitmap's scanline for the specified line starting from the 
specified point.
The dither offset of the bitmap is taken to be TPoint(0,0).
@param aBuf The buffer in which the scanline is returned. 
@param aPoint The start pixel. 
@param aLength The number of pixels to get. 
@param aDispMode Format to be used to write the data to the buffer. 
@publishedAll
@released
*/
EXPORT_C void CFbsBitmap::GetScanLine(TDes8& aBuf,const TPoint& aPoint,TInt aLength,TDisplayMode aDispMode) const
	{
	GetScanLine(aBuf,aPoint,aLength,TPoint(0,0),aDispMode);
	}

/** Gets the bitmap's scanline for the specified line starting from the specified 
point and using the specified dither offset.
@param aBuf The buffer in which the scanline is returned. 
@param aPixel The start pixel. 
@param aLength The number of pixels to get. 
@param aDitherOffset The dither offset of the bitmap. 
@param aDispMode Format to be used to write the data to the buffer. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::GetScanLine(TDes8& aBuf,const TPoint& aPoint,TInt aLength,const TPoint& aDitherOffset,TDisplayMode aDispMode) const
	{
	if(!iHandle) return;
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);
	CFbsRasterizer* rasterizer = NULL;
	if ((iFlags & EIsExtendedBitmap) && iFbs)
		{
		rasterizer = iFbs->iHelper->Rasterizer();
		if (rasterizer)
			{
			CFbsRasterizer::TBitmapDesc desc;
			desc.iSizeInPixels = bmp->SizeInPixels();
			desc.iDispMode = bmp->DisplayMode();
			desc.iDataType = bmp->iUid;
			desc.iData = data;
			desc.iDataSize = bmp->iHeader.iBitmapSize - bmp->iHeader.iStructSize;
			rasterizer->BeginBitmap(bmp->Extra()->iSerialNumber, desc, NULL);
			}
		}
	bmp->GetScanLine(aBuf, aPoint, aLength, ETrue, aDitherOffset, aDispMode, data);
	if (rasterizer)
		{
		rasterizer->EndBitmap(bmp->Extra()->iSerialNumber);
		}
	EndDataAccess(ETrue);
	}

/** Sets the bitmap's horizontal scanline at the specified y co-ordinate to the 
scanline contained in the buffer.
@param aBuf The new scanline to be written to the bitmap. 
@param aY The y co-ordinate of the scanline.
@panic FBSCLI 11 in debug builds if this is a compressed bitmap.
@panic FBSCLI 28 in debug builds if this is a read-only bitmap.
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::SetScanLine(TDes8& aBuf,TInt aY) const
	{
	if (!iHandle)
		return;	
	if (iFlags & EIsReadOnlyBitmapMask)
		{
		__ASSERT_DEBUG(EFalse, ::Panic(EFbsPanicBitmapReadOnly));
		return;
		}
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);
	if (bmp->IsCompressed())
		{
		EndDataAccess(ETrue);
		__ASSERT_DEBUG(EFalse, ::Panic(EFbsBitmapInvalidCompression));
		return;
		}
	data = bmp->ScanLineAddress(data, aY);
	TInt bytewidth = bmp->iByteWidth;
	TInt bytelen=aBuf.Length();
	if(bytelen<bytewidth) bytewidth=bytelen;
	TInt wordlen=bytewidth>>2;
	TUint32* ptr=(TUint32*)aBuf.Ptr();
	TUint32* ptrlim=ptr+wordlen;
	while(ptr<ptrlim)
		*data++=*ptr++;
	TInt limit=wordlen<<2;
	if(limit<bytewidth)
		{
		TUint8* byteptr=(TUint8*)ptrlim;
		TUint8* databyte=(TUint8*)data;
		while(limit<bytewidth)
			{
			*databyte++=*byteptr++;
			limit++;
			}
		}
	EndDataAccess(EFalse);
	}

/** Gets the bitmap's vertical scanline starting at the specified x co-ordinate.
Note: The method only works for uncompressed bitmaps.
Note: The dither offset of the bitmap is taken to be TPoint(0,0).
@param aBuf The buffer in which the vertical scanline is returned. 
@param aX The x co-ordinate of the vertical scanline. 
@param aDispMode Format to be used to write the data to the buffer. 
@panic FBSCLI 11 in debug builds if this is not an ucompressed bitmap or an extended bitmap.
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::GetVerticalScanLine(TDes8& aBuf,TInt aX,TDisplayMode aDispMode) const
	{
	GetVerticalScanLine(aBuf,aX,TPoint(0,0),aDispMode);
	}

/** Gets the bitmap's vertical scanline starting at the specified x co-ordinate 
and using the specified dither offset.
Note: The method only works for uncompressed bitmaps.
@param aBuf The buffer in which the vertical scanline will be returned. 
@param aX The x co-ordinate of the vertical scanline to get. 
@param aDitherOffset The dither offset of the bitmap. 
@param aDispMode Format to be used to write the data to the buffer. 
@panic FBSCLI 11 in debug builds if this is not an ucompressed bitmap or an extended bitmap.
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::GetVerticalScanLine(TDes8& aBuf,TInt aX,const TPoint& aDitherOffset,TDisplayMode aDispMode) const
	{
	if(!iHandle) return;
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);
	CFbsRasterizer* rasterizer = NULL;
	if ((iFlags & EIsExtendedBitmap) && iFbs)
		{
		rasterizer = iFbs->iHelper->Rasterizer();
		if (rasterizer)
			{
			CFbsRasterizer::TBitmapDesc desc;
			desc.iSizeInPixels = bmp->SizeInPixels();
			desc.iDispMode = bmp->DisplayMode();
			desc.iDataType = bmp->iUid;
			desc.iData = data;
			desc.iDataSize = bmp->iHeader.iBitmapSize - bmp->iHeader.iStructSize;
			rasterizer->BeginBitmap(bmp->Extra()->iSerialNumber, desc, NULL);
			}
		}
	bmp->GetVerticalScanLine(aBuf, aX, ETrue, aDitherOffset, aDispMode, data, rasterizer);
	if (rasterizer)
		{
		rasterizer->EndBitmap(bmp->Extra()->iSerialNumber);
		}
	EndDataAccess(ETrue);
	}

/** Gets the handle number of the bitmap.
The returned value can be used to give another thread access to the bitmap.
@return The handle number of the bitmap. 
@publishedAll 
@released
@see CFbsBitmap::Duplicate()
*/
EXPORT_C TInt CFbsBitmap::Handle() const
	{
	if(!iHandle) 
		return(0);
	if (iFlags & EIsRomBitmap)
		return TInt(iAddressPointer);
	else
		return(iServerHandle);
	}

/** Creates a bitmap header.
This is used when streaming bitmaps to stores.
@return The bitmap header for the bitmap. 
@publishedAll 
@released
*/
EXPORT_C SEpocBitmapHeader CFbsBitmap::Header() const
	{
	if (iHandle)
		return CleanAddress()->iHeader;
	SEpocBitmapHeader header;
	return(header);
	}

/** Converts a horizontal dimension on the graphics device from pixels to twips.
@param aPixels A horizontal dimension on the graphics device in pixels. 
@return A horizontal dimension on the graphics device in twips. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::HorizontalPixelsToTwips(TInt aPixels) const
	{
	if(iHandle==NULL) return(0);
	return CleanAddress()->HorizontalPixelsToTwips(aPixels);
	}

/** Converts a horizontal dimension on the graphics device from twips to pixels.
@param aTwips A horizontal dimension on the graphics device in twips. 
@return A horizontal dimension on the graphics device in pixels. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::HorizontalTwipsToPixels(TInt aTwips) const
	{
	if(iHandle==NULL) return(0);
	return CleanAddress()->HorizontalTwipsToPixels(aTwips);
	}

/** Gets the RGB value of the specified pixel.
Note: The method only works for uncompressed bitmaps and extended bitmaps.
@param aColor On return, the RGB value of the specified pixel. 
@param aPixel The pixel whose colour is to be determined.
@panic FBSCLI 11 in debug builds if this is a compressed bitmap.
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::GetPixel(TRgb& aColor,const TPoint& aPoint) const
	{
	if(!iHandle) 
		{
		return;
		}	
	
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);
	CFbsRasterizer* rasterizer = NULL;
	if ((iFlags & EIsExtendedBitmap) && iFbs)
		{
		rasterizer = iFbs->iHelper->Rasterizer();
		if (rasterizer)
			{
			CFbsRasterizer::TBitmapDesc desc;
			desc.iSizeInPixels = bmp->SizeInPixels();
			desc.iDispMode = bmp->DisplayMode();
			desc.iDataType = bmp->iUid;
			desc.iData = data;
			desc.iDataSize = bmp->iHeader.iBitmapSize - bmp->iHeader.iStructSize;
			rasterizer->BeginBitmap(bmp->Extra()->iSerialNumber, desc, NULL);
			}
		}
	bmp->GetPixel(aColor, aPoint, data, rasterizer);
	if (rasterizer)
		{
		rasterizer->EndBitmap(bmp->Extra()->iSerialNumber);
		}
	EndDataAccess(ETrue);
	}

/** Gets the pixel-size of the bitmap.
@return The size of the bitmap, in pixels. 
@publishedAll 
@released
*/
EXPORT_C TSize CFbsBitmap::SizeInPixels() const
	{
    TSize zero;
	if(!iHandle) return(zero);
	return CleanAddress()->SizeInPixels();
	}

/** Sets the twip-size of the bitmap by converting the bitmaps pixel-size from 
pixels to twips, using the conversion functions in the specified graphics 
device map.
@param aMap The graphics device map to be used for providing pixel to twip 
conversion. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::SetSizeInTwips(const MGraphicsDeviceMap* aMap)
	{
	if (!iHandle || (iFlags & EIsRomBitmap) || aMap == NULL)
		return;
	TSize size=SizeInPixels();
	size.iWidth=aMap->HorizontalPixelsToTwips(size.iWidth);
	size.iHeight=aMap->VerticalPixelsToTwips(size.iHeight);
	iFbs->SetCallBackPtr(&iServerHandle);
	iFbs->CallBack();
	// SizeInPixels() called CleanAddress() so call Address() now to make sure we don't clean the bitmap twice
	Address()->iHeader.iSizeInTwips=size;
	}

/** Sets the twip-size of the bitmap directly to the specified size.
@param aSizeInTwips The new size of the bitmap, in twips. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::SetSizeInTwips(const TSize& aSizeInTwips)
	{
	if (!iHandle || (iFlags & EIsRomBitmap))
		return;
	iFbs->SetCallBackPtr(&iServerHandle);
	iFbs->CallBack();
	CleanAddress()->iHeader.iSizeInTwips = aSizeInTwips;
	}

/** Externalises the bitmap to the specified stream. Not supported for extended bitmaps.
@param aStream The write stream. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::ExternalizeL(RWriteStream& aStream) const
	{
	if (!iHandle)
		User::Leave(KErrGeneral);
	BeginDataAccess();
	Address()->ExternalizeL(aStream, *this);	
	EndDataAccess(ETrue);
	}

/** Externalises that area of the bitmap contained within a specified 
rectangular area. Not supported for extended bitmaps.
@param aStream The write stream
@param aRect The rectangular area of the bitmap to externalise. The bitmap 
that is externalized will be of this size. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::ExternalizeRectangleL(RWriteStream& aStream,const TRect& aRect) const
	{
	if (!iHandle)
		User::Leave(KErrGeneral);
	BeginDataAccess();
	Address()->ExternalizeRectangleL(aStream, aRect, *this);
	EndDataAccess(ETrue);
	}

/** Internalises a CFbsBitmap from a stream.
@param aStream The read stream.
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::InternalizeL(RReadStream& aStream)
	{
	if(!iFbs) User::Leave(KErrCouldNotConnect);
	Reset();
	SEpocBitmapHeader header;
	CBitwiseBitmap::InternalizeHeaderL(aStream,header);

	TDisplayMode dispmode = CBitwiseBitmap::DisplayMode(header.iBitsPerPixel,header.iColor);
	User::LeaveIfError(Create(header.iSizeInPixels,dispmode));

	TUint32* data;
	CBitwiseBitmap* bmp=BeginDataAccessAndGetCleanAddress(data);
	bmp->iHeader=header;
	TInt bytesize = header.iBitmapSize - header.iStructSize;
	if (bytesize > 0)
		{
		bmp->DoInternalizeL(aStream, bytesize, data);
		EndDataAccess(EFalse);
		}
	else
		{
		EndDataAccess(ETrue);
		}
	}

EXPORT_C TInt CFbsBitmap::Compress()
 	{
	return Compress(ERLECompression);
	}

/** Compresses bitmap in RAM.
@param aScheme specifies preferred compression type ERLECompression or EPaletteCompression
@return KErrNone on success, KErrGeneral if the bitmap handle is NULL, KErrAccessDenied if 
the bitmap is in ROM or it is an extended bitmap, otherwise one of the system wide error codes. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::Compress(TBitmapfileCompressionScheme aScheme)
	{
 	if (!iHandle)
 		return KErrGeneral;
 	if (iFlags & EIsReadOnlyBitmapMask)
 		return KErrAccessDenied; 	
	TPckgBuf<TBmpHandles> handlebuf;
	TIpcArgs args(iHandle, aScheme, &handlebuf);
	TInt err = iFbs->SendCommand(EFbsMessBitmapCompress, args);
	if (err != KErrNone)
		return err;
	iHandle = handlebuf().iHandle;
	iServerHandle = handlebuf().iServerHandle;
	iAddressPointer = (CBitwiseBitmap*)(iFbs->HeapBase() + handlebuf().iAddressOffset);
	return KErrNone;
	}

/** Submits the bitmap for asynchronous background compression.
@param aRequestStatus The request status which will be completed with the appropriate error code after the compression has finished
The error code will be KErrNone on success, KErrGeneral if the bitmap handle is NULL, KErrAccessDenied if the
bitmap is in ROM or it is an extended bitmap, otherwise one of the system wide error codes.
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::CompressInBackground(TRequestStatus& aRequestStatus)
	{
	CompressInBackground(aRequestStatus, ERLECompression);
	}

/** Submits the bitmap for asynchronous background compression. No notification will be provided when the compression has completed.
@return KErrNone if the bitmap was successfully submitted to the background compression queue, KErrGeneral if the bitmap handle is NULL, 
KErrAccessDenied if the bitmap is in ROM or it is an extended bitmap,  otherwise another of the system-wide error codes.
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::CompressInBackground()
	{
	return CompressInBackground(ERLECompression);
	}
	
/** Submits the bitmap for asynchronous background compression.
@param aRequestStatus The request status which will be completed with the appropriate error code after the compression has finished.
The error code will be KErrNone on success, KErrGeneral if the bitmap handle is NULL, KErrAccessDenied if the
bitmap is in ROM or it is an extended bitmap, otherwise one of the system wide error codes.
@param aScheme Specifies preferred compression type: ERLECompression or EPaletteCompression
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::CompressInBackground(TRequestStatus& aRequestStatus, TBitmapfileCompressionScheme aScheme)
	{
	TRequestStatus* reqStat = &aRequestStatus;
	aRequestStatus = KRequestPending;
	if (!iHandle)
		User::RequestComplete(reqStat, KErrGeneral);
	else if (iFlags & EIsReadOnlyBitmapMask)
		User::RequestComplete(reqStat, KErrAccessDenied);	
	else
		{
		TIpcArgs args(iHandle, aScheme, ETrue);
		iFbs->SendCommand(EFbsMessBitmapBgCompress, args, aRequestStatus);
		}
	}

/** Submits the bitmap for asynchronous background compression. No notification will be provided when the compression has completed.
@return KErrNone if the bitmap was successfully submitted to the background compression queue, KErrGeneral if the bitmap handle is NULL, 
KErrAccessDenied if the bitmap is in ROM or it is an extended bitmap, otherwise another of the system-wide error codes.
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::CompressInBackground(TBitmapfileCompressionScheme aScheme)
	{
	if (!iHandle)
		return KErrGeneral;
	if (iFlags & EIsReadOnlyBitmapMask)
		return KErrAccessDenied;	
	TIpcArgs args(iHandle, aScheme, EFalse);
	return iFbs->SendCommand(EFbsMessBitmapBgCompress, args);
	}

/**Tests whether the bitmap located in RAM has been compressed.
@return ETrue if the bitmap is compressed, EFalse otherwise.
@publishedAll
@released
*/	
EXPORT_C TBool CFbsBitmap::IsCompressedInRAM() const
	{
	CBitwiseBitmap* bitmap = CleanAddress();
	if (bitmap==NULL)
		{
			return EFalse;
		}	
	return bitmap->IsCompressedInRAM();
	}

/** Gets the twip-size of the bitmap.
@return The size of the bitmap, in twips. 
@publishedAll 
@released
*/
EXPORT_C TSize CFbsBitmap::SizeInTwips() const
	{
    TSize zero;
	if(iHandle==NULL) return(zero);
	return CleanAddress()->SizeInTwips();
	}

/** Converts a vertical dimension on the graphics device from pixels to twips.
@param aPixels A vertical dimension on the graphics device in pixels. 
@return A vertical dimension on the graphics device in twips. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::VerticalPixelsToTwips(TInt aPixels) const
	{
	if(iHandle==NULL) return(0);
	return CleanAddress()->VerticalPixelsToTwips(aPixels);
	}

/** Converts a vertical dimension on the graphics device from twips to pixels.
@param aTwips A vertical dimension on the graphics device in twips. 
@return A vertical dimension on the graphics device in pixels. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::VerticalTwipsToPixels(TInt aTwips) const
	{
	if(iHandle==NULL) return(0);
	return CleanAddress()->VerticalTwipsToPixels(aTwips);
	}

/** Tests whether or not the specified file is in ROM.
@param aFilename The name of the file. 
@param aWord On return, contains the address of the file in ROM. 
@return ETrue if the file is in the ROM; EFalse otherwise. 
@publishedAll 
@released
*/
EXPORT_C TBool CFbsBitmap::IsFileInRom(const TDesC& aFilename,TUint32*& aWord)
	{
	RFbsSession* fbs=RFbsSession::GetSession();
	__ASSERT_ALWAYS(fbs,Panic(EFbsPanicNoConnection));
	return fbs->LookupBitmapInROM (aFilename, (TAny*&)aWord);
	}

/** Tests whether or not the specified file is in ROM.
@param aFile The file handle
@param aWord On return, contains the address of the file in ROM. 
@return ETrue if the file is in the ROM; EFalse otherwise. 
@publishedAll 
@released
*/
EXPORT_C TBool CFbsBitmap::IsFileInRom(RFile& aFile,TUint32*& aWord)
	{
	// cannot use rom lookup cache as filename is not available
	// offset must be initialised to zero to indicate beginning of the file
	aWord = 0;
	return aFile.Seek(ESeekAddress,(TInt&)aWord)==KErrNone;
	}
	
/** Tests whether or not the bitmap is monochrome.
Monochrome bitmaps have a display-mode of 1 bit-per-pixel.
@return ETrue if the bitmap is monochrome; EFalse otherwise. 
@publishedAll 
@released
*/
EXPORT_C TBool CFbsBitmap::IsMonochrome() const
	{
	if(!iHandle) return(EFalse);
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);
	TBool isMonochrome = bmp->IsMonochrome(data);
	EndDataAccess(ETrue);
	return isMonochrome;
	}

/** Marks the beginning of direct access to the bitmap data.
This function prepares the bitmap for direct access to its pixel data
and should be used before calling DataAddress(), otherwise performance
may be degraded on certain platforms.
Calls to BeginDataAccess() must be coupled with subsequent calls to EndDataAccess().

@publishedAll
@released
@see CFbsBitmap::DataAddress()
@see CFbsBitmap::EndDataAccess()
*/
EXPORT_C void CFbsBitmap::BeginDataAccess() const
	{
	if (!iHandle)
		return;
	(void)CleanAddress();	//called for side-effect to make sure bitmap reference is current. Should be low overhead.
	const_cast<CFbsBitmap*>(this)->iUseCount++;
	}

/** Marks the end of direct access to the bitmap data.
Use this function after ending direct access to the bitmap data.
Calls to EndDataAccess() must correspond to prior calls to BeginDataAccess().
See BeginDataAccess() for more details.

@param aReadOnly Whether or not the bitmap data has only been read since
                 the corresponding call to BeginDataAccess().

@publishedAll
@released
@param aReadOnly True if the bitmap data had only been read.  False if the data has been modified.
@see CFbsBitmap::BeginDataAccess()
*/
EXPORT_C void CFbsBitmap::EndDataAccess(TBool aReadOnly) const
	{
	if (!iHandle)
		return;
	const_cast<CFbsBitmap*>(this)->iUseCount--;
	if (!aReadOnly && !(iFlags & EIsReadOnlyBitmapMask))
		User::LockedInc(iAddressPointer->Extra()->iTouchCount);
	}

/** Locks the global bitmap heap.
This function is deprecated, since it is no longer necessary to lock the global
bitmap heap to prevent the pixel data from being moved in memory asynchronously,
as the value returned by DataAddress() can now only change as a result of bitmap
operations explicitly requested by clients of the Font and Bitmap Server.
Calls to LockHeap() should be replaced by calls to BeginDataAccess().

Calls to LockHeap() must be coupled with subsequent calls to CFbsBitmap::UnlockHeap().
Code called between a LockHeap() - UnlockHeap() pair must not include any other calls to
CFbsBitmap methods, which internally may call CFbsBitmap::LockHeap(). Also, code must
not leave between a LockHeap() - UnlockHeap() pair.
@note	IMPORTANT: CFbsBitmap::LockHeap() cannot be used as a means of synchronization between
threads concurrently accessing bitmap data.

@publishedAll 
@deprecated
@see CFbsBitmap::UnlockHeap()
@see CFbsBitmap::BeginDataAccess()
*/
EXPORT_C void CFbsBitmap::LockHeap(TBool /*aAlways*/) const
	{
	BeginDataAccess();
#ifdef SYMBIAN_DEBUG_FBS_LOCKHEAP
	//These debug checks now refer to the cleaned data address
	if (!iHandle)
		return;
	if (!(iFlags & EIsRomBitmap)) // can't do anything with ROM bitmaps
		{
		TThreadId threadId = RThread().Id();
		iFbs->iHelper->iDebugMutex.Wait();
		if (iAddressPointer->Extra()->iLockCount++ == 0)
			{
			__ASSERT_ALWAYS(iAddressPointer->Extra()->iThreadId == TThreadId(KNullThreadId), Panic(EFbsPanicBadHeapLock));
			iAddressPointer->Extra()->iThreadId = threadId;
			}
		else
			__ASSERT_ALWAYS(iAddressPointer->Extra()->iThreadId == threadId, Panic(EFbsPanicBadHeapLock));
		iFbs->iHelper->iDebugMutex.Signal();
		}
#endif
	}

/** Unlocks the global heap. 
This function is deprecated. See LockHeap() for more details.
Calls to UnlockHeap() should be replaced by calls to EndDataAccess().
Calls to UnlockHeap() must correspond to prior calls to LockHeap() or LockHeapLC().

@publishedAll 
@deprecated
@see CFbsBitmap::LockHeap()
@see CFbsBitmap::EndDataAccess()
*/
EXPORT_C void CFbsBitmap::UnlockHeap(TBool /*aAlways*/) const
	{
#ifdef SYMBIAN_DEBUG_FBS_LOCKHEAP
	if (!iHandle)
		return;
	if (!(iFlags & EIsRomBitmap)) // can't do anything with ROM bitmaps
		{
		TThreadId threadId = RThread().Id();
		iFbs->iHelper->iDebugMutex.Wait();
		__ASSERT_ALWAYS(iAddressPointer->Extra()->iLockCount > 0, Panic(EFbsPanicBadHeapLock));
		__ASSERT_ALWAYS(iAddressPointer->Extra()->iThreadId == threadId, Panic(EFbsPanicBadHeapLock));
		if (--iAddressPointer->Extra()->iLockCount == 0)
			iAddressPointer->Extra()->iThreadId = TThreadId(KNullThreadId);
		iFbs->iHelper->iDebugMutex.Signal();
		}
#endif
	EndDataAccess();
	}

/** Locks the global bitmap heap, leaving on the clean-up stack a pointer
to a TCleanupItem that unlocks the heap on deletion.
Use this function instead of LockHeap() if code may leave between the
LockHeap() - UnlockHeap() pair. Calls to LockHeapLC() must be coupled with
subsequent calls to CFbsBitmap::UnlockHeap() or CleanupStack::PopAndDestroy().
This function is deprecated. See CFbsBitmap::LockHeap() for more details.

@publishedAll 
@deprecated
@see CFbsBitmap::LockHeap()
*/
EXPORT_C void CFbsBitmap::LockHeapLC(TBool /*aAlways*/) const
	{
	LockHeap();
	TCleanupItem cleanitem(CFbsBitmap::UnlockHeap, (TAny*)this);
	CleanupStack::PushL(cleanitem);
	}

EXPORT_C void CFbsBitmap::UnlockHeap(TAny* aFbsBitmap)
	{
	((CFbsBitmap*)aFbsBitmap)->UnlockHeap();
	}

/** Tests whether the bitmap is volatile.
A bitmap becomes volatile if CFbsBitmap::DataAdress() is called without
CFbsBitmap::BeginDataAccess() having been called before and it can become non-volatile
again if a resizing or compression is performed.

@internalTechnology
@prototype
*/
EXPORT_C TBool CFbsBitmap::IsVolatile() const
	{
	if (!iHandle)
		return EFalse;
	return CleanAddress()->iSettings.IsVolatileBitmap();
	}

/** Tests how many times the bitmap has been touched.
A bitmap is touched whenever CFbsBitmap::EndDataAccess() is called with the parameter
aReadOnly set to EFalse and also whenever a resizing or compression is performed.

@internalTechnology
@prototype
@return The number of times the bitmap has been touched.
*/
EXPORT_C TInt CFbsBitmap::TouchCount() const
	{
	if (!iHandle || (iFlags & EIsReadOnlyBitmapMask))
			return 0; // A read-only bitmap can never be touched.
	return CleanAddress()->Extra()->iTouchCount;
	}

/** Returns the serial number of the bitmap
The serial number is unique to this bitmap.
The serial number is a signed 64-bit integer, with only the positive values being assigned.
As ROM bitmaps do not have serial numbers, the serial number will use the negative range
of values so that ROM bitmap's serial number cannot be the same as a RAM bitmap's.
ROM bitmap's address pointers are unique to the ROM bitmap, so the serial number will just
be negative value of the address pointer.

@internalTechnology
@prototype
@return The unique serial number for the bitmap
*/
EXPORT_C TInt64 CFbsBitmap::SerialNumber() const
	{
	if (!iHandle)
		return 0;
	if (iFlags & EIsRomBitmap)
		return -TInt64(reinterpret_cast<TUint32>(iAddressPointer));
	return CleanAddress()->Extra()->iSerialNumber;
	}

/** Tests whether the bitmap is large.
@return ETrue if the bitmap is large, EFalse if not. 
@publishedAll 
@released
*/
EXPORT_C TBool CFbsBitmap::IsLargeBitmap() const
	{
	CBitwiseBitmap* bitmap = CleanAddress();
	if (!bitmap)
		{
		return EFalse;
		}
	return bitmap->IsLargeBitmap();
	}

/** Returns the handle for the hardware bitmap which this CFbsBitmap is using.
@return The handle to the hardware bitmap. The handle is NULL if it is not 
a hardware bitmap. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::HardwareBitmapHandle() const
	{
	CBitwiseBitmap* bitmap = CleanAddress();
	if (!bitmap)
		{
		return 0;
		}
	return bitmap->HardwareBitmapHandle();
	}

/** Gets the attributes of the bitmap's palette.
This is not currently supported.
@param aModifiable On return, whether or not the palette is modifiable. 
@param aNumEntries On return, the number of entries in the palette. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::PaletteAttributes(TBool& aModifiable,TInt& aNumEntries) const
	{
	aModifiable=EFalse;
	aNumEntries=0;
	}

/** Sets the bitmap's palette.
This is not currently supported.
@param aPalette Not used. 
@publishedAll 
@released
*/
EXPORT_C void CFbsBitmap::SetPalette(CPalette* /*aPalette*/)
	{
	}

/** Gets the bitmap's palette.
This is not currently supported.
@param aPalette Not used. 
@return KErrNotSupported. 
@publishedAll 
@released
*/
EXPORT_C TInt CFbsBitmap::GetPalette(CPalette*& /*aPalette*/) const
	{
	return(KErrNotSupported);
	}

/**
@internalComponent
This method loads a bitmap from an opened file handle.

@param  aFile mbm or rsc file handle (rsc file format: header + rsc
	data section + mbm file section).
@param  aId Bitmap ID - should be less than mbm file bitmaps count.
@param  aShareIfLoaded Specifies whether or not the loaded bitmap will be
    made available for sharing between FBSERV clients.
@param  aFileOffset mbm file section offset into rsc file.
@return KErrNone if successful, otherwise another
            of the system-wide error codes.
*/	
TInt CFbsBitmap::DoLoad(RFile& aFile,TInt32 aId,TBool aShareIfLoaded,TUint aFileOffset)
	{
	TInt ret=KErrNone;
	TPckgBuf<TBmpHandles> handlebuf;
	TPckgBuf<TLoadBitmapArg> loadBitmapArg;
	loadBitmapArg().iBitmapId = aId;
	loadBitmapArg().iShareIfLoaded = TInt(aShareIfLoaded);
	loadBitmapArg().iFileOffset = aFileOffset;
	//Getting the RFs Handle(2) and RFile handle(3) into a TIpcArgs into 2nd and 3rd argument
	TIpcArgs fileargs;
	ret=aFile.TransferToServer(fileargs,2,3);
	if (ret!=KErrNone)
		return ret;	
	fileargs.Set(0,&handlebuf);
	fileargs.Set(1,&loadBitmapArg);
	ret=iFbs->SendCommand(EFbsMessBitmapLoad,fileargs);
	if(ret!=KErrNone) return(ret);
	iHandle=handlebuf().iHandle;
	iServerHandle=handlebuf().iServerHandle;
	iAddressPointer=(CBitwiseBitmap*)(iFbs->HeapBase()+handlebuf().iAddressOffset);
	ret = iFbs->iHelper->AddBitmap(*this);
	if (ret != KErrNone)
		return ret;
	return iFbs->AllocScanLineBuffer(iAddressPointer->iByteWidth+4);
	}

/**
@internalComponent
This method loads a bitmap from the mbm or rsc file specified by the filename.

@param  aFileName mbm or rsc file name (rsc file format: header + rsc
	data section + mbm file section).
@param  aId Bitmap ID - should be less than mbm file bitmaps count.
@param  aShareIfLoaded Specifies whether or not the loaded bitmap will be
    made available for sharing between FBSERV clients.
@param  aFileOffset mbm file section offset into rsc file.
@return KErrNone if successful, otherwise another
            of the system-wide error codes.
*/
TInt CFbsBitmap::DoLoad(const TDesC& aFileName,TInt32 aId,TBool aShareIfLoaded,TUint aFileOffset)
	{
	TInt ret=KErrNone;
	TPckgBuf<TBmpHandles> handlebuf;
	TPckgBuf<TLoadBitmapArg> loadBitmapArg;
	loadBitmapArg().iBitmapId = aId;
	loadBitmapArg().iShareIfLoaded = TInt(aShareIfLoaded);
	loadBitmapArg().iFileOffset = aFileOffset;
	TIpcArgs fileargs;
	fileargs.Set(0,&handlebuf);
	fileargs.Set(1,&loadBitmapArg);
	fileargs.Set(2,&aFileName);
	ret=iFbs->SendCommand(EFbsMessBitmapLoadFast,fileargs);
	if(ret!=KErrNone) return(ret);
	iHandle=handlebuf().iHandle;
	iServerHandle=handlebuf().iServerHandle;
	iAddressPointer=(CBitwiseBitmap*)(iFbs->HeapBase()+handlebuf().iAddressOffset);
	ret = iFbs->iHelper->AddBitmap(*this);
	if (ret != KErrNone)
		return ret;
	return iFbs->AllocScanLineBuffer(iAddressPointer->iByteWidth+4);
	}

/**
@internalComponent
This method handles very special case when the rsc file is in RAM, but it 
contains ROM mbm file.  ROM mbm file format is different than RAM mbm file 
format and ROM mbm file cannot be loaded into RAM using standard techniques 
(used by CFbsBitmap::DoLoad()). We have to check it is really a ROM mbm file. 
If it is - we have to allocate the right amount of RAM, read and copy 
requested ROM bitmap to the allocated RAM.

@leave KErrNotSupported if this is a RAM rsc file with ROM mbm file section, 
	or any of the RFile related error codes.
@param aFileName rsc file name (rsc file format: header + rsc data section + 
	mbm file section).
@param  aId Bitmap ID - should be less than mbm file bitmaps count.
@param aFileOffset mbm file section offset into rsc file.
@return EFalse - this is not a ROM mbm file. ETrue - this is a ROM mbm file 
			and	requested by aId bitmmap is loaded.
*/	
TBool CFbsBitmap::LoadShiftedRomBmpL(const TDesC& aFileName, TInt32 aId, TUint aFileOffset)
	{
	RFile mbm_file;
	::CleanupClosePushL(mbm_file);
	User::LeaveIfError(mbm_file.Open(iFbs->FileServer(), aFileName, EFileRead | EFileShareReadersOnly));
	TInt pos = static_cast <TInt> (aFileOffset);
	User::LeaveIfError(mbm_file.Seek(ESeekStart, pos));//move to the beginning of the mbm file section
	TBuf8<sizeof(CBitwiseBitmap)> buf;
	//Check if it is a ROM mbm file
	User::LeaveIfError(mbm_file.Read(buf, sizeof(KMultiBitmapRomImageUid.iUid)));//Bitmap file UID - ROM or RAM
	TInt32 mbm_uid = *(reinterpret_cast <const TInt32*> (buf.Ptr())); 
	TBool loaded = EFalse;
	if(mbm_uid == KMultiBitmapRomImageUid.iUid)
		{
		if(!KRomMBMInRamRSC)
			{
			User::Leave(KErrNotSupported);
			}
		else
			{
			User::LeaveIfError(mbm_file.Read(buf, sizeof(TInt32)));//Number of bitmaps
			TInt32 bmp_cnt = *(reinterpret_cast <const TInt32*> (buf.Ptr()));  
			if(aId >= bmp_cnt) 
				{
				User::Leave(KErrNotFound);
				}
			for(TInt i=0;i<aId;i++) //Read bitmap UIDs located before aId.
				{
				User::LeaveIfError(mbm_file.Read(buf, sizeof(aId)));
				}
			User::LeaveIfError(mbm_file.Read(buf, sizeof(TInt32)));//Read the offset of aId bitmap.
			TInt bmp_offset = *(reinterpret_cast <const TInt32*> (buf.Ptr())) + TInt(aFileOffset); 
			pos = static_cast <TInt> (bmp_offset);
			User::LeaveIfError(mbm_file.Seek(ESeekStart, pos));//move the file pointer to the bitmap
			User::LeaveIfError(mbm_file.Read(buf, sizeof(CBitwiseBitmap)));//Read CBitwiseBitmap data (without the bitmap data)
			const CBitwiseBitmap* bmp = reinterpret_cast <const CBitwiseBitmap*> (buf.Ptr());
			//Calculate bitmap data size, alocate enough memory for the bitmap, copy CBitwiseBitmap
			//members first, read the bitmap data from the file, copy the data to the allocated memory,
			//initialize iRomPointer.
			//If sizeof(CBitwiseBitmap) != real size of CBitwiseBitmap then we could have problems,
			//because bitmap data won't be copied at the right position.
			TInt size = bmp->iHeader.iBitmapSize - sizeof(SEpocBitmapHeader) + sizeof(CBitwiseBitmap);
			TUint8* bmp_mem = new (ELeave) TUint8[size];
			//There is no need bmp_mem to be aligned, because it is a pointer to a RAM block of memory.
			TCleanupItem cleanitem(FreeMem, bmp_mem);
			CleanupStack::PushL(cleanitem);
			Mem::Copy(bmp_mem, bmp, sizeof(CBitwiseBitmap));
			TPtr8 pbmp(bmp_mem + sizeof(CBitwiseBitmap), size - sizeof(CBitwiseBitmap));
			User::LeaveIfError(mbm_file.Read(pbmp, size - sizeof(CBitwiseBitmap)));//read the bitmap data. We've already read the CBitwiseBitmap data.
			CleanupStack::Pop(bmp_mem);
			iAddressPointer = reinterpret_cast<CBitwiseBitmap*>(bmp_mem);
			iFlags = EIsRomBitmap;
			iHandle = 1;
			loaded = ETrue;
			}//end of - if(!KRomMBMInRamRSC) - "else" part
		}//end of - if(mbm_uid == KMultiBitmapRomImageUid.iUid)
	CleanupStack::PopAndDestroy();//mbm_file
	return loaded;
	}

/**
Swaps the bitmap's width and height.
For example, if the bitmap's size is (40, 20), the new size will be (20, 40).
Bitmap content is not preserved.
@publishedAll
@released
@return KErrNone if the call was successful, KErrGeneral if the bitmap handle is 
invalid, KErrAccessDenied if the bitmap is in ROM, KErrNotSupported if the bitmap
is a hardware bitmap or an extended bitmap.
*/
EXPORT_C TInt CFbsBitmap::SwapWidthAndHeight()
	{
	if(!iHandle) 
		{
		return KErrGeneral;
		}	
	TUint32* data;
	CBitwiseBitmap* bmp = BeginDataAccessAndGetCleanAddress(data);

	// Check the new bitmap size here then decide whether to swap the bitmap on the 
	// client side or send it to be done on the server and reallocate memory for it.
	TInt newWidthInBytes = CBitwiseBitmap::ByteWidth(bmp->iHeader.iSizeInPixels.iHeight, bmp->iSettings.CurrentDisplayMode());
	TInt64 hugeDataSize = TInt64(bmp->iHeader.iSizeInPixels.iWidth) * TInt64(newWidthInBytes);

	TInt err = KErrNone;
	// If the size of the new swapped bitmap is less than or equal its original size before the swap,
	// then we do not need to reallocate memory. The swapping is straight forward.
	if( I64HIGH(hugeDataSize) == 0 && I64LOW(hugeDataSize) <= TUint(bmp->iHeader.iBitmapSize - bmp->iHeader.iStructSize) )	
		{
		err = bmp->SwapWidthAndHeight(data);
		// Even though used DataAddress() as read-only, need to increment touch count, so indicate that data has been written
		EndDataAccess(EFalse);
		}
	// Otherwise we need to reallocate memory. We do this by using the already exisitng 
	// Resize() function as a work around- Code Reusability!!
	else
		{
		EndDataAccess(ETrue); // Used DataAddress() to read only.
		// Resize will increase touch counter
		err = Resize(TSize(bmp->iHeader.iSizeInPixels.iHeight, bmp->iHeader.iSizeInPixels.iWidth));
		}
	return err;
	}
	
/** Gets a pointer to the decompression buffer owned by this thread's FBServ session.
@param aSize The size in bytes of the scan lines to decompress.
@return A pointer to the decompression buffer or NULL if there is no FBServ session.
@internalTechnology
@released
*/
EXPORT_C HBufC8* CFbsBitmap::GetDecompressionBuffer(TInt aSize)
	{
		RFbsSession* ses=RFbsSession::GetSession();
		return ses? ses->GetDecompressionBuffer(aSize) : NULL;
	}

/** Gets a pointer to the rasterizer for extended bitmaps if present.
@return A pointer to the rasterizer owned by this thread's FBServ session.
@return NULL if the rasterizer is not present.
@internalTechnology
@prototype
*/
EXPORT_C CFbsRasterizer* CFbsBitmap::Rasterizer()
	{
	RFbsSession* session = RFbsSession::GetSession();
	return session ? session->iHelper->Rasterizer() : NULL;
	}

/** Loads a specific bitmap from an opened multi-bitmap file handle.
The bitmap may be shared by other font and bitmap server clients.
@param aFile The handle of the multi-bitmap (.mbm) file. 
@param aId The bitmap identifier.
@param aShareIfLoaded Specifies whether or not the loaded bitmap will be made 
available for sharing between font and bitmap server clients. 
@return KErrNone if successful, otherwise another of the system error 
codes. 
@publishedAll
@released
*/	
EXPORT_C TInt CFbsBitmap::Load(RFile& aFile,TInt32 aId/*=0*/,TBool aShareIfLoaded/*=ETrue*/)
	{
	return Load(aFile,aId,aShareIfLoaded,0);
	}

/** Loads a specific bitmap from an opened multi-bitmap file handle.
The bitmap may be shared by other font and bitmap server clients.
@param aFile The handle of the multi-bitmap (.mbm) file. 
@param aId The bitmap identifier.
@param aShareIfLoaded  Specifies whether or not the loaded bitmap will be made 
available for sharing between FBSERV clients.
@param aFileOffset Bitmap file section offset within the file.
@return KErrNone if successful, otherwise another of the system error codes.
@publishedAll
@released
*/	
EXPORT_C TInt CFbsBitmap::Load(RFile& aFile,TInt32 aId,TBool aShareIfLoaded,TUint aFileOffset)
	{
	if (!iFbs)
		{
		return(KErrCouldNotConnect);
		}
	Reset();
	TUint32* rompointer;
	IsFileInRom(aFile,rompointer);
	TBool romPointerValid;
	TInt err = DoLoadFromRom(rompointer, aId, aFileOffset, romPointerValid);
	if (!romPointerValid)
		{
		err = DoLoad(aFile,aId,aShareIfLoaded,aFileOffset);
		}
	return err;
	}

/** Loads and compresses a specific bitmap from an opened multi-bitmap file handle.
The bitmap may be shared by other font and bitmap server clients.
If the bitmap is loaded from ROM then compression is not allowed.
@param aFile The handle of the multi-bitmap (.mbm) file. 
@param aId The bitmap identifier.
@param aShareIfLoaded Specifies whether or not the loaded bitmap will be
made available for sharing between FBSERV clients.
@return KErrNone if successful, otherwise another of the system-wide error 
codes. 
@publishedAll 
@released
*/	
EXPORT_C TInt CFbsBitmap::LoadAndCompress(RFile& aFile,TInt32 aId/*=0*/,TBool aShareIfLoaded/*=ETrue*/)
	{
	return LoadAndCompress(aFile,aId,aShareIfLoaded,0);
	}

/** Loads and compresses a specific bitmap from an opened multi-bitmap file handle.
The bitmap may be shared by other font and bitmap server clients. If the 
bitmap is loaded from ROM then compression is not allowed.
@param aFile The handle of the multi-bitmap (.mbm) file. 
@param aId The bitmap identifier.
@param aShareIfLoaded Specifies whether or not the loaded bitmap will be made 
available for sharing between FBSERV clients.
@param aFileOffset Bitmap file section offset within the file.
@return KErrNone if successful, otherwise another of the system-wide error 
codes. 
@publishedAll 
@released
*/	
EXPORT_C TInt CFbsBitmap::LoadAndCompress(RFile& aFile,TInt32 aId,TBool aShareIfLoaded,TUint aFileOffset)
	{
	TInt err = Load(aFile,aId,aShareIfLoaded,aFileOffset);
	if (err == KErrNone)
		{
		err = !(iFlags & EIsRomBitmap) ? Compress() : KErrAccessDenied;
		}
	return err;
	}

/** Gets all the bitmap handles for all the bitmaps stored in the Font Bitmap Server. There is a limit of
the number of bitmaps that can be retrieved defined by KMaxBitmapHandleBufferSize. If this limit has been
reached then KErrOverflow will be returned.
@param aBitmapIdArray returns an array of all the bitmap handles
@return KErrNone if successful, KErrOverflow if the bitmapBuffer is not large enough to store 
all the bitmap handles, otherwise another of the system-wide error codes. 
@capability ReadDeviceData
@internalComponent
@released
*/	
EXPORT_C TInt CFbsBitmap::GetAllBitmapHandles(RArray<TInt>& aBitmapIdArray) const
	{
	RBuf8 bitmapBuffer;
	TInt ret = bitmapBuffer.Create(KMaxBitmapHandleBufferSize);
	if (ret==KErrNone)
		{
		TIpcArgs args(&bitmapBuffer);
		ret=iFbs->SendCommand(EFbsGetAllBitmapHandles, args);
		if (ret==KErrNone)
			{
			// Convert data returned from server and place into the RArray (aBitmapIdArray)
			aBitmapIdArray.Reset();
			TInt* bitmapIdPtr = (TInt*)bitmapBuffer.Ptr();
			const TInt numBitmapIds = bitmapBuffer.Size() / KNumBytesPerBitmapHandle; // Divide by number of bytes per bitmap handle to get total number of bitmap IDs
			for (TInt count=0; count<numBitmapIds; ++count)
				{
				TInt bitmapId = *bitmapIdPtr++;
				ret = aBitmapIdArray.Append(bitmapId);
				if (ret!=KErrNone)
					break;
				}
			}
		}
	bitmapBuffer.Close();
	return ret;
	}

/**
@internalComponent
This method tries to load a bitmap if mbm or rsc file is in ROM.

@param  aRomPointer the address of the file in ROM
@param  aId a Bitmap ID which should be less than mbm file bitmaps count.
@param  aFileOffset mbm file section offset into rsc file.
@param  aRomPointerValid on output it is set to ETrue if aRomPointer points to a valid ROM file or EFalse otherwise.
@return KErrNone if successful, otherwise another of the system-wide error codes.
*/
TInt CFbsBitmap::DoLoadFromRom(TUint32* aRomPointer, TInt32 aId, TUint aFileOffset, TBool& aRomPointerValid)
	{
	aRomPointerValid = ETrue;
	if(aRomPointer)
		{
		TUint8* temp = reinterpret_cast <TUint8*> (aRomPointer);
		__ASSERT_DEBUG(!(TUint(temp) & 0x00000003),Panic(EFbsBitmapAlignment));
		temp += aFileOffset;
		aRomPointer = reinterpret_cast <TUint32*> (temp);
		if(TInt32(*aRomPointer)==KMultiBitmapRomImageUid.iUid)
			{
			TInt numbitmaps = (TInt)*(aRomPointer+1);
			if(aId>=numbitmaps)
				{
				return(KErrEof);
				}
			TInt offset = *(aRomPointer+aId+2);
			iAddressPointer = (CBitwiseBitmap*)(((TUint8*)aRomPointer) + offset);
			iFlags = EIsRomBitmap;
			iHandle = 1;
			return iFbs->AllocScanLineBuffer(iAddressPointer->iByteWidth + 4);
			}
		}
	aRomPointerValid = EFalse;
	return KErrNone;
	}


/**
Creates an extended bitmap. Extended bitmaps are used to store immutable
data in a platform-specific format. They cannot be used as targets of
graphics contexts, and modification of their data via DataAddress() or
TBitmapUtil is not supported and results in undefined behaviour up to
and including process termination.

Initialisation of the raw data of the new bitmap is carried out by copying 
the data pointed to by the parameter aData.

Read-only access to the raw data of an extended bitmap is provided by
DataAddress() and DataSize() in conjunction with BeginDataAccess() and
EndDataAccess().

Extended bitmaps have a conceptual size in pixels and a conceptual
display mode for compatibility purposes. The raw data can be independent
of these properties.

@param aSizeInPixels The conceptual width and height of the new bitmap in pixels.
@param aDispMode The conceptual display mode of the new bitmap.
@param aType The UID identifying the data format of the new bitmap. Used by the
             extended bitmap rasterizer to distinguish between different data types.
@param aData A pointer to the raw data to be stored in the new bitmap.
@param aDataSize The size in bytes of the raw data to be stored in the new bitmap.
@return KErrNone if successful; KErrArgument if the width or height specified in
aSizeInPixels is negative, aDispMode is an invalid display mode, aData is NULL,
aDataSize is negative or zero, or aDataType is a UID reserved for OS use; KErrTooBig
if the width or height specified in aSizeInPixels exceeds KMaxTInt/4, or aDataSize
exceeds KMaxTInt/2; otherwise another of the system-wide error codes.
@publishedPartner
@prototype
@see CFbsBitmap::DataAddress()
@see CFbsBitmap::DataSize()
@see CFbsBitmap::BeginDataAccess()
@see CFbsBitmap::EndDataAccess()
*/
EXPORT_C TInt CFbsBitmap::CreateExtendedBitmap(const TSize& aSizeInPixels, TDisplayMode aDispMode, TUid aType, const TAny* aData, TInt aDataSize)
	{
	if (!aData || aDataSize == 0)
		{
		return KErrArgument;
		}
	TInt err = DoCreate(aSizeInPixels, aDispMode, aType, aDataSize);
	if (err == KErrNone)
		{
		Mem::Copy(iFbs->iLargeBitmapChunk.Base() + iAddressPointer->iDataOffset, aData, aDataSize);
		}
	return err;
	}

/**
Creates an extended bitmap. Extended bitmaps are used to store immutable
data in a platform-specific format. They cannot be used as targets of
graphics contexts, and modification of their data via DataAddress() or
TBitmapUtil is not supported and results in undefined behaviour up to
and including process termination.

Initialisation of the raw data of the new bitmap is carried out by a 
callback to the MFbsExtendedBitmapInitializer::InitExtendedBitmap() 
function passed through the parameter aInitializer.

Read-only access to the raw data of an extended bitmap is provided by
DataAddress() and DataSize() in conjunction with BeginDataAccess() and
EndDataAccess().

Extended bitmaps have a conceptual size in pixels and a conceptual
display mode for compatibility purposes. The raw data can be independent
of these properties.

@param aSizeInPixels The conceptual width and height of the new bitmap in pixels.
@param aDispMode The conceptual display mode of the new bitmap.
@param aType The UID identifying the data format of the new bitmap. Used by the
             extended bitmap rasterizer to distinguish between different data types.
@param aDataSize The size in bytes of the raw data to be stored in the new bitmap.
@param aInitializer A reference to the initializer of the raw data to be stored in the new bitmap.
@return KErrNone if successful; KErrArgument if the width or height specified in
aSizeInPixels is negative, aDispMode is an invalid display mode, aData is NULL,
aDataSize is negative or zero, or aDataType is a UID reserved for OS use; KErrTooBig
if the width or height specified in aSizeInPixels exceeds KMaxTInt/4, or aDataSize
exceeds KMaxTInt/2; otherwise another of the system-wide error codes.
@publishedPartner
@prototype
@see CFbsBitmap::DataAddress()
@see CFbsBitmap::DataSize()
@see CFbsBitmap::BeginDataAccess()
@see CFbsBitmap::EndDataAccess()
@see MFbsExtendedBitmapInitializer
*/
EXPORT_C TInt CFbsBitmap::CreateExtendedBitmap(const TSize& aSizeInPixels, TDisplayMode aDispMode, TUid aType, TInt aDataSize, MFbsExtendedBitmapInitializer& aInitializer)
	{
	if (aDataSize == 0)
		{
		return KErrArgument;
		}
	TInt err = DoCreate(aSizeInPixels, aDispMode, aType, aDataSize);
	if (err == KErrNone)
		{
		err = aInitializer.InitExtendedBitmap(iFbs->iLargeBitmapChunk.Base() + iAddressPointer->iDataOffset, aDataSize);
		if (err != KErrNone)
			{
			Reset();
			}
		}
	return err;
	}

/**
Gets the UID identifying the data format of an extended bitmap.
@return The UID identifying the data format of the bitmap or
        KNullUid if the bitmap is not an extended bitmap.
@publishedPartner
@prototype
*/
EXPORT_C TUid CFbsBitmap::ExtendedBitmapType() const
	{
	if (iHandle == 0)
		{
		return KNullUid;
		}
	TUid type = CleanAddress()->iUid;
	if (type.iUid == KCBitwiseBitmapUid.iUid || type.iUid == KCBitwiseBitmapHardwareUid.iUid)
		{
		return KNullUid;
		}
	return type;
	}

/**
Gets the size in bytes of the bitmap data.
@return The size in bytes of the bitmap data.
@publishedPartner
@prototype
*/
EXPORT_C TInt CFbsBitmap::DataSize() const
	{
	if (iHandle == 0)
		{
		return 0;
		}
	CBitwiseBitmap* bmp = CleanAddress();
	return bmp->iHeader.iBitmapSize - bmp->iHeader.iStructSize;
	}

/**
Gets a pointer to an extra buffer for general use owned by this thread's FBServ session.
@param aSize The size of the buffer in bytes
@return A pointer to the extra buffer if successful or NULL if there is no FBServ session
@internalTechnology
@released
*/
EXPORT_C HBufC8* CFbsBitmap::GetExtraBuffer(TInt aSize)
	{
		RFbsSession* ses=RFbsSession::GetSession();
		return ses? ses->GetExtraBuffer(aSize) : NULL;
	}
