1 /* 2 * (C) Copyright IBM Corp. 1998-2015 - 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 /* Google patch: Behdad says: Unsafe dereference follows. */ 132 const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset); 133 134 if (! glyphIterator->next()) { 135 return FALSE; 136 } 137 138 if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) { 139 return FALSE; 140 } 141 142 glyphCount -= 1; 143 glyph += direction; 144 } 145 146 return TRUE; 147 } 148 149 le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, 150 GlyphIterator *glyphIterator, 151 const LEFontInstance *fontInstance, 152 LEErrorCode& success) const 153 { 154 if (LE_FAILURE(success)) { 155 return 0; 156 } 157 158 switch(SWAPW(subtableFormat)) 159 { 160 case 0: 161 return 0; 162 163 /* Google patch: Behdad says: Unsafe downcasts follow. */ 164 165 case 1: 166 { 167 const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this; 168 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 169 } 170 171 case 2: 172 { 173 const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this; 174 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 175 } 176 177 case 3: 178 { 179 const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this; 180 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 181 } 182 183 default: 184 return 0; 185 } 186 } 187 188 le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, 189 GlyphIterator *glyphIterator, 190 const LEFontInstance *fontInstance, 191 LEErrorCode& success) const 192 { 193 if (LE_FAILURE(success)) { 194 return 0; 195 } 196 197 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 198 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 199 200 if (coverageIndex >= 0) { 201 le_uint16 srSetCount = SWAPW(subRuleSetCount); 202 203 if (coverageIndex < srSetCount) { 204 Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]); 205 /* Google patch: Behdad says: Unsafe dereference follows. */ 206 const SubRuleSetTable *subRuleSetTable = 207 (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset); 208 le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount); 209 le_int32 position = glyphIterator->getCurrStreamPosition(); 210 211 for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) { 212 Offset subRuleTableOffset = 213 SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]); 214 const SubRuleTable *subRuleTable = 215 (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset); 216 le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1; 217 le_uint16 substCount = SWAPW(subRuleTable->substCount); 218 219 if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) { 220 const SubstitutionLookupRecord *substLookupRecordArray = 221 (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount]; 222 223 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 224 225 return matchCount + 1; 226 } 227 228 glyphIterator->setCurrStreamPosition(position); 229 } 230 } 231 232 // XXX If we get here, the table is mal-formed... 233 } 234 235 return 0; 236 } 237 238 le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 239 GlyphIterator *glyphIterator, 240 const LEFontInstance *fontInstance, 241 LEErrorCode& success) const 242 { 243 if (LE_FAILURE(success)) { 244 return 0; 245 } 246 247 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 248 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 249 250 if (coverageIndex >= 0) { 251 /* Google patch: Behdad says: Unsafe dereference follows. */ 252 const ClassDefinitionTable *classDefinitionTable = 253 (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset)); 254 le_uint16 scSetCount = SWAPW(subClassSetCount); 255 le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID()); 256 257 if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) { 258 Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]); 259 /* Google patch: Behdad says: Unsafe dereference follows. */ 260 const SubClassSetTable *subClassSetTable = 261 (const SubClassSetTable *) ((char *) this + subClassSetTableOffset); 262 le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount); 263 le_int32 position = glyphIterator->getCurrStreamPosition(); 264 265 for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) { 266 Offset subClassRuleTableOffset = 267 SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]); 268 const SubClassRuleTable *subClassRuleTable = 269 (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset); 270 le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1; 271 le_uint16 substCount = SWAPW(subClassRuleTable->substCount); 272 273 if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) { 274 const SubstitutionLookupRecord *substLookupRecordArray = 275 (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount]; 276 277 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 278 279 return matchCount + 1; 280 } 281 282 glyphIterator->setCurrStreamPosition(position); 283 } 284 } 285 286 // XXX If we get here, the table is mal-formed... 287 } 288 289 return 0; 290 } 291 292 le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 293 GlyphIterator *glyphIterator, 294 const LEFontInstance *fontInstance, 295 LEErrorCode& success)const 296 { 297 if (LE_FAILURE(success)) { 298 return 0; 299 } 300 301 le_uint16 gCount = SWAPW(glyphCount); 302 le_uint16 subCount = SWAPW(substCount); 303 le_int32 position = glyphIterator->getCurrStreamPosition(); 304 305 // Back up the glyph iterator so that we 306 // can call next() before the check, which 307 // will leave it pointing at the last glyph 308 // that matched when we're done. 309 glyphIterator->prev(); 310 311 if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) { 312 const SubstitutionLookupRecord *substLookupRecordArray = 313 (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount]; 314 315 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success); 316 317 return gCount + 1; 318 } 319 320 glyphIterator->setCurrStreamPosition(position); 321 322 return 0; 323 } 324 325 le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, 326 GlyphIterator *glyphIterator, 327 const LEFontInstance *fontInstance, 328 LEErrorCode& success) const 329 { 330 if (LE_FAILURE(success)) { 331 return 0; 332 } 333 334 switch(SWAPW(subtableFormat)) 335 { 336 case 0: 337 return 0; 338 339 /* Google patch: Behdad says: Unsafe downcasts follow. */ 340 341 case 1: 342 { 343 const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this; 344 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 345 } 346 347 case 2: 348 { 349 const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this; 350 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 351 } 352 353 case 3: 354 { 355 const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this; 356 return subtable->process(lookupProcessor, glyphIterator, fontInstance, success); 357 } 358 359 default: 360 return 0; 361 } 362 } 363 364 // NOTE: This could be a #define, but that seems to confuse 365 // the Visual Studio .NET 2003 compiler on the calls to the 366 // GlyphIterator constructor. It somehow can't decide if 367 // emptyFeatureList matches an le_uint32 or an le_uint16... 368 static const FeatureMask emptyFeatureList = 0x00000000UL; 369 370 le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, 371 GlyphIterator *glyphIterator, 372 const LEFontInstance *fontInstance, 373 LEErrorCode& success) const 374 { 375 if (LE_FAILURE(success)) { 376 return 0; 377 } 378 379 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 380 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 381 382 if (coverageIndex >= 0) { 383 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); 384 385 if (coverageIndex < srSetCount) { 386 Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]); 387 /* Google patch: Behdad says: Unsafe dereference follows. */ 388 const ChainSubRuleSetTable *chainSubRuleSetTable = 389 (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset); 390 le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount); 391 le_int32 position = glyphIterator->getCurrStreamPosition(); 392 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 393 394 for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) { 395 Offset chainSubRuleTableOffset = 396 SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]); 397 const ChainSubRuleTable *chainSubRuleTable = 398 (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset); 399 le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount); 400 le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1; 401 const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1]; 402 le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]); 403 const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1]; 404 le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]); 405 406 tempIterator.setCurrStreamPosition(position); 407 408 if (! tempIterator.prev(backtrackGlyphCount)) { 409 continue; 410 } 411 412 tempIterator.prev(); 413 if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) { 414 continue; 415 } 416 417 tempIterator.setCurrStreamPosition(position); 418 tempIterator.next(inputGlyphCount); 419 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) { 420 continue; 421 } 422 423 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) { 424 const SubstitutionLookupRecord *substLookupRecordArray = 425 (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1]; 426 427 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 428 429 return inputGlyphCount + 1; 430 } 431 432 glyphIterator->setCurrStreamPosition(position); 433 } 434 } 435 436 // XXX If we get here, the table is mal-formed... 437 } 438 439 return 0; 440 } 441 442 le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 443 GlyphIterator *glyphIterator, 444 const LEFontInstance *fontInstance, 445 LEErrorCode& success) const 446 { 447 if (LE_FAILURE(success)) { 448 return 0; 449 } 450 451 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 452 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 453 454 if (coverageIndex >= 0) { 455 /* Google patch: Behdad says: Unsafe dereferences follow. */ 456 const ClassDefinitionTable *backtrackClassDefinitionTable = 457 (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset)); 458 const ClassDefinitionTable *inputClassDefinitionTable = 459 (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset)); 460 const ClassDefinitionTable *lookaheadClassDefinitionTable = 461 (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset)); 462 le_uint16 scSetCount = SWAPW(chainSubClassSetCount); 463 le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID()); 464 465 if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) { 466 Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]); 467 /* Google patch: Behdad says: Unsafe dereference follows. */ 468 const ChainSubClassSetTable *chainSubClassSetTable = 469 (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset); 470 le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount); 471 le_int32 position = glyphIterator->getCurrStreamPosition(); 472 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 473 474 for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) { 475 Offset chainSubClassRuleTableOffset = 476 SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]); 477 const ChainSubClassRuleTable *chainSubClassRuleTable = 478 (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset); 479 le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount); 480 481 // TODO: Ticket #11557 - enable this check, originally from ticket #11525. 482 // Depends on other, more extensive, changes. 483 // LEReferenceToArrayOf<le_uint16> backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount); 484 if( LE_FAILURE(success) ) { return 0; } 485 486 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1; 487 const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1]; 488 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]); 489 const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1]; 490 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]); 491 492 493 tempIterator.setCurrStreamPosition(position); 494 495 if (! tempIterator.prev(backtrackGlyphCount)) { 496 continue; 497 } 498 499 tempIterator.prev(); 500 if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount, 501 &tempIterator, backtrackClassDefinitionTable, TRUE)) { 502 continue; 503 } 504 505 tempIterator.setCurrStreamPosition(position); 506 tempIterator.next(inputGlyphCount); 507 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) { 508 continue; 509 } 510 511 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) { 512 const SubstitutionLookupRecord *substLookupRecordArray = 513 (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1]; 514 515 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 516 517 return inputGlyphCount + 1; 518 } 519 520 glyphIterator->setCurrStreamPosition(position); 521 } 522 } 523 524 // XXX If we get here, the table is mal-formed... 525 } 526 527 return 0; 528 } 529 530 le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 531 GlyphIterator *glyphIterator, 532 const LEFontInstance *fontInstance, 533 LEErrorCode & success) const 534 { 535 if (LE_FAILURE(success)) { 536 return 0; 537 } 538 539 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount); 540 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]); 541 const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1]; 542 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]); 543 const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1]; 544 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]); 545 le_int32 position = glyphIterator->getCurrStreamPosition(); 546 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 547 548 if (! tempIterator.prev(backtrkGlyphCount)) { 549 return 0; 550 } 551 552 tempIterator.prev(); 553 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray, 554 backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) { 555 return 0; 556 } 557 558 tempIterator.setCurrStreamPosition(position); 559 tempIterator.next(inputGlyphCount - 1); 560 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray, 561 lookaheadGlyphCount, &tempIterator, (const char *) this)) { 562 return 0; 563 } 564 565 // Back up the glyph iterator so that we 566 // can call next() before the check, which 567 // will leave it pointing at the last glyph 568 // that matched when we're done. 569 glyphIterator->prev(); 570 571 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray, 572 inputGlyphCount, glyphIterator, (const char *) this)) { 573 const SubstitutionLookupRecord *substLookupRecordArray = 574 (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1]; 575 576 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 577 578 return inputGlyphCount; 579 } 580 581 glyphIterator->setCurrStreamPosition(position); 582 583 return 0; 584 } 585 586 U_NAMESPACE_END 587