]> git.saurik.com Git - apple/icu.git/blame - icuSources/layout/IndicReordering.cpp
ICU-8.11.4.tar.gz
[apple/icu.git] / icuSources / layout / IndicReordering.cpp
CommitLineData
b75a7d8f 1/*
b75a7d8f 2 *
73c04bcf 3 * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
b75a7d8f
A
4 *
5 */
6
7#include "LETypes.h"
8#include "OpenTypeTables.h"
9#include "OpenTypeUtilities.h"
10#include "IndicReordering.h"
374ca955 11#include "LEGlyphStorage.h"
b75a7d8f
A
12#include "MPreFixups.h"
13
14U_NAMESPACE_BEGIN
15
73c04bcf
A
16#define loclFeatureTag LE_LOCL_FEATURE_TAG
17#define initFeatureTag LE_INIT_FEATURE_TAG
18#define nuktFeatureTag LE_NUKT_FEATURE_TAG
19#define akhnFeatureTag LE_AKHN_FEATURE_TAG
20#define rphfFeatureTag LE_RPHF_FEATURE_TAG
21#define blwfFeatureTag LE_BLWF_FEATURE_TAG
22#define halfFeatureTag LE_HALF_FEATURE_TAG
23#define pstfFeatureTag LE_PSTF_FEATURE_TAG
24#define vatuFeatureTag LE_VATU_FEATURE_TAG
25#define presFeatureTag LE_PRES_FEATURE_TAG
26#define blwsFeatureTag LE_BLWS_FEATURE_TAG
27#define abvsFeatureTag LE_ABVS_FEATURE_TAG
28#define pstsFeatureTag LE_PSTS_FEATURE_TAG
29#define halnFeatureTag LE_HALN_FEATURE_TAG
30
31#define blwmFeatureTag LE_BLWM_FEATURE_TAG
32#define abvmFeatureTag LE_ABVM_FEATURE_TAG
33#define distFeatureTag LE_DIST_FEATURE_TAG
34
35#define loclFeatureMask 0x80000000UL
36#define rphfFeatureMask 0x40000000UL
37#define blwfFeatureMask 0x20000000UL
38#define halfFeatureMask 0x10000000UL
39#define pstfFeatureMask 0x08000000UL
40#define nuktFeatureMask 0x04000000UL
41#define akhnFeatureMask 0x02000000UL
42#define vatuFeatureMask 0x01000000UL
43#define presFeatureMask 0x00800000UL
44#define blwsFeatureMask 0x00400000UL
45#define abvsFeatureMask 0x00200000UL
46#define pstsFeatureMask 0x00100000UL
47#define halnFeatureMask 0x00080000UL
48#define blwmFeatureMask 0x00040000UL
49#define abvmFeatureMask 0x00020000UL
50#define distFeatureMask 0x00010000UL
51#define initFeatureMask 0x00008000UL
52
53class IndicReorderingOutput : public UMemory {
b75a7d8f 54private:
73c04bcf 55 le_int32 fOutIndex;
b75a7d8f 56 LEUnicode *fOutChars;
374ca955
A
57
58 LEGlyphStorage &fGlyphStorage;
b75a7d8f 59
73c04bcf
A
60 LEUnicode fMpre;
61 le_int32 fMpreIndex;
374ca955 62
73c04bcf
A
63 LEUnicode fMbelow;
64 le_int32 fMbelowIndex;
374ca955 65
73c04bcf
A
66 LEUnicode fMabove;
67 le_int32 fMaboveIndex;
374ca955 68
73c04bcf
A
69 LEUnicode fMpost;
70 le_int32 fMpostIndex;
374ca955 71
73c04bcf
A
72 LEUnicode fLengthMark;
73 le_int32 fLengthMarkIndex;
374ca955 74
73c04bcf
A
75 LEUnicode fVirama;
76 le_int32 fViramaIndex;
77
78 FeatureMask fMatraFeatures;
374ca955 79
73c04bcf 80 le_int32 fMPreOutIndex;
b75a7d8f 81 MPreFixups *fMPreFixups;
374ca955 82
73c04bcf
A
83 LEUnicode fVMabove;
84 LEUnicode fVMpost;
85 le_int32 fVMIndex;
86 FeatureMask fVMFeatures;
374ca955 87
73c04bcf
A
88 LEUnicode fSMabove;
89 LEUnicode fSMbelow;
90 le_int32 fSMIndex;
91 FeatureMask fSMFeatures;
374ca955
A
92
93 void saveMatra(LEUnicode matra, le_int32 matraIndex, IndicClassTable::CharClass matraClass)
b75a7d8f
A
94 {
95 // FIXME: check if already set, or if not a matra...
374ca955 96 if (IndicClassTable::isLengthMark(matraClass)) {
b75a7d8f 97 fLengthMark = matra;
374ca955 98 fLengthMarkIndex = matraIndex;
73c04bcf
A
99 } else if (IndicClassTable::isVirama(matraClass)) {
100 fVirama = matra;
101 fViramaIndex = matraIndex;
374ca955 102 } else {
73c04bcf
A
103 switch (matraClass & CF_POS_MASK) {
104 case CF_POS_BEFORE:
374ca955
A
105 fMpre = matra;
106 fMpreIndex = matraIndex;
107 break;
108
73c04bcf 109 case CF_POS_BELOW:
374ca955
A
110 fMbelow = matra;
111 fMbelowIndex = matraIndex;
112 break;
113
73c04bcf 114 case CF_POS_ABOVE:
374ca955
A
115 fMabove = matra;
116 fMaboveIndex = matraIndex;
117 break;
118
73c04bcf 119 case CF_POS_AFTER:
374ca955
A
120 fMpost = matra;
121 fMpostIndex = matraIndex;
122 break;
123
124 default:
125 // can't get here...
126 break;
127 }
b75a7d8f
A
128 }
129 }
130
131public:
73c04bcf 132 IndicReorderingOutput(LEUnicode *outChars, LEGlyphStorage &glyphStorage, MPreFixups *mpreFixups)
374ca955
A
133 : fOutIndex(0), fOutChars(outChars), fGlyphStorage(glyphStorage),
134 fMpre(0), fMpreIndex(0), fMbelow(0), fMbelowIndex(0), fMabove(0), fMaboveIndex(0),
73c04bcf
A
135 fMpost(0), fMpostIndex(0), fLengthMark(0), fLengthMarkIndex(0), fVirama(0), fViramaIndex(0),
136 fMatraFeatures(0), fMPreOutIndex(-1), fMPreFixups(mpreFixups),
137 fVMabove(0), fVMpost(0), fVMIndex(0), fVMFeatures(0),
138 fSMabove(0), fSMbelow(0), fSMIndex(0), fSMFeatures(0)
b75a7d8f
A
139 {
140 // nothing else to do...
141 }
142
73c04bcf 143 ~IndicReorderingOutput()
b75a7d8f
A
144 {
145 // nothing to do here...
146 }
147
374ca955 148 void reset()
b75a7d8f 149 {
73c04bcf 150 fMpre = fMbelow = fMabove = fMpost = fLengthMark = fVirama = 0;
b75a7d8f 151 fMPreOutIndex = -1;
374ca955
A
152
153 fVMabove = fVMpost = 0;
154 fSMabove = fSMbelow = 0;
155 }
156
73c04bcf
A
157 void writeChar(LEUnicode ch, le_uint32 charIndex, FeatureMask charFeatures)
158 {
159 LEErrorCode success = LE_NO_ERROR;
160
161 fOutChars[fOutIndex] = ch;
162
163 fGlyphStorage.setCharIndex(fOutIndex, charIndex, success);
164 fGlyphStorage.setAuxData(fOutIndex, charFeatures, success);
165
166 fOutIndex += 1;
167 }
168
169 le_bool noteMatra(const IndicClassTable *classTable, LEUnicode matra, le_uint32 matraIndex, FeatureMask matraFeatures, le_bool wordStart)
374ca955
A
170 {
171 IndicClassTable::CharClass matraClass = classTable->getCharClass(matra);
172
73c04bcf
A
173 fMatraFeatures = matraFeatures;
174
175 if (wordStart) {
176 fMatraFeatures |= initFeatureMask;
177 }
b75a7d8f
A
178
179 if (IndicClassTable::isMatra(matraClass)) {
180 if (IndicClassTable::isSplitMatra(matraClass)) {
181 const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass);
182 int i;
183
184 for (i = 0; i < 3 && (*splitMatra)[i] != 0; i += 1) {
185 LEUnicode piece = (*splitMatra)[i];
186 IndicClassTable::CharClass pieceClass = classTable->getCharClass(piece);
187
374ca955 188 saveMatra(piece, matraIndex, pieceClass);
b75a7d8f
A
189 }
190 } else {
374ca955 191 saveMatra(matra, matraIndex, matraClass);
b75a7d8f 192 }
374ca955
A
193
194 return TRUE;
195 }
196
197 return FALSE;
198 }
199
73c04bcf 200 void noteVowelModifier(const IndicClassTable *classTable, LEUnicode vowelModifier, le_uint32 vowelModifierIndex, FeatureMask vowelModifierFeatures)
374ca955
A
201 {
202 IndicClassTable::CharClass vmClass = classTable->getCharClass(vowelModifier);
203
204 fVMIndex = vowelModifierIndex;
73c04bcf 205 fVMFeatures = vowelModifierFeatures;
374ca955
A
206
207 if (IndicClassTable::isVowelModifier(vmClass)) {
73c04bcf
A
208 switch (vmClass & CF_POS_MASK) {
209 case CF_POS_ABOVE:
374ca955
A
210 fVMabove = vowelModifier;
211 break;
212
73c04bcf 213 case CF_POS_AFTER:
374ca955
A
214 fVMpost = vowelModifier;
215 break;
216
217 default:
218 // FIXME: this is an error...
219 break;
220 }
221 }
222 }
223
73c04bcf 224 void noteStressMark(const IndicClassTable *classTable, LEUnicode stressMark, le_uint32 stressMarkIndex, FeatureMask stressMarkFeatures)
374ca955
A
225 {
226 IndicClassTable::CharClass smClass = classTable->getCharClass(stressMark);
227
228 fSMIndex = stressMarkIndex;
73c04bcf 229 fSMFeatures = stressMarkFeatures;
374ca955
A
230
231 if (IndicClassTable::isStressMark(smClass)) {
73c04bcf
A
232 switch (smClass & CF_POS_MASK) {
233 case CF_POS_ABOVE:
374ca955
A
234 fSMabove = stressMark;
235 break;
236
73c04bcf 237 case CF_POS_BELOW:
374ca955
A
238 fSMbelow = stressMark;
239 break;
240
241 default:
242 // FIXME: this is an error...
243 break;
244 }
b75a7d8f
A
245 }
246 }
247
248 void noteBaseConsonant()
249 {
250 if (fMPreFixups != NULL && fMPreOutIndex >= 0) {
251 fMPreFixups->add(fOutIndex, fMPreOutIndex);
252 }
253 }
254
73c04bcf
A
255 // Handles virama in Sinhala split vowels.
256 void writeVirama()
257 {
258 if (fVirama != 0) {
259 writeChar(fVirama, fViramaIndex, fMatraFeatures);
260 }
261 }
262
b75a7d8f
A
263 void writeMpre()
264 {
265 if (fMpre != 0) {
266 fMPreOutIndex = fOutIndex;
73c04bcf 267 writeChar(fMpre, fMpreIndex, fMatraFeatures);
b75a7d8f
A
268 }
269 }
270
271 void writeMbelow()
272 {
273 if (fMbelow != 0) {
73c04bcf 274 writeChar(fMbelow, fMbelowIndex, fMatraFeatures);
b75a7d8f
A
275 }
276 }
277
278 void writeMabove()
279 {
280 if (fMabove != 0) {
73c04bcf 281 writeChar(fMabove, fMaboveIndex, fMatraFeatures);
b75a7d8f
A
282 }
283 }
284
285 void writeMpost()
286 {
287 if (fMpost != 0) {
73c04bcf 288 writeChar(fMpost, fMpostIndex, fMatraFeatures);
b75a7d8f
A
289 }
290 }
291
292 void writeLengthMark()
293 {
294 if (fLengthMark != 0) {
73c04bcf 295 writeChar(fLengthMark, fLengthMarkIndex, fMatraFeatures);
b75a7d8f
A
296 }
297 }
374ca955
A
298
299 void writeVMabove()
300 {
301 if (fVMabove != 0) {
73c04bcf 302 writeChar(fVMabove, fVMIndex, fVMFeatures);
374ca955
A
303 }
304 }
305
306 void writeVMpost()
307 {
308 if (fVMpost != 0) {
73c04bcf 309 writeChar(fVMpost, fVMIndex, fVMFeatures);
374ca955
A
310 }
311 }
312
313 void writeSMabove()
314 {
315 if (fSMabove != 0) {
73c04bcf 316 writeChar(fSMabove, fSMIndex, fSMFeatures);
374ca955
A
317 }
318 }
319
320 void writeSMbelow()
321 {
322 if (fSMbelow != 0) {
73c04bcf 323 writeChar(fSMbelow, fSMIndex, fSMFeatures);
374ca955
A
324 }
325 }
326
b75a7d8f
A
327 le_int32 getOutputIndex()
328 {
329 return fOutIndex;
330 }
331};
332
333enum
334{
335 C_DOTTED_CIRCLE = 0x25CC
336};
337
73c04bcf
A
338// TODO: Find better names for these!
339#define tagArray4 (loclFeatureMask | nuktFeatureMask | akhnFeatureMask | vatuFeatureMask | presFeatureMask | blwsFeatureMask | abvsFeatureMask | pstsFeatureMask | halnFeatureMask | blwmFeatureMask | abvmFeatureMask | distFeatureMask)
340#define tagArray3 (pstfFeatureMask | tagArray4)
341#define tagArray2 (halfFeatureMask | tagArray3)
342#define tagArray1 (blwfFeatureMask | tagArray2)
343#define tagArray0 (rphfFeatureMask | tagArray1)
b75a7d8f 344
73c04bcf 345static const FeatureMap featureMap[] =
b75a7d8f 346{
73c04bcf
A
347 {loclFeatureTag, loclFeatureMask},
348 {initFeatureTag, initFeatureMask},
349 {nuktFeatureTag, nuktFeatureMask},
350 {akhnFeatureTag, akhnFeatureMask},
351 {rphfFeatureTag, rphfFeatureMask},
352 {blwfFeatureTag, blwfFeatureMask},
353 {halfFeatureTag, halfFeatureMask},
354 {pstfFeatureTag, pstfFeatureMask},
355 {vatuFeatureTag, vatuFeatureMask},
356 {presFeatureTag, presFeatureMask},
357 {blwsFeatureTag, blwsFeatureMask},
358 {abvsFeatureTag, abvsFeatureMask},
359 {pstsFeatureTag, pstsFeatureMask},
360 {halnFeatureTag, halnFeatureMask},
361 {blwmFeatureTag, blwmFeatureMask},
362 {abvmFeatureTag, abvmFeatureMask},
363 {distFeatureTag, distFeatureMask}
b75a7d8f
A
364};
365
73c04bcf 366static const le_int32 featureCount = LE_ARRAY_SIZE(featureMap);
b75a7d8f 367
73c04bcf
A
368static const le_int8 stateTable[][CC_COUNT] =
369{
370// xx vm sm iv i2 i3 ct cn nu dv s1 s2 s3 vr zw
371 { 1, 6, 1, 5, 8, 11, 3, 2, 1, 5, 9, 5, 5, 1, 1}, // 0 - ground state
372 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 1 - exit state
373 {-1, 6, 1, -1, -1, -1, -1, -1, -1, 5, 9, 5, 5, 4, 12}, // 2 - consonant with nukta
374 {-1, 6, 1, -1, -1, -1, -1, -1, 2, 5, 9, 5, 5, 4, 12}, // 3 - consonant
375 {-1, -1, -1, -1, -1, -1, 3, 2, -1, -1, -1, -1, -1, -1, 7}, // 4 - consonant virama
376 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 5 - dependent vowels
377 {-1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - vowel mark
378 {-1, -1, -1, -1, -1, -1, 3, 2, -1, -1, -1, -1, -1, -1, -1}, // 7 - consonant virama ZWJ, consonant ZWJ virama
379 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1}, // 8 - independent vowels that can take a virama
380 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 5, -1, -1}, // 9 - first part of split vowel
381 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1}, // 10 - second part of split vowel
382 {-1, 6, 1, -1, -1, -1, -1, -1, -1, 5, 9, 5, 5, 4, -1}, // 11 - independent vowels that can take an iv
383 {-1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1} // 12 - consonant ZWJ (TODO: Take everything else that can be after a consonant?)
b75a7d8f
A
384};
385
73c04bcf
A
386
387const FeatureMap *IndicReordering::getFeatureMap(le_int32 &count)
b75a7d8f 388{
73c04bcf
A
389 count = featureCount;
390
391 return featureMap;
b75a7d8f
A
392}
393
394le_int32 IndicReordering::findSyllable(const IndicClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount)
395{
396 le_int32 cursor = prev;
397 le_int8 state = 0;
398
399 while (cursor < charCount) {
400 IndicClassTable::CharClass charClass = classTable->getCharClass(chars[cursor]);
401
73c04bcf 402 state = stateTable[state][charClass & CF_CLASS_MASK];
b75a7d8f
A
403
404 if (state < 0) {
405 break;
406 }
407
408 cursor += 1;
409 }
410
411 return cursor;
412}
413
414le_int32 IndicReordering::reorder(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode,
374ca955 415 LEUnicode *outChars, LEGlyphStorage &glyphStorage,
b75a7d8f
A
416 MPreFixups **outMPreFixups)
417{
418 MPreFixups *mpreFixups = NULL;
419 const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
420
73c04bcf 421 if (classTable->scriptFlags & SF_MPRE_FIXUP) {
b75a7d8f
A
422 mpreFixups = new MPreFixups(charCount);
423 }
424
73c04bcf 425 IndicReorderingOutput output(outChars, glyphStorage, mpreFixups);
b75a7d8f 426 le_int32 i, prev = 0;
73c04bcf 427 le_bool lastInWord = FALSE;
b75a7d8f
A
428
429 while (prev < charCount) {
430 le_int32 syllable = findSyllable(classTable, chars, prev, charCount);
374ca955 431 le_int32 matra, markStart = syllable;
b75a7d8f 432
374ca955
A
433 output.reset();
434
435 if (classTable->isStressMark(chars[markStart - 1])) {
436 markStart -= 1;
73c04bcf 437 output.noteStressMark(classTable, chars[markStart], markStart, tagArray1);
b75a7d8f 438 }
374ca955 439
73c04bcf 440 if (markStart != prev && classTable->isVowelModifier(chars[markStart - 1])) {
374ca955 441 markStart -= 1;
73c04bcf 442 output.noteVowelModifier(classTable, chars[markStart], markStart, tagArray1);
b75a7d8f
A
443 }
444
374ca955
A
445 matra = markStart - 1;
446
73c04bcf 447 while (output.noteMatra(classTable, chars[matra], matra, tagArray1, !lastInWord) && matra != prev) {
374ca955
A
448 matra -= 1;
449 }
b75a7d8f 450
73c04bcf
A
451 lastInWord = TRUE;
452
453 switch (classTable->getCharClass(chars[prev]) & CF_CLASS_MASK) {
454 case CC_RESERVED:
455 lastInWord = FALSE;
456 /* fall through */
457
458 case CC_INDEPENDENT_VOWEL:
459 case CC_ZERO_WIDTH_MARK:
b75a7d8f 460 for (i = prev; i < syllable; i += 1) {
73c04bcf 461 output.writeChar(chars[i], i, tagArray1);
b75a7d8f
A
462 }
463
464 break;
465
73c04bcf
A
466 case CC_NUKTA:
467 case CC_VIRAMA:
468 output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1);
469 output.writeChar(chars[prev], prev, tagArray1);
b75a7d8f
A
470 break;
471
73c04bcf
A
472 case CC_DEPENDENT_VOWEL:
473 case CC_SPLIT_VOWEL_PIECE_1:
474 case CC_SPLIT_VOWEL_PIECE_2:
475 case CC_SPLIT_VOWEL_PIECE_3:
476 case CC_VOWEL_MODIFIER:
477 case CC_STRESS_MARK:
b75a7d8f 478 output.writeMpre();
374ca955 479
73c04bcf 480 output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1);
374ca955 481
b75a7d8f 482 output.writeMbelow();
374ca955 483 output.writeSMbelow();
b75a7d8f 484 output.writeMabove();
374ca955 485
73c04bcf 486 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) {
374ca955
A
487 output.writeMpost();
488 }
489
73c04bcf 490 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) {
374ca955
A
491 output.writeVMabove();
492 output.writeSMabove(); // FIXME: there are no SM's in these scripts...
493 }
494
73c04bcf 495 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) {
374ca955
A
496 output.writeMpost();
497 }
498
b75a7d8f 499 output.writeLengthMark();
73c04bcf 500 output.writeVirama();
374ca955 501
73c04bcf 502 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) {
374ca955
A
503 output.writeVMabove();
504 output.writeSMabove();
505 }
506
507 output.writeVMpost();
b75a7d8f
A
508 break;
509
73c04bcf
A
510 case CC_INDEPENDENT_VOWEL_2:
511 case CC_INDEPENDENT_VOWEL_3:
512 case CC_CONSONANT:
513 case CC_CONSONANT_WITH_NUKTA:
b75a7d8f 514 {
374ca955
A
515 le_uint32 length = markStart - prev;
516 le_int32 lastConsonant = markStart - 1;
b75a7d8f
A
517 le_int32 baseLimit = prev;
518
519 // Check for REPH at front of syllable
520 if (length > 2 && classTable->isReph(chars[prev]) && classTable->isVirama(chars[prev + 1])) {
521 baseLimit += 2;
522
523 // Check for eyelash RA, if the script supports it
73c04bcf 524 if ((classTable->scriptFlags & SF_EYELASH_RA) != 0 &&
b75a7d8f
A
525 chars[baseLimit] == C_SIGN_ZWJ) {
526 if (length > 3) {
527 baseLimit += 1;
528 } else {
529 baseLimit -= 2;
530 }
531 }
532 }
533
534 while (lastConsonant > baseLimit && !classTable->isConsonant(chars[lastConsonant])) {
535 lastConsonant -= 1;
536 }
537
538 le_int32 baseConsonant = lastConsonant;
539 le_int32 postBase = lastConsonant + 1;
73c04bcf 540 le_int32 postBaseLimit = classTable->scriptFlags & SF_POST_BASE_LIMIT_MASK;
374ca955
A
541 le_bool seenVattu = FALSE;
542 le_bool seenBelowBaseForm = FALSE;
543
73c04bcf 544 if (postBase < markStart && classTable->isNukta(chars[postBase])) {
374ca955
A
545 postBase += 1;
546 }
b75a7d8f
A
547
548 while (baseConsonant > baseLimit) {
549 IndicClassTable::CharClass charClass = classTable->getCharClass(chars[baseConsonant]);
550
551 if (IndicClassTable::isConsonant(charClass)) {
552 if (postBaseLimit == 0 || seenVattu ||
553 (baseConsonant > baseLimit && !classTable->isVirama(chars[baseConsonant - 1])) ||
554 !IndicClassTable::hasPostOrBelowBaseForm(charClass)) {
555 break;
556 }
557
558 seenVattu = IndicClassTable::isVattu(charClass);
559
560 if (IndicClassTable::hasPostBaseForm(charClass)) {
561 if (seenBelowBaseForm) {
562 break;
563 }
564
565 postBase = baseConsonant;
566 } else if (IndicClassTable::hasBelowBaseForm(charClass)) {
374ca955 567 seenBelowBaseForm = TRUE;
b75a7d8f
A
568 }
569
570 postBaseLimit -= 1;
571 }
572
573 baseConsonant -= 1;
574 }
575
576 // Write Mpre
577 output.writeMpre();
578
579 // Write eyelash RA
580 // NOTE: baseLimit == prev + 3 iff eyelash RA present...
581 if (baseLimit == prev + 3) {
73c04bcf
A
582 output.writeChar(chars[prev], prev, tagArray2);
583 output.writeChar(chars[prev + 1], prev + 1, tagArray2);
584 output.writeChar(chars[prev + 2], prev + 2, tagArray2);
b75a7d8f
A
585 }
586
587 // write any pre-base consonants
374ca955 588 le_bool supressVattu = TRUE;
b75a7d8f
A
589
590 for (i = baseLimit; i < baseConsonant; i += 1) {
591 LEUnicode ch = chars[i];
374ca955 592 // Don't put 'blwf' on first consonant.
73c04bcf 593 FeatureMask features = (i == baseLimit? tagArray2 : tagArray1);
b75a7d8f
A
594 IndicClassTable::CharClass charClass = classTable->getCharClass(ch);
595
596 if (IndicClassTable::isConsonant(charClass)) {
597 if (IndicClassTable::isVattu(charClass) && supressVattu) {
73c04bcf 598 features = tagArray4;
b75a7d8f
A
599 }
600
601 supressVattu = IndicClassTable::isVattu(charClass);
602 } else if (IndicClassTable::isVirama(charClass) && chars[i + 1] == C_SIGN_ZWNJ)
603 {
73c04bcf 604 features = tagArray4;
b75a7d8f
A
605 }
606
73c04bcf 607 output.writeChar(ch, i, features);
b75a7d8f
A
608 }
609
610 le_int32 bcSpan = baseConsonant + 1;
611
374ca955 612 if (bcSpan < markStart && classTable->isNukta(chars[bcSpan])) {
b75a7d8f
A
613 bcSpan += 1;
614 }
615
374ca955 616 if (baseConsonant == lastConsonant && bcSpan < markStart && classTable->isVirama(chars[bcSpan])) {
b75a7d8f
A
617 bcSpan += 1;
618
374ca955 619 if (bcSpan < markStart && chars[bcSpan] == C_SIGN_ZWNJ) {
b75a7d8f
A
620 bcSpan += 1;
621 }
622 }
623
624 // note the base consonant for post-GSUB fixups
625 output.noteBaseConsonant();
626
627 // write base consonant
628 for (i = baseConsonant; i < bcSpan; i += 1) {
73c04bcf 629 output.writeChar(chars[i], i, tagArray4);
b75a7d8f
A
630 }
631
73c04bcf 632 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) {
b75a7d8f 633 output.writeMbelow();
374ca955 634 output.writeSMbelow(); // FIXME: there are no SMs in these scripts...
b75a7d8f
A
635 output.writeMabove();
636 output.writeMpost();
637 }
638
639 // write below-base consonants
640 if (baseConsonant != lastConsonant) {
641 for (i = bcSpan + 1; i < postBase; i += 1) {
73c04bcf 642 output.writeChar(chars[i], i, tagArray1);
b75a7d8f
A
643 }
644
645 if (postBase > lastConsonant) {
646 // write halant that was after base consonant
73c04bcf 647 output.writeChar(chars[bcSpan], bcSpan, tagArray1);
b75a7d8f
A
648 }
649 }
650
374ca955 651 // write Mbelow, SMbelow, Mabove
73c04bcf 652 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) {
b75a7d8f 653 output.writeMbelow();
374ca955 654 output.writeSMbelow();
b75a7d8f
A
655 output.writeMabove();
656 }
657
73c04bcf 658 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) {
b75a7d8f 659 if (baseLimit == prev + 2) {
73c04bcf
A
660 output.writeChar(chars[prev], prev, tagArray0);
661 output.writeChar(chars[prev + 1], prev + 1, tagArray0);
b75a7d8f
A
662 }
663
374ca955
A
664 output.writeVMabove();
665 output.writeSMabove(); // FIXME: there are no SM's in these scripts...
b75a7d8f
A
666 }
667
668 // write post-base consonants
669 // FIXME: does this put the right tags on post-base consonants?
670 if (baseConsonant != lastConsonant) {
671 if (postBase <= lastConsonant) {
672 for (i = postBase; i <= lastConsonant; i += 1) {
73c04bcf 673 output.writeChar(chars[i], i, tagArray3);
b75a7d8f
A
674 }
675
676 // write halant that was after base consonant
73c04bcf 677 output.writeChar(chars[bcSpan], bcSpan, tagArray1);
b75a7d8f
A
678 }
679
680 // write the training halant, if there is one
681 if (lastConsonant < matra && classTable->isVirama(chars[matra])) {
73c04bcf 682 output.writeChar(chars[matra], matra, tagArray4);
b75a7d8f
A
683 }
684 }
685
686 // write Mpost
73c04bcf 687 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) {
b75a7d8f
A
688 output.writeMpost();
689 }
690
691 output.writeLengthMark();
73c04bcf 692 output.writeVirama();
b75a7d8f
A
693
694 // write reph
73c04bcf 695 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) {
b75a7d8f 696 if (baseLimit == prev + 2) {
73c04bcf
A
697 output.writeChar(chars[prev], prev, tagArray0);
698 output.writeChar(chars[prev + 1], prev + 1, tagArray0);
b75a7d8f
A
699 }
700
374ca955
A
701 output.writeVMabove();
702 output.writeSMabove();
b75a7d8f
A
703 }
704
374ca955 705 output.writeVMpost();
b75a7d8f
A
706
707 break;
708 }
709
710 default:
711 break;
712 }
713
714 prev = syllable;
715 }
716
717 *outMPreFixups = mpreFixups;
718
719 return output.getOutputIndex();
720}
721
374ca955 722void IndicReordering::adjustMPres(MPreFixups *mpreFixups, LEGlyphStorage &glyphStorage)
b75a7d8f
A
723{
724 if (mpreFixups != NULL) {
374ca955 725 mpreFixups->apply(glyphStorage);
b75a7d8f
A
726
727 delete mpreFixups;
728 }
729}
730
731U_NAMESPACE_END