~ubuntu-branches/ubuntu/precise/icu/precise

« back to all changes in this revision

Viewing changes to source/layout/ContextualSubstSubtables.cpp

  • Committer: Package Import Robot
  • Author(s): Jay Berkenbilt
  • Date: 2009-09-04 11:56:06 UTC
  • mfrom: (10.1.6 sid)
  • Revision ID: package-import@ubuntu.com-20090904115606-sqxxuizelam5tozb
Tags: 4.2.1-3
Change install-doc target to not fail if there are subdirectories of
doc/html.  This is necessary to handle the doc/html/search directory
created by doxygen 3.6.1.  (Closes: #544799)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (C) Copyright IBM Corp. 1998-2008 - 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(glyph);
 
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(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, 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(glyph);
 
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(glyph);
 
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
                le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
 
470
                const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
 
471
                le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
 
472
                const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
 
473
                le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
 
474
                
 
475
 
 
476
                tempIterator.setCurrStreamPosition(position);
 
477
 
 
478
                if (! tempIterator.prev(backtrackGlyphCount)) {
 
479
                    continue;
 
480
                }
 
481
 
 
482
                tempIterator.prev();
 
483
                if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
 
484
                    &tempIterator, backtrackClassDefinitionTable, TRUE)) {
 
485
                    continue;
 
486
                }
 
487
 
 
488
                tempIterator.setCurrStreamPosition(position);
 
489
                tempIterator.next(inputGlyphCount);
 
490
                if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
 
491
                    continue;
 
492
                }
 
493
 
 
494
                if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
 
495
                    const SubstitutionLookupRecord *substLookupRecordArray = 
 
496
                        (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
 
497
 
 
498
                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
 
499
 
 
500
                    return inputGlyphCount + 1;
 
501
                }
 
502
 
 
503
                glyphIterator->setCurrStreamPosition(position);
 
504
            }
 
505
        }
 
506
 
 
507
        // XXX If we get here, the table is mal-formed...
 
508
    }
 
509
    
 
510
    return 0;
 
511
}
 
512
 
 
513
le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 
 
514
                                                                 GlyphIterator *glyphIterator,
 
515
                                                                 const LEFontInstance *fontInstance,
 
516
                                                                 LEErrorCode & success) const
 
517
{
 
518
    if (LE_FAILURE(success)) { 
 
519
        return 0;
 
520
    }
 
521
 
 
522
    le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
 
523
    le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
 
524
    const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
 
525
    const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
 
526
    const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
 
527
    le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
 
528
    le_int32 position = glyphIterator->getCurrStreamPosition();
 
529
    GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
 
530
 
 
531
    if (! tempIterator.prev(backtrkGlyphCount)) {
 
532
        return 0;
 
533
    }
 
534
 
 
535
    tempIterator.prev();
 
536
    if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
 
537
        backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
 
538
        return 0;
 
539
    }
 
540
 
 
541
    tempIterator.setCurrStreamPosition(position);
 
542
    tempIterator.next(inputGlyphCount - 1);
 
543
    if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
 
544
        lookaheadGlyphCount, &tempIterator, (const char *) this)) {
 
545
        return 0;
 
546
    }
 
547
 
 
548
    // Back up the glyph iterator so that we
 
549
    // can call next() before the check, which
 
550
    // will leave it pointing at the last glyph
 
551
    // that matched when we're done.
 
552
    glyphIterator->prev();
 
553
 
 
554
    if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
 
555
        inputGlyphCount, glyphIterator, (const char *) this)) {
 
556
        const SubstitutionLookupRecord *substLookupRecordArray = 
 
557
            (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
 
558
 
 
559
        ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
 
560
 
 
561
        return inputGlyphCount;
 
562
    }
 
563
 
 
564
    glyphIterator->setCurrStreamPosition(position);
 
565
 
 
566
    return 0;
 
567
}
 
568
 
 
569
U_NAMESPACE_END