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