2
* @(#)ContextualSubstSubtables.cpp 1.11 00/03/15
4
* (C) Copyright IBM Corp. 1998, 1999, 2000, 2001 - All Rights Reserved
9
#include "LEFontInstance.h"
10
#include "OpenTypeTables.h"
11
#include "GlyphSubstitutionTables.h"
12
#include "ContextualSubstSubtables.h"
13
#include "GlyphIterator.h"
14
#include "LookupProcessor.h"
15
#include "CoverageTables.h"
21
NOTE: This could be optimized somewhat by keeping track
22
of the previous sequenceIndex in the loop and doing next()
23
or prev() of the delta between that and the current
24
sequenceIndex instead of always resetting to the front.
26
void ContextualSubstitutionBase::applySubstitutionLookups(
27
const LookupProcessor *lookupProcessor,
28
const SubstitutionLookupRecord *substLookupRecordArray,
30
GlyphIterator *glyphIterator,
31
const LEFontInstance *fontInstance,
34
GlyphIterator tempIterator(*glyphIterator);
36
for (le_int16 subst = 0; subst < substCount; subst += 1) {
37
le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
38
le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);
40
tempIterator.setCurrStreamPosition(position);
41
tempIterator.next(sequenceIndex);
43
lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance);
47
le_bool ContextualSubstitutionBase::matchGlyphIDs(const LEGlyphID *glyphArray, le_uint16 glyphCount,
48
GlyphIterator *glyphIterator)
50
for (le_uint16 match = 0; match < glyphCount; match += 1) {
51
if (! glyphIterator->next()) {
55
LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
57
if (glyph != SWAPW(glyphArray[match])) {
65
le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount,
66
GlyphIterator *glyphIterator,
67
const ClassDefinitionTable *classDefinitionTable)
69
for (le_uint16 match = 0; match < glyphCount; match += 1) {
70
if (! glyphIterator->next()) {
74
LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
75
le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph);
76
le_int32 matchClass = SWAPW(classArray[match]);
78
if (glyphClass != matchClass) {
79
// Some fonts, e.g. Traditional Arabic, have classes
80
// in the class array which aren't in the class definition
81
// table. If we're looking for such a class, pretend that
83
if (classDefinitionTable->hasGlyphClass(matchClass)) {
92
le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
93
GlyphIterator *glyphIterator, const char *offsetBase)
95
for (le_uint16 glyph = 0; glyph < glyphCount; glyph += 1) {
96
Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);
97
const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
99
if (! glyphIterator->next()) {
103
if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
111
le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
112
const LEFontInstance *fontInstance) const
114
switch(SWAPW(subtableFormat))
121
const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
123
return subtable->process(lookupProcessor, glyphIterator, fontInstance);
128
const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
130
return subtable->process(lookupProcessor, glyphIterator, fontInstance);
135
const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
137
return subtable->process(lookupProcessor, glyphIterator, fontInstance);
145
le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
146
const LEFontInstance *fontInstance) const
148
LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
149
le_int32 coverageIndex = getGlyphCoverage(glyph);
151
if (coverageIndex >= 0) {
152
le_uint16 srSetCount = SWAPW(subRuleSetCount);
154
if (coverageIndex < srSetCount) {
155
Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
156
const SubRuleSetTable *subRuleSetTable =
157
(const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset);
158
le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
159
le_int32 position = glyphIterator->getCurrStreamPosition();
161
for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
162
Offset subRuleTableOffset =
163
SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
164
const SubRuleTable *subRuleTable =
165
(const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset);
166
le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;
167
le_uint16 substCount = SWAPW(subRuleTable->substCount);
169
if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
170
const SubstitutionLookupRecord *substLookupRecordArray =
171
(const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
173
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position);
175
return matchCount + 1;
178
glyphIterator->setCurrStreamPosition(position);
182
// XXX If we get here, the table is mal-formed...
188
le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
189
const LEFontInstance *fontInstance) const
191
LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
192
le_int32 coverageIndex = getGlyphCoverage(glyph);
194
if (coverageIndex >= 0) {
195
const ClassDefinitionTable *classDefinitionTable =
196
(const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset));
197
le_uint16 scSetCount = SWAPW(subClassSetCount);
198
le_int32 setClass = classDefinitionTable->getGlyphClass((LEGlyphID) glyphIterator->getCurrGlyphID());
200
if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
201
Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
202
const SubClassSetTable *subClassSetTable =
203
(const SubClassSetTable *) ((char *) this + subClassSetTableOffset);
204
le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
205
le_int32 position = glyphIterator->getCurrStreamPosition();
207
for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
208
Offset subClassRuleTableOffset =
209
SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
210
const SubClassRuleTable *subClassRuleTable =
211
(const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset);
212
le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
213
le_uint16 substCount = SWAPW(subClassRuleTable->substCount);
215
if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
216
const SubstitutionLookupRecord *substLookupRecordArray =
217
(const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];
219
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position);
221
return matchCount + 1;
224
glyphIterator->setCurrStreamPosition(position);
228
// XXX If we get here, the table is mal-formed...
234
le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
235
const LEFontInstance *fontInstance)const
237
le_uint16 gCount = SWAPW(glyphCount);
238
le_uint16 subCount = SWAPW(substCount);
239
le_int32 position = glyphIterator->getCurrStreamPosition();
241
// Back up the glyph iterator so that we
242
// can call next() before the check, which
243
// will leave it pointing at the last glyph
244
// that matched when we're done.
245
glyphIterator->prev();
247
if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
248
const SubstitutionLookupRecord *substLookupRecordArray =
249
(const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
251
ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position);
256
glyphIterator->setCurrStreamPosition(position);
261
le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
262
const LEFontInstance *fontInstance) const
264
switch(SWAPW(subtableFormat))
271
const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
273
return subtable->process(lookupProcessor, glyphIterator, fontInstance);
278
const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
280
return subtable->process(lookupProcessor, glyphIterator, fontInstance);
285
const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
287
return subtable->process(lookupProcessor, glyphIterator, fontInstance);
295
le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
296
const LEFontInstance *fontInstance) const
298
LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
299
le_int32 coverageIndex = getGlyphCoverage(glyph);
301
if (coverageIndex >= 0) {
302
le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
304
if (coverageIndex < srSetCount) {
305
Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
306
const ChainSubRuleSetTable *chainSubRuleSetTable =
307
(const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset);
308
le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
309
le_int32 position = glyphIterator->getCurrStreamPosition();
310
GlyphIterator tempIterator(*glyphIterator);
312
for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
313
Offset chainSubRuleTableOffset =
314
SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
315
const ChainSubRuleTable *chainSubRuleTable =
316
(const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset);
317
le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);
318
le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;
319
const LEGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1];
320
le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);
321
const LEGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1];
322
le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);
324
tempIterator.setCurrStreamPosition(position);
325
tempIterator.prev(backtrackGlyphCount + 1);
326
if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator)) {
330
tempIterator.setCurrStreamPosition(position);
331
tempIterator.next(inputGlyphCount);
332
if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
336
if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
337
const SubstitutionLookupRecord *substLookupRecordArray =
338
(const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
340
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position);
342
return inputGlyphCount + 1;
345
glyphIterator->setCurrStreamPosition(position);
349
// XXX If we get here, the table is mal-formed...
355
le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
356
const LEFontInstance *fontInstance) const
358
LEGlyphID glyph = (LEGlyphID) glyphIterator->getCurrGlyphID();
359
le_int32 coverageIndex = getGlyphCoverage(glyph);
361
if (coverageIndex >= 0) {
362
const ClassDefinitionTable *backtrackClassDefinitionTable =
363
(const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
364
const ClassDefinitionTable *inputClassDefinitionTable =
365
(const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
366
const ClassDefinitionTable *lookaheadClassDefinitionTable =
367
(const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
368
le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
369
le_int32 setClass = inputClassDefinitionTable->getGlyphClass((LEGlyphID) glyphIterator->getCurrGlyphID());
371
if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
372
Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
373
const ChainSubClassSetTable *chainSubClassSetTable =
374
(const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
375
le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
376
le_int32 position = glyphIterator->getCurrStreamPosition();
377
GlyphIterator tempIterator(*glyphIterator);
379
for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
380
Offset chainSubClassRuleTableOffset =
381
SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
382
const ChainSubClassRuleTable *chainSubClassRuleTable =
383
(const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
384
le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
385
le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
386
const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
387
le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
388
const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
389
le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
392
tempIterator.setCurrStreamPosition(position);
393
tempIterator.prev(backtrackGlyphCount + 1);
394
if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
395
&tempIterator, backtrackClassDefinitionTable)) {
399
tempIterator.setCurrStreamPosition(position);
400
tempIterator.next(inputGlyphCount);
401
if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
405
if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
406
const SubstitutionLookupRecord *substLookupRecordArray =
407
(const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
409
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position);
411
return inputGlyphCount + 1;
414
glyphIterator->setCurrStreamPosition(position);
418
// XXX If we get here, the table is mal-formed...
424
le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
425
const LEFontInstance *fontInstance) const
427
le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
428
le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
429
const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
430
const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
431
const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
432
le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
433
le_int32 position = glyphIterator->getCurrStreamPosition();
434
GlyphIterator tempIterator(*glyphIterator);
436
tempIterator.prev(backtrkGlyphCount + 1);
437
if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
438
backtrkGlyphCount, &tempIterator, (const char *) this)) {
442
tempIterator.setCurrStreamPosition(position);
443
tempIterator.next(inputGlyphCount - 1);
444
if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
445
lookaheadGlyphCount, &tempIterator, (const char *) this)) {
449
// Back up the glyph iterator so that we
450
// can call next() before the check, which
451
// will leave it pointing at the last glyph
452
// that matched when we're done.
453
glyphIterator->prev();
455
if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
456
inputGlyphCount, glyphIterator, (const char *) this)) {
457
const SubstitutionLookupRecord *substLookupRecordArray =
458
(const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
460
ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position);
462
return inputGlyphCount + 1;
465
glyphIterator->setCurrStreamPosition(position);