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