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