le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 
                                                         GlyphIterator *glyphIterator,
                                                         const LEFontInstance *fontInstance,
                                                         LEErrorCode& success) const
{
    if (LE_FAILURE(success)) { 
        return 0;
    }

    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
    le_int32 coverageIndex = getGlyphCoverage(glyph);

    if (coverageIndex >= 0) {
        const ClassDefinitionTable *classDefinitionTable =
            (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset));
        le_uint16 scSetCount = SWAPW(subClassSetCount);
        le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());

        if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
            Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
            const SubClassSetTable *subClassSetTable =
                (const SubClassSetTable *) ((char *) this + subClassSetTableOffset);
            le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
            le_int32 position = glyphIterator->getCurrStreamPosition();

            for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
                Offset subClassRuleTableOffset =
                    SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
                const SubClassRuleTable *subClassRuleTable =
                    (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset);
                le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
                le_uint16 substCount = SWAPW(subClassRuleTable->substCount);

                if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
                    const SubstitutionLookupRecord *substLookupRecordArray = 
                        (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];

                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);

                    return matchCount + 1;
                }

                glyphIterator->setCurrStreamPosition(position);
            }
        }

        // XXX If we get here, the table is mal-formed...
    }
    
    return 0;
}
le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
                                                              const LEFontInstance *fontInstance) const
{
    LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
    le_int32 coverageIndex = getGlyphCoverage(glyph);

    if (coverageIndex >= 0) {
        const ClassDefinitionTable *backtrackClassDefinitionTable =
            (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
        const ClassDefinitionTable *inputClassDefinitionTable =
            (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
        const ClassDefinitionTable *lookaheadClassDefinitionTable =
            (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
        le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
        le_int32 setClass = inputClassDefinitionTable->getGlyphClass((LEGlyphID) glyphIterator->getCurrGlyphID());

        if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
            Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
            const ChainSubClassSetTable *chainSubClassSetTable =
                (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
            le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
            le_int32 position = glyphIterator->getCurrStreamPosition();
            GlyphIterator tempIterator(*glyphIterator);

            for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
                Offset chainSubClassRuleTableOffset =
                    SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
                const ChainSubClassRuleTable *chainSubClassRuleTable =
                    (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
                le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
                le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
                const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
                le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
                const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
                le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
                

                tempIterator.setCurrStreamPosition(position);
                tempIterator.prev(backtrackGlyphCount + 1);
                if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
                    &tempIterator, backtrackClassDefinitionTable)) {
                    continue;
                }

                tempIterator.setCurrStreamPosition(position);
                tempIterator.next(inputGlyphCount);
                if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
                    continue;
                }

                if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
                    const SubstitutionLookupRecord *substLookupRecordArray = 
                        (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];

                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position);

                    return inputGlyphCount + 1;
                }

                glyphIterator->setCurrStreamPosition(position);
            }
        }

        // XXX If we get here, the table is mal-formed...
    }
    
    return 0;
}
le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor,
                                                                 GlyphIterator *glyphIterator,
                                                                 const LEFontInstance *fontInstance,
                                                                 LEErrorCode& success) const
{
    if (LE_FAILURE(success)) {
        return 0;
    }

    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
    le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
    if (LE_FAILURE(success)) {
        return 0;
    }

    if (coverageIndex >= 0) {
        LEReferenceTo<ClassDefinitionTable>
             backtrackClassDefinitionTable(base, success, SWAPW(backtrackClassDefTableOffset));
        LEReferenceTo<ClassDefinitionTable>
             inputClassDefinitionTable(base, success, SWAPW(inputClassDefTableOffset));
        LEReferenceTo<ClassDefinitionTable>
             lookaheadClassDefinitionTable(base, success, SWAPW(lookaheadClassDefTableOffset));
        le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
        le_int32 setClass = inputClassDefinitionTable->getGlyphClass(inputClassDefinitionTable,
                                                                     glyphIterator->getCurrGlyphID(),
                                                                     success);
        LEReferenceToArrayOf<Offset>
            chainSubClassSetTableOffsetArrayRef(base, success, chainSubClassSetTableOffsetArray, scSetCount);
        if (LE_FAILURE(success)) {
            return 0;
        }

        if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
            Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
            LEReferenceTo<ChainSubClassSetTable>
                 chainSubClassSetTable(base, success, chainSubClassSetTableOffset);
            if (LE_FAILURE(success)) { return 0; }
            le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
            le_int32 position = glyphIterator->getCurrStreamPosition();
            GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
            LEReferenceToArrayOf<Offset>
                chainSubClassRuleTableOffsetArrayRef(base, success, chainSubClassSetTable->chainSubClassRuleTableOffsetArray, chainSubClassRuleCount);
            if (LE_FAILURE(success)) {
                return 0;
            }
            for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
                Offset chainSubClassRuleTableOffset =
                    SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
                LEReferenceTo<ChainSubClassRuleTable>
                     chainSubClassRuleTable(chainSubClassSetTable, success, chainSubClassRuleTableOffset);
                if (LE_FAILURE(success)) { return 0; }
                le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
                LEReferenceToArrayOf<le_uint16>   backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount);
                if( LE_FAILURE(success) ) { return 0; }
                le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
                LEReferenceToArrayOf<le_uint16>   inputClassArray(base, success, &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1],inputGlyphCount+2); // +2 for the lookaheadGlyphCount count
                le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray.getObject(inputGlyphCount, success));
                LEReferenceToArrayOf<le_uint16>   lookaheadClassArray(base, success, inputClassArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2); // +2 for the substCount

                if( LE_FAILURE(success) ) { return 0; }
                le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);


                tempIterator.setCurrStreamPosition(position);

                if (! tempIterator.prev(backtrackGlyphCount)) {
                    continue;
                }

                tempIterator.prev();
                if (! matchGlyphClasses(backtrackClassArray, backtrackGlyphCount,
                                        &tempIterator, backtrackClassDefinitionTable, success, TRUE)) {
                    continue;
                }

                tempIterator.setCurrStreamPosition(position);
                tempIterator.next(inputGlyphCount);
                if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable, success)) {
                    continue;
                }

                if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable, success)) {
                    LEReferenceToArrayOf<SubstitutionLookupRecord>
                      substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadClassArray.getAlias(lookaheadGlyphCount + 1, success), substCount);
                    if (LE_FAILURE(success)) { return 0; }
                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);

                    return inputGlyphCount + 1;
                }

                glyphIterator->setCurrStreamPosition(position);
            }
        }

        // XXX If we get here, the table is mal-formed...
    }

    return 0;
}
le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference &base,
         const LookupProcessor *lookupProcessor,
         GlyphIterator *glyphIterator,
         const LEFontInstance *fontInstance,
         LEErrorCode& success) const
{
    if (LE_FAILURE(success)) {
        return 0;
    }

    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
    le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);
    if (LE_FAILURE(success)) {
        return 0;
    }

    if (coverageIndex >= 0) {
        LEReferenceTo<ClassDefinitionTable> classDefinitionTable(base, success, SWAPW(classDefTableOffset));
        if (LE_FAILURE(success)) { return 0; }
        le_uint16 scSetCount = SWAPW(subClassSetCount);
        le_int32 setClass = classDefinitionTable->getGlyphClass(classDefinitionTable,
                                                                glyphIterator->getCurrGlyphID(),
                                                                success);

        if (setClass < scSetCount) {
            LEReferenceToArrayOf<Offset>
                subClassSetTableOffsetArrayRef(base, success, subClassSetTableOffsetArray, scSetCount);
            if (LE_FAILURE(success)) { return 0; }
            if (subClassSetTableOffsetArray[setClass] != 0) {

                Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
                LEReferenceTo<SubClassSetTable> subClassSetTable(base, success, subClassSetTableOffset);
                if (LE_FAILURE(success)) { return 0; }
                le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
                le_int32 position = glyphIterator->getCurrStreamPosition();
                LEReferenceToArrayOf<Offset>
                    subClassRuleTableOffsetArrayRef(base, success, subClassSetTable->subClassRuleTableOffsetArray, subClassRuleCount);
                if (LE_FAILURE(success)) {
                    return 0;
                }
                for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
                    Offset subClassRuleTableOffset =
                        SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
                    LEReferenceTo<SubClassRuleTable>
                        subClassRuleTable(subClassSetTable, success, subClassRuleTableOffset);
                    if (LE_FAILURE(success)) { return 0; }
                    le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
                    le_uint16 substCount = SWAPW(subClassRuleTable->substCount);

                    LEReferenceToArrayOf<le_uint16> classArray(base, success, subClassRuleTable->classArray, matchCount+1);

                    if (LE_FAILURE(success)) { return 0; }
                    if (matchGlyphClasses(classArray, matchCount, glyphIterator, classDefinitionTable, success)) {
                        LEReferenceToArrayOf<SubstitutionLookupRecord>
                          substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount], substCount);

                        applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);

                        return matchCount + 1;
                    }

                    glyphIterator->setCurrStreamPosition(position);
                }
            }
        }

        // XXX If we get here, the table is mal-formed...
    }

    return 0;
}