diff -r 000000000000 -r bde4ae8d615e os/textandloc/fontservices/textshaperplugin/source/IcuLayoutEngine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/textandloc/fontservices/textshaperplugin/source/IcuLayoutEngine.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,455 @@ +/* +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* Implementation of CIcuLayoutEngine +* This is a CShaper using the Icu Layout Engine. +* +*/ + +// System includes +#include +#include +#include +#include +#include + +// ICU includes +#include "math.h" +#include "LETypes.h" +#include "LEScripts.h" +#include "LELanguages.h" +#include "LayoutEngine.h" +#include "SymbianFontInstance.h" + +#include "IcuLayoutEngine.h" + +// Icu namespace +U_NAMESPACE_USE + +// Convert from float to int rounding to the nearest integer +inline TInt FloatToInt(float a) + { + return a < 0? static_cast(a - 0.5) : static_cast(a + 0.5); + } + +/** Array of Script Codes that need to be translated into LEScriptCodes for the +construction of the LayoutEngine. */ +const LETag scriptCodes[] = { + zyyyScriptTag, /* 'zyyy' (COMMON) */ + qaaiScriptTag, /* 'qaai' (INHERITED) */ + arabScriptTag, /* 'arab' (ARABIC) */ + armnScriptTag, /* 'armn' (ARMENIAN) */ + bengScriptTag, /* 'beng' (BENGALI) */ + bopoScriptTag, /* 'bopo' (BOPOMOFO) */ + cherScriptTag, /* 'cher' (CHEROKEE) */ + qaacScriptTag, /* 'qaac' (COPTIC) */ + cyrlScriptTag, /* 'cyrl' (CYRILLIC) */ + dsrtScriptTag, /* 'dsrt' (DESERET) */ + devaScriptTag, /* 'deva' (DEVANAGARI) */ + ethiScriptTag, /* 'ethi' (ETHIOPIC) */ + georScriptTag, /* 'geor' (GEORGIAN) */ + gothScriptTag, /* 'goth' (GOTHIC) */ + grekScriptTag, /* 'grek' (GREEK) */ + gujrScriptTag, /* 'gujr' (GUJARATI) */ + guruScriptTag, /* 'guru' (GURMUKHI) */ + haniScriptTag, /* 'hani' (HAN) */ + hangScriptTag, /* 'hang' (HANGUL) */ + hebrScriptTag, /* 'hebr' (HEBREW) */ + hiraScriptTag, /* 'hira' (HIRAGANA) */ + kndaScriptTag, /* 'knda' (KANNADA) */ + kanaScriptTag, /* 'kana' (KATAKANA) */ + khmrScriptTag, /* 'khmr' (KHMER) */ + laooScriptTag, /* 'laoo' (LAO) */ + latnScriptTag, /* 'latn' (LATIN) */ + mlymScriptTag, /* 'mlym' (MALAYALAM) */ + mongScriptTag, /* 'mong' (MONGOLIAN) */ + mymrScriptTag, /* 'mymr' (MYANMAR) */ + ogamScriptTag, /* 'ogam' (OGHAM) */ + italScriptTag, /* 'ital' (OLD_ITALIC) */ + oryaScriptTag, /* 'orya' (ORIYA) */ + runrScriptTag, /* 'runr' (RUNIC) */ + sinhScriptTag, /* 'sinh' (SINHALA) */ + syrcScriptTag, /* 'syrc' (SYRIAC) */ + tamlScriptTag, /* 'taml' (TAMIL) */ + teluScriptTag, /* 'telu' (TELUGU) */ + thaaScriptTag, /* 'thaa' (THAANA) */ + thaiScriptTag, /* 'thai' (THAI) */ + tibtScriptTag, /* 'tibt' (TIBETAN) */ + cansScriptTag, /* 'cans' (CANADIAN_ABORIGINAL) */ + yiiiScriptTag, /* 'yiii' (YI) */ + tglgScriptTag, /* 'tglg' (TAGALOG) */ + hanoScriptTag, /* 'hano' (HANUNOO) */ + buhdScriptTag, /* 'buhd' (BUHID) */ + tagbScriptTag, /* 'tagb' (TAGBANWA) */ + braiScriptTag, /* 'brai' (BRAILLE) */ + cprtScriptTag, /* 'cprt' (CYPRIOT) */ + limbScriptTag, /* 'limb' (LIMBU) */ + linbScriptTag, /* 'linb' (LINEAR_B) */ + osmaScriptTag, /* 'osma' (OSMANYA) */ + shawScriptTag, /* 'shaw' (SHAVIAN) */ + taleScriptTag, /* 'tale' (TAI_LE) */ + ugarScriptTag, /* 'ugar' (UGARITIC) */ + hrktScriptTag /* 'hrkt' (KATAKANA_OR_HIRAGANA) */ +}; + +/** Array of Language Codes that need to be translated into LELanguageCodes for the +construction of the LayoutEngine. */ +const LETag languageCodes[] = { + nullLanguageTag, /* '' (null) */ + araLanguageTag, /* 'ARA' (Arabic) */ + asmLanguageTag, /* 'ASM' (Assamese) */ + benLanguageTag, /* 'BEN' (Bengali) */ + farLanguageTag, /* 'FAR' (Farsi) */ + gujLanguageTag, /* 'GUJ' (Gujarati) */ + hinLanguageTag, /* 'HIN' (Hindi) */ + iwrLanguageTag, /* 'IWR' (Hebrew) */ + jiiLanguageTag, /* 'JII' (Yiddish) */ + janLanguageTag, /* 'JAN' (Japanese) */ + kanLanguageTag, /* 'KAN' (Kannada) */ + kokLanguageTag, /* 'KOK' (Konkani) */ + korLanguageTag, /* 'KOR' (Korean) */ + kshLanguageTag, /* 'KSH' (Kashmiri) */ + malLanguageTag, /* 'MAL' (Malayalam (Traditional)) */ + marLanguageTag, /* 'MAR' (Marathi) */ + mlrLanguageTag, /* 'MLR' (Malayalam (Reformed)) */ + mniLanguageTag, /* 'MNI' (Manipuri) */ + oriLanguageTag, /* 'ORI' (Oriya) */ + sanLanguageTag, /* 'SAN' (Sanscrit) */ + sndLanguageTag, /* 'SND' (Sindhi) */ + snhLanguageTag, /* 'SNH' (Sinhalese) */ + syrLanguageTag, /* 'SYR' (Syriac) */ + tamLanguageTag, /* 'TAM' (Tamil) */ + telLanguageTag, /* 'TEL' (Telugu) */ + thaLanguageTag, /* 'THA' (Thai) */ + urdLanguageTag, /* 'URD' (Urdu) */ + zhpLanguageTag, /* 'ZHP' (Chinese (Phonetic)) */ + zhsLanguageTag, /* 'ZHS' (Chinese (Simplified)) */ + zhtLanguageTag /* 'ZHT' (Chinese (Traditional)) */ +}; + +/** +Translate the script code passed in to a LEScriptCode +*/ +TInt ScriptCode(TUint32 aScript) + { + TInt scriptCode = -1; + for (TInt i= 0; i < scriptCodeCount; i++) + { + if (scriptCodes[i] == aScript) + { + scriptCode = i; + break; + } + } + return scriptCode; + } + +/** +Translate the language code passed in to a LELanguageCode +*/ +TInt LanguageCode(TUint32 aLanguage) + { + TInt languageCode = -1; + for (TInt i= 0; i < languageCodeCount; i++) + { + if (languageCodes[i] == aLanguage) + { + languageCode = i; + break; + } + } + return languageCode; + } + +/** +Create a instance of CIcuLayoutEngine +@param aBitmapFont The required font. +@param aHeap The heap to be used for storage by the engine. +@return A pointer to the new CIcuLayoutEngine instance. +*/ +CShaper * CIcuLayoutEngine::NewL(CBitmapFont* aBitmapFont, TInt aScript, TInt aLanguage, RHeap* aHeap) + { + CIcuLayoutEngine* newShaper = new(ELeave)CIcuLayoutEngine(aScript, aLanguage); + CleanupStack::PushL(newShaper); + newShaper->ConstructL(aBitmapFont, aScript, aLanguage, aHeap); + CleanupStack::Pop(); // newShaper + return newShaper; + } + + +/** +Construct an instance of CIcuLayoutEngine +@param aBitMapFont The required font +@param aHeap The heap to be used for storage by the engine +@return incase of exceptions with an Error Code +@see CShaper + */ +TInt CIcuLayoutEngine::ConstructL(CBitmapFont* aBitMapFont, TInt aScript, TInt aLanguage, RHeap* aHeap ) + { + // allocate a block of memory from aHeap for the layout engine + // which is accessed via the Umemory class + iClientHeap = aHeap; + + // this needs to be on the heap + LEErrorCode fontStatus = LE_NO_ERROR; + iFontInstance = new SymbianFontInstance(aBitMapFont, fontStatus, aScript == mlymScriptTag); + if(NULL == iFontInstance) + { + User::Leave(KErrGeneral); + } + if (fontStatus == LE_MEMORY_ALLOCATION_ERROR) + { + User::Leave(KErrNoMemory); + } + else if (fontStatus != LE_NO_ERROR) + { + //note this leave may actually be caused by OOM situations, + //due to the way errors codes are handled in the open source code + User::Leave(KErrGeneral); + } + + + // create and initialise a ICU layout Engine + // Note the engine is created using the Umemory heap + LEErrorCode success = LE_NO_ERROR; + + // Translate the script code into an LEScriptCode + TInt scriptCode = ScriptCode(aScript); + + // Translate the language code into an LELanguageCode + TInt languageCode = LanguageCode(aLanguage); + + // Finally instantiate the LayoutEngine + iEngine = LayoutEngine::layoutEngineFactory(iFontInstance, scriptCode, languageCode, success); + + // For debugging - check the total memory used by construction +#ifdef SHAPER_MEMORY_DEBUG + TInt totalAllocSize = 0; + TInt used = iHeap->AllocSize(totalAllocSize); + RDebug::Print(_L("shaper construction %d cells %d"), totalAllocSize, used); +#endif + + if (success == LE_MEMORY_ALLOCATION_ERROR) + { + User::Leave(KErrNoMemory); + } + else if (success != LE_NO_ERROR) + { + //note this leave may actually be caused by OOM situations, + //due to the way errors codes are handled in the open source code + User::Leave(KErrGeneral); + } + return KErrNone; + } + +CIcuLayoutEngine::CIcuLayoutEngine(TUint32 aScript, TUint32 aLanguage): + iScript(aScript), + iLanguage(aLanguage) + { + } + +/** + Frees all resources owned by ... + */ + CIcuLayoutEngine::~CIcuLayoutEngine() + { + // delete the engine instance + if ( iEngine ) + { + delete( iEngine ); + } + + // delete the font instance from client heap + delete( iFontInstance ); + } + +/** +Returns the script and the language this shaper has been instansiated with. +*/ +void* CIcuLayoutEngine::ExtendedInterface (TUid aInterfaceId) + { + if (aInterfaceId == KUidShaperGetScript) + return (TUint32*)iScript; + else + if (aInterfaceId == KUidShaperGetLang) + return (TUint32*)iLanguage; + else + return CShaper::ExtendedInterface(aInterfaceId); + } + +/** This is implementation of CShaper::ShapeText for the Icu layout Engine + The data is taken from TInput and pass to the shaper. + A memory buffer is allocated on aHeapForOutput starting with TShapeHeader is allocated. + The results of the shaping are copied into this buffer and passed back via aOutput. + @param aOutput On success a new structure containing the results allocated on aHeapForOutput. + @param aInput The input text and other parameters. + @param aHeapForOutput On success, aOutput should be allocated from this and nothing else. + On failure, nothing should be allocated from it. + @return Error value from one of the system-wide error codes on failure, KErrNone on success. + @see CShaper::ShapeText + */ +TInt CIcuLayoutEngine::ShapeText(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput) + { + // For debugging - the heap before shaping + TInt totalAllocSize = 0; + TInt used; +#ifdef SHAPER_MEMORY_DEBUG + used = User::Heap().AllocSize(totalAllocSize); + RDebug::Print(_L("before shaping %d cells %d bytes used"), used, totalAllocSize); +#endif + + iFontInstance->SetSessionHandle(aInput.iSessionHandle); + TRAPD( error, IcuShapeTextL(aOutput, aInput, aHeapForOutput)); + if (error == KErrNoMemory) + { + used = User::Heap().AllocSize(totalAllocSize); + RDebug::Print(_L("shaper out of memory %d cells %d"), totalAllocSize, used); + } + +#ifdef SHAPER_MEMORY_DEBUG + used = User::Heap().AllocSize(totalAllocSize); + RDebug::Print(_L("Shaped %d characters %d glyphs "), aOutput->iCharacterCount, aOutput->iGlyphCount ); + RDebug::Print(_L("after shaping %d cells %d bytes used"), used, totalAllocSize); +#endif + + // hide the ICU error codes as KErrGeneral + if ((error == KErrNoMemory) || (error == KErrNone)) + return error; + else + return KErrGeneral; + } + +/** This calls the ICU Layout engine to shape the text. It allocates memory for the results +and then reads the results. This memory is freed by the caller. +This function can leave if OOM. + @param aOutput On success a new structure containing the results allocated on aHeapForOutput. + @param aInput The input text and other parameters. + @param aHeapForOutput On success, aOutput should be allocated from this and nothing else. + On failure, nothing should be allocated from it. + @return Error value from one of the system-wide error codes on failure, KErrNone on success. + @see CIcuLayoutEngine::ShapeText + */ +void CIcuLayoutEngine::IcuShapeTextL(TShapeHeader*& aOutput, const TInput& aInput, RHeap* aHeapForOutput) + { + LEErrorCode success = LE_NO_ERROR; + const LEUnicode * p = (LEUnicode *)aInput.iText->Ptr(); + TInt noChars = aInput.iEnd - aInput.iStart; + + // Call to layout + TInt noOfGlyphs = iEngine->layoutChars( + p, // chars - the input character context + aInput.iStart, // the offset of the first character to process + noChars, // count - the number of characters to process // offset + aInput.iText->Length(), // max - the number of characters in the input context // size of text + FALSE, // rightToLeft - TRUE if the characters are in a right to left directional run + 0, // start X + 0, // start Y + success); // result code + + if (success == LE_MEMORY_ALLOCATION_ERROR) + User::Leave(KErrNoMemory); + else if (success != LE_NO_ERROR) + { + User::Leave(KErrGeneral); + } + + + // Get some memory to pass into the layout engine for the results + TInt bufferSize = (sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(float) * 2) + * noOfGlyphs + sizeof(float) * 2; + TUint8* buffer = reinterpret_cast( User::AllocL(bufferSize) ); + CleanupStack::PushL(buffer); + LEGlyphID* glyphBuffer = reinterpret_cast(buffer); + le_int32* indexBuffer = reinterpret_cast(glyphBuffer + noOfGlyphs); + float* positionBuffer = reinterpret_cast(indexBuffer + noOfGlyphs); + + + // now get results glyph codes, positions and indices + // from the layout engine + if (success == LE_NO_ERROR) + iEngine->getGlyphs(glyphBuffer, success); + + if (success == LE_NO_ERROR) + iEngine->getGlyphPositions(positionBuffer, success); + + if (success == LE_NO_ERROR) + iEngine->getCharIndices(indexBuffer, aInput.iStart, success); + if (success == LE_NO_ERROR) + // Reset the memory used by the IcuLayoutEngine + iEngine->reset(); + if (success == LE_MEMORY_ALLOCATION_ERROR) + User::Leave(KErrNoMemory); + else + if (success != LE_NO_ERROR) + { + User::Leave(KErrGeneral); + } + + // Some of the glyph codes are 0xFFFF and 0x0001. 0xFFFF is a value used by ICU layout + // engine to indicate no glyph, and 0x0001 is used to indicate a ZWJ or a ZWNJ. + // These should be stripped out now. A ZWJ or a ZWNJ glyph has no meaning here. Their + // effects on the precedig and proceding characters have already been taken into + // consideration during shaping, so we don't need them anymore. + // Also, their presence in the final glyph list was causing GDI to break with GDI:1 + // i.e. more than 8 glyphs in a glyph cluster. + LEGlyphID gidOfZWJ = iFontInstance->mapCharToGlyph(0x200D); // Added by Symbian: 1922 mlyl + TInt actualNoOfGlyphs = 0; + for (LEGlyphID* p = glyphBuffer + noOfGlyphs; p != glyphBuffer;) + { + --p; + if (*p != 0xFFFF && *p != 0x0001 && *p != gidOfZWJ) // Added by Symbian: 1922 mlyl + ++actualNoOfGlyphs; + } + + // get some memory to pass back the results, + // This needs to be big enough for a TShapeHeader + // plus 10 bytes for every glyph returned (-1 for the 1 byte allocated in TShapeHeader for iBuffer) + aOutput = reinterpret_cast( aHeapForOutput->AllocL( + sizeof(TShapeHeader) + (actualNoOfGlyphs * 10) + 3) ); + + // get the results into the shaper structure aOutput + aOutput->iGlyphCount = actualNoOfGlyphs; + aOutput->iCharacterCount = noChars; + aOutput->iReserved0 = 0; + aOutput->iReserved1 = 0; + + // iBuffer contains 10 bytes for every glyph + // the glyph code (4 bytes), position X(2 bytes) Y(2 bytes) and indices(2 bytes) + + // first is glyph count * 4 byte glyph codes + TUint32* glyphOut = reinterpret_cast(aOutput->iBuffer); + TInt16* posOut = reinterpret_cast(aOutput->iBuffer + + (4 * actualNoOfGlyphs)); + TInt16* indicesOut = reinterpret_cast(aOutput->iBuffer + + (8 * actualNoOfGlyphs) + 4); + for (TInt i=0; i < noOfGlyphs; i++) + { + if (*glyphBuffer != 0xFFFF && *glyphBuffer != 0x0001 && *glyphBuffer != gidOfZWJ) // Added by Symbian: 1922 mlyl + { + *glyphOut++ = *glyphBuffer; + *posOut++ = FloatToInt( positionBuffer[0] ); + *posOut++ = FloatToInt( positionBuffer[1] ); + *indicesOut++ = *indexBuffer; + } + ++glyphBuffer; + positionBuffer += 2; + ++indexBuffer; + } + // There is an extra pair of positions: this is the total advance + posOut[0] = FloatToInt( positionBuffer[0] ); + posOut[1] = FloatToInt( positionBuffer[1] ); + + CleanupStack::PopAndDestroy(buffer); + + }