|
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 } |