sl@0: /*
sl@0: * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: * All rights reserved.
sl@0: * This component and the accompanying materials are made available
sl@0: * under the terms of "Eclipse Public License v1.0"
sl@0: * which accompanies this distribution, and is available
sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: *
sl@0: * Initial Contributors:
sl@0: * Nokia Corporation - initial contribution.
sl@0: *
sl@0: * Contributors:
sl@0: *
sl@0: * Description: 
sl@0: * Implementation of CIcuLayoutEngine
sl@0: * This is a CShaper using the Icu Layout Engine.
sl@0: *
sl@0: */
sl@0: 
sl@0: // System includes
sl@0: #include <e32base.h>
sl@0: #include <gdi.h>
sl@0: #include <e32math.h>
sl@0: #include <openfont.h>
sl@0: #include <fntstore.h>
sl@0: 
sl@0: // ICU includes
sl@0: #include "math.h"
sl@0: #include "LETypes.h"
sl@0: #include "LEScripts.h"
sl@0: #include "LELanguages.h"
sl@0: #include "LayoutEngine.h"
sl@0: #include "SymbianFontInstance.h"
sl@0: 
sl@0: #include "IcuLayoutEngine.h"
sl@0: 
sl@0: // Icu namespace
sl@0: U_NAMESPACE_USE
sl@0: 
sl@0: // Convert from float to int rounding to the nearest integer
sl@0: inline TInt FloatToInt(float a)
sl@0: 	{
sl@0: 	return a < 0? static_cast<TInt>(a - 0.5) : static_cast<TInt>(a + 0.5);
sl@0: 	}
sl@0: 
sl@0: /** Array of Script Codes that need to be translated into LEScriptCodes for the 
sl@0: construction of the LayoutEngine. */
sl@0: const LETag scriptCodes[] = {
sl@0:     zyyyScriptTag, /* 'zyyy' (COMMON) */
sl@0:     qaaiScriptTag, /* 'qaai' (INHERITED) */
sl@0:     arabScriptTag, /* 'arab' (ARABIC) */
sl@0:     armnScriptTag, /* 'armn' (ARMENIAN) */
sl@0:     bengScriptTag, /* 'beng' (BENGALI) */
sl@0:     bopoScriptTag, /* 'bopo' (BOPOMOFO) */
sl@0:     cherScriptTag, /* 'cher' (CHEROKEE) */
sl@0:     qaacScriptTag, /* 'qaac' (COPTIC) */
sl@0:     cyrlScriptTag, /* 'cyrl' (CYRILLIC) */
sl@0:     dsrtScriptTag, /* 'dsrt' (DESERET) */
sl@0:     devaScriptTag, /* 'deva' (DEVANAGARI) */
sl@0:     ethiScriptTag, /* 'ethi' (ETHIOPIC) */
sl@0:     georScriptTag, /* 'geor' (GEORGIAN) */
sl@0:     gothScriptTag, /* 'goth' (GOTHIC) */
sl@0:     grekScriptTag, /* 'grek' (GREEK) */
sl@0:     gujrScriptTag, /* 'gujr' (GUJARATI) */
sl@0:     guruScriptTag, /* 'guru' (GURMUKHI) */
sl@0:     haniScriptTag, /* 'hani' (HAN) */
sl@0:     hangScriptTag, /* 'hang' (HANGUL) */
sl@0:     hebrScriptTag, /* 'hebr' (HEBREW) */
sl@0:     hiraScriptTag, /* 'hira' (HIRAGANA) */
sl@0:     kndaScriptTag, /* 'knda' (KANNADA) */
sl@0:     kanaScriptTag, /* 'kana' (KATAKANA) */
sl@0:     khmrScriptTag, /* 'khmr' (KHMER) */
sl@0:     laooScriptTag, /* 'laoo' (LAO) */
sl@0:     latnScriptTag, /* 'latn' (LATIN) */
sl@0:     mlymScriptTag, /* 'mlym' (MALAYALAM) */
sl@0:     mongScriptTag, /* 'mong' (MONGOLIAN) */
sl@0:     mymrScriptTag, /* 'mymr' (MYANMAR) */
sl@0:     ogamScriptTag, /* 'ogam' (OGHAM) */
sl@0:     italScriptTag, /* 'ital' (OLD_ITALIC) */
sl@0:     oryaScriptTag, /* 'orya' (ORIYA) */
sl@0:     runrScriptTag, /* 'runr' (RUNIC) */
sl@0:     sinhScriptTag, /* 'sinh' (SINHALA) */
sl@0:     syrcScriptTag, /* 'syrc' (SYRIAC) */
sl@0:     tamlScriptTag, /* 'taml' (TAMIL) */
sl@0:     teluScriptTag, /* 'telu' (TELUGU) */
sl@0:     thaaScriptTag, /* 'thaa' (THAANA) */
sl@0:     thaiScriptTag, /* 'thai' (THAI) */
sl@0:     tibtScriptTag, /* 'tibt' (TIBETAN) */
sl@0:     cansScriptTag, /* 'cans' (CANADIAN_ABORIGINAL) */
sl@0:     yiiiScriptTag, /* 'yiii' (YI) */
sl@0:     tglgScriptTag, /* 'tglg' (TAGALOG) */
sl@0:     hanoScriptTag, /* 'hano' (HANUNOO) */
sl@0:     buhdScriptTag, /* 'buhd' (BUHID) */
sl@0:     tagbScriptTag, /* 'tagb' (TAGBANWA) */
sl@0:     braiScriptTag, /* 'brai' (BRAILLE) */
sl@0:     cprtScriptTag, /* 'cprt' (CYPRIOT) */
sl@0:     limbScriptTag, /* 'limb' (LIMBU) */
sl@0:     linbScriptTag, /* 'linb' (LINEAR_B) */
sl@0:     osmaScriptTag, /* 'osma' (OSMANYA) */
sl@0:     shawScriptTag, /* 'shaw' (SHAVIAN) */
sl@0:     taleScriptTag, /* 'tale' (TAI_LE) */
sl@0:     ugarScriptTag, /* 'ugar' (UGARITIC) */
sl@0:     hrktScriptTag  /* 'hrkt' (KATAKANA_OR_HIRAGANA) */
sl@0: };
sl@0: 
sl@0: /** Array of Language Codes that need to be translated into LELanguageCodes for the 
sl@0: construction of the LayoutEngine. */
sl@0: const LETag languageCodes[] = {
sl@0:     nullLanguageTag, /* '' (null) */
sl@0:     araLanguageTag, /* 'ARA' (Arabic) */
sl@0:     asmLanguageTag, /* 'ASM' (Assamese) */
sl@0:     benLanguageTag, /* 'BEN' (Bengali) */
sl@0:     farLanguageTag, /* 'FAR' (Farsi) */
sl@0:     gujLanguageTag, /* 'GUJ' (Gujarati) */
sl@0:     hinLanguageTag, /* 'HIN' (Hindi) */
sl@0:     iwrLanguageTag, /* 'IWR' (Hebrew) */
sl@0:     jiiLanguageTag, /* 'JII' (Yiddish) */
sl@0:     janLanguageTag, /* 'JAN' (Japanese) */
sl@0:     kanLanguageTag, /* 'KAN' (Kannada) */
sl@0:     kokLanguageTag, /* 'KOK' (Konkani) */
sl@0:     korLanguageTag, /* 'KOR' (Korean) */
sl@0:     kshLanguageTag, /* 'KSH' (Kashmiri) */
sl@0:     malLanguageTag, /* 'MAL' (Malayalam (Traditional)) */
sl@0:     marLanguageTag, /* 'MAR' (Marathi) */
sl@0:     mlrLanguageTag, /* 'MLR' (Malayalam (Reformed)) */
sl@0:     mniLanguageTag, /* 'MNI' (Manipuri) */
sl@0:     oriLanguageTag, /* 'ORI' (Oriya) */
sl@0:     sanLanguageTag, /* 'SAN' (Sanscrit) */
sl@0:     sndLanguageTag, /* 'SND' (Sindhi) */
sl@0:     snhLanguageTag, /* 'SNH' (Sinhalese) */
sl@0:     syrLanguageTag, /* 'SYR' (Syriac) */
sl@0:     tamLanguageTag, /* 'TAM' (Tamil) */
sl@0:     telLanguageTag, /* 'TEL' (Telugu) */
sl@0:     thaLanguageTag, /* 'THA' (Thai) */
sl@0:     urdLanguageTag, /* 'URD' (Urdu) */
sl@0:     zhpLanguageTag, /* 'ZHP' (Chinese (Phonetic)) */
sl@0:     zhsLanguageTag, /* 'ZHS' (Chinese (Simplified)) */
sl@0:     zhtLanguageTag  /* 'ZHT' (Chinese (Traditional)) */
sl@0: };
sl@0: 
sl@0: /**
sl@0: Translate the script code passed in to a LEScriptCode
sl@0: */ 
sl@0: TInt ScriptCode(TUint32 aScript)
sl@0: 	{
sl@0: 	TInt scriptCode = -1;
sl@0:     for (TInt i= 0; i < scriptCodeCount; i++)
sl@0:     	{
sl@0:     	if (scriptCodes[i] == aScript)
sl@0:     		{
sl@0:     		scriptCode = i;
sl@0:     		break;
sl@0:     		}
sl@0:     	}
sl@0:     return scriptCode;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: Translate the language code passed in to a LELanguageCode
sl@0: */
sl@0: TInt LanguageCode(TUint32 aLanguage)
sl@0: 	{
sl@0: 	TInt languageCode = -1;
sl@0:     for (TInt i= 0; i < languageCodeCount; i++)
sl@0:     	{
sl@0:     	if (languageCodes[i] == aLanguage)
sl@0:     		{
sl@0:     		languageCode = i;
sl@0:     		break;
sl@0:     		}
sl@0:     	}
sl@0:     return languageCode;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Create a instance of CIcuLayoutEngine
sl@0: @param aBitmapFont The required font.
sl@0: @param aHeap The heap to be used for storage by the engine.
sl@0: @return A pointer to the new CIcuLayoutEngine instance.
sl@0: */
sl@0: CShaper * CIcuLayoutEngine::NewL(CBitmapFont* aBitmapFont, TInt aScript, TInt aLanguage, RHeap* aHeap)
sl@0: 	{
sl@0: 	CIcuLayoutEngine* newShaper = new(ELeave)CIcuLayoutEngine(aScript, aLanguage);
sl@0: 	CleanupStack::PushL(newShaper);
sl@0: 	newShaper->ConstructL(aBitmapFont, aScript, aLanguage, aHeap);
sl@0: 	CleanupStack::Pop(); // newShaper
sl@0: 	return newShaper;	
sl@0: 	} 
sl@0: 
sl@0: 
sl@0: /**
sl@0: Construct an instance of CIcuLayoutEngine 	
sl@0: @param aBitMapFont The required font
sl@0: @param aHeap The heap to be used for storage by the engine
sl@0: @return incase of exceptions with an Error Code
sl@0: @see CShaper
sl@0:  */
sl@0: TInt  CIcuLayoutEngine::ConstructL(CBitmapFont* aBitMapFont, TInt aScript, TInt aLanguage, RHeap* aHeap )
sl@0: 	{
sl@0: 	// allocate a block of memory from aHeap for the layout engine 
sl@0: 	// which is accessed via the Umemory class
sl@0: 	iClientHeap = aHeap;
sl@0: 
sl@0: 	// this needs to be on the heap
sl@0: 	LEErrorCode fontStatus = LE_NO_ERROR;
sl@0: 	iFontInstance = new SymbianFontInstance(aBitMapFont, fontStatus, aScript == mlymScriptTag);
sl@0: 	if(NULL == iFontInstance)
sl@0: 		{
sl@0: 		User::Leave(KErrGeneral);
sl@0: 		}
sl@0: 	if (fontStatus == LE_MEMORY_ALLOCATION_ERROR)
sl@0:    		{
sl@0:    		User::Leave(KErrNoMemory);
sl@0:    		} 	
sl@0:    	else if (fontStatus != LE_NO_ERROR)
sl@0:    		{
sl@0:    		//note this leave may actually be caused by OOM situations, 
sl@0:    		//due to the way errors codes are handled in the open source code
sl@0:    		User::Leave(KErrGeneral);
sl@0:    	 	}
sl@0:    	 	
sl@0: 
sl@0:  	// create and initialise a ICU layout Engine
sl@0: 	// Note the engine is created using the Umemory heap 
sl@0:     LEErrorCode success = LE_NO_ERROR;
sl@0:     
sl@0:     // Translate the script code into an LEScriptCode
sl@0:     TInt scriptCode = ScriptCode(aScript);
sl@0:     
sl@0:     // Translate the language code into an LELanguageCode
sl@0:     TInt languageCode = LanguageCode(aLanguage);
sl@0:     
sl@0:     // Finally instantiate the LayoutEngine    
sl@0: 	iEngine = LayoutEngine::layoutEngineFactory(iFontInstance, scriptCode, languageCode, success); 
sl@0: 
sl@0: 	// For debugging - check the total memory used by construction
sl@0: #ifdef SHAPER_MEMORY_DEBUG
sl@0: 	TInt totalAllocSize = 0;
sl@0: 	TInt used = iHeap->AllocSize(totalAllocSize);
sl@0: 	RDebug::Print(_L("shaper construction %d cells %d"), totalAllocSize, used);
sl@0: #endif
sl@0: 
sl@0: 	if (success == LE_MEMORY_ALLOCATION_ERROR)
sl@0: 		{
sl@0: 		User::Leave(KErrNoMemory);	
sl@0: 		}
sl@0: 	else if (success != LE_NO_ERROR)
sl@0: 		{
sl@0:  		//note this leave may actually be caused by OOM situations, 
sl@0:  		//due to the way errors codes are handled in the open source code
sl@0:  		User::Leave(KErrGeneral);
sl@0: 		}
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 
sl@0: CIcuLayoutEngine::CIcuLayoutEngine(TUint32 aScript, TUint32 aLanguage):
sl@0: 	iScript(aScript),
sl@0: 	iLanguage(aLanguage)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0:  Frees all resources owned by ...
sl@0:  */
sl@0:  CIcuLayoutEngine::~CIcuLayoutEngine()
sl@0: 	{
sl@0: 	// delete the engine instance
sl@0: 	if ( iEngine )
sl@0: 		{
sl@0: 		delete( iEngine );
sl@0: 		}
sl@0: 		
sl@0: 	// delete the font instance from client heap
sl@0: 	delete( iFontInstance );
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Returns the script and the language this shaper has been instansiated with.
sl@0: */	
sl@0: void* CIcuLayoutEngine::ExtendedInterface (TUid aInterfaceId)
sl@0: 	{
sl@0: 	if (aInterfaceId == KUidShaperGetScript)		
sl@0: 		return (TUint32*)iScript;
sl@0: 	else
sl@0: 		if (aInterfaceId == KUidShaperGetLang)
sl@0: 			return (TUint32*)iLanguage;
sl@0: 		else
sl@0: 			return CShaper::ExtendedInterface(aInterfaceId);			
sl@0: 	}
sl@0: 	
sl@0: /** This is implementation of CShaper::ShapeText for the Icu layout Engine
sl@0:  The data is taken from TInput and pass to the shaper.
sl@0:  A memory buffer is allocated on aHeapForOutput starting with TShapeHeader is allocated.
sl@0:  The results of the shaping are copied into this buffer and passed back via aOutput. 
sl@0:  @param aOutput On success a new structure containing the results allocated on aHeapForOutput.  
sl@0:  @param aInput The input text and other parameters.
sl@0:  @param aHeapForOutput On success, aOutput should be allocated from this and nothing else. 
sl@0:  		On failure, nothing should be allocated from it.
sl@0:  @return Error value from one of the system-wide error codes on	failure, KErrNone on success.
sl@0:  @see CShaper::ShapeText
sl@0:  */		
sl@0: TInt CIcuLayoutEngine::ShapeText(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
sl@0: 	{
sl@0: 	// For debugging - the heap before shaping
sl@0: 	TInt totalAllocSize = 0;
sl@0: 	TInt used;
sl@0: #ifdef SHAPER_MEMORY_DEBUG
sl@0: 	used = User::Heap().AllocSize(totalAllocSize);
sl@0: 	RDebug::Print(_L("before shaping %d cells %d bytes used"), used, totalAllocSize);
sl@0: #endif
sl@0: 
sl@0: 	iFontInstance->SetSessionHandle(aInput.iSessionHandle);
sl@0: 	TRAPD( error, IcuShapeTextL(aOutput, aInput, aHeapForOutput));
sl@0: 	if (error == KErrNoMemory)
sl@0: 		{
sl@0: 		used = User::Heap().AllocSize(totalAllocSize);
sl@0: 		RDebug::Print(_L("shaper out of memory %d cells %d"), totalAllocSize, used);
sl@0: 		}
sl@0: 
sl@0: #ifdef SHAPER_MEMORY_DEBUG
sl@0: 	used = User::Heap().AllocSize(totalAllocSize);
sl@0: 	RDebug::Print(_L("Shaped %d characters %d glyphs "), aOutput->iCharacterCount, aOutput->iGlyphCount );
sl@0: 	RDebug::Print(_L("after shaping %d cells %d bytes used"), used, totalAllocSize);
sl@0: #endif
sl@0: 
sl@0: 	// hide the ICU error codes as KErrGeneral
sl@0: 	if ((error == KErrNoMemory) || (error == KErrNone))
sl@0: 		return error;
sl@0: 	else
sl@0: 		return KErrGeneral;		
sl@0: 	}
sl@0: 
sl@0: /** This calls the ICU Layout engine to shape the text.  It allocates memory for the results
sl@0: and then reads the results.  This memory is freed by the caller.
sl@0: This function can leave if OOM.
sl@0:  @param aOutput On success a new structure containing the results allocated on aHeapForOutput.  
sl@0:  @param aInput The input text and other parameters.
sl@0:  @param aHeapForOutput On success, aOutput should be allocated from this and nothing else. 
sl@0:  		On failure, nothing should be allocated from it.
sl@0:  @return Error value from one of the system-wide error codes on	failure, KErrNone on success.
sl@0:  @see CIcuLayoutEngine::ShapeText
sl@0:  */
sl@0: void  CIcuLayoutEngine::IcuShapeTextL(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
sl@0: 	{
sl@0: 	LEErrorCode success = LE_NO_ERROR;
sl@0: 	const LEUnicode * p = (LEUnicode *)aInput.iText->Ptr();
sl@0: 	TInt noChars = aInput.iEnd - aInput.iStart;
sl@0: 
sl@0: 	// Call to layout  
sl@0: 	TInt noOfGlyphs = iEngine->layoutChars(
sl@0: 			p, 							// chars - the input character context
sl@0: 			aInput.iStart,				// the offset of the first character to process	
sl@0: 			noChars,					// count - the number of characters to process	// offset
sl@0: 			aInput.iText->Length(), 	// max - the number of characters in the input context	// size of text
sl@0: 			FALSE, 						// rightToLeft - TRUE if the characters are in a right to left directional run
sl@0: 			0, 							// start X
sl@0: 			0, 							// start Y
sl@0: 			success);					// result code
sl@0: 
sl@0: 	if (success == LE_MEMORY_ALLOCATION_ERROR)
sl@0: 		User::Leave(KErrNoMemory);
sl@0: 	else if (success != LE_NO_ERROR) 
sl@0: 		{
sl@0: 		User::Leave(KErrGeneral);
sl@0: 		}
sl@0: 	
sl@0: 
sl@0: 	// Get some memory to pass into the layout engine for the results
sl@0: 	TInt bufferSize = (sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(float) * 2)
sl@0: 		* noOfGlyphs + sizeof(float) * 2;
sl@0: 	TUint8* buffer = reinterpret_cast<TUint8*>( User::AllocL(bufferSize) );
sl@0: 	CleanupStack::PushL(buffer);
sl@0: 	LEGlyphID* glyphBuffer = reinterpret_cast<LEGlyphID*>(buffer);
sl@0: 	le_int32* indexBuffer = reinterpret_cast<le_int32*>(glyphBuffer + noOfGlyphs);
sl@0: 	float* positionBuffer = reinterpret_cast<float*>(indexBuffer + noOfGlyphs);
sl@0: 	
sl@0: 	
sl@0: 	// now get results glyph codes, positions and indices
sl@0: 	// from the layout engine
sl@0: 	if (success == LE_NO_ERROR)
sl@0: 		iEngine->getGlyphs(glyphBuffer, success);
sl@0: 
sl@0: 	if (success == LE_NO_ERROR)
sl@0: 		iEngine->getGlyphPositions(positionBuffer, success);
sl@0: 
sl@0: 	if (success == LE_NO_ERROR)
sl@0: 		iEngine->getCharIndices(indexBuffer, aInput.iStart, success);
sl@0: 	if (success == LE_NO_ERROR)
sl@0: 		// Reset the memory used by the IcuLayoutEngine
sl@0: 		iEngine->reset();
sl@0: 	if (success == LE_MEMORY_ALLOCATION_ERROR)
sl@0: 		User::Leave(KErrNoMemory);
sl@0: 	else 
sl@0: 		if (success != LE_NO_ERROR)
sl@0:  			{
sl@0: 			User::Leave(KErrGeneral);
sl@0: 			}
sl@0: 
sl@0: 	// Some of the glyph codes are 0xFFFF and 0x0001. 0xFFFF is a value used by ICU layout
sl@0: 	// engine to indicate no glyph, and 0x0001 is used to indicate a ZWJ or a ZWNJ.
sl@0: 	// These should be stripped out now. A ZWJ or a ZWNJ glyph has no meaning here. Their 
sl@0: 	// effects on the precedig and proceding characters have already been taken into 
sl@0: 	// consideration during shaping, so we don't need them anymore.
sl@0: 	// Also, their presence in the final glyph list was causing GDI to break with GDI:1
sl@0: 	// i.e. more than 8 glyphs in a glyph cluster.
sl@0: 	LEGlyphID gidOfZWJ = iFontInstance->mapCharToGlyph(0x200D); // Added by Symbian: 1922 mlyl
sl@0: 	TInt actualNoOfGlyphs = 0;
sl@0: 	for (LEGlyphID* p = glyphBuffer + noOfGlyphs; p != glyphBuffer;)
sl@0: 		{
sl@0: 		--p;
sl@0: 		if (*p != 0xFFFF && *p != 0x0001 && *p != gidOfZWJ) // Added by Symbian: 1922 mlyl
sl@0: 			++actualNoOfGlyphs;
sl@0: 		}
sl@0: 
sl@0: 	// get some memory to pass back the results,  
sl@0: 	// This needs to be big enough for a TShapeHeader
sl@0: 	// plus 10 bytes for every glyph returned (-1 for the 1 byte allocated in TShapeHeader for iBuffer)
sl@0: 	aOutput = reinterpret_cast<TShapeHeader*>( aHeapForOutput->AllocL(
sl@0: 		sizeof(TShapeHeader) + (actualNoOfGlyphs * 10) + 3) );
sl@0: 
sl@0: 	// get the results into the shaper structure aOutput 
sl@0: 	aOutput->iGlyphCount = actualNoOfGlyphs;
sl@0: 	aOutput->iCharacterCount = noChars;
sl@0:  	aOutput->iReserved0 = 0;
sl@0: 	aOutput->iReserved1 = 0;
sl@0: 
sl@0:  	// iBuffer contains 10 bytes for every glyph
sl@0:  	// the glyph code (4 bytes), position X(2 bytes) Y(2 bytes) and indices(2 bytes)
sl@0:  
sl@0:  	// first is glyph count * 4 byte glyph codes
sl@0:  	TUint32* glyphOut = reinterpret_cast<TUint32*>(aOutput->iBuffer);
sl@0:  	TInt16* posOut = reinterpret_cast<TInt16*>(aOutput->iBuffer +
sl@0:  		(4 * actualNoOfGlyphs));
sl@0:  	TInt16* indicesOut = reinterpret_cast<TInt16*>(aOutput->iBuffer +
sl@0:  		(8 * actualNoOfGlyphs) + 4);
sl@0:  	for (TInt i=0; i < noOfGlyphs; i++)
sl@0:  		{
sl@0:  		if (*glyphBuffer != 0xFFFF && *glyphBuffer != 0x0001 && *glyphBuffer != gidOfZWJ) // Added by Symbian: 1922 mlyl
sl@0:  			{
sl@0: 	  		*glyphOut++ = *glyphBuffer;
sl@0: 			*posOut++ = FloatToInt( positionBuffer[0] );
sl@0: 			*posOut++ = FloatToInt( positionBuffer[1] );
sl@0: 			*indicesOut++ = *indexBuffer;
sl@0:  			}
sl@0:  		++glyphBuffer;
sl@0:  		positionBuffer += 2;
sl@0:  		++indexBuffer;
sl@0: 		}
sl@0: 	// There is an extra pair of positions: this is the total advance
sl@0: 	posOut[0] = FloatToInt( positionBuffer[0] );
sl@0: 	posOut[1] = FloatToInt( positionBuffer[1] );
sl@0: 	
sl@0: 	CleanupStack::PopAndDestroy(buffer);	
sl@0: 	
sl@0: 	}