os/textandloc/fontservices/textshaperplugin/IcuSource/layout/IndicReordering.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2  *
     3  * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
     4  *
     5  */
     6 
     7 #include "LETypes.h"
     8 #include "OpenTypeTables.h"
     9 #include "OpenTypeUtilities.h"
    10 #include "IndicReordering.h"
    11 #include "LEGlyphStorage.h"
    12 #include "MPreFixups.h"
    13 
    14 U_NAMESPACE_BEGIN
    15 
    16 const LEUnicode KBearURA		= 0x0A73;
    17 const LEUnicode KDepVowelU		= 0x0A41;
    18 const LEUnicode KDepVowelUU		= 0x0A42;
    19 const LEUnicode KDepVowelOO		= 0x0A4B;
    20 const LEUnicode KVowelU	    	= 0x0A09;
    21 const LEUnicode KVowelUU		= 0x0A0A;
    22 const LEUnicode KVowelOO		= 0x0A13;
    23 
    24 class ReorderingOutput : public UMemory {
    25 private:
    26     le_int32 fOutIndex;
    27     LEUnicode *fOutChars;
    28 
    29     LEGlyphStorage &fGlyphStorage;
    30 
    31     LEUnicode fMpre;
    32     le_int32  fMpreIndex;
    33 
    34     LEUnicode fMbelow;
    35     le_int32  fMbelowIndex;
    36 
    37     LEUnicode fMabove;
    38     le_int32  fMaboveIndex;
    39 
    40     LEUnicode fMpost;
    41     le_int32  fMpostIndex;
    42 
    43     LEUnicode fLengthMark;
    44     le_int32  fLengthMarkIndex;
    45 
    46     const LETag *fMatraTags;
    47     
    48     le_int32 fMPreOutIndex;
    49     MPreFixups *fMPreFixups;
    50     
    51     LEUnicode fVMabove;
    52     LEUnicode fVMpost;
    53     le_int32  fVMIndex;
    54     const LETag *fVMTags;
    55     
    56     LEUnicode fSMabove;
    57     LEUnicode fSMbelow;
    58     le_int32  fSMIndex;
    59     const LETag *fSMTags;
    60 
    61     void saveMatra(LEUnicode matra, le_int32 matraIndex, IndicClassTable::CharClass matraClass)
    62     {
    63         // FIXME: check if already set, or if not a matra...
    64         if (IndicClassTable::isLengthMark(matraClass)) {
    65             fLengthMark = matra;
    66             fLengthMarkIndex = matraIndex;
    67         } else {
    68             switch (matraClass & CF_POS_MASK) {
    69             case CF_POS_BEFORE:
    70                 fMpre = matra;
    71                 fMpreIndex = matraIndex;
    72                 break;
    73                
    74             case CF_POS_BELOW:
    75                 fMbelow = matra;
    76                 fMbelowIndex = matraIndex;
    77                 break;
    78                
    79             case CF_POS_ABOVE:
    80                 fMabove = matra;
    81                 fMaboveIndex = matraIndex;
    82                 break;
    83                
    84             case CF_POS_AFTER:
    85                 fMpost = matra;
    86                 fMpostIndex = matraIndex;
    87                 break;
    88                
    89             default:
    90                 // can't get here...
    91                 break;
    92            }
    93         }
    94         
    95         // 1922 mlyl : only the right part of matra AU should be displayed -->
    96         if (fMpre == CC_DEPENDENT_VOWEL_SIGN_MLYL_E && fLengthMark != 0) 
    97         {
    98         	fMpre = 0;
    99         	fMpreIndex = -1;
   100         } 
   101         // <-- 1922 mlyl
   102     }
   103 
   104 public:
   105     ReorderingOutput(LEUnicode *outChars, LEGlyphStorage &glyphStorage, MPreFixups *mpreFixups)
   106         : fOutIndex(0), fOutChars(outChars), fGlyphStorage(glyphStorage),
   107           fMpre(0), fMpreIndex(0), fMbelow(0), fMbelowIndex(0), fMabove(0), fMaboveIndex(0),
   108           fMpost(0), fMpostIndex(0), fLengthMark(0), fLengthMarkIndex(0), fMatraTags(NULL),
   109           fMPreOutIndex(-1), fMPreFixups(mpreFixups),
   110           fVMabove(0), fVMpost(0), fVMIndex(0), fVMTags(NULL),
   111           fSMabove(0), fSMbelow(0), fSMIndex(0), fSMTags(NULL)
   112     {
   113         // nothing else to do...
   114     }
   115 
   116     ~ReorderingOutput()
   117     {
   118         // nothing to do here...
   119     }
   120 
   121     void reset()
   122     {
   123         fMpre = fMbelow = fMabove = fMpost = fLengthMark = 0;
   124         fMPreOutIndex = -1;
   125         
   126         fVMabove = fVMpost  = 0;
   127         fSMabove = fSMbelow = 0;
   128     }
   129 
   130     void writeChar(LEUnicode ch, le_uint32 charIndex, const LETag *charTags)
   131     {
   132         LEErrorCode success = LE_NO_ERROR;
   133 
   134         fOutChars[fOutIndex] = ch;
   135 
   136         fGlyphStorage.setCharIndex(fOutIndex, charIndex, success);
   137         fGlyphStorage.setAuxData(fOutIndex, (void *) charTags, success);
   138 
   139         fOutIndex += 1;
   140     }
   141 
   142     le_bool noteMatra(const IndicClassTable *classTable, LEUnicode matra, le_uint32 matraIndex, const LETag *matraTags)
   143     {
   144         IndicClassTable::CharClass matraClass = classTable->getCharClass(matra);
   145 
   146         fMatraTags  = matraTags;
   147 
   148         if (IndicClassTable::isMatra(matraClass)) {
   149             if (IndicClassTable::isSplitMatra(matraClass)) {
   150                 const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass);
   151                 int i;
   152 
   153                 for (i = 0; i < 3 && (*splitMatra)[i] != 0; i += 1) {
   154                     LEUnicode piece = (*splitMatra)[i];
   155                     IndicClassTable::CharClass pieceClass = classTable->getCharClass(piece);
   156 
   157                     saveMatra(piece, matraIndex, pieceClass);
   158                 }
   159             } else {
   160                 saveMatra(matra, matraIndex, matraClass);
   161             }
   162 
   163             return TRUE;
   164         }
   165 
   166         return FALSE;
   167     }
   168     
   169     void noteVowelModifier(const IndicClassTable *classTable, LEUnicode vowelModifier, le_uint32 vowelModifierIndex, const LETag *vowelModifierTags)
   170     {
   171         IndicClassTable::CharClass vmClass = classTable->getCharClass(vowelModifier);
   172         
   173         fVMIndex = vowelModifierIndex;
   174         fVMTags  = vowelModifierTags;
   175         
   176         if (IndicClassTable::isVowelModifier(vmClass)) {
   177            switch (vmClass & CF_POS_MASK) {
   178            case CF_POS_ABOVE:
   179                fVMabove = vowelModifier;
   180                break;
   181             
   182            case CF_POS_AFTER:
   183                fVMpost = vowelModifier;
   184                break;
   185            
   186            default:
   187                // FIXME: this is an error...
   188                break;
   189            }
   190         }
   191     }
   192     
   193     void noteStressMark(const IndicClassTable *classTable, LEUnicode stressMark, le_uint32 stressMarkIndex, const LETag *stressMarkTags)
   194     {
   195        IndicClassTable::CharClass smClass = classTable->getCharClass(stressMark);
   196         
   197         fSMIndex = stressMarkIndex;
   198         fSMTags  = stressMarkTags;
   199         
   200         if (IndicClassTable::isStressMark(smClass)) {
   201             switch (smClass & CF_POS_MASK) {
   202             case CF_POS_ABOVE:
   203                 fSMabove = stressMark;
   204                 break;
   205             
   206             case CF_POS_BELOW:
   207                 fSMbelow = stressMark;
   208                 break;
   209            
   210             default:
   211                 // FIXME: this is an error...
   212                 break;
   213            }
   214         }
   215     }
   216 
   217     void noteBaseConsonant()
   218     {
   219         if (fMPreFixups != NULL && fMPreOutIndex >= 0) {
   220             fMPreFixups->add(fOutIndex, fMPreOutIndex);
   221         }
   222     }
   223 
   224     void writeMpre()
   225     {
   226         if (fMpre != 0) {
   227             fMPreOutIndex = fOutIndex;
   228             writeChar(fMpre, fMpreIndex, fMatraTags);
   229         }
   230     }
   231 
   232     void writeMbelow()
   233     {
   234         if (fMbelow != 0) {
   235             writeChar(fMbelow, fMbelowIndex, fMatraTags);
   236         }
   237     }
   238 
   239     void writeMabove()
   240     {
   241         if (fMabove != 0) {
   242             writeChar(fMabove, fMaboveIndex, fMatraTags);
   243         }
   244     }
   245 
   246     void writeMpost()
   247     {
   248         if (fMpost != 0) {
   249             writeChar(fMpost, fMpostIndex, fMatraTags);
   250         }
   251     }
   252 
   253     void writeLengthMark()
   254     {
   255         if (fLengthMark != 0) {
   256             writeChar(fLengthMark, fLengthMarkIndex, fMatraTags);
   257         }
   258     }
   259     
   260     void writeVMabove()
   261     {
   262         if (fVMabove != 0) {
   263             writeChar(fVMabove, fVMIndex, fVMTags);
   264         }
   265     }
   266         
   267     void writeVMpost()
   268     {
   269         if (fVMpost != 0) {
   270             writeChar(fVMpost, fVMIndex, fVMTags);
   271         }
   272     }
   273     
   274     void writeSMabove()
   275     {
   276         if (fSMabove != 0) {
   277             writeChar(fSMabove, fSMIndex, fSMTags);
   278         }
   279     }
   280     
   281     void writeSMbelow()
   282     {
   283         if (fSMbelow != 0) {
   284             writeChar(fSMbelow, fSMIndex, fSMTags);
   285         }
   286     }
   287     
   288     le_int32 getOutputIndex()
   289     {
   290         return fOutIndex;
   291     }
   292 };
   293 
   294 enum
   295 {
   296     C_DOTTED_CIRCLE = 0x25CC
   297 };
   298 
   299 static const LETag emptyTag       = 0x00000000; // ''
   300 
   301 static const LETag nuktFeatureTag = LE_NUKT_FEATURE_TAG;
   302 static const LETag akhnFeatureTag = LE_AKHN_FEATURE_TAG;
   303 static const LETag rphfFeatureTag = LE_RPHF_FEATURE_TAG;
   304 static const LETag blwfFeatureTag = LE_BLWF_FEATURE_TAG;
   305 static const LETag halfFeatureTag = LE_HALF_FEATURE_TAG;
   306 static const LETag pstfFeatureTag = LE_PSTF_FEATURE_TAG;
   307 static const LETag vatuFeatureTag = LE_VATU_FEATURE_TAG;
   308 static const LETag presFeatureTag = LE_PRES_FEATURE_TAG;
   309 static const LETag blwsFeatureTag = LE_BLWS_FEATURE_TAG;
   310 static const LETag abvsFeatureTag = LE_ABVS_FEATURE_TAG;
   311 static const LETag pstsFeatureTag = LE_PSTS_FEATURE_TAG;
   312 static const LETag halnFeatureTag = LE_HALN_FEATURE_TAG;
   313 
   314 static const LETag blwmFeatureTag = LE_BLWM_FEATURE_TAG;
   315 static const LETag abvmFeatureTag = LE_ABVM_FEATURE_TAG;
   316 static const LETag distFeatureTag = LE_DIST_FEATURE_TAG;
   317 static const LETag loclFeatureTag = LE_LOCL_FEATURE_TAG;
   318 
   319 // These are in the order in which the features need to be applied
   320 // for correct processing
   321 static const LETag featureOrder[] =
   322 {
   323     loclFeatureTag,
   324     nuktFeatureTag, akhnFeatureTag, rphfFeatureTag, blwfFeatureTag, halfFeatureTag, pstfFeatureTag,
   325     vatuFeatureTag, presFeatureTag, blwsFeatureTag, abvsFeatureTag, pstsFeatureTag, halnFeatureTag,
   326     blwmFeatureTag, abvmFeatureTag, distFeatureTag, emptyTag
   327 };
   328 
   329 // The order of these is determined so that the tag array of each glyph can start
   330 // at an offset into this array 
   331 // FIXME: do we want a seperate tag array for each kind of character??
   332 // FIXME: are there cases where this ordering causes glyphs to get tags
   333 // that they shouldn't?
   334 static const LETag tagArray[] =
   335 {
   336     rphfFeatureTag, blwfFeatureTag, halfFeatureTag, pstfFeatureTag, nuktFeatureTag, akhnFeatureTag,
   337     vatuFeatureTag, presFeatureTag, blwsFeatureTag, abvsFeatureTag, pstsFeatureTag, halnFeatureTag,
   338     blwmFeatureTag, abvmFeatureTag, distFeatureTag, loclFeatureTag, emptyTag
   339 };
   340 
   341 
   342 // Nokia: New state responses ia and de, and new states for Devanagari Independent Vowel A 
   343 // added by Nokia to allow the special Devanagari CANDRA A formation using A + CANDRA E, and
   344 // a new zero width joiner state specially for ZWJ's that come after the Independent Vowel A
   345 // Also, changed the consonant response to ZWJ by allowing it to have a ZWJ straight after it.
   346 // This allows Kannada RA to take a ZWJ after it and not make it a REPHA
   347 // Nokia: New states for Gurmukhi bearers to support decompositions of the independent vowels 
   348 // into a sequence of a vowel bearer and a depending vowel sign.
   349 static const le_int8 stateTable[][CC_COUNT] =
   350 {
   351 //   xx  vm  sm  iv  i2  ct  cn  nu  dv  s1  s2  s3  vr  zw  ia  de  cr  to  ba  bi  bu  ga  gi  gu 
   352     { 1,  1,  1,  5,  8,  3,  2,  1,  1,  9,  5,  1,  1,  1, 20,  1, 25, 26, 27, 28, 29,  1,  1,  1}, //  0 - ground state
   353     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  1 - exit state
   354     {-1,  6,  1, -1, -1, -1, -1, -1,  5,  9,  5,  5,  4, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, //  2 - consonant with nukta
   355     {-1,  6,  1, -1, -1, -1, -1,  2,  5,  9,  5,  5,  4, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, //  3 - consonant
   356     {-1, -1, -1, -1, -1, 12, 11, -1, -1, -1, -1, -1, -1, 22, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1}, //  4 - ct vr
   357     {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  5 - dependent vowels
   358     {-1, -1,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  6 - vowel mark
   359     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  7 - ZWJ, ZWNJ seen after a consonant: Modified by Nokia
   360     {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  8 - independent vowels that can take a virama
   361     {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, 10,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  9 - first part of split vowel
   362     {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 10 - second part of split vowel
   363     {-1,  6,  1, -1, -1, -1, -1, -1,  5,  9,  5,  5, 13, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 11 - ct vr ct nu
   364     {-1,  6,  1, -1, -1, -1, -1, 11,  5,  9,  5,  5, 13, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 12 - ct vr ct
   365     {-1, -1, -1, -1, -1, 15, 14, -1, -1, -1, -1, -1, -1, 23, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1}, // 13 - ct vr ct vr
   366     {-1,  6,  1, -1, -1, -1, -1, -1,  5,  9,  5,  5, 16, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 14 - ct vr ct vr ct nu
   367     {-1,  6,  1, -1, -1, -1, -1, 14,  5,  9,  5,  5, 16, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 15 - ct vr ct vr ct
   368     {-1, -1, -1, -1, -1, 18, 17, -1, -1, -1, -1, -1, -1, 24, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1}, // 16 - ct vr ct vr ct vr
   369     {-1,  6,  1, -1, -1, -1, -1, -1,  5,  9,  5,  5, 19, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 17 - ct vr ct vr ct vr ct nu
   370     {-1,  6,  1, -1, -1, -1, -1, 17,  5,  9,  5,  5, 19, -1, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 18 - ct vr ct vr ct vr ct
   371     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 19 - ct vr ct vr ct vr ct vr
   372     {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1,  5, -1, -1, -1, -1, -1, -1, -1, -1}, // 20 - devanagari independent vowel A that can take a modifier - CANDRA E: Added by Nokia
   373     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  5, -1, -1, -1, -1, -1, -1, -1, -1}, // 21 - ZWJ after independent vowel A: Added by Nokia  
   374     {-1,  6, -1, -1, -1, 12, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1}, // 22 - ZWJ after a virama: Added by Nokia  
   375     {-1,  6, -1, -1, -1, 15, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1}, // 23 - ZWJ after a ct vr ct vr: Added by Nokia  
   376     {-1,  6, -1, -1, -1, 18, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1}, // 24 - ZWJ after a ct vr ct vr ct vr: Added by Nokia  
   377     {-1,  6,  1, -1, -1, -1, -1,  2,  5,  9,  5,  5,  4,  7, -1,  5, -1, 26, -1, -1, -1,  5,  5,  5}, // 25 - Kannada consonant Ra: Added by Nokia
   378     {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, 10,  5,  4, 21, -1,  5, -1, -1, -1, -1, -1, -1, -1, -1}, // 26 - devanagari independent vowel A that can take a modifier - CANDRA E: Added by Nokia
   379     {-1,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  5, -1, -1}, // 27 - Gurmukhi bearer ARA and independent A
   380     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  5, -1}, // 28 - Gurmukhi bearer IRI
   381     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  5}, // 29 - Gurmukhi bearer URA
   382 };
   383 
   384 
   385 const LETag *IndicReordering::getFeatureOrder()
   386 {
   387     return featureOrder;
   388 }
   389 
   390 le_int32 IndicReordering::findSyllable(const IndicClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount)
   391 {
   392     le_int32 cursor = prev;
   393     le_int8 state = 0;
   394 
   395     while (cursor < charCount) {
   396         IndicClassTable::CharClass charClass = classTable->getCharClass(chars[cursor]);
   397 
   398         state = stateTable[state][charClass & CF_CLASS_MASK];
   399 
   400         if (state < 0) {
   401             break;
   402         }
   403 
   404         cursor += 1;
   405     }
   406 
   407     return cursor;
   408 }
   409 
   410 le_int32 IndicReordering::reorder(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode,
   411                                   LEUnicode *outChars, LEGlyphStorage &glyphStorage,
   412                                   MPreFixups **outMPreFixups, LEErrorCode& success)
   413 {
   414     MPreFixups *mpreFixups = NULL;
   415     const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
   416 
   417     if (classTable->scriptFlags & SF_MPRE_FIXUP) {
   418         mpreFixups = new MPreFixups(charCount);
   419         if (!mpreFixups) {
   420             success = LE_MEMORY_ALLOCATION_ERROR;
   421             return 0;
   422         }
   423     }
   424 
   425     ReorderingOutput output(outChars, glyphStorage, mpreFixups);
   426     le_int32 i, prev = 0;
   427 
   428     while (prev < charCount) {
   429         le_int32 syllable = findSyllable(classTable, chars, prev, charCount);
   430         le_int32 matra, markStart = syllable;
   431 
   432         output.reset();
   433         
   434         if (classTable->isStressMark(chars[markStart - 1])) {
   435             markStart -= 1;
   436             output.noteStressMark(classTable, chars[markStart], markStart, &tagArray[1]);
   437         }
   438         
   439         if (prev != markStart && classTable->isVowelModifier(chars[markStart - 1])) {
   440             markStart -= 1;
   441             output.noteVowelModifier(classTable, chars[markStart], markStart, &tagArray[1]);
   442         }
   443         
   444         matra = markStart - 1;
   445         
   446         // Added by Nokia. Workaround ligature substitution: Bearer URA + Dependent Vowel -> Independent Vowel
   447         // For these sequences, no need to write matra since it will be replaced.
   448         if (!(chars[prev] == KBearURA && (prev + 1 < syllable) && 
   449         		(chars[prev+1] == KDepVowelU || chars[prev+1] == KDepVowelUU || chars[prev+1] == KDepVowelOO ))) {
   450        		
   451         	while (prev <= matra && output.noteMatra(classTable, chars[matra], matra, &tagArray[1])) {
   452             	matra -= 1;
   453         	}
   454         }
   455 
   456         
   457         switch (classTable->getCharClass(chars[prev]) & CF_CLASS_MASK) {
   458         case CC_RESERVED:
   459         case CC_INDEPENDENT_VOWEL:
   460         case CC_ZERO_WIDTH_MARK:
   461         case CC_INDEPENDENT_VOWEL_A:	// Added by Nokia
   462         case CC_INDEPENDENT_VOWEL_TAMIL_O:	// Added by Nokia
   463         case CC_GUR_BEARER_U:	//Added by Nokia
   464         	
   465         	// Added by Nokia. Workaround ligature substitution: Bearer URA + Dependent Vowel -> Independent Vowel
   466         	if (chars[prev] == KBearURA && (prev + 1 < markStart)){
   467         		if (chars[prev+1] == KDepVowelU){
   468         	   		output.writeChar(KVowelU, prev, &tagArray[1]);
   469         	   		prev = prev+2;
   470         		}
   471         		else if (chars[prev+1] == KDepVowelUU){
   472         			output.writeChar(KVowelUU, prev, &tagArray[1]);
   473         			prev = prev+2;
   474         		}
   475         		else if (chars[prev+1] == KDepVowelOO){
   476         			output.writeChar(KVowelOO, prev, &tagArray[1]);
   477         			prev = prev+2;
   478         		}
   479         	}
   480        	
   481             for (i = prev; i < syllable; i += 1) {
   482                 output.writeChar(chars[i], i, &tagArray[1]);
   483             }
   484 
   485             break;
   486 
   487         case CC_NUKTA:
   488         case CC_VIRAMA:
   489             output.writeChar(C_DOTTED_CIRCLE, prev, &tagArray[1]);
   490             output.writeChar(chars[prev], prev, &tagArray[1]);
   491             break;
   492 
   493         case CC_DEPENDENT_VOWEL:
   494         case CC_DEPENDENT_VOWEL_CANDRA_E:	// Added by Nokia
   495         case CC_SPLIT_VOWEL_PIECE_1:
   496         case CC_SPLIT_VOWEL_PIECE_2:
   497         case CC_SPLIT_VOWEL_PIECE_3:
   498         case CC_VOWEL_MODIFIER:
   499         case CC_STRESS_MARK:
   500         case CC_GUR_DEPENDENT_VOWEL_A:
   501         case CC_GUR_DEPENDENT_VOWEL_I:
   502         case CC_GUR_DEPENDENT_VOWEL_U:
   503             output.writeMpre();
   504 
   505             output.writeChar(C_DOTTED_CIRCLE, prev, &tagArray[1]);
   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 
   526             if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) {
   527                 output.writeVMabove();
   528                 output.writeSMabove();
   529             }
   530 
   531             output.writeVMpost();
   532             break;
   533 
   534         case CC_INDEPENDENT_VOWEL_2:
   535         case CC_CONSONANT:
   536         case CC_CONSONANT_WITH_NUKTA:
   537         case CC_CONSONANT_KANNADA_BENGALI_RA:
   538         case CC_GUR_BEARER_A:				// Added by Nokia
   539         case CC_GUR_BEARER_I:				// Added by Nokia
   540         {
   541             le_uint32 length = markStart - prev;
   542             le_int32  lastConsonant = markStart - 1;
   543             le_int32  baseLimit = prev;
   544             
   545             // Check for REPH at front of syllable
   546             if (length > 2 && classTable->isReph(chars[prev]) && classTable->isVirama(chars[prev + 1])) {
   547                 baseLimit += 2;
   548 
   549                 // Check for eyelash RA, if the script supports it
   550                 if ((classTable->scriptFlags & SF_EYELASH_RA) != 0 &&
   551                     chars[baseLimit] == C_SIGN_ZWJ) {
   552                     if (length > 3) {
   553                         baseLimit += 1;
   554                     } else {
   555                         baseLimit -= 2;
   556                     }
   557                 }
   558             }
   559 
   560             while (lastConsonant > baseLimit && !classTable->isConsonant(chars[lastConsonant])) {
   561                 lastConsonant -= 1;
   562             }
   563 
   564             le_int32 baseConsonant = lastConsonant;
   565             le_int32 postBase = lastConsonant + 1;
   566             le_int32 postBaseLimit = classTable->scriptFlags & SF_POST_BASE_LIMIT_MASK;
   567             le_bool  seenVattu = FALSE;
   568             le_bool  seenBelowBaseForm = FALSE;
   569 
   570             if (postBase < markStart && classTable->isNukta(chars[postBase])) {
   571                 postBase += 1;
   572             }
   573 
   574             while (baseConsonant > baseLimit) {
   575                 IndicClassTable::CharClass charClass = classTable->getCharClass(chars[baseConsonant]);
   576 
   577                 if (IndicClassTable::isConsonant(charClass)) {
   578                     IndicClassTable::CharClass nextCharClass
   579                     	= classTable->getCharClass(chars[baseConsonant + 1]);
   580                     le_bool hasNukta = IndicClassTable::isNukta(nextCharClass);
   581                     // Consonants with nuktas never have post-base or below-base forms
   582                     le_bool hasPostBaseForm = !hasNukta
   583                     	&& IndicClassTable::hasPostBaseForm(charClass);
   584                     le_bool hasBelowBaseForm = !hasNukta
   585                     	&& IndicClassTable::hasBelowBaseForm(charClass);
   586 
   587                     // Added by Nokia -- A Bengali Ya should only have a post base form if it is the last component in a consonant cluster.
   588                     if (IndicClassTable::isBengaliYa(charClass) && (baseConsonant != lastConsonant))
   589 						hasPostBaseForm = FALSE;
   590 
   591                     // Added by Nokia 1922 mlyl: YAKAR/VAKAR/RAKAR are not formed after LLA/LLLA/RRA, but when LLA/LLLA/RRA is one of combination ligature?-->
   592                     if ((chars[baseConsonant] == CC_CONSONANT_MLYL_YA || chars[baseConsonant] == CC_CONSONANT_MLYL_VA || chars[baseConsonant] == CC_CONSONANT_MLYL_RA)
   593                     		&& baseConsonant >=2
   594                     		&& (chars[baseConsonant - 2] == CC_CONSONANT_MLYL_LLA || chars[baseConsonant - 2] == CC_CONSONANT_MLYL_LLLA || chars[baseConsonant - 2] == CC_CONSONANT_MLYL_RRA))
   595                     	hasPostBaseForm = FALSE;
   596 
   597                     // D15 + D4D + D2F/D35 + D4D + D30: YAKAR/VAKAR not formed
   598                     if ((chars[baseConsonant] == CC_CONSONANT_MLYL_YA || chars[baseConsonant] == CC_CONSONANT_MLYL_VA)
   599                     		&& lastConsonant >= 4
   600                     		&& chars[lastConsonant] == CC_CONSONANT_MLYL_RA)
   601                     	hasPostBaseForm = FALSE;
   602                     // <-- 1922 mlyl
   603                     
   604                     if (postBaseLimit == 0 || seenVattu ||
   605                         (baseConsonant > baseLimit && !classTable->isVirama(chars[baseConsonant - 1])) ||
   606                         (!hasPostBaseForm && !hasBelowBaseForm)) {
   607                         break;
   608                     }
   609 
   610                     // Consonants with nuktas are never vattus
   611                     seenVattu = !hasNukta && IndicClassTable::isVattu(charClass);
   612 
   613                     if (hasPostBaseForm) {
   614                         if (seenBelowBaseForm) {
   615                             break;
   616                         }
   617 
   618                         postBase = baseConsonant;
   619                     } else if (hasBelowBaseForm) {
   620                         seenBelowBaseForm = TRUE;
   621                     }
   622 
   623                     postBaseLimit -= 1;
   624                 }
   625 
   626                 baseConsonant -= 1;
   627             }
   628 
   629             // Write Mpre
   630             output.writeMpre();
   631 
   632             // Write eyelash RA
   633             // NOTE: baseLimit == prev + 3 iff eyelash RA present...
   634             if (baseLimit == prev + 3) {
   635                 output.writeChar(chars[prev], prev, &tagArray[2]);
   636                 output.writeChar(chars[prev + 1], prev + 1, &tagArray[2]);
   637                 output.writeChar(chars[prev + 2], prev + 2, &tagArray[2]);
   638             }
   639 
   640             // write any pre-base consonants
   641             le_bool supressVattu = TRUE;
   642 
   643             for (i = baseLimit; i < baseConsonant; i += 1) {
   644                 LEUnicode ch = chars[i];
   645                 // Don't put 'blwf' on first consonant.
   646                 const LETag *tag = (i == baseLimit? &tagArray[2] : &tagArray[1]);
   647                 IndicClassTable::CharClass charClass = classTable->getCharClass(ch);
   648                 IndicClassTable::CharClass nextCharClass =
   649                 	classTable->getCharClass(chars[i + 1]);
   650                 	
   651                 // Nokia: Added a check to see if the character that is two characters after
   652                 // the RA is a ZWJ, which then doesn't allow the RA to become a VATTU and allows
   653                 // the formation of an EYELASH RA
   654                 le_bool isGenuineVattu = IndicClassTable::isVattu(charClass)
   655                 	&& !IndicClassTable::isNukta(nextCharClass)
   656                 	&& chars[i + 2] != C_SIGN_ZWJ;
   657 
   658                 if (IndicClassTable::isConsonant(charClass)) {
   659                     if (isGenuineVattu && supressVattu) {
   660                         tag = &tagArray[4];
   661                     }
   662 
   663                     supressVattu = isGenuineVattu;
   664                 } else if (IndicClassTable::isVirama(charClass) && chars[i + 1] == C_SIGN_ZWNJ)
   665                 {
   666                     tag = &tagArray[4];
   667                 }
   668 
   669                 output.writeChar(ch, i, tag);
   670             }
   671 
   672             le_int32 bcSpan = baseConsonant + 1;
   673 
   674             if (bcSpan < markStart && classTable->isNukta(chars[bcSpan])) {
   675                 bcSpan += 1;
   676             }
   677 
   678             if (baseConsonant == lastConsonant && bcSpan < markStart && classTable->isVirama(chars[bcSpan])) {
   679                 bcSpan += 1;
   680 
   681                 if (bcSpan < markStart && chars[bcSpan] == C_SIGN_ZWNJ) {
   682                     bcSpan += 1;
   683                 }
   684             }
   685 
   686             // note the base consonant for post-GSUB fixups
   687             output.noteBaseConsonant();
   688 
   689             // write base consonant
   690             for (i = baseConsonant; i < bcSpan; i += 1) {
   691 	        	// 1922 mlyl -->
   692 	        	if (i >= 2 && chars[i] == C_SIGN_ZWJ && classTable->isMlylChillu(chars[i-2]))
   693 	        		output.writeChar(chars[i], i, &tagArray[2]);
   694 	        	else
   695 	        	// <-- 1922 mlyl
   696 	                output.writeChar(chars[i], i, &tagArray[4]);
   697             }
   698 
   699             //write Mbelow, SMbelow, Mabove, Mpost after base consonant with flag SF_MATRAS_AFTER_BASE setting
   700             if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) {
   701                 output.writeMbelow();
   702                 output.writeSMbelow(); // FIXME: there are no SMs in these scripts...
   703                 output.writeMabove();
   704                 output.writeMpost();
   705             }
   706 
   707             // write below-base consonants
   708             if (baseConsonant != lastConsonant) {
   709                 for (i = bcSpan + 1; i < postBase; i += 1) {
   710                     output.writeChar(chars[i], i, &tagArray[1]);
   711                 }
   712 
   713                 if (postBase > lastConsonant) {
   714                     // write halant that was after base consonant
   715                     output.writeChar(chars[bcSpan], bcSpan, &tagArray[1]);
   716                 }
   717             }
   718 
   719             // Added by Nokia: write Mbelow, SMbelow, Mabove after below-base consonants without flag SF_MATRAS_AFTER_BASE or SF_MATRAS_AFTER_POSTBASE
   720             if (((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) &&
   721             	((classTable->scriptFlags & SF_MATRAS_AFTER_POSTBASE) == 0)) {
   722             	output.writeMbelow();
   723                 output.writeSMbelow();
   724                 output.writeMabove();
   725             }
   726 
   727             if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) {
   728                 if (baseLimit == prev + 2) {
   729                     output.writeChar(chars[prev], prev, &tagArray[0]);
   730                     output.writeChar(chars[prev + 1], prev + 1, &tagArray[0]);
   731                 }
   732 
   733                 output.writeVMabove();
   734                 output.writeSMabove(); // FIXME: there are no SM's in these scripts...
   735             }
   736 
   737             // write post-base consonants
   738             // FIXME: does this put the right tags on post-base consonants?
   739             if (baseConsonant != lastConsonant) {
   740                 if (postBase <= lastConsonant) {
   741                     for (i = postBase; i <= lastConsonant; i += 1) {
   742                         output.writeChar(chars[i], i, &tagArray[3]);
   743                     }
   744 
   745                     // write halant that was after base consonant
   746                     output.writeChar(chars[bcSpan], bcSpan, &tagArray[1]);
   747                 }
   748 
   749                 // write the training halant, if there is one
   750                 if (lastConsonant < matra && classTable->isVirama(chars[matra])) {
   751                     output.writeChar(chars[matra], matra, &tagArray[4]);
   752                 }
   753             }
   754 	        
   755             // Added by Nokia: write Mbelow, SMbelow, Mabove and Mpost after post-base consonants with flag SF_MATRAS_AFTER_POSTBASE
   756 	        if ((classTable->scriptFlags & SF_MATRAS_AFTER_POSTBASE) != 0) {
   757 	        		output.writeMbelow();
   758                     output.writeSMbelow();
   759                     output.writeMabove();
   760                     output.writeMpost();
   761 	        }
   762 
   763 	        //Added by Nokia: write Mpost finally
   764             if (((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) &&
   765             	((classTable->scriptFlags & SF_MATRAS_AFTER_POSTBASE) == 0)) {
   766                 output.writeMpost();
   767 	        }
   768             
   769 	        output.writeLengthMark();
   770 
   771             // write reph
   772             if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) {
   773                 if (baseLimit == prev + 2) {
   774                     output.writeChar(chars[prev], prev, &tagArray[0]);
   775                     output.writeChar(chars[prev + 1], prev + 1, &tagArray[0]);
   776                 }
   777 
   778                 output.writeVMabove();
   779                 output.writeSMabove();
   780             }
   781 
   782             output.writeVMpost();
   783 
   784             break;
   785         }
   786 
   787         default:
   788             break;
   789         }
   790 
   791         prev = syllable;
   792     }
   793 
   794     *outMPreFixups = mpreFixups;
   795 
   796     return output.getOutputIndex();
   797 }
   798 
   799 void IndicReordering::adjustMPres(MPreFixups *mpreFixups,
   800     LEGlyphStorage &glyphStorage, LEErrorCode& success)
   801 {
   802     if (LE_SUCCESS(success) && mpreFixups != NULL) {
   803         mpreFixups->apply(glyphStorage, success);
   804         
   805         delete mpreFixups;
   806     }
   807 }
   808 
   809 U_NAMESPACE_END