3 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
8 #include "OpenTypeTables.h"
9 #include "OpenTypeUtilities.h"
10 #include "IndicReordering.h"
11 #include "LEGlyphStorage.h"
12 #include "MPreFixups.h"
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
31 #define blwmFeatureTag LE_BLWM_FEATURE_TAG
32 #define abvmFeatureTag LE_ABVM_FEATURE_TAG
33 #define distFeatureTag LE_DIST_FEATURE_TAG
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
53 class IndicReorderingOutput
: public UMemory
{
55 le_int32 fSyllableCount
;
59 LEGlyphStorage
&fGlyphStorage
;
65 le_int32 fMbelowIndex
;
68 le_int32 fMaboveIndex
;
73 LEUnicode fLengthMark
;
74 le_int32 fLengthMarkIndex
;
77 le_int32 fAlLakunaIndex
;
79 FeatureMask fMatraFeatures
;
81 le_int32 fMPreOutIndex
;
82 MPreFixups
*fMPreFixups
;
87 FeatureMask fVMFeatures
;
92 FeatureMask fSMFeatures
;
94 void saveMatra(LEUnicode matra
, le_int32 matraIndex
, IndicClassTable::CharClass matraClass
)
96 // FIXME: check if already set, or if not a matra...
97 if (IndicClassTable::isLengthMark(matraClass
)) {
99 fLengthMarkIndex
= matraIndex
;
100 } else if (IndicClassTable::isAlLakuna(matraClass
)) {
102 fAlLakunaIndex
= matraIndex
;
104 switch (matraClass
& CF_POS_MASK
) {
107 fMpreIndex
= matraIndex
;
112 fMbelowIndex
= matraIndex
;
117 fMaboveIndex
= matraIndex
;
122 fMpostIndex
= matraIndex
;
133 IndicReorderingOutput(LEUnicode
*outChars
, LEGlyphStorage
&glyphStorage
, MPreFixups
*mpreFixups
)
134 : fSyllableCount(0), fOutIndex(0), fOutChars(outChars
), fGlyphStorage(glyphStorage
),
135 fMpre(0), fMpreIndex(0), fMbelow(0), fMbelowIndex(0), fMabove(0), fMaboveIndex(0),
136 fMpost(0), fMpostIndex(0), fLengthMark(0), fLengthMarkIndex(0), fAlLakuna(0), fAlLakunaIndex(0),
137 fMatraFeatures(0), fMPreOutIndex(-1), fMPreFixups(mpreFixups
),
138 fVMabove(0), fVMpost(0), fVMIndex(0), fVMFeatures(0),
139 fSMabove(0), fSMbelow(0), fSMIndex(0), fSMFeatures(0)
141 // nothing else to do...
144 ~IndicReorderingOutput()
146 // nothing to do here...
153 fMpre
= fMbelow
= fMabove
= fMpost
= fLengthMark
= fAlLakuna
= 0;
156 fVMabove
= fVMpost
= 0;
157 fSMabove
= fSMbelow
= 0;
160 void writeChar(LEUnicode ch
, le_uint32 charIndex
, FeatureMask charFeatures
)
162 LEErrorCode success
= LE_NO_ERROR
;
164 fOutChars
[fOutIndex
] = ch
;
166 fGlyphStorage
.setCharIndex(fOutIndex
, charIndex
, success
);
167 fGlyphStorage
.setAuxData(fOutIndex
, charFeatures
| (fSyllableCount
& LE_GLYPH_GROUP_MASK
), success
);
172 le_bool
noteMatra(const IndicClassTable
*classTable
, LEUnicode matra
, le_uint32 matraIndex
, FeatureMask matraFeatures
, le_bool wordStart
)
174 IndicClassTable::CharClass matraClass
= classTable
->getCharClass(matra
);
176 fMatraFeatures
= matraFeatures
;
179 fMatraFeatures
|= initFeatureMask
;
182 if (IndicClassTable::isMatra(matraClass
)) {
183 if (IndicClassTable::isSplitMatra(matraClass
)) {
184 const SplitMatra
*splitMatra
= classTable
->getSplitMatra(matraClass
);
187 for (i
= 0; i
< 3 && (*splitMatra
)[i
] != 0; i
+= 1) {
188 LEUnicode piece
= (*splitMatra
)[i
];
189 IndicClassTable::CharClass pieceClass
= classTable
->getCharClass(piece
);
191 saveMatra(piece
, matraIndex
, pieceClass
);
194 saveMatra(matra
, matraIndex
, matraClass
);
203 void noteVowelModifier(const IndicClassTable
*classTable
, LEUnicode vowelModifier
, le_uint32 vowelModifierIndex
, FeatureMask vowelModifierFeatures
)
205 IndicClassTable::CharClass vmClass
= classTable
->getCharClass(vowelModifier
);
207 fVMIndex
= vowelModifierIndex
;
208 fVMFeatures
= vowelModifierFeatures
;
210 if (IndicClassTable::isVowelModifier(vmClass
)) {
211 switch (vmClass
& CF_POS_MASK
) {
213 fVMabove
= vowelModifier
;
217 fVMpost
= vowelModifier
;
221 // FIXME: this is an error...
227 void noteStressMark(const IndicClassTable
*classTable
, LEUnicode stressMark
, le_uint32 stressMarkIndex
, FeatureMask stressMarkFeatures
)
229 IndicClassTable::CharClass smClass
= classTable
->getCharClass(stressMark
);
231 fSMIndex
= stressMarkIndex
;
232 fSMFeatures
= stressMarkFeatures
;
234 if (IndicClassTable::isStressMark(smClass
)) {
235 switch (smClass
& CF_POS_MASK
) {
237 fSMabove
= stressMark
;
241 fSMbelow
= stressMark
;
245 // FIXME: this is an error...
251 void noteBaseConsonant()
253 if (fMPreFixups
!= NULL
&& fMPreOutIndex
>= 0) {
254 fMPreFixups
->add(fOutIndex
, fMPreOutIndex
);
258 // Handles Al-Lakuna in Sinhala split vowels.
261 if (fAlLakuna
!= 0) {
262 writeChar(fAlLakuna
, fAlLakunaIndex
, fMatraFeatures
);
269 fMPreOutIndex
= fOutIndex
;
270 writeChar(fMpre
, fMpreIndex
, fMatraFeatures
);
277 writeChar(fMbelow
, fMbelowIndex
, fMatraFeatures
);
284 writeChar(fMabove
, fMaboveIndex
, fMatraFeatures
);
291 writeChar(fMpost
, fMpostIndex
, fMatraFeatures
);
295 void writeLengthMark()
297 if (fLengthMark
!= 0) {
298 writeChar(fLengthMark
, fLengthMarkIndex
, fMatraFeatures
);
305 writeChar(fVMabove
, fVMIndex
, fVMFeatures
);
312 writeChar(fVMpost
, fVMIndex
, fVMFeatures
);
319 writeChar(fSMabove
, fSMIndex
, fSMFeatures
);
326 writeChar(fSMbelow
, fSMIndex
, fSMFeatures
);
330 le_int32
getOutputIndex()
338 C_MALAYALAM_VOWEL_SIGN_U
= 0x0D41,
339 C_DOTTED_CIRCLE
= 0x25CC
342 // TODO: Find better names for these!
343 #define tagArray4 (loclFeatureMask | nuktFeatureMask | akhnFeatureMask | vatuFeatureMask | presFeatureMask | blwsFeatureMask | abvsFeatureMask | pstsFeatureMask | halnFeatureMask | blwmFeatureMask | abvmFeatureMask | distFeatureMask)
344 #define tagArray3 (pstfFeatureMask | tagArray4)
345 #define tagArray2 (halfFeatureMask | tagArray3)
346 #define tagArray1 (blwfFeatureMask | tagArray2)
347 #define tagArray0 (rphfFeatureMask | tagArray1)
349 static const FeatureMap featureMap
[] =
351 {loclFeatureTag
, loclFeatureMask
},
352 {initFeatureTag
, initFeatureMask
},
353 {nuktFeatureTag
, nuktFeatureMask
},
354 {akhnFeatureTag
, akhnFeatureMask
},
355 {rphfFeatureTag
, rphfFeatureMask
},
356 {blwfFeatureTag
, blwfFeatureMask
},
357 {halfFeatureTag
, halfFeatureMask
},
358 {pstfFeatureTag
, pstfFeatureMask
},
359 {vatuFeatureTag
, vatuFeatureMask
},
360 {presFeatureTag
, presFeatureMask
},
361 {blwsFeatureTag
, blwsFeatureMask
},
362 {abvsFeatureTag
, abvsFeatureMask
},
363 {pstsFeatureTag
, pstsFeatureMask
},
364 {halnFeatureTag
, halnFeatureMask
},
365 {blwmFeatureTag
, blwmFeatureMask
},
366 {abvmFeatureTag
, abvmFeatureMask
},
367 {distFeatureTag
, distFeatureMask
}
370 static const le_int32 featureCount
= LE_ARRAY_SIZE(featureMap
);
372 static const le_int8 stateTable
[][CC_COUNT
] =
374 // xx vm sm iv i2 i3 ct cn nu dv s1 s2 s3 vr zw al
375 { 1, 6, 1, 5, 8, 11, 3, 2, 1, 5, 9, 5, 5, 1, 1, 1}, // 0 - ground state
376 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 1 - exit state
377 {-1, 6, 1, -1, -1, -1, -1, -1, -1, 5, 9, 5, 5, 4, 12, -1}, // 2 - consonant with nukta
378 {-1, 6, 1, -1, -1, -1, -1, -1, 2, 5, 9, 5, 5, 4, 12, 13}, // 3 - consonant
379 {-1, -1, -1, -1, -1, -1, 3, 2, -1, -1, -1, -1, -1, -1, 7, -1}, // 4 - consonant virama
380 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 5 - dependent vowels
381 {-1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - vowel mark
382 {-1, -1, -1, -1, -1, -1, 3, 2, -1, -1, -1, -1, -1, -1, -1, -1}, // 7 - consonant virama ZWJ, consonant ZWJ virama
383 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1}, // 8 - independent vowels that can take a virama
384 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 5, -1, -1, -1}, // 9 - first part of split vowel
385 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1}, // 10 - second part of split vowel
386 {-1, 6, 1, -1, -1, -1, -1, -1, -1, 5, 9, 5, 5, 4, -1, -1}, // 11 - independent vowels that can take an iv
387 {-1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, 7}, // 12 - consonant ZWJ (TODO: Take everything else that can be after a consonant?)
388 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1} // 13 - consonant al-lakuna ZWJ consonant
392 const FeatureMap
*IndicReordering::getFeatureMap(le_int32
&count
)
394 count
= featureCount
;
399 le_int32
IndicReordering::findSyllable(const IndicClassTable
*classTable
, const LEUnicode
*chars
, le_int32 prev
, le_int32 charCount
)
401 le_int32 cursor
= prev
;
404 while (cursor
< charCount
) {
405 IndicClassTable::CharClass charClass
= classTable
->getCharClass(chars
[cursor
]);
407 state
= stateTable
[state
][charClass
& CF_CLASS_MASK
];
419 le_int32
IndicReordering::reorder(const LEUnicode
*chars
, le_int32 charCount
, le_int32 scriptCode
,
420 LEUnicode
*outChars
, LEGlyphStorage
&glyphStorage
,
421 MPreFixups
**outMPreFixups
)
423 MPreFixups
*mpreFixups
= NULL
;
424 const IndicClassTable
*classTable
= IndicClassTable::getScriptClassTable(scriptCode
);
426 if (classTable
->scriptFlags
& SF_MPRE_FIXUP
) {
427 mpreFixups
= new MPreFixups(charCount
);
430 IndicReorderingOutput
output(outChars
, glyphStorage
, mpreFixups
);
431 le_int32 i
, prev
= 0;
432 le_bool lastInWord
= FALSE
;
434 while (prev
< charCount
) {
435 le_int32 syllable
= findSyllable(classTable
, chars
, prev
, charCount
);
436 le_int32 matra
, markStart
= syllable
;
440 if (classTable
->isStressMark(chars
[markStart
- 1])) {
442 output
.noteStressMark(classTable
, chars
[markStart
], markStart
, tagArray1
);
445 if (markStart
!= prev
&& classTable
->isVowelModifier(chars
[markStart
- 1])) {
447 output
.noteVowelModifier(classTable
, chars
[markStart
], markStart
, tagArray1
);
450 matra
= markStart
- 1;
452 while (output
.noteMatra(classTable
, chars
[matra
], matra
, tagArray1
, !lastInWord
) && matra
!= prev
) {
458 switch (classTable
->getCharClass(chars
[prev
]) & CF_CLASS_MASK
) {
463 case CC_INDEPENDENT_VOWEL
:
464 case CC_ZERO_WIDTH_MARK
:
465 for (i
= prev
; i
< syllable
; i
+= 1) {
466 output
.writeChar(chars
[i
], i
, tagArray1
);
473 output
.writeChar(C_DOTTED_CIRCLE
, prev
, tagArray1
);
474 output
.writeChar(chars
[prev
], prev
, tagArray1
);
478 // A lone virama is illegal unless it follows a
479 // MALAYALAM_VOWEL_SIGN_U. Such a usage is called
481 if (chars
[prev
- 1] != C_MALAYALAM_VOWEL_SIGN_U
) {
482 output
.writeChar(C_DOTTED_CIRCLE
, prev
, tagArray1
);
485 output
.writeChar(chars
[prev
], prev
, tagArray1
);
488 case CC_DEPENDENT_VOWEL
:
489 case CC_SPLIT_VOWEL_PIECE_1
:
490 case CC_SPLIT_VOWEL_PIECE_2
:
491 case CC_SPLIT_VOWEL_PIECE_3
:
492 case CC_VOWEL_MODIFIER
:
496 output
.writeChar(C_DOTTED_CIRCLE
, prev
, tagArray1
);
498 output
.writeMbelow();
499 output
.writeSMbelow();
500 output
.writeMabove();
502 if ((classTable
->scriptFlags
& SF_MATRAS_AFTER_BASE
) != 0) {
506 if ((classTable
->scriptFlags
& SF_REPH_AFTER_BELOW
) != 0) {
507 output
.writeVMabove();
508 output
.writeSMabove(); // FIXME: there are no SM's in these scripts...
511 if ((classTable
->scriptFlags
& SF_MATRAS_AFTER_BASE
) == 0) {
515 output
.writeLengthMark();
516 output
.writeAlLakuna();
518 if ((classTable
->scriptFlags
& SF_REPH_AFTER_BELOW
) == 0) {
519 output
.writeVMabove();
520 output
.writeSMabove();
523 output
.writeVMpost();
526 case CC_INDEPENDENT_VOWEL_2
:
527 case CC_INDEPENDENT_VOWEL_3
:
529 case CC_CONSONANT_WITH_NUKTA
:
531 le_uint32 length
= markStart
- prev
;
532 le_int32 lastConsonant
= markStart
- 1;
533 le_int32 baseLimit
= prev
;
535 // Check for REPH at front of syllable
536 if (length
> 2 && classTable
->isReph(chars
[prev
]) && classTable
->isVirama(chars
[prev
+ 1])) {
539 // Check for eyelash RA, if the script supports it
540 if ((classTable
->scriptFlags
& SF_EYELASH_RA
) != 0 &&
541 chars
[baseLimit
] == C_SIGN_ZWJ
) {
550 while (lastConsonant
> baseLimit
&& !classTable
->isConsonant(chars
[lastConsonant
])) {
554 IndicClassTable::CharClass charClass
= CC_RESERVED
;
555 IndicClassTable::CharClass nextClass
= CC_RESERVED
;
556 le_int32 baseConsonant
= lastConsonant
;
557 le_int32 postBase
= lastConsonant
+ 1;
558 le_int32 postBaseLimit
= classTable
->scriptFlags
& SF_POST_BASE_LIMIT_MASK
;
559 le_bool seenVattu
= FALSE
;
560 le_bool seenBelowBaseForm
= FALSE
;
561 le_bool hasNukta
= FALSE
;
562 le_bool hasBelowBaseForm
= FALSE
;
563 le_bool hasPostBaseForm
= FALSE
;
565 if (postBase
< markStart
&& classTable
->isNukta(chars
[postBase
])) {
566 charClass
= CC_NUKTA
;
570 while (baseConsonant
> baseLimit
) {
571 nextClass
= charClass
;
572 hasNukta
= IndicClassTable::isNukta(nextClass
);
573 charClass
= classTable
->getCharClass(chars
[baseConsonant
]);
575 hasBelowBaseForm
= IndicClassTable::hasBelowBaseForm(charClass
) && !hasNukta
;
576 hasPostBaseForm
= IndicClassTable::hasPostBaseForm(charClass
) && !hasNukta
;
578 if (IndicClassTable::isConsonant(charClass
)) {
579 if (postBaseLimit
== 0 || seenVattu
||
580 (baseConsonant
> baseLimit
&& !classTable
->isVirama(chars
[baseConsonant
- 1])) ||
581 !(hasBelowBaseForm
|| hasPostBaseForm
)) {
585 // consonants with nuktas are never vattus
586 seenVattu
= IndicClassTable::isVattu(charClass
) && !hasNukta
;
588 // consonants with nuktas never have below- or post-base forms
589 if (hasPostBaseForm
) {
590 if (seenBelowBaseForm
) {
594 postBase
= baseConsonant
;
595 } else if (hasBelowBaseForm
) {
596 seenBelowBaseForm
= TRUE
;
609 // NOTE: baseLimit == prev + 3 iff eyelash RA present...
610 if (baseLimit
== prev
+ 3) {
611 output
.writeChar(chars
[prev
], prev
, tagArray2
);
612 output
.writeChar(chars
[prev
+ 1], prev
+ 1, tagArray2
);
613 output
.writeChar(chars
[prev
+ 2], prev
+ 2, tagArray2
);
616 // write any pre-base consonants
617 le_bool supressVattu
= TRUE
;
619 for (i
= baseLimit
; i
< baseConsonant
; i
+= 1) {
620 LEUnicode ch
= chars
[i
];
621 // Don't put 'blwf' on first consonant.
622 FeatureMask features
= (i
== baseLimit
? tagArray2
: tagArray1
);
624 charClass
= classTable
->getCharClass(ch
);
625 nextClass
= classTable
->getCharClass(chars
[i
+ 1]);
626 hasNukta
= IndicClassTable::isNukta(nextClass
);
628 if (IndicClassTable::isConsonant(charClass
)) {
629 if (IndicClassTable::isVattu(charClass
) && !hasNukta
&& supressVattu
) {
630 features
= tagArray4
;
633 supressVattu
= IndicClassTable::isVattu(charClass
) && !hasNukta
;
634 } else if (IndicClassTable::isVirama(charClass
) && chars
[i
+ 1] == C_SIGN_ZWNJ
)
636 features
= tagArray4
;
639 output
.writeChar(ch
, i
, features
);
642 le_int32 bcSpan
= baseConsonant
+ 1;
644 if (bcSpan
< markStart
&& classTable
->isNukta(chars
[bcSpan
])) {
648 if (baseConsonant
== lastConsonant
&& bcSpan
< markStart
&&
649 (classTable
->isVirama(chars
[bcSpan
]) || classTable
->isAlLakuna(chars
[bcSpan
]))) {
652 if (bcSpan
< markStart
&& chars
[bcSpan
] == C_SIGN_ZWNJ
) {
657 // note the base consonant for post-GSUB fixups
658 output
.noteBaseConsonant();
660 // write base consonant
661 for (i
= baseConsonant
; i
< bcSpan
; i
+= 1) {
662 output
.writeChar(chars
[i
], i
, tagArray4
);
665 if ((classTable
->scriptFlags
& SF_MATRAS_AFTER_BASE
) != 0) {
666 output
.writeMbelow();
667 output
.writeSMbelow(); // FIXME: there are no SMs in these scripts...
668 output
.writeMabove();
672 // write below-base consonants
673 if (baseConsonant
!= lastConsonant
) {
674 for (i
= bcSpan
+ 1; i
< postBase
; i
+= 1) {
675 output
.writeChar(chars
[i
], i
, tagArray1
);
678 if (postBase
> lastConsonant
) {
679 // write halant that was after base consonant
680 output
.writeChar(chars
[bcSpan
], bcSpan
, tagArray1
);
684 // write Mbelow, SMbelow, Mabove
685 if ((classTable
->scriptFlags
& SF_MATRAS_AFTER_BASE
) == 0) {
686 output
.writeMbelow();
687 output
.writeSMbelow();
688 output
.writeMabove();
691 if ((classTable
->scriptFlags
& SF_REPH_AFTER_BELOW
) != 0) {
692 if (baseLimit
== prev
+ 2) {
693 output
.writeChar(chars
[prev
], prev
, tagArray0
);
694 output
.writeChar(chars
[prev
+ 1], prev
+ 1, tagArray0
);
697 output
.writeVMabove();
698 output
.writeSMabove(); // FIXME: there are no SM's in these scripts...
701 // write post-base consonants
702 // FIXME: does this put the right tags on post-base consonants?
703 if (baseConsonant
!= lastConsonant
) {
704 if (postBase
<= lastConsonant
) {
705 for (i
= postBase
; i
<= lastConsonant
; i
+= 1) {
706 output
.writeChar(chars
[i
], i
, tagArray3
);
709 // write halant that was after base consonant
710 output
.writeChar(chars
[bcSpan
], bcSpan
, tagArray1
);
713 // write the training halant, if there is one
714 if (lastConsonant
< matra
&& classTable
->isVirama(chars
[matra
])) {
715 output
.writeChar(chars
[matra
], matra
, tagArray4
);
720 if ((classTable
->scriptFlags
& SF_MATRAS_AFTER_BASE
) == 0) {
724 output
.writeLengthMark();
725 output
.writeAlLakuna();
728 if ((classTable
->scriptFlags
& SF_REPH_AFTER_BELOW
) == 0) {
729 if (baseLimit
== prev
+ 2) {
730 output
.writeChar(chars
[prev
], prev
, tagArray0
);
731 output
.writeChar(chars
[prev
+ 1], prev
+ 1, tagArray0
);
734 output
.writeVMabove();
735 output
.writeSMabove();
738 output
.writeVMpost();
750 *outMPreFixups
= mpreFixups
;
752 return output
.getOutputIndex();
755 void IndicReordering::adjustMPres(MPreFixups
*mpreFixups
, LEGlyphStorage
&glyphStorage
)
757 if (mpreFixups
!= NULL
) {
758 mpreFixups
->apply(glyphStorage
);