// 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:
//

/**
 @file
 @internalComponent - Internal Symbian test code
*/

#include "TFBS.H"
#include "../sfbs/UTILS.H"
#include "../sfbs/fbshelper.h"
#include <shapeinfo.h>
#include <graphics/openfontrasterizer.h>
#include <graphics/openfontconstants.h>
#include "fbsdefs.h"
#include "fbsmessage.h"

TInt buffer[2];

_LIT(KFBSERVFontFileDir, "\\resource\\fonts\\");
_LIT(KTypefaceName, "DejaVu Sans Condensed");

// TLS Handle for TestFlushCallback test, from tfbsserver.mmp
const TInt KTlsHandle = 0x10273364;


#ifdef __WINS__
template<class C> XTCallCounter<C>::XTCallCounter(CTGraphicsBase& aTestBase)
	: iTestBase(aTestBase), iVFCallsOutsideFBServ(0)
	{}

template<class C> void XTCallCounter<C>::ExecuteShellcode(TInt aFromFunction)
	{
	const TUint32 KFBServId = 0x10003A16;
	const TUint32 KTFbsServerId = 0x10273364;
	TSecureId id = RProcess().SecureId();
	if (id != KFBServId)
		{
		User::LockedInc(iVFCallsOutsideFBServ);
		if (id == KTFbsServerId)
			{
			TBuf<128> name;
			XVtableInjector<C>::GetVirtualFunctionName(aFromFunction, name);
			iTestBase.INFO_PRINTF2(_L("Virtual function call to %S from outside FBServ"), &name);
			}
		}
	}
#endif


void CTFbs::DeleteScanLineBuffer()
	{
	delete iFbs->iScanLineBuffer;
	iFbs->iScanLineBuffer = 0;
	};

CTFbs::CTFbs(CTestStep* aStep):
	CTGraphicsBase(aStep),
	iHandle(0),
	iFbs(NULL),
	iTs(NULL),
	iHeap(NULL),
	iFs(NULL),
	iResourceCount(0),
	iAllocs(0)
#ifdef __WINS__
	, iFontCallCounter(*this), iOpenFontCallCounter(*this)
#endif
	{
	}

void CTFbs::ConstructL()
	{
	ExpandCleanupStackL();
	
	TestConstruction();
	AllocScanLineBuf();
	
	INFO_PRINTF1(_L("FBSERV testing"));
	}
	
CTFbs::~CTFbs()
	{
	delete iTs;
	}

void CTFbs::RunTestCaseL(TInt aCurTestCase)
	{
	((CTFbsStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
	switch(aCurTestCase)
		{
	case 1:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0555"));
		TestConnection();
		break;
	case 2:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0558"));
		TestInvalidFiles();
		break;
	case 3:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0556"));
		TestFlushCallBack();
		break;
	case 4:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0568"));
		TestMultiThread();
		break;
	case 5:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0559"));
		TestGetFont();
		break;
	case 6:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0560"));
		TestFontStore();
		break;
	case 7:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-PREQ807_1_Load_all_fonts-0001"));
		TestAllFontsLoaded();
		break;
	case 8:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0561"));
		TestFontNameAlias();
		break;
	case 9:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0557"));
		TestAddFontFile();
		break;
	case 10:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0562"));
		TestBufferedFont();
		break;
	case 11:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0563"));
		TestMultipleFont();
		break;
	case 12:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0564"));
		TestCreateBitmap();
		break;
	case 13:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0565"));
		TestLoadBitmap();
		break;
	case 14:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0566"));
		TestQueryBitmap();
		TRAPD(errCode, TestRomBitmapL());
		if(errCode==KErrNone)
			{
			TestHeapCompression();
			}
		break;
	case 15:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0570"));
		TestDefaultLanguageForMetrics();		
		break;
	case 16:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-CTFbs-TestDuplicateFontFileEntries-0001"));
		TestDuplicateFontFileEntries();
		break;
	//COMMENTED OUT FOR NOW BECAUSE DEF084095 FIX MAKES THIS TEST REDUNDANT
	/*case 17:
		TestShapeHeaderMemoryLeakAtClientDeath();
		break;*/
	case 17:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0506"));
		TestBitmapHandleImmutable();
		break;
	case 18:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0507"));
		TestBitmapBeginEnd();
		break;
	case 19:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0508"));
		TestSingletonServer();
		break;
	case 21:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0620"));
		TestFontSessionCacheLookupL();
		break;
	case 22:
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0650"));
		TestInvalidHandlesInIpcCallsL();
		break;
	case 23:
		// this one should always be the last test, since it checks the final virtual function call count
		((CTFbsStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0619"));
		TestNoVFCallsToGlobalObjects();
		break;
	case 24:
		((CTFbsStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
		((CTFbsStep*)iStep)->CloseTMSGraphicsStep();
		TestComplete();		
		break;
		}
	((CTFbsStep*)iStep)->RecordTestResultL();
	}

CFbsFontEx* CTFbs::SelectFont()
	{
	CFbsFontEx* font=NULL;
	TInt ret=iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KTypefaceName, 15));
	TEST(ret==KErrNone);
#ifdef __WINS__
	CBitmapFont* bitmapFont = font->Address();
	iFontCallCounter.iInjector.InjectShellcode(bitmapFont, &iFontCallCounter);
	if (bitmapFont->IsOpenFont())
		{
		iOpenFontCallCounter.iInjector.InjectShellcode(bitmapFont->OpenFont(), &iOpenFontCallCounter);
		}
#endif
	TEST(font->MaxCharWidthInPixels()>0);
	TEST(font->MaxNormalCharWidthInPixels()>0);
	return(font);
	}

CFbsFontEx* CTFbs::SelectOpenTypeFont()
	{
	CFbsFontEx* font=NULL;
	TFontSpec fsp;
	fsp.iTypeface.iName=_L("Series 60 Sans");
	fsp.iHeight=15;
	TInt ret=iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font,fsp);
	TEST(ret==KErrNone);
#ifdef __WINS__
	CBitmapFont* bitmapFont = font->Address();
	iFontCallCounter.iInjector.InjectShellcode(bitmapFont, &iFontCallCounter);
	if (bitmapFont->IsOpenFont())
		{
		iOpenFontCallCounter.iInjector.InjectShellcode(bitmapFont->OpenFont(), &iOpenFontCallCounter);
		}
#endif
	TEST(font->MaxCharWidthInPixels()>0);
	TEST(font->MaxNormalCharWidthInPixels()>0);
	return(font);
	}

void CTFbs::TestConstruction()
	{
	CFbsBitmap bmp;
	iTestBitmapName = KTestBitmapOnZ;
	TInt ret=bmp.Load(iTestBitmapName,ETfbs,NULL);
	if (ret != KErrNone)
		User::Panic(_L("Could not load bitmap"),ret);
	bmp.Reset();

	iFbs = RFbsSession::GetSession();
	TRAP(ret,iTs = (CFbsTypefaceStore*)CFbsTypefaceStore::NewL(NULL));
	TEST(iTs != NULL);
	CFbsFontEx* font = SelectFont();
	iTs->ReleaseFont(font);
	}
	
/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0555

	@SYMTestCaseDesc
	Tests the connections to the FbsSession

	@SYMTestActions
	Allocates a 100 RFbsSession objects and
	connects to the server and checks if
	all connections succeeded. Frees the memory
	and checks the heap memory.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestConnection()
	{
	INFO_PRINTF1(_L("class RFbsSession"));
	__UHEAP_MARK;
	const TInt numconnects=100;
	RFbsSession* connections=(RFbsSession*)User::Alloc(sizeof(RFbsSession)*numconnects);
	TEST(connections!=NULL);
	TInt count=0;
	for(;count<numconnects;count++)
		new(&connections[count]) RFbsSession;
	TEST(iFbs->ResourceCount()==0);
	for(count=0;count<numconnects;count++)
		{
		TInt ret=connections[count].Connect();
		if(ret!=KErrNone)
			break;
		}
	INFO_PRINTF2(_L("    %d connections created.\n"),count);
	TEST(iFbs->ResourceCount()==0);
	for(TInt count2=0;count2<count;count2++)
		connections[count2].Disconnect();
	TEST(iFbs->ResourceCount()==0);
	User::Free(connections);
	User::Heap().Check();
	__UHEAP_MARKEND;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0556

	@SYMTestCaseDesc
	Tests if the flush callback function
	is called properly.

	@SYMTestActions
	Sets the flush callback, fills the cache with different
	fonts until the cache is full.
	Create one more font which forces an eviction of a font
	in the cache.
	Check call back is called.
	Reset the flush callback, create another new font,
	check that the callback was not called.
	Check for memory and resource leaks.
	
	@SYMTestExpectedResults
	Callback function should be called once at end of loop.
*/
void CTFbs::TestFlushCallBack()
	{
	INFO_PRINTF1(_L("Test Flush CallBack"));

	__UHEAP_MARK;
	CFbsTypefaceStore* tfs=NULL;
	TRAPD(ret,tfs=CFbsTypefaceStore::NewL(NULL));
	TEST(ret==KErrNone);
	TEST(tfs!=NULL);

	UserSvr::DllSetTls(KTlsHandle, this);
	INFO_PRINTF1(_L("Testing Flush CallBack mechanism..."));
	iFbs->SetCallBack(TCallBack(FlushCallBack, NULL));
	CFbsFontEx* font=NULL;

	// Fill up the fontcache so that on the final iteration, the first 
	// font is evicted, thereby destroying it server-side and executing the 
	// callback.
	iFlushCallbackReceived = EFalse;
	TInt fontSize = 10;
	for (TInt fontEntries = 0; fontEntries < KMaxFontCacheEntries+1; fontEntries++)
		{
		ret=tfs->GetNearestFontToDesignHeightInTwips((CFont*&)font, TFontSpec(KTypefaceName, fontSize));
		TEST(ret==KErrNone);
		iResourceCount++;
		CheckResourceCount();
		tfs->ReleaseFont(font);
		fontSize += 15;
		}
	TEST(iFlushCallbackReceived);

	// Now check callback is correctly reset and callback function is not executed
	// when another font is evicted from the cache.
	// Resource count wont increase as although a new font is being created, another
	// will be evicted from the cache.
	iFlushCallbackReceived = EFalse;
	iFbs->ResetCallBack();
	ret=tfs->GetNearestFontToDesignHeightInTwips((CFont*&)font, TFontSpec(KTypefaceName, fontSize));
	TEST(ret==KErrNone);
	tfs->ReleaseFont(font);
	TEST(!iFlushCallbackReceived);
	CheckResourceCount();

	UserSvr::DllFreeTls(KTlsHandle);
	delete tfs;
	iResourceCount = 0;
	CheckResourceCount();
	__UHEAP_MARKEND;
	}

TInt CTFbs::FlushCallBack(TAny* /*aPtr*/)
	{
	CTFbs* tfbs = static_cast<CTFbs*>(UserSvr::DllTls(KTlsHandle));
	tfbs->INFO_PRINTF1(_L("    ...Flush CallBack called successfully"));
	tfbs->iFlushCallbackReceived = ETrue;
	--tfbs->iResourceCount;
	return(0);
	}


#ifdef __WINS__
_LIT(KCTFbsTestFont,"z:\\resource\\fonts\\eon14.gdr");
#else
_LIT(KCTFbsTestFont,"z:\\resource\\fonts\\eon.gdr");
#endif

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0557

	@SYMTestCaseDesc
	Tests adding of a font file
	to the font store

	@SYMTestActions
	Creates a type face store and adds
	font files to it. Checks if adding
	the files succeeded. Removes the files
	from the store. Checks if succeeded.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestAddFontFile()
	{
	INFO_PRINTF1(_L("Test Add File"));
	__UHEAP_MARK;
	CFbsTypefaceStore* tfs=NULL;
	TRAPD(ret,tfs=CFbsTypefaceStore::NewL(NULL));
	TEST(ret==KErrNone);
	TEST(tfs!=NULL);
	TInt id1=0;
	TInt id2=0;
	TInt id3=0;
	TInt id4=0;
	ret=tfs->AddFile(KCTFbsTestFont,id1);
	TEST(ret==KErrNone);
	TEST(id1!=0);
	ret=tfs->AddFile(KCTFbsTestFont,id2);
	TEST(ret==KErrNone);
	TEST(id2==id1);
	ret=tfs->AddFile(KCTFbsTestFont,id3);
	TEST(ret==KErrNone);
	TEST(id3==id2);
	tfs->RemoveFile(id1);
	tfs->RemoveFile(id2);
	tfs->RemoveFile(id3);
	ret=tfs->AddFile(KCTFbsTestFont,id4);
	TEST(ret==KErrNone);
	TEST(id4==id1);
	tfs->RemoveFile(id4);
	delete tfs;
	__UHEAP_MARKEND;
	
	//test the sequence AddFile, GetNearestFont, ReleaseFont, RemoveFile
	CFbsTypefaceStore* tfs1=NULL;
    TRAPD(ret1,tfs1=CFbsTypefaceStore::NewL(NULL));
    TEST(ret1==KErrNone);
    TEST(tfs1!=NULL);
    TInt id5=0;
    ret1=tfs1->AddFile(_L("z:\\resource\\fonts\\DejaVuSerifCondensed.ttf"),id5);
    TEST(ret1==KErrNone);
    TEST(id5!=0);
    
    TInt id6=0;
    ret1=tfs1->AddFile(_L("z:\\resource\\fonts\\DejaVuSansCondensed.ttf"), id6);
    TEST(ret1==KErrNone);
    TEST(id6!=0);    
    
    TFontSpec fsp1;
    fsp1.iTypeface.iName=_L("DejaVu Serif Condensed");
    fsp1.iHeight=15;
    CFont* font1;
    ret1=tfs1->GetNearestFontToDesignHeightInTwips((CFont*&)font1,fsp1);
    TEST(ret1==KErrNone);
    
    TFontSpec fsp2;
    fsp2.iTypeface.iName=_L("DejaVu Serif Condensed");
    fsp2.iHeight=30;
    CFont *font2;
    ret1=tfs1->GetNearestFontToDesignHeightInTwips((CFont*&)font2,fsp2);
    TEST(ret1==KErrNone);

    TFontSpec fsp3;
    fsp3.iTypeface.iName=_L("DejaVu Sans Condensed");
    fsp3.iHeight=20;
    CFont *font3;
    ret1=tfs1->GetNearestFontToDesignHeightInTwips((CFont*&)font3,fsp3);
    TEST(ret1==KErrNone);

    TFontSpec fsp4;
    fsp4.iTypeface.iName=_L("DejaVu Serif Condensed");
    fsp4.iHeight=35;
    CFont *font4;
    ret1=tfs1->GetNearestFontToDesignHeightInTwips((CFont*&)font4,fsp4);
    TEST(ret1==KErrNone);
    
    if (font1)
        tfs1->ReleaseFont(font1);
    if (font2)
        tfs1->ReleaseFont(font2);
    if (font4)
        tfs1->ReleaseFont(font4);
 
    if (id6)
        tfs1->RemoveFile(id6);
    if (id5)
        tfs1->RemoveFile(id5);
    delete tfs1;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0558

	@SYMTestCaseDesc
	Tries to add and load a nonexisting 
	file to the FbsTypeFaceStore and checks
	if it fails.
	
	@SYMTestActions
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestInvalidFiles()
	{
	INFO_PRINTF1(_L("Test Invalid Files"));
	__UHEAP_MARK;
	CFbsTypefaceStore* tfs=NULL;
	TRAPD(ret,tfs=CFbsTypefaceStore::NewL(NULL));
	TEST(ret==KErrNone);
	TEST(tfs!=NULL);
	TInt id=0;
	ret=tfs->AddFile(_L("\\nonexist.gdr"),id);
	TEST(ret!=KErrNone);
	delete tfs;
	CFbsBitmapEx bmp;
	ret=bmp.Load(_L("\\nonexist.mbm"),0);
	TEST(ret!=KErrNone);
	User::Heap().Check();
	__UHEAP_MARKEND;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0559

	@SYMTestCaseDesc
	Gets a font and tests all its properties. 

	@SYMTestActions
	Tests the char width, text width, handles, verifies
	the resource count and the heap for memory leaks
	CharWidthInPixels() and TextWidthInPixels() may return 
	different values depending on the hardware used.
	Therefore, when comparing these values for the same character,
	allow a margin of 1 pixel difference.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestGetFont()
	{
	INFO_PRINTF1(_L("Test Get Font"));
	CFbsFontEx* font=SelectFont();
	iResourceCount++;
	TEST(font->Handle()!=0);
	CheckResourceCount();
	TUid uid;
	uid=KCFbsFontUid;
	TEST(font->TypeUid()==uid);
	TInt w=font->TextWidthInPixels(_L(" "));
	TEST(w>0);
	// Now test the same use case with context
	CFont::TMeasureTextInput param;
	param.iStartInputChar = 34;
	TInt wContext=font->TextWidthInPixels(_L("->This text will not be measured<- "),&param);
	TEST(wContext==w);
	// End of first use case with context
		
	TInt x=font->TextCount(_L("          "),10);
	TEST(10/w==x);
	TInt y,z;
	y=font->TextCount(_L("   "),10,z);
	TEST(y==x);
	TInt cwidth=font->CharWidthInPixels('i');
	TInt twidth=font->TextWidthInPixels(_L("i"));
	TInt charTextdiff = cwidth - twidth;
	TEST(1>=charTextdiff && -1<=charTextdiff);
	TInt twidthContext=font->TextWidthInPixels(_L("->This text will not be measured<-i"),&param);
	TEST(twidth==twidthContext);
	cwidth=font->CharWidthInPixels('p');
	twidth=font->TextWidthInPixels(_L("p"));
	charTextdiff = cwidth - twidth;
	TEST(1>=charTextdiff && -1<=charTextdiff);
	twidthContext=font->TextWidthInPixels(_L("->This text will not be measured<-p"),&param);
	TEST(twidth==twidthContext);
	cwidth=font->CharWidthInPixels('W');
	twidth=font->TextWidthInPixels(_L("W"));
	charTextdiff = cwidth - twidth;
	TEST(1>=charTextdiff && -1<=charTextdiff);
	twidthContext=font->TextWidthInPixels(_L("->This text will not be measured<-W"),&param);
	TEST(twidth==twidthContext);
	cwidth=font->CharWidthInPixels(' ');
	twidth=font->TextWidthInPixels(_L(" "));
	charTextdiff = cwidth - twidth;
	TEST(1>=charTextdiff && -1<=charTextdiff);
	SCharWidth chwid;
	font->TextWidthInPixels(_L(" "),chwid);
	TEST(chwid.iMove==w);
	TEST(chwid.iWidth+chwid.iLeftAdjust+chwid.iRightAdjust==chwid.iMove);
	font->TextWidthInPixels(_L("->This text will not be measured<- "),&param,chwid);
	TEST(chwid.iMove==w);
	TEST(chwid.iWidth+chwid.iLeftAdjust+chwid.iRightAdjust==chwid.iMove);

	// Now do all these tests with an OpenType font where the width with context is different from the
	// width without context
	// NOTE:	These tests are performed for WINS and WINSCW only because we are using a TrueType font, and the bounds of 
	// 			the text returned is different for different hardware devices, including different h4's	and hence 
	//			cannot be measured.
	#if defined __WINS__ || defined __WINSCW__
	CFbsFontEx* openFont = SelectOpenTypeFont();
	iResourceCount++;
	TEST(font->Handle()!=0);
	CheckResourceCount();
	uid=KCFbsFontUid;
	TEST(font->TypeUid()==uid);
	cwidth=openFont->CharWidthInPixels('.');
	twidth=openFont->TextWidthInPixels(_L("."));
	charTextdiff = cwidth - twidth;
	TEST(1>=charTextdiff && -1<=charTextdiff);
	param.iStartInputChar = 1;
	twidthContext=openFont->TextWidthInPixels(_L("\x0915."),&param);
	TEST(twidth!=twidthContext);
	cwidth=openFont->CharWidthInPixels(',');
	twidth=openFont->TextWidthInPixels(_L(","));
	charTextdiff = cwidth - twidth;
	TEST(1>=charTextdiff && -1<=charTextdiff);
	twidthContext=openFont->TextWidthInPixels(_L("\x0915,"),&param);
	TEST(cwidth!=twidthContext);
	TEST(twidth!=twidthContext);
	openFont->TextWidthInPixels(_L("\x0915."),&param,chwid);
	TEST(chwid.iMove!=cwidth);
	#endif

	CFbsFontEx* font2=SelectFont(); // Don't increment iResourceCount as the font is already in the cache
	CheckResourceCount();
	iTs->ReleaseFont(font2);
	RFbsSession* fbsalt=RFbsSession::GetSession();
	CFbsFontEx* font3=new CFbsFontEx;
	font3->Duplicate(font->Handle());
	iResourceCount++;
	TEST(font3->Handle());
	CheckResourceCount();
	TEST(fbsalt->ResourceCount()==iResourceCount);
	iTs->ReleaseFont(font);
	iResourceCount--;
	TEST(w==font3->TextWidthInPixels(_L(" ")));
	CheckResourceCount();
	TEST(fbsalt->ResourceCount()==iResourceCount);
	font3->Reset();
	User::Free(font3);
	iResourceCount--;
	CheckResourceCount();
	TEST(fbsalt->ResourceCount()==iResourceCount);
	User::Heap().Check();
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0560

	@SYMTestCaseDesc
	Tests the font store.

	@SYMTestActions
	Allocates an array of pointers which is
	used to store the font height. It tests
	the font height and gets the nearest font
	available. The heap is checked for 
	memory leaks.	
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestFontStore()
	{
	INFO_PRINTF1(_L("Test Font Store"));
	CFbsFontEx* font=NULL;
	TFontSpec fs;
	TInt typefaces=iTs->NumTypefaces();
	TTypefaceSupport info;
	for(TInt count=0;count<typefaces;count++)
		{
		iTs->TypefaceSupport(info,count);
		INFO_PRINTF1(_L("    "));
	    TBuf<KMaxTypefaceNameLength> tname;
		tname.Copy(info.iTypeface.iName);
		INFO_PRINTF1(tname);
		INFO_PRINTF1(_L("\n"));
		TInt* heightarray=(TInt*)User::Alloc(info.iNumHeights*sizeof(TInt));
		TInt index=0;
		for(;index<info.iNumHeights;index++)
			heightarray[index]=iTs->FontHeightInTwips(count,index);
		for(index=1;index<info.iNumHeights;index++)
			TEST(heightarray[index]>heightarray[index-1]);
		for(index=0;index<info.iNumHeights;index++)
			heightarray[index]=iTs->FontHeightInPixels(count,index);
		for(index=1;index<info.iNumHeights;index++)
			TEST(heightarray[index]>=heightarray[index-1]);
		delete [] heightarray;
		for(index=0;index<info.iNumHeights;index++)
			{
			TInt height=iTs->FontHeightInTwips(count,index);
			fs.iTypeface=info.iTypeface;
			fs.iHeight=height;
			TInt ret=iTs->GetNearestFontToDesignHeightInTwips((CFont*&)font,fs);
			TEST(ret==KErrNone);
			TEST(font->Handle());
			iTs->ReleaseFont(font);

			height=iTs->FontHeightInPixels(count,index);
			fs.iTypeface=info.iTypeface;
			fs.iHeight=height;
			ret=iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font,fs);
			TEST(ret==KErrNone);
			TEST(font->Handle());
			iTs->ReleaseFont(font);
			}
		}
	iResourceCount = iFbs->ResourceCount(); // Allow for fonts left in the typeface store cache
	User::Heap().Check();
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0561

	@SYMTestCaseDesc
	Tests the font name alias

	@SYMTestActions
	Creates three different font name alias with a 
	mixture of caps and small letters. Checks the font
	name aliases using the different names.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestFontNameAlias()
	{
	INFO_PRINTF1(_L("Test Font Name Alias"));

	TInt size = 20;
	_LIT(KFontAlias0,"Font alias 0");
	_LIT(KFontAlias1,"Font alias 1");
	_LIT(KFontAlias2,"FOnT AlIaS 0");//Alias name in mixture of caps & small letters for KFontAlias0

    TBuf<KMaxTypefaceNameLength> defaultName;
    TBuf<KMaxTypefaceNameLength> fontName[3];

	CFbsFontEx* font = NULL;
	TFontSpec fs(KNullDesC,200);
	TInt ret = iTs->GetNearestFontToDesignHeightInTwips((CFont*&)font,fs);
	TEST(ret == KErrNone);
	TEST(font->Handle());
	fs = font->FontSpecInTwips();
	defaultName = fs.iTypeface.iName;
	iTs->ReleaseFont(font);

	TTypefaceSupport info;
	for (TInt index = 0, nameIndex = 0; nameIndex < 3; index++)
		{
		iTs->TypefaceSupport(info,index);
		if (info.iTypeface.iName != defaultName)
			fontName[nameIndex++] = info.iTypeface.iName;
		}

	TRAP(ret,iTs->SetFontNameAliasL(KFontAlias0,fontName[0]));
	TEST(ret == KErrNone);
	CheckFontNameAlias(KFontAlias0,fontName[0],size);
	//Testing if it works even if the alias name passed differs in case
	CheckFontNameAlias(KFontAlias2,fontName[0],size);

	TRAP(ret,iTs->SetFontNameAliasL(KFontAlias1,fontName[1]));
	TEST(ret == KErrNone);
	CheckFontNameAlias(KFontAlias0,fontName[0],size);
	CheckFontNameAlias(KFontAlias1,fontName[1],size);

	TRAP(ret,iTs->SetFontNameAliasL(KFontAlias0,fontName[2]));
	TEST(ret == KErrNone);
	CheckFontNameAlias(KFontAlias0,fontName[2],size);
	CheckFontNameAlias(KFontAlias1,fontName[1],size);

	TRAP(ret,iTs->SetFontNameAliasL(KFontAlias1,KNullDesC));
	TEST(ret == KErrNone);
	CheckFontNameAlias(KFontAlias0,fontName[2],size);
	CheckFontNameAlias(KFontAlias1,defaultName,size);

	TRAP(ret,iTs->SetFontNameAliasL(KFontAlias0,KNullDesC));
	TEST(ret == KErrNone);
	CheckFontNameAlias(KFontAlias0,defaultName,size);
	CheckFontNameAlias(KFontAlias1,defaultName,size);
	iResourceCount--; // Allow for a cache eviction because the last check fills the cache

	CheckResourceCount();
	User::Heap().Check();
	}

void CTFbs::CheckFontNameAlias(const TDesC& aFontAlias, const TDesC& aFontName, TInt& aSize)
	{
	CFbsFontEx* font = NULL;
	TFontSpec fs(aFontAlias,aSize);
	aSize += 20;

	TInt ret = iTs->GetNearestFontToDesignHeightInTwips((CFont*&)font,fs);
	TEST(ret == KErrNone);
	TEST(font->Handle());

	TFontSpec checkFS = font->FontSpecInTwips();
	TEST(checkFS.iTypeface.iName == aFontName);

	iTs->ReleaseFont(font);
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0562

	@SYMTestCaseDesc
	Tests the width of a font stored in a buffer
	
	@SYMTestActions
	Gets how much of the specified descriptor can be 
	displayed for a specified font without 
	exceeding the specified width.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestBufferedFont()
	{
	INFO_PRINTF1(_L("Test Buffered Font"));
	CFbsFontEx* font=SelectFont();
	TBuf<1280> largebuf;
	TInt count=0;
	for(;count<1280;count++)
		largebuf.Append(32);
	TInt width,lcount,rcount,lwidth,rwidth;
	width=font->TextWidthInPixels(largebuf);
	for(count=0;count<1280;count+=500)
		{
		lcount=font->TextCount(largebuf.Left(count),100000);
		TEST(lcount==count);
		rcount=font->TextCount(largebuf.Right(1280-count),100000);
		TEST(rcount==1280-count);
		lwidth=font->TextWidthInPixels(largebuf.Left(count));
		rwidth=font->TextWidthInPixels(largebuf.Right(1280-count));
		TEST(rwidth+lwidth==width);
		}
	iTs->ReleaseFont(font);
	CheckResourceCount();
	User::Heap().Check();
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0563

	@SYMTestCaseDesc
	Tests having multiple fonts allocated
	and deallocated

	@SYMTestActions
	Gets multiple font. Releases the hold of a 
	typeface store client on a specified font.
	Decrements the access-count for the specified 
	font by one. If this reduces the access-count 
	to zero then the font is no longer needed by any 
	client, and is deleted from the typeface store list.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestMultipleFont()
	{
	INFO_PRINTF1(_L("Test Multiple Font"));
	const TInt numfonts=100;
	CFbsFontEx* fonts[numfonts];
	TInt count=0;
	for(;count<numfonts;count++)
		fonts[count]=SelectFont();
	for(count=0;count<numfonts;count++)
		iTs->ReleaseFont(fonts[count]);
	INFO_PRINTF2(_L("    %d font handles created.\n"),numfonts);
	CheckResourceCount();
	User::Heap().Check();
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0564

	@SYMTestCaseDesc
	Tests creation of unique bitmaps with
	no handles already to them. Also tests
	and verifies defects DEF069571 and DEF076347.
	
	@SYMDEF DEF069571 DEF076347
	
	@SYMTestActions
	Test creation of original bitmaps. Destroys 
	existing bitmap and creates a new one. Tests
	creation of bitmap by duplicating an already
	existing bitmap. Tests creation of different 
	sized bitmaps and resizes them.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestCreateBitmap()
	{
	INFO_PRINTF1(_L("Test Create Bitmap"));
	__UHEAP_MARK;

	CFbsBitmapEx bmp1;
	CFbsBitmapEx bmp2;

	// Test creation of original bitmaps (ie handles are unique)
	TInt ret=bmp1.Create(TSize(0,0),EGray2);
	TEST(ret==KErrNone);
	iResourceCount++;
	CheckResourceCount();

	ret=bmp2.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	iResourceCount++;
	TEST(bmp2.Handle()!=bmp1.Handle());
	CheckResourceCount();

	ret=bmp2.Create(TSize(0,0),EGray2); // Destroys existing and creates new
	TEST(ret==KErrNone);
	TEST(bmp2.Handle()!=bmp1.Handle());
	CheckResourceCount();
	bmp2.Reset();
	iResourceCount--;
	CheckResourceCount();

	// Test creation by duplication
	RFbsSession* fbsalt=RFbsSession::GetSession();
	CFbsBitmapEx bmp3;

	ret=bmp3.Duplicate(bmp1.Handle());
	TEST(ret==KErrNone);
	iResourceCount++;
	CheckResourceCount();
	TEST(fbsalt->ResourceCount()==iResourceCount);
	TEST((TInt)bmp1.BitmapAddress());
	CBitwiseBitmap* bmp3add=bmp3.BitmapAddress();
	CBitwiseBitmap* bmp1add=bmp1.BitmapAddress();
	TEST(bmp3add==bmp1add);
	TEST(bmp3.Handle()==bmp1.Handle());
	bmp3.Reset();
	iResourceCount--;
	CheckResourceCount();
	TEST(fbsalt->ResourceCount()==iResourceCount);
	bmp1.Reset();
	iResourceCount--;
	CheckResourceCount();
	TEST(fbsalt->ResourceCount()==iResourceCount);
	
	//Testing the DEF069571
	
	CFbsBitmapEx bmp0;
	//Test creation of large bitmaps (>65536)
	TInt ret0=bmp0.Create(TSize(65536,1),EGray256);
	bmp0.Reset();
	
	//Testcode for DEF076347
	CFbsBitmapEx bmp01;
	TInt ret01=bmp01.Create(TSize(65536,1),EColor16MU);
	TInt ret02=bmp01.SetDisplayMode(EColor16MA);
	bmp01.Reset();
	
	

	// Test creation of different sizes and resizing them
	DoResizeBitmap(EGray2);
	DoResizeBitmap(EGray4);
	DoResizeBitmap(EGray16);
	DoResizeBitmap(EGray256);
	DoResizeBitmap(EColor16);
	DoResizeBitmap(EColor256);
	DoResizeBitmap(EColor4K);
	DoResizeBitmap(EColor64K);
	DoResizeBitmap(EColor16M);

	User::Heap().Check();
	__UHEAP_MARKEND;
	}

void CTFbs::DoResizeBitmap(TDisplayMode aDispMode)
	{
	const TInt numNewSizes = 5;
	const TSize newSizes[numNewSizes] = { TSize(0,0), TSize(1,1), TSize(17,20), TSize(32,32), TSize(32,1025) };
	const TInt numTwipsSizes = 4;
	const TSize twipsSizes[numTwipsSizes] = { TSize(100,100), TSize(1440,1440), TSize(1000000,1000000), TSize(0,0) };

	__UHEAP_MARK;

	CFbsBitmapEx bmp;

	TInt count;
	for(count = 0; count < numNewSizes; count++)
		{
		TSize size = newSizes[count];
		TInt ret = bmp.Create(size,aDispMode);
		TEST(ret == KErrNone);
		TEST(bmp.Handle() != 0);
		TEST(bmp.SizeInPixels() == size);
		TEST(bmp.DisplayMode() == aDispMode);
		}

	for(count = 0; count < numNewSizes; count++)
		{
		TInt ret = bmp.Create(TSize(0,0),aDispMode);
		TSize size = newSizes[count];
		ret = bmp.Resize(size);
		TEST(ret == KErrNone);
		TEST(bmp.SizeInPixels() == size);
		}

	for(count = 0; count < numTwipsSizes; count++)
		{
		TSize size = twipsSizes[count];
		bmp.SetSizeInTwips(size);
		TEST(bmp.SizeInTwips() == size);
		}

	bmp.Reset();
	CheckResourceCount();

	User::Heap().Check();
	DeleteScanLineBuffer();
	__UHEAP_MARKEND;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0565

	@SYMTestCaseDesc
	Tests loading of bitmaps

	@SYMTestActions
	Loads a specific bitmap from a multi-bitmap 
	file. Retrieves the bitmap addresses for the
	bitmap and check if they are valid.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestLoadBitmap()
	{
	INFO_PRINTF1(_L("Test Load Bitmap"));
	__UHEAP_MARK;
	CFbsBitmapEx bmp1;
	CFbsBitmapEx bmp2;
	CFbsBitmapEx bmp3;
	CFbsBitmapEx bmp4;
	CFbsBitmapEx bmp5;
	TInt ret=bmp1.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	iResourceCount++;
	TEST(bmp1.Handle()!=0);
	ret=bmp2.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	iResourceCount++;
	CBitwiseBitmap* bmp1add=bmp1.BitmapAddress();
	TEST((TInt)bmp1add);
	CBitwiseBitmap* bmp2add=bmp2.BitmapAddress();
	TEST(bmp1add==bmp2add);
	TEST(bmp1.Handle()==bmp2.Handle());
	ret=bmp3.Load(iTestBitmapName,ETblank);
	TEST(ret==KErrNone);
	iResourceCount++;
	TEST(bmp1.Handle()!=bmp3.Handle());
	bmp2.Reset();
	iResourceCount--;
	ret=bmp4.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	iResourceCount++;
	CBitwiseBitmap* bmp4add=bmp4.BitmapAddress();
	TEST(bmp1add==bmp4add);
	TEST(bmp4.Handle()==bmp1.Handle());
	ret=bmp5.Load(iTestBitmapName,ETblank);
	TEST(ret==KErrNone);
	iResourceCount++;
	CBitwiseBitmap* bmp3add=bmp3.BitmapAddress();
	CBitwiseBitmap* bmp5add=bmp5.BitmapAddress();
	TEST((TInt)bmp3add);
	TEST(bmp3add==bmp5add);
	TEST(bmp5.Handle()==bmp3.Handle());
	CheckResourceCount();
	bmp3.Reset();
	iResourceCount--;
	bmp4.Reset();
	iResourceCount--;
	bmp5.Reset();
	iResourceCount--;
	ret=bmp2.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	iResourceCount++;
	bmp2add=bmp2.BitmapAddress();
	TEST(bmp1add==bmp2add);
	TEST(bmp1.Handle()==bmp2.Handle());
	CheckResourceCount();
	bmp1.Reset();
	iResourceCount--;
	bmp2.Reset();
	iResourceCount--;
	CheckResourceCount();

	ret=bmp1.Load(iTestBitmapName,ETfbs,EFalse);
	TEST(ret==KErrNone);
	ret=bmp2.Load(iTestBitmapName,ETfbs,ETrue);
	TEST(ret==KErrNone);
	ret=bmp3.Load(iTestBitmapName,ETfbs,ETrue);
	TEST(ret==KErrNone);
	ret=bmp4.Load(iTestBitmapName,ETfbs,EFalse);
	TEST(ret==KErrNone);
	ret=bmp5.Load(iTestBitmapName,ETfbs,ETrue);
	TEST(ret==KErrNone);
	bmp1add=bmp1.BitmapAddress();
	bmp2add=bmp2.BitmapAddress();
	bmp3add=bmp3.BitmapAddress();
	bmp4add=bmp4.BitmapAddress();
	bmp5add=bmp5.BitmapAddress();
	TEST(bmp1add!=bmp2add);
	TEST(bmp1add!=bmp3add);
	TEST(bmp1add!=bmp4add);
	TEST(bmp1add!=bmp5add);
	TEST(bmp2add==bmp3add);
	TEST(bmp2add!=bmp4add);
	TEST(bmp2add==bmp5add);
	TEST(bmp3add!=bmp4add);
	TEST(bmp3add==bmp5add);
	TEST(bmp4add!=bmp5add);
	bmp1.Reset();
	bmp2.Reset();
	bmp3.Reset();
	bmp4.Reset();
	bmp5.Reset();
	User::Heap().Check();
	DeleteScanLineBuffer();
	__UHEAP_MARKEND;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0566

	@SYMTestCaseDesc
	Checks the properties of a created bitmap.
	
	@SYMTestActions
	Creates a bitmap. Checks the resource count.
	Checks the handle, size, display mode and 
	conversion methods for twips to pixels. Checks
	the heap for memory leaks.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestQueryBitmap()
	{
	INFO_PRINTF1(_L("Test Query Bitmap"));
	__UHEAP_MARK;
	CheckResourceCount();
	CFbsBitmapEx bmp;
	TInt ret=bmp.Create(TSize(100,100),EGray16);
	TEST(ret==KErrNone);
	iResourceCount++;
	CheckResourceCount();
	TEST(bmp.Handle()!=0);
	TEST(bmp.SizeInPixels()==TSize(100,100));
	TEST(bmp.DisplayMode()==EGray16);
	bmp.SetSizeInTwips(TSize(1000,1000));
	TEST(bmp.SizeInTwips()==TSize(1000,1000));
	TEST(bmp.HorizontalPixelsToTwips(10)==100);
	TEST(bmp.VerticalPixelsToTwips(10)==100);
	TEST(bmp.HorizontalTwipsToPixels(100)==10);
	TEST(bmp.VerticalTwipsToPixels(100)==10);
	TEST(bmp.ScanLineLength(100,EGray16)==52);
	bmp.Reset();
	iResourceCount--;
	CheckResourceCount();
	User::Heap().Check();
	DeleteScanLineBuffer();
	__UHEAP_MARKEND;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0567

	@SYMTestCaseDesc
	Extended test to check scan line buffer in 
	session allocated correctly for SetRomBitmapL	

	@SYMTestActions
	Loads a specific bitmap from a multi-bitmap 
	file. Reset the bitmap and checks the resource 
	count. Loads new bitmaps, checks the handle
	the bitmap address and data address.

	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestRomBitmapL()
	{
	_LIT(KBmpFile, "z:\\system\\data\\tfbs.rbm");
	INFO_PRINTF1(_L("Test Rom Bitmap"));
	CheckResourceCount();
	CFbsBitmapEx bmpx;
	TInt ret=bmpx.Load(KBmpFile,ETfbs);
	if (ret != KErrNone)
		{
		INFO_PRINTF2(_L("Rom bitmap tfbs.mbm not loaded %d\r\n"),ret);
		return;
		}
	bmpx.Reset();
	CheckResourceCount();
	__UHEAP_MARK;
	CFbsBitmapEx bmp1;
	CFbsBitmapEx bmp2;
	CFbsBitmapEx bmp3;
	CFbsBitmapEx bmp4;
	CFbsBitmapEx bmp5;
	ret=bmp1.Load(KBmpFile,ETfbs);
	TEST(ret==KErrNone);
	TEST(bmp1.Handle()!=0);
	ret=bmp2.Load(KBmpFile,ETfbs);
	TEST(ret==KErrNone);
	CBitwiseBitmap* bmp1add=bmp1.BitmapAddress();
	TEST((TInt)bmp1add);
	CBitwiseBitmap* bmp2add=bmp2.BitmapAddress();
	TEST(bmp1add==bmp2add);
	TEST(bmp1.Handle()==bmp2.Handle());
	CheckResourceCount();

	ret=bmp3.Load(KBmpFile,ETblank);
	TEST(ret==KErrNone);
	TEST(bmp1.Handle()!=bmp3.Handle());
	bmp2.Reset();
	ret=bmp4.Load(KBmpFile,ETfbs);
	TEST(ret==KErrNone);
	CBitwiseBitmap* bmp4add=bmp4.BitmapAddress();
	TEST(bmp1add==bmp4add);
	TEST(bmp4.Handle()==bmp1.Handle());

	ret=bmp5.Load(KBmpFile,ETblank);
	TEST(ret==KErrNone);
	CBitwiseBitmap* bmp3add=bmp3.BitmapAddress();
	CBitwiseBitmap* bmp5add=bmp5.BitmapAddress();
	TEST((TInt)bmp3add);
	TEST(bmp3add==bmp5add);
	TEST(bmp5.Handle()==bmp3.Handle());

	CheckResourceCount();
	bmp3.Reset();
	bmp4.Reset();
	bmp5.Reset();
	ret=bmp2.Load(KBmpFile,ETfbs);
	TEST(ret==KErrNone);
	bmp2add=bmp2.BitmapAddress();
	TEST(bmp1add==bmp2add);
	TEST(bmp1.Handle()==bmp2.Handle());

	CheckResourceCount();
	bmp2.Reset();
	ret=bmp2.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	bmp2add=bmp2.BitmapAddress();
	TSize bmpsize=bmp1.SizeInPixels();
	TInt sllen=CFbsBitmap::ScanLineLength(bmpsize.iWidth,bmp1.DisplayMode());
	sllen*=bmpsize.iHeight;
	bmp1.LockHeap();
	TUint32* bmp1bits=bmp1.DataAddress();
	bmp1.UnlockHeap();
	bmp2.LockHeap();
	TUint32* bmp2bits=bmp2.DataAddress();
	bmp2.UnlockHeap();
	TEST(Mem::Compare((TUint8*)bmp1bits,sllen,(TUint8*)bmp2bits,sllen)==0);
	bmp1.Reset();
	bmp2.Reset();

	ret=bmp1.Load(KBmpFile,ETfbs);
	TEST(ret==KErrNone);
	// Extended test to check scan line buffer in session allocated 
	// correctly for SetRomBitmapL()
	DeleteScanLineBuffer();
	TInt size = 0;
	bmp2.SetRomBitmapL(bmp1.BitmapAddress(),size);
	TEST(iFbs->iScanLineBuffer != 0);
	TEST(Mem::Compare((TUint8*)bmp1.BitmapAddress(),size,(TUint8*)bmp2.BitmapAddress(),size)==0);
	bmp1.Reset();
	bmp2.Reset();

	User::Heap().Check();
	DeleteScanLineBuffer();
	__UHEAP_MARKEND;
	}

TInt AlternateThreadTest(TAny* aAny)
	{
	CTFbs* alt = static_cast<CTFbs*> (aAny);
	__UHEAP_MARK;

	TInt ret=RFbsSession::Connect();
	alt->TEST(ret==KErrNone);
	RFbsSession* fbs=RFbsSession::GetSession();
	alt->TEST(fbs!=NULL);
	alt->TEST(fbs->ResourceCount()==0);

	CFbsFontEx* font=new CFbsFontEx;
	ret=font->Duplicate(buffer[0]);
	alt->TEST(ret==KErrNone);
	alt->TEST(fbs->ResourceCount()==1);
	
	CFbsBitmapEx bmp;
	ret=bmp.Duplicate(buffer[1]);
	alt->TEST(ret==KErrNone);
#if defined(__WINS__)
	alt->TEST(fbs->ResourceCount()==2);
#endif
	
	CFbsFontEx* font2=new CFbsFontEx;
	ret=font2->Duplicate(buffer[0]);
	alt->TEST(ret==KErrNone);
	font->Reset();
	User::Free(font);
	font2->Reset();
	User::Free(font2);
#if defined(__WINS__)
	alt->TEST(fbs->ResourceCount()==1);
#endif
	CFbsBitmapEx bmp2;
	ret=bmp2.Duplicate(buffer[1]);
	alt->TEST(ret==KErrNone);
	bmp.Reset();
	bmp2.Reset();
	alt->TEST(fbs->ResourceCount()==0);
	RFbsSession::Disconnect();
	__UHEAP_MARKEND;
	return(KErrNone);
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0568

	@SYMTestCaseDesc
	Tests the resource counting of font objects
	during multi threading
	
	@SYMTestActions
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestMultiThread()
	{
	INFO_PRINTF1(_L("Test Multiple Threads"));
	CFbsFontEx* font=SelectFont();
	TEST(font->Handle()!=0);
	iResourceCount++;
	CheckResourceCount();
	
	CFbsBitmapEx bmp;
	TInt ret=bmp.Load(iTestBitmapName,ETfbs);
	TEST(ret==KErrNone);
	iResourceCount++;
	CheckResourceCount();

	buffer[0]=font->Handle();
	buffer[1]=bmp.Handle();
	RThread thrd;
	TRequestStatus stat;
	thrd.Create(_L("AlternateThreadTest"),AlternateThreadTest,KDefaultStackSize,0x2000,0x2000,this);
	thrd.SetPriority(EPriorityMuchMore);
	thrd.Logon(stat);
	thrd.Resume();
	User::WaitForRequest(stat);
	thrd.Close();
	bmp.Reset();
	iResourceCount--;
	iTs->ReleaseFont(font);
	iResourceCount--;
	CheckResourceCount();
	User::Heap().Check();
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0569

	@SYMTestCaseDesc
	Tests compression of bitmaps on the heap.

	@SYMTestActions
	Creates a bitmap. Checks the resource count.
	Allocates memory on the heap. Locks the heap and
	stores the bitmaps data address. The heap is unlocked.
	Copies data from the stored data address and compares
	the copied data with the original data. The heap is
	checked for memory leaks.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestHeapCompression()
	{
	INFO_PRINTF1(_L("Test Heap Compression"));
	__UHEAP_MARK;
	CheckResourceCount();
	CFbsBitmapEx bmp1;
	TInt ret=bmp1.Create(TSize(100,100),EGray16);
	TEST(ret==KErrNone);
	iResourceCount++;
	CheckResourceCount();
	CFbsBitmapEx bmp2;
	ret=bmp2.Create(TSize(100,100),EGray16);
	TEST(ret==KErrNone);
	iResourceCount++;
	CheckResourceCount();
	TUint32* data=(TUint32*)User::Alloc(5200);
	TEST(data!=NULL);
	bmp2.LockHeap();
	TUint32* sladd=bmp2.DataAddress();
	bmp2.UnlockHeap();
	TUint32* slptr=sladd;
	for(TInt count=0;count<1300;count++)
		*slptr++=count;
	Mem::Copy(data,sladd,5200);
	bmp1.Reset();
	iResourceCount--;
	CheckResourceCount();
	bmp2.LockHeap();
	TUint32* newdata=bmp2.DataAddress();
	bmp2.UnlockHeap();
	TEST(Mem::Compare((TUint8*)data,5200,(TUint8*)newdata,5200)==0);
	bmp2.Reset();
	iResourceCount--;
	CheckResourceCount();
	delete data;
	User::Heap().Check();
	DeleteScanLineBuffer();
	__UHEAP_MARKEND;
	}

void CTFbs::ExpandCleanupStackL()
	{
	TInt count=0;
	for(;count<10;count++)
		CleanupStack::PushL((TUint32*)0x1);
	CleanupStack::Pop(count);
	}

void CTFbs::CheckResourceCount()
	{
	const TInt serverResourceCount = iFbs->ResourceCount();
	TEST(serverResourceCount == iResourceCount);
	}

//
// DoCreateBitmap(), CreateBitmap(), DoAllocScanLineBufL(), CTFbs::AllocScanLineBuf() are 
// used to show "INC044388  SymbianOS week 12 Fbserv crashes (on HW only)" defect
// (problem with NULL scanline buffer) and to prove its fix.
// The idea of the test:
// A second thread ("CreateBitmap" is the thread name) is created and when resumed it
// creates a bitmap and initializes ComprBitmap pointer to point to it.
// The "CreateBitmap" thread signals the main thread, that the bitmap has been created,
// and waits until receiving "Die" signal and then dies.
// The main thread waits for a signal from the second thread and then duplicates the bitmap and 
// calls GetScanLine() on duplicated bitmap object. If the call fails, the defect is not fixed!

CFbsBitmap* ComprBitmap = NULL;//Shared between threads bitmap pointer.
_LIT(KRamComprBitmap, "z:\\system\\data\\16bit20col.mbm");
RSemaphore  BitmapCreatedSyncObj;//It is used to signal when the bitmap, created by the thread, 
								 //is ready for use
RSemaphore  DieSyncObj;//It is used to signal that "CreateBitmapThread" can die.

//Thread function. It is used by AllocScanLineBuf() test to create a test bitmap and share
//it with the main thread. This function is called from CreateBitmap().
static TInt DoCreateBitmapL(CTFbs* aTest)
	{
	aTest->TEST(::ComprBitmap == NULL);

	ComprBitmap = new (ELeave) CFbsBitmap;

	CleanupStack::PushL(::ComprBitmap);
	User::LeaveIfError(::ComprBitmap->Load(KRamComprBitmap, 0));
	CleanupStack::Pop(::ComprBitmap);

	return KErrNone;
	}

//Thread function. It prepares the cleanup stack and traps the call to DoCreateBitmap().
static TInt CreateBitmap(TAny* aTest)
	{
	CTFbs* test = static_cast <CTFbs*> (aTest);

	CTrapCleanup* trapCleanup = CTrapCleanup::New();
	test->TEST(trapCleanup != NULL);
	TInt err = RFbsSession::Connect();
	test->TEST(err == KErrNone);

	TRAP(err, DoCreateBitmapL(test));

	::BitmapCreatedSyncObj.Signal();//Signal the main thread, that the bitmap has been created
	::DieSyncObj.Wait();//Wait "Die" command from the main thread

	delete ::ComprBitmap;
	::ComprBitmap = NULL;
	RFbsSession::Disconnect();
	delete trapCleanup;
	return err;
	}

static void DoAllocScanLineBufL(CTFbs& aTest)
	{
	aTest.TEST(::ComprBitmap == NULL);
	//Create semaphores
	::CleanupClosePushL(::BitmapCreatedSyncObj);
	::CleanupClosePushL(::DieSyncObj);
	User::LeaveIfError(::BitmapCreatedSyncObj.CreateLocal(0));
	User::LeaveIfError(::DieSyncObj.CreateLocal(0));
	//Create "CreateBitmap" thread. The tread will create "ComprBitmap" bitmap.
	RThread createBitmapThread;
	_LIT(KName, "CreateBitmap");
	User::LeaveIfError(createBitmapThread.Create(KName, 
		(TThreadFunction)CreateBitmap, KDefaultStackSize, KMinHeapSize, 0x00100000, &aTest));
	RDebug::Print(_L("CreateBitmap thread started\r\n"));	
	//Request notification when the tread dies.
	TRequestStatus status;
	createBitmapThread.Logon(status);
	//Resume the thread
	createBitmapThread.Resume();
	::BitmapCreatedSyncObj.Wait();//Wait "bitmap created" signal
	//The bitmap "ComprBitmap" should be already created
	aTest.TEST(::ComprBitmap != NULL);
	//Duplicate the bitmap
	CFbsBitmap* bmp = new (ELeave) CFbsBitmap;
	CleanupStack::PushL(bmp);
	TInt err = bmp->Duplicate(::ComprBitmap->Handle());
	aTest.TEST(err == KErrNone);
	//Call GetScanLine(). It will fail if the defect is not fixed.
	TBuf8<100> buf;
	bmp->GetScanLine(buf, TPoint(0, 0), 10, EColor256);
	//Cleanup
	CleanupStack::PopAndDestroy(bmp);
	//Signal & Wait until "CreateBitmap" thread dies.
	::DieSyncObj.Signal();
	User::WaitForRequest(status);
	aTest.TEST(::ComprBitmap == NULL);
	CleanupStack::PopAndDestroy(&::DieSyncObj);
	CleanupStack::PopAndDestroy(&::BitmapCreatedSyncObj);
	}

//INC044388 - SymbianOS week 12 Fbserv crashes (on HW only)
void CTFbs::AllocScanLineBuf()
	{
	TRAPD(err, ::DoAllocScanLineBufL(*this));
	TEST(err == KErrNone);
	}
// End of INC044388 test.


int CTFbs::LoadOpenFontLibraries()
	{
	RImplInfoPtrArray implementationArray;
	TInt error = KErrNone;
	TUid uid = {KUidOpenFontRasterizerPlunginInterface};

	TRAPD(ecomerror,REComSession::ListImplementationsL(uid,implementationArray));
	TEST(ecomerror==KErrNone);

	const TInt availCount = implementationArray.Count();
	for (TInt count=0;count<availCount;++count)
		{
		const CImplementationInformation* info = implementationArray[count];
		TUid rasterizerUid = info->ImplementationUid();
		// Create a rasterizer
		COpenFontRasterizer* rasterizer=0;
		TRAP(error,rasterizer = COpenFontRasterizer::NewL(rasterizerUid));
		if (!error)
			{
			// Install it in the font store.
			TRAP(error,iFs->InstallRasterizerL(rasterizer));
			if (error)
				delete rasterizer;
			}
		}
	implementationArray.ResetAndDestroy();
	return error;
	}
	
TBool CTFbs::CheckTypefacesSupport(const TTypefaceSupport& aInfo1, const TTypefaceSupport& aInfo2)
	{
	if ((aInfo1.iTypeface == aInfo2.iTypeface) &&
		(aInfo1.iIsScalable == aInfo2.iIsScalable) &&
		(aInfo1.iMaxHeightInTwips == aInfo2.iMaxHeightInTwips) &&
		(aInfo1.iMinHeightInTwips == aInfo2.iMinHeightInTwips) &&
		(aInfo1.iNumHeights == aInfo2.iNumHeights))
		{
		return ETrue;	
		}
	return EFalse;
	}

void CTFbs::LoadFontsL(const TDesC& aFontsDir)
	{
	TUid id1 = TUid::Uid(0);

	RFs fileSys;
	User::LeaveIfError(fileSys.Connect());

	TFindFile fileFinder(fileSys);
	CDir* foundFileList = NULL;
	
	_LIT(KFBSERVFontFilePattern, "*");
	TInt findFileComplete = fileFinder.FindWildByDir(KFBSERVFontFilePattern,aFontsDir,foundFileList);

	while (!findFileComplete)
		{
		CleanupStack::PushL(foundFileList);

		const TInt foundFileCount = foundFileList->Count();
		for (TInt i = 0; i < foundFileCount; i++)
			{			
			TParse parse;
			if (parse.Set((*foundFileList)[i].iName,&fileFinder.File(),NULL) == KErrNone)
				{
				// Get filename and extension of font proposing to be loaded
				TPtrC fontFilename = parse.NameAndExt();
				INFO_PRINTF2(_L("CTFbs::LoadFontsL to load font filename: %S\r\n"), &fontFilename);
				TRAPD(addFileError,id1=iFs->AddFileL(parse.FullName()));
				if (addFileError != KErrNone)
					{
					// Log error in the "corrupt font" file
					User::Panic(_L("Wrong font file"), addFileError);
					}
				}
			}
		CleanupStack::PopAndDestroy(foundFileList); 
		findFileComplete = fileFinder.FindWild(foundFileList);
		}		
	fileSys.Close();
	}

 /**
   @SYMTestCaseID GRAPHICS-PREQ807_1_Load_all_fonts-0001
  
   @SYMPREQ REQ4723
  
   @SYMTestCaseDesc The test manually scans the font folders and loads all font files available.
   Once all the fonts have been loaded and stored in a CFontStore, the TTypefaces stored in this
   CFontStore object are compared to the TTypefaces stored in an existing CFbsTypefaceStore. 
   
   @SYMTestPriority High 
  
   @SYMTestStatus Implemented
   
   @SYMTestActions \n
   API Calls:\n	
      
   @SYMTestExpectedResults The test expects that all the font files loaded by the test matches the ones 
   that FBserv loaded during the startup initialisation.    
  */
void CTFbs::TestAllFontsLoaded()
	{
	INFO_PRINTF1(_L("Test Load all fonts files"));
	__UHEAP_MARK;

	iHeap=UserHeap::ChunkHeap(NULL,0x10000,0x10000);
	TRAPD(ret,iFs=CFontStore::NewL(iHeap));
	TEST(ret==KErrNone);
	TEST(iFs != NULL);

	ret = LoadOpenFontLibraries();
	TEST(ret==KErrNone);

	TRAP(ret, LoadFontsL(KFBSERVFontFileDir));
	TEST(ret==KErrNone);

	// Check the Typefaces are the same both in the newly CFontStore and existing CFbsTypefaceStore
	TInt fsTypefaceNum = iFs->NumTypefaces();
	TInt tsTypefaceNum = iTs->NumTypefaces();
	TEST(fsTypefaceNum == tsTypefaceNum);	

	TBool equal = EFalse;
	for (TInt i = 0; i < fsTypefaceNum; i++)
		{
		TTypefaceSupport infoFs;
		iFs->TypefaceSupport(infoFs,i);
		for (TInt j = 0; j < tsTypefaceNum; j++)
			{
			TTypefaceSupport infoTs;
			iTs->TypefaceSupport(infoTs,j);
			
			equal = CheckTypefacesSupport(infoFs, infoTs);
			if (equal)
				{
				break;
				}
			}
		// Check if the CFontStore typeface has been found in the CFbsTypefaceStore
		TEST(equal);
		}
		
	delete iFs;
	iHeap->Close();

	REComSession::FinalClose();
	
	User::Heap().Check();
	__UHEAP_MARKEND;
	}

/**
	@SYMTestCaseID
	GRAPHICS-FBSERV-0570

	@SYMTestCaseDesc
	Tests default language for metrics.

	@SYMTestActions
	Constructs a TFontSpec object with the specified 
	typeface and height. Gets the font which is the 
	nearest to the given font specification. Checks
	that the maximum font height is correct for a 
	specified language.
	
	@SYMTestExpectedResults
	Test should pass
*/
void CTFbs::TestDefaultLanguageForMetrics()
	{
	static const TInt KRequiredHeight = 24;
	static const TInt KReturnedMaxHeight = 36;
	TInt rc = KErrGeneral;

	// Case 00
	// No languages are set on font spec and typeface store
	//
	TFontSpec fontSpec0(KTypefaceName, KRequiredHeight);
	CFont* font0 = NULL;
	rc = iTs->GetNearestFontToDesignHeightInPixels(font0, fontSpec0);
	TEST(KErrNone == rc);
	TEST(NULL != font0);
	TEST(KReturnedMaxHeight == font0->FontMaxHeight());
	INFO_PRINTF2(_L("FontMaxHeight returns %d"), font0->FontMaxHeight());

	// Case 01
	// Set language on font spec will suppress that on typeface store
	//
	fontSpec0.SetScriptTypeForMetrics(ELangGreek);
	CFont* font1 = NULL;
	rc = iTs->GetNearestFontToDesignHeightInPixels(font1, fontSpec0);
	TEST(KErrNone == rc);
	TEST(NULL != font1);
	TEST(KReturnedMaxHeight == font1->FontMaxHeight());
	INFO_PRINTF2(_L("FontMaxHeight returns %d"), font1->FontMaxHeight());

	// Set language on typeface store
	iTs->SetDefaultLanguageForMetrics(ELangEnglish);

	// Case 10
	// Language on typeface store will suppress that on font spec
	// _if_ its not specified
	//
	TFontSpec fontSpec1(KTypefaceName, KRequiredHeight);
	CFont* font2 = NULL;
	rc = iTs->GetNearestFontToDesignHeightInPixels(font2, fontSpec1);
	TEST(KErrNone == rc);
	TEST(NULL != font2);
	TEST(KReturnedMaxHeight == font2->FontMaxHeight());
	INFO_PRINTF2(_L("FontMaxHeight returns %d"), font2->FontMaxHeight());

	// Case 11 - Negative test of case 10
	//
	fontSpec1.SetScriptTypeForMetrics(ELangRussian);
	CFont* font3 = NULL;
	rc = iTs->GetNearestFontToDesignHeightInPixels(font3, fontSpec1);
	TEST(KErrNone == rc);
	TEST(NULL != font3);
	TEST(KReturnedMaxHeight == font3->FontMaxHeight());
	INFO_PRINTF2(_L("FontMaxHeight returns %d"), font3->FontMaxHeight());

	iTs->ReleaseFont(font0);
	iTs->ReleaseFont(font1);
	iTs->ReleaseFont(font2);
	iTs->ReleaseFont(font3);

	CheckResourceCount();
	User::Heap().Check();
	}
	

//The "bad" versions of these standard fonts have been hacked to give specific results
_LIT(KFBSERVFontFileOpen, 		"Z:\\resource\\fonts\\DejaVuSansCondensed.ttf");

//This file is identical to DejaVuSansCondensed.ttf
_LIT(KFBSERVFontFileBadOpen, 	"Z:\\PlatTest\\Graphics\\TestData\\uniquified_fonts\\xx_dejavusanscondensed.ttf");

 /**
   @SYMTestCaseID GRAPHICS-CTFbs-TestDuplicateFontFileEntries-0001
  
   @SYMDEF  DEF094692
  
   @SYMTestCaseDesc  If Open fonts are loaded that are marginally unique compared to the 
   					 existing fonts then they are not actually added to the typeface system, and may even be discarded.
   					 The fix is actually in FNTSTORE, but I need to test in an environment with full Open font support,
   					 which is not provided in the fontstore test code.
   					 Bi9tmap fon ts are tested in fntstore\tfs\t_fntmem.cpp
   
   @SYMTestPriority Med 
  
   @SYMTestStatus Implemented
   
   @SYMTestActions \n
   		The original versions of the Open fonts are first loaded to ensure that they have actually been loaded.
   		The original versions of the Open fonts are loaded again to demobnstrate they have the same IDs.
   		A version of the open font which is identical except for a different filename should be rejected
   	
   			
   API Calls:	AddFile\n	
      
   @SYMTestExpectedResults The test expects:
   		The original versions should load without changing the number of typefaces
   		The second load should return the same UID for the font
   		The identical fonts should return captured fail codes, and not change the typeface counts
   		The semi-identical font should perform a single increase to UIDs and typefaces
  */
void CTFbs::TestDuplicateFontFileEntries()
	{
	
	INFO_PRINTF1(_L("Test Load semi-duplicate fonts files"));
	TInt numFacesBefore=iTs->NumTypefaces();
	TInt aIdOpen1=0;
	TInt aIdOpen1b=0;
	TInt aIdOpen2=0;
	//make sure the originals of these fonts were safely opened
	//both should simply cause a reference-count increase on the originator files.
	TInt err2=iTs->AddFile(KFBSERVFontFileOpen,aIdOpen1);
	TEST(err2==KErrNone);
	if (err2)
		{
		INFO_PRINTF1(_L("One of the expected fonts was missing. Test abandoned."));
		}
	else
		{
		TInt numFacesAfterLoadOriginals=iTs->NumTypefaces();
		//TEST(numFacesBefore==numFacesAfterLoadOriginals);
		if (numFacesBefore!=numFacesAfterLoadOriginals)
			INFO_PRINTF2(_L("Warning: reinstalling the system fonts added %d typefaces!"), numFacesAfterLoadOriginals-numFacesBefore);
		
		//load the originals again just to prove the UIDs are re-used - only makes sense for open font where UID is generated!
		TInt err2=iTs->AddFile(KFBSERVFontFileOpen,aIdOpen1b);
		TEST(err2==KErrNone);
		TEST(aIdOpen1==aIdOpen1b);
		
		TInt numFacesAfterLoadBadFile3=iTs->NumTypefaces();
		TEST(numFacesBefore==numFacesAfterLoadBadFile3);
		
		//This open font file contains no new fonts, so will ultimately be discarded
		//The pathname is different so it won't be considered identical to its originator
		TInt err4=iTs->AddFile(KFBSERVFontFileBadOpen,aIdOpen2);
		TEST(err4==KErrAlreadyExists && aIdOpen2==0); 
		if (err4!=KErrAlreadyExists)
				INFO_PRINTF2(_L("Unexpected error code was %d"),err4);	 
		
		TInt numFacesAfterLoadBadFile4=iTs->NumTypefaces();
		TEST(numFacesBefore==numFacesAfterLoadBadFile4);
		
		}
	
	if (aIdOpen1)	iTs->RemoveFile(aIdOpen1);
	if (aIdOpen1b)	iTs->RemoveFile(aIdOpen1b);
	if (aIdOpen2)	iTs->RemoveFile(aIdOpen2);
	
	//The added typeface should have been uninstalled
	TInt numFacesAfterUninstall=iTs->NumTypefaces();
	TEST(numFacesAfterUninstall==numFacesBefore);
	
	
	}


/*
COMMENTED OUT FOR NOW BECAUSE DEF084095 FIX MAKES THIS TEST REDUNDANT
//DEF078039: Workwer function: Hindi - Risk of memory leak (RShapeInfo) if client thread dies
TInt TShapeHeaderMemoryLeakTest(TAny* aTest)
	{
	_LIT16(KHindi1,"\x0915\x094D\x0937\x0924\x094D\x0930\x093F\x092F\x0020\x0909\x0926\x094D\x0926\x0947\x0936\x094D\x0020\x0915\x094D\x0937\x093F\x092A\x094D\x0930");
	_LIT(KDevFontFace, "Devanagari OT Eval");
	
	CTFbs* test = static_cast<CTFbs*> (aTest);
	
	__UHEAP_MARK;
	
	const TDesC16& Hindi1 = KHindi1;
	RShapeInfo shapeInfo;
	TBool isOpen = EFalse;
	
	// Create a cleanup stack for this thread
	CTrapCleanup* trapCleanup = CTrapCleanup::New();
	test->TEST(trapCleanup != NULL);

	// Create a new session with FBSERV
	TInt ret=RFbsSession::Connect();
	test->TEST(ret==KErrNone);
	RFbsSession* fbs=RFbsSession::GetSession();
	test->TEST(fbs!=NULL);

	// Create a FbsFont to use for shaping
	TFontSpec testFontSpec(KDevFontFace,200); 
	CFbsBitmap* bmp = new(ELeave) CFbsBitmap;
	ret = bmp->Create(TSize(100,100),EGray2);
	if (ret == KErrNotSupported)
		return ret;
	else
		User::LeaveIfError(ret);

	CFbsBitmapDevice* device = NULL;
	TRAPD(err,device = CFbsBitmapDevice::NewL(bmp));
	User::LeaveIfError(err);

	CFbsBitGc* gc = NULL;
	User::LeaveIfError(device->CreateContext(gc));

	CFbsFont* font = NULL;
	User::LeaveIfError(device->GetNearestFontToDesignHeightInTwips(font,testFontSpec));
	gc->UseFont(font);
	
	// Open shapeInfo by calling GetCharacterPosition2. This makes an IPC call to the 
	// server and shapes Hindi, resulting in memory being allocated for a TShapeHeader object
	CFont::TPositionParam param;
	param.iDirection = CFont::EHorizontal;
	param.iFlags = CFont::TPositionParam::EFLogicalOrder;
	param.iText.Set(Hindi1);
	param.iPosInText = 0;
	param.iPen.iX = param.iPen.iY = 0;
	TBool r = font->GetCharacterPosition2(param, shapeInfo);
	
	// Test is memory was allocated to a TShapeHeader object
	isOpen = shapeInfo.IsOpen();
	test->TEST(isOpen == 1);
	
	// Tidy up and close
	delete bmp;
	delete device;
	delete gc;

	// Disconnect from the server. i.e. end ther session, without calling 
	// RShapeInfo::Close(), to simulate a client death
	RFbsSession::Disconnect();
	
	// Check to see is TShapeHeader has been freed.
	// Since a pointer the the TShapeHeader object is stored with the 
	// COpenFontSessionCache, when the client disconnects, the TShapeHeader 
	// object is freed along with the session cache.
	isOpen = shapeInfo.IsOpen();
	test->TEST(isOpen == 0);
	
	delete trapCleanup;

	__UHEAP_MARKEND;
	return(KErrNone);
	}
*/
/*
COMMENTED OUT FOR NOW BECAUSE DEF084095 FIX MAKES THIS TEST REDUNDANT

//DEF078039: Hindi - Risk of memory leak (RShapeInfo) if client thread dies
void CTFbs::TestShapeHeaderMemoryLeakAtClientDeath()
	{
	INFO_PRINTF1(_L("Test Shape Header Memory Leak At Client Death"));
	RThread shaperThread;
	TRequestStatus stat;
	shaperThread.Create(_L("Shaper Thread"),TShapeHeaderMemoryLeakTest,KDefaultStackSize, KMinHeapSize, 0x00100000,this);
	shaperThread.SetPriority(EPriorityMuchMore);
	shaperThread.Logon(stat);
	shaperThread.Resume();
	User::WaitForRequest(stat);
	shaperThread.Close();
	User::Heap().Check();
	}
// End of DEF078039 test.
*/

/**
@SYMTestCaseID			GRAPHICS-FBSERV-0506

@SYMDEF					INC103815

@SYMTestCaseDesc		Tests that the value returned by CFbsBitmap::Handle()
						does not change after resizing or compression

@SYMTestPriority		High

@SYMTestType			UT

@SYMTestStatus			Implemented

@SYMTestActions			1. Create a bitmap and store its handle number
						2. Resize the bitmap and compare its handle number with the stored value
						3. Compress the bitmap and compare its handle number with the stored value

@SYMTestExpectedResults	All the handle numbers returned should be the same
*/
void CTFbs::TestBitmapHandleImmutable()
	{
	INFO_PRINTF1(_L("Test fix for INC103815"));
	CFbsBitmap *bmp = new CFbsBitmap;
	TEST(bmp != NULL);
	if (bmp == NULL)
		return;
	TEST(bmp->Create(TSize(200, 200), EColor256) == KErrNone);
	TInt handle = bmp->Handle();
	TEST(bmp->Resize(TSize(400, 400)) == KErrNone);
	TEST(handle == bmp->Handle());
	TEST(bmp->Compress() == KErrNone);
	TEST(handle == bmp->Handle());
	delete bmp;
	}


/**
@SYMTestCaseID		GRAPHICS-FBSERV-0507
@SYMTestPriority	High
@SYMTestType		UT
@SYMTestStatus		Implemented
@SYMDEF				PDEF102570

@SYMTestCaseDesc
	Tests that the attributes and the data address of a bitmap do not change between
	calls to CFbsBitmap::BeginDataAccess() and CFbsBitmap::EndDataAccess() due to resizing
	or compression by other clients

@SYMTestActions
	1: Create a bitmap and a second CFbsBitmap object that refers to the same bitmap.
	2: Call BeginDataAccess() on the first CFbsBitmap object.
	3: Call Resize() on the second CFbsBitmap object.
	4: Call EndDataAccess() on the first CFbsBitmap object checking its state before and after.
	5: Call BeginDataAccess() on the first CFbsBitmap object.
	6: Call Compress() on the second CFbsBitmap object.
	7: Call EndDataAccess() on the first CFbsBitmap object checking its state before and after.

@SYMTestExpectedResults
	The affected attributes and the data address of the bitmap should change only
	after the calls to EndDataAccess()
*/
void CTFbs::TestBitmapBeginEnd()
	{
	INFO_PRINTF1(_L("Test CFbsBitmap::BeginDataAccess()-EndDataAccess()"));
	CFbsBitmap *bmp1 = new CFbsBitmap;
	CFbsBitmap *bmp2 = new CFbsBitmap;
	TEST(bmp1 != NULL && bmp2 != NULL);
	if (bmp1 == NULL || bmp2 == NULL)
		return;
	TEST(bmp1->Create(TSize(200, 200), EColor256) == KErrNone);
	TEST(bmp2->Duplicate(bmp1->Handle()) == KErrNone);
	TUint32* dataAddress1 = bmp1->DataAddress();
	TUint32* dataAddress2 = bmp2->DataAddress();
	TEST(dataAddress1 == dataAddress2);
	bmp1->BeginDataAccess();
	TEST(bmp2->Resize(TSize(400, 400)) == KErrNone);
	dataAddress2 = bmp2->DataAddress();
	TEST(bmp1->SizeInPixels() == TSize(200, 200));
	TEST(bmp1->DataAddress() == dataAddress1);
	bmp1->EndDataAccess();
	TEST(bmp1->SizeInPixels() == TSize(400, 400));
	dataAddress1 = bmp1->DataAddress();
	TEST(dataAddress1 == dataAddress2);
	bmp1->BeginDataAccess();
	TEST(bmp2->Compress() == KErrNone);
	dataAddress2 = bmp2->DataAddress();
	TEST(bmp1->Header().iCompression == ENoBitmapCompression);
	TEST(bmp1->DataAddress() == dataAddress1);
	bmp1->EndDataAccess();
	TEST(bmp1->Header().iCompression != ENoBitmapCompression);
	dataAddress1 = bmp1->DataAddress();
	TEST(dataAddress1 == dataAddress2);
	delete bmp1;
	delete bmp2;
	}


/**
@SYMTestCaseID		GRAPHICS-FBSERV-0508
@SYMTestPriority	High
@SYMTestType		UT
@SYMTestStatus		Implemented
@SYMDEF				DEF104752

@SYMTestCaseDesc
	Tests that trying to launch a second instance of FBServ fails gracefully

@SYMTestActions
	Start a new instance of FBSERV.EXE. Since the Font and Bitmap Server should
	already be running, the created process should panic immediately.

@SYMTestExpectedResults
	Panic FBSERV 5
*/
void CTFbs::TestSingletonServer()
	{
	INFO_PRINTF1(_L("Test singleton FBServ process"));
	_LIT(KFBSERVServerExe, "z:\\sys\\bin\\fbserv.exe");
	RProcess fbs;
	TInt ret = fbs.Create(KFBSERVServerExe, KNullDesC);
#ifdef __WINS__
	// On the emulator it's not possible to load the same EXEXP twice
	// DWin32CodeSeg::DoCreate() returns KErrAlreadyExists in that case
	if (ret == KErrAlreadyExists)
		return;
#endif
	TEST(ret == KErrNone);
	TRequestStatus status;
	fbs.Logon(status);
	TEST(status == KRequestPending);
	fbs.Resume();
	User::WaitForRequest(status);
	TExitType exitType = fbs.ExitType();
	TExitCategoryName exitCategory = fbs.ExitCategory();
	TInt exitReason = fbs.ExitReason();
	TEST(exitType == EExitPanic);
	TEST(exitCategory == KFBSERVPanicCategory);
	TEST(exitReason == EFbsPanicStartupFailed);
	fbs.Close();
	}

/**
@SYMTestCaseID      GRAPHICS-FBSERV-0620
@SYMTestPriority    High
@SYMTestStatus      Implemented
@SYMDEF             DEF140138

@SYMTestCaseDesc
	A positive test that shows in cases where the font glyph cache is full and the 
	session cache becomes used, client-side CFbsFont calls that query the session cache 
	successfully find the glyph, proving that the session handles used client-side and server-side
	are the same, thereby avoiding any unneccessary IPC calls.

@SYMTestActions
	Create a large font which consumes a lot of memory.
	Create a CFbsBitGc and a CFbsBitmap target.
	Use the CFbsBitGc to render some text, thereby filling the font glyph cache. 
		Renders enough glyphs to fill up the font glyph cache, so that the session cache is used
		for later characters.
	Call CBitmapFont::CharacterNeedsToBeRasterized() with a NULL session handle.
	Call CBitmapFont::CharacterNeedsToBeRasterized() with the RFbsSession handle.
	Call CFbsFont::GetCharacterData() to retrieve a pointer to the bitmap data. Compare this with the data 
		returned from CBitmapFont::GetCharacterData().

@SYMTestExpectedResults
	When using KNullHandle, CharacterNeedsToBeRasterized() with the first character, is expected to pass
		proving that the font cache is working as expected when glyphs can fit into it.
	When using KNullHandle, CharacterNeedsToBeRasterized() with the last character, it expected to fail, 
		proving that the glyph has not been cached in the font glyph cache. (If it had, it would find a 
		match regardless of the	session handle as it looks in the font cache before the session cache).
	When using the correct session handle with CharacterNeedsToBeRasterized() with the last character, 
		should return ETrue, proving that the glyph has been cached, and was found because the correct 
		session handle was supplied, therefore must be in the session cache.    
	The bitmap pointers returned by CFbsFont::GetCharacterData() and CBitmapFont::GetCharacterData() should match, 
		proving the public API CFbsFont::GetCharacterData() is correctly using the data stored in the session cache,
		and not returning the data of a separately-rasterized glyph.
*/
void CTFbs::TestFontSessionCacheLookupL()
	{
	INFO_PRINTF1(_L("Test Font Session-cache Lookup"));

	User::LeaveIfError(RFbsSession::Connect());    
	RFbsSession* fbsSession = RFbsSession::GetSession();
	CFbsTypefaceStore* ts = CFbsTypefaceStore::NewL(NULL);
	CleanupStack::PushL(ts);

	TFontSpec fs(_L("DejaVu Sans Mono"), 80);
	fs.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
	CFbsFont* font = NULL;
	TEST(KErrNone == ts->GetNearestFontToDesignHeightInPixels((CFont*&)font, fs));

	CFbsBitmap* target = new (ELeave) CFbsBitmap;
	CleanupStack::PushL(target);
	User::LeaveIfError(target->Create(TSize(100, 100), EColor16MU));
	CFbsBitmapDevice* bgDevice = CFbsBitmapDevice::NewL(target);
	CleanupStack::PushL(bgDevice);
	CFbsBitGc* bgGc = NULL;
	User::LeaveIfError(bgDevice->CreateContext(bgGc));
	bgGc->UseFont(font);
	CleanupStack::PushL(bgGc);
	_LIT(KTestText, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ");

	// Draw the text, forcing the glyphs into the font and session caches.
	bgGc->DrawText(KTestText, TPoint(0, 10));

	CBitmapFont* bmFont = CTFbsFont::FontAddress(font);
	
	// Check that the first character in KTestText has been rasterized, and is in the font cache. 
	TBool glyphIsInFontCache = !bmFont->CharacterNeedsToBeRasterized(KNullHandle, KTestText()[0]);
	TEST(glyphIsInFontCache);
	
	// Check that the last character in KTestText has been rasterized, and is not in the font cache
	// because it did not fit, therefore it should be in the session cache.
	const TChar KTestChar = KTestText()[KTestText().Length() - 1];
	glyphIsInFontCache = !bmFont->CharacterNeedsToBeRasterized(KNullHandle, KTestChar);
	TEST(!glyphIsInFontCache);
	TBool glyphIsInSessionCache = !bmFont->CharacterNeedsToBeRasterized(fbsSession->iHelper->iServerSessionHandle, KTestChar);
	TEST(glyphIsInSessionCache);

	// Test that when calling GetCharacterData() on CFbsFont, it returns the same rasterized data as 
	// the bitmap in the session cache, proving that the client API is using the session cache handle correctly.
	TSize bitmapSize;
	const TUint8* bitmapDataClient;
	const TUint8* bitmapDataSessionCache;
	TOpenFontCharMetrics metrics;
	font->GetCharacterData(KTestChar,metrics,bitmapDataClient,bitmapSize);
	bmFont->GetCharacterData(fbsSession->iHelper->iServerSessionHandle, KTestChar, metrics, bitmapDataSessionCache);
	TEST(bitmapDataClient != NULL && bitmapDataClient == bitmapDataSessionCache);

	bgGc->DiscardFont();
	CleanupStack::PopAndDestroy(4); // bgGc, bgDevice, target, ts
	RFbsSession::Disconnect();
	}
	
/**
@SYMTestCaseID      GRAPHICS-FBSERV-0650
@SYMTestPriority    High
@SYMTestStatus      Implemented
@SYMDEF             DEF141816

@SYMTestCaseDesc
	A negative test that shows that IPC calls from CFbsBitmap which uses a 
	CFbsFont handle fail and that IPC calls from CFbsFont which use a 
	CFbsBitmap handle fail.

@SYMTestActions
	i. Create a bitmap.
	ii. Create a font.
	iii. Send a bitmap-related IPC message to server with bitmap handle.
	iv. Send a bitmap-related IPC message to server with font handle.
	v. Send a font-related IPC message to server with font handle.
	vi. In a separate thread, send a font-related IPC message to server with
		bitmap handle.
	
@SYMTestExpectedResults
	Steps iii. and v. should return KErrNone.
	Step iv. should return KErrUnknown.
	Step vi. should panic with FBSERV -6.
*/
void CTFbs::TestInvalidHandlesInIpcCallsL()
	{
	INFO_PRINTF1(_L("Test Bitmap and Font IPC calls with invalid handles"));
	CFbsFontEx* font = SelectFont();

	CFbsBitmapEx* bmp = new(ELeave) CFbsBitmapEx();
	TEST(KErrNone == bmp->Create(TSize(1,1),EGray2));

	TInt fontHandle = font->FontHandle();
	TInt bitmapHandle = bmp->BitmapHandle();

	// Send a IPC command to resize a bitmap with a font handle
	TPckgBuf<TBmpHandles> handlebuf;
	TIpcArgs args1(fontHandle, 2, 2, &handlebuf);
	// Send a IPC command to resize a bitmap with the bitmap's handle
	TEST(KErrNone == iFbs->SendCommand(EFbsMessBitmapBgCompress, bitmapHandle));
	// Send a IPC command to resize a bitmap with the font's handle
	TEST(KErrUnknown == iFbs->SendCommand(EFbsMessBitmapBgCompress, fontHandle));

	// Send a IPC command to set the font's height with the font's handle
	TEST(KErrNone == iFbs->SendCommand(EFbsMessSetTwipsHeight, fontHandle, 49));
	// In a second thread, send a IPC command to set the font's height with the 
	// bitmap's handle.  Should panic with FBServ -6.
	TFbsTestThreadInfo threadInfo = {EFbsSecondThreadInvalidHandleInIpcCall};
 	TExitCategoryName exitCategoryName(KFbsPanicCategory);
	_LIT(KTestName, "TestInvalidHandlesInIpcCall");
 	CreateSecondThreadAndCheckPanicL(threadInfo, -6, exitCategoryName, KTestName);

	iTs->ReleaseFont(font);
	delete bmp;
	}

/**
Creates a second thread and do some panic tests in it.
@param aTestInfo The information for the tests
@param aPanicCode The expected panic code
@param aExitCategory The expected panic category
@param aThreadName The name of the new thread
@leave Gets system wide error code
*/
void CTFbs::CreateSecondThreadAndCheckPanicL(TFbsTestThreadInfo& aTestInfo, TInt aPanicCode, TExitCategoryName aExitCategory, const TDesC &aThreadName)
	{
	RThread secondThread;
	User::LeaveIfError(secondThread.Create(aThreadName, SecondThreadStart, KDefaultStackSize, 0x1000, 0x1000, &aTestInfo));
	// Launch second thread
	TRequestStatus statusSecondThread;
	secondThread.Logon(statusSecondThread);
	secondThread.SetPriority(EPriorityLess);
	secondThread.Resume();	
	
	User::WaitForRequest(statusSecondThread);
	
	if(EExitPanic != secondThread.ExitType())
		{
		ERR_PRINTF3(_L("Expected exit type: %d, Actual exit type: %d"), EExitPanic, secondThread.ExitType());
		TEST(EFalse);
		}
	
	if(aPanicCode != secondThread.ExitReason())
		{
		ERR_PRINTF3(_L("Expected panic code: %d, Actual panic code: %d"), aPanicCode, secondThread.ExitReason());
        TEST(EFalse);
		}
	
	TExitCategoryName secondThreadExitCategory = secondThread.ExitCategory();
	if(aExitCategory != secondThreadExitCategory)
		{
		ERR_PRINTF3(_L("Expected panic category: %S, Actual panic category: %S"), &aExitCategory, &secondThreadExitCategory);
        TEST(EFalse);
		}
	
	//Close the handle
	secondThread.Close();
	}

/**
Second thread entry function.
*/
TInt CTFbs::SecondThreadStart(TAny* aTestInfo)
	{
	
	__UHEAP_MARK;
    TInt procHandles1  =0;
    TInt threadHandles1=0;
    RThread().HandleCount(procHandles1, threadHandles1);
	CTrapCleanup* cleanupStack = CTrapCleanup::New();
	
	if (!cleanupStack)
	    {
	    __UHEAP_MARKEND;
	    return KErrNoMemory;
	    }
	
	TInt result = KErrNone;
	TRAP(result, SecondThreadMainL(static_cast<TFbsTestThreadInfo*>(aTestInfo)));
	
	delete cleanupStack;

    TInt procHandles2  =0;
    TInt threadHandles2=0;
    RThread().HandleCount(procHandles2,threadHandles2);
    if (threadHandles1 != threadHandles2)
        {
        result = KErrGeneral;  // Thread-owned handles not closed
        }
	__UHEAP_MARKEND;

	return result;
	}

/**
Run the test contained within the TFbsTestThreadInfo object. A new thread is
created for each test and only one of the cases in the switch statements
below will be used.

@param aTestInfo The parameters for the test
@return One of the system wide error codes or an enumeration of passed tests.
 */
TInt CTFbs::SecondThreadMainL(TFbsTestThreadInfo* aTestInfo)
    {
    TInt result = 0;
    TFbsMultiThreadTestCase testcase = aTestInfo->iTestCase;

    //test cases without the need of an initialised driver
    switch (testcase)
    	{
    case EFbsSecondThreadInvalidHandleInIpcCall:
    	result = SecondThreadPanicInvalidHandleInIpcCall();
        break;
    	}
    return result;
    }

/**
Implementation of SecondThread test EFbsSecondThreadInvalidHandleInIpcCall

@panic FBSERV -6 If the test is successful

@return One of the system wide error codes.
 */
TInt CTFbs::SecondThreadPanicInvalidHandleInIpcCall()
	{
	TInt result = RFbsSession::Connect();
	if (KErrNone != result)
		{
		return result;
		}
	RFbsSession* fbs = RFbsSession::GetSession();
	CFbsBitmapEx* bmp = new CFbsBitmapEx();
	if (!bmp)
		{
		return KErrGeneral;
		}
	result = bmp->Create(TSize(1,1),EGray2);
	if(KErrNone != result)
		{
		delete bmp;
		return KErrGeneral;
		}

	CFbsTypefaceStore* ts = NULL;
	ts = (CFbsTypefaceStore*)CFbsTypefaceStore::NewL(NULL);
	if (!ts)
		{
		delete bmp;
		return KErrGeneral;
		}

	CFbsFontEx* font=NULL;
	result = ts->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KTypefaceName, 15));
	if (!font)
		{
		delete bmp;
		delete ts;
		return KErrGeneral;
		}

	TInt fontHandle = font->FontHandle();
	TInt bitmapHandle = bmp->BitmapHandle();

	// Send a IPC command to set twips height of font with a bitmap handle
	result = fbs->SendCommand(EFbsMessSetTwipsHeight, bitmapHandle, 49);

	ts->ReleaseFont(font);
	delete bmp;
	delete ts;
	return result;
	}

/**
@SYMTestCaseID		GRAPHICS-FBSERV-0619
@SYMTestPriority	High
@SYMTestType		UT
@SYMTestStatus		Implemented
@SYMDEF				EI0014

@SYMTestCaseDesc
	Tests that there are no virtual function calls to objects in FBServ's shared heap from outside
	the FBServ process. Such function calls only work if DLLs are guaranteed to be mapped at the
	same logical address in every process. This is not necessarily true for all memory models.

@SYMTestActions
	Selects a font, intercepts the VF table in the corresponding CBitmapFont and COpenFont objects
	to record virtual function calls from outside the FBServ process, calls the vulnerable functions
	on the created CFbsFont object and releases the font.

@SYMTestExpectedResults
	Number of virtual function calls to CBitmapFont and COpenFont from outside FBServ is 0
*/
void CTFbs::TestNoVFCallsToGlobalObjects()
	{
#ifdef __WINS__
	INFO_PRINTF1(_L("Test no virtual function calls to objects in FBServ's shared heap from outside FBServ process"));
	CFbsFontEx* font = SelectFont();
	(void)font->TypeUid();
	(void)font->HeightInPixels();
	(void)font->AscentInPixels();
	(void)font->DescentInPixels();
	(void)font->CharWidthInPixels('A');
	(void)font->TextWidthInPixels(_L("A"));
	(void)font->BaselineOffsetInPixels();
	(void)font->TextCount(_L("A"), 10);
	TInt excess;
	(void)font->TextCount(_L("A"), 10, excess);
	(void)font->MaxCharWidthInPixels();
	(void)font->MaxNormalCharWidthInPixels();
	(void)font->FontSpecInTwips();
	TOpenFontCharMetrics metrics;
	const TUint8* bitmap;
	TSize size;
	(void)font->GetCharacterData('A', metrics, bitmap, size);
	CFont::TPositionParam param;
	param.iText.Set(_L("A"));
	(void)font->GetCharacterPosition(param);
	(void)font->FontCapitalAscent();
	(void)font->FontMaxAscent();
	(void)font->FontStandardDescent();
	(void)font->FontMaxDescent();
	(void)font->FontLineGap();
	iTs->ReleaseFont(font);
	TEST(iFontCallCounter.iVFCallsOutsideFBServ == 0);
	TEST(iOpenFontCallCounter.iVFCallsOutsideFBServ == 0);
#else
	INFO_PRINTF1(_L("Test no virtual function calls to objects in FBServ's shared heap from outside FBServ process - skipped on target"));
#endif
	}

//--------------
__CONSTRUCT_STEP__(Fbs)
