diff -r 000000000000 -r bde4ae8d615e os/graphics/graphicsdeviceinterface/gdi/sgdi/FontThai.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/graphicsdeviceinterface/gdi/sgdi/FontThai.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,968 @@ +// Copyright (c) 2003-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: +// + +/** + @file + @internalComponent +*/ + + +#include +#include "FontThai.h" + + +// +// ThaiGlyph Namespace definition +// + + +/** + This namespace holds functions used to evaluate a glyph character code + against a given Thai related prediciate. The 'code' argument is a glyph + from the current output cluster and so may be a Thai glyph, Thai PUA glyph, + the dotted circle glyph or 0xffff. Therefore it was decided not to implement + these routines using a data driven table approach as it would be inefficient. +@internalComponent. +*/ +namespace ThaiGlyph + { + const TText16 KYoYing = 0x0E0D; + const TText16 KYoYingPua = 0xF70F; + const TText16 KThoThan = 0x0E10; + const TText16 KThoThanPua = 0xF700; + const TText16 KNikhahit = 0x0E4D; + const TText16 KNikhahitPua = 0xF711; + const TText16 KSaraAa = 0x0E32; + const TText16 KSaraAm = 0x0E33; + + + TBool IsThaiGlyph(TUint code) + { + return ((code > 0x0E00 && code < 0x0E3B) || + (code > 0x0E3E && code < 0x0E5C) || + (code >= 0xF700 && code <= 0xF71A)); + } + + TBool IsThaiConsonant(TUint code) + { + return (code >= 0x0E01 && code <= 0x0E2E); + } + + TBool IsThaiTallConsonant(TUint code) + { + return (//code == 0x0E0A || // CHO CHANG not tall at all + //code == 0x0E0B || // SO SO not tall at all + code == 0x0E1B || // PO PLA + code == 0x0E1D || // FO FA + code == 0x0E1F || // FO FAN + code == 0x0E2C); // LO CHULA in some fonts, Unicode tables show it as tall + } + + TBool IsThaiShortConsonant(TUint code) + { + return (((code >= 0x0E01 && code <= 0x0E2E) || (code == KUnicodeDottedCircle)) && + code != 0x0E1B && // PO PLA + code != 0x0E1D && // FO FA + code != 0x0E1F && // FO FAN + code != 0x0E2C); // LO CHULA in some fonts, Unicode tables show it as tall + } + + TBool IsThaiConsonantWithDisjointDescender(TUint code) + { + return (code == ThaiGlyph::KYoYing || code == ThaiGlyph::KThoThan); + } + + TBool IsThaiConsonantWithJointDescender(TUint code) + { + return (code == 0x0E0E || // DO CHADA + code == 0x0E0F || // PO PATAK + code == 0x0E24 || // RU + code == 0x0E26); // LU + } + + TBool IsThaiVowel(TUint code) + { + return ((code >= 0x0E30 && code <= 0x0E3A) || + (code >= 0x0E40 && code <= 0x0E44) || + code == 0x0E47); // MAITAIKHU + } + + TBool IsThaiDepVowel(TUint code) + { + return (code == 0x0E31 || // MAI HAN-AKAT + (code >= 0x0E34 && code <= 0x0E3A) || + code == 0x0E47); // MAITAIKHU + } + + TBool IsThaiDepVowelAbove(TUint code) + { + return (code == 0x0E31 || // MAI HAN-AKAT + (code >= 0x0E34 && code <= 0x0E37) || + code == 0x0E47); // MAITAIKHU + } + + TBool IsThaiDepVowelAbovePUA(TUint code) + { + return (code == 0xF710 || // MAI HAN-AKAT + (code >= 0xF701 && code <= 0xF704) || + code == 0xF712); // MAITAIKHU + } + + TBool IsThaiDepVowelBelow(TUint code) + { + return (code >= 0x0E38 && code <= 0x0E3A); + } + + TBool IsThaiIndepVowel(TUint code) + { + return (code == 0x0E30 || // SARA A + code == 0x0E32 || // SARA AA + code == 0x0E33 || // SARA AM + (code >= 0x0E40 && code <= 0x0E44)); + } + + TBool IsThaiToneMark(TUint code) + { + return (code >= 0x0E48 && code <= 0x0E4B); + } + } + + +// +// +// ThaiCharRules Namespace definition +// +// + + +/** + ThaiCharRules namespace holds the data and lookup methods + implementing the WTT 2.0 input/output validation matrix. +@internalComponent +*/ +namespace ThaiCharRules + { + const TUint KThaiCodePageStart = 0x0E00; + const TUint KThaiCodePageEnd = 0x0E5C; + const TUint KNumThaiCharacters = KThaiCodePageEnd-KThaiCodePageStart; + + enum Wtt2Rule + { + EUndefined, + EAccept, + EComposite, + EReject, + ERejectStrict, + }; + + /** + This enumeration holds the set of classification values a Thai + character can be categorised as in the WTT2.0 specification. + */ + enum CharClassification + { + ENull, + EControl, + ENonPrintable, + EConsonant, + ELeadingVowel, + EOrdinaryFollowingVowel, + EDependentFollowingVowel, + ESpecialFollowingVowel, + EShortBelowVowel, + ELongBelowVowel, + EBelowDiacritic, + EToneMark, + EAboveDiacritic0, + EAboveDiacritic1, + EAboveDiacritic2, + EAboveDiacritic3, + EAboveVowel1, + EAboveVowel2, + EAboveVowel3, + // marker for end + EMaxClassification + }; + + + /** + Data table holding the classification of each character. + */ + static const TUint8 iCharClassifications[KNumThaiCharacters] = + { + ENull, // No entry in code page + EConsonant, // 0x0E01 + EConsonant, // 0x0E02 + EConsonant, // 0x0E03 + EConsonant, // 0x0E04 + EConsonant, // 0x0E05 + EConsonant, // 0x0E06 + EConsonant, // 0x0E07 + EConsonant, // 0x0E08 + EConsonant, // 0x0E09 + EConsonant, // 0x0E0A + EConsonant, // 0x0E0B + EConsonant, // 0x0E0C + EConsonant, // 0x0E0D + EConsonant, // 0x0E0E + EConsonant, // 0x0E0F + + EConsonant, // 0x0E10 + EConsonant, // 0x0E11 + EConsonant, // 0x0E12 + EConsonant, // 0x0E13 + EConsonant, // 0x0E14 + EConsonant, // 0x0E15 + EConsonant, // 0x0E16 + EConsonant, // 0x0E17 + EConsonant, // 0x0E18 + EConsonant, // 0x0E19 + EConsonant, // 0x0E1A + EConsonant, // 0x0E1B + EConsonant, // 0x0E1C + EConsonant, // 0x0E1D + EConsonant, // 0x0E1E + EConsonant, // 0x0E1F + + EConsonant, // 0x0E20 + EConsonant, // 0x0E21 + EConsonant, // 0x0E22 + EConsonant, // 0x0E23 + EConsonant, // 0x0E24 + EConsonant, // 0x0E25 + EConsonant, // 0x0E26 + EConsonant, // 0x0E27 + EConsonant, // 0x0E28 + EConsonant, // 0x0E29 + EConsonant, // 0x0E2A + EConsonant, // 0x0E2B + EConsonant, // 0x0E2C + EConsonant, // 0x0E2D + EConsonant, // 0x0E2E + ENonPrintable, // 0x0E2F + + EOrdinaryFollowingVowel,// 0x0E30 + EAboveVowel2, // 0x0E31 + EOrdinaryFollowingVowel,// 0x0E32 + EOrdinaryFollowingVowel,// 0x0E33 + EAboveVowel1, // 0x0E34 + EAboveVowel3, // 0x0E35 + EAboveVowel2, // 0x0E36 + EAboveVowel3, // 0x0E37 + EShortBelowVowel, // 0x0E38 + ELongBelowVowel, // 0x0E39 + EBelowDiacritic, // 0x0E3A + ENull, // 0x0E3B + ENull, // 0x0E3C + ENull, // 0x0E3D + ENull, // 0x0E3E + ENonPrintable, // 0x0E3F + + ELeadingVowel, // 0x0E40 + ELeadingVowel, // 0x0E41 + ELeadingVowel, // 0x0E42 + ELeadingVowel, // 0x0E43 + ELeadingVowel, // 0x0E44 + EDependentFollowingVowel,//0x0E45 + ENonPrintable, // 0x0E46 + EAboveDiacritic2, // 0x0E47 + EToneMark, // 0x0E48 + EToneMark, // 0x0E49 + EToneMark, // 0x0E4A + EToneMark, // 0x0E4B + EAboveDiacritic1, // 0x0E4C + EAboveDiacritic0, // 0x0E4D + EAboveDiacritic3, // 0x0E4E + ENonPrintable, // 0x0E4F + + ENonPrintable, // 0x0E50 + ENonPrintable, // 0x0E51 + ENonPrintable, // 0x0E52 + ENonPrintable, // 0x0E53 + ENonPrintable, // 0x0E54 + ENonPrintable, // 0x0E55 + ENonPrintable, // 0x0E56 + ENonPrintable, // 0x0E57 + ENonPrintable, // 0x0E58 + ENonPrintable, // 0x0E59 + ENonPrintable, // 0x0E5A + ENonPrintable, // 0x0E5B + + // Value at last measurement was 92 bytes. 27/6/2003 + }; + + + /** + WTT 2.0 Rules data table of prev to next character + */ + static const TUint8 iInputRules[EMaxClassification][EMaxClassification] = + { + /* Previous character ENull */ + { + EUndefined, EUndefined, EUndefined, EUndefined, EUndefined, + EUndefined, EUndefined, EUndefined, EUndefined, EUndefined, + EUndefined, EUndefined, EUndefined, EUndefined, EUndefined, + EUndefined, EUndefined, EUndefined, EUndefined + }, + + /* Previous character EControl */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + EAccept, EAccept, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character ENonPrintable */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EConsonant */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + EAccept, ERejectStrict, EAccept, EComposite, EComposite, + EComposite, EComposite, EComposite, EComposite, EComposite, EComposite, + EComposite, EComposite, EComposite, + }, + + /* Previous character ELeadingVowel */ + { + EUndefined, EUndefined, ERejectStrict, EAccept, ERejectStrict, + ERejectStrict, ERejectStrict, ERejectStrict, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EOrdinaryFollowingVowel */ + { + EUndefined, EUndefined, ERejectStrict, EAccept, ERejectStrict, + EAccept, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EDependentFollowingVowel */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + EAccept, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character ESpecialFollowingVowel */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, EAccept, ERejectStrict, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EShortBelowVowel */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + EAccept, ERejectStrict, EAccept, EReject, EReject, + EReject, EComposite, EComposite, EComposite, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character ELongBelowVowel */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EComposite, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EBelowDiacritic */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EToneMark */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + EAccept, EAccept, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveDiacritic0 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveDiacritic1 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveDiacritic2 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveDiacritic3 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EReject, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveVowel1 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EComposite, EReject, EComposite, EReject, EReject, +// EReject, EComposite, EComposite, EComposite, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveVowel2 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EComposite, EReject, EReject, EReject, EReject, + EReject, EReject, EReject, + }, + + /* Previous character EAboveVowel3 */ + { + EUndefined, EUndefined, EAccept, EAccept, EAccept, + ERejectStrict, ERejectStrict, EAccept, EReject, EReject, + EReject, EComposite, EReject, EReject, EReject, EReject, +// EReject, EComposite, EReject, EComposite, EReject, + EReject, EReject, EReject, + }, + + // Value at last measurement was 324 bytes. 27/6/2003 + }; + + + /** + This routine looks up the WTT 2.0 rule for the given + Thai character codes provided in the WTT 2.0 data table. + @param aPrevChar + Unicode character code preceding the assumed position. + @param aChar + Unicode character code proceeding the assumed position. + @return Wtt2Rule + The rule value found in data table. + */ + Wtt2Rule LookupWtt2Rule(TUint aPrevChar, TUint aChar) + { + const CharClassification prevCharClassification = + static_cast( + (aPrevChar > KThaiCodePageStart && aPrevChar < KThaiCodePageEnd) ? + iCharClassifications[aPrevChar - KThaiCodePageStart] : + ENonPrintable); + const CharClassification charClassification = + static_cast( + (aChar > KThaiCodePageStart && aChar < KThaiCodePageEnd) ? + iCharClassifications[aChar - KThaiCodePageStart] : + ENonPrintable); + + return static_cast + (iInputRules[prevCharClassification][charClassification]); + } + + } + +using namespace ThaiCharRules; + + +// +// +// ThaiGlyphPUASubstitution Namespace definition +// +// + + +/** + This utility namespace holds the data and lookup mechanisms to support + the GlyphSelector_Thai glyph selection class in choosing Private User + Area (PUA) Thai character positional variant glyphs. Use of the PUA glyphs + results in a satisfactory rendition of Thai writing in Symbian OS. +@internalComponent +*/ +namespace ThaiGlyphPUASubstitution + { + + typedef TBool (*UnicodeCharValidator)(const TGlyphSelectionState& aGss); + + struct PUASubstTableEntry + { + TUint iOrigGlyph; + TUint iPUAGlyph; + UnicodeCharValidator iRuleFunc; + }; + + + /** + ThaiGlyphPUASubstitution rule method which checks the context for + short consonant preceding char OR + short consonant & dependent vowel below preceding char. + @param aGss + Container object holds the glyph selection context for the method. + @return TBool + ETrue when the rule context is satisfied, EFalse if not. + */ + TBool RuleShortConsonant(const TGlyphSelectionState& aGss) + { + if (aGss.iParam.iOutputGlyphs == 1) { + //check the context for short consonant preceding char + TUint consonantGss = aGss.iParam.iOutput[0].iCode; + if (ThaiGlyph::IsThaiShortConsonant(consonantGss) || + consonantGss == ThaiGlyph::KYoYingPua || + consonantGss == ThaiGlyph::KThoThanPua) + return ETrue; + else + return EFalse; + } + if (aGss.iParam.iOutputGlyphs == 2) { + //check the context for short consonant & dependent vowel below preceding char + TUint consonantGss = aGss.iParam.iOutput[0].iCode; + TUint depVowelGss = aGss.iParam.iOutput[1].iCode; + if ((ThaiGlyph::IsThaiShortConsonant(consonantGss) || + consonantGss == ThaiGlyph::KYoYingPua || + consonantGss == ThaiGlyph::KThoThanPua) && + (ThaiGlyph::IsThaiDepVowelBelow(depVowelGss) || + (depVowelGss >= 0xF718 && + depVowelGss <= 0xF71A))) + return ETrue; + else + return EFalse; + } + return EFalse; + } + + /** + ThaiGlyphPUASubstitution rule method which checks the context for + tall consonant preceding char. + @param aGss + Container object holds the glyph selection context for the method. + @return TBool + ETrue when the rule context is satisfied, EFalse if not. + */ + TBool RuleTallConsonant(const TGlyphSelectionState& aGss) + { + if ((aGss.iParam.iOutputGlyphs == 1) && + ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode)) + return ETrue; + else + return EFalse; + } + + /** + ThaiGlyphPUASubstitution rule method which checks the context for a tall + consonant which does not have a dependent vowel above or a nikhahit or a + following sara am. + @param aGss + Container object holds the glyph selection context for the method. + @return TBool + ETrue when the rule context is satisfied, EFalse if not. + */ + TBool RuleTallConsonantNoVowelAbove(const TGlyphSelectionState& aGss) + { + if (aGss.iParam.iOutputGlyphs == 0) + return EFalse; + if (!ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode)) + return EFalse; + if (aGss.iParam.iOutputGlyphs == 1) + return ETrue; + if (aGss.iParam.iOutputGlyphs != 2) + return EFalse; + TUint wantDepVowel = aGss.iParam.iOutput[1].iCode; + if (ThaiGlyph::IsThaiDepVowelAbove(wantDepVowel) + || ThaiGlyph::IsThaiDepVowelAbovePUA(wantDepVowel) + || wantDepVowel == ThaiGlyph::KNikhahit + || wantDepVowel == ThaiGlyph::KNikhahitPua) + return EFalse; + return ETrue; + } + + /** + ThaiGlyphPUASubstitution rule method which checks the context for tall + consonant with either a dependent vowel above or nikhahit. + @param aGss + Container object holds the glyph selection context for the method. + @return TBool + ETrue when the rule context is satisfied, EFalse if not. + */ + TBool RuleTallConsonantVowelAbove(const TGlyphSelectionState& aGss) + { + if ((aGss.iParam.iOutputGlyphs == 2) && + ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode) && + (ThaiGlyph::IsThaiDepVowelAbovePUA(aGss.iParam.iOutput[1].iCode)) + || aGss.iParam.iOutput[1].iCode == ThaiGlyph::KNikhahitPua) + return ETrue; + else + return EFalse; + } + + /** + ThaiGlyphPUASubstitution rule method which checks the context for + consonant with joined descender preceding char. + @param aGss + Container object holds the glyph selection context for the method. + @return TBool + ETrue when the rule context is satisfied, EFalse if not. + */ + TBool RuleConsonantWithJointDescender(const TGlyphSelectionState& aGss) + { + if ((aGss.iParam.iOutputGlyphs == 1) && + ThaiGlyph::IsThaiConsonantWithJointDescender(aGss.iParam.iOutput[0].iCode)) + return ETrue; + else + return EFalse; + } + + + const PUASubstTableEntry RuleTable[] = { + /** + This data member of the ThaiGlyphPUASubstitution class holds rules + on when a given PUA glyph should be substituted for the original + 0x0Exx glyph. Table lookup returns the first match found from the + start of the table, therefore duplicate match situations must be + avoided in the rule set logic. + */ + /* iOrigGlyph, iPUAGlyph, iRuleFunc */ + + // Substitutions for a tone or sign mark above a short consonant + { 0x0E48, 0xF70A, RuleShortConsonant }, + { 0x0E49, 0xF70B, RuleShortConsonant }, + { 0x0E4A, 0xF70C, RuleShortConsonant }, + { 0x0E4B, 0xF70D, RuleShortConsonant }, + { 0x0E4C, 0xF70E, RuleShortConsonant }, + + // Substitutions for a vowel or sign mark above a tall consonant + { 0x0E34, 0xF701, RuleTallConsonant }, + { 0x0E35, 0xF702, RuleTallConsonant }, + { 0x0E36, 0xF703, RuleTallConsonant }, + { 0x0E37, 0xF704, RuleTallConsonant }, + { 0x0E31, 0xF710, RuleTallConsonant }, + { 0x0E4D, 0xF711, RuleTallConsonant }, + { 0x0E47, 0xF712, RuleTallConsonant }, + + // Substitutions for a tone or sign mark above a tall consonant + { 0x0E48, 0xF705, RuleTallConsonantNoVowelAbove }, + { 0x0E49, 0xF706, RuleTallConsonantNoVowelAbove }, + { 0x0E4A, 0xF707, RuleTallConsonantNoVowelAbove }, + { 0x0E4B, 0xF708, RuleTallConsonantNoVowelAbove }, + { 0x0E4C, 0xF709, RuleTallConsonantNoVowelAbove }, + + // Substitutions for a tone or sign mark above a vowel which is + // above a tall consonant + { 0x0E48, 0xF713, RuleTallConsonantVowelAbove }, + { 0x0E49, 0xF714, RuleTallConsonantVowelAbove }, + { 0x0E4A, 0xF715, RuleTallConsonantVowelAbove }, + { 0x0E4B, 0xF716, RuleTallConsonantVowelAbove }, + { 0x0E4C, 0xF717, RuleTallConsonantVowelAbove }, + + // Substitutions for a vowel or sign mark below a consonant with a + // joined descender + { 0x0E38, 0xF718, RuleConsonantWithJointDescender }, + { 0x0E39, 0xF719, RuleConsonantWithJointDescender }, + { 0x0E3A, 0xF71A, RuleConsonantWithJointDescender }, + + { 0, 0, 0} + + // Size of table at last measurement was 312 bytes. 27/6/2003 + }; + + + /** + This is the lookup method to determine if the current character being + processed needs to be substituted for a glyph in the PUA area given the + supplied context. It scans the rule table and returns when it finds it's + first match. Therefore duplicate match situations must be avoided in + the rule set logic. + @param aCode + On input it is the character to lookup, on exit it is either unchanged + or a code in the PUA 0xF700..0xF71A. + @param aGss + Container object holds the glyph selection context for the method. + @return TBool + ETrue when a match is found and aCode has changed, EFalse otherwise. + */ + TBool Lookup(TUint& aCode, const TGlyphSelectionState& aGss) + { + const PUASubstTableEntry* tablePtr = RuleTable; + while (tablePtr->iOrigGlyph) + { + if ((aCode == tablePtr->iOrigGlyph) && tablePtr->iRuleFunc(aGss)) + { + aCode = tablePtr->iPUAGlyph; + return ETrue; // Rule match, substitute glyph code + } + tablePtr++; + } + return EFalse; // No match in table + } + } + + +// +// +// GlyphSelector_Thai Class definition +// +// + + +/** + This is the default glyph processing method for the Thai characters in the + range 0x0E00..0x0E7F and is invoked from the Glyph selection algorithm in + CFont::GetCharacterPosition() method. It is capable of processing base + Thai characters as well as Thai combining vowels, signs a tone marks. +@param aGss + Container object holds the input/output parameters of the method. +@return TBool + ETrue when glyph cluster updated successfully, EFalse on error condition. +@see + The method GlyphSelector_Thai::Process() also handles it for other cases. +*/ +TBool GlyphSelector_Thai::Process(TGlyphSelectionState& aGss, RShapeInfo&) + { + // Get the Unicode character codes we need to process the current + // glyph and increment the iterator onto th next character. + TUint prevCode = (aGss.iText.LengthToStart() > 0) ? aGss.iText.Get(-1) : 0xFFFF; + TUint code = aGss.iText.GetThenNext(); // Inc to next char + TUint nextCode = !aGss.iText.AtEnd() ? aGss.iText.Get(0) : 0xFFFF; + + // Is it a Thai base char or a mark (combining) char? + if ((aGss.iCats & 0xF0) == TChar::EMarkGroup) + { + + // Thai character is combining mark but first check to see if it + // follows a Thai base character before processing it. + if ((aGss.iParam.iOutputGlyphs > 0) && + !ThaiGlyph::IsThaiGlyph(prevCode)) + { + (void) aGss.iText.Prev(); + aGss.iClusterState = TGlyphSelectionState::EGClusterComplete; + return ETrue; + } + + // Missing base glyph? Insert a dotted circle glyph if true. + if (aGss.iParam.iOutputGlyphs == 0) + { + if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle)) + return EFalse; + aGss.iParam.iPen += aGss.iAdvance; + } + + // Test if SARA AM follows this current Thai mark, since it is + // a SPECIAL CASE. If present we need NIKHAHIT glyph before this + // current Thai mark char. + if (nextCode == ThaiGlyph::KSaraAm && + (aGss.iParam.iOutputGlyphs == 1) && ThaiGlyph::IsThaiToneMark(code)) + { + TUint nikhahit = ThaiGlyph::KNikhahit; + // Check and do PUA glyph substitution on Nikhahit + ThaiGlyphPUASubstitution::Lookup(nikhahit, aGss); + + if (!aGss.AppendGlyphToCluster(nikhahit)) + return EFalse; + + // Check and do PUA glyph substitution on combining mark + ThaiGlyphPUASubstitution::Lookup(code, aGss); + + // Append the curernt Thai Mark to the output stack of glyphs. + if (!aGss.AppendGlyphToCluster(code)) + return EFalse; + + // We now need to add SARA AA glyph after the current Thai mark char. + aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0; + if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAa)) + return EFalse; + + // Skip the following SARA AM character since we've added + // its glyphs to it's previous character's glyph cluster. + // As we've added a base char to the end of the glyph cluster + // make sure the pen is moved on by the caller. + (void) aGss.iText.Next(); + aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes; + } + else + { + // Check and do PUA glyph substitution on combining mark + ThaiGlyphPUASubstitution::Lookup(code, aGss); + + // Append the curernt Thai Mark to the output stack of glyphs. + if (!aGss.AppendGlyphToCluster(code)) + return EFalse; + + aGss.iPen = TGlyphSelectionState::EPenAdvance_No; + } + } + else + + { + // Thai character is an independent consonant, digit or sign + + // Handle disjoint descender consonants followed by below vowel. + // In these two cases we substitute consonant with PUA + // consonant that the descender removed. Check code not last one. + if (code == ThaiGlyph::KYoYing && nextCode != 0xffff && + ThaiGlyph::IsThaiDepVowelBelow(nextCode)) + code = ThaiGlyph::KYoYingPua; + else if (code == ThaiGlyph::KThoThan && nextCode != 0xffff && + ThaiGlyph::IsThaiDepVowelBelow(nextCode)) + code = ThaiGlyph::KThoThanPua; + + // Append the glyph details for the Thai character onto the output + // stack of glyphs. + if (!aGss.AppendGlyphToCluster(code)) + return EFalse; + + // Make sure the caller advances the pen for a base char! + aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes; + } + + // Lookup in rule table to determine if the current glyph and cluster is + // now complete? + if (ThaiCharRules::LookupWtt2Rule(aGss.iCodePt, nextCode) == ThaiCharRules::EComposite) + aGss.iClusterState = TGlyphSelectionState::EGClusterNotComplete; + else + aGss.iClusterState = TGlyphSelectionState::EGClusterComplete; + + return ETrue; + } + + +// +// +// GlyphSelector_ThaiSaraAm Class definition +// +// + + +/** + This is the glyph processing method for the Thai SARA AM (U+0E33) character + which is handled as a special case since it is decomposed into two glyphs + - the combining NIKHAHIT mark & SARA AA following vowel in some cases. + It is invoked from the Glyph selection algorithm in + CFont::GetCharacterPosition() method for all cases where SARA AM is not + following a tone mark and thus be a glyph cluster of its own. +@param aGss + Container object holds the input/output parameters of the method. +@return TBool + ETrue when glyph cluster updated successfully, EFalse on error condition. +@see + The method GlyphSelector_Thai::Process() also handles it for other cases. +*/ +TBool GlyphSelector_ThaiSaraAm::Process(TGlyphSelectionState& aGss, RShapeInfo&) + { + if (aGss.iCodePt != ThaiGlyph::KSaraAm) //could have got here via + { //FindLocalisedProcessFunc in font.cpp + RShapeInfo dummy; + return GlyphSelector_Thai::Process(aGss, dummy); + } + + // Pen advance accumulator local variable + TSize compoundAdvance; + + if (aGss.iText.LengthToStart() == 0) + { + // If at the start of a line then render it with a preceding + // dotted circle as this is invalid positioning for SARA AM. + + if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle)) + return EFalse; + aGss.iParam.iPen += aGss.iAdvance; + + aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0; + if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm)) + return EFalse; + compoundAdvance += aGss.iAdvance; + } + else + { + // Normal condition - text iterator now some way into the text line + // being processed. + + TUint prevChar = aGss.iText.Get(-1); + if (ThaiGlyph::IsThaiShortConsonant(prevChar)) + { + // SARA AM is following normal height consonant so we can output + // non-decomposed SARA AM glyph. + + if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm)) + return EFalse; + compoundAdvance = aGss.iAdvance; + } + else if (ThaiGlyph::IsThaiTallConsonant(prevChar)) + { + // SARA AM is following tall consonant so we output decomposed + // version of SARA AM but with NIKHAHIT taken from the PUA. + + if (!aGss.AppendGlyphToCluster(ThaiGlyph::KNikhahitPua)) + return EFalse; + compoundAdvance = aGss.iAdvance; + aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0; + if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAa)) + return EFalse; + compoundAdvance += aGss.iAdvance; + } + else + { + // SARA AM is a following vowel but is not following a valid + // consonant char and so default is to render with dotted circle. + if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle)) + return EFalse; + aGss.iParam.iPen += aGss.iAdvance; + + aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0; + if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm)) + return EFalse; + compoundAdvance += aGss.iAdvance; + } + + } + + // Update output parameters resulting from above processing. + // Move text iterator onto next character to process. + aGss.iText.Next(); + + // Advance pen just for the SARA AA char as advance for dotted + // circle is done above. + aGss.iAdvance = compoundAdvance; + aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes; + + if (!aGss.iText.AtEnd() && + (ThaiCharRules::LookupWtt2Rule(aGss.iCodePt, aGss.iText.Get()) == + ThaiCharRules::EComposite)) + aGss.iClusterState = TGlyphSelectionState::EGClusterNotComplete; + else + aGss.iClusterState = TGlyphSelectionState::EGClusterComplete; + + return ETrue; + }