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