1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/fontservices/textshaperplugin/IcuSource/layout/ThaiShaping.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,307 @@
1.4 +/*
1.5 + *
1.6 + * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
1.7 + *
1.8 + */
1.9 +
1.10 +#include "LETypes.h"
1.11 +#include "LEGlyphFilter.h"
1.12 +#include "OpenTypeTables.h"
1.13 +#include "LEGlyphStorage.h"
1.14 +#include "ThaiShaping.h"
1.15 +
1.16 +U_NAMESPACE_BEGIN
1.17 +
1.18 +enum {
1.19 + CH_SPACE = 0x0020,
1.20 + CH_YAMAKKAN = 0x0E4E,
1.21 + CH_MAI_HANAKAT = 0x0E31,
1.22 + CH_SARA_AA = 0x0E32,
1.23 + CH_SARA_AM = 0x0E33,
1.24 + CH_SARA_UEE = 0x0E37,
1.25 + CH_MAITAIKHU = 0x0E47,
1.26 + CH_NIKHAHIT = 0x0E4D,
1.27 + CH_SARA_U = 0x0E38,
1.28 + CH_PHINTHU = 0x0E3A,
1.29 + CH_YO_YING = 0x0E0D,
1.30 + CH_THO_THAN = 0x0E10,
1.31 + CH_DOTTED_CIRCLE = 0x25CC
1.32 +};
1.33 +
1.34 + le_uint8 ThaiShaping::getCharClass(LEUnicode ch)
1.35 +{
1.36 + le_uint8 charClass = NON;
1.37 +
1.38 + if (ch >= 0x0E00 && ch <= 0x0E5B) {
1.39 + charClass = classTable[ch - 0x0E00];
1.40 + }
1.41 +
1.42 + return charClass;
1.43 +}
1.44 +
1.45 +
1.46 +LEUnicode ThaiShaping::leftAboveVowel(LEUnicode vowel, le_uint8 glyphSet)
1.47 +{
1.48 + static const LEUnicode leftAboveVowels[][7] = {
1.49 + {0x0E61, 0x0E32, 0x0E33, 0x0E64, 0x0E65, 0x0E66, 0x0E67},
1.50 + {0xF710, 0x0E32, 0x0E33, 0xF701, 0xF702, 0xF703, 0xF704},
1.51 + {0xF884, 0x0E32, 0x0E33, 0xF885, 0xF886, 0xF887, 0xF788},
1.52 + {0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37}
1.53 + };
1.54 +
1.55 + if (vowel >= CH_MAI_HANAKAT && vowel <= CH_SARA_UEE) {
1.56 + return leftAboveVowels[glyphSet][vowel - CH_MAI_HANAKAT];
1.57 + }
1.58 +
1.59 + if (vowel == CH_YAMAKKAN && glyphSet == 0) {
1.60 + return 0x0E7E;
1.61 + }
1.62 +
1.63 + return vowel;
1.64 +}
1.65 +
1.66 +LEUnicode ThaiShaping::lowerRightTone(LEUnicode tone, le_uint8 glyphSet)
1.67 +{
1.68 + static const LEUnicode lowerRightTones[][7] = {
1.69 + {0x0E68, 0x0E69, 0x0E6A, 0x0E6B, 0x0E6C, 0x0E6D, 0x0E6E},
1.70 + {0x0E47, 0xF70A, 0xF70B, 0xF70C, 0xF70D, 0xF70E, 0x0E4D},
1.71 + {0x0E47, 0xF88B, 0xF88E, 0xF891, 0xF894, 0xF897, 0x0E4D},
1.72 + {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
1.73 + };
1.74 +
1.75 + if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
1.76 + return lowerRightTones[glyphSet][tone - CH_MAITAIKHU];
1.77 + }
1.78 +
1.79 + return tone;
1.80 +}
1.81 +
1.82 +LEUnicode ThaiShaping::lowerLeftTone(LEUnicode tone, le_uint8 glyphSet)
1.83 +{
1.84 + static const LEUnicode lowerLeftTones[][7] = {
1.85 + {0x0E76, 0x0E77, 0x0E78, 0x0E79, 0x0E7A, 0x0E7B, 0x0E7C},
1.86 + {0xF712, 0xF705, 0xF706, 0xF707, 0xF708, 0xF709, 0xF711},
1.87 + {0xF889, 0xF88C, 0xF88F, 0xF892, 0xF895, 0xF898, 0xF899},
1.88 + {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
1.89 + };
1.90 +
1.91 + if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
1.92 + return lowerLeftTones[glyphSet][tone - CH_MAITAIKHU];
1.93 + }
1.94 +
1.95 + return tone;
1.96 +}
1.97 +
1.98 +LEUnicode ThaiShaping::upperLeftTone(LEUnicode tone, le_uint8 glyphSet)
1.99 +{
1.100 + static const LEUnicode upperLeftTones[][7] = {
1.101 + {0x0E6F, 0x0E70, 0x0E71, 0x0E72, 0x0E73, 0x0E74, 0x0E75},
1.102 + {0xF712, 0xF713, 0xF714, 0xF715, 0xF716, 0xF717, 0xF711},
1.103 + {0xF889, 0xF88A, 0xF88D, 0xF890, 0xF893, 0xF896, 0xF899},
1.104 + {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
1.105 + };
1.106 +
1.107 + if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
1.108 + return upperLeftTones[glyphSet][tone - CH_MAITAIKHU];
1.109 + }
1.110 +
1.111 + return tone;
1.112 +}
1.113 +
1.114 +LEUnicode ThaiShaping::lowerBelowVowel(LEUnicode vowel, le_uint8 glyphSet)
1.115 +{
1.116 + static const LEUnicode lowerBelowVowels[][3] = {
1.117 + {0x0E3C, 0x0E3D, 0x0E3E},
1.118 + {0xF718, 0xF719, 0xF71A},
1.119 + {0x0E38, 0x0E39, 0x0E3A},
1.120 + {0x0E38, 0x0E39, 0x0E3A}
1.121 +
1.122 + };
1.123 +
1.124 + if (vowel >= CH_SARA_U && vowel <= CH_PHINTHU) {
1.125 + return lowerBelowVowels[glyphSet][vowel - CH_SARA_U];
1.126 + }
1.127 +
1.128 + return vowel;
1.129 +}
1.130 +
1.131 +LEUnicode ThaiShaping::noDescenderCOD(LEUnicode cod, le_uint8 glyphSet)
1.132 +{
1.133 + static const LEUnicode noDescenderCODs[][4] = {
1.134 + {0x0E60, 0x0E0E, 0x0E0F, 0x0E63},
1.135 + {0xF70F, 0x0E0E, 0x0E0F, 0xF700},
1.136 + {0x0E0D, 0x0E0E, 0x0E0F, 0x0E10},
1.137 + {0x0E0D, 0x0E0E, 0x0E0F, 0x0E10}
1.138 +
1.139 + };
1.140 +
1.141 + if (cod >= CH_YO_YING && cod <= CH_THO_THAN) {
1.142 + return noDescenderCODs[glyphSet][cod - CH_YO_YING];
1.143 + }
1.144 +
1.145 + return cod;
1.146 +}
1.147 +
1.148 +le_uint8 ThaiShaping::doTransition (StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet,
1.149 + LEUnicode errorChar, LEUnicode *outputBuffer, LEGlyphStorage &glyphStorage, le_int32 &outputIndex)
1.150 +{
1.151 + LEErrorCode success = LE_NO_ERROR;
1.152 +
1.153 + switch (transition.action) {
1.154 + case tA:
1.155 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.156 + outputBuffer[outputIndex++] = currChar;
1.157 + break;
1.158 +
1.159 + case tC:
1.160 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.161 + outputBuffer[outputIndex++] = currChar;
1.162 + break;
1.163 +
1.164 + case tD:
1.165 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.166 + outputBuffer[outputIndex++] = leftAboveVowel(currChar, glyphSet);
1.167 + break;
1.168 +
1.169 + case tE:
1.170 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.171 + outputBuffer[outputIndex++] = lowerRightTone(currChar, glyphSet);
1.172 + break;
1.173 +
1.174 + case tF:
1.175 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.176 + outputBuffer[outputIndex++] = lowerLeftTone(currChar, glyphSet);
1.177 + break;
1.178 +
1.179 + case tG:
1.180 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.181 + outputBuffer[outputIndex++] = upperLeftTone(currChar, glyphSet);
1.182 + break;
1.183 +
1.184 + case tH:
1.185 + {
1.186 + LEUnicode cod = outputBuffer[outputIndex - 1];
1.187 + LEUnicode coa = noDescenderCOD(cod, glyphSet);
1.188 +
1.189 + if (cod != coa) {
1.190 + outputBuffer[outputIndex - 1] = coa;
1.191 +
1.192 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.193 + outputBuffer[outputIndex++] = currChar;
1.194 + break;
1.195 + }
1.196 +
1.197 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.198 + outputBuffer[outputIndex++] = lowerBelowVowel(currChar, glyphSet);
1.199 + break;
1.200 + }
1.201 +
1.202 + case tR:
1.203 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.204 + outputBuffer[outputIndex++] = errorChar;
1.205 +
1.206 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.207 + outputBuffer[outputIndex++] = currChar;
1.208 + break;
1.209 +
1.210 + case tS:
1.211 + if (currChar == CH_SARA_AM) {
1.212 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.213 + outputBuffer[outputIndex++] = errorChar;
1.214 + }
1.215 +
1.216 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.217 + outputBuffer[outputIndex++] = currChar;
1.218 + break;
1.219 +
1.220 + default:
1.221 + // FIXME: if we get here, there's an error
1.222 + // in the state table!
1.223 + glyphStorage.setCharIndex(outputIndex, inputIndex, success);
1.224 + outputBuffer[outputIndex++] = currChar;
1.225 + break;
1.226 + }
1.227 +
1.228 + return transition.nextState;
1.229 +}
1.230 +
1.231 +le_uint8 ThaiShaping::getNextState(LEUnicode ch, le_uint8 prevState, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar,
1.232 + le_uint8 &charClass, LEUnicode *output, LEGlyphStorage &glyphStorage, le_int32 &outputIndex)
1.233 +{
1.234 + StateTransition transition;
1.235 +
1.236 + charClass = getCharClass(ch);
1.237 + transition = getTransition(prevState, charClass);
1.238 +
1.239 + return doTransition(transition, ch, inputIndex, glyphSet, errorChar, output, glyphStorage, outputIndex);
1.240 +}
1.241 +
1.242 +le_bool ThaiShaping::isLegalHere(LEUnicode ch, le_uint8 prevState)
1.243 +{
1.244 + le_uint8 charClass = getCharClass(ch);
1.245 + StateTransition transition = getTransition(prevState, charClass);
1.246 +
1.247 + switch (transition.action) {
1.248 + case tA:
1.249 + case tC:
1.250 + case tD:
1.251 + case tE:
1.252 + case tF:
1.253 + case tG:
1.254 + case tH:
1.255 + return TRUE;
1.256 +
1.257 + case tR:
1.258 + case tS:
1.259 + return FALSE;
1.260 +
1.261 + default:
1.262 + // FIXME: if we get here, there's an error
1.263 + // in the state table!
1.264 + return FALSE;
1.265 + }
1.266 +}
1.267 +
1.268 +le_int32 ThaiShaping::compose(const LEUnicode *input, le_int32 offset, le_int32 charCount, le_uint8 glyphSet,
1.269 + LEUnicode errorChar, LEUnicode *output, LEGlyphStorage &glyphStorage)
1.270 +{
1.271 + le_uint8 state = 0;
1.272 + le_int32 inputIndex;
1.273 + le_int32 outputIndex = 0;
1.274 + le_uint8 conState = 0xFF;
1.275 + le_int32 conInput = -1;
1.276 + le_int32 conOutput = -1;
1.277 +
1.278 + for (inputIndex = 0; inputIndex < charCount; inputIndex += 1) {
1.279 + LEUnicode ch = input[inputIndex + offset];
1.280 + le_uint8 charClass;
1.281 +
1.282 + // Decompose SARA AM into NIKHAHIT + SARA AA
1.283 + if (ch == CH_SARA_AM && isLegalHere(ch, state)) {
1.284 + outputIndex = conOutput;
1.285 + state = getNextState(CH_NIKHAHIT, conState, inputIndex, glyphSet, errorChar, charClass,
1.286 + output, glyphStorage, outputIndex);
1.287 +
1.288 + for (int j = conInput + 1; j < inputIndex; j += 1) {
1.289 + ch = input[j + offset];
1.290 + state = getNextState(ch, state, j, glyphSet, errorChar, charClass,
1.291 + output, glyphStorage, outputIndex);
1.292 + }
1.293 +
1.294 + ch = CH_SARA_AA;
1.295 + }
1.296 +
1.297 + state = getNextState(ch, state, inputIndex, glyphSet, errorChar, charClass,
1.298 + output, glyphStorage, outputIndex);
1.299 +
1.300 + if (charClass >= CON && charClass <= COD) {
1.301 + conState = state;
1.302 + conInput = inputIndex;
1.303 + conOutput = outputIndex;
1.304 + }
1.305 + }
1.306 +
1.307 + return outputIndex;
1.308 +}
1.309 +
1.310 +U_NAMESPACE_END