2 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
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"
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.
24 void ContextualSubstitutionBase::applySubstitutionLookups(
25 const LookupProcessor
*lookupProcessor
,
26 const SubstitutionLookupRecord
*substLookupRecordArray
,
28 GlyphIterator
*glyphIterator
,
29 const LEFontInstance
*fontInstance
,
32 GlyphIterator
tempIterator(*glyphIterator
);
34 for (le_int16 subst
= 0; subst
< substCount
; subst
+= 1) {
35 le_uint16 sequenceIndex
= SWAPW(substLookupRecordArray
[subst
].sequenceIndex
);
36 le_uint16 lookupListIndex
= SWAPW(substLookupRecordArray
[subst
].lookupListIndex
);
38 tempIterator
.setCurrStreamPosition(position
);
39 tempIterator
.next(sequenceIndex
);
41 lookupProcessor
->applySingleLookup(lookupListIndex
, &tempIterator
, fontInstance
);
45 le_bool
ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID
*glyphArray
, le_uint16 glyphCount
,
46 GlyphIterator
*glyphIterator
, le_bool backtrack
)
48 le_int32 direction
= 1;
52 match
= glyphCount
-1;
56 while (glyphCount
> 0) {
57 if (! glyphIterator
->next()) {
61 TTGlyphID glyph
= (TTGlyphID
) glyphIterator
->getCurrGlyphID();
63 if (glyph
!= SWAPW(glyphArray
[match
])) {
74 le_bool
ContextualSubstitutionBase::matchGlyphClasses(const le_uint16
*classArray
, le_uint16 glyphCount
,
75 GlyphIterator
*glyphIterator
,
76 const ClassDefinitionTable
*classDefinitionTable
,
79 le_int32 direction
= 1;
83 match
= glyphCount
- 1;
87 while (glyphCount
> 0) {
88 if (! glyphIterator
->next()) {
92 LEGlyphID glyph
= glyphIterator
->getCurrGlyphID();
93 le_int32 glyphClass
= classDefinitionTable
->getGlyphClass(glyph
);
94 le_int32 matchClass
= SWAPW(classArray
[match
]);
96 if (glyphClass
!= matchClass
) {
97 // Some fonts, e.g. Traditional Arabic, have classes
98 // in the class array which aren't in the class definition
99 // table. If we're looking for such a class, pretend that
101 if (classDefinitionTable
->hasGlyphClass(matchClass
)) {
113 le_bool
ContextualSubstitutionBase::matchGlyphCoverages(const Offset
*coverageTableOffsetArray
, le_uint16 glyphCount
,
114 GlyphIterator
*glyphIterator
, const char *offsetBase
, le_bool backtrack
)
116 le_int32 direction
= 1;
120 glyph
= glyphCount
- 1;
124 while (glyphCount
> 0) {
125 Offset coverageTableOffset
= SWAPW(coverageTableOffsetArray
[glyph
]);
126 const CoverageTable
*coverageTable
= (const CoverageTable
*) (offsetBase
+ coverageTableOffset
);
128 if (! glyphIterator
->next()) {
132 if (coverageTable
->getGlyphCoverage((LEGlyphID
) glyphIterator
->getCurrGlyphID()) < 0) {
143 le_uint32
ContextualSubstitutionSubtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
144 const LEFontInstance
*fontInstance
) const
146 switch(SWAPW(subtableFormat
))
153 const ContextualSubstitutionFormat1Subtable
*subtable
= (const ContextualSubstitutionFormat1Subtable
*) this;
155 return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
);
160 const ContextualSubstitutionFormat2Subtable
*subtable
= (const ContextualSubstitutionFormat2Subtable
*) this;
162 return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
);
167 const ContextualSubstitutionFormat3Subtable
*subtable
= (const ContextualSubstitutionFormat3Subtable
*) this;
169 return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
);
177 le_uint32
ContextualSubstitutionFormat1Subtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
178 const LEFontInstance
*fontInstance
) const
180 LEGlyphID glyph
= glyphIterator
->getCurrGlyphID();
181 le_int32 coverageIndex
= getGlyphCoverage(glyph
);
183 if (coverageIndex
>= 0) {
184 le_uint16 srSetCount
= SWAPW(subRuleSetCount
);
186 if (coverageIndex
< srSetCount
) {
187 Offset subRuleSetTableOffset
= SWAPW(subRuleSetTableOffsetArray
[coverageIndex
]);
188 const SubRuleSetTable
*subRuleSetTable
=
189 (const SubRuleSetTable
*) ((char *) this + subRuleSetTableOffset
);
190 le_uint16 subRuleCount
= SWAPW(subRuleSetTable
->subRuleCount
);
191 le_int32 position
= glyphIterator
->getCurrStreamPosition();
193 for (le_uint16 subRule
= 0; subRule
< subRuleCount
; subRule
+= 1) {
194 Offset subRuleTableOffset
=
195 SWAPW(subRuleSetTable
->subRuleTableOffsetArray
[subRule
]);
196 const SubRuleTable
*subRuleTable
=
197 (const SubRuleTable
*) ((char *) subRuleSetTable
+ subRuleTableOffset
);
198 le_uint16 matchCount
= SWAPW(subRuleTable
->glyphCount
) - 1;
199 le_uint16 substCount
= SWAPW(subRuleTable
->substCount
);
201 if (matchGlyphIDs(subRuleTable
->inputGlyphArray
, matchCount
, glyphIterator
)) {
202 const SubstitutionLookupRecord
*substLookupRecordArray
=
203 (const SubstitutionLookupRecord
*) &subRuleTable
->inputGlyphArray
[matchCount
];
205 applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
);
207 return matchCount
+ 1;
210 glyphIterator
->setCurrStreamPosition(position
);
214 // XXX If we get here, the table is mal-formed...
220 le_uint32
ContextualSubstitutionFormat2Subtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
221 const LEFontInstance
*fontInstance
) const
223 LEGlyphID glyph
= glyphIterator
->getCurrGlyphID();
224 le_int32 coverageIndex
= getGlyphCoverage(glyph
);
226 if (coverageIndex
>= 0) {
227 const ClassDefinitionTable
*classDefinitionTable
=
228 (const ClassDefinitionTable
*) ((char *) this + SWAPW(classDefTableOffset
));
229 le_uint16 scSetCount
= SWAPW(subClassSetCount
);
230 le_int32 setClass
= classDefinitionTable
->getGlyphClass(glyphIterator
->getCurrGlyphID());
232 if (setClass
< scSetCount
&& subClassSetTableOffsetArray
[setClass
] != 0) {
233 Offset subClassSetTableOffset
= SWAPW(subClassSetTableOffsetArray
[setClass
]);
234 const SubClassSetTable
*subClassSetTable
=
235 (const SubClassSetTable
*) ((char *) this + subClassSetTableOffset
);
236 le_uint16 subClassRuleCount
= SWAPW(subClassSetTable
->subClassRuleCount
);
237 le_int32 position
= glyphIterator
->getCurrStreamPosition();
239 for (le_uint16 scRule
= 0; scRule
< subClassRuleCount
; scRule
+= 1) {
240 Offset subClassRuleTableOffset
=
241 SWAPW(subClassSetTable
->subClassRuleTableOffsetArray
[scRule
]);
242 const SubClassRuleTable
*subClassRuleTable
=
243 (const SubClassRuleTable
*) ((char *) subClassSetTable
+ subClassRuleTableOffset
);
244 le_uint16 matchCount
= SWAPW(subClassRuleTable
->glyphCount
) - 1;
245 le_uint16 substCount
= SWAPW(subClassRuleTable
->substCount
);
247 if (matchGlyphClasses(subClassRuleTable
->classArray
, matchCount
, glyphIterator
, classDefinitionTable
)) {
248 const SubstitutionLookupRecord
*substLookupRecordArray
=
249 (const SubstitutionLookupRecord
*) &subClassRuleTable
->classArray
[matchCount
];
251 applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
);
253 return matchCount
+ 1;
256 glyphIterator
->setCurrStreamPosition(position
);
260 // XXX If we get here, the table is mal-formed...
266 le_uint32
ContextualSubstitutionFormat3Subtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
267 const LEFontInstance
*fontInstance
)const
269 le_uint16 gCount
= SWAPW(glyphCount
);
270 le_uint16 subCount
= SWAPW(substCount
);
271 le_int32 position
= glyphIterator
->getCurrStreamPosition();
273 // Back up the glyph iterator so that we
274 // can call next() before the check, which
275 // will leave it pointing at the last glyph
276 // that matched when we're done.
277 glyphIterator
->prev();
279 if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray
, gCount
, glyphIterator
, (const char *) this)) {
280 const SubstitutionLookupRecord
*substLookupRecordArray
=
281 (const SubstitutionLookupRecord
*) &coverageTableOffsetArray
[gCount
];
283 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, subCount
, glyphIterator
, fontInstance
, position
);
288 glyphIterator
->setCurrStreamPosition(position
);
293 le_uint32
ChainingContextualSubstitutionSubtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
294 const LEFontInstance
*fontInstance
) const
296 switch(SWAPW(subtableFormat
))
303 const ChainingContextualSubstitutionFormat1Subtable
*subtable
= (const ChainingContextualSubstitutionFormat1Subtable
*) this;
305 return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
);
310 const ChainingContextualSubstitutionFormat2Subtable
*subtable
= (const ChainingContextualSubstitutionFormat2Subtable
*) this;
312 return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
);
317 const ChainingContextualSubstitutionFormat3Subtable
*subtable
= (const ChainingContextualSubstitutionFormat3Subtable
*) this;
319 return subtable
->process(lookupProcessor
, glyphIterator
, fontInstance
);
327 // NOTE: This could be a #define, but that seems to confuse
328 // the Visual Studio .NET 2003 compiler on the calls to the
329 // GlyphIterator constructor. It somehow can't decide if
330 // emptyFeatureList matches an le_uint32 or an le_uint16...
331 static const FeatureMask emptyFeatureList
= 0x00000000UL
;
333 le_uint32
ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
334 const LEFontInstance
*fontInstance
) const
336 LEGlyphID glyph
= glyphIterator
->getCurrGlyphID();
337 le_int32 coverageIndex
= getGlyphCoverage(glyph
);
339 if (coverageIndex
>= 0) {
340 le_uint16 srSetCount
= SWAPW(chainSubRuleSetCount
);
342 if (coverageIndex
< srSetCount
) {
343 Offset chainSubRuleSetTableOffset
= SWAPW(chainSubRuleSetTableOffsetArray
[coverageIndex
]);
344 const ChainSubRuleSetTable
*chainSubRuleSetTable
=
345 (const ChainSubRuleSetTable
*) ((char *) this + chainSubRuleSetTableOffset
);
346 le_uint16 chainSubRuleCount
= SWAPW(chainSubRuleSetTable
->chainSubRuleCount
);
347 le_int32 position
= glyphIterator
->getCurrStreamPosition();
348 GlyphIterator
tempIterator(*glyphIterator
, emptyFeatureList
);
350 for (le_uint16 subRule
= 0; subRule
< chainSubRuleCount
; subRule
+= 1) {
351 Offset chainSubRuleTableOffset
=
352 SWAPW(chainSubRuleSetTable
->chainSubRuleTableOffsetArray
[subRule
]);
353 const ChainSubRuleTable
*chainSubRuleTable
=
354 (const ChainSubRuleTable
*) ((char *) chainSubRuleSetTable
+ chainSubRuleTableOffset
);
355 le_uint16 backtrackGlyphCount
= SWAPW(chainSubRuleTable
->backtrackGlyphCount
);
356 le_uint16 inputGlyphCount
= (le_uint16
) SWAPW(chainSubRuleTable
->backtrackGlyphArray
[backtrackGlyphCount
]) - 1;
357 const TTGlyphID
*inputGlyphArray
= &chainSubRuleTable
->backtrackGlyphArray
[backtrackGlyphCount
+ 1];
358 le_uint16 lookaheadGlyphCount
= (le_uint16
) SWAPW(inputGlyphArray
[inputGlyphCount
]);
359 const TTGlyphID
*lookaheadGlyphArray
= &inputGlyphArray
[inputGlyphCount
+ 1];
360 le_uint16 substCount
= (le_uint16
) SWAPW(lookaheadGlyphArray
[lookaheadGlyphCount
]);
362 tempIterator
.setCurrStreamPosition(position
);
364 if (! tempIterator
.prev(backtrackGlyphCount
)) {
369 if (! matchGlyphIDs(chainSubRuleTable
->backtrackGlyphArray
, backtrackGlyphCount
, &tempIterator
, TRUE
)) {
373 tempIterator
.setCurrStreamPosition(position
);
374 tempIterator
.next(inputGlyphCount
);
375 if (!matchGlyphIDs(lookaheadGlyphArray
, lookaheadGlyphCount
, &tempIterator
)) {
379 if (matchGlyphIDs(inputGlyphArray
, inputGlyphCount
, glyphIterator
)) {
380 const SubstitutionLookupRecord
*substLookupRecordArray
=
381 (const SubstitutionLookupRecord
*) &lookaheadGlyphArray
[lookaheadGlyphCount
+ 1];
383 applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
);
385 return inputGlyphCount
+ 1;
388 glyphIterator
->setCurrStreamPosition(position
);
392 // XXX If we get here, the table is mal-formed...
398 le_uint32
ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
399 const LEFontInstance
*fontInstance
) const
401 LEGlyphID glyph
= glyphIterator
->getCurrGlyphID();
402 le_int32 coverageIndex
= getGlyphCoverage(glyph
);
404 if (coverageIndex
>= 0) {
405 const ClassDefinitionTable
*backtrackClassDefinitionTable
=
406 (const ClassDefinitionTable
*) ((char *) this + SWAPW(backtrackClassDefTableOffset
));
407 const ClassDefinitionTable
*inputClassDefinitionTable
=
408 (const ClassDefinitionTable
*) ((char *) this + SWAPW(inputClassDefTableOffset
));
409 const ClassDefinitionTable
*lookaheadClassDefinitionTable
=
410 (const ClassDefinitionTable
*) ((char *) this + SWAPW(lookaheadClassDefTableOffset
));
411 le_uint16 scSetCount
= SWAPW(chainSubClassSetCount
);
412 le_int32 setClass
= inputClassDefinitionTable
->getGlyphClass(glyphIterator
->getCurrGlyphID());
414 if (setClass
< scSetCount
&& chainSubClassSetTableOffsetArray
[setClass
] != 0) {
415 Offset chainSubClassSetTableOffset
= SWAPW(chainSubClassSetTableOffsetArray
[setClass
]);
416 const ChainSubClassSetTable
*chainSubClassSetTable
=
417 (const ChainSubClassSetTable
*) ((char *) this + chainSubClassSetTableOffset
);
418 le_uint16 chainSubClassRuleCount
= SWAPW(chainSubClassSetTable
->chainSubClassRuleCount
);
419 le_int32 position
= glyphIterator
->getCurrStreamPosition();
420 GlyphIterator
tempIterator(*glyphIterator
, emptyFeatureList
);
422 for (le_uint16 scRule
= 0; scRule
< chainSubClassRuleCount
; scRule
+= 1) {
423 Offset chainSubClassRuleTableOffset
=
424 SWAPW(chainSubClassSetTable
->chainSubClassRuleTableOffsetArray
[scRule
]);
425 const ChainSubClassRuleTable
*chainSubClassRuleTable
=
426 (const ChainSubClassRuleTable
*) ((char *) chainSubClassSetTable
+ chainSubClassRuleTableOffset
);
427 le_uint16 backtrackGlyphCount
= SWAPW(chainSubClassRuleTable
->backtrackGlyphCount
);
428 le_uint16 inputGlyphCount
= SWAPW(chainSubClassRuleTable
->backtrackClassArray
[backtrackGlyphCount
]) - 1;
429 const le_uint16
*inputClassArray
= &chainSubClassRuleTable
->backtrackClassArray
[backtrackGlyphCount
+ 1];
430 le_uint16 lookaheadGlyphCount
= SWAPW(inputClassArray
[inputGlyphCount
]);
431 const le_uint16
*lookaheadClassArray
= &inputClassArray
[inputGlyphCount
+ 1];
432 le_uint16 substCount
= SWAPW(lookaheadClassArray
[lookaheadGlyphCount
]);
435 tempIterator
.setCurrStreamPosition(position
);
437 if (! tempIterator
.prev(backtrackGlyphCount
)) {
442 if (! matchGlyphClasses(chainSubClassRuleTable
->backtrackClassArray
, backtrackGlyphCount
,
443 &tempIterator
, backtrackClassDefinitionTable
, TRUE
)) {
447 tempIterator
.setCurrStreamPosition(position
);
448 tempIterator
.next(inputGlyphCount
);
449 if (! matchGlyphClasses(lookaheadClassArray
, lookaheadGlyphCount
, &tempIterator
, lookaheadClassDefinitionTable
)) {
453 if (matchGlyphClasses(inputClassArray
, inputGlyphCount
, glyphIterator
, inputClassDefinitionTable
)) {
454 const SubstitutionLookupRecord
*substLookupRecordArray
=
455 (const SubstitutionLookupRecord
*) &lookaheadClassArray
[lookaheadGlyphCount
+ 1];
457 applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
);
459 return inputGlyphCount
+ 1;
462 glyphIterator
->setCurrStreamPosition(position
);
466 // XXX If we get here, the table is mal-formed...
472 le_uint32
ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor
*lookupProcessor
, GlyphIterator
*glyphIterator
,
473 const LEFontInstance
*fontInstance
) const
475 le_uint16 backtrkGlyphCount
= SWAPW(backtrackGlyphCount
);
476 le_uint16 inputGlyphCount
= (le_uint16
) SWAPW(backtrackCoverageTableOffsetArray
[backtrkGlyphCount
]);
477 const Offset
*inputCoverageTableOffsetArray
= &backtrackCoverageTableOffsetArray
[backtrkGlyphCount
+ 1];
478 const le_uint16 lookaheadGlyphCount
= (le_uint16
) SWAPW(inputCoverageTableOffsetArray
[inputGlyphCount
]);
479 const Offset
*lookaheadCoverageTableOffsetArray
= &inputCoverageTableOffsetArray
[inputGlyphCount
+ 1];
480 le_uint16 substCount
= (le_uint16
) SWAPW(lookaheadCoverageTableOffsetArray
[lookaheadGlyphCount
]);
481 le_int32 position
= glyphIterator
->getCurrStreamPosition();
482 GlyphIterator
tempIterator(*glyphIterator
, emptyFeatureList
);
484 if (! tempIterator
.prev(backtrkGlyphCount
)) {
489 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray
,
490 backtrkGlyphCount
, &tempIterator
, (const char *) this, TRUE
)) {
494 tempIterator
.setCurrStreamPosition(position
);
495 tempIterator
.next(inputGlyphCount
- 1);
496 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray
,
497 lookaheadGlyphCount
, &tempIterator
, (const char *) this)) {
501 // Back up the glyph iterator so that we
502 // can call next() before the check, which
503 // will leave it pointing at the last glyph
504 // that matched when we're done.
505 glyphIterator
->prev();
507 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray
,
508 inputGlyphCount
, glyphIterator
, (const char *) this)) {
509 const SubstitutionLookupRecord
*substLookupRecordArray
=
510 (const SubstitutionLookupRecord
*) &lookaheadCoverageTableOffsetArray
[lookaheadGlyphCount
+ 1];
512 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
);
514 return inputGlyphCount
;
517 glyphIterator
->setCurrStreamPosition(position
);