sl@0: /* sl@0: * sl@0: * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved sl@0: * sl@0: */ sl@0: sl@0: #include "LETypes.h" sl@0: #include "LEFontInstance.h" sl@0: #include "OpenTypeTables.h" sl@0: #include "GlyphSubstitutionTables.h" sl@0: #include "ContextualSubstSubtables.h" sl@0: #include "GlyphIterator.h" sl@0: #include "LookupProcessor.h" sl@0: #include "CoverageTables.h" sl@0: #include "LESwaps.h" sl@0: sl@0: U_NAMESPACE_BEGIN sl@0: sl@0: /* sl@0: NOTE: This could be optimized somewhat by keeping track sl@0: of the previous sequenceIndex in the loop and doing next() sl@0: or prev() of the delta between that and the current sl@0: sequenceIndex instead of always resetting to the front. sl@0: */ sl@0: void ContextualSubstitutionBase::applySubstitutionLookups( sl@0: const LookupProcessor *lookupProcessor, sl@0: const SubstitutionLookupRecord *substLookupRecordArray, sl@0: le_uint16 substCount, sl@0: GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, sl@0: le_int32 position, sl@0: LEErrorCode& success) sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return; sl@0: } sl@0: sl@0: GlyphIterator tempIterator(*glyphIterator); sl@0: sl@0: for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) { sl@0: le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex); sl@0: le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex); sl@0: sl@0: tempIterator.setCurrStreamPosition(position); sl@0: tempIterator.next(sequenceIndex); sl@0: sl@0: lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, sl@0: fontInstance, success); sl@0: } sl@0: } sl@0: sl@0: le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount, sl@0: GlyphIterator *glyphIterator, le_bool backtrack) sl@0: { sl@0: le_int32 direction = 1; sl@0: le_int32 match = 0; sl@0: sl@0: if (backtrack) { sl@0: match = glyphCount -1; sl@0: direction = -1; sl@0: } sl@0: sl@0: while (glyphCount > 0) { sl@0: if (! glyphIterator->next()) { sl@0: return FALSE; sl@0: } sl@0: sl@0: TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID(); sl@0: sl@0: if (glyph != SWAPW(glyphArray[match])) { sl@0: return FALSE; sl@0: } sl@0: sl@0: glyphCount -= 1; sl@0: match += direction; sl@0: } sl@0: sl@0: return TRUE; sl@0: } sl@0: sl@0: le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount, sl@0: GlyphIterator *glyphIterator, sl@0: const ClassDefinitionTable *classDefinitionTable, sl@0: le_bool backtrack) sl@0: { sl@0: le_int32 direction = 1; sl@0: le_int32 match = 0; sl@0: sl@0: if (backtrack) { sl@0: match = glyphCount - 1; sl@0: direction = -1; sl@0: } sl@0: sl@0: while (glyphCount > 0) { sl@0: if (! glyphIterator->next()) { sl@0: return FALSE; sl@0: } sl@0: sl@0: LEGlyphID glyph = glyphIterator->getCurrGlyphID(); sl@0: le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph); sl@0: le_int32 matchClass = SWAPW(classArray[match]); sl@0: sl@0: if (glyphClass != matchClass) { sl@0: // Some fonts, e.g. Traditional Arabic, have classes sl@0: // in the class array which aren't in the class definition sl@0: // table. If we're looking for such a class, pretend that sl@0: // we found it. sl@0: if (classDefinitionTable->hasGlyphClass(matchClass)) { sl@0: return FALSE; sl@0: } sl@0: } sl@0: sl@0: glyphCount -= 1; sl@0: match += direction; sl@0: } sl@0: sl@0: return TRUE; sl@0: } sl@0: sl@0: le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount, sl@0: GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack) sl@0: { sl@0: le_int32 direction = 1; sl@0: le_int32 glyph = 0; sl@0: sl@0: if (backtrack) { sl@0: glyph = glyphCount - 1; sl@0: direction = -1; sl@0: } sl@0: sl@0: while (glyphCount > 0) { sl@0: Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]); sl@0: const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset); sl@0: sl@0: if (! glyphIterator->next()) { sl@0: return FALSE; sl@0: } sl@0: sl@0: if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) { sl@0: return FALSE; sl@0: } sl@0: sl@0: glyphCount -= 1; sl@0: glyph += direction; sl@0: } sl@0: sl@0: return TRUE; sl@0: } sl@0: sl@0: le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: switch(SWAPW(subtableFormat)) sl@0: { sl@0: case 0: sl@0: return 0; sl@0: sl@0: case 1: sl@0: { sl@0: const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this; sl@0: sl@0: return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); sl@0: } sl@0: sl@0: case 2: sl@0: { sl@0: const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this; sl@0: sl@0: return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); sl@0: } sl@0: sl@0: case 3: sl@0: { sl@0: const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this; sl@0: sl@0: return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); sl@0: } sl@0: sl@0: default: sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: LEGlyphID glyph = glyphIterator->getCurrGlyphID(); sl@0: le_int32 coverageIndex = getGlyphCoverage(glyph); sl@0: sl@0: if (coverageIndex >= 0) { sl@0: le_uint16 srSetCount = SWAPW(subRuleSetCount); sl@0: sl@0: if (coverageIndex < srSetCount) { sl@0: Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]); sl@0: const SubRuleSetTable *subRuleSetTable = sl@0: (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset); sl@0: le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount); sl@0: le_int32 position = glyphIterator->getCurrStreamPosition(); sl@0: sl@0: for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) { sl@0: Offset subRuleTableOffset = sl@0: SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]); sl@0: const SubRuleTable *subRuleTable = sl@0: (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset); sl@0: le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1; sl@0: le_uint16 substCount = SWAPW(subRuleTable->substCount); sl@0: sl@0: if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) { sl@0: const SubstitutionLookupRecord *substLookupRecordArray = sl@0: (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount]; sl@0: sl@0: applySubstitutionLookups(lookupProcessor, substLookupRecordArray, sl@0: substCount, glyphIterator, fontInstance, position, success); sl@0: sl@0: return matchCount + 1; sl@0: } sl@0: sl@0: glyphIterator->setCurrStreamPosition(position); sl@0: } sl@0: } sl@0: sl@0: // XXX If we get here, the table is mal-formed... sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: LEGlyphID glyph = glyphIterator->getCurrGlyphID(); sl@0: le_int32 coverageIndex = getGlyphCoverage(glyph); sl@0: sl@0: if (coverageIndex >= 0) { sl@0: const ClassDefinitionTable *classDefinitionTable = sl@0: (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset)); sl@0: le_uint16 scSetCount = SWAPW(subClassSetCount); sl@0: le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID()); sl@0: sl@0: if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) { sl@0: Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]); sl@0: const SubClassSetTable *subClassSetTable = sl@0: (const SubClassSetTable *) ((char *) this + subClassSetTableOffset); sl@0: le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount); sl@0: le_int32 position = glyphIterator->getCurrStreamPosition(); sl@0: sl@0: for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) { sl@0: Offset subClassRuleTableOffset = sl@0: SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]); sl@0: const SubClassRuleTable *subClassRuleTable = sl@0: (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset); sl@0: le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1; sl@0: le_uint16 substCount = SWAPW(subClassRuleTable->substCount); sl@0: sl@0: if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) { sl@0: const SubstitutionLookupRecord *substLookupRecordArray = sl@0: (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount]; sl@0: sl@0: applySubstitutionLookups(lookupProcessor, substLookupRecordArray, sl@0: substCount, glyphIterator, fontInstance, position, success); sl@0: sl@0: return matchCount + 1; sl@0: } sl@0: sl@0: glyphIterator->setCurrStreamPosition(position); sl@0: } sl@0: } sl@0: sl@0: // XXX If we get here, the table is mal-formed... sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: le_uint16 gCount = SWAPW(glyphCount); sl@0: le_uint16 subCount = SWAPW(substCount); sl@0: le_int32 position = glyphIterator->getCurrStreamPosition(); sl@0: sl@0: // Back up the glyph iterator so that we sl@0: // can call next() before the check, which sl@0: // will leave it pointing at the last glyph sl@0: // that matched when we're done. sl@0: glyphIterator->prev(); sl@0: sl@0: if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) { sl@0: const SubstitutionLookupRecord *substLookupRecordArray = sl@0: (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount]; sl@0: sl@0: ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, sl@0: subCount, glyphIterator, fontInstance, position, success); sl@0: sl@0: return gCount + 1; sl@0: } sl@0: sl@0: glyphIterator->setCurrStreamPosition(position); sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: switch(SWAPW(subtableFormat)) sl@0: { sl@0: case 0: sl@0: return 0; sl@0: sl@0: case 1: sl@0: { sl@0: const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this; sl@0: sl@0: return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); sl@0: } sl@0: sl@0: case 2: sl@0: { sl@0: const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this; sl@0: sl@0: return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); sl@0: } sl@0: sl@0: case 3: sl@0: { sl@0: const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this; sl@0: sl@0: return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); sl@0: } sl@0: sl@0: default: sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: static const LETag emptyTag = 0; sl@0: sl@0: le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: LEGlyphID glyph = glyphIterator->getCurrGlyphID(); sl@0: le_int32 coverageIndex = getGlyphCoverage(glyph); sl@0: sl@0: if (coverageIndex >= 0) { sl@0: le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); sl@0: sl@0: if (coverageIndex < srSetCount) { sl@0: Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]); sl@0: const ChainSubRuleSetTable *chainSubRuleSetTable = sl@0: (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset); sl@0: le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount); sl@0: le_int32 position = glyphIterator->getCurrStreamPosition(); sl@0: GlyphIterator tempIterator(*glyphIterator, emptyTag); sl@0: sl@0: for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) { sl@0: Offset chainSubRuleTableOffset = sl@0: SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]); sl@0: const ChainSubRuleTable *chainSubRuleTable = sl@0: (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset); sl@0: le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount); sl@0: le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1; sl@0: const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1]; sl@0: le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]); sl@0: const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1]; sl@0: le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]); sl@0: sl@0: tempIterator.setCurrStreamPosition(position); sl@0: sl@0: if (! tempIterator.prev(backtrackGlyphCount)) { sl@0: continue; sl@0: } sl@0: sl@0: tempIterator.prev(); sl@0: if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) { sl@0: continue; sl@0: } sl@0: sl@0: tempIterator.setCurrStreamPosition(position); sl@0: tempIterator.next(inputGlyphCount); sl@0: if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) { sl@0: continue; sl@0: } sl@0: sl@0: if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) { sl@0: const SubstitutionLookupRecord *substLookupRecordArray = sl@0: (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1]; sl@0: sl@0: applySubstitutionLookups(lookupProcessor, substLookupRecordArray, sl@0: substCount, glyphIterator, fontInstance, position, success); sl@0: sl@0: return inputGlyphCount + 1; sl@0: } sl@0: sl@0: glyphIterator->setCurrStreamPosition(position); sl@0: } sl@0: } sl@0: sl@0: // XXX If we get here, the table is mal-formed... sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: LEGlyphID glyph = glyphIterator->getCurrGlyphID(); sl@0: le_int32 coverageIndex = getGlyphCoverage(glyph); sl@0: sl@0: if (coverageIndex >= 0) { sl@0: const ClassDefinitionTable *backtrackClassDefinitionTable = sl@0: (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset)); sl@0: const ClassDefinitionTable *inputClassDefinitionTable = sl@0: (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset)); sl@0: const ClassDefinitionTable *lookaheadClassDefinitionTable = sl@0: (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset)); sl@0: le_uint16 scSetCount = SWAPW(chainSubClassSetCount); sl@0: le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID()); sl@0: sl@0: if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) { sl@0: Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]); sl@0: const ChainSubClassSetTable *chainSubClassSetTable = sl@0: (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset); sl@0: le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount); sl@0: le_int32 position = glyphIterator->getCurrStreamPosition(); sl@0: GlyphIterator tempIterator(*glyphIterator, emptyTag); sl@0: sl@0: for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) { sl@0: Offset chainSubClassRuleTableOffset = sl@0: SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]); sl@0: const ChainSubClassRuleTable *chainSubClassRuleTable = sl@0: (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset); sl@0: le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount); sl@0: le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1; sl@0: const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1]; sl@0: le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]); sl@0: const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1]; sl@0: le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]); sl@0: sl@0: sl@0: tempIterator.setCurrStreamPosition(position); sl@0: sl@0: if (! tempIterator.prev(backtrackGlyphCount)) { sl@0: continue; sl@0: } sl@0: sl@0: tempIterator.prev(); sl@0: if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount, sl@0: &tempIterator, backtrackClassDefinitionTable, TRUE)) { sl@0: continue; sl@0: } sl@0: sl@0: tempIterator.setCurrStreamPosition(position); sl@0: tempIterator.next(inputGlyphCount); sl@0: if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) { sl@0: continue; sl@0: } sl@0: sl@0: if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) { sl@0: const SubstitutionLookupRecord *substLookupRecordArray = sl@0: (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1]; sl@0: sl@0: applySubstitutionLookups(lookupProcessor, substLookupRecordArray, sl@0: substCount, glyphIterator, fontInstance, position, success); sl@0: sl@0: return inputGlyphCount + 1; sl@0: } sl@0: sl@0: glyphIterator->setCurrStreamPosition(position); sl@0: } sl@0: } sl@0: sl@0: // XXX If we get here, the table is mal-formed... sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, sl@0: const LEFontInstance *fontInstance, LEErrorCode& success) const sl@0: { sl@0: if (LE_FAILURE(success)) { sl@0: return 0; sl@0: } sl@0: sl@0: le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount); sl@0: le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]); sl@0: const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1]; sl@0: const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]); sl@0: const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1]; sl@0: le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]); sl@0: le_int32 position = glyphIterator->getCurrStreamPosition(); sl@0: GlyphIterator tempIterator(*glyphIterator, emptyTag); sl@0: sl@0: if (! tempIterator.prev(backtrkGlyphCount)) { sl@0: return 0; sl@0: } sl@0: sl@0: tempIterator.prev(); sl@0: if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray, sl@0: backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) { sl@0: return 0; sl@0: } sl@0: sl@0: tempIterator.setCurrStreamPosition(position); sl@0: tempIterator.next(inputGlyphCount - 1); sl@0: if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray, sl@0: lookaheadGlyphCount, &tempIterator, (const char *) this)) { sl@0: return 0; sl@0: } sl@0: sl@0: // Back up the glyph iterator so that we sl@0: // can call next() before the check, which sl@0: // will leave it pointing at the last glyph sl@0: // that matched when we're done. sl@0: glyphIterator->prev(); sl@0: sl@0: if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray, sl@0: inputGlyphCount, glyphIterator, (const char *) this)) { sl@0: const SubstitutionLookupRecord *substLookupRecordArray = sl@0: (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1]; sl@0: sl@0: ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, sl@0: substCount, glyphIterator, fontInstance, position, success); sl@0: sl@0: return inputGlyphCount; sl@0: } sl@0: sl@0: glyphIterator->setCurrStreamPosition(position); sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: U_NAMESPACE_END