fontservices/textshaperplugin/source/IcuLayoutEngine.cpp
changeset 0 1fb32624e06b
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 /*
       
     2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 * Implementation of CIcuLayoutEngine
       
    16 * This is a CShaper using the Icu Layout Engine.
       
    17 *
       
    18 */
       
    19 
       
    20 // System includes
       
    21 #include <e32base.h>
       
    22 #include <gdi.h>
       
    23 #include <e32math.h>
       
    24 #include <openfont.h>
       
    25 #include <fntstore.h>
       
    26 
       
    27 // ICU includes
       
    28 #include "math.h"
       
    29 #include "LETypes.h"
       
    30 #include "LEScripts.h"
       
    31 #include "LELanguages.h"
       
    32 #include "LayoutEngine.h"
       
    33 #include "SymbianFontInstance.h"
       
    34 
       
    35 #include "IcuLayoutEngine.h"
       
    36 
       
    37 // Icu namespace
       
    38 U_NAMESPACE_USE
       
    39 
       
    40 // Convert from float to int rounding to the nearest integer
       
    41 inline TInt FloatToInt(float a)
       
    42 	{
       
    43 	return a < 0? static_cast<TInt>(a - 0.5) : static_cast<TInt>(a + 0.5);
       
    44 	}
       
    45 
       
    46 /** Array of Script Codes that need to be translated into LEScriptCodes for the 
       
    47 construction of the LayoutEngine. */
       
    48 const LETag scriptCodes[] = {
       
    49     zyyyScriptTag, /* 'zyyy' (COMMON) */
       
    50     qaaiScriptTag, /* 'qaai' (INHERITED) */
       
    51     arabScriptTag, /* 'arab' (ARABIC) */
       
    52     armnScriptTag, /* 'armn' (ARMENIAN) */
       
    53     bengScriptTag, /* 'beng' (BENGALI) */
       
    54     bopoScriptTag, /* 'bopo' (BOPOMOFO) */
       
    55     cherScriptTag, /* 'cher' (CHEROKEE) */
       
    56     qaacScriptTag, /* 'qaac' (COPTIC) */
       
    57     cyrlScriptTag, /* 'cyrl' (CYRILLIC) */
       
    58     dsrtScriptTag, /* 'dsrt' (DESERET) */
       
    59     devaScriptTag, /* 'deva' (DEVANAGARI) */
       
    60     ethiScriptTag, /* 'ethi' (ETHIOPIC) */
       
    61     georScriptTag, /* 'geor' (GEORGIAN) */
       
    62     gothScriptTag, /* 'goth' (GOTHIC) */
       
    63     grekScriptTag, /* 'grek' (GREEK) */
       
    64     gujrScriptTag, /* 'gujr' (GUJARATI) */
       
    65     guruScriptTag, /* 'guru' (GURMUKHI) */
       
    66     haniScriptTag, /* 'hani' (HAN) */
       
    67     hangScriptTag, /* 'hang' (HANGUL) */
       
    68     hebrScriptTag, /* 'hebr' (HEBREW) */
       
    69     hiraScriptTag, /* 'hira' (HIRAGANA) */
       
    70     kndaScriptTag, /* 'knda' (KANNADA) */
       
    71     kanaScriptTag, /* 'kana' (KATAKANA) */
       
    72     khmrScriptTag, /* 'khmr' (KHMER) */
       
    73     laooScriptTag, /* 'laoo' (LAO) */
       
    74     latnScriptTag, /* 'latn' (LATIN) */
       
    75     mlymScriptTag, /* 'mlym' (MALAYALAM) */
       
    76     mongScriptTag, /* 'mong' (MONGOLIAN) */
       
    77     mymrScriptTag, /* 'mymr' (MYANMAR) */
       
    78     ogamScriptTag, /* 'ogam' (OGHAM) */
       
    79     italScriptTag, /* 'ital' (OLD_ITALIC) */
       
    80     oryaScriptTag, /* 'orya' (ORIYA) */
       
    81     runrScriptTag, /* 'runr' (RUNIC) */
       
    82     sinhScriptTag, /* 'sinh' (SINHALA) */
       
    83     syrcScriptTag, /* 'syrc' (SYRIAC) */
       
    84     tamlScriptTag, /* 'taml' (TAMIL) */
       
    85     teluScriptTag, /* 'telu' (TELUGU) */
       
    86     thaaScriptTag, /* 'thaa' (THAANA) */
       
    87     thaiScriptTag, /* 'thai' (THAI) */
       
    88     tibtScriptTag, /* 'tibt' (TIBETAN) */
       
    89     cansScriptTag, /* 'cans' (CANADIAN_ABORIGINAL) */
       
    90     yiiiScriptTag, /* 'yiii' (YI) */
       
    91     tglgScriptTag, /* 'tglg' (TAGALOG) */
       
    92     hanoScriptTag, /* 'hano' (HANUNOO) */
       
    93     buhdScriptTag, /* 'buhd' (BUHID) */
       
    94     tagbScriptTag, /* 'tagb' (TAGBANWA) */
       
    95     braiScriptTag, /* 'brai' (BRAILLE) */
       
    96     cprtScriptTag, /* 'cprt' (CYPRIOT) */
       
    97     limbScriptTag, /* 'limb' (LIMBU) */
       
    98     linbScriptTag, /* 'linb' (LINEAR_B) */
       
    99     osmaScriptTag, /* 'osma' (OSMANYA) */
       
   100     shawScriptTag, /* 'shaw' (SHAVIAN) */
       
   101     taleScriptTag, /* 'tale' (TAI_LE) */
       
   102     ugarScriptTag, /* 'ugar' (UGARITIC) */
       
   103     hrktScriptTag  /* 'hrkt' (KATAKANA_OR_HIRAGANA) */
       
   104 };
       
   105 
       
   106 /** Array of Language Codes that need to be translated into LELanguageCodes for the 
       
   107 construction of the LayoutEngine. */
       
   108 const LETag languageCodes[] = {
       
   109     nullLanguageTag, /* '' (null) */
       
   110     araLanguageTag, /* 'ARA' (Arabic) */
       
   111     asmLanguageTag, /* 'ASM' (Assamese) */
       
   112     benLanguageTag, /* 'BEN' (Bengali) */
       
   113     farLanguageTag, /* 'FAR' (Farsi) */
       
   114     gujLanguageTag, /* 'GUJ' (Gujarati) */
       
   115     hinLanguageTag, /* 'HIN' (Hindi) */
       
   116     iwrLanguageTag, /* 'IWR' (Hebrew) */
       
   117     jiiLanguageTag, /* 'JII' (Yiddish) */
       
   118     janLanguageTag, /* 'JAN' (Japanese) */
       
   119     kanLanguageTag, /* 'KAN' (Kannada) */
       
   120     kokLanguageTag, /* 'KOK' (Konkani) */
       
   121     korLanguageTag, /* 'KOR' (Korean) */
       
   122     kshLanguageTag, /* 'KSH' (Kashmiri) */
       
   123     malLanguageTag, /* 'MAL' (Malayalam (Traditional)) */
       
   124     marLanguageTag, /* 'MAR' (Marathi) */
       
   125     mlrLanguageTag, /* 'MLR' (Malayalam (Reformed)) */
       
   126     mniLanguageTag, /* 'MNI' (Manipuri) */
       
   127     oriLanguageTag, /* 'ORI' (Oriya) */
       
   128     sanLanguageTag, /* 'SAN' (Sanscrit) */
       
   129     sndLanguageTag, /* 'SND' (Sindhi) */
       
   130     snhLanguageTag, /* 'SNH' (Sinhalese) */
       
   131     syrLanguageTag, /* 'SYR' (Syriac) */
       
   132     tamLanguageTag, /* 'TAM' (Tamil) */
       
   133     telLanguageTag, /* 'TEL' (Telugu) */
       
   134     thaLanguageTag, /* 'THA' (Thai) */
       
   135     urdLanguageTag, /* 'URD' (Urdu) */
       
   136     zhpLanguageTag, /* 'ZHP' (Chinese (Phonetic)) */
       
   137     zhsLanguageTag, /* 'ZHS' (Chinese (Simplified)) */
       
   138     zhtLanguageTag  /* 'ZHT' (Chinese (Traditional)) */
       
   139 };
       
   140 
       
   141 /**
       
   142 Translate the script code passed in to a LEScriptCode
       
   143 */ 
       
   144 TInt ScriptCode(TUint32 aScript)
       
   145 	{
       
   146 	TInt scriptCode = -1;
       
   147     for (TInt i= 0; i < scriptCodeCount; i++)
       
   148     	{
       
   149     	if (scriptCodes[i] == aScript)
       
   150     		{
       
   151     		scriptCode = i;
       
   152     		break;
       
   153     		}
       
   154     	}
       
   155     return scriptCode;
       
   156 	}
       
   157 	
       
   158 /**
       
   159 Translate the language code passed in to a LELanguageCode
       
   160 */
       
   161 TInt LanguageCode(TUint32 aLanguage)
       
   162 	{
       
   163 	TInt languageCode = -1;
       
   164     for (TInt i= 0; i < languageCodeCount; i++)
       
   165     	{
       
   166     	if (languageCodes[i] == aLanguage)
       
   167     		{
       
   168     		languageCode = i;
       
   169     		break;
       
   170     		}
       
   171     	}
       
   172     return languageCode;
       
   173 	}
       
   174 
       
   175 /**
       
   176 Create a instance of CIcuLayoutEngine
       
   177 @param aBitmapFont The required font.
       
   178 @param aHeap The heap to be used for storage by the engine.
       
   179 @return A pointer to the new CIcuLayoutEngine instance.
       
   180 */
       
   181 CShaper * CIcuLayoutEngine::NewL(CBitmapFont* aBitmapFont, TInt aScript, TInt aLanguage, RHeap* aHeap)
       
   182 	{
       
   183 	CIcuLayoutEngine* newShaper = new(ELeave)CIcuLayoutEngine(aScript, aLanguage);
       
   184 	CleanupStack::PushL(newShaper);
       
   185 	newShaper->ConstructL(aBitmapFont, aScript, aLanguage, aHeap);
       
   186 	CleanupStack::Pop(); // newShaper
       
   187 	return newShaper;	
       
   188 	} 
       
   189 
       
   190 
       
   191 /**
       
   192 Construct an instance of CIcuLayoutEngine 	
       
   193 @param aBitMapFont The required font
       
   194 @param aHeap The heap to be used for storage by the engine
       
   195 @return incase of exceptions with an Error Code
       
   196 @see CShaper
       
   197  */
       
   198 TInt  CIcuLayoutEngine::ConstructL(CBitmapFont* aBitMapFont, TInt aScript, TInt aLanguage, RHeap* aHeap )
       
   199 	{
       
   200 	// allocate a block of memory from aHeap for the layout engine 
       
   201 	// which is accessed via the Umemory class
       
   202 	iClientHeap = aHeap;
       
   203 
       
   204 	// this needs to be on the heap
       
   205 	LEErrorCode fontStatus = LE_NO_ERROR;
       
   206 	iFontInstance = new SymbianFontInstance(aBitMapFont, fontStatus, aScript == mlymScriptTag);
       
   207 	if(NULL == iFontInstance)
       
   208 		{
       
   209 		User::Leave(KErrGeneral);
       
   210 		}
       
   211 	if (fontStatus == LE_MEMORY_ALLOCATION_ERROR)
       
   212    		{
       
   213    		User::Leave(KErrNoMemory);
       
   214    		} 	
       
   215    	else if (fontStatus != LE_NO_ERROR)
       
   216    		{
       
   217    		//note this leave may actually be caused by OOM situations, 
       
   218    		//due to the way errors codes are handled in the open source code
       
   219    		User::Leave(KErrGeneral);
       
   220    	 	}
       
   221    	 	
       
   222 
       
   223  	// create and initialise a ICU layout Engine
       
   224 	// Note the engine is created using the Umemory heap 
       
   225     LEErrorCode success = LE_NO_ERROR;
       
   226     
       
   227     // Translate the script code into an LEScriptCode
       
   228     TInt scriptCode = ScriptCode(aScript);
       
   229     
       
   230     // Translate the language code into an LELanguageCode
       
   231     TInt languageCode = LanguageCode(aLanguage);
       
   232     
       
   233     // Finally instantiate the LayoutEngine    
       
   234 	iEngine = LayoutEngine::layoutEngineFactory(iFontInstance, scriptCode, languageCode, success); 
       
   235 
       
   236 	// For debugging - check the total memory used by construction
       
   237 #ifdef SHAPER_MEMORY_DEBUG
       
   238 	TInt totalAllocSize = 0;
       
   239 	TInt used = iHeap->AllocSize(totalAllocSize);
       
   240 	RDebug::Print(_L("shaper construction %d cells %d"), totalAllocSize, used);
       
   241 #endif
       
   242 
       
   243 	if (success == LE_MEMORY_ALLOCATION_ERROR)
       
   244 		{
       
   245 		User::Leave(KErrNoMemory);	
       
   246 		}
       
   247 	else if (success != LE_NO_ERROR)
       
   248 		{
       
   249  		//note this leave may actually be caused by OOM situations, 
       
   250  		//due to the way errors codes are handled in the open source code
       
   251  		User::Leave(KErrGeneral);
       
   252 		}
       
   253 	return KErrNone;
       
   254 	}
       
   255 
       
   256 CIcuLayoutEngine::CIcuLayoutEngine(TUint32 aScript, TUint32 aLanguage):
       
   257 	iScript(aScript),
       
   258 	iLanguage(aLanguage)
       
   259 	{
       
   260 	}
       
   261 
       
   262 /** 
       
   263  Frees all resources owned by ...
       
   264  */
       
   265  CIcuLayoutEngine::~CIcuLayoutEngine()
       
   266 	{
       
   267 	// delete the engine instance
       
   268 	if ( iEngine )
       
   269 		{
       
   270 		delete( iEngine );
       
   271 		}
       
   272 		
       
   273 	// delete the font instance from client heap
       
   274 	delete( iFontInstance );
       
   275 	}
       
   276 
       
   277 /**
       
   278 Returns the script and the language this shaper has been instansiated with.
       
   279 */	
       
   280 void* CIcuLayoutEngine::ExtendedInterface (TUid aInterfaceId)
       
   281 	{
       
   282 	if (aInterfaceId == KUidShaperGetScript)		
       
   283 		return (TUint32*)iScript;
       
   284 	else
       
   285 		if (aInterfaceId == KUidShaperGetLang)
       
   286 			return (TUint32*)iLanguage;
       
   287 		else
       
   288 			return CShaper::ExtendedInterface(aInterfaceId);			
       
   289 	}
       
   290 	
       
   291 /** This is implementation of CShaper::ShapeText for the Icu layout Engine
       
   292  The data is taken from TInput and pass to the shaper.
       
   293  A memory buffer is allocated on aHeapForOutput starting with TShapeHeader is allocated.
       
   294  The results of the shaping are copied into this buffer and passed back via aOutput. 
       
   295  @param aOutput On success a new structure containing the results allocated on aHeapForOutput.  
       
   296  @param aInput The input text and other parameters.
       
   297  @param aHeapForOutput On success, aOutput should be allocated from this and nothing else. 
       
   298  		On failure, nothing should be allocated from it.
       
   299  @return Error value from one of the system-wide error codes on	failure, KErrNone on success.
       
   300  @see CShaper::ShapeText
       
   301  */		
       
   302 TInt CIcuLayoutEngine::ShapeText(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
       
   303 	{
       
   304 	// For debugging - the heap before shaping
       
   305 	TInt totalAllocSize = 0;
       
   306 	TInt used;
       
   307 #ifdef SHAPER_MEMORY_DEBUG
       
   308 	used = User::Heap().AllocSize(totalAllocSize);
       
   309 	RDebug::Print(_L("before shaping %d cells %d bytes used"), used, totalAllocSize);
       
   310 #endif
       
   311 
       
   312 	iFontInstance->SetSessionHandle(aInput.iSessionHandle);
       
   313 	TRAPD( error, IcuShapeTextL(aOutput, aInput, aHeapForOutput));
       
   314 	if (error == KErrNoMemory)
       
   315 		{
       
   316 		used = User::Heap().AllocSize(totalAllocSize);
       
   317 		RDebug::Print(_L("shaper out of memory %d cells %d"), totalAllocSize, used);
       
   318 		}
       
   319 
       
   320 #ifdef SHAPER_MEMORY_DEBUG
       
   321 	used = User::Heap().AllocSize(totalAllocSize);
       
   322 	RDebug::Print(_L("Shaped %d characters %d glyphs "), aOutput->iCharacterCount, aOutput->iGlyphCount );
       
   323 	RDebug::Print(_L("after shaping %d cells %d bytes used"), used, totalAllocSize);
       
   324 #endif
       
   325 
       
   326 	// hide the ICU error codes as KErrGeneral
       
   327 	if ((error == KErrNoMemory) || (error == KErrNone))
       
   328 		return error;
       
   329 	else
       
   330 		return KErrGeneral;		
       
   331 	}
       
   332 
       
   333 /** This calls the ICU Layout engine to shape the text.  It allocates memory for the results
       
   334 and then reads the results.  This memory is freed by the caller.
       
   335 This function can leave if OOM.
       
   336  @param aOutput On success a new structure containing the results allocated on aHeapForOutput.  
       
   337  @param aInput The input text and other parameters.
       
   338  @param aHeapForOutput On success, aOutput should be allocated from this and nothing else. 
       
   339  		On failure, nothing should be allocated from it.
       
   340  @return Error value from one of the system-wide error codes on	failure, KErrNone on success.
       
   341  @see CIcuLayoutEngine::ShapeText
       
   342  */
       
   343 void  CIcuLayoutEngine::IcuShapeTextL(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
       
   344 	{
       
   345 	LEErrorCode success = LE_NO_ERROR;
       
   346 	const LEUnicode * p = (LEUnicode *)aInput.iText->Ptr();
       
   347 	TInt noChars = aInput.iEnd - aInput.iStart;
       
   348 
       
   349 	// Call to layout  
       
   350 	TInt noOfGlyphs = iEngine->layoutChars(
       
   351 			p, 							// chars - the input character context
       
   352 			aInput.iStart,				// the offset of the first character to process	
       
   353 			noChars,					// count - the number of characters to process	// offset
       
   354 			aInput.iText->Length(), 	// max - the number of characters in the input context	// size of text
       
   355 			FALSE, 						// rightToLeft - TRUE if the characters are in a right to left directional run
       
   356 			0, 							// start X
       
   357 			0, 							// start Y
       
   358 			success);					// result code
       
   359 
       
   360 	if (success == LE_MEMORY_ALLOCATION_ERROR)
       
   361 		User::Leave(KErrNoMemory);
       
   362 	else if (success != LE_NO_ERROR) 
       
   363 		{
       
   364 		User::Leave(KErrGeneral);
       
   365 		}
       
   366 	
       
   367 
       
   368 	// Get some memory to pass into the layout engine for the results
       
   369 	TInt bufferSize = (sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(float) * 2)
       
   370 		* noOfGlyphs + sizeof(float) * 2;
       
   371 	TUint8* buffer = reinterpret_cast<TUint8*>( User::AllocL(bufferSize) );
       
   372 	CleanupStack::PushL(buffer);
       
   373 	LEGlyphID* glyphBuffer = reinterpret_cast<LEGlyphID*>(buffer);
       
   374 	le_int32* indexBuffer = reinterpret_cast<le_int32*>(glyphBuffer + noOfGlyphs);
       
   375 	float* positionBuffer = reinterpret_cast<float*>(indexBuffer + noOfGlyphs);
       
   376 	
       
   377 	
       
   378 	// now get results glyph codes, positions and indices
       
   379 	// from the layout engine
       
   380 	if (success == LE_NO_ERROR)
       
   381 		iEngine->getGlyphs(glyphBuffer, success);
       
   382 
       
   383 	if (success == LE_NO_ERROR)
       
   384 		iEngine->getGlyphPositions(positionBuffer, success);
       
   385 
       
   386 	if (success == LE_NO_ERROR)
       
   387 		iEngine->getCharIndices(indexBuffer, aInput.iStart, success);
       
   388 	if (success == LE_NO_ERROR)
       
   389 		// Reset the memory used by the IcuLayoutEngine
       
   390 		iEngine->reset();
       
   391 	if (success == LE_MEMORY_ALLOCATION_ERROR)
       
   392 		User::Leave(KErrNoMemory);
       
   393 	else 
       
   394 		if (success != LE_NO_ERROR)
       
   395  			{
       
   396 			User::Leave(KErrGeneral);
       
   397 			}
       
   398 
       
   399 	// Some of the glyph codes are 0xFFFF and 0x0001. 0xFFFF is a value used by ICU layout
       
   400 	// engine to indicate no glyph, and 0x0001 is used to indicate a ZWJ or a ZWNJ.
       
   401 	// These should be stripped out now. A ZWJ or a ZWNJ glyph has no meaning here. Their 
       
   402 	// effects on the precedig and proceding characters have already been taken into 
       
   403 	// consideration during shaping, so we don't need them anymore.
       
   404 	// Also, their presence in the final glyph list was causing GDI to break with GDI:1
       
   405 	// i.e. more than 8 glyphs in a glyph cluster.
       
   406 	LEGlyphID gidOfZWJ = iFontInstance->mapCharToGlyph(0x200D); // Added by Symbian: 1922 mlyl
       
   407 	TInt actualNoOfGlyphs = 0;
       
   408 	for (LEGlyphID* p = glyphBuffer + noOfGlyphs; p != glyphBuffer;)
       
   409 		{
       
   410 		--p;
       
   411 		if (*p != 0xFFFF && *p != 0x0001 && *p != gidOfZWJ) // Added by Symbian: 1922 mlyl
       
   412 			++actualNoOfGlyphs;
       
   413 		}
       
   414 
       
   415 	// get some memory to pass back the results,  
       
   416 	// This needs to be big enough for a TShapeHeader
       
   417 	// plus 10 bytes for every glyph returned (-1 for the 1 byte allocated in TShapeHeader for iBuffer)
       
   418 	aOutput = reinterpret_cast<TShapeHeader*>( aHeapForOutput->AllocL(
       
   419 		sizeof(TShapeHeader) + (actualNoOfGlyphs * 10) + 3) );
       
   420 
       
   421 	// get the results into the shaper structure aOutput 
       
   422 	aOutput->iGlyphCount = actualNoOfGlyphs;
       
   423 	aOutput->iCharacterCount = noChars;
       
   424  	aOutput->iReserved0 = 0;
       
   425 	aOutput->iReserved1 = 0;
       
   426 
       
   427  	// iBuffer contains 10 bytes for every glyph
       
   428  	// the glyph code (4 bytes), position X(2 bytes) Y(2 bytes) and indices(2 bytes)
       
   429  
       
   430  	// first is glyph count * 4 byte glyph codes
       
   431  	TUint32* glyphOut = reinterpret_cast<TUint32*>(aOutput->iBuffer);
       
   432  	TInt16* posOut = reinterpret_cast<TInt16*>(aOutput->iBuffer +
       
   433  		(4 * actualNoOfGlyphs));
       
   434  	TInt16* indicesOut = reinterpret_cast<TInt16*>(aOutput->iBuffer +
       
   435  		(8 * actualNoOfGlyphs) + 4);
       
   436  	for (TInt i=0; i < noOfGlyphs; i++)
       
   437  		{
       
   438  		if (*glyphBuffer != 0xFFFF && *glyphBuffer != 0x0001 && *glyphBuffer != gidOfZWJ) // Added by Symbian: 1922 mlyl
       
   439  			{
       
   440 	  		*glyphOut++ = *glyphBuffer;
       
   441 			*posOut++ = FloatToInt( positionBuffer[0] );
       
   442 			*posOut++ = FloatToInt( positionBuffer[1] );
       
   443 			*indicesOut++ = *indexBuffer;
       
   444  			}
       
   445  		++glyphBuffer;
       
   446  		positionBuffer += 2;
       
   447  		++indexBuffer;
       
   448 		}
       
   449 	// There is an extra pair of positions: this is the total advance
       
   450 	posOut[0] = FloatToInt( positionBuffer[0] );
       
   451 	posOut[1] = FloatToInt( positionBuffer[1] );
       
   452 	
       
   453 	CleanupStack::PopAndDestroy(buffer);	
       
   454 	
       
   455 	}