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
16U_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*/
24void 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
50le_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
79le_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
118le_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
148le_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
185le_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
234le_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
286le_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
319le_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...
360static const FeatureMask emptyFeatureList = 0x00000000UL;
361
362le_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
433le_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
513le_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
569U_NAMESPACE_END
570