os/textandloc/fontservices/textshaperplugin/IcuSource/layout/ThaiShaping.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-2004 - All Rights Reserved
     4  *
     5  */
     6 
     7 #include "LETypes.h"
     8 #include "LEGlyphFilter.h"
     9 #include "OpenTypeTables.h"
    10 #include "LEGlyphStorage.h"
    11 #include "ThaiShaping.h"
    12 
    13 U_NAMESPACE_BEGIN
    14 
    15 enum {
    16     CH_SPACE        = 0x0020,
    17     CH_YAMAKKAN     = 0x0E4E,
    18     CH_MAI_HANAKAT  = 0x0E31,
    19     CH_SARA_AA      = 0x0E32,
    20     CH_SARA_AM      = 0x0E33,
    21     CH_SARA_UEE     = 0x0E37,
    22     CH_MAITAIKHU    = 0x0E47,
    23     CH_NIKHAHIT     = 0x0E4D,
    24     CH_SARA_U       = 0x0E38,
    25     CH_PHINTHU      = 0x0E3A,
    26     CH_YO_YING      = 0x0E0D,
    27     CH_THO_THAN     = 0x0E10,
    28     CH_DOTTED_CIRCLE = 0x25CC
    29 };
    30 
    31     le_uint8 ThaiShaping::getCharClass(LEUnicode ch)
    32 {
    33     le_uint8 charClass = NON;
    34     
    35     if (ch >= 0x0E00 && ch <= 0x0E5B) {
    36         charClass = classTable[ch - 0x0E00];
    37     }
    38     
    39     return charClass;
    40 }
    41 
    42 
    43 LEUnicode ThaiShaping::leftAboveVowel(LEUnicode vowel, le_uint8 glyphSet)
    44 {
    45     static const LEUnicode leftAboveVowels[][7] = {
    46         {0x0E61, 0x0E32, 0x0E33, 0x0E64, 0x0E65, 0x0E66, 0x0E67},
    47         {0xF710, 0x0E32, 0x0E33, 0xF701, 0xF702, 0xF703, 0xF704},
    48         {0xF884, 0x0E32, 0x0E33, 0xF885, 0xF886, 0xF887, 0xF788},
    49         {0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37}
    50     };
    51    
    52     if (vowel >= CH_MAI_HANAKAT && vowel <= CH_SARA_UEE) {
    53         return leftAboveVowels[glyphSet][vowel - CH_MAI_HANAKAT];
    54     }
    55     
    56     if (vowel == CH_YAMAKKAN && glyphSet == 0) {
    57         return 0x0E7E;
    58     }
    59     
    60     return vowel;
    61 }
    62 
    63 LEUnicode ThaiShaping::lowerRightTone(LEUnicode tone, le_uint8 glyphSet)
    64 {
    65     static const LEUnicode lowerRightTones[][7] = {
    66         {0x0E68, 0x0E69, 0x0E6A, 0x0E6B, 0x0E6C, 0x0E6D, 0x0E6E},
    67         {0x0E47, 0xF70A, 0xF70B, 0xF70C, 0xF70D, 0xF70E, 0x0E4D},
    68         {0x0E47, 0xF88B, 0xF88E, 0xF891, 0xF894, 0xF897, 0x0E4D},
    69         {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
    70     };
    71 
    72     if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
    73         return lowerRightTones[glyphSet][tone - CH_MAITAIKHU];
    74     }
    75     
    76     return tone;
    77 }
    78 
    79 LEUnicode ThaiShaping::lowerLeftTone(LEUnicode tone, le_uint8 glyphSet)
    80 {
    81     static const LEUnicode lowerLeftTones[][7] = {
    82         {0x0E76, 0x0E77, 0x0E78, 0x0E79, 0x0E7A, 0x0E7B, 0x0E7C},
    83         {0xF712, 0xF705, 0xF706, 0xF707, 0xF708, 0xF709, 0xF711},
    84         {0xF889, 0xF88C, 0xF88F, 0xF892, 0xF895, 0xF898, 0xF899},
    85         {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
    86     };
    87 
    88     if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
    89         return lowerLeftTones[glyphSet][tone - CH_MAITAIKHU];
    90     }
    91     
    92     return tone;
    93 }
    94 
    95 LEUnicode ThaiShaping::upperLeftTone(LEUnicode tone, le_uint8 glyphSet)
    96 {
    97     static const LEUnicode upperLeftTones[][7] = {
    98         {0x0E6F, 0x0E70, 0x0E71, 0x0E72, 0x0E73, 0x0E74, 0x0E75},
    99         {0xF712, 0xF713, 0xF714, 0xF715, 0xF716, 0xF717, 0xF711},
   100         {0xF889, 0xF88A, 0xF88D, 0xF890, 0xF893, 0xF896, 0xF899},
   101         {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
   102     };
   103 
   104     if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
   105         return upperLeftTones[glyphSet][tone - CH_MAITAIKHU];
   106     }
   107     
   108     return tone;
   109 }
   110 
   111 LEUnicode ThaiShaping::lowerBelowVowel(LEUnicode vowel, le_uint8 glyphSet)
   112 {
   113     static const LEUnicode lowerBelowVowels[][3] = {
   114         {0x0E3C, 0x0E3D, 0x0E3E},
   115         {0xF718, 0xF719, 0xF71A},
   116         {0x0E38, 0x0E39, 0x0E3A},
   117         {0x0E38, 0x0E39, 0x0E3A}
   118 
   119     };
   120 
   121     if (vowel >= CH_SARA_U && vowel <= CH_PHINTHU) {
   122         return lowerBelowVowels[glyphSet][vowel - CH_SARA_U];
   123     }
   124     
   125     return vowel;
   126 }
   127 
   128 LEUnicode ThaiShaping::noDescenderCOD(LEUnicode cod, le_uint8 glyphSet)
   129 {
   130     static const LEUnicode noDescenderCODs[][4] = {
   131         {0x0E60, 0x0E0E, 0x0E0F, 0x0E63},
   132         {0xF70F, 0x0E0E, 0x0E0F, 0xF700},
   133         {0x0E0D, 0x0E0E, 0x0E0F, 0x0E10},
   134         {0x0E0D, 0x0E0E, 0x0E0F, 0x0E10}
   135 
   136     };
   137 
   138     if (cod >= CH_YO_YING && cod <= CH_THO_THAN) {
   139         return noDescenderCODs[glyphSet][cod - CH_YO_YING];
   140     }
   141     
   142     return cod;
   143 }
   144 
   145 le_uint8 ThaiShaping::doTransition (StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet,
   146         LEUnicode errorChar, LEUnicode *outputBuffer, LEGlyphStorage &glyphStorage, le_int32 &outputIndex)
   147 {
   148     LEErrorCode success = LE_NO_ERROR;
   149 
   150     switch (transition.action) {
   151     case tA:
   152         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   153         outputBuffer[outputIndex++] = currChar;
   154         break;
   155         
   156     case tC:
   157         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   158         outputBuffer[outputIndex++] = currChar;
   159         break;
   160         
   161     case tD:
   162         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   163         outputBuffer[outputIndex++] = leftAboveVowel(currChar, glyphSet);
   164         break;
   165         
   166     case tE:
   167         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   168         outputBuffer[outputIndex++] = lowerRightTone(currChar, glyphSet);
   169         break;
   170         
   171     case tF:
   172         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   173         outputBuffer[outputIndex++] = lowerLeftTone(currChar, glyphSet);
   174         break;
   175     
   176     case tG:
   177         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   178         outputBuffer[outputIndex++] = upperLeftTone(currChar, glyphSet);
   179         break;
   180         
   181     case tH:
   182     {
   183         LEUnicode cod = outputBuffer[outputIndex - 1];
   184         LEUnicode coa = noDescenderCOD(cod, glyphSet);
   185 
   186         if (cod != coa) {
   187             outputBuffer[outputIndex - 1] = coa;
   188             
   189             glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   190             outputBuffer[outputIndex++] = currChar;
   191             break;
   192         }
   193 
   194         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   195         outputBuffer[outputIndex++] = lowerBelowVowel(currChar, glyphSet);
   196         break;
   197     }
   198         
   199     case tR:
   200         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   201         outputBuffer[outputIndex++] = errorChar;
   202 
   203         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   204         outputBuffer[outputIndex++] = currChar;
   205         break;
   206         
   207     case tS:
   208         if (currChar == CH_SARA_AM) {
   209             glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   210             outputBuffer[outputIndex++] = errorChar;
   211         }
   212 
   213         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   214         outputBuffer[outputIndex++] = currChar;
   215         break;
   216         
   217     default:
   218         // FIXME: if we get here, there's an error
   219         // in the state table!
   220         glyphStorage.setCharIndex(outputIndex, inputIndex, success);
   221         outputBuffer[outputIndex++] = currChar;
   222         break;
   223      }
   224      
   225      return transition.nextState;
   226 }
   227 
   228 le_uint8 ThaiShaping::getNextState(LEUnicode ch, le_uint8 prevState, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar,
   229                               le_uint8 &charClass, LEUnicode *output, LEGlyphStorage &glyphStorage, le_int32 &outputIndex)
   230 {
   231     StateTransition transition;
   232 
   233     charClass = getCharClass(ch);
   234     transition = getTransition(prevState, charClass);
   235     
   236     return doTransition(transition, ch, inputIndex, glyphSet, errorChar, output, glyphStorage, outputIndex);
   237 }
   238 
   239 le_bool ThaiShaping::isLegalHere(LEUnicode ch, le_uint8 prevState)
   240 {
   241     le_uint8 charClass = getCharClass(ch);
   242     StateTransition transition = getTransition(prevState, charClass);
   243 
   244     switch (transition.action) {
   245     case tA:
   246     case tC:
   247     case tD:
   248     case tE:
   249     case tF:
   250     case tG:
   251     case tH:
   252         return TRUE;
   253             
   254     case tR:
   255     case tS:
   256         return FALSE;
   257             
   258     default:
   259         // FIXME: if we get here, there's an error
   260         // in the state table!
   261         return FALSE;
   262     }
   263 }
   264     
   265 le_int32 ThaiShaping::compose(const LEUnicode *input, le_int32 offset, le_int32 charCount, le_uint8 glyphSet,
   266                           LEUnicode errorChar, LEUnicode *output, LEGlyphStorage &glyphStorage)
   267 {
   268     le_uint8 state = 0;
   269     le_int32 inputIndex;
   270     le_int32 outputIndex = 0;
   271     le_uint8 conState = 0xFF;
   272     le_int32 conInput = -1;
   273     le_int32 conOutput = -1;
   274     
   275     for (inputIndex = 0; inputIndex < charCount; inputIndex += 1) {
   276         LEUnicode ch = input[inputIndex + offset];
   277         le_uint8 charClass;
   278         
   279         // Decompose SARA AM into NIKHAHIT + SARA AA
   280         if (ch == CH_SARA_AM && isLegalHere(ch, state)) {
   281             outputIndex = conOutput;
   282             state = getNextState(CH_NIKHAHIT, conState, inputIndex, glyphSet, errorChar, charClass,
   283                 output, glyphStorage, outputIndex);
   284             
   285             for (int j = conInput + 1; j < inputIndex; j += 1) {
   286                 ch = input[j + offset];
   287                 state = getNextState(ch, state, j, glyphSet, errorChar, charClass,
   288                     output, glyphStorage, outputIndex);
   289             }
   290             
   291             ch = CH_SARA_AA;
   292         }
   293         
   294         state = getNextState(ch, state, inputIndex, glyphSet, errorChar, charClass,
   295             output, glyphStorage, outputIndex);
   296         
   297         if (charClass >= CON && charClass <= COD) {
   298             conState = state;
   299             conInput = inputIndex;
   300             conOutput = outputIndex;
   301         }
   302     }
   303     
   304     return outputIndex;
   305 }
   306 
   307 U_NAMESPACE_END