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