fontservices/textshaperplugin/test/CreateTestData/T_SHAP_createTestData.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 09 Jun 2010 11:40:52 +0300
branchRCL_3
changeset 36 f902e87c146f
parent 0 1fb32624e06b
permissions -rw-r--r--
Revision: 201021 Kit: 2010123

/*
* Copyright (c) 2008-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: 
* Creates test data files that are used by TC_SHAP_shapeText.cpp test. 
* This tool uses the Unicode test input text defined in inputData.h and
* shapes the text by calling the IcuLayoutEngine API ShapeText().
* The result, along with the input text is stored in the test data files with 
* extensions .dat
* First, the reference input data is stored in the data files in the following format, seperated by a delimiter - | :
* Length (of the input data string)	Font typeface name | Font file name | Starting offset in the input string | End offset in the input string | Input text string
* Then the result of the shaping is stored in data files in the following format:
* Output glyph count	Output glyphs	Glyph X and Y coordinates	Glyph advances	Glyph indices	Output character count
* The TC_SHAP_shape_Text test is programmed to read in files in this format, and this format only.
* This tool needs to be run, and new test data files need to be created everytime the 
* IcuLayoutEngine shaping rules are changed/edited/appended.
* IN ORDER TO CREATE NEW TEST DATA FILES USING THIS UTILITY, YOU WILL NEED TO:
* 1. Add a new TInputData entry in inputData.txt
* 2. Delete any old data files in %EPOCROOT%epoc32\winscw\c\
* 3. Run the test.
* IN ORDER TO GET THE TC_SHAP_shapeText TEST FILE TO USE THIS NEW DATA, YOU WILL NEED TO:
* 1. Add your new test file in perforce to:
* IcuLayoutEngine/test/testdata/...
* They will have been added to %EPOCROOT%epoc32\winscw\c
* 2. Update the bld.inf file for IcuLayoutEngine to export this file to z:\test\data\...
* 3. Update the .cpp file by adding the a new literal at the top of the file with the new filename to be used.
* 4. Update the TC_SHAP_shapeText.iby file in IcuLayoutEngine/test to include the new file.
* THIS TOOL SHOULD ONLY BE RUN BY SOMEONE WHO KNOWS WHAT HE/SHE IS DOING!!
*
*/


#include <e32def.h>
#include <e32test.h>
#include <e32std.h>
#include <f32file.h>
#include <fntstore.h>
#include <s32file.h>

#include <graphics/openfontrasterizer.h>
#include <graphics/openfontconstants.h>
#include <graphics/shapeimpl.h>
#include "inputData.h"

const TUint32 KDevanagariScriptCode = 0x64657661;
const TUint32 KKannadaScriptCode = 0x6B6E6461;
const TUint32 KHindiLanguageCode = 0x48494E20;
const TUint32 KKannadaLanguageCode = 0x4B414E20;
const TUint32 KGujaratiScriptCode = 0x67756A72;
const TUint32 KGujaratiLanguageCode = 0x47554A20;
const TUint32 KBengaliScriptCode = 0x62656E67;
const TUint32 KBengaliLanguageCode = 0x42454E20;
const TUint32 KTamilScriptCode = 0x74616D6C;
const TUint32 KTamilLanguageCode = 0x54414D20;
const TUint32 KTeluguScriptCode = 0x74656C75;
const TUint32 KTeluguLanguageCode = 0x54454C20;
const TUint32 KGurmukhiScriptCode = 0x67757275;
const TUint32 KGurmukhiLanguageCode = 0;
const TUint32 KMalayalamScriptCode = 0x6d6c796d;
const TUint32 KMalayalamLanguageCode = 0x4d4c5220;


_LIT16(KDelimiter, "|");

//RTest Macros etc
static RTest TheTest(_L("T_SHAP_createTestData"));
static void Check(TInt aValue, TInt aLine)
	{
	if(!aValue)
		{
		TheTest(EFalse, aLine);
		}
	}

static  void Check(TInt aValue, TInt aExpected, TInt aLine)
	{
	if(aValue != aExpected)
		{
		RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
		TheTest(EFalse, aLine);
		}
	}

#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)	
#define TEST(arg) ::Check((arg), __LINE__)

/* 
Used for cleanup of RImplInfoArray implementationArray below 
This method is stolen from FbsTop.cpp
*/
LOCAL_C void ResetAndDestroyRImplInfoPtrArray(TAny* aPtr)
	{
	RImplInfoPtrArray* array = reinterpret_cast <RImplInfoPtrArray*> (aPtr);
	array->ResetAndDestroy();
	}
	
/*
Load all ECOM implemented rasterizer DLLs. 
This method is stolen from CFbTop::LoadOpenFontLibraries()
*/
LOCAL_C void LoadOpenFontLibraries(CFontStore* aFontStore)
	{

	RImplInfoPtrArray implementationArray;
	TCleanupItem cleanup(ResetAndDestroyRImplInfoPtrArray, &implementationArray);
	CleanupStack::PushL(cleanup);
	TInt error;
	TInt ecomerror;
	TInt ecomnotready;
	TUid uid = {KUidOpenFontRasterizerPlunginInterface};

	// Making sure that no race situation arises
	// If ECom is not ready, give it another chance and try again. if it still doesn't work 
	// after the third try, then it just carries on quietly and fails... 
	for (ecomnotready =0; ecomnotready <3; ecomnotready++)
		{
		TRAP(ecomerror,REComSession::ListImplementationsL(uid,implementationArray));
		if (!ecomerror)
			{
			break;
			}
		else
			{
			ecomerror = 0; 	
			User::After(0);
			}
		}

	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,aFontStore->InstallRasterizerL(rasterizer));
   			if (error)
   				delete rasterizer;
   			}
		}
	CleanupStack::PopAndDestroy(&implementationArray); 	

	}
	
LOCAL_C void WriteInputData(RWriteStream& aStream, const TInputData& aInputData)
	{
	//output the input data to the file
	TPtrC input = aInputData.TextInput();
	TInt length = input.Length();
	TInt start = aInputData.iStart;
	if (start < 0)
		start += length;
	TInt end = aInputData.iEnd;
	if (end <= 0)
		end += length;

	aStream.WriteInt16L(length);

	aStream.WriteL(aInputData.TypeFaceName());
	aStream.WriteL(KDelimiter);

	aStream.WriteL(aInputData.FontFilename());
	aStream.WriteL(KDelimiter);
	
	aStream.WriteInt16L(start);
	aStream.WriteL(KDelimiter);
	aStream.WriteInt16L(end);
	aStream.WriteL(KDelimiter);

	aStream.WriteL(input);
	aStream.WriteL(KDelimiter);
	}

static void WriteOutputData(RWriteStream& aStream, const TInputData& aInputData, 
							TUint32 aScript, TUint32 aLanguage)
	{
	//SHAPE THE TEXT

	TPtrC input = aInputData.TextInput();
	TInt length = input.Length();
	TInt start = aInputData.iStart;
	if (start < 0)
		start += length;
	TInt end = aInputData.iEnd;
	if (end <= 0)
		end += length;

	//set up font store and install rasterizer(s)
	CFontStore* fontStore = CFontStore::NewL(&User::Heap());
	fontStore->iKPixelWidthInTwips = 11860;
	fontStore->iKPixelHeightInTwips = 11860;
	CleanupStack::PushL(fontStore);
	LoadOpenFontLibraries(fontStore);

	//add required font file
	TRAPD( err, fontStore->AddFileL(aInputData.FontFilename()) );
	TEST(err==KErrNone);
	
	CBitmapFont* font;
	TFontSpec fontSpec(aInputData.TypeFaceName(), 12);
	fontStore->GetNearestFontToDesignHeightInPixels((CFont*&)font, fontSpec);
	CleanupStack::PushL(font);

	CShaper* theShaper = NULL;
	CShaperFactory* shaperFactory = NULL;

	RImplInfoPtrArray implementationArray;
	TCleanupItem cleanup(ResetAndDestroyRImplInfoPtrArray, &implementationArray);
	CleanupStack::PushL(cleanup);
	TInt error;
	TInt ecomerror;
	TInt ecomnotready;
	TUid uid = {KUidShaperFactoryPlunginInterface};

	// Making sure that no race situation arises between FBserv and Ecom
	// If ECom is not ready, give it another chance and try again. if it still doesn't work 
	// after the third try, then it just carries on quietly and fails... 
	for (ecomnotready =0; ecomnotready <3; ecomnotready++)
		{
       		TRAP(ecomerror,REComSession::ListImplementationsL(uid,implementationArray));
		if (!ecomerror)
			{
			break;
			}
		else
			{
			ecomerror = 0; 	
			User::After(0);
			}
		}

	const TInt availCount = implementationArray.Count();
	for (TInt count=0;count<availCount;++count)
		{
		const CImplementationInformation* info = implementationArray[count];
		TUid shaperFactoryUid = info->ImplementationUid();
 		// Create a shaper factory
 		//CShaperFactory* shaperFactory = 0;
 		TRAP(error,shaperFactory = CShaperFactory::NewL(shaperFactoryUid));
   		TEST2(error, KErrNone);
   			// Create a shaper
   		TRAPD(err, theShaper = shaperFactory->NewShaperL(font, aScript, aLanguage, &User::Heap()));
   		TEST2(err, KErrNone);
    	}
	CleanupStack::PopAndDestroy(&implementationArray); 	

	CleanupStack::PushL(shaperFactory);
	CleanupStack::PushL(theShaper);

	// create the data to be shaped
	// this uses testData, defined in testData.h
	CShaper::TInput shaperInput;
	shaperInput.iText = &input;
	shaperInput.iStart = start;
	shaperInput.iEnd = end;

	TShapeHeader* output = NULL;
	err = theShaper->ShapeText(output, shaperInput, &User::Heap());
	TEST2(err,KErrNone);
	CleanupStack::PushL(output);
	
	
	//AND FILL THE FILE UP WITH THE RESULTS
	
	//first the glyph count
	aStream.WriteInt16L(output->iGlyphCount);
	TInt glyphCount(output->iGlyphCount);
	TInt i;
	
	//then the Glyphs
	TUint32* shapePtr32 = (reinterpret_cast<TUint32*>(&output->iBuffer[0]));
	for(i=0; i <glyphCount; i++)
		{
		aStream.WriteInt32L(*shapePtr32);
		shapePtr32++;
		}
	
	//then the X and Y positions
	TUint16* shapePtr16 = (reinterpret_cast<TUint16*>(shapePtr32));
	for(i=0; i<glyphCount*2; i++)
		{
		aStream.WriteInt16L(*shapePtr16);
		shapePtr16++;		
		}
	
  	//then the advance
  	aStream.WriteInt16L(*shapePtr16);
	shapePtr16++;		
  	aStream.WriteInt16L(*shapePtr16);
	shapePtr16++;		
 	
	//then the indices
	for(i=0; i<glyphCount; i++)
		{
		aStream.WriteInt16L(*shapePtr16);
		shapePtr16++;		
		}	
	
	//then the character count
	aStream.WriteInt16L(output->iCharacterCount);

	CleanupStack::PopAndDestroy(output);
	CleanupStack::PopAndDestroy(theShaper);
	CleanupStack::PopAndDestroy(shaperFactory);
	REComSession::FinalClose();

	CleanupStack::Pop(font);  
	fontStore->ReleaseFont(font);
	CleanupStack::PopAndDestroy(fontStore);

	//close the ecom session opened by LoadOpenFontLibraries()
	REComSession::FinalClose();
	}

static void MainL()
	{
	RFs fs;
	RFile file;
	RFileBuf buf;

	// Create the Devanagari test data files
	const TInt numberOfTests
		= sizeof(TNR_Dev_OTInputData)/sizeof(TNR_Dev_OTInputData[0]);
	for (TInt i = 0; i != numberOfTests; ++i)
		{
		const TInputData& data = TNR_Dev_OTInputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		// note this uses RFile::Create so that users of this utility cannot accidentally write over
		// files created before. If this test fails, you need to ensure that the file specified by 
		// KFileName is correct, and if so delete it before running this utility.
		TEST2(file.Create(fs, data.OutputFilename(), EFileWrite), KErrNone);
				
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);

		//write to the stream
		WriteInputData(stream, data);
		WriteOutputData(stream, data, KDevanagariScriptCode, KHindiLanguageCode);

		CleanupStack::PopAndDestroy(2);	//buf, fs
		}
	
	// Create the Kannada test data files
	const TInt numberOfKanTests = sizeof(Kannada_InputData)/sizeof(Kannada_InputData[0]);
	for (TInt i = 0; i != numberOfKanTests; i++)
		{
		const TInputData& kan_data = Kannada_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, kan_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, kan_data);
		WriteOutputData(stream, kan_data, KKannadaScriptCode, KKannadaLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}

	
	// Create the Gujarati test data files
	const TInt numberOfGujTests = sizeof(Gujarati_InputData)/sizeof(Gujarati_InputData[0]);
	for (TInt i = 0; i != numberOfGujTests; i++)
		{
		const TInputData& kan_data = Gujarati_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, kan_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, kan_data);
		WriteOutputData(stream, kan_data, KGujaratiScriptCode, KGujaratiLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}
	
	
	// Create the Bengali test data files
	const TInt numberOfBenTests = sizeof(Bengali_InputData)/sizeof(Bengali_InputData[0]);
	for (TInt i = 0; i != numberOfBenTests; i++)
		{
		const TInputData& ben_data = Bengali_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, ben_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, ben_data);
		WriteOutputData(stream, ben_data, KBengaliScriptCode, KBengaliLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}
	
	// Create the Tamil test data files
	const TInt numberOfTamTests = sizeof(Tamil_InputData)/sizeof(Tamil_InputData[0]);
	for (TInt i = 0; i != numberOfTamTests; i++)
		{
		const TInputData& tam_data = Tamil_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, tam_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, tam_data);
		WriteOutputData(stream, tam_data, KTamilScriptCode, KTamilLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}
	
	// Create the Telugu test data files
	const TInt numberOfTelTests = sizeof(Telugu_InputData)/sizeof(Telugu_InputData[0]);
	for (TInt i = 0; i != numberOfTelTests; i++)
		{
		const TInputData& tel_data = Telugu_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, tel_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, tel_data);
		WriteOutputData(stream, tel_data, KTeluguScriptCode, KTeluguLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}
	
	// Create the Gurmukhi test data files
	const TInt numberOfGurTests = sizeof(Gurmukhi_InputData)/sizeof(Gurmukhi_InputData[0]);
	for (TInt i = 0; i != numberOfGurTests; i++)
		{
		const TInputData& tel_data = Gurmukhi_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, tel_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, tel_data);
		WriteOutputData(stream, tel_data, KGurmukhiScriptCode, KGurmukhiLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}
	
	// 	Create the Malayalam test data files
	const TInt numberOfMalaTests = sizeof(Malayalam_InputData)/sizeof(Malayalam_InputData[0]);
	for (TInt i = 0; i != numberOfMalaTests; i++)
		{
		const TInputData& tel_data = Malayalam_InputData[i];
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEST2(file.Create(fs, tel_data.OutputFilename(), EFileWrite), KErrNone);
		CleanupClosePushL(buf);
		buf.Attach(file);
		RWriteStream stream(&buf);
			
		WriteInputData(stream, tel_data);
		WriteOutputData(stream, tel_data, KMalayalamScriptCode, KMalayalamLanguageCode);
		
		CleanupStack::PopAndDestroy(2);
		}
	}

TInt E32Main()
	{
	__UHEAP_MARK;
		
	CTrapCleanup* cleanup = CTrapCleanup::New();
	if(!cleanup)
		return KErrNoMemory;
	
	TRAPD(err, MainL());
	TEST2(err, KErrNone);
	
	delete cleanup;
	__UHEAP_MARKEND;

	return KErrNone;
	}