os/textandloc/fontservices/textshaperplugin/IcuSource/layout/ContextualSubstSubtables.cpp
Update contrib.
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,
34 if (LE_FAILURE(success)) {
38 GlyphIterator tempIterator(*glyphIterator);
40 for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
41 le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
42 le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);
44 tempIterator.setCurrStreamPosition(position);
45 tempIterator.next(sequenceIndex);
47 lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator,
48 fontInstance, success);
52 le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount,
53 GlyphIterator *glyphIterator, le_bool backtrack)
55 le_int32 direction = 1;
59 match = glyphCount -1;
63 while (glyphCount > 0) {
64 if (! glyphIterator->next()) {
68 TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();
70 if (glyph != SWAPW(glyphArray[match])) {
81 le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount,
82 GlyphIterator *glyphIterator,
83 const ClassDefinitionTable *classDefinitionTable,
86 le_int32 direction = 1;
90 match = glyphCount - 1;
94 while (glyphCount > 0) {
95 if (! glyphIterator->next()) {
99 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
100 le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph);
101 le_int32 matchClass = SWAPW(classArray[match]);
103 if (glyphClass != matchClass) {
104 // Some fonts, e.g. Traditional Arabic, have classes
105 // in the class array which aren't in the class definition
106 // table. If we're looking for such a class, pretend that
108 if (classDefinitionTable->hasGlyphClass(matchClass)) {
120 le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
121 GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack)
123 le_int32 direction = 1;
127 glyph = glyphCount - 1;
131 while (glyphCount > 0) {
132 Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);
133 const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
135 if (! glyphIterator->next()) {
139 if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
150 le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
151 const LEFontInstance *fontInstance, LEErrorCode& success) const
153 if (LE_FAILURE(success)) {
157 switch(SWAPW(subtableFormat))
164 const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
166 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
171 const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
173 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
178 const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
180 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
188 le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
189 const LEFontInstance *fontInstance, LEErrorCode& success) const
191 if (LE_FAILURE(success)) {
195 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
196 le_int32 coverageIndex = getGlyphCoverage(glyph);
198 if (coverageIndex >= 0) {
199 le_uint16 srSetCount = SWAPW(subRuleSetCount);
201 if (coverageIndex < srSetCount) {
202 Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
203 const SubRuleSetTable *subRuleSetTable =
204 (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset);
205 le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
206 le_int32 position = glyphIterator->getCurrStreamPosition();
208 for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
209 Offset subRuleTableOffset =
210 SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
211 const SubRuleTable *subRuleTable =
212 (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset);
213 le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;
214 le_uint16 substCount = SWAPW(subRuleTable->substCount);
216 if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
217 const SubstitutionLookupRecord *substLookupRecordArray =
218 (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
220 applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
221 substCount, glyphIterator, fontInstance, position, success);
223 return matchCount + 1;
226 glyphIterator->setCurrStreamPosition(position);
230 // XXX If we get here, the table is mal-formed...
236 le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
237 const LEFontInstance *fontInstance, 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,
272 substCount, glyphIterator, fontInstance, position, success);
274 return matchCount + 1;
277 glyphIterator->setCurrStreamPosition(position);
281 // XXX If we get here, the table is mal-formed...
287 le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
288 const LEFontInstance *fontInstance, LEErrorCode& success) const
290 if (LE_FAILURE(success)) {
294 le_uint16 gCount = SWAPW(glyphCount);
295 le_uint16 subCount = SWAPW(substCount);
296 le_int32 position = glyphIterator->getCurrStreamPosition();
298 // Back up the glyph iterator so that we
299 // can call next() before the check, which
300 // will leave it pointing at the last glyph
301 // that matched when we're done.
302 glyphIterator->prev();
304 if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
305 const SubstitutionLookupRecord *substLookupRecordArray =
306 (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
308 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
309 subCount, glyphIterator, fontInstance, position, success);
314 glyphIterator->setCurrStreamPosition(position);
319 le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
320 const LEFontInstance *fontInstance, LEErrorCode& success) const
322 if (LE_FAILURE(success)) {
326 switch(SWAPW(subtableFormat))
333 const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
335 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
340 const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
342 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
347 const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
349 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
357 static const LETag emptyTag = 0;
359 le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
360 const LEFontInstance *fontInstance, LEErrorCode& success) const
362 if (LE_FAILURE(success)) {
366 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
367 le_int32 coverageIndex = getGlyphCoverage(glyph);
369 if (coverageIndex >= 0) {
370 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
372 if (coverageIndex < srSetCount) {
373 Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
374 const ChainSubRuleSetTable *chainSubRuleSetTable =
375 (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset);
376 le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
377 le_int32 position = glyphIterator->getCurrStreamPosition();
378 GlyphIterator tempIterator(*glyphIterator, emptyTag);
380 for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
381 Offset chainSubRuleTableOffset =
382 SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
383 const ChainSubRuleTable *chainSubRuleTable =
384 (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset);
385 le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);
386 le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;
387 const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1];
388 le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);
389 const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1];
390 le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);
392 tempIterator.setCurrStreamPosition(position);
394 if (! tempIterator.prev(backtrackGlyphCount)) {
399 if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
403 tempIterator.setCurrStreamPosition(position);
404 tempIterator.next(inputGlyphCount);
405 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
409 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
410 const SubstitutionLookupRecord *substLookupRecordArray =
411 (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
413 applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
414 substCount, glyphIterator, fontInstance, position, success);
416 return inputGlyphCount + 1;
419 glyphIterator->setCurrStreamPosition(position);
423 // XXX If we get here, the table is mal-formed...
429 le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
430 const LEFontInstance *fontInstance, LEErrorCode& success) const
432 if (LE_FAILURE(success)) {
436 LEGlyphID glyph = glyphIterator->getCurrGlyphID();
437 le_int32 coverageIndex = getGlyphCoverage(glyph);
439 if (coverageIndex >= 0) {
440 const ClassDefinitionTable *backtrackClassDefinitionTable =
441 (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
442 const ClassDefinitionTable *inputClassDefinitionTable =
443 (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
444 const ClassDefinitionTable *lookaheadClassDefinitionTable =
445 (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
446 le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
447 le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
449 if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
450 Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
451 const ChainSubClassSetTable *chainSubClassSetTable =
452 (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
453 le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
454 le_int32 position = glyphIterator->getCurrStreamPosition();
455 GlyphIterator tempIterator(*glyphIterator, emptyTag);
457 for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
458 Offset chainSubClassRuleTableOffset =
459 SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
460 const ChainSubClassRuleTable *chainSubClassRuleTable =
461 (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
462 le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
463 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
464 const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
465 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
466 const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
467 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
470 tempIterator.setCurrStreamPosition(position);
472 if (! tempIterator.prev(backtrackGlyphCount)) {
477 if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
478 &tempIterator, backtrackClassDefinitionTable, TRUE)) {
482 tempIterator.setCurrStreamPosition(position);
483 tempIterator.next(inputGlyphCount);
484 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
488 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
489 const SubstitutionLookupRecord *substLookupRecordArray =
490 (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
492 applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
493 substCount, glyphIterator, fontInstance, position, success);
495 return inputGlyphCount + 1;
498 glyphIterator->setCurrStreamPosition(position);
502 // XXX If we get here, the table is mal-formed...
508 le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator,
509 const LEFontInstance *fontInstance, LEErrorCode& success) const
511 if (LE_FAILURE(success)) {
515 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
516 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
517 const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
518 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
519 const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
520 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
521 le_int32 position = glyphIterator->getCurrStreamPosition();
522 GlyphIterator tempIterator(*glyphIterator, emptyTag);
524 if (! tempIterator.prev(backtrkGlyphCount)) {
529 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
530 backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
534 tempIterator.setCurrStreamPosition(position);
535 tempIterator.next(inputGlyphCount - 1);
536 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
537 lookaheadGlyphCount, &tempIterator, (const char *) this)) {
541 // Back up the glyph iterator so that we
542 // can call next() before the check, which
543 // will leave it pointing at the last glyph
544 // that matched when we're done.
545 glyphIterator->prev();
547 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
548 inputGlyphCount, glyphIterator, (const char *) this)) {
549 const SubstitutionLookupRecord *substLookupRecordArray =
550 (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
552 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray,
553 substCount, glyphIterator, fontInstance, position, success);
555 return inputGlyphCount;
558 glyphIterator->setCurrStreamPosition(position);