2
* (C) Copyright IBM Corp. 1998-2008 - 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,
33
if (LE_FAILURE(success)) {
37
GlyphIterator tempIterator(*glyphIterator);
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);
43
tempIterator.setCurrStreamPosition(position);
44
tempIterator.next(sequenceIndex);
46
lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
50
le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount,
51
GlyphIterator *glyphIterator, le_bool backtrack)
53
le_int32 direction = 1;
57
match = glyphCount -1;
61
while (glyphCount > 0) {
62
if (! glyphIterator->next()) {
66
TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();
68
if (glyph != SWAPW(glyphArray[match])) {
79
le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount,
80
GlyphIterator *glyphIterator,
81
const ClassDefinitionTable *classDefinitionTable,
84
le_int32 direction = 1;
88
match = glyphCount - 1;
92
while (glyphCount > 0) {
93
if (! glyphIterator->next()) {
97
LEGlyphID glyph = glyphIterator->getCurrGlyphID();
98
le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph);
99
le_int32 matchClass = SWAPW(classArray[match]);
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
106
if (classDefinitionTable->hasGlyphClass(matchClass)) {
118
le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
119
GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack)
121
le_int32 direction = 1;
125
glyph = glyphCount - 1;
129
while (glyphCount > 0) {
130
Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);
131
const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
133
if (! glyphIterator->next()) {
137
if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
148
le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
149
GlyphIterator *glyphIterator,
150
const LEFontInstance *fontInstance,
151
LEErrorCode& success) const
153
if (LE_FAILURE(success)) {
157
switch(SWAPW(subtableFormat))
164
const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
165
return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
170
const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
171
return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
176
const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
177
return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
185
le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
186
GlyphIterator *glyphIterator,
187
const LEFontInstance *fontInstance,
188
LEErrorCode& success) const
190
if (LE_FAILURE(success)) {
194
LEGlyphID glyph = glyphIterator->getCurrGlyphID();
195
le_int32 coverageIndex = getGlyphCoverage(glyph);
197
if (coverageIndex >= 0) {
198
le_uint16 srSetCount = SWAPW(subRuleSetCount);
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();
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);
215
if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
216
const SubstitutionLookupRecord *substLookupRecordArray =
217
(const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
219
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
221
return matchCount + 1;
224
glyphIterator->setCurrStreamPosition(position);
228
// XXX If we get here, the table is mal-formed...
234
le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
235
GlyphIterator *glyphIterator,
236
const LEFontInstance *fontInstance,
237
LEErrorCode& success) const
239
if (LE_FAILURE(success)) {
243
LEGlyphID glyph = glyphIterator->getCurrGlyphID();
244
le_int32 coverageIndex = getGlyphCoverage(glyph);
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());
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();
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);
267
if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
268
const SubstitutionLookupRecord *substLookupRecordArray =
269
(const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];
271
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
273
return matchCount + 1;
276
glyphIterator->setCurrStreamPosition(position);
280
// XXX If we get here, the table is mal-formed...
286
le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
287
GlyphIterator *glyphIterator,
288
const LEFontInstance *fontInstance,
289
LEErrorCode& success)const
291
if (LE_FAILURE(success)) {
295
le_uint16 gCount = SWAPW(glyphCount);
296
le_uint16 subCount = SWAPW(substCount);
297
le_int32 position = glyphIterator->getCurrStreamPosition();
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();
305
if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
306
const SubstitutionLookupRecord *substLookupRecordArray =
307
(const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
309
ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success);
314
glyphIterator->setCurrStreamPosition(position);
319
le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor,
320
GlyphIterator *glyphIterator,
321
const LEFontInstance *fontInstance,
322
LEErrorCode& success) const
324
if (LE_FAILURE(success)) {
328
switch(SWAPW(subtableFormat))
335
const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
336
return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
341
const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
342
return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
347
const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
348
return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
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;
362
le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor,
363
GlyphIterator *glyphIterator,
364
const LEFontInstance *fontInstance,
365
LEErrorCode& success) const
367
if (LE_FAILURE(success)) {
371
LEGlyphID glyph = glyphIterator->getCurrGlyphID();
372
le_int32 coverageIndex = getGlyphCoverage(glyph);
374
if (coverageIndex >= 0) {
375
le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
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);
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]);
397
tempIterator.setCurrStreamPosition(position);
399
if (! tempIterator.prev(backtrackGlyphCount)) {
404
if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
408
tempIterator.setCurrStreamPosition(position);
409
tempIterator.next(inputGlyphCount);
410
if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
414
if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
415
const SubstitutionLookupRecord *substLookupRecordArray =
416
(const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
418
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
420
return inputGlyphCount + 1;
423
glyphIterator->setCurrStreamPosition(position);
427
// XXX If we get here, the table is mal-formed...
433
le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor,
434
GlyphIterator *glyphIterator,
435
const LEFontInstance *fontInstance,
436
LEErrorCode& success) const
438
if (LE_FAILURE(success)) {
442
LEGlyphID glyph = glyphIterator->getCurrGlyphID();
443
le_int32 coverageIndex = getGlyphCoverage(glyph);
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());
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);
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]);
476
tempIterator.setCurrStreamPosition(position);
478
if (! tempIterator.prev(backtrackGlyphCount)) {
483
if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
484
&tempIterator, backtrackClassDefinitionTable, TRUE)) {
488
tempIterator.setCurrStreamPosition(position);
489
tempIterator.next(inputGlyphCount);
490
if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
494
if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
495
const SubstitutionLookupRecord *substLookupRecordArray =
496
(const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
498
applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
500
return inputGlyphCount + 1;
503
glyphIterator->setCurrStreamPosition(position);
507
// XXX If we get here, the table is mal-formed...
513
le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor,
514
GlyphIterator *glyphIterator,
515
const LEFontInstance *fontInstance,
516
LEErrorCode & success) const
518
if (LE_FAILURE(success)) {
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);
531
if (! tempIterator.prev(backtrkGlyphCount)) {
536
if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
537
backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
541
tempIterator.setCurrStreamPosition(position);
542
tempIterator.next(inputGlyphCount - 1);
543
if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
544
lookaheadGlyphCount, &tempIterator, (const char *) this)) {
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();
554
if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
555
inputGlyphCount, glyphIterator, (const char *) this)) {
556
const SubstitutionLookupRecord *substLookupRecordArray =
557
(const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
559
ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
561
return inputGlyphCount;
564
glyphIterator->setCurrStreamPosition(position);