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