3  * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved 
   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" 
  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. 
  25 void ContextualSubstitutionBase::applySubstitutionLookups( 
  26         const LookupProcessor 
*lookupProcessor
, 
  27         const SubstitutionLookupRecord 
*substLookupRecordArray
, 
  29         GlyphIterator 
*glyphIterator
, 
  30         const LEFontInstance 
*fontInstance
, 
  33     GlyphIterator 
tempIterator(*glyphIterator
); 
  35     for (le_int16 subst 
= 0; subst 
< substCount
; subst 
+= 1) { 
  36         le_uint16 sequenceIndex 
= SWAPW(substLookupRecordArray
[subst
].sequenceIndex
); 
  37         le_uint16 lookupListIndex 
= SWAPW(substLookupRecordArray
[subst
].lookupListIndex
); 
  39         tempIterator
.setCurrStreamPosition(position
); 
  40         tempIterator
.next(sequenceIndex
); 
  42         lookupProcessor
->applySingleLookup(lookupListIndex
, &tempIterator
, fontInstance
); 
  46 le_bool 
ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID 
*glyphArray
, le_uint16 glyphCount
, 
  47                                                GlyphIterator 
*glyphIterator
, le_bool backtrack
) 
  49     le_int32 direction 
= 1; 
  53         match 
= glyphCount 
-1; 
  57     while (glyphCount 
> 0) { 
  58         if (! glyphIterator
->next()) { 
  62         TTGlyphID glyph 
= (TTGlyphID
) glyphIterator
->getCurrGlyphID(); 
  64         if (glyph 
!= SWAPW(glyphArray
[match
])) { 
  75 le_bool 
ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 
*classArray
, le_uint16 glyphCount
, 
  76                                                GlyphIterator 
*glyphIterator
, 
  77                                                const ClassDefinitionTable 
*classDefinitionTable
, 
  80     le_int32 direction 
= 1; 
  84         match 
= glyphCount 
- 1; 
  88     while (glyphCount 
> 0) { 
  89         if (! glyphIterator
->next()) { 
  93         LEGlyphID glyph 
= glyphIterator
->getCurrGlyphID(); 
  94         le_int32 glyphClass 
= classDefinitionTable
->getGlyphClass(glyph
); 
  95         le_int32 matchClass 
= SWAPW(classArray
[match
]); 
  97         if (glyphClass 
!= matchClass
) { 
  98             // Some fonts, e.g. Traditional Arabic, have classes 
  99             // in the class array which aren't in the class definition 
 100             // table. If we're looking for such a class, pretend that 
 102             if (classDefinitionTable
->hasGlyphClass(matchClass
)) { 
 114 le_bool 
ContextualSubstitutionBase::matchGlyphCoverages(const Offset 
*coverageTableOffsetArray
, le_uint16 glyphCount
, 
 115                                                      GlyphIterator 
*glyphIterator
, const char *offsetBase
, le_bool backtrack
) 
 117     le_int32 direction 
= 1; 
 121         glyph 
= glyphCount 
- 1; 
 125     while (glyphCount 
> 0) { 
 126         Offset coverageTableOffset 
= SWAPW(coverageTableOffsetArray
[glyph
]); 
 127         const CoverageTable 
*coverageTable 
= (const CoverageTable 
*) (offsetBase 
+ coverageTableOffset
); 
 129         if (! glyphIterator
->next()) { 
 133         if (coverageTable
->getGlyphCoverage((LEGlyphID
) glyphIterator
->getCurrGlyphID()) < 0) { 
 144 le_uint32 
ContextualSubstitutionSubtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 145                                                const LEFontInstance 
*fontInstance
) const 
 147     switch(SWAPW(subtableFormat
)) 
 154         const ContextualSubstitutionFormat1Subtable 
*subtable 
= (const ContextualSubstitutionFormat1Subtable 
*) this; 
 156         return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
); 
 161         const ContextualSubstitutionFormat2Subtable 
*subtable 
= (const ContextualSubstitutionFormat2Subtable 
*) this; 
 163         return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
); 
 168         const ContextualSubstitutionFormat3Subtable 
*subtable 
= (const ContextualSubstitutionFormat3Subtable 
*) this; 
 170         return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
); 
 178 le_uint32 
ContextualSubstitutionFormat1Subtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 179                                                       const LEFontInstance 
*fontInstance
) const 
 181     LEGlyphID glyph 
= glyphIterator
->getCurrGlyphID(); 
 182     le_int32 coverageIndex 
= getGlyphCoverage(glyph
); 
 184     if (coverageIndex 
>= 0) { 
 185         le_uint16 srSetCount 
= SWAPW(subRuleSetCount
); 
 187         if (coverageIndex 
< srSetCount
) { 
 188             Offset subRuleSetTableOffset 
= SWAPW(subRuleSetTableOffsetArray
[coverageIndex
]); 
 189             const SubRuleSetTable 
*subRuleSetTable 
= 
 190                 (const SubRuleSetTable 
*) ((char *) this + subRuleSetTableOffset
); 
 191             le_uint16 subRuleCount 
= SWAPW(subRuleSetTable
->subRuleCount
); 
 192             le_int32 position 
= glyphIterator
->getCurrStreamPosition(); 
 194             for (le_uint16 subRule 
= 0; subRule 
< subRuleCount
; subRule 
+= 1) { 
 195                 Offset subRuleTableOffset 
= 
 196                     SWAPW(subRuleSetTable
->subRuleTableOffsetArray
[subRule
]); 
 197                 const SubRuleTable 
*subRuleTable 
= 
 198                     (const SubRuleTable 
*) ((char *) subRuleSetTable 
+ subRuleTableOffset
); 
 199                 le_uint16 matchCount 
= SWAPW(subRuleTable
->glyphCount
) - 1; 
 200                 le_uint16 substCount 
= SWAPW(subRuleTable
->substCount
); 
 202                 if (matchGlyphIDs(subRuleTable
->inputGlyphArray
, matchCount
, glyphIterator
)) { 
 203                     const SubstitutionLookupRecord 
*substLookupRecordArray 
=  
 204                         (const SubstitutionLookupRecord 
*) &subRuleTable
->inputGlyphArray
[matchCount
]; 
 206                     applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
); 
 208                     return matchCount 
+ 1; 
 211                 glyphIterator
->setCurrStreamPosition(position
); 
 215         // XXX If we get here, the table is mal-formed... 
 221 le_uint32 
ContextualSubstitutionFormat2Subtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 222                                                       const LEFontInstance 
*fontInstance
) const 
 224     LEGlyphID glyph 
= glyphIterator
->getCurrGlyphID(); 
 225     le_int32 coverageIndex 
= getGlyphCoverage(glyph
); 
 227     if (coverageIndex 
>= 0) { 
 228         const ClassDefinitionTable 
*classDefinitionTable 
= 
 229             (const ClassDefinitionTable 
*) ((char *) this + SWAPW(classDefTableOffset
)); 
 230         le_uint16 scSetCount 
= SWAPW(subClassSetCount
); 
 231         le_int32 setClass 
= classDefinitionTable
->getGlyphClass(glyphIterator
->getCurrGlyphID()); 
 233         if (setClass 
< scSetCount 
&& subClassSetTableOffsetArray
[setClass
] != 0) { 
 234             Offset subClassSetTableOffset 
= SWAPW(subClassSetTableOffsetArray
[setClass
]); 
 235             const SubClassSetTable 
*subClassSetTable 
= 
 236                 (const SubClassSetTable 
*) ((char *) this + subClassSetTableOffset
); 
 237             le_uint16 subClassRuleCount 
= SWAPW(subClassSetTable
->subClassRuleCount
); 
 238             le_int32 position 
= glyphIterator
->getCurrStreamPosition(); 
 240             for (le_uint16 scRule 
= 0; scRule 
< subClassRuleCount
; scRule 
+= 1) { 
 241                 Offset subClassRuleTableOffset 
= 
 242                     SWAPW(subClassSetTable
->subClassRuleTableOffsetArray
[scRule
]); 
 243                 const SubClassRuleTable 
*subClassRuleTable 
= 
 244                     (const SubClassRuleTable 
*) ((char *) subClassSetTable 
+ subClassRuleTableOffset
); 
 245                 le_uint16 matchCount 
= SWAPW(subClassRuleTable
->glyphCount
) - 1; 
 246                 le_uint16 substCount 
= SWAPW(subClassRuleTable
->substCount
); 
 248                 if (matchGlyphClasses(subClassRuleTable
->classArray
, matchCount
, glyphIterator
, classDefinitionTable
)) { 
 249                     const SubstitutionLookupRecord 
*substLookupRecordArray 
=  
 250                         (const SubstitutionLookupRecord 
*) &subClassRuleTable
->classArray
[matchCount
]; 
 252                     applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
); 
 254                     return matchCount 
+ 1; 
 257                 glyphIterator
->setCurrStreamPosition(position
); 
 261         // XXX If we get here, the table is mal-formed... 
 267 le_uint32 
ContextualSubstitutionFormat3Subtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 268                                                       const LEFontInstance 
*fontInstance
)const  
 270     le_uint16 gCount 
= SWAPW(glyphCount
); 
 271     le_uint16 subCount 
= SWAPW(substCount
); 
 272     le_int32 position 
= glyphIterator
->getCurrStreamPosition(); 
 274     // Back up the glyph iterator so that we 
 275     // can call next() before the check, which 
 276     // will leave it pointing at the last glyph 
 277     // that matched when we're done. 
 278     glyphIterator
->prev(); 
 280     if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray
, gCount
, glyphIterator
, (const char *) this)) { 
 281         const SubstitutionLookupRecord 
*substLookupRecordArray 
=  
 282             (const SubstitutionLookupRecord 
*) &coverageTableOffsetArray
[gCount
]; 
 284         ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, subCount
, glyphIterator
, fontInstance
, position
); 
 289     glyphIterator
->setCurrStreamPosition(position
); 
 294 le_uint32 
ChainingContextualSubstitutionSubtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 295                                                        const LEFontInstance 
*fontInstance
) const 
 297     switch(SWAPW(subtableFormat
)) 
 304         const ChainingContextualSubstitutionFormat1Subtable 
*subtable 
= (const ChainingContextualSubstitutionFormat1Subtable 
*) this; 
 306         return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
); 
 311         const ChainingContextualSubstitutionFormat2Subtable 
*subtable 
= (const ChainingContextualSubstitutionFormat2Subtable 
*) this; 
 313         return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
); 
 318         const ChainingContextualSubstitutionFormat3Subtable 
*subtable 
= (const ChainingContextualSubstitutionFormat3Subtable 
*) this; 
 320         return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
); 
 328 static const LETag emptyTag 
= 0; 
 330 le_uint32 
ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 331                                                               const LEFontInstance 
*fontInstance
) const 
 333     LEGlyphID glyph 
= glyphIterator
->getCurrGlyphID(); 
 334     le_int32 coverageIndex 
= getGlyphCoverage(glyph
); 
 336     if (coverageIndex 
>= 0) { 
 337         le_uint16 srSetCount 
= SWAPW(chainSubRuleSetCount
); 
 339         if (coverageIndex 
< srSetCount
) { 
 340             Offset chainSubRuleSetTableOffset 
= SWAPW(chainSubRuleSetTableOffsetArray
[coverageIndex
]); 
 341             const ChainSubRuleSetTable 
*chainSubRuleSetTable 
= 
 342                 (const ChainSubRuleSetTable 
*) ((char *) this + chainSubRuleSetTableOffset
); 
 343             le_uint16 chainSubRuleCount 
= SWAPW(chainSubRuleSetTable
->chainSubRuleCount
); 
 344             le_int32 position 
= glyphIterator
->getCurrStreamPosition(); 
 345             GlyphIterator 
tempIterator(*glyphIterator
, emptyTag
); 
 347             for (le_uint16 subRule 
= 0; subRule 
< chainSubRuleCount
; subRule 
+= 1) { 
 348                 Offset chainSubRuleTableOffset 
= 
 349                     SWAPW(chainSubRuleSetTable
->chainSubRuleTableOffsetArray
[subRule
]); 
 350                 const ChainSubRuleTable 
*chainSubRuleTable 
= 
 351                     (const ChainSubRuleTable 
*) ((char *) chainSubRuleSetTable 
+ chainSubRuleTableOffset
); 
 352                 le_uint16 backtrackGlyphCount 
= SWAPW(chainSubRuleTable
->backtrackGlyphCount
); 
 353                 le_uint16 inputGlyphCount 
= (le_uint16
) SWAPW(chainSubRuleTable
->backtrackGlyphArray
[backtrackGlyphCount
]) - 1; 
 354                 const TTGlyphID 
*inputGlyphArray 
= &chainSubRuleTable
->backtrackGlyphArray
[backtrackGlyphCount 
+ 1]; 
 355                 le_uint16 lookaheadGlyphCount 
= (le_uint16
) SWAPW(inputGlyphArray
[inputGlyphCount
]); 
 356                 const TTGlyphID 
*lookaheadGlyphArray 
= &inputGlyphArray
[inputGlyphCount 
+ 1]; 
 357                 le_uint16 substCount 
= (le_uint16
) SWAPW(lookaheadGlyphArray
[lookaheadGlyphCount
]); 
 359                 tempIterator
.setCurrStreamPosition(position
); 
 361                 if (! tempIterator
.prev(backtrackGlyphCount
)) { 
 366                 if (! matchGlyphIDs(chainSubRuleTable
->backtrackGlyphArray
, backtrackGlyphCount
, &tempIterator
, TRUE
)) { 
 370                 tempIterator
.setCurrStreamPosition(position
); 
 371                 tempIterator
.next(inputGlyphCount
); 
 372                 if (!matchGlyphIDs(lookaheadGlyphArray
, lookaheadGlyphCount
, &tempIterator
)) { 
 376                 if (matchGlyphIDs(inputGlyphArray
, inputGlyphCount
, glyphIterator
)) { 
 377                     const SubstitutionLookupRecord 
*substLookupRecordArray 
=  
 378                         (const SubstitutionLookupRecord 
*) &lookaheadGlyphArray
[lookaheadGlyphCount 
+ 1]; 
 380                     applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
); 
 382                     return inputGlyphCount 
+ 1; 
 385                 glyphIterator
->setCurrStreamPosition(position
); 
 389         // XXX If we get here, the table is mal-formed... 
 395 le_uint32 
ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 396                                                               const LEFontInstance 
*fontInstance
) const 
 398     LEGlyphID glyph 
= glyphIterator
->getCurrGlyphID(); 
 399     le_int32 coverageIndex 
= getGlyphCoverage(glyph
); 
 401     if (coverageIndex 
>= 0) { 
 402         const ClassDefinitionTable 
*backtrackClassDefinitionTable 
= 
 403             (const ClassDefinitionTable 
*) ((char *) this + SWAPW(backtrackClassDefTableOffset
)); 
 404         const ClassDefinitionTable 
*inputClassDefinitionTable 
= 
 405             (const ClassDefinitionTable 
*) ((char *) this + SWAPW(inputClassDefTableOffset
)); 
 406         const ClassDefinitionTable 
*lookaheadClassDefinitionTable 
= 
 407             (const ClassDefinitionTable 
*) ((char *) this + SWAPW(lookaheadClassDefTableOffset
)); 
 408         le_uint16 scSetCount 
= SWAPW(chainSubClassSetCount
); 
 409         le_int32 setClass 
= inputClassDefinitionTable
->getGlyphClass(glyphIterator
->getCurrGlyphID()); 
 411         if (setClass 
< scSetCount 
&& chainSubClassSetTableOffsetArray
[setClass
] != 0) { 
 412             Offset chainSubClassSetTableOffset 
= SWAPW(chainSubClassSetTableOffsetArray
[setClass
]); 
 413             const ChainSubClassSetTable 
*chainSubClassSetTable 
= 
 414                 (const ChainSubClassSetTable 
*) ((char *) this + chainSubClassSetTableOffset
); 
 415             le_uint16 chainSubClassRuleCount 
= SWAPW(chainSubClassSetTable
->chainSubClassRuleCount
); 
 416             le_int32 position 
= glyphIterator
->getCurrStreamPosition(); 
 417             GlyphIterator 
tempIterator(*glyphIterator
, emptyTag
); 
 419             for (le_uint16 scRule 
= 0; scRule 
< chainSubClassRuleCount
; scRule 
+= 1) { 
 420                 Offset chainSubClassRuleTableOffset 
= 
 421                     SWAPW(chainSubClassSetTable
->chainSubClassRuleTableOffsetArray
[scRule
]); 
 422                 const ChainSubClassRuleTable 
*chainSubClassRuleTable 
= 
 423                     (const ChainSubClassRuleTable 
*) ((char *) chainSubClassSetTable 
+ chainSubClassRuleTableOffset
); 
 424                 le_uint16 backtrackGlyphCount 
= SWAPW(chainSubClassRuleTable
->backtrackGlyphCount
); 
 425                 le_uint16 inputGlyphCount 
= SWAPW(chainSubClassRuleTable
->backtrackClassArray
[backtrackGlyphCount
]) - 1; 
 426                 const le_uint16 
*inputClassArray 
= &chainSubClassRuleTable
->backtrackClassArray
[backtrackGlyphCount 
+ 1]; 
 427                 le_uint16 lookaheadGlyphCount 
= SWAPW(inputClassArray
[inputGlyphCount
]); 
 428                 const le_uint16 
*lookaheadClassArray 
= &inputClassArray
[inputGlyphCount 
+ 1]; 
 429                 le_uint16 substCount 
= SWAPW(lookaheadClassArray
[lookaheadGlyphCount
]); 
 432                 tempIterator
.setCurrStreamPosition(position
); 
 434                 if (! tempIterator
.prev(backtrackGlyphCount
)) { 
 439                 if (! matchGlyphClasses(chainSubClassRuleTable
->backtrackClassArray
, backtrackGlyphCount
, 
 440                     &tempIterator
, backtrackClassDefinitionTable
, TRUE
)) { 
 444                 tempIterator
.setCurrStreamPosition(position
); 
 445                 tempIterator
.next(inputGlyphCount
); 
 446                 if (! matchGlyphClasses(lookaheadClassArray
, lookaheadGlyphCount
, &tempIterator
, lookaheadClassDefinitionTable
)) { 
 450                 if (matchGlyphClasses(inputClassArray
, inputGlyphCount
, glyphIterator
, inputClassDefinitionTable
)) { 
 451                     const SubstitutionLookupRecord 
*substLookupRecordArray 
=  
 452                         (const SubstitutionLookupRecord 
*) &lookaheadClassArray
[lookaheadGlyphCount 
+ 1]; 
 454                     applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
); 
 456                     return inputGlyphCount 
+ 1; 
 459                 glyphIterator
->setCurrStreamPosition(position
); 
 463         // XXX If we get here, the table is mal-formed... 
 469 le_uint32 
ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor 
*lookupProcessor
, GlyphIterator 
*glyphIterator
, 
 470                                                               const LEFontInstance 
*fontInstance
) const 
 472     le_uint16 backtrkGlyphCount 
= SWAPW(backtrackGlyphCount
); 
 473     le_uint16 inputGlyphCount 
= (le_uint16
) SWAPW(backtrackCoverageTableOffsetArray
[backtrkGlyphCount
]); 
 474     const Offset 
*inputCoverageTableOffsetArray 
= &backtrackCoverageTableOffsetArray
[backtrkGlyphCount 
+ 1]; 
 475     const le_uint16 lookaheadGlyphCount 
= (le_uint16
) SWAPW(inputCoverageTableOffsetArray
[inputGlyphCount
]); 
 476     const Offset 
*lookaheadCoverageTableOffsetArray 
= &inputCoverageTableOffsetArray
[inputGlyphCount 
+ 1]; 
 477     le_uint16 substCount 
= (le_uint16
) SWAPW(lookaheadCoverageTableOffsetArray
[lookaheadGlyphCount
]); 
 478     le_int32 position 
= glyphIterator
->getCurrStreamPosition(); 
 479     GlyphIterator 
tempIterator(*glyphIterator
, emptyTag
); 
 481     if (! tempIterator
.prev(backtrkGlyphCount
)) { 
 486     if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray
, 
 487         backtrkGlyphCount
, &tempIterator
, (const char *) this, TRUE
)) { 
 491     tempIterator
.setCurrStreamPosition(position
); 
 492     tempIterator
.next(inputGlyphCount 
- 1); 
 493     if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray
, 
 494         lookaheadGlyphCount
, &tempIterator
, (const char *) this)) { 
 498     // Back up the glyph iterator so that we 
 499     // can call next() before the check, which 
 500     // will leave it pointing at the last glyph 
 501     // that matched when we're done. 
 502     glyphIterator
->prev(); 
 504     if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray
, 
 505         inputGlyphCount
, glyphIterator
, (const char *) this)) { 
 506         const SubstitutionLookupRecord 
*substLookupRecordArray 
=  
 507             (const SubstitutionLookupRecord 
*) &lookaheadCoverageTableOffsetArray
[lookaheadGlyphCount 
+ 1]; 
 509         ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
); 
 511         return inputGlyphCount
; 
 514     glyphIterator
->setCurrStreamPosition(position
);