os/textandloc/fontservices/textbase/sgdi/FontThai.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2003-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 /**
    17  @file
    18  @internalComponent
    19 */
    20 
    21 
    22 //#include <textbase.h>
    23 #include <gdi.h>
    24 #include "FontThai.h"
    25 
    26 
    27 //
    28 // ThaiGlyph Namespace definition
    29 //
    30 
    31 
    32 /**
    33  This namespace holds functions used to evaluate a glyph character code
    34  against a given Thai related prediciate. The 'code' argument is a glyph
    35  from the current output cluster and so may be a Thai glyph, Thai PUA glyph, 
    36  the dotted circle glyph or 0xffff. Therefore it was decided not to implement
    37  these routines using a data driven table approach as it would be inefficient.
    38 @internalComponent.
    39 */
    40 namespace ThaiGlyph
    41     {
    42     const TText16 KYoYing		= 0x0E0D;
    43     const TText16 KYoYingPua	= 0xF70F;
    44     const TText16 KThoThan		= 0x0E10;
    45     const TText16 KThoThanPua	= 0xF700;
    46     const TText16 KNikhahit	    = 0x0E4D;
    47     const TText16 KNikhahitPua	= 0xF711;
    48     const TText16 KSaraAa		= 0x0E32;
    49     const TText16 KSaraAm		= 0x0E33;
    50 
    51     
    52      TBool IsThaiGlyph(TUint code)
    53     	{
    54        	return ((code > 0x0E00 && code < 0x0E3B) ||
    55     			(code > 0x0E3E && code < 0x0E5C) ||
    56     			(code >= 0xF700 && code <= 0xF71A));
    57     	}
    58 
    59      TBool IsThaiConsonant(TUint code)
    60     	{
    61     	return (code >= 0x0E01 && code <= 0x0E2E);
    62     	}
    63 
    64      TBool IsThaiTallConsonant(TUint code)
    65     	{
    66     	return (//code == 0x0E0A ||	// CHO CHANG not tall at all
    67     			//code == 0x0E0B ||	// SO SO not tall at all
    68     			code == 0x0E1B ||	// PO PLA
    69     			code == 0x0E1D ||	// FO FA
    70     			code == 0x0E1F ||	// FO FAN
    71     			code == 0x0E2C);	// LO CHULA in some fonts, Unicode tables show it as tall
    72     	}
    73 
    74      TBool IsThaiShortConsonant(TUint code)
    75     	{
    76     	return (((code >= 0x0E01 && code <= 0x0E2E) || (code == KUnicodeDottedCircle)) &&
    77     			code != 0x0E1B &&	// PO PLA
    78     			code != 0x0E1D &&	// FO FA
    79     			code != 0x0E1F &&	// FO FAN
    80     			code != 0x0E2C);	// LO CHULA in some fonts, Unicode tables show it as tall
    81     	}
    82 
    83      TBool IsThaiConsonantWithDisjointDescender(TUint code)
    84     	{
    85     	return (code == ThaiGlyph::KYoYing || code == ThaiGlyph::KThoThan);
    86     	}
    87 
    88      TBool IsThaiConsonantWithJointDescender(TUint code)
    89     	{
    90     	return (code == 0x0E0E || // DO CHADA
    91     			code == 0x0E0F || // PO PATAK
    92     			code == 0x0E24 || // RU
    93        			code == 0x0E26);  // LU
    94     	}
    95 
    96      TBool IsThaiVowel(TUint code)
    97     	{
    98     	return ((code >= 0x0E30 && code <= 0x0E3A) ||
    99     			(code >= 0x0E40 && code <= 0x0E44) ||
   100     			code == 0x0E47);	// MAITAIKHU
   101     	}
   102 
   103      TBool IsThaiDepVowel(TUint code)
   104     	{
   105     	return (code == 0x0E31 ||	// MAI HAN-AKAT
   106     			(code >= 0x0E34 && code <= 0x0E3A) ||
   107     			code == 0x0E47);	// MAITAIKHU
   108     	}
   109 
   110      TBool IsThaiDepVowelAbove(TUint code)
   111     	{
   112     	return (code == 0x0E31 ||	// MAI HAN-AKAT
   113     			(code >= 0x0E34 && code <= 0x0E37) ||
   114     			code == 0x0E47);	// MAITAIKHU
   115     	}
   116 
   117      TBool IsThaiDepVowelAbovePUA(TUint code)
   118     	{
   119     	return (code == 0xF710 ||	// MAI HAN-AKAT
   120     			(code >= 0xF701 && code <= 0xF704) ||
   121     			code == 0xF712);	// MAITAIKHU
   122     	}
   123 
   124      TBool IsThaiDepVowelBelow(TUint code)
   125     	{
   126     	return (code >= 0x0E38 && code <= 0x0E3A);
   127     	}
   128 
   129      TBool IsThaiIndepVowel(TUint code)
   130     	{
   131     	return (code == 0x0E30 ||	// SARA A
   132       			code == 0x0E32 ||	// SARA AA
   133     			code == 0x0E33 ||	// SARA AM
   134     			(code >= 0x0E40 && code <= 0x0E44));
   135     	}
   136 
   137      TBool IsThaiToneMark(TUint code)
   138     	{
   139     	return (code >= 0x0E48 && code <= 0x0E4B);
   140     	}
   141     }
   142 
   143     
   144 //
   145 //
   146 // ThaiCharRules Namespace definition
   147 //
   148 //
   149 
   150 
   151 /**
   152  ThaiCharRules namespace holds the data and lookup methods
   153  implementing the WTT 2.0 input/output validation matrix.
   154 @internalComponent
   155 */
   156 namespace ThaiCharRules
   157 	{
   158   	const TUint KThaiCodePageStart      = 0x0E00;
   159 	const TUint KThaiCodePageEnd        = 0x0E5C;
   160 	const TUint KNumThaiCharacters      = KThaiCodePageEnd-KThaiCodePageStart;
   161 
   162 	enum Wtt2Rule
   163 		{
   164 		EUndefined,
   165 		EAccept,
   166 		EComposite,
   167 		EReject,
   168 		ERejectStrict,
   169 		};
   170 
   171 	/**
   172 	This enumeration holds the set of classification values a Thai
   173 	character can be categorised as in the WTT2.0 specification.
   174 	*/
   175 	enum CharClassification
   176 		{
   177 		ENull,
   178 		EControl,
   179 		ENonPrintable,
   180 		EConsonant,
   181 		ELeadingVowel,
   182 		EOrdinaryFollowingVowel,
   183 		EDependentFollowingVowel,
   184 		ESpecialFollowingVowel,
   185 		EShortBelowVowel,
   186 		ELongBelowVowel,
   187 		EBelowDiacritic,
   188 		EToneMark,
   189 		EAboveDiacritic0,
   190 		EAboveDiacritic1,
   191 		EAboveDiacritic2,
   192 		EAboveDiacritic3,
   193 		EAboveVowel1,
   194 		EAboveVowel2,
   195 		EAboveVowel3,
   196 		// marker for end
   197 		EMaxClassification
   198 		};
   199 
   200 
   201 	/**
   202 	 Data table holding the classification of each character.
   203 	*/
   204 	static const TUint8 iCharClassifications[KNumThaiCharacters] = 
   205         {
   206     	ENull,			// No entry in code page
   207     	EConsonant,		// 0x0E01
   208     	EConsonant,		// 0x0E02
   209     	EConsonant,		// 0x0E03
   210     	EConsonant,		// 0x0E04
   211     	EConsonant,		// 0x0E05
   212     	EConsonant,		// 0x0E06
   213     	EConsonant,		// 0x0E07
   214     	EConsonant,		// 0x0E08
   215     	EConsonant,		// 0x0E09
   216     	EConsonant,		// 0x0E0A
   217     	EConsonant,		// 0x0E0B
   218     	EConsonant,		// 0x0E0C
   219     	EConsonant,		// 0x0E0D
   220     	EConsonant,		// 0x0E0E
   221     	EConsonant,		// 0x0E0F
   222 
   223     	EConsonant,		// 0x0E10
   224     	EConsonant,		// 0x0E11
   225     	EConsonant,		// 0x0E12
   226     	EConsonant,		// 0x0E13
   227     	EConsonant,		// 0x0E14
   228     	EConsonant,		// 0x0E15
   229     	EConsonant,		// 0x0E16
   230     	EConsonant,		// 0x0E17
   231     	EConsonant,		// 0x0E18
   232     	EConsonant,		// 0x0E19
   233     	EConsonant,		// 0x0E1A
   234     	EConsonant,		// 0x0E1B
   235     	EConsonant,		// 0x0E1C
   236     	EConsonant,		// 0x0E1D
   237     	EConsonant,		// 0x0E1E
   238     	EConsonant,		// 0x0E1F
   239 
   240     	EConsonant,		// 0x0E20
   241     	EConsonant,		// 0x0E21
   242     	EConsonant,		// 0x0E22
   243     	EConsonant,		// 0x0E23
   244     	EConsonant,		// 0x0E24
   245     	EConsonant,		// 0x0E25
   246     	EConsonant,		// 0x0E26
   247     	EConsonant,		// 0x0E27
   248     	EConsonant,		// 0x0E28
   249     	EConsonant,		// 0x0E29
   250     	EConsonant,		// 0x0E2A
   251     	EConsonant,		// 0x0E2B
   252     	EConsonant,		// 0x0E2C
   253     	EConsonant,		// 0x0E2D
   254     	EConsonant,		// 0x0E2E
   255     	ENonPrintable,	// 0x0E2F
   256 
   257     	EOrdinaryFollowingVowel,// 0x0E30
   258     	EAboveVowel2,			// 0x0E31
   259     	EOrdinaryFollowingVowel,// 0x0E32
   260     	EOrdinaryFollowingVowel,// 0x0E33
   261     	EAboveVowel1,			// 0x0E34
   262     	EAboveVowel3,			// 0x0E35
   263     	EAboveVowel2,			// 0x0E36
   264     	EAboveVowel3,			// 0x0E37
   265     	EShortBelowVowel,		// 0x0E38
   266     	ELongBelowVowel,		// 0x0E39
   267     	EBelowDiacritic,		// 0x0E3A
   268     	ENull,					// 0x0E3B
   269     	ENull,					// 0x0E3C
   270     	ENull,					// 0x0E3D
   271     	ENull,					// 0x0E3E
   272     	ENonPrintable,			// 0x0E3F
   273 
   274     	ELeadingVowel,			// 0x0E40
   275     	ELeadingVowel,			// 0x0E41
   276     	ELeadingVowel,			// 0x0E42
   277     	ELeadingVowel,			// 0x0E43
   278     	ELeadingVowel,			// 0x0E44
   279     	EDependentFollowingVowel,//0x0E45
   280     	ENonPrintable,			// 0x0E46
   281     	EAboveDiacritic2,		// 0x0E47
   282     	EToneMark,				// 0x0E48
   283     	EToneMark,				// 0x0E49
   284     	EToneMark,				// 0x0E4A
   285     	EToneMark,				// 0x0E4B
   286     	EAboveDiacritic1,		// 0x0E4C
   287     	EAboveDiacritic0,		// 0x0E4D
   288     	EAboveDiacritic3,		// 0x0E4E
   289     	ENonPrintable,			// 0x0E4F
   290 
   291     	ENonPrintable,			// 0x0E50
   292     	ENonPrintable,			// 0x0E51
   293     	ENonPrintable,			// 0x0E52
   294     	ENonPrintable,			// 0x0E53
   295     	ENonPrintable,			// 0x0E54
   296     	ENonPrintable,			// 0x0E55
   297     	ENonPrintable,			// 0x0E56
   298     	ENonPrintable,			// 0x0E57
   299     	ENonPrintable,			// 0x0E58
   300     	ENonPrintable,			// 0x0E59
   301     	ENonPrintable,			// 0x0E5A
   302     	ENonPrintable,			// 0x0E5B
   303 
   304     	// Value at last measurement was 92 bytes. 27/6/2003
   305         };
   306 
   307 
   308 	/**
   309 	 WTT 2.0 Rules data table of prev to next character
   310 	*/
   311 	static const TUint8 iInputRules[EMaxClassification][EMaxClassification] =
   312         {
   313     	/* Previous character ENull */
   314     	    {
   315     		EUndefined, EUndefined, EUndefined, EUndefined, EUndefined, 
   316     		EUndefined, EUndefined, EUndefined, EUndefined, EUndefined,
   317     		EUndefined, EUndefined, EUndefined, EUndefined, EUndefined,
   318     		EUndefined, EUndefined, EUndefined, EUndefined 
   319     	    },
   320 
   321     	/* Previous character EControl */
   322     	    {
   323     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   324     		EAccept, EAccept, EAccept, EReject, EReject,
   325     		EReject, EReject, EReject, EReject, EReject, EReject,
   326     		EReject, EReject, EReject,
   327     	    },
   328 
   329     	/* Previous character ENonPrintable */
   330     	    {
   331     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   332     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   333     		EReject, EReject, EReject, EReject, EReject, EReject,
   334     		EReject, EReject, EReject,
   335     	    },
   336 
   337     	/* Previous character EConsonant */
   338     	    {
   339     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   340     		EAccept, ERejectStrict, EAccept, EComposite, EComposite,
   341     		EComposite, EComposite, EComposite, EComposite, EComposite, EComposite,
   342     		EComposite, EComposite, EComposite,
   343     	    },
   344 
   345     	/* Previous character ELeadingVowel */
   346     	    {
   347     		EUndefined, EUndefined, ERejectStrict, EAccept, ERejectStrict, 
   348     		ERejectStrict, ERejectStrict, ERejectStrict, EReject, EReject,
   349     		EReject, EReject, EReject, EReject, EReject, EReject,
   350     		EReject, EReject, EReject,
   351     	    },
   352 
   353     	/* Previous character EOrdinaryFollowingVowel */
   354     	    {
   355     		EUndefined, EUndefined, ERejectStrict, EAccept, ERejectStrict, 
   356     		EAccept, ERejectStrict, EAccept, EReject, EReject,
   357     		EReject, EReject, EReject, EReject, EReject, EReject,
   358     		EReject, EReject, EReject,
   359     	    },
   360 
   361     	/* Previous character EDependentFollowingVowel */
   362     	    {
   363     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   364     		EAccept, ERejectStrict, EAccept, EReject, EReject,
   365     		EReject, EReject, EReject, EReject, EReject, EReject,
   366     		EReject, EReject, EReject,
   367     	    },
   368 
   369     	/* Previous character ESpecialFollowingVowel */
   370     	    {
   371     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   372     		ERejectStrict, EAccept, ERejectStrict, EReject, EReject,
   373     		EReject, EReject, EReject, EReject, EReject, EReject,
   374     		EReject, EReject, EReject,
   375     	    },
   376 
   377     	/* Previous character EShortBelowVowel */
   378     	    {
   379     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   380     		EAccept, ERejectStrict, EAccept, EReject, EReject,
   381     		EReject, EComposite, EComposite, EComposite, EReject, EReject,
   382     		EReject, EReject, EReject,
   383     	    },
   384     		
   385     	/* Previous character ELongBelowVowel */
   386     	    {
   387     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   388     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   389     		EReject, EComposite, EReject, EReject, EReject, EReject,
   390     		EReject, EReject, EReject,
   391     	    },
   392 
   393     	/* Previous character EBelowDiacritic */
   394     	    {
   395     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   396     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   397     		EReject, EReject, EReject, EReject, EReject, EReject,
   398     		EReject, EReject, EReject,
   399     	    },
   400     	
   401     	/* Previous character EToneMark */
   402     	    {
   403     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   404     		EAccept, EAccept, EAccept, EReject, EReject,
   405     		EReject, EReject, EReject, EReject, EReject, EReject,
   406     		EReject, EReject, EReject,
   407     	    },
   408     	
   409 	   	/* Previous character EAboveDiacritic0 */
   410     	    {
   411     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   412     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   413     		EReject, EReject, EReject, EReject, EReject, EReject,
   414     		EReject, EReject, EReject,
   415     	    },
   416     	
   417     	/* Previous character EAboveDiacritic1 */
   418     	    {
   419     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   420     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   421     		EReject, EReject, EReject, EReject, EReject, EReject,
   422     		EReject, EReject, EReject,
   423     	    },
   424     	
   425     	/* Previous character EAboveDiacritic2 */
   426     	    {
   427     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   428     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   429     		EReject, EReject, EReject, EReject, EReject, EReject,
   430     		EReject, EReject, EReject,
   431     	    },
   432     	
   433     	/* Previous character EAboveDiacritic3 */
   434     	    {
   435     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   436     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   437     		EReject, EReject, EReject, EReject, EReject, EReject,
   438     		EReject, EReject, EReject,
   439     	    },
   440     	
   441     	/* Previous character EAboveVowel1 */
   442     	    {
   443     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   444     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   445     		EReject, EComposite, EReject, EComposite, EReject, EReject,
   446 //    		EReject, EComposite, EComposite, EComposite, EReject, EReject,
   447     		EReject, EReject, EReject,
   448     	    },
   449     	
   450     	/* Previous character EAboveVowel2 */
   451     	    {
   452     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   453     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   454     		EReject, EComposite, EReject, EReject, EReject, EReject,
   455     		EReject, EReject, EReject,
   456     	    },
   457     	
   458     	/* Previous character EAboveVowel3 */
   459     	    {
   460     		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   461     		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   462     		EReject, EComposite, EReject, EReject, EReject, EReject,
   463 //			EReject, EComposite, EReject, EComposite, EReject,
   464     		EReject, EReject, EReject,
   465     	    },
   466 
   467     	// Value at last measurement was 324 bytes. 27/6/2003
   468         };
   469 
   470 
   471     /**
   472      This routine looks up the WTT 2.0 rule for the given 
   473      Thai character codes provided in the WTT 2.0 data table.
   474     @param aPrevChar 
   475      Unicode character code preceding the assumed position.
   476     @param aChar
   477      Unicode character code proceeding the assumed position.
   478     @return Wtt2Rule
   479      The rule value found in data table.
   480     */
   481     Wtt2Rule LookupWtt2Rule(TUint aPrevChar, TUint aChar)
   482         {
   483     	const CharClassification prevCharClassification = 
   484     	    static_cast<CharClassification>(
   485     		(aPrevChar > KThaiCodePageStart && aPrevChar < KThaiCodePageEnd) ?
   486     			iCharClassifications[aPrevChar - KThaiCodePageStart] :
   487     			ENonPrintable);
   488     	const CharClassification charClassification = 
   489     	    static_cast<CharClassification>(
   490     		(aChar > KThaiCodePageStart && aChar < KThaiCodePageEnd) ?
   491     			iCharClassifications[aChar - KThaiCodePageStart] :
   492     			ENonPrintable);
   493 
   494     	return static_cast<Wtt2Rule>
   495     	    (iInputRules[prevCharClassification][charClassification]);
   496         }
   497 
   498     }
   499 
   500 using namespace ThaiCharRules;
   501     
   502     
   503 //
   504 //
   505 // ThaiGlyphPUASubstitution Namespace definition
   506 //
   507 //
   508 
   509 
   510 /**
   511  This utility namespace holds the data and lookup mechanisms to support
   512  the GlyphSelector_Thai glyph selection class in choosing Private User
   513  Area (PUA) Thai character positional variant glyphs. Use of the PUA glyphs
   514  results in a satisfactory rendition of Thai writing in Symbian OS.
   515 @internalComponent
   516 */
   517 namespace ThaiGlyphPUASubstitution
   518 	{
   519 	
   520 	typedef TBool (*UnicodeCharValidator)(const TGlyphSelectionState& aGss);
   521 
   522 	struct PUASubstTableEntry
   523 		{
   524 		TUint	iOrigGlyph;
   525 		TUint	iPUAGlyph;
   526 		UnicodeCharValidator	iRuleFunc;
   527 		};
   528 
   529 
   530     /**
   531      ThaiGlyphPUASubstitution rule method which checks the context for
   532      short consonant preceding char OR 
   533      short consonant & dependent vowel below preceding char.
   534     @param aGss
   535      Container object holds the glyph selection context for the method.
   536     @return TBool
   537      ETrue when the rule context is satisfied, EFalse if not. 
   538     */
   539      TBool RuleShortConsonant(const TGlyphSelectionState& aGss)
   540    	{
   541    		if (aGss.iParam.iOutputGlyphs == 1) {
   542    		//check the context for short consonant preceding char
   543     		TUint consonantGss = aGss.iParam.iOutput[0].iCode;
   544     		if (ThaiGlyph::IsThaiShortConsonant(consonantGss) ||
   545     			consonantGss == ThaiGlyph::KYoYingPua ||
   546     			consonantGss == ThaiGlyph::KThoThanPua)
   547     			return ETrue;
   548     		else 
   549     			return EFalse;
   550     	}
   551     	if (aGss.iParam.iOutputGlyphs == 2) {
   552     	//check the context for short consonant & dependent vowel below preceding char
   553     		TUint consonantGss = aGss.iParam.iOutput[0].iCode;
   554     		TUint depVowelGss = aGss.iParam.iOutput[1].iCode;
   555     		if ((ThaiGlyph::IsThaiShortConsonant(consonantGss) ||
   556     			consonantGss == ThaiGlyph::KYoYingPua ||
   557     			consonantGss == ThaiGlyph::KThoThanPua) && 
   558     		  (ThaiGlyph::IsThaiDepVowelBelow(depVowelGss) ||
   559     			(depVowelGss >= 0xF718 &&
   560     			 depVowelGss <= 0xF71A)))
   561     			return ETrue;
   562     		else
   563     			return EFalse;
   564     	}
   565     	return EFalse;
   566     }
   567 
   568     /**
   569      ThaiGlyphPUASubstitution rule method which checks the context for
   570      tall consonant preceding char.
   571     @param aGss
   572      Container object holds the glyph selection context for the method.
   573     @return TBool
   574      ETrue when the rule context is satisfied, EFalse if not. 
   575     */
   576     TBool RuleTallConsonant(const TGlyphSelectionState& aGss)
   577     	{
   578     	if ((aGss.iParam.iOutputGlyphs == 1) &&
   579     	 	ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode))
   580     		return ETrue;
   581     	else
   582     		return EFalse;
   583     	}
   584 
   585     /**
   586      ThaiGlyphPUASubstitution rule method which checks the context for a tall
   587      consonant which does not have a dependent vowel above or a nikhahit or a
   588      following sara am.
   589     @param aGss
   590      Container object holds the glyph selection context for the method.
   591     @return TBool
   592      ETrue when the rule context is satisfied, EFalse if not.
   593     */
   594     TBool RuleTallConsonantNoVowelAbove(const TGlyphSelectionState& aGss)
   595     	{
   596     	if (aGss.iParam.iOutputGlyphs == 0)
   597     		return EFalse;
   598     	if (!ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode))
   599     		return EFalse;
   600     	if (aGss.iParam.iOutputGlyphs == 1)
   601     		return ETrue;
   602     	if (aGss.iParam.iOutputGlyphs != 2)
   603     		return EFalse;
   604     	TUint wantDepVowel = aGss.iParam.iOutput[1].iCode;
   605     	if (ThaiGlyph::IsThaiDepVowelAbove(wantDepVowel)
   606     		|| ThaiGlyph::IsThaiDepVowelAbovePUA(wantDepVowel)
   607     		|| wantDepVowel == ThaiGlyph::KNikhahit
   608     		|| wantDepVowel == ThaiGlyph::KNikhahitPua)
   609     		return EFalse;
   610 	return ETrue;
   611     	}
   612 
   613     /**
   614      ThaiGlyphPUASubstitution rule method which checks the context for tall
   615      consonant with either a dependent vowel above or nikhahit.
   616     @param aGss
   617      Container object holds the glyph selection context for the method.
   618     @return TBool
   619      ETrue when the rule context is satisfied, EFalse if not.
   620     */
   621     TBool RuleTallConsonantVowelAbove(const TGlyphSelectionState& aGss)
   622     	{
   623     	if ((aGss.iParam.iOutputGlyphs == 2) &&
   624     	 	ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode) &&
   625     		(ThaiGlyph::IsThaiDepVowelAbovePUA(aGss.iParam.iOutput[1].iCode))
   626     		|| aGss.iParam.iOutput[1].iCode == ThaiGlyph::KNikhahitPua)
   627     		return ETrue;
   628     	else
   629     		return EFalse;
   630     	}
   631 
   632     /**
   633      ThaiGlyphPUASubstitution rule method which checks the context for
   634      consonant with joined descender preceding char.
   635     @param aGss
   636      Container object holds the glyph selection context for the method.
   637     @return TBool
   638      ETrue when the rule context is satisfied, EFalse if not. 
   639     */
   640      TBool RuleConsonantWithJointDescender(const TGlyphSelectionState& aGss)
   641    	{
   642     	if ((aGss.iParam.iOutputGlyphs == 1) &&
   643     	 	ThaiGlyph::IsThaiConsonantWithJointDescender(aGss.iParam.iOutput[0].iCode))
   644     		return ETrue;
   645     	else
   646     		return EFalse;
   647     	}
   648 
   649 
   650     const PUASubstTableEntry RuleTable[] = {
   651     /**
   652      This data member of the ThaiGlyphPUASubstitution class holds rules
   653      on when a given PUA glyph should be substituted for the original
   654      0x0Exx glyph. Table lookup returns the first match found from the
   655      start of the table, therefore duplicate match situations must be 
   656      avoided in the rule set logic.
   657     */
   658     /*    iOrigGlyph, iPUAGlyph, iRuleFunc                                     */
   659 
   660     	// Substitutions for a tone or sign mark above a short consonant
   661     	{ 0x0E48,     0xF70A,    RuleShortConsonant },
   662     	{ 0x0E49,     0xF70B,    RuleShortConsonant },
   663     	{ 0x0E4A,     0xF70C,    RuleShortConsonant },
   664     	{ 0x0E4B,     0xF70D,    RuleShortConsonant },
   665     	{ 0x0E4C,     0xF70E,    RuleShortConsonant },
   666 
   667     	// Substitutions for a vowel or sign mark above a tall consonant
   668     	{ 0x0E34,	  0xF701,	 RuleTallConsonant },
   669     	{ 0x0E35,	  0xF702,	 RuleTallConsonant },
   670     	{ 0x0E36,	  0xF703,	 RuleTallConsonant },
   671     	{ 0x0E37,	  0xF704,	 RuleTallConsonant },
   672     	{ 0x0E31,	  0xF710,	 RuleTallConsonant },
   673     	{ 0x0E4D,	  0xF711,	 RuleTallConsonant },
   674     	{ 0x0E47,	  0xF712,	 RuleTallConsonant },
   675 
   676     	// Substitutions for a tone or sign mark above a tall consonant
   677     	{ 0x0E48,	  0xF705,	 RuleTallConsonantNoVowelAbove },
   678     	{ 0x0E49,	  0xF706,	 RuleTallConsonantNoVowelAbove },
   679     	{ 0x0E4A,	  0xF707,	 RuleTallConsonantNoVowelAbove },
   680     	{ 0x0E4B,	  0xF708,	 RuleTallConsonantNoVowelAbove },
   681     	{ 0x0E4C,	  0xF709, 	 RuleTallConsonantNoVowelAbove },	
   682 
   683     	// Substitutions for a tone or sign mark above a vowel which is 
   684     	// above a tall consonant
   685     	{ 0x0E48,	  0xF713,	 RuleTallConsonantVowelAbove },
   686     	{ 0x0E49,	  0xF714,	 RuleTallConsonantVowelAbove },
   687     	{ 0x0E4A,	  0xF715,	 RuleTallConsonantVowelAbove },
   688     	{ 0x0E4B,	  0xF716,	 RuleTallConsonantVowelAbove },
   689     	{ 0x0E4C,	  0xF717,	 RuleTallConsonantVowelAbove },	
   690 
   691     	// Substitutions for a vowel or sign mark below a consonant with a  
   692     	// joined descender
   693     	{ 0x0E38,	  0xF718,	 RuleConsonantWithJointDescender },
   694     	{ 0x0E39,	  0xF719,	 RuleConsonantWithJointDescender },
   695     	{ 0x0E3A,	  0xF71A,	 RuleConsonantWithJointDescender },
   696 
   697     	{ 0, 0, 0}
   698 
   699     	// Size of table at last measurement was 312 bytes. 27/6/2003
   700     	};
   701 
   702 
   703     /**
   704      This is the lookup method to determine if the current character being 
   705      processed needs to be substituted for a glyph in the PUA area given the 
   706      supplied context. It scans the rule table and returns when it finds it's
   707      first match. Therefore duplicate match situations must be avoided in
   708      the rule set logic.
   709     @param aCode
   710      On input it is the character to lookup, on exit it is either unchanged
   711      or a code in the PUA 0xF700..0xF71A.
   712     @param aGss
   713      Container object holds the glyph selection context for the method.
   714     @return TBool
   715      ETrue when a match is found and aCode has changed, EFalse otherwise.
   716     */
   717     TBool Lookup(TUint& aCode, const TGlyphSelectionState& aGss)
   718     	{
   719     	const PUASubstTableEntry* tablePtr = RuleTable;
   720     	while (tablePtr->iOrigGlyph)
   721     		{
   722     		if ((aCode == tablePtr->iOrigGlyph) && tablePtr->iRuleFunc(aGss))
   723     			{
   724     			aCode = tablePtr->iPUAGlyph;
   725     			return ETrue; // Rule match, substitute glyph code
   726     			}
   727     		tablePtr++;
   728     		}
   729     	return EFalse; // No match in table
   730     	}
   731     }
   732 
   733 
   734 // 
   735 //
   736 // GlyphSelector_Thai Class definition
   737 //
   738 //
   739 
   740 
   741 /**
   742  This is the default glyph processing method for the Thai characters in the
   743  range 0x0E00..0x0E7F and is invoked from the Glyph selection algorithm in 
   744  CFont::GetCharacterPosition() method. It is capable of processing base
   745  Thai characters as well as Thai combining vowels, signs a tone marks.
   746 @param aGss
   747  Container object holds the input/output parameters of the method.
   748 @return TBool
   749  ETrue when glyph cluster updated successfully, EFalse on error condition.
   750 @see 
   751  The method GlyphSelector_Thai::Process() also handles it for other cases.
   752 */
   753 TBool GlyphSelector_Thai::Process(TGlyphSelectionState& aGss, RShapeInfo&) 
   754 	{
   755 	// Get the Unicode character codes we need to process the current 
   756 	// glyph and increment the iterator onto th next character.
   757 	TUint prevCode = (aGss.iText.LengthToStart() > 0) ? aGss.iText.Get(-1) : 0xFFFF;
   758 	TUint code = aGss.iText.GetThenNext(); // Inc to next char
   759 	TUint nextCode = !aGss.iText.AtEnd() ? aGss.iText.Get(0) : 0xFFFF;
   760 	
   761 	// Is it a Thai base char or a mark (combining) char?
   762 	if ((aGss.iCats & 0xF0) == TChar::EMarkGroup)
   763 		{
   764     
   765 		// Thai character is combining mark but first check to see if it
   766 		// follows a Thai base character before processing it.
   767 		if ((aGss.iParam.iOutputGlyphs > 0) && 
   768 			!ThaiGlyph::IsThaiGlyph(prevCode))
   769 			{
   770 			(void) aGss.iText.Prev();
   771 			aGss.iClusterState = TGlyphSelectionState::EGClusterComplete;
   772 			return ETrue;
   773 			}
   774 		
   775 		// Missing base glyph? Insert a dotted circle glyph if true.
   776 		if (aGss.iParam.iOutputGlyphs == 0) 
   777 			{
   778 			if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle))
   779 				return EFalse;
   780 			aGss.iParam.iPen += aGss.iAdvance;
   781 			}
   782 
   783 		// Test if SARA AM follows this current Thai mark, since it is
   784 		// a SPECIAL CASE. If present we need NIKHAHIT glyph before this 
   785 		// current Thai mark char.
   786 		if (nextCode == ThaiGlyph::KSaraAm &&
   787 			(aGss.iParam.iOutputGlyphs == 1) && ThaiGlyph::IsThaiToneMark(code))
   788 			{
   789 			TUint nikhahit = ThaiGlyph::KNikhahit;
   790 			// Check and do PUA glyph substitution on Nikhahit
   791 			ThaiGlyphPUASubstitution::Lookup(nikhahit, aGss);
   792 
   793 			if (!aGss.AppendGlyphToCluster(nikhahit))
   794 				return EFalse;
   795 	
   796 			// Check and do PUA glyph substitution on combining mark
   797 			ThaiGlyphPUASubstitution::Lookup(code, aGss);
   798 
   799 			// Append the curernt Thai Mark to the output stack of glyphs.
   800 			if (!aGss.AppendGlyphToCluster(code))
   801 				return EFalse;
   802 
   803 			// We now need to add SARA AA glyph after the current Thai mark char.
   804 			aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   805 			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAa))
   806 				return EFalse;
   807 			
   808 			// Skip the following SARA AM character since we've added
   809 			// its glyphs to it's previous character's glyph cluster.
   810 			// As we've added a base char to the end of the glyph cluster
   811 			// make sure the pen is moved on by the caller.
   812 			(void) aGss.iText.Next();
   813 			aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
   814 			}
   815 		else
   816 			{
   817 			// Check and do PUA glyph substitution on combining mark
   818 			ThaiGlyphPUASubstitution::Lookup(code, aGss);
   819 
   820 			// Append the curernt Thai Mark to the output stack of glyphs.
   821 			if (!aGss.AppendGlyphToCluster(code))
   822 				return EFalse;
   823 
   824 			aGss.iPen = TGlyphSelectionState::EPenAdvance_No;
   825 			}
   826 		}
   827 	else
   828 
   829 		{
   830 		// Thai character is an independent consonant, digit or sign
   831 
   832 		// Handle disjoint descender consonants followed by below vowel.
   833 		// In these two cases we substitute consonant with PUA 
   834 		// consonant that the descender removed. Check code not last one.
   835 		if (code == ThaiGlyph::KYoYing && nextCode != 0xffff &&
   836 			        ThaiGlyph::IsThaiDepVowelBelow(nextCode))
   837 			code = ThaiGlyph::KYoYingPua;
   838 		else if (code == ThaiGlyph::KThoThan &&  nextCode != 0xffff &&
   839 			        ThaiGlyph::IsThaiDepVowelBelow(nextCode))
   840 		  	code = ThaiGlyph::KThoThanPua;
   841 			
   842 		// Append the glyph details for the Thai character onto the output 
   843 		// stack of glyphs.
   844 		if (!aGss.AppendGlyphToCluster(code))
   845 			return EFalse;
   846 
   847 		// Make sure the caller advances the pen for a base char!
   848 		aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
   849 		}
   850 
   851 	// Lookup in rule table to determine if the current glyph and cluster is 
   852 	// now complete? 
   853 	if (ThaiCharRules::LookupWtt2Rule(aGss.iCodePt, nextCode) == ThaiCharRules::EComposite)
   854 		aGss.iClusterState = TGlyphSelectionState::EGClusterNotComplete;
   855 	else
   856 		aGss.iClusterState = TGlyphSelectionState::EGClusterComplete;
   857 
   858 	return ETrue;
   859 	}
   860 
   861 
   862 // 
   863 //
   864 // GlyphSelector_ThaiSaraAm Class definition
   865 //
   866 //
   867 
   868 
   869 /**
   870  This is the glyph processing method for the Thai SARA AM (U+0E33) character
   871  which is handled as a special case since it is decomposed into two glyphs 
   872  - the combining NIKHAHIT mark & SARA AA following vowel in some cases.
   873  It is invoked from the Glyph selection algorithm in 
   874  CFont::GetCharacterPosition() method for all cases where SARA AM is not 
   875  following a tone mark and thus be a glyph cluster of its own.
   876 @param aGss
   877  Container object holds the input/output parameters of the method.
   878 @return TBool
   879  ETrue when glyph cluster updated successfully, EFalse on error condition.
   880 @see 
   881  The method GlyphSelector_Thai::Process() also handles it for other cases.
   882 */ 
   883 TBool GlyphSelector_ThaiSaraAm::Process(TGlyphSelectionState& aGss, RShapeInfo&)
   884 	{
   885 	if (aGss.iCodePt != ThaiGlyph::KSaraAm) //could have got here via
   886 		{                    //FindLocalisedProcessFunc in font.cpp
   887 		RShapeInfo dummy;
   888 		return GlyphSelector_Thai::Process(aGss, dummy);
   889 		}
   890 	
   891 	// Pen advance accumulator local variable
   892 	TSize compoundAdvance;
   893 
   894 	if (aGss.iText.LengthToStart() == 0)
   895 		{
   896 		// If at the start of a line then render it with a preceding 
   897 		// dotted circle as this is invalid positioning for SARA AM. 
   898 		
   899 		if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle))
   900 			return EFalse;
   901 		aGss.iParam.iPen += aGss.iAdvance;
   902 
   903 		aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   904 		if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm))
   905 			return EFalse;
   906 		compoundAdvance += aGss.iAdvance;
   907 		}
   908 	else
   909 		{
   910 		// Normal condition - text iterator now some way into the text line
   911 		// being processed.
   912 		
   913 		TUint prevChar = aGss.iText.Get(-1);
   914 		if (ThaiGlyph::IsThaiShortConsonant(prevChar))
   915 			{
   916 			// SARA AM is following normal height consonant so we can output
   917 			// non-decomposed SARA AM glyph.
   918 
   919 			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm))
   920 				return EFalse;
   921 			compoundAdvance = aGss.iAdvance;
   922 			}
   923 		else if (ThaiGlyph::IsThaiTallConsonant(prevChar))
   924 			{
   925 			// SARA AM is following tall consonant so we output decomposed
   926 			// version of SARA AM but with NIKHAHIT taken from the PUA.
   927 
   928 			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KNikhahitPua))
   929 				return EFalse;
   930 			compoundAdvance = aGss.iAdvance;
   931 			aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   932 			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAa))
   933 				return EFalse;
   934 			compoundAdvance += aGss.iAdvance;
   935 			}
   936 		else
   937 			{
   938 			// SARA AM is a following vowel but is not following a valid
   939 			// consonant char and so default is to render with dotted circle.
   940 			if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle))
   941 				return EFalse;
   942 			aGss.iParam.iPen += aGss.iAdvance;
   943 
   944 			aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   945 			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm))
   946 				return EFalse;
   947 			compoundAdvance += aGss.iAdvance;
   948 			}
   949 
   950 		}
   951 
   952 	// Update output parameters resulting from above processing.
   953 	// Move text iterator onto next character to process.
   954 	aGss.iText.Next();
   955 
   956 	// Advance pen just for the SARA AA char as advance for dotted 
   957 	// circle is done above.
   958 	aGss.iAdvance = compoundAdvance;
   959 	aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
   960 
   961 	if (!aGss.iText.AtEnd() &&
   962 		(ThaiCharRules::LookupWtt2Rule(aGss.iCodePt, aGss.iText.Get()) == 
   963 		 ThaiCharRules::EComposite))
   964 		aGss.iClusterState = TGlyphSelectionState::EGClusterNotComplete;
   965 	else
   966 		aGss.iClusterState = TGlyphSelectionState::EGClusterComplete;
   967 
   968 	return ETrue;
   969 	}