Update contrib.
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
15 * Implementation of CIcuLayoutEngine
16 * This is a CShaper using the Icu Layout Engine.
30 #include "LEScripts.h"
31 #include "LELanguages.h"
32 #include "LayoutEngine.h"
33 #include "SymbianFontInstance.h"
35 #include "IcuLayoutEngine.h"
40 // Convert from float to int rounding to the nearest integer
41 inline TInt FloatToInt(float a)
43 return a < 0? static_cast<TInt>(a - 0.5) : static_cast<TInt>(a + 0.5);
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) */
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)) */
142 Translate the script code passed in to a LEScriptCode
144 TInt ScriptCode(TUint32 aScript)
146 TInt scriptCode = -1;
147 for (TInt i= 0; i < scriptCodeCount; i++)
149 if (scriptCodes[i] == aScript)
159 Translate the language code passed in to a LELanguageCode
161 TInt LanguageCode(TUint32 aLanguage)
163 TInt languageCode = -1;
164 for (TInt i= 0; i < languageCodeCount; i++)
166 if (languageCodes[i] == aLanguage)
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.
181 CShaper * CIcuLayoutEngine::NewL(CBitmapFont* aBitmapFont, TInt aScript, TInt aLanguage, RHeap* aHeap)
183 CIcuLayoutEngine* newShaper = new(ELeave)CIcuLayoutEngine(aScript, aLanguage);
184 CleanupStack::PushL(newShaper);
185 newShaper->ConstructL(aBitmapFont, aScript, aLanguage, aHeap);
186 CleanupStack::Pop(); // newShaper
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
198 TInt CIcuLayoutEngine::ConstructL(CBitmapFont* aBitMapFont, TInt aScript, TInt aLanguage, RHeap* aHeap )
200 // allocate a block of memory from aHeap for the layout engine
201 // which is accessed via the Umemory class
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)
209 User::Leave(KErrGeneral);
211 if (fontStatus == LE_MEMORY_ALLOCATION_ERROR)
213 User::Leave(KErrNoMemory);
215 else if (fontStatus != LE_NO_ERROR)
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);
223 // create and initialise a ICU layout Engine
224 // Note the engine is created using the Umemory heap
225 LEErrorCode success = LE_NO_ERROR;
227 // Translate the script code into an LEScriptCode
228 TInt scriptCode = ScriptCode(aScript);
230 // Translate the language code into an LELanguageCode
231 TInt languageCode = LanguageCode(aLanguage);
233 // Finally instantiate the LayoutEngine
234 iEngine = LayoutEngine::layoutEngineFactory(iFontInstance, scriptCode, languageCode, success);
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);
243 if (success == LE_MEMORY_ALLOCATION_ERROR)
245 User::Leave(KErrNoMemory);
247 else if (success != LE_NO_ERROR)
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);
256 CIcuLayoutEngine::CIcuLayoutEngine(TUint32 aScript, TUint32 aLanguage):
263 Frees all resources owned by ...
265 CIcuLayoutEngine::~CIcuLayoutEngine()
267 // delete the engine instance
273 // delete the font instance from client heap
274 delete( iFontInstance );
278 Returns the script and the language this shaper has been instansiated with.
280 void* CIcuLayoutEngine::ExtendedInterface (TUid aInterfaceId)
282 if (aInterfaceId == KUidShaperGetScript)
283 return (TUint32*)iScript;
285 if (aInterfaceId == KUidShaperGetLang)
286 return (TUint32*)iLanguage;
288 return CShaper::ExtendedInterface(aInterfaceId);
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
302 TInt CIcuLayoutEngine::ShapeText(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
304 // For debugging - the heap before shaping
305 TInt totalAllocSize = 0;
307 #ifdef SHAPER_MEMORY_DEBUG
308 used = User::Heap().AllocSize(totalAllocSize);
309 RDebug::Print(_L("before shaping %d cells %d bytes used"), used, totalAllocSize);
312 iFontInstance->SetSessionHandle(aInput.iSessionHandle);
313 TRAPD( error, IcuShapeTextL(aOutput, aInput, aHeapForOutput));
314 if (error == KErrNoMemory)
316 used = User::Heap().AllocSize(totalAllocSize);
317 RDebug::Print(_L("shaper out of memory %d cells %d"), totalAllocSize, used);
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);
326 // hide the ICU error codes as KErrGeneral
327 if ((error == KErrNoMemory) || (error == KErrNone))
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
343 void CIcuLayoutEngine::IcuShapeTextL(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
345 LEErrorCode success = LE_NO_ERROR;
346 const LEUnicode * p = (LEUnicode *)aInput.iText->Ptr();
347 TInt noChars = aInput.iEnd - aInput.iStart;
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
358 success); // result code
360 if (success == LE_MEMORY_ALLOCATION_ERROR)
361 User::Leave(KErrNoMemory);
362 else if (success != LE_NO_ERROR)
364 User::Leave(KErrGeneral);
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);
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);
383 if (success == LE_NO_ERROR)
384 iEngine->getGlyphPositions(positionBuffer, success);
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
391 if (success == LE_MEMORY_ALLOCATION_ERROR)
392 User::Leave(KErrNoMemory);
394 if (success != LE_NO_ERROR)
396 User::Leave(KErrGeneral);
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;)
411 if (*p != 0xFFFF && *p != 0x0001 && *p != gidOfZWJ) // Added by Symbian: 1922 mlyl
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) );
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;
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)
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++)
438 if (*glyphBuffer != 0xFFFF && *glyphBuffer != 0x0001 && *glyphBuffer != gidOfZWJ) // Added by Symbian: 1922 mlyl
440 *glyphOut++ = *glyphBuffer;
441 *posOut++ = FloatToInt( positionBuffer[0] );
442 *posOut++ = FloatToInt( positionBuffer[1] );
443 *indicesOut++ = *indexBuffer;
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] );
453 CleanupStack::PopAndDestroy(buffer);