2 * (C) Copyright IBM Corp. 1998-2015 - 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(lookupProcessor
->getReference(), glyph
, success
);
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(lookupProcessor
->getReference(), glyph
, success
);
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(lookupProcessor
->getReference(), glyph
, success
);
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(lookupProcessor
->getReference(), glyph
, success
);
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
);
470 // TODO: Ticket #11557 - enable this check, originally from ticket #11525.
471 // Depends on other, more extensive, changes.
472 // LEReferenceToArrayOf<le_uint16> backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount);
473 if( LE_FAILURE(success
) ) { return 0; }
475 le_uint16 inputGlyphCount
= SWAPW(chainSubClassRuleTable
->backtrackClassArray
[backtrackGlyphCount
]) - 1;
476 const le_uint16
*inputClassArray
= &chainSubClassRuleTable
->backtrackClassArray
[backtrackGlyphCount
+ 1];
477 le_uint16 lookaheadGlyphCount
= SWAPW(inputClassArray
[inputGlyphCount
]);
478 const le_uint16
*lookaheadClassArray
= &inputClassArray
[inputGlyphCount
+ 1];
479 le_uint16 substCount
= SWAPW(lookaheadClassArray
[lookaheadGlyphCount
]);
482 tempIterator
.setCurrStreamPosition(position
);
484 if (! tempIterator
.prev(backtrackGlyphCount
)) {
489 if (! matchGlyphClasses(chainSubClassRuleTable
->backtrackClassArray
, backtrackGlyphCount
,
490 &tempIterator
, backtrackClassDefinitionTable
, TRUE
)) {
494 tempIterator
.setCurrStreamPosition(position
);
495 tempIterator
.next(inputGlyphCount
);
496 if (! matchGlyphClasses(lookaheadClassArray
, lookaheadGlyphCount
, &tempIterator
, lookaheadClassDefinitionTable
)) {
500 if (matchGlyphClasses(inputClassArray
, inputGlyphCount
, glyphIterator
, inputClassDefinitionTable
)) {
501 const SubstitutionLookupRecord
*substLookupRecordArray
=
502 (const SubstitutionLookupRecord
*) &lookaheadClassArray
[lookaheadGlyphCount
+ 1];
504 applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
, success
);
506 return inputGlyphCount
+ 1;
509 glyphIterator
->setCurrStreamPosition(position
);
513 // XXX If we get here, the table is mal-formed...
519 le_uint32
ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor
*lookupProcessor
,
520 GlyphIterator
*glyphIterator
,
521 const LEFontInstance
*fontInstance
,
522 LEErrorCode
& success
) const
524 if (LE_FAILURE(success
)) {
528 le_uint16 backtrkGlyphCount
= SWAPW(backtrackGlyphCount
);
529 le_uint16 inputGlyphCount
= (le_uint16
) SWAPW(backtrackCoverageTableOffsetArray
[backtrkGlyphCount
]);
530 const Offset
*inputCoverageTableOffsetArray
= &backtrackCoverageTableOffsetArray
[backtrkGlyphCount
+ 1];
531 const le_uint16 lookaheadGlyphCount
= (le_uint16
) SWAPW(inputCoverageTableOffsetArray
[inputGlyphCount
]);
532 const Offset
*lookaheadCoverageTableOffsetArray
= &inputCoverageTableOffsetArray
[inputGlyphCount
+ 1];
533 le_uint16 substCount
= (le_uint16
) SWAPW(lookaheadCoverageTableOffsetArray
[lookaheadGlyphCount
]);
534 le_int32 position
= glyphIterator
->getCurrStreamPosition();
535 GlyphIterator
tempIterator(*glyphIterator
, emptyFeatureList
);
537 if (! tempIterator
.prev(backtrkGlyphCount
)) {
542 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray
,
543 backtrkGlyphCount
, &tempIterator
, (const char *) this, TRUE
)) {
547 tempIterator
.setCurrStreamPosition(position
);
548 tempIterator
.next(inputGlyphCount
- 1);
549 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray
,
550 lookaheadGlyphCount
, &tempIterator
, (const char *) this)) {
554 // Back up the glyph iterator so that we
555 // can call next() before the check, which
556 // will leave it pointing at the last glyph
557 // that matched when we're done.
558 glyphIterator
->prev();
560 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray
,
561 inputGlyphCount
, glyphIterator
, (const char *) this)) {
562 const SubstitutionLookupRecord
*substLookupRecordArray
=
563 (const SubstitutionLookupRecord
*) &lookaheadCoverageTableOffsetArray
[lookaheadGlyphCount
+ 1];
565 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor
, substLookupRecordArray
, substCount
, glyphIterator
, fontInstance
, position
, success
);
567 return inputGlyphCount
;
570 glyphIterator
->setCurrStreamPosition(position
);