os/textandloc/fontservices/textshaperplugin/source/IcuLayoutEngine.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}