os/graphics/graphicsdeviceinterface/gdi/sgdi/FontThai.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/graphicsdeviceinterface/gdi/sgdi/FontThai.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,968 @@
     1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +/**
    1.20 + @file
    1.21 + @internalComponent
    1.22 +*/
    1.23 +
    1.24 +
    1.25 +#include <gdi.h>
    1.26 +#include "FontThai.h"
    1.27 +
    1.28 +
    1.29 +//
    1.30 +// ThaiGlyph Namespace definition
    1.31 +//
    1.32 +
    1.33 +
    1.34 +/**
    1.35 + This namespace holds functions used to evaluate a glyph character code
    1.36 + against a given Thai related prediciate. The 'code' argument is a glyph
    1.37 + from the current output cluster and so may be a Thai glyph, Thai PUA glyph, 
    1.38 + the dotted circle glyph or 0xffff. Therefore it was decided not to implement
    1.39 + these routines using a data driven table approach as it would be inefficient.
    1.40 +@internalComponent.
    1.41 +*/
    1.42 +namespace ThaiGlyph
    1.43 +    {
    1.44 +    const TText16 KYoYing		= 0x0E0D;
    1.45 +    const TText16 KYoYingPua	= 0xF70F;
    1.46 +    const TText16 KThoThan		= 0x0E10;
    1.47 +    const TText16 KThoThanPua	= 0xF700;
    1.48 +    const TText16 KNikhahit	    = 0x0E4D;
    1.49 +    const TText16 KNikhahitPua	= 0xF711;
    1.50 +    const TText16 KSaraAa		= 0x0E32;
    1.51 +    const TText16 KSaraAm		= 0x0E33;
    1.52 +
    1.53 +    
    1.54 +     TBool IsThaiGlyph(TUint code)
    1.55 +    	{
    1.56 +       	return ((code > 0x0E00 && code < 0x0E3B) ||
    1.57 +    			(code > 0x0E3E && code < 0x0E5C) ||
    1.58 +    			(code >= 0xF700 && code <= 0xF71A));
    1.59 +    	}
    1.60 +
    1.61 +     TBool IsThaiConsonant(TUint code)
    1.62 +    	{
    1.63 +    	return (code >= 0x0E01 && code <= 0x0E2E);
    1.64 +    	}
    1.65 +
    1.66 +     TBool IsThaiTallConsonant(TUint code)
    1.67 +    	{
    1.68 +    	return (//code == 0x0E0A ||	// CHO CHANG not tall at all
    1.69 +    			//code == 0x0E0B ||	// SO SO not tall at all
    1.70 +    			code == 0x0E1B ||	// PO PLA
    1.71 +    			code == 0x0E1D ||	// FO FA
    1.72 +    			code == 0x0E1F ||	// FO FAN
    1.73 +    			code == 0x0E2C);	// LO CHULA in some fonts, Unicode tables show it as tall
    1.74 +    	}
    1.75 +
    1.76 +     TBool IsThaiShortConsonant(TUint code)
    1.77 +    	{
    1.78 +    	return (((code >= 0x0E01 && code <= 0x0E2E) || (code == KUnicodeDottedCircle)) &&
    1.79 +    			code != 0x0E1B &&	// PO PLA
    1.80 +    			code != 0x0E1D &&	// FO FA
    1.81 +    			code != 0x0E1F &&	// FO FAN
    1.82 +    			code != 0x0E2C);	// LO CHULA in some fonts, Unicode tables show it as tall
    1.83 +    	}
    1.84 +
    1.85 +     TBool IsThaiConsonantWithDisjointDescender(TUint code)
    1.86 +    	{
    1.87 +    	return (code == ThaiGlyph::KYoYing || code == ThaiGlyph::KThoThan);
    1.88 +    	}
    1.89 +
    1.90 +     TBool IsThaiConsonantWithJointDescender(TUint code)
    1.91 +    	{
    1.92 +    	return (code == 0x0E0E || // DO CHADA
    1.93 +    			code == 0x0E0F || // PO PATAK
    1.94 +    			code == 0x0E24 || // RU
    1.95 +       			code == 0x0E26);  // LU
    1.96 +    	}
    1.97 +
    1.98 +     TBool IsThaiVowel(TUint code)
    1.99 +    	{
   1.100 +    	return ((code >= 0x0E30 && code <= 0x0E3A) ||
   1.101 +    			(code >= 0x0E40 && code <= 0x0E44) ||
   1.102 +    			code == 0x0E47);	// MAITAIKHU
   1.103 +    	}
   1.104 +
   1.105 +     TBool IsThaiDepVowel(TUint code)
   1.106 +    	{
   1.107 +    	return (code == 0x0E31 ||	// MAI HAN-AKAT
   1.108 +    			(code >= 0x0E34 && code <= 0x0E3A) ||
   1.109 +    			code == 0x0E47);	// MAITAIKHU
   1.110 +    	}
   1.111 +
   1.112 +     TBool IsThaiDepVowelAbove(TUint code)
   1.113 +    	{
   1.114 +    	return (code == 0x0E31 ||	// MAI HAN-AKAT
   1.115 +    			(code >= 0x0E34 && code <= 0x0E37) ||
   1.116 +    			code == 0x0E47);	// MAITAIKHU
   1.117 +    	}
   1.118 +
   1.119 +     TBool IsThaiDepVowelAbovePUA(TUint code)
   1.120 +    	{
   1.121 +    	return (code == 0xF710 ||	// MAI HAN-AKAT
   1.122 +    			(code >= 0xF701 && code <= 0xF704) ||
   1.123 +    			code == 0xF712);	// MAITAIKHU
   1.124 +    	}
   1.125 +
   1.126 +     TBool IsThaiDepVowelBelow(TUint code)
   1.127 +    	{
   1.128 +    	return (code >= 0x0E38 && code <= 0x0E3A);
   1.129 +    	}
   1.130 +
   1.131 +     TBool IsThaiIndepVowel(TUint code)
   1.132 +    	{
   1.133 +    	return (code == 0x0E30 ||	// SARA A
   1.134 +      			code == 0x0E32 ||	// SARA AA
   1.135 +    			code == 0x0E33 ||	// SARA AM
   1.136 +    			(code >= 0x0E40 && code <= 0x0E44));
   1.137 +    	}
   1.138 +
   1.139 +     TBool IsThaiToneMark(TUint code)
   1.140 +    	{
   1.141 +    	return (code >= 0x0E48 && code <= 0x0E4B);
   1.142 +    	}
   1.143 +    }
   1.144 +
   1.145 +    
   1.146 +//
   1.147 +//
   1.148 +// ThaiCharRules Namespace definition
   1.149 +//
   1.150 +//
   1.151 +
   1.152 +
   1.153 +/**
   1.154 + ThaiCharRules namespace holds the data and lookup methods
   1.155 + implementing the WTT 2.0 input/output validation matrix.
   1.156 +@internalComponent
   1.157 +*/
   1.158 +namespace ThaiCharRules
   1.159 +	{
   1.160 +  	const TUint KThaiCodePageStart      = 0x0E00;
   1.161 +	const TUint KThaiCodePageEnd        = 0x0E5C;
   1.162 +	const TUint KNumThaiCharacters      = KThaiCodePageEnd-KThaiCodePageStart;
   1.163 +
   1.164 +	enum Wtt2Rule
   1.165 +		{
   1.166 +		EUndefined,
   1.167 +		EAccept,
   1.168 +		EComposite,
   1.169 +		EReject,
   1.170 +		ERejectStrict,
   1.171 +		};
   1.172 +
   1.173 +	/**
   1.174 +	This enumeration holds the set of classification values a Thai
   1.175 +	character can be categorised as in the WTT2.0 specification.
   1.176 +	*/
   1.177 +	enum CharClassification
   1.178 +		{
   1.179 +		ENull,
   1.180 +		EControl,
   1.181 +		ENonPrintable,
   1.182 +		EConsonant,
   1.183 +		ELeadingVowel,
   1.184 +		EOrdinaryFollowingVowel,
   1.185 +		EDependentFollowingVowel,
   1.186 +		ESpecialFollowingVowel,
   1.187 +		EShortBelowVowel,
   1.188 +		ELongBelowVowel,
   1.189 +		EBelowDiacritic,
   1.190 +		EToneMark,
   1.191 +		EAboveDiacritic0,
   1.192 +		EAboveDiacritic1,
   1.193 +		EAboveDiacritic2,
   1.194 +		EAboveDiacritic3,
   1.195 +		EAboveVowel1,
   1.196 +		EAboveVowel2,
   1.197 +		EAboveVowel3,
   1.198 +		// marker for end
   1.199 +		EMaxClassification
   1.200 +		};
   1.201 +
   1.202 +
   1.203 +	/**
   1.204 +	 Data table holding the classification of each character.
   1.205 +	*/
   1.206 +	static const TUint8 iCharClassifications[KNumThaiCharacters] = 
   1.207 +        {
   1.208 +    	ENull,			// No entry in code page
   1.209 +    	EConsonant,		// 0x0E01
   1.210 +    	EConsonant,		// 0x0E02
   1.211 +    	EConsonant,		// 0x0E03
   1.212 +    	EConsonant,		// 0x0E04
   1.213 +    	EConsonant,		// 0x0E05
   1.214 +    	EConsonant,		// 0x0E06
   1.215 +    	EConsonant,		// 0x0E07
   1.216 +    	EConsonant,		// 0x0E08
   1.217 +    	EConsonant,		// 0x0E09
   1.218 +    	EConsonant,		// 0x0E0A
   1.219 +    	EConsonant,		// 0x0E0B
   1.220 +    	EConsonant,		// 0x0E0C
   1.221 +    	EConsonant,		// 0x0E0D
   1.222 +    	EConsonant,		// 0x0E0E
   1.223 +    	EConsonant,		// 0x0E0F
   1.224 +
   1.225 +    	EConsonant,		// 0x0E10
   1.226 +    	EConsonant,		// 0x0E11
   1.227 +    	EConsonant,		// 0x0E12
   1.228 +    	EConsonant,		// 0x0E13
   1.229 +    	EConsonant,		// 0x0E14
   1.230 +    	EConsonant,		// 0x0E15
   1.231 +    	EConsonant,		// 0x0E16
   1.232 +    	EConsonant,		// 0x0E17
   1.233 +    	EConsonant,		// 0x0E18
   1.234 +    	EConsonant,		// 0x0E19
   1.235 +    	EConsonant,		// 0x0E1A
   1.236 +    	EConsonant,		// 0x0E1B
   1.237 +    	EConsonant,		// 0x0E1C
   1.238 +    	EConsonant,		// 0x0E1D
   1.239 +    	EConsonant,		// 0x0E1E
   1.240 +    	EConsonant,		// 0x0E1F
   1.241 +
   1.242 +    	EConsonant,		// 0x0E20
   1.243 +    	EConsonant,		// 0x0E21
   1.244 +    	EConsonant,		// 0x0E22
   1.245 +    	EConsonant,		// 0x0E23
   1.246 +    	EConsonant,		// 0x0E24
   1.247 +    	EConsonant,		// 0x0E25
   1.248 +    	EConsonant,		// 0x0E26
   1.249 +    	EConsonant,		// 0x0E27
   1.250 +    	EConsonant,		// 0x0E28
   1.251 +    	EConsonant,		// 0x0E29
   1.252 +    	EConsonant,		// 0x0E2A
   1.253 +    	EConsonant,		// 0x0E2B
   1.254 +    	EConsonant,		// 0x0E2C
   1.255 +    	EConsonant,		// 0x0E2D
   1.256 +    	EConsonant,		// 0x0E2E
   1.257 +    	ENonPrintable,	// 0x0E2F
   1.258 +
   1.259 +    	EOrdinaryFollowingVowel,// 0x0E30
   1.260 +    	EAboveVowel2,			// 0x0E31
   1.261 +    	EOrdinaryFollowingVowel,// 0x0E32
   1.262 +    	EOrdinaryFollowingVowel,// 0x0E33
   1.263 +    	EAboveVowel1,			// 0x0E34
   1.264 +    	EAboveVowel3,			// 0x0E35
   1.265 +    	EAboveVowel2,			// 0x0E36
   1.266 +    	EAboveVowel3,			// 0x0E37
   1.267 +    	EShortBelowVowel,		// 0x0E38
   1.268 +    	ELongBelowVowel,		// 0x0E39
   1.269 +    	EBelowDiacritic,		// 0x0E3A
   1.270 +    	ENull,					// 0x0E3B
   1.271 +    	ENull,					// 0x0E3C
   1.272 +    	ENull,					// 0x0E3D
   1.273 +    	ENull,					// 0x0E3E
   1.274 +    	ENonPrintable,			// 0x0E3F
   1.275 +
   1.276 +    	ELeadingVowel,			// 0x0E40
   1.277 +    	ELeadingVowel,			// 0x0E41
   1.278 +    	ELeadingVowel,			// 0x0E42
   1.279 +    	ELeadingVowel,			// 0x0E43
   1.280 +    	ELeadingVowel,			// 0x0E44
   1.281 +    	EDependentFollowingVowel,//0x0E45
   1.282 +    	ENonPrintable,			// 0x0E46
   1.283 +    	EAboveDiacritic2,		// 0x0E47
   1.284 +    	EToneMark,				// 0x0E48
   1.285 +    	EToneMark,				// 0x0E49
   1.286 +    	EToneMark,				// 0x0E4A
   1.287 +    	EToneMark,				// 0x0E4B
   1.288 +    	EAboveDiacritic1,		// 0x0E4C
   1.289 +    	EAboveDiacritic0,		// 0x0E4D
   1.290 +    	EAboveDiacritic3,		// 0x0E4E
   1.291 +    	ENonPrintable,			// 0x0E4F
   1.292 +
   1.293 +    	ENonPrintable,			// 0x0E50
   1.294 +    	ENonPrintable,			// 0x0E51
   1.295 +    	ENonPrintable,			// 0x0E52
   1.296 +    	ENonPrintable,			// 0x0E53
   1.297 +    	ENonPrintable,			// 0x0E54
   1.298 +    	ENonPrintable,			// 0x0E55
   1.299 +    	ENonPrintable,			// 0x0E56
   1.300 +    	ENonPrintable,			// 0x0E57
   1.301 +    	ENonPrintable,			// 0x0E58
   1.302 +    	ENonPrintable,			// 0x0E59
   1.303 +    	ENonPrintable,			// 0x0E5A
   1.304 +    	ENonPrintable,			// 0x0E5B
   1.305 +
   1.306 +    	// Value at last measurement was 92 bytes. 27/6/2003
   1.307 +        };
   1.308 +
   1.309 +
   1.310 +	/**
   1.311 +	 WTT 2.0 Rules data table of prev to next character
   1.312 +	*/
   1.313 +	static const TUint8 iInputRules[EMaxClassification][EMaxClassification] =
   1.314 +        {
   1.315 +    	/* Previous character ENull */
   1.316 +    	    {
   1.317 +    		EUndefined, EUndefined, EUndefined, EUndefined, EUndefined, 
   1.318 +    		EUndefined, EUndefined, EUndefined, EUndefined, EUndefined,
   1.319 +    		EUndefined, EUndefined, EUndefined, EUndefined, EUndefined,
   1.320 +    		EUndefined, EUndefined, EUndefined, EUndefined 
   1.321 +    	    },
   1.322 +
   1.323 +    	/* Previous character EControl */
   1.324 +    	    {
   1.325 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.326 +    		EAccept, EAccept, EAccept, EReject, EReject,
   1.327 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.328 +    		EReject, EReject, EReject,
   1.329 +    	    },
   1.330 +
   1.331 +    	/* Previous character ENonPrintable */
   1.332 +    	    {
   1.333 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.334 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.335 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.336 +    		EReject, EReject, EReject,
   1.337 +    	    },
   1.338 +
   1.339 +    	/* Previous character EConsonant */
   1.340 +    	    {
   1.341 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.342 +    		EAccept, ERejectStrict, EAccept, EComposite, EComposite,
   1.343 +    		EComposite, EComposite, EComposite, EComposite, EComposite, EComposite,
   1.344 +    		EComposite, EComposite, EComposite,
   1.345 +    	    },
   1.346 +
   1.347 +    	/* Previous character ELeadingVowel */
   1.348 +    	    {
   1.349 +    		EUndefined, EUndefined, ERejectStrict, EAccept, ERejectStrict, 
   1.350 +    		ERejectStrict, ERejectStrict, ERejectStrict, EReject, EReject,
   1.351 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.352 +    		EReject, EReject, EReject,
   1.353 +    	    },
   1.354 +
   1.355 +    	/* Previous character EOrdinaryFollowingVowel */
   1.356 +    	    {
   1.357 +    		EUndefined, EUndefined, ERejectStrict, EAccept, ERejectStrict, 
   1.358 +    		EAccept, ERejectStrict, EAccept, EReject, EReject,
   1.359 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.360 +    		EReject, EReject, EReject,
   1.361 +    	    },
   1.362 +
   1.363 +    	/* Previous character EDependentFollowingVowel */
   1.364 +    	    {
   1.365 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.366 +    		EAccept, ERejectStrict, EAccept, EReject, EReject,
   1.367 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.368 +    		EReject, EReject, EReject,
   1.369 +    	    },
   1.370 +
   1.371 +    	/* Previous character ESpecialFollowingVowel */
   1.372 +    	    {
   1.373 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.374 +    		ERejectStrict, EAccept, ERejectStrict, EReject, EReject,
   1.375 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.376 +    		EReject, EReject, EReject,
   1.377 +    	    },
   1.378 +
   1.379 +    	/* Previous character EShortBelowVowel */
   1.380 +    	    {
   1.381 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.382 +    		EAccept, ERejectStrict, EAccept, EReject, EReject,
   1.383 +    		EReject, EComposite, EComposite, EComposite, EReject, EReject,
   1.384 +    		EReject, EReject, EReject,
   1.385 +    	    },
   1.386 +    		
   1.387 +    	/* Previous character ELongBelowVowel */
   1.388 +    	    {
   1.389 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.390 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.391 +    		EReject, EComposite, EReject, EReject, EReject, EReject,
   1.392 +    		EReject, EReject, EReject,
   1.393 +    	    },
   1.394 +
   1.395 +    	/* Previous character EBelowDiacritic */
   1.396 +    	    {
   1.397 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.398 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.399 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.400 +    		EReject, EReject, EReject,
   1.401 +    	    },
   1.402 +    	
   1.403 +    	/* Previous character EToneMark */
   1.404 +    	    {
   1.405 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.406 +    		EAccept, EAccept, EAccept, EReject, EReject,
   1.407 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.408 +    		EReject, EReject, EReject,
   1.409 +    	    },
   1.410 +    	
   1.411 +	   	/* Previous character EAboveDiacritic0 */
   1.412 +    	    {
   1.413 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.414 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.415 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.416 +    		EReject, EReject, EReject,
   1.417 +    	    },
   1.418 +    	
   1.419 +    	/* Previous character EAboveDiacritic1 */
   1.420 +    	    {
   1.421 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.422 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.423 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.424 +    		EReject, EReject, EReject,
   1.425 +    	    },
   1.426 +    	
   1.427 +    	/* Previous character EAboveDiacritic2 */
   1.428 +    	    {
   1.429 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.430 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.431 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.432 +    		EReject, EReject, EReject,
   1.433 +    	    },
   1.434 +    	
   1.435 +    	/* Previous character EAboveDiacritic3 */
   1.436 +    	    {
   1.437 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.438 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.439 +    		EReject, EReject, EReject, EReject, EReject, EReject,
   1.440 +    		EReject, EReject, EReject,
   1.441 +    	    },
   1.442 +    	
   1.443 +    	/* Previous character EAboveVowel1 */
   1.444 +    	    {
   1.445 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.446 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.447 +    		EReject, EComposite, EReject, EComposite, EReject, EReject,
   1.448 +//    		EReject, EComposite, EComposite, EComposite, EReject, EReject,
   1.449 +    		EReject, EReject, EReject,
   1.450 +    	    },
   1.451 +    	
   1.452 +    	/* Previous character EAboveVowel2 */
   1.453 +    	    {
   1.454 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.455 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.456 +    		EReject, EComposite, EReject, EReject, EReject, EReject,
   1.457 +    		EReject, EReject, EReject,
   1.458 +    	    },
   1.459 +    	
   1.460 +    	/* Previous character EAboveVowel3 */
   1.461 +    	    {
   1.462 +    		EUndefined, EUndefined, EAccept, EAccept, EAccept, 
   1.463 +    		ERejectStrict, ERejectStrict, EAccept, EReject, EReject,
   1.464 +    		EReject, EComposite, EReject, EReject, EReject, EReject,
   1.465 +//			EReject, EComposite, EReject, EComposite, EReject,
   1.466 +    		EReject, EReject, EReject,
   1.467 +    	    },
   1.468 +
   1.469 +    	// Value at last measurement was 324 bytes. 27/6/2003
   1.470 +        };
   1.471 +
   1.472 +
   1.473 +    /**
   1.474 +     This routine looks up the WTT 2.0 rule for the given 
   1.475 +     Thai character codes provided in the WTT 2.0 data table.
   1.476 +    @param aPrevChar 
   1.477 +     Unicode character code preceding the assumed position.
   1.478 +    @param aChar
   1.479 +     Unicode character code proceeding the assumed position.
   1.480 +    @return Wtt2Rule
   1.481 +     The rule value found in data table.
   1.482 +    */
   1.483 +    Wtt2Rule LookupWtt2Rule(TUint aPrevChar, TUint aChar)
   1.484 +        {
   1.485 +    	const CharClassification prevCharClassification = 
   1.486 +    	    static_cast<CharClassification>(
   1.487 +    		(aPrevChar > KThaiCodePageStart && aPrevChar < KThaiCodePageEnd) ?
   1.488 +    			iCharClassifications[aPrevChar - KThaiCodePageStart] :
   1.489 +    			ENonPrintable);
   1.490 +    	const CharClassification charClassification = 
   1.491 +    	    static_cast<CharClassification>(
   1.492 +    		(aChar > KThaiCodePageStart && aChar < KThaiCodePageEnd) ?
   1.493 +    			iCharClassifications[aChar - KThaiCodePageStart] :
   1.494 +    			ENonPrintable);
   1.495 +
   1.496 +    	return static_cast<Wtt2Rule>
   1.497 +    	    (iInputRules[prevCharClassification][charClassification]);
   1.498 +        }
   1.499 +
   1.500 +    }
   1.501 +
   1.502 +using namespace ThaiCharRules;
   1.503 +    
   1.504 +    
   1.505 +//
   1.506 +//
   1.507 +// ThaiGlyphPUASubstitution Namespace definition
   1.508 +//
   1.509 +//
   1.510 +
   1.511 +
   1.512 +/**
   1.513 + This utility namespace holds the data and lookup mechanisms to support
   1.514 + the GlyphSelector_Thai glyph selection class in choosing Private User
   1.515 + Area (PUA) Thai character positional variant glyphs. Use of the PUA glyphs
   1.516 + results in a satisfactory rendition of Thai writing in Symbian OS.
   1.517 +@internalComponent
   1.518 +*/
   1.519 +namespace ThaiGlyphPUASubstitution
   1.520 +	{
   1.521 +	
   1.522 +	typedef TBool (*UnicodeCharValidator)(const TGlyphSelectionState& aGss);
   1.523 +
   1.524 +	struct PUASubstTableEntry
   1.525 +		{
   1.526 +		TUint	iOrigGlyph;
   1.527 +		TUint	iPUAGlyph;
   1.528 +		UnicodeCharValidator	iRuleFunc;
   1.529 +		};
   1.530 +
   1.531 +
   1.532 +    /**
   1.533 +     ThaiGlyphPUASubstitution rule method which checks the context for
   1.534 +     short consonant preceding char OR 
   1.535 +     short consonant & dependent vowel below preceding char.
   1.536 +    @param aGss
   1.537 +     Container object holds the glyph selection context for the method.
   1.538 +    @return TBool
   1.539 +     ETrue when the rule context is satisfied, EFalse if not. 
   1.540 +    */
   1.541 +     TBool RuleShortConsonant(const TGlyphSelectionState& aGss)
   1.542 +   	{
   1.543 +   		if (aGss.iParam.iOutputGlyphs == 1) {
   1.544 +   		//check the context for short consonant preceding char
   1.545 +    		TUint consonantGss = aGss.iParam.iOutput[0].iCode;
   1.546 +    		if (ThaiGlyph::IsThaiShortConsonant(consonantGss) ||
   1.547 +    			consonantGss == ThaiGlyph::KYoYingPua ||
   1.548 +    			consonantGss == ThaiGlyph::KThoThanPua)
   1.549 +    			return ETrue;
   1.550 +    		else 
   1.551 +    			return EFalse;
   1.552 +    	}
   1.553 +    	if (aGss.iParam.iOutputGlyphs == 2) {
   1.554 +    	//check the context for short consonant & dependent vowel below preceding char
   1.555 +    		TUint consonantGss = aGss.iParam.iOutput[0].iCode;
   1.556 +    		TUint depVowelGss = aGss.iParam.iOutput[1].iCode;
   1.557 +    		if ((ThaiGlyph::IsThaiShortConsonant(consonantGss) ||
   1.558 +    			consonantGss == ThaiGlyph::KYoYingPua ||
   1.559 +    			consonantGss == ThaiGlyph::KThoThanPua) && 
   1.560 +    		  (ThaiGlyph::IsThaiDepVowelBelow(depVowelGss) ||
   1.561 +    			(depVowelGss >= 0xF718 &&
   1.562 +    			 depVowelGss <= 0xF71A)))
   1.563 +    			return ETrue;
   1.564 +    		else
   1.565 +    			return EFalse;
   1.566 +    	}
   1.567 +    	return EFalse;
   1.568 +    }
   1.569 +
   1.570 +    /**
   1.571 +     ThaiGlyphPUASubstitution rule method which checks the context for
   1.572 +     tall consonant preceding char.
   1.573 +    @param aGss
   1.574 +     Container object holds the glyph selection context for the method.
   1.575 +    @return TBool
   1.576 +     ETrue when the rule context is satisfied, EFalse if not. 
   1.577 +    */
   1.578 +    TBool RuleTallConsonant(const TGlyphSelectionState& aGss)
   1.579 +    	{
   1.580 +    	if ((aGss.iParam.iOutputGlyphs == 1) &&
   1.581 +    	 	ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode))
   1.582 +    		return ETrue;
   1.583 +    	else
   1.584 +    		return EFalse;
   1.585 +    	}
   1.586 +
   1.587 +    /**
   1.588 +     ThaiGlyphPUASubstitution rule method which checks the context for a tall
   1.589 +     consonant which does not have a dependent vowel above or a nikhahit or a
   1.590 +     following sara am.
   1.591 +    @param aGss
   1.592 +     Container object holds the glyph selection context for the method.
   1.593 +    @return TBool
   1.594 +     ETrue when the rule context is satisfied, EFalse if not.
   1.595 +    */
   1.596 +    TBool RuleTallConsonantNoVowelAbove(const TGlyphSelectionState& aGss)
   1.597 +    	{
   1.598 +    	if (aGss.iParam.iOutputGlyphs == 0)
   1.599 +    		return EFalse;
   1.600 +    	if (!ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode))
   1.601 +    		return EFalse;
   1.602 +    	if (aGss.iParam.iOutputGlyphs == 1)
   1.603 +    		return ETrue;
   1.604 +    	if (aGss.iParam.iOutputGlyphs != 2)
   1.605 +    		return EFalse;
   1.606 +    	TUint wantDepVowel = aGss.iParam.iOutput[1].iCode;
   1.607 +    	if (ThaiGlyph::IsThaiDepVowelAbove(wantDepVowel)
   1.608 +    		|| ThaiGlyph::IsThaiDepVowelAbovePUA(wantDepVowel)
   1.609 +    		|| wantDepVowel == ThaiGlyph::KNikhahit
   1.610 +    		|| wantDepVowel == ThaiGlyph::KNikhahitPua)
   1.611 +    		return EFalse;
   1.612 +	return ETrue;
   1.613 +    	}
   1.614 +
   1.615 +    /**
   1.616 +     ThaiGlyphPUASubstitution rule method which checks the context for tall
   1.617 +     consonant with either a dependent vowel above or nikhahit.
   1.618 +    @param aGss
   1.619 +     Container object holds the glyph selection context for the method.
   1.620 +    @return TBool
   1.621 +     ETrue when the rule context is satisfied, EFalse if not.
   1.622 +    */
   1.623 +    TBool RuleTallConsonantVowelAbove(const TGlyphSelectionState& aGss)
   1.624 +    	{
   1.625 +    	if ((aGss.iParam.iOutputGlyphs == 2) &&
   1.626 +    	 	ThaiGlyph::IsThaiTallConsonant(aGss.iParam.iOutput[0].iCode) &&
   1.627 +    		(ThaiGlyph::IsThaiDepVowelAbovePUA(aGss.iParam.iOutput[1].iCode))
   1.628 +    		|| aGss.iParam.iOutput[1].iCode == ThaiGlyph::KNikhahitPua)
   1.629 +    		return ETrue;
   1.630 +    	else
   1.631 +    		return EFalse;
   1.632 +    	}
   1.633 +
   1.634 +    /**
   1.635 +     ThaiGlyphPUASubstitution rule method which checks the context for
   1.636 +     consonant with joined descender preceding char.
   1.637 +    @param aGss
   1.638 +     Container object holds the glyph selection context for the method.
   1.639 +    @return TBool
   1.640 +     ETrue when the rule context is satisfied, EFalse if not. 
   1.641 +    */
   1.642 +     TBool RuleConsonantWithJointDescender(const TGlyphSelectionState& aGss)
   1.643 +   	{
   1.644 +    	if ((aGss.iParam.iOutputGlyphs == 1) &&
   1.645 +    	 	ThaiGlyph::IsThaiConsonantWithJointDescender(aGss.iParam.iOutput[0].iCode))
   1.646 +    		return ETrue;
   1.647 +    	else
   1.648 +    		return EFalse;
   1.649 +    	}
   1.650 +
   1.651 +
   1.652 +    const PUASubstTableEntry RuleTable[] = {
   1.653 +    /**
   1.654 +     This data member of the ThaiGlyphPUASubstitution class holds rules
   1.655 +     on when a given PUA glyph should be substituted for the original
   1.656 +     0x0Exx glyph. Table lookup returns the first match found from the
   1.657 +     start of the table, therefore duplicate match situations must be 
   1.658 +     avoided in the rule set logic.
   1.659 +    */
   1.660 +    /*    iOrigGlyph, iPUAGlyph, iRuleFunc                                     */
   1.661 +
   1.662 +    	// Substitutions for a tone or sign mark above a short consonant
   1.663 +    	{ 0x0E48,     0xF70A,    RuleShortConsonant },
   1.664 +    	{ 0x0E49,     0xF70B,    RuleShortConsonant },
   1.665 +    	{ 0x0E4A,     0xF70C,    RuleShortConsonant },
   1.666 +    	{ 0x0E4B,     0xF70D,    RuleShortConsonant },
   1.667 +    	{ 0x0E4C,     0xF70E,    RuleShortConsonant },
   1.668 +
   1.669 +    	// Substitutions for a vowel or sign mark above a tall consonant
   1.670 +    	{ 0x0E34,	  0xF701,	 RuleTallConsonant },
   1.671 +    	{ 0x0E35,	  0xF702,	 RuleTallConsonant },
   1.672 +    	{ 0x0E36,	  0xF703,	 RuleTallConsonant },
   1.673 +    	{ 0x0E37,	  0xF704,	 RuleTallConsonant },
   1.674 +    	{ 0x0E31,	  0xF710,	 RuleTallConsonant },
   1.675 +    	{ 0x0E4D,	  0xF711,	 RuleTallConsonant },
   1.676 +    	{ 0x0E47,	  0xF712,	 RuleTallConsonant },
   1.677 +
   1.678 +    	// Substitutions for a tone or sign mark above a tall consonant
   1.679 +    	{ 0x0E48,	  0xF705,	 RuleTallConsonantNoVowelAbove },
   1.680 +    	{ 0x0E49,	  0xF706,	 RuleTallConsonantNoVowelAbove },
   1.681 +    	{ 0x0E4A,	  0xF707,	 RuleTallConsonantNoVowelAbove },
   1.682 +    	{ 0x0E4B,	  0xF708,	 RuleTallConsonantNoVowelAbove },
   1.683 +    	{ 0x0E4C,	  0xF709, 	 RuleTallConsonantNoVowelAbove },	
   1.684 +
   1.685 +    	// Substitutions for a tone or sign mark above a vowel which is 
   1.686 +    	// above a tall consonant
   1.687 +    	{ 0x0E48,	  0xF713,	 RuleTallConsonantVowelAbove },
   1.688 +    	{ 0x0E49,	  0xF714,	 RuleTallConsonantVowelAbove },
   1.689 +    	{ 0x0E4A,	  0xF715,	 RuleTallConsonantVowelAbove },
   1.690 +    	{ 0x0E4B,	  0xF716,	 RuleTallConsonantVowelAbove },
   1.691 +    	{ 0x0E4C,	  0xF717,	 RuleTallConsonantVowelAbove },	
   1.692 +
   1.693 +    	// Substitutions for a vowel or sign mark below a consonant with a  
   1.694 +    	// joined descender
   1.695 +    	{ 0x0E38,	  0xF718,	 RuleConsonantWithJointDescender },
   1.696 +    	{ 0x0E39,	  0xF719,	 RuleConsonantWithJointDescender },
   1.697 +    	{ 0x0E3A,	  0xF71A,	 RuleConsonantWithJointDescender },
   1.698 +
   1.699 +    	{ 0, 0, 0}
   1.700 +
   1.701 +    	// Size of table at last measurement was 312 bytes. 27/6/2003
   1.702 +    	};
   1.703 +
   1.704 +
   1.705 +    /**
   1.706 +     This is the lookup method to determine if the current character being 
   1.707 +     processed needs to be substituted for a glyph in the PUA area given the 
   1.708 +     supplied context. It scans the rule table and returns when it finds it's
   1.709 +     first match. Therefore duplicate match situations must be avoided in
   1.710 +     the rule set logic.
   1.711 +    @param aCode
   1.712 +     On input it is the character to lookup, on exit it is either unchanged
   1.713 +     or a code in the PUA 0xF700..0xF71A.
   1.714 +    @param aGss
   1.715 +     Container object holds the glyph selection context for the method.
   1.716 +    @return TBool
   1.717 +     ETrue when a match is found and aCode has changed, EFalse otherwise.
   1.718 +    */
   1.719 +    TBool Lookup(TUint& aCode, const TGlyphSelectionState& aGss)
   1.720 +    	{
   1.721 +    	const PUASubstTableEntry* tablePtr = RuleTable;
   1.722 +    	while (tablePtr->iOrigGlyph)
   1.723 +    		{
   1.724 +    		if ((aCode == tablePtr->iOrigGlyph) && tablePtr->iRuleFunc(aGss))
   1.725 +    			{
   1.726 +    			aCode = tablePtr->iPUAGlyph;
   1.727 +    			return ETrue; // Rule match, substitute glyph code
   1.728 +    			}
   1.729 +    		tablePtr++;
   1.730 +    		}
   1.731 +    	return EFalse; // No match in table
   1.732 +    	}
   1.733 +    }
   1.734 +
   1.735 +
   1.736 +// 
   1.737 +//
   1.738 +// GlyphSelector_Thai Class definition
   1.739 +//
   1.740 +//
   1.741 +
   1.742 +
   1.743 +/**
   1.744 + This is the default glyph processing method for the Thai characters in the
   1.745 + range 0x0E00..0x0E7F and is invoked from the Glyph selection algorithm in 
   1.746 + CFont::GetCharacterPosition() method. It is capable of processing base
   1.747 + Thai characters as well as Thai combining vowels, signs a tone marks.
   1.748 +@param aGss
   1.749 + Container object holds the input/output parameters of the method.
   1.750 +@return TBool
   1.751 + ETrue when glyph cluster updated successfully, EFalse on error condition.
   1.752 +@see 
   1.753 + The method GlyphSelector_Thai::Process() also handles it for other cases.
   1.754 +*/
   1.755 +TBool GlyphSelector_Thai::Process(TGlyphSelectionState& aGss, RShapeInfo&) 
   1.756 +	{
   1.757 +	// Get the Unicode character codes we need to process the current 
   1.758 +	// glyph and increment the iterator onto th next character.
   1.759 +	TUint prevCode = (aGss.iText.LengthToStart() > 0) ? aGss.iText.Get(-1) : 0xFFFF;
   1.760 +	TUint code = aGss.iText.GetThenNext(); // Inc to next char
   1.761 +	TUint nextCode = !aGss.iText.AtEnd() ? aGss.iText.Get(0) : 0xFFFF;
   1.762 +	
   1.763 +	// Is it a Thai base char or a mark (combining) char?
   1.764 +	if ((aGss.iCats & 0xF0) == TChar::EMarkGroup)
   1.765 +		{
   1.766 +    
   1.767 +		// Thai character is combining mark but first check to see if it
   1.768 +		// follows a Thai base character before processing it.
   1.769 +		if ((aGss.iParam.iOutputGlyphs > 0) && 
   1.770 +			!ThaiGlyph::IsThaiGlyph(prevCode))
   1.771 +			{
   1.772 +			(void) aGss.iText.Prev();
   1.773 +			aGss.iClusterState = TGlyphSelectionState::EGClusterComplete;
   1.774 +			return ETrue;
   1.775 +			}
   1.776 +		
   1.777 +		// Missing base glyph? Insert a dotted circle glyph if true.
   1.778 +		if (aGss.iParam.iOutputGlyphs == 0) 
   1.779 +			{
   1.780 +			if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle))
   1.781 +				return EFalse;
   1.782 +			aGss.iParam.iPen += aGss.iAdvance;
   1.783 +			}
   1.784 +
   1.785 +		// Test if SARA AM follows this current Thai mark, since it is
   1.786 +		// a SPECIAL CASE. If present we need NIKHAHIT glyph before this 
   1.787 +		// current Thai mark char.
   1.788 +		if (nextCode == ThaiGlyph::KSaraAm &&
   1.789 +			(aGss.iParam.iOutputGlyphs == 1) && ThaiGlyph::IsThaiToneMark(code))
   1.790 +			{
   1.791 +			TUint nikhahit = ThaiGlyph::KNikhahit;
   1.792 +			// Check and do PUA glyph substitution on Nikhahit
   1.793 +			ThaiGlyphPUASubstitution::Lookup(nikhahit, aGss);
   1.794 +
   1.795 +			if (!aGss.AppendGlyphToCluster(nikhahit))
   1.796 +				return EFalse;
   1.797 +	
   1.798 +			// Check and do PUA glyph substitution on combining mark
   1.799 +			ThaiGlyphPUASubstitution::Lookup(code, aGss);
   1.800 +
   1.801 +			// Append the curernt Thai Mark to the output stack of glyphs.
   1.802 +			if (!aGss.AppendGlyphToCluster(code))
   1.803 +				return EFalse;
   1.804 +
   1.805 +			// We now need to add SARA AA glyph after the current Thai mark char.
   1.806 +			aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   1.807 +			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAa))
   1.808 +				return EFalse;
   1.809 +			
   1.810 +			// Skip the following SARA AM character since we've added
   1.811 +			// its glyphs to it's previous character's glyph cluster.
   1.812 +			// As we've added a base char to the end of the glyph cluster
   1.813 +			// make sure the pen is moved on by the caller.
   1.814 +			(void) aGss.iText.Next();
   1.815 +			aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
   1.816 +			}
   1.817 +		else
   1.818 +			{
   1.819 +			// Check and do PUA glyph substitution on combining mark
   1.820 +			ThaiGlyphPUASubstitution::Lookup(code, aGss);
   1.821 +
   1.822 +			// Append the curernt Thai Mark to the output stack of glyphs.
   1.823 +			if (!aGss.AppendGlyphToCluster(code))
   1.824 +				return EFalse;
   1.825 +
   1.826 +			aGss.iPen = TGlyphSelectionState::EPenAdvance_No;
   1.827 +			}
   1.828 +		}
   1.829 +	else
   1.830 +
   1.831 +		{
   1.832 +		// Thai character is an independent consonant, digit or sign
   1.833 +
   1.834 +		// Handle disjoint descender consonants followed by below vowel.
   1.835 +		// In these two cases we substitute consonant with PUA 
   1.836 +		// consonant that the descender removed. Check code not last one.
   1.837 +		if (code == ThaiGlyph::KYoYing && nextCode != 0xffff &&
   1.838 +			        ThaiGlyph::IsThaiDepVowelBelow(nextCode))
   1.839 +			code = ThaiGlyph::KYoYingPua;
   1.840 +		else if (code == ThaiGlyph::KThoThan &&  nextCode != 0xffff &&
   1.841 +			        ThaiGlyph::IsThaiDepVowelBelow(nextCode))
   1.842 +		  	code = ThaiGlyph::KThoThanPua;
   1.843 +			
   1.844 +		// Append the glyph details for the Thai character onto the output 
   1.845 +		// stack of glyphs.
   1.846 +		if (!aGss.AppendGlyphToCluster(code))
   1.847 +			return EFalse;
   1.848 +
   1.849 +		// Make sure the caller advances the pen for a base char!
   1.850 +		aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
   1.851 +		}
   1.852 +
   1.853 +	// Lookup in rule table to determine if the current glyph and cluster is 
   1.854 +	// now complete? 
   1.855 +	if (ThaiCharRules::LookupWtt2Rule(aGss.iCodePt, nextCode) == ThaiCharRules::EComposite)
   1.856 +		aGss.iClusterState = TGlyphSelectionState::EGClusterNotComplete;
   1.857 +	else
   1.858 +		aGss.iClusterState = TGlyphSelectionState::EGClusterComplete;
   1.859 +
   1.860 +	return ETrue;
   1.861 +	}
   1.862 +
   1.863 +
   1.864 +// 
   1.865 +//
   1.866 +// GlyphSelector_ThaiSaraAm Class definition
   1.867 +//
   1.868 +//
   1.869 +
   1.870 +
   1.871 +/**
   1.872 + This is the glyph processing method for the Thai SARA AM (U+0E33) character
   1.873 + which is handled as a special case since it is decomposed into two glyphs 
   1.874 + - the combining NIKHAHIT mark & SARA AA following vowel in some cases.
   1.875 + It is invoked from the Glyph selection algorithm in 
   1.876 + CFont::GetCharacterPosition() method for all cases where SARA AM is not 
   1.877 + following a tone mark and thus be a glyph cluster of its own.
   1.878 +@param aGss
   1.879 + Container object holds the input/output parameters of the method.
   1.880 +@return TBool
   1.881 + ETrue when glyph cluster updated successfully, EFalse on error condition.
   1.882 +@see 
   1.883 + The method GlyphSelector_Thai::Process() also handles it for other cases.
   1.884 +*/ 
   1.885 +TBool GlyphSelector_ThaiSaraAm::Process(TGlyphSelectionState& aGss, RShapeInfo&)
   1.886 +	{
   1.887 +	if (aGss.iCodePt != ThaiGlyph::KSaraAm) //could have got here via
   1.888 +		{                    //FindLocalisedProcessFunc in font.cpp
   1.889 +		RShapeInfo dummy;
   1.890 +		return GlyphSelector_Thai::Process(aGss, dummy);
   1.891 +		}
   1.892 +	
   1.893 +	// Pen advance accumulator local variable
   1.894 +	TSize compoundAdvance;
   1.895 +
   1.896 +	if (aGss.iText.LengthToStart() == 0)
   1.897 +		{
   1.898 +		// If at the start of a line then render it with a preceding 
   1.899 +		// dotted circle as this is invalid positioning for SARA AM. 
   1.900 +		
   1.901 +		if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle))
   1.902 +			return EFalse;
   1.903 +		aGss.iParam.iPen += aGss.iAdvance;
   1.904 +
   1.905 +		aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   1.906 +		if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm))
   1.907 +			return EFalse;
   1.908 +		compoundAdvance += aGss.iAdvance;
   1.909 +		}
   1.910 +	else
   1.911 +		{
   1.912 +		// Normal condition - text iterator now some way into the text line
   1.913 +		// being processed.
   1.914 +		
   1.915 +		TUint prevChar = aGss.iText.Get(-1);
   1.916 +		if (ThaiGlyph::IsThaiShortConsonant(prevChar))
   1.917 +			{
   1.918 +			// SARA AM is following normal height consonant so we can output
   1.919 +			// non-decomposed SARA AM glyph.
   1.920 +
   1.921 +			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm))
   1.922 +				return EFalse;
   1.923 +			compoundAdvance = aGss.iAdvance;
   1.924 +			}
   1.925 +		else if (ThaiGlyph::IsThaiTallConsonant(prevChar))
   1.926 +			{
   1.927 +			// SARA AM is following tall consonant so we output decomposed
   1.928 +			// version of SARA AM but with NIKHAHIT taken from the PUA.
   1.929 +
   1.930 +			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KNikhahitPua))
   1.931 +				return EFalse;
   1.932 +			compoundAdvance = aGss.iAdvance;
   1.933 +			aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   1.934 +			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAa))
   1.935 +				return EFalse;
   1.936 +			compoundAdvance += aGss.iAdvance;
   1.937 +			}
   1.938 +		else
   1.939 +			{
   1.940 +			// SARA AM is a following vowel but is not following a valid
   1.941 +			// consonant char and so default is to render with dotted circle.
   1.942 +			if (!aGss.AppendGlyphToCluster(KUnicodeDottedCircle))
   1.943 +				return EFalse;
   1.944 +			aGss.iParam.iPen += aGss.iAdvance;
   1.945 +
   1.946 +			aGss.iAdvance.iWidth = aGss.iAdvance.iHeight = 0;
   1.947 +			if (!aGss.AppendGlyphToCluster(ThaiGlyph::KSaraAm))
   1.948 +				return EFalse;
   1.949 +			compoundAdvance += aGss.iAdvance;
   1.950 +			}
   1.951 +
   1.952 +		}
   1.953 +
   1.954 +	// Update output parameters resulting from above processing.
   1.955 +	// Move text iterator onto next character to process.
   1.956 +	aGss.iText.Next();
   1.957 +
   1.958 +	// Advance pen just for the SARA AA char as advance for dotted 
   1.959 +	// circle is done above.
   1.960 +	aGss.iAdvance = compoundAdvance;
   1.961 +	aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
   1.962 +
   1.963 +	if (!aGss.iText.AtEnd() &&
   1.964 +		(ThaiCharRules::LookupWtt2Rule(aGss.iCodePt, aGss.iText.Get()) == 
   1.965 +		 ThaiCharRules::EComposite))
   1.966 +		aGss.iClusterState = TGlyphSelectionState::EGClusterNotComplete;
   1.967 +	else
   1.968 +		aGss.iClusterState = TGlyphSelectionState::EGClusterComplete;
   1.969 +
   1.970 +	return ETrue;
   1.971 +	}