1 /* 2 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved 3 * 4 */ 5 6 #include "LETypes.h" 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" 14 #include "LESwaps.h" 15 16 U_NAMESPACE_BEGIN 17 18 /* 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. 23 */ 24 void ContextualSubstitutionBase::applySubstitutionLookups( 25 const LookupProcessor *lookupProcessor, 26 const SubstitutionLookupRecord *substLookupRecordArray, 27 le_uint16 substCount, 28 GlyphIterator *glyphIterator, 29 const LEFontInstance *fontInstance, 30 le_int32 position, 31 LEErrorCode& success) 32 { 33 if (LE_FAILURE(success)) { 34 return; 35 } 36 37 GlyphIterator tempIterator(*glyphIterator); 38 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); 42 43 tempIterator.setCurrStreamPosition(position); 44 tempIterator.next(sequenceIndex); 45 46 lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success); 47 } 48 } 49 50 le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount, 51 GlyphIterator *glyphIterator, le_bool backtrack) 52 { 53 le_int32 direction = 1; 54 le_int32 match = 0; 55 56 if (backtrack) { 57 match = glyphCount -1; 58 direction = -1; 59 } 60 61 while (glyphCount > 0) { 62 if (! glyphIterator->next()) { 63 return FALSE; 64 } 65 66 TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID(); 67 68 if (glyph != SWAPW(glyphArray[match])) { 69 return FALSE; 70 } 71 72 glyphCount -= 1; 73 match += direction; 74 } 75 76 return TRUE; 77 } 78 79 le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount, 80 GlyphIterator *glyphIterator, 81 const ClassDefinitionTable *classDefinitionTable, 82 le_bool backtrack) 83 { 84 le_int32 direction = 1; 85 le_int32 match = 0; 86 87 if (backtrack) { 88 match = glyphCount - 1; 89 direction = -1; 90 } 91 92 while (glyphCount > 0) { 93 if (! glyphIterator->next()) { 94 return FALSE; 95 } 96 97 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 98 le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph); 99 le_int32 matchClass = SWAPW(classArray[match]); 100 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 105 // we found it. 106 if (classDefinitionTable->hasGlyphClass(matchClass)) { 107 return FALSE; 108 } 109 } 110 111 glyphCount -= 1; 112 match += direction; 113 } 114 115 return TRUE; 116 } 117 118 le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount, 119 GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack) 120 { 121 le_int32 direction = 1; 122 le_int32 glyph = 0; 123 124 if (backtrack) { 125 glyph = glyphCount - 1; 126 direction = -1; 127 } 128 129 while (glyphCount > 0) { 130 Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]); 131 const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset); 132 133 if (! glyphIterator->next()) { 134 return FALSE; 135 } 136 137 if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) { 138 return FALSE; 139 } 140 141 glyphCount -= 1; 142 glyph += direction; 143 } 144 145 return TRUE; 146 } 147 148 le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, 149 GlyphIterator *glyphIterator, 150 const LEFontInstance *fontInstance, 151 LEErrorCode& success) const 152 { 153 if (LE_FAILURE(success)) { 154 return 0; 155 } 156 157 switch(SWAPW(subtableFormat)) 158 { 159 case 0: 160 return 0; 161 162 case 1: 163 { 164 const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this; 165 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 166 } 167 168 case 2: 169 { 170 const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this; 171 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 172 } 173 174 case 3: 175 { 176 const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this; 177 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 178 } 179 180 default: 181 return 0; 182 } 183 } 184 185 le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, 186 GlyphIterator *glyphIterator, 187 const LEFontInstance *fontInstance, 188 LEErrorCode& success) const 189 { 190 if (LE_FAILURE(success)) { 191 return 0; 192 } 193 194 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 195 le_int32 coverageIndex = getGlyphCoverage(glyph); 196 197 if (coverageIndex >= 0) { 198 le_uint16 srSetCount = SWAPW(subRuleSetCount); 199 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(); 206 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); 214 215 if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) { 216 const SubstitutionLookupRecord *substLookupRecordArray = 217 (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount]; 218 219 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 220 221 return matchCount + 1; 222 } 223 224 glyphIterator->setCurrStreamPosition(position); 225 } 226 } 227 228 // XXX If we get here, the table is mal-formed... 229 } 230 231 return 0; 232 } 233 234 le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 235 GlyphIterator *glyphIterator, 236 const LEFontInstance *fontInstance, 237 LEErrorCode& success) const 238 { 239 if (LE_FAILURE(success)) { 240 return 0; 241 } 242 243 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 244 le_int32 coverageIndex = getGlyphCoverage(glyph); 245 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()); 251 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(); 258 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); 266 267 if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) { 268 const SubstitutionLookupRecord *substLookupRecordArray = 269 (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount]; 270 271 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 272 273 return matchCount + 1; 274 } 275 276 glyphIterator->setCurrStreamPosition(position); 277 } 278 } 279 280 // XXX If we get here, the table is mal-formed... 281 } 282 283 return 0; 284 } 285 286 le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 287 GlyphIterator *glyphIterator, 288 const LEFontInstance *fontInstance, 289 LEErrorCode& success)const 290 { 291 if (LE_FAILURE(success)) { 292 return 0; 293 } 294 295 le_uint16 gCount = SWAPW(glyphCount); 296 le_uint16 subCount = SWAPW(substCount); 297 le_int32 position = glyphIterator->getCurrStreamPosition(); 298 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(); 304 305 if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) { 306 const SubstitutionLookupRecord *substLookupRecordArray = 307 (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount]; 308 309 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success); 310 311 return gCount + 1; 312 } 313 314 glyphIterator->setCurrStreamPosition(position); 315 316 return 0; 317 } 318 319 le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, 320 GlyphIterator *glyphIterator, 321 const LEFontInstance *fontInstance, 322 LEErrorCode& success) const 323 { 324 if (LE_FAILURE(success)) { 325 return 0; 326 } 327 328 switch(SWAPW(subtableFormat)) 329 { 330 case 0: 331 return 0; 332 333 case 1: 334 { 335 const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this; 336 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 337 } 338 339 case 2: 340 { 341 const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this; 342 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 343 } 344 345 case 3: 346 { 347 const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this; 348 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 349 } 350 351 default: 352 return 0; 353 } 354 } 355 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; 361 362 le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, 363 GlyphIterator *glyphIterator, 364 const LEFontInstance *fontInstance, 365 LEErrorCode& success) const 366 { 367 if (LE_FAILURE(success)) { 368 return 0; 369 } 370 371 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 372 le_int32 coverageIndex = getGlyphCoverage(glyph); 373 374 if (coverageIndex >= 0) { 375 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); 376 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); 384 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]); 396 397 tempIterator.setCurrStreamPosition(position); 398 399 if (! tempIterator.prev(backtrackGlyphCount)) { 400 continue; 401 } 402 403 tempIterator.prev(); 404 if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) { 405 continue; 406 } 407 408 tempIterator.setCurrStreamPosition(position); 409 tempIterator.next(inputGlyphCount); 410 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) { 411 continue; 412 } 413 414 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) { 415 const SubstitutionLookupRecord *substLookupRecordArray = 416 (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1]; 417 418 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 419 420 return inputGlyphCount + 1; 421 } 422 423 glyphIterator->setCurrStreamPosition(position); 424 } 425 } 426 427 // XXX If we get here, the table is mal-formed... 428 } 429 430 return 0; 431 } 432 433 le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 434 GlyphIterator *glyphIterator, 435 const LEFontInstance *fontInstance, 436 LEErrorCode& success) const 437 { 438 if (LE_FAILURE(success)) { 439 return 0; 440 } 441 442 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 443 le_int32 coverageIndex = getGlyphCoverage(glyph); 444 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()); 454 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); 462 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]); 474 475 476 tempIterator.setCurrStreamPosition(position); 477 478 if (! tempIterator.prev(backtrackGlyphCount)) { 479 continue; 480 } 481 482 tempIterator.prev(); 483 if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount, 484 &tempIterator, backtrackClassDefinitionTable, TRUE)) { 485 continue; 486 } 487 488 tempIterator.setCurrStreamPosition(position); 489 tempIterator.next(inputGlyphCount); 490 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) { 491 continue; 492 } 493 494 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) { 495 const SubstitutionLookupRecord *substLookupRecordArray = 496 (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1]; 497 498 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 499 500 return inputGlyphCount + 1; 501 } 502 503 glyphIterator->setCurrStreamPosition(position); 504 } 505 } 506 507 // XXX If we get here, the table is mal-formed... 508 } 509 510 return 0; 511 } 512 513 le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 514 GlyphIterator *glyphIterator, 515 const LEFontInstance *fontInstance, 516 LEErrorCode & success) const 517 { 518 if (LE_FAILURE(success)) { 519 return 0; 520 } 521 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); 530 531 if (! tempIterator.prev(backtrkGlyphCount)) { 532 return 0; 533 } 534 535 tempIterator.prev(); 536 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray, 537 backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) { 538 return 0; 539 } 540 541 tempIterator.setCurrStreamPosition(position); 542 tempIterator.next(inputGlyphCount - 1); 543 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray, 544 lookaheadGlyphCount, &tempIterator, (const char *) this)) { 545 return 0; 546 } 547 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(); 553 554 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray, 555 inputGlyphCount, glyphIterator, (const char *) this)) { 556 const SubstitutionLookupRecord *substLookupRecordArray = 557 (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1]; 558 559 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 560 561 return inputGlyphCount; 562 } 563 564 glyphIterator->setCurrStreamPosition(position); 565 566 return 0; 567 } 568 569 U_NAMESPACE_END 570