1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/fontservices/textshaperplugin/source/IcuLayoutEngine.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,455 @@
1.4 +/*
1.5 +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +* Implementation of CIcuLayoutEngine
1.19 +* This is a CShaper using the Icu Layout Engine.
1.20 +*
1.21 +*/
1.22 +
1.23 +// System includes
1.24 +#include <e32base.h>
1.25 +#include <gdi.h>
1.26 +#include <e32math.h>
1.27 +#include <openfont.h>
1.28 +#include <fntstore.h>
1.29 +
1.30 +// ICU includes
1.31 +#include "math.h"
1.32 +#include "LETypes.h"
1.33 +#include "LEScripts.h"
1.34 +#include "LELanguages.h"
1.35 +#include "LayoutEngine.h"
1.36 +#include "SymbianFontInstance.h"
1.37 +
1.38 +#include "IcuLayoutEngine.h"
1.39 +
1.40 +// Icu namespace
1.41 +U_NAMESPACE_USE
1.42 +
1.43 +// Convert from float to int rounding to the nearest integer
1.44 +inline TInt FloatToInt(float a)
1.45 + {
1.46 + return a < 0? static_cast<TInt>(a - 0.5) : static_cast<TInt>(a + 0.5);
1.47 + }
1.48 +
1.49 +/** Array of Script Codes that need to be translated into LEScriptCodes for the
1.50 +construction of the LayoutEngine. */
1.51 +const LETag scriptCodes[] = {
1.52 + zyyyScriptTag, /* 'zyyy' (COMMON) */
1.53 + qaaiScriptTag, /* 'qaai' (INHERITED) */
1.54 + arabScriptTag, /* 'arab' (ARABIC) */
1.55 + armnScriptTag, /* 'armn' (ARMENIAN) */
1.56 + bengScriptTag, /* 'beng' (BENGALI) */
1.57 + bopoScriptTag, /* 'bopo' (BOPOMOFO) */
1.58 + cherScriptTag, /* 'cher' (CHEROKEE) */
1.59 + qaacScriptTag, /* 'qaac' (COPTIC) */
1.60 + cyrlScriptTag, /* 'cyrl' (CYRILLIC) */
1.61 + dsrtScriptTag, /* 'dsrt' (DESERET) */
1.62 + devaScriptTag, /* 'deva' (DEVANAGARI) */
1.63 + ethiScriptTag, /* 'ethi' (ETHIOPIC) */
1.64 + georScriptTag, /* 'geor' (GEORGIAN) */
1.65 + gothScriptTag, /* 'goth' (GOTHIC) */
1.66 + grekScriptTag, /* 'grek' (GREEK) */
1.67 + gujrScriptTag, /* 'gujr' (GUJARATI) */
1.68 + guruScriptTag, /* 'guru' (GURMUKHI) */
1.69 + haniScriptTag, /* 'hani' (HAN) */
1.70 + hangScriptTag, /* 'hang' (HANGUL) */
1.71 + hebrScriptTag, /* 'hebr' (HEBREW) */
1.72 + hiraScriptTag, /* 'hira' (HIRAGANA) */
1.73 + kndaScriptTag, /* 'knda' (KANNADA) */
1.74 + kanaScriptTag, /* 'kana' (KATAKANA) */
1.75 + khmrScriptTag, /* 'khmr' (KHMER) */
1.76 + laooScriptTag, /* 'laoo' (LAO) */
1.77 + latnScriptTag, /* 'latn' (LATIN) */
1.78 + mlymScriptTag, /* 'mlym' (MALAYALAM) */
1.79 + mongScriptTag, /* 'mong' (MONGOLIAN) */
1.80 + mymrScriptTag, /* 'mymr' (MYANMAR) */
1.81 + ogamScriptTag, /* 'ogam' (OGHAM) */
1.82 + italScriptTag, /* 'ital' (OLD_ITALIC) */
1.83 + oryaScriptTag, /* 'orya' (ORIYA) */
1.84 + runrScriptTag, /* 'runr' (RUNIC) */
1.85 + sinhScriptTag, /* 'sinh' (SINHALA) */
1.86 + syrcScriptTag, /* 'syrc' (SYRIAC) */
1.87 + tamlScriptTag, /* 'taml' (TAMIL) */
1.88 + teluScriptTag, /* 'telu' (TELUGU) */
1.89 + thaaScriptTag, /* 'thaa' (THAANA) */
1.90 + thaiScriptTag, /* 'thai' (THAI) */
1.91 + tibtScriptTag, /* 'tibt' (TIBETAN) */
1.92 + cansScriptTag, /* 'cans' (CANADIAN_ABORIGINAL) */
1.93 + yiiiScriptTag, /* 'yiii' (YI) */
1.94 + tglgScriptTag, /* 'tglg' (TAGALOG) */
1.95 + hanoScriptTag, /* 'hano' (HANUNOO) */
1.96 + buhdScriptTag, /* 'buhd' (BUHID) */
1.97 + tagbScriptTag, /* 'tagb' (TAGBANWA) */
1.98 + braiScriptTag, /* 'brai' (BRAILLE) */
1.99 + cprtScriptTag, /* 'cprt' (CYPRIOT) */
1.100 + limbScriptTag, /* 'limb' (LIMBU) */
1.101 + linbScriptTag, /* 'linb' (LINEAR_B) */
1.102 + osmaScriptTag, /* 'osma' (OSMANYA) */
1.103 + shawScriptTag, /* 'shaw' (SHAVIAN) */
1.104 + taleScriptTag, /* 'tale' (TAI_LE) */
1.105 + ugarScriptTag, /* 'ugar' (UGARITIC) */
1.106 + hrktScriptTag /* 'hrkt' (KATAKANA_OR_HIRAGANA) */
1.107 +};
1.108 +
1.109 +/** Array of Language Codes that need to be translated into LELanguageCodes for the
1.110 +construction of the LayoutEngine. */
1.111 +const LETag languageCodes[] = {
1.112 + nullLanguageTag, /* '' (null) */
1.113 + araLanguageTag, /* 'ARA' (Arabic) */
1.114 + asmLanguageTag, /* 'ASM' (Assamese) */
1.115 + benLanguageTag, /* 'BEN' (Bengali) */
1.116 + farLanguageTag, /* 'FAR' (Farsi) */
1.117 + gujLanguageTag, /* 'GUJ' (Gujarati) */
1.118 + hinLanguageTag, /* 'HIN' (Hindi) */
1.119 + iwrLanguageTag, /* 'IWR' (Hebrew) */
1.120 + jiiLanguageTag, /* 'JII' (Yiddish) */
1.121 + janLanguageTag, /* 'JAN' (Japanese) */
1.122 + kanLanguageTag, /* 'KAN' (Kannada) */
1.123 + kokLanguageTag, /* 'KOK' (Konkani) */
1.124 + korLanguageTag, /* 'KOR' (Korean) */
1.125 + kshLanguageTag, /* 'KSH' (Kashmiri) */
1.126 + malLanguageTag, /* 'MAL' (Malayalam (Traditional)) */
1.127 + marLanguageTag, /* 'MAR' (Marathi) */
1.128 + mlrLanguageTag, /* 'MLR' (Malayalam (Reformed)) */
1.129 + mniLanguageTag, /* 'MNI' (Manipuri) */
1.130 + oriLanguageTag, /* 'ORI' (Oriya) */
1.131 + sanLanguageTag, /* 'SAN' (Sanscrit) */
1.132 + sndLanguageTag, /* 'SND' (Sindhi) */
1.133 + snhLanguageTag, /* 'SNH' (Sinhalese) */
1.134 + syrLanguageTag, /* 'SYR' (Syriac) */
1.135 + tamLanguageTag, /* 'TAM' (Tamil) */
1.136 + telLanguageTag, /* 'TEL' (Telugu) */
1.137 + thaLanguageTag, /* 'THA' (Thai) */
1.138 + urdLanguageTag, /* 'URD' (Urdu) */
1.139 + zhpLanguageTag, /* 'ZHP' (Chinese (Phonetic)) */
1.140 + zhsLanguageTag, /* 'ZHS' (Chinese (Simplified)) */
1.141 + zhtLanguageTag /* 'ZHT' (Chinese (Traditional)) */
1.142 +};
1.143 +
1.144 +/**
1.145 +Translate the script code passed in to a LEScriptCode
1.146 +*/
1.147 +TInt ScriptCode(TUint32 aScript)
1.148 + {
1.149 + TInt scriptCode = -1;
1.150 + for (TInt i= 0; i < scriptCodeCount; i++)
1.151 + {
1.152 + if (scriptCodes[i] == aScript)
1.153 + {
1.154 + scriptCode = i;
1.155 + break;
1.156 + }
1.157 + }
1.158 + return scriptCode;
1.159 + }
1.160 +
1.161 +/**
1.162 +Translate the language code passed in to a LELanguageCode
1.163 +*/
1.164 +TInt LanguageCode(TUint32 aLanguage)
1.165 + {
1.166 + TInt languageCode = -1;
1.167 + for (TInt i= 0; i < languageCodeCount; i++)
1.168 + {
1.169 + if (languageCodes[i] == aLanguage)
1.170 + {
1.171 + languageCode = i;
1.172 + break;
1.173 + }
1.174 + }
1.175 + return languageCode;
1.176 + }
1.177 +
1.178 +/**
1.179 +Create a instance of CIcuLayoutEngine
1.180 +@param aBitmapFont The required font.
1.181 +@param aHeap The heap to be used for storage by the engine.
1.182 +@return A pointer to the new CIcuLayoutEngine instance.
1.183 +*/
1.184 +CShaper * CIcuLayoutEngine::NewL(CBitmapFont* aBitmapFont, TInt aScript, TInt aLanguage, RHeap* aHeap)
1.185 + {
1.186 + CIcuLayoutEngine* newShaper = new(ELeave)CIcuLayoutEngine(aScript, aLanguage);
1.187 + CleanupStack::PushL(newShaper);
1.188 + newShaper->ConstructL(aBitmapFont, aScript, aLanguage, aHeap);
1.189 + CleanupStack::Pop(); // newShaper
1.190 + return newShaper;
1.191 + }
1.192 +
1.193 +
1.194 +/**
1.195 +Construct an instance of CIcuLayoutEngine
1.196 +@param aBitMapFont The required font
1.197 +@param aHeap The heap to be used for storage by the engine
1.198 +@return incase of exceptions with an Error Code
1.199 +@see CShaper
1.200 + */
1.201 +TInt CIcuLayoutEngine::ConstructL(CBitmapFont* aBitMapFont, TInt aScript, TInt aLanguage, RHeap* aHeap )
1.202 + {
1.203 + // allocate a block of memory from aHeap for the layout engine
1.204 + // which is accessed via the Umemory class
1.205 + iClientHeap = aHeap;
1.206 +
1.207 + // this needs to be on the heap
1.208 + LEErrorCode fontStatus = LE_NO_ERROR;
1.209 + iFontInstance = new SymbianFontInstance(aBitMapFont, fontStatus, aScript == mlymScriptTag);
1.210 + if(NULL == iFontInstance)
1.211 + {
1.212 + User::Leave(KErrGeneral);
1.213 + }
1.214 + if (fontStatus == LE_MEMORY_ALLOCATION_ERROR)
1.215 + {
1.216 + User::Leave(KErrNoMemory);
1.217 + }
1.218 + else if (fontStatus != LE_NO_ERROR)
1.219 + {
1.220 + //note this leave may actually be caused by OOM situations,
1.221 + //due to the way errors codes are handled in the open source code
1.222 + User::Leave(KErrGeneral);
1.223 + }
1.224 +
1.225 +
1.226 + // create and initialise a ICU layout Engine
1.227 + // Note the engine is created using the Umemory heap
1.228 + LEErrorCode success = LE_NO_ERROR;
1.229 +
1.230 + // Translate the script code into an LEScriptCode
1.231 + TInt scriptCode = ScriptCode(aScript);
1.232 +
1.233 + // Translate the language code into an LELanguageCode
1.234 + TInt languageCode = LanguageCode(aLanguage);
1.235 +
1.236 + // Finally instantiate the LayoutEngine
1.237 + iEngine = LayoutEngine::layoutEngineFactory(iFontInstance, scriptCode, languageCode, success);
1.238 +
1.239 + // For debugging - check the total memory used by construction
1.240 +#ifdef SHAPER_MEMORY_DEBUG
1.241 + TInt totalAllocSize = 0;
1.242 + TInt used = iHeap->AllocSize(totalAllocSize);
1.243 + RDebug::Print(_L("shaper construction %d cells %d"), totalAllocSize, used);
1.244 +#endif
1.245 +
1.246 + if (success == LE_MEMORY_ALLOCATION_ERROR)
1.247 + {
1.248 + User::Leave(KErrNoMemory);
1.249 + }
1.250 + else if (success != LE_NO_ERROR)
1.251 + {
1.252 + //note this leave may actually be caused by OOM situations,
1.253 + //due to the way errors codes are handled in the open source code
1.254 + User::Leave(KErrGeneral);
1.255 + }
1.256 + return KErrNone;
1.257 + }
1.258 +
1.259 +CIcuLayoutEngine::CIcuLayoutEngine(TUint32 aScript, TUint32 aLanguage):
1.260 + iScript(aScript),
1.261 + iLanguage(aLanguage)
1.262 + {
1.263 + }
1.264 +
1.265 +/**
1.266 + Frees all resources owned by ...
1.267 + */
1.268 + CIcuLayoutEngine::~CIcuLayoutEngine()
1.269 + {
1.270 + // delete the engine instance
1.271 + if ( iEngine )
1.272 + {
1.273 + delete( iEngine );
1.274 + }
1.275 +
1.276 + // delete the font instance from client heap
1.277 + delete( iFontInstance );
1.278 + }
1.279 +
1.280 +/**
1.281 +Returns the script and the language this shaper has been instansiated with.
1.282 +*/
1.283 +void* CIcuLayoutEngine::ExtendedInterface (TUid aInterfaceId)
1.284 + {
1.285 + if (aInterfaceId == KUidShaperGetScript)
1.286 + return (TUint32*)iScript;
1.287 + else
1.288 + if (aInterfaceId == KUidShaperGetLang)
1.289 + return (TUint32*)iLanguage;
1.290 + else
1.291 + return CShaper::ExtendedInterface(aInterfaceId);
1.292 + }
1.293 +
1.294 +/** This is implementation of CShaper::ShapeText for the Icu layout Engine
1.295 + The data is taken from TInput and pass to the shaper.
1.296 + A memory buffer is allocated on aHeapForOutput starting with TShapeHeader is allocated.
1.297 + The results of the shaping are copied into this buffer and passed back via aOutput.
1.298 + @param aOutput On success a new structure containing the results allocated on aHeapForOutput.
1.299 + @param aInput The input text and other parameters.
1.300 + @param aHeapForOutput On success, aOutput should be allocated from this and nothing else.
1.301 + On failure, nothing should be allocated from it.
1.302 + @return Error value from one of the system-wide error codes on failure, KErrNone on success.
1.303 + @see CShaper::ShapeText
1.304 + */
1.305 +TInt CIcuLayoutEngine::ShapeText(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
1.306 + {
1.307 + // For debugging - the heap before shaping
1.308 + TInt totalAllocSize = 0;
1.309 + TInt used;
1.310 +#ifdef SHAPER_MEMORY_DEBUG
1.311 + used = User::Heap().AllocSize(totalAllocSize);
1.312 + RDebug::Print(_L("before shaping %d cells %d bytes used"), used, totalAllocSize);
1.313 +#endif
1.314 +
1.315 + iFontInstance->SetSessionHandle(aInput.iSessionHandle);
1.316 + TRAPD( error, IcuShapeTextL(aOutput, aInput, aHeapForOutput));
1.317 + if (error == KErrNoMemory)
1.318 + {
1.319 + used = User::Heap().AllocSize(totalAllocSize);
1.320 + RDebug::Print(_L("shaper out of memory %d cells %d"), totalAllocSize, used);
1.321 + }
1.322 +
1.323 +#ifdef SHAPER_MEMORY_DEBUG
1.324 + used = User::Heap().AllocSize(totalAllocSize);
1.325 + RDebug::Print(_L("Shaped %d characters %d glyphs "), aOutput->iCharacterCount, aOutput->iGlyphCount );
1.326 + RDebug::Print(_L("after shaping %d cells %d bytes used"), used, totalAllocSize);
1.327 +#endif
1.328 +
1.329 + // hide the ICU error codes as KErrGeneral
1.330 + if ((error == KErrNoMemory) || (error == KErrNone))
1.331 + return error;
1.332 + else
1.333 + return KErrGeneral;
1.334 + }
1.335 +
1.336 +/** This calls the ICU Layout engine to shape the text. It allocates memory for the results
1.337 +and then reads the results. This memory is freed by the caller.
1.338 +This function can leave if OOM.
1.339 + @param aOutput On success a new structure containing the results allocated on aHeapForOutput.
1.340 + @param aInput The input text and other parameters.
1.341 + @param aHeapForOutput On success, aOutput should be allocated from this and nothing else.
1.342 + On failure, nothing should be allocated from it.
1.343 + @return Error value from one of the system-wide error codes on failure, KErrNone on success.
1.344 + @see CIcuLayoutEngine::ShapeText
1.345 + */
1.346 +void CIcuLayoutEngine::IcuShapeTextL(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput)
1.347 + {
1.348 + LEErrorCode success = LE_NO_ERROR;
1.349 + const LEUnicode * p = (LEUnicode *)aInput.iText->Ptr();
1.350 + TInt noChars = aInput.iEnd - aInput.iStart;
1.351 +
1.352 + // Call to layout
1.353 + TInt noOfGlyphs = iEngine->layoutChars(
1.354 + p, // chars - the input character context
1.355 + aInput.iStart, // the offset of the first character to process
1.356 + noChars, // count - the number of characters to process // offset
1.357 + aInput.iText->Length(), // max - the number of characters in the input context // size of text
1.358 + FALSE, // rightToLeft - TRUE if the characters are in a right to left directional run
1.359 + 0, // start X
1.360 + 0, // start Y
1.361 + success); // result code
1.362 +
1.363 + if (success == LE_MEMORY_ALLOCATION_ERROR)
1.364 + User::Leave(KErrNoMemory);
1.365 + else if (success != LE_NO_ERROR)
1.366 + {
1.367 + User::Leave(KErrGeneral);
1.368 + }
1.369 +
1.370 +
1.371 + // Get some memory to pass into the layout engine for the results
1.372 + TInt bufferSize = (sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(float) * 2)
1.373 + * noOfGlyphs + sizeof(float) * 2;
1.374 + TUint8* buffer = reinterpret_cast<TUint8*>( User::AllocL(bufferSize) );
1.375 + CleanupStack::PushL(buffer);
1.376 + LEGlyphID* glyphBuffer = reinterpret_cast<LEGlyphID*>(buffer);
1.377 + le_int32* indexBuffer = reinterpret_cast<le_int32*>(glyphBuffer + noOfGlyphs);
1.378 + float* positionBuffer = reinterpret_cast<float*>(indexBuffer + noOfGlyphs);
1.379 +
1.380 +
1.381 + // now get results glyph codes, positions and indices
1.382 + // from the layout engine
1.383 + if (success == LE_NO_ERROR)
1.384 + iEngine->getGlyphs(glyphBuffer, success);
1.385 +
1.386 + if (success == LE_NO_ERROR)
1.387 + iEngine->getGlyphPositions(positionBuffer, success);
1.388 +
1.389 + if (success == LE_NO_ERROR)
1.390 + iEngine->getCharIndices(indexBuffer, aInput.iStart, success);
1.391 + if (success == LE_NO_ERROR)
1.392 + // Reset the memory used by the IcuLayoutEngine
1.393 + iEngine->reset();
1.394 + if (success == LE_MEMORY_ALLOCATION_ERROR)
1.395 + User::Leave(KErrNoMemory);
1.396 + else
1.397 + if (success != LE_NO_ERROR)
1.398 + {
1.399 + User::Leave(KErrGeneral);
1.400 + }
1.401 +
1.402 + // Some of the glyph codes are 0xFFFF and 0x0001. 0xFFFF is a value used by ICU layout
1.403 + // engine to indicate no glyph, and 0x0001 is used to indicate a ZWJ or a ZWNJ.
1.404 + // These should be stripped out now. A ZWJ or a ZWNJ glyph has no meaning here. Their
1.405 + // effects on the precedig and proceding characters have already been taken into
1.406 + // consideration during shaping, so we don't need them anymore.
1.407 + // Also, their presence in the final glyph list was causing GDI to break with GDI:1
1.408 + // i.e. more than 8 glyphs in a glyph cluster.
1.409 + LEGlyphID gidOfZWJ = iFontInstance->mapCharToGlyph(0x200D); // Added by Symbian: 1922 mlyl
1.410 + TInt actualNoOfGlyphs = 0;
1.411 + for (LEGlyphID* p = glyphBuffer + noOfGlyphs; p != glyphBuffer;)
1.412 + {
1.413 + --p;
1.414 + if (*p != 0xFFFF && *p != 0x0001 && *p != gidOfZWJ) // Added by Symbian: 1922 mlyl
1.415 + ++actualNoOfGlyphs;
1.416 + }
1.417 +
1.418 + // get some memory to pass back the results,
1.419 + // This needs to be big enough for a TShapeHeader
1.420 + // plus 10 bytes for every glyph returned (-1 for the 1 byte allocated in TShapeHeader for iBuffer)
1.421 + aOutput = reinterpret_cast<TShapeHeader*>( aHeapForOutput->AllocL(
1.422 + sizeof(TShapeHeader) + (actualNoOfGlyphs * 10) + 3) );
1.423 +
1.424 + // get the results into the shaper structure aOutput
1.425 + aOutput->iGlyphCount = actualNoOfGlyphs;
1.426 + aOutput->iCharacterCount = noChars;
1.427 + aOutput->iReserved0 = 0;
1.428 + aOutput->iReserved1 = 0;
1.429 +
1.430 + // iBuffer contains 10 bytes for every glyph
1.431 + // the glyph code (4 bytes), position X(2 bytes) Y(2 bytes) and indices(2 bytes)
1.432 +
1.433 + // first is glyph count * 4 byte glyph codes
1.434 + TUint32* glyphOut = reinterpret_cast<TUint32*>(aOutput->iBuffer);
1.435 + TInt16* posOut = reinterpret_cast<TInt16*>(aOutput->iBuffer +
1.436 + (4 * actualNoOfGlyphs));
1.437 + TInt16* indicesOut = reinterpret_cast<TInt16*>(aOutput->iBuffer +
1.438 + (8 * actualNoOfGlyphs) + 4);
1.439 + for (TInt i=0; i < noOfGlyphs; i++)
1.440 + {
1.441 + if (*glyphBuffer != 0xFFFF && *glyphBuffer != 0x0001 && *glyphBuffer != gidOfZWJ) // Added by Symbian: 1922 mlyl
1.442 + {
1.443 + *glyphOut++ = *glyphBuffer;
1.444 + *posOut++ = FloatToInt( positionBuffer[0] );
1.445 + *posOut++ = FloatToInt( positionBuffer[1] );
1.446 + *indicesOut++ = *indexBuffer;
1.447 + }
1.448 + ++glyphBuffer;
1.449 + positionBuffer += 2;
1.450 + ++indexBuffer;
1.451 + }
1.452 + // There is an extra pair of positions: this is the total advance
1.453 + posOut[0] = FloatToInt( positionBuffer[0] );
1.454 + posOut[1] = FloatToInt( positionBuffer[1] );
1.455 +
1.456 + CleanupStack::PopAndDestroy(buffer);
1.457 +
1.458 + }