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