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 + }