os/textandloc/fontservices/textshaperplugin/IcuSource/layout/ContextualSubstSubtables.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
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 "LEFontInstance.h"
sl@0
     9
#include "OpenTypeTables.h"
sl@0
    10
#include "GlyphSubstitutionTables.h"
sl@0
    11
#include "ContextualSubstSubtables.h"
sl@0
    12
#include "GlyphIterator.h"
sl@0
    13
#include "LookupProcessor.h"
sl@0
    14
#include "CoverageTables.h"
sl@0
    15
#include "LESwaps.h"
sl@0
    16
sl@0
    17
U_NAMESPACE_BEGIN
sl@0
    18
sl@0
    19
/*
sl@0
    20
    NOTE: This could be optimized somewhat by keeping track
sl@0
    21
    of the previous sequenceIndex in the loop and doing next()
sl@0
    22
    or prev() of the delta between that and the current
sl@0
    23
    sequenceIndex instead of always resetting to the front.
sl@0
    24
*/
sl@0
    25
void ContextualSubstitutionBase::applySubstitutionLookups(
sl@0
    26
        const LookupProcessor *lookupProcessor,
sl@0
    27
        const SubstitutionLookupRecord *substLookupRecordArray,
sl@0
    28
        le_uint16 substCount,
sl@0
    29
        GlyphIterator *glyphIterator,
sl@0
    30
        const LEFontInstance *fontInstance,
sl@0
    31
        le_int32 position,
sl@0
    32
        LEErrorCode& success)
sl@0
    33
{
sl@0
    34
    if (LE_FAILURE(success)) {
sl@0
    35
        return;
sl@0
    36
    }
sl@0
    37
sl@0
    38
    GlyphIterator tempIterator(*glyphIterator);
sl@0
    39
sl@0
    40
    for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
sl@0
    41
        le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
sl@0
    42
        le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);
sl@0
    43
sl@0
    44
        tempIterator.setCurrStreamPosition(position);
sl@0
    45
        tempIterator.next(sequenceIndex);
sl@0
    46
sl@0
    47
        lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator,
sl@0
    48
            fontInstance, success);
sl@0
    49
    }
sl@0
    50
}
sl@0
    51
sl@0
    52
le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount,
sl@0
    53
                                               GlyphIterator *glyphIterator, le_bool backtrack)
sl@0
    54
{
sl@0
    55
    le_int32 direction = 1;
sl@0
    56
    le_int32 match = 0;
sl@0
    57
sl@0
    58
    if (backtrack) {
sl@0
    59
        match = glyphCount -1;
sl@0
    60
        direction = -1;
sl@0
    61
    }
sl@0
    62
sl@0
    63
    while (glyphCount > 0) {
sl@0
    64
        if (! glyphIterator->next()) {
sl@0
    65
            return FALSE;
sl@0
    66
        }
sl@0
    67
sl@0
    68
        TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();
sl@0
    69
sl@0
    70
        if (glyph != SWAPW(glyphArray[match])) {
sl@0
    71
            return FALSE;
sl@0
    72
        }
sl@0
    73
sl@0
    74
        glyphCount -= 1;
sl@0
    75
        match += direction;
sl@0
    76
    }
sl@0
    77
sl@0
    78
    return TRUE;
sl@0
    79
}
sl@0
    80
sl@0
    81
le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount,
sl@0
    82
                                               GlyphIterator *glyphIterator,
sl@0
    83
                                               const ClassDefinitionTable *classDefinitionTable,
sl@0
    84
                                               le_bool backtrack)
sl@0
    85
{
sl@0
    86
    le_int32 direction = 1;
sl@0
    87
    le_int32 match = 0;
sl@0
    88
sl@0
    89
    if (backtrack) {
sl@0
    90
        match = glyphCount - 1;
sl@0
    91
        direction = -1;
sl@0
    92
    }
sl@0
    93
sl@0
    94
    while (glyphCount > 0) {
sl@0
    95
        if (! glyphIterator->next()) {
sl@0
    96
            return FALSE;
sl@0
    97
        }
sl@0
    98
sl@0
    99
        LEGlyphID glyph = glyphIterator->getCurrGlyphID();
sl@0
   100
        le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph);
sl@0
   101
        le_int32 matchClass = SWAPW(classArray[match]);
sl@0
   102
sl@0
   103
        if (glyphClass != matchClass) {
sl@0
   104
            // Some fonts, e.g. Traditional Arabic, have classes
sl@0
   105
            // in the class array which aren't in the class definition
sl@0
   106
            // table. If we're looking for such a class, pretend that
sl@0
   107
            // we found it.
sl@0
   108
            if (classDefinitionTable->hasGlyphClass(matchClass)) {
sl@0
   109
                return FALSE;
sl@0
   110
            }
sl@0
   111
        }
sl@0
   112
sl@0
   113
        glyphCount -= 1;
sl@0
   114
        match += direction;
sl@0
   115
    }
sl@0
   116
sl@0
   117
    return TRUE;
sl@0
   118
}
sl@0
   119
sl@0
   120
le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
sl@0
   121
                                                     GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack)
sl@0
   122
{
sl@0
   123
    le_int32 direction = 1;
sl@0
   124
    le_int32 glyph = 0;
sl@0
   125
sl@0
   126
    if (backtrack) {
sl@0
   127
        glyph = glyphCount - 1;
sl@0
   128
        direction = -1;
sl@0
   129
    }
sl@0
   130
sl@0
   131
    while (glyphCount > 0) {
sl@0
   132
        Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);
sl@0
   133
        const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
sl@0
   134
sl@0
   135
        if (! glyphIterator->next()) {
sl@0
   136
            return FALSE;
sl@0
   137
        }
sl@0
   138
sl@0
   139
        if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
sl@0
   140
            return FALSE;
sl@0
   141
        }
sl@0
   142
sl@0
   143
        glyphCount -= 1;
sl@0
   144
        glyph += direction;
sl@0
   145
    }
sl@0
   146
sl@0
   147
    return TRUE;
sl@0
   148
}
sl@0
   149
sl@0
   150
le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   151
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   152
{
sl@0
   153
    if (LE_FAILURE(success)) {
sl@0
   154
        return 0;
sl@0
   155
    }
sl@0
   156
sl@0
   157
    switch(SWAPW(subtableFormat))
sl@0
   158
    {
sl@0
   159
    case 0:
sl@0
   160
        return 0;
sl@0
   161
sl@0
   162
    case 1:
sl@0
   163
    {
sl@0
   164
        const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
sl@0
   165
sl@0
   166
        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
sl@0
   167
    }
sl@0
   168
sl@0
   169
    case 2:
sl@0
   170
    {
sl@0
   171
        const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
sl@0
   172
sl@0
   173
        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
sl@0
   174
    }
sl@0
   175
sl@0
   176
    case 3:
sl@0
   177
    {
sl@0
   178
        const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
sl@0
   179
sl@0
   180
        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
sl@0
   181
    }
sl@0
   182
sl@0
   183
    default:
sl@0
   184
        return 0;
sl@0
   185
    }
sl@0
   186
}
sl@0
   187
sl@0
   188
le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   189
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   190
{
sl@0
   191
    if (LE_FAILURE(success)) {
sl@0
   192
    	return 0;
sl@0
   193
    }
sl@0
   194
sl@0
   195
    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
sl@0
   196
    le_int32 coverageIndex = getGlyphCoverage(glyph);
sl@0
   197
sl@0
   198
    if (coverageIndex >= 0) {
sl@0
   199
        le_uint16 srSetCount = SWAPW(subRuleSetCount);
sl@0
   200
sl@0
   201
        if (coverageIndex < srSetCount) {
sl@0
   202
            Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
sl@0
   203
            const SubRuleSetTable *subRuleSetTable =
sl@0
   204
                (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset);
sl@0
   205
            le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
sl@0
   206
            le_int32 position = glyphIterator->getCurrStreamPosition();
sl@0
   207
sl@0
   208
            for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
sl@0
   209
                Offset subRuleTableOffset =
sl@0
   210
                    SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
sl@0
   211
                const SubRuleTable *subRuleTable =
sl@0
   212
                    (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset);
sl@0
   213
                le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;
sl@0
   214
                le_uint16 substCount = SWAPW(subRuleTable->substCount);
sl@0
   215
sl@0
   216
                if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
sl@0
   217
                    const SubstitutionLookupRecord *substLookupRecordArray = 
sl@0
   218
                        (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
sl@0
   219
sl@0
   220
                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
sl@0
   221
                        substCount, glyphIterator, fontInstance, position, success);
sl@0
   222
sl@0
   223
                    return matchCount + 1;
sl@0
   224
                }
sl@0
   225
sl@0
   226
                glyphIterator->setCurrStreamPosition(position);
sl@0
   227
            }
sl@0
   228
        }
sl@0
   229
sl@0
   230
        // XXX If we get here, the table is mal-formed...
sl@0
   231
    }
sl@0
   232
    
sl@0
   233
    return 0;
sl@0
   234
}
sl@0
   235
sl@0
   236
le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   237
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   238
{
sl@0
   239
    if (LE_FAILURE(success)) {
sl@0
   240
        return 0;
sl@0
   241
    }
sl@0
   242
sl@0
   243
    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
sl@0
   244
    le_int32 coverageIndex = getGlyphCoverage(glyph);
sl@0
   245
sl@0
   246
    if (coverageIndex >= 0) {
sl@0
   247
        const ClassDefinitionTable *classDefinitionTable =
sl@0
   248
            (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset));
sl@0
   249
        le_uint16 scSetCount = SWAPW(subClassSetCount);
sl@0
   250
        le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
sl@0
   251
sl@0
   252
        if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
sl@0
   253
            Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
sl@0
   254
            const SubClassSetTable *subClassSetTable =
sl@0
   255
                (const SubClassSetTable *) ((char *) this + subClassSetTableOffset);
sl@0
   256
            le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
sl@0
   257
            le_int32 position = glyphIterator->getCurrStreamPosition();
sl@0
   258
sl@0
   259
            for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
sl@0
   260
                Offset subClassRuleTableOffset =
sl@0
   261
                    SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
sl@0
   262
                const SubClassRuleTable *subClassRuleTable =
sl@0
   263
                    (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset);
sl@0
   264
                le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
sl@0
   265
                le_uint16 substCount = SWAPW(subClassRuleTable->substCount);
sl@0
   266
sl@0
   267
                if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
sl@0
   268
                    const SubstitutionLookupRecord *substLookupRecordArray = 
sl@0
   269
                        (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];
sl@0
   270
sl@0
   271
                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
sl@0
   272
                        substCount, glyphIterator, fontInstance, position, success);
sl@0
   273
sl@0
   274
                    return matchCount + 1;
sl@0
   275
                }
sl@0
   276
sl@0
   277
                glyphIterator->setCurrStreamPosition(position);
sl@0
   278
            }
sl@0
   279
        }
sl@0
   280
sl@0
   281
        // XXX If we get here, the table is mal-formed...
sl@0
   282
    }
sl@0
   283
    
sl@0
   284
    return 0;
sl@0
   285
}
sl@0
   286
sl@0
   287
le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   288
    const LEFontInstance *fontInstance, LEErrorCode& success) const 
sl@0
   289
{
sl@0
   290
    if (LE_FAILURE(success)) {
sl@0
   291
        return 0;
sl@0
   292
    }
sl@0
   293
sl@0
   294
    le_uint16 gCount = SWAPW(glyphCount);
sl@0
   295
    le_uint16 subCount = SWAPW(substCount);
sl@0
   296
    le_int32 position = glyphIterator->getCurrStreamPosition();
sl@0
   297
sl@0
   298
    // Back up the glyph iterator so that we
sl@0
   299
    // can call next() before the check, which
sl@0
   300
    // will leave it pointing at the last glyph
sl@0
   301
    // that matched when we're done.
sl@0
   302
    glyphIterator->prev();
sl@0
   303
sl@0
   304
    if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
sl@0
   305
        const SubstitutionLookupRecord *substLookupRecordArray = 
sl@0
   306
            (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
sl@0
   307
sl@0
   308
        ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
sl@0
   309
            subCount, glyphIterator, fontInstance, position, success);
sl@0
   310
sl@0
   311
        return gCount + 1;
sl@0
   312
    }
sl@0
   313
sl@0
   314
    glyphIterator->setCurrStreamPosition(position);
sl@0
   315
sl@0
   316
    return 0;
sl@0
   317
}
sl@0
   318
sl@0
   319
le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   320
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   321
{
sl@0
   322
    if (LE_FAILURE(success)) {
sl@0
   323
        return 0;
sl@0
   324
    }
sl@0
   325
sl@0
   326
    switch(SWAPW(subtableFormat))
sl@0
   327
    {
sl@0
   328
    case 0:
sl@0
   329
        return 0;
sl@0
   330
sl@0
   331
    case 1:
sl@0
   332
    {
sl@0
   333
        const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
sl@0
   334
sl@0
   335
        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
sl@0
   336
    }
sl@0
   337
sl@0
   338
    case 2:
sl@0
   339
    {
sl@0
   340
        const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
sl@0
   341
sl@0
   342
        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
sl@0
   343
    }
sl@0
   344
sl@0
   345
    case 3:
sl@0
   346
    {
sl@0
   347
        const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
sl@0
   348
sl@0
   349
        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
sl@0
   350
    }
sl@0
   351
sl@0
   352
    default:
sl@0
   353
        return 0;
sl@0
   354
    }
sl@0
   355
}
sl@0
   356
sl@0
   357
static const LETag emptyTag = 0;
sl@0
   358
sl@0
   359
le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   360
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   361
{
sl@0
   362
    if (LE_FAILURE(success)) {
sl@0
   363
        return 0;
sl@0
   364
    }
sl@0
   365
sl@0
   366
    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
sl@0
   367
    le_int32 coverageIndex = getGlyphCoverage(glyph);
sl@0
   368
sl@0
   369
    if (coverageIndex >= 0) {
sl@0
   370
        le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
sl@0
   371
sl@0
   372
        if (coverageIndex < srSetCount) {
sl@0
   373
            Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
sl@0
   374
            const ChainSubRuleSetTable *chainSubRuleSetTable =
sl@0
   375
                (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset);
sl@0
   376
            le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
sl@0
   377
            le_int32 position = glyphIterator->getCurrStreamPosition();
sl@0
   378
            GlyphIterator tempIterator(*glyphIterator, emptyTag);
sl@0
   379
sl@0
   380
            for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
sl@0
   381
                Offset chainSubRuleTableOffset =
sl@0
   382
                    SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
sl@0
   383
                const ChainSubRuleTable *chainSubRuleTable =
sl@0
   384
                    (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset);
sl@0
   385
                le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);
sl@0
   386
                le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;
sl@0
   387
                const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1];
sl@0
   388
                le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);
sl@0
   389
                const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1];
sl@0
   390
                le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);
sl@0
   391
sl@0
   392
                tempIterator.setCurrStreamPosition(position);
sl@0
   393
sl@0
   394
                if (! tempIterator.prev(backtrackGlyphCount)) {
sl@0
   395
                    continue;
sl@0
   396
                }
sl@0
   397
sl@0
   398
                tempIterator.prev();
sl@0
   399
                if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
sl@0
   400
                    continue;
sl@0
   401
                }
sl@0
   402
sl@0
   403
                tempIterator.setCurrStreamPosition(position);
sl@0
   404
                tempIterator.next(inputGlyphCount);
sl@0
   405
                if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
sl@0
   406
                    continue;
sl@0
   407
                }
sl@0
   408
sl@0
   409
                if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
sl@0
   410
                    const SubstitutionLookupRecord *substLookupRecordArray = 
sl@0
   411
                        (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
sl@0
   412
sl@0
   413
                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
sl@0
   414
                        substCount, glyphIterator, fontInstance, position, success);
sl@0
   415
sl@0
   416
                    return inputGlyphCount + 1;
sl@0
   417
                }
sl@0
   418
sl@0
   419
                glyphIterator->setCurrStreamPosition(position);
sl@0
   420
            }
sl@0
   421
        }
sl@0
   422
sl@0
   423
        // XXX If we get here, the table is mal-formed...
sl@0
   424
    }
sl@0
   425
    
sl@0
   426
    return 0;
sl@0
   427
}
sl@0
   428
sl@0
   429
le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   430
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   431
{
sl@0
   432
    if (LE_FAILURE(success)) {
sl@0
   433
        return 0;
sl@0
   434
    }
sl@0
   435
sl@0
   436
    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
sl@0
   437
    le_int32 coverageIndex = getGlyphCoverage(glyph);
sl@0
   438
sl@0
   439
    if (coverageIndex >= 0) {
sl@0
   440
        const ClassDefinitionTable *backtrackClassDefinitionTable =
sl@0
   441
            (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
sl@0
   442
        const ClassDefinitionTable *inputClassDefinitionTable =
sl@0
   443
            (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
sl@0
   444
        const ClassDefinitionTable *lookaheadClassDefinitionTable =
sl@0
   445
            (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
sl@0
   446
        le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
sl@0
   447
        le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
sl@0
   448
sl@0
   449
        if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
sl@0
   450
            Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
sl@0
   451
            const ChainSubClassSetTable *chainSubClassSetTable =
sl@0
   452
                (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
sl@0
   453
            le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
sl@0
   454
            le_int32 position = glyphIterator->getCurrStreamPosition();
sl@0
   455
            GlyphIterator tempIterator(*glyphIterator, emptyTag);
sl@0
   456
sl@0
   457
            for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
sl@0
   458
                Offset chainSubClassRuleTableOffset =
sl@0
   459
                    SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
sl@0
   460
                const ChainSubClassRuleTable *chainSubClassRuleTable =
sl@0
   461
                    (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
sl@0
   462
                le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
sl@0
   463
                le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
sl@0
   464
                const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
sl@0
   465
                le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
sl@0
   466
                const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
sl@0
   467
                le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
sl@0
   468
                
sl@0
   469
sl@0
   470
                tempIterator.setCurrStreamPosition(position);
sl@0
   471
sl@0
   472
                if (! tempIterator.prev(backtrackGlyphCount)) {
sl@0
   473
                    continue;
sl@0
   474
                }
sl@0
   475
sl@0
   476
                tempIterator.prev();
sl@0
   477
                if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
sl@0
   478
                    &tempIterator, backtrackClassDefinitionTable, TRUE)) {
sl@0
   479
                    continue;
sl@0
   480
                }
sl@0
   481
sl@0
   482
                tempIterator.setCurrStreamPosition(position);
sl@0
   483
                tempIterator.next(inputGlyphCount);
sl@0
   484
                if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
sl@0
   485
                    continue;
sl@0
   486
                }
sl@0
   487
sl@0
   488
                if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
sl@0
   489
                    const SubstitutionLookupRecord *substLookupRecordArray = 
sl@0
   490
                        (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
sl@0
   491
sl@0
   492
                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
sl@0
   493
                        substCount, glyphIterator, fontInstance, position, success);
sl@0
   494
sl@0
   495
                    return inputGlyphCount + 1;
sl@0
   496
                }
sl@0
   497
sl@0
   498
                glyphIterator->setCurrStreamPosition(position);
sl@0
   499
            }
sl@0
   500
        }
sl@0
   501
sl@0
   502
        // XXX If we get here, the table is mal-formed...
sl@0
   503
    }
sl@0
   504
    
sl@0
   505
    return 0;
sl@0
   506
}
sl@0
   507
sl@0
   508
le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
sl@0
   509
    const LEFontInstance *fontInstance, LEErrorCode& success) const
sl@0
   510
{
sl@0
   511
    if (LE_FAILURE(success)) {
sl@0
   512
        return 0;
sl@0
   513
    }
sl@0
   514
sl@0
   515
    le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
sl@0
   516
    le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
sl@0
   517
    const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
sl@0
   518
    const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
sl@0
   519
    const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
sl@0
   520
    le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
sl@0
   521
    le_int32 position = glyphIterator->getCurrStreamPosition();
sl@0
   522
    GlyphIterator tempIterator(*glyphIterator, emptyTag);
sl@0
   523
sl@0
   524
    if (! tempIterator.prev(backtrkGlyphCount)) {
sl@0
   525
        return 0;
sl@0
   526
    }
sl@0
   527
sl@0
   528
    tempIterator.prev();
sl@0
   529
    if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
sl@0
   530
        backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
sl@0
   531
        return 0;
sl@0
   532
    }
sl@0
   533
sl@0
   534
    tempIterator.setCurrStreamPosition(position);
sl@0
   535
    tempIterator.next(inputGlyphCount - 1);
sl@0
   536
    if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
sl@0
   537
        lookaheadGlyphCount, &tempIterator, (const char *) this)) {
sl@0
   538
        return 0;
sl@0
   539
    }
sl@0
   540
sl@0
   541
    // Back up the glyph iterator so that we
sl@0
   542
    // can call next() before the check, which
sl@0
   543
    // will leave it pointing at the last glyph
sl@0
   544
    // that matched when we're done.
sl@0
   545
    glyphIterator->prev();
sl@0
   546
sl@0
   547
    if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
sl@0
   548
        inputGlyphCount, glyphIterator, (const char *) this)) {
sl@0
   549
        const SubstitutionLookupRecord *substLookupRecordArray = 
sl@0
   550
            (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
sl@0
   551
sl@0
   552
        ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
sl@0
   553
            substCount, glyphIterator, fontInstance, position, success);
sl@0
   554
sl@0
   555
        return inputGlyphCount;
sl@0
   556
    }
sl@0
   557
sl@0
   558
    glyphIterator->setCurrStreamPosition(position);
sl@0
   559
sl@0
   560
    return 0;
sl@0
   561
}
sl@0
   562
sl@0
   563
U_NAMESPACE_END