ContextualSubstSubtables.cpp revision 11281:e6d938af3941
1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26/* 27 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved 28 * 29 */ 30 31#include "LETypes.h" 32#include "LEFontInstance.h" 33#include "OpenTypeTables.h" 34#include "GlyphSubstitutionTables.h" 35#include "ContextualSubstSubtables.h" 36#include "GlyphIterator.h" 37#include "LookupProcessor.h" 38#include "CoverageTables.h" 39#include "LESwaps.h" 40 41U_NAMESPACE_BEGIN 42 43/* 44 NOTE: This could be optimized somewhat by keeping track 45 of the previous sequenceIndex in the loop and doing next() 46 or prev() of the delta between that and the current 47 sequenceIndex instead of always resetting to the front. 48*/ 49void ContextualSubstitutionBase::applySubstitutionLookups( 50 const LookupProcessor *lookupProcessor, 51 const LEReferenceToArrayOf<SubstitutionLookupRecord>& substLookupRecordArray, 52 le_uint16 substCount, 53 GlyphIterator *glyphIterator, 54 const LEFontInstance *fontInstance, 55 le_int32 position, 56 LEErrorCode& success) 57{ 58 if (LE_FAILURE(success)) { 59 return; 60 } 61 62 GlyphIterator tempIterator(*glyphIterator); 63 const SubstitutionLookupRecord *substLookupRecordArrayPtr = substLookupRecordArray.getAlias(); // OK to dereference, range checked against substCount below. 64 65 for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) { 66 le_uint16 sequenceIndex = SWAPW(substLookupRecordArrayPtr[subst].sequenceIndex); 67 le_uint16 lookupListIndex = SWAPW(substLookupRecordArrayPtr[subst].lookupListIndex); 68 69 tempIterator.setCurrStreamPosition(position); 70 tempIterator.next(sequenceIndex); 71 72 lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success); 73 } 74} 75 76le_bool ContextualSubstitutionBase::matchGlyphIDs(const LEReferenceToArrayOf<TTGlyphID>& glyphArray, le_uint16 glyphCount, 77 GlyphIterator *glyphIterator, le_bool backtrack) 78{ 79 le_int32 direction = 1; 80 le_int32 match = 0; 81 82 if (backtrack) { 83 match = glyphCount -1; 84 direction = -1; 85 } 86 87 while (glyphCount > 0) { 88 if (! glyphIterator->next()) { 89 return FALSE; 90 } 91 92 TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID(); 93 94 if (glyph != SWAPW(glyphArray[match])) { 95 return FALSE; 96 } 97 98 glyphCount -= 1; 99 match += direction; 100 } 101 102 return TRUE; 103} 104 105le_bool ContextualSubstitutionBase::matchGlyphClasses( 106 const LEReferenceToArrayOf<le_uint16> &classArray, 107 le_uint16 glyphCount, 108 GlyphIterator *glyphIterator, 109 const LEReferenceTo<ClassDefinitionTable> &classDefinitionTable, 110 LEErrorCode &success, 111 le_bool backtrack) 112{ 113 if (LE_FAILURE(success)) { return FALSE; } 114 115 le_int32 direction = 1; 116 le_int32 match = 0; 117 118 if (backtrack) { 119 match = glyphCount - 1; 120 direction = -1; 121 } 122 123 while (glyphCount > 0) { 124 if (! glyphIterator->next()) { 125 return FALSE; 126 } 127 128 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 129 le_int32 glyphClass = classDefinitionTable->getGlyphClass(classDefinitionTable, glyph, success); 130 le_int32 matchClass = SWAPW(classArray[match]); 131 132 if (glyphClass != matchClass) { 133 // Some fonts, e.g. Traditional Arabic, have classes 134 // in the class array which aren't in the class definition 135 // table. If we're looking for such a class, pretend that 136 // we found it. 137 if (classDefinitionTable->hasGlyphClass(classDefinitionTable, matchClass, success)) { 138 return FALSE; 139 } 140 } 141 142 glyphCount -= 1; 143 match += direction; 144 } 145 146 return TRUE; 147} 148 149le_bool ContextualSubstitutionBase::matchGlyphCoverages(const LEReferenceToArrayOf<Offset> &coverageTableOffsetArray, le_uint16 glyphCount, 150GlyphIterator *glyphIterator, const LETableReference &offsetBase, LEErrorCode &success, le_bool backtrack) 151{ 152 le_int32 direction = 1; 153 le_int32 glyph = 0; 154 155 if (backtrack) { 156 glyph = glyphCount - 1; 157 direction = -1; 158 } 159 160 while (glyphCount > 0) { 161 Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]); 162 LEReferenceTo<CoverageTable> coverageTable(offsetBase, success, coverageTableOffset); 163 164 if (LE_FAILURE(success) || ! glyphIterator->next()) { 165 return FALSE; 166 } 167 168 if (coverageTable->getGlyphCoverage(coverageTable, 169 (LEGlyphID) glyphIterator->getCurrGlyphID(), 170 success) < 0) { 171 return FALSE; 172 } 173 174 glyphCount -= 1; 175 glyph += direction; 176 } 177 178 return TRUE; 179} 180 181le_uint32 ContextualSubstitutionSubtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 182 GlyphIterator *glyphIterator, 183 const LEFontInstance *fontInstance, 184 LEErrorCode& success) const 185{ 186 if (LE_FAILURE(success)) { 187 return 0; 188 } 189 190 switch(SWAPW(subtableFormat)) 191 { 192 case 0: 193 return 0; 194 195 case 1: 196 { 197 LEReferenceTo<ContextualSubstitutionFormat1Subtable> subtable(base, success, (const ContextualSubstitutionFormat1Subtable *) this); 198 if( LE_FAILURE(success) ) { 199 return 0; 200 } 201 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 202 } 203 204 case 2: 205 { 206 LEReferenceTo<ContextualSubstitutionFormat2Subtable> subtable(base, success, (const ContextualSubstitutionFormat2Subtable *) this); 207 if( LE_FAILURE(success) ) { 208 return 0; 209 } 210 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 211 } 212 213 case 3: 214 { 215 LEReferenceTo<ContextualSubstitutionFormat3Subtable> subtable(base, success, (const ContextualSubstitutionFormat3Subtable *) this); 216 if( LE_FAILURE(success) ) { 217 return 0; 218 } 219 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 220 } 221 222 default: 223 return 0; 224 } 225} 226 227le_uint32 ContextualSubstitutionFormat1Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 228 GlyphIterator *glyphIterator, 229 const LEFontInstance *fontInstance, 230 LEErrorCode& success) const 231{ 232 if (LE_FAILURE(success)) { 233 return 0; 234 } 235 236 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 237 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 238 if (LE_FAILURE(success)) { 239 return 0; 240 } 241 242 if (coverageIndex >= 0) { 243 le_uint16 srSetCount = SWAPW(subRuleSetCount); 244 245 if (coverageIndex < srSetCount) { 246 LEReferenceToArrayOf<Offset> subRuleSetTableOffsetArrayRef(base, success, 247 &subRuleSetTableOffsetArray[coverageIndex], 1); 248 if (LE_FAILURE(success)) { 249 return 0; 250 } 251 Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]); 252 LEReferenceTo<SubRuleSetTable> 253 subRuleSetTable(base, success, (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset)); 254 le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount); 255 le_int32 position = glyphIterator->getCurrStreamPosition(); 256 257 LEReferenceToArrayOf<Offset> subRuleTableOffsetArrayRef(base, success, 258 subRuleSetTable->subRuleTableOffsetArray, subRuleCount); 259 if (LE_FAILURE(success)) { 260 return 0; 261 } 262 for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) { 263 Offset subRuleTableOffset = 264 SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]); 265 LEReferenceTo<SubRuleTable> 266 subRuleTable(subRuleSetTable, success, subRuleTableOffset); 267 le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1; 268 le_uint16 substCount = SWAPW(subRuleTable->substCount); 269 LEReferenceToArrayOf<TTGlyphID> inputGlyphArray(base, success, subRuleTable->inputGlyphArray, matchCount+2); 270 if (LE_FAILURE(success)) { return 0; } 271 if (matchGlyphIDs(inputGlyphArray, matchCount, glyphIterator)) { 272 LEReferenceToArrayOf<SubstitutionLookupRecord> 273 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount], substCount); 274 275 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 276 277 return matchCount + 1; 278 } 279 280 glyphIterator->setCurrStreamPosition(position); 281 } 282 } 283 284 // XXX If we get here, the table is mal-formed... 285 } 286 287 return 0; 288} 289 290le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference &base, 291 const LookupProcessor *lookupProcessor, 292 GlyphIterator *glyphIterator, 293 const LEFontInstance *fontInstance, 294 LEErrorCode& success) const 295{ 296 if (LE_FAILURE(success)) { 297 return 0; 298 } 299 300 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 301 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 302 if (LE_FAILURE(success)) { 303 return 0; 304 } 305 306 if (coverageIndex >= 0) { 307 LEReferenceTo<ClassDefinitionTable> classDefinitionTable(base, success, 308 (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset))); 309 le_uint16 scSetCount = SWAPW(subClassSetCount); 310 le_int32 setClass = classDefinitionTable->getGlyphClass(classDefinitionTable, 311 glyphIterator->getCurrGlyphID(), 312 success); 313 314 if (setClass < scSetCount) { 315 LEReferenceToArrayOf<Offset> 316 subClassSetTableOffsetArrayRef(base, success, subClassSetTableOffsetArray, setClass); 317 if (LE_FAILURE(success)) { return 0; } 318 if (subClassSetTableOffsetArray[setClass] != 0) { 319 320 Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]); 321 LEReferenceTo<SubClassSetTable> 322 subClassSetTable(base, success, (const SubClassSetTable *) ((char *) this + subClassSetTableOffset)); 323 le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount); 324 le_int32 position = glyphIterator->getCurrStreamPosition(); 325 LEReferenceToArrayOf<Offset> 326 subClassRuleTableOffsetArrayRef(base, success, subClassSetTable->subClassRuleTableOffsetArray, subClassRuleCount); 327 if (LE_FAILURE(success)) { 328 return 0; 329 } 330 for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) { 331 Offset subClassRuleTableOffset = 332 SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]); 333 LEReferenceTo<SubClassRuleTable> 334 subClassRuleTable(subClassSetTable, success, subClassRuleTableOffset); 335 le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1; 336 le_uint16 substCount = SWAPW(subClassRuleTable->substCount); 337 338 LEReferenceToArrayOf<le_uint16> classArray(base, success, subClassRuleTable->classArray, matchCount+1); 339 340 if (LE_FAILURE(success)) { return 0; } 341 if (matchGlyphClasses(classArray, matchCount, glyphIterator, classDefinitionTable, success)) { 342 LEReferenceToArrayOf<SubstitutionLookupRecord> 343 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount], substCount); 344 345 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 346 347 return matchCount + 1; 348 } 349 350 glyphIterator->setCurrStreamPosition(position); 351 } 352 } 353 } 354 355 // XXX If we get here, the table is mal-formed... 356 } 357 358 return 0; 359} 360 361le_uint32 ContextualSubstitutionFormat3Subtable::process(const LETableReference &base, 362 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 le_uint16 gCount = SWAPW(glyphCount); 372 le_uint16 subCount = SWAPW(substCount); 373 le_int32 position = glyphIterator->getCurrStreamPosition(); 374 375 // Back up the glyph iterator so that we 376 // can call next() before the check, which 377 // will leave it pointing at the last glyph 378 // that matched when we're done. 379 glyphIterator->prev(); 380 381 LEReferenceToArrayOf<Offset> covTableOffsetArray(base, success, coverageTableOffsetArray, gCount); 382 383 if( LE_FAILURE(success) ) { return 0; } 384 385 if (ContextualSubstitutionBase::matchGlyphCoverages(covTableOffsetArray, gCount, glyphIterator, base, success)) { 386 LEReferenceToArrayOf<SubstitutionLookupRecord> 387 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount], subCount); 388 389 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success); 390 391 return gCount + 1; 392 } 393 394 glyphIterator->setCurrStreamPosition(position); 395 396 return 0; 397} 398 399le_uint32 ChainingContextualSubstitutionSubtable::process(const LEReferenceTo<ChainingContextualSubstitutionSubtable> &base, 400 const LookupProcessor *lookupProcessor, 401 GlyphIterator *glyphIterator, 402 const LEFontInstance *fontInstance, 403 LEErrorCode& success) const 404{ 405 if (LE_FAILURE(success)) { 406 return 0; 407 } 408 409 switch(SWAPW(subtableFormat)) 410 { 411 case 0: 412 return 0; 413 414 case 1: 415 { 416 LEReferenceTo<ChainingContextualSubstitutionFormat1Subtable> subtable(base, success, (ChainingContextualSubstitutionFormat1Subtable *) this); 417 if(LE_FAILURE(success)) return 0; 418 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 419 } 420 421 case 2: 422 { 423 LEReferenceTo<ChainingContextualSubstitutionFormat2Subtable> subtable(base, success, (const ChainingContextualSubstitutionFormat2Subtable *) this); 424 if( LE_FAILURE(success) ) { return 0; } 425 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 426 } 427 428 case 3: 429 { 430 LEReferenceTo<ChainingContextualSubstitutionFormat3Subtable> subtable(base, success, (const ChainingContextualSubstitutionFormat3Subtable *) this); 431 if( LE_FAILURE(success) ) { return 0; } 432 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 433 } 434 435 default: 436 return 0; 437 } 438} 439 440// NOTE: This could be a #define, but that seems to confuse 441// the Visual Studio .NET 2003 compiler on the calls to the 442// GlyphIterator constructor. It somehow can't decide if 443// emptyFeatureList matches an le_uint32 or an le_uint16... 444static const FeatureMask emptyFeatureList = 0x00000000UL; 445 446le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 447 GlyphIterator *glyphIterator, 448 const LEFontInstance *fontInstance, 449 LEErrorCode& success) const 450{ 451 if (LE_FAILURE(success)) { 452 return 0; 453 } 454 455 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 456 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 457 if (LE_FAILURE(success)) { 458 return 0; 459 } 460 461 if (coverageIndex >= 0) { 462 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); 463 464 if (coverageIndex < srSetCount) { 465 LEReferenceToArrayOf<Offset> 466 chainSubRuleSetTableOffsetArrayRef(base, success, chainSubRuleSetTableOffsetArray, coverageIndex); 467 if (LE_FAILURE(success)) { 468 return 0; 469 } 470 Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]); 471 LEReferenceTo<ChainSubRuleSetTable> 472 chainSubRuleSetTable(base, success, (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset)); 473 le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount); 474 le_int32 position = glyphIterator->getCurrStreamPosition(); 475 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 476 LEReferenceToArrayOf<Offset> 477 chainSubRuleTableOffsetArrayRef(base, success, chainSubRuleSetTable->chainSubRuleTableOffsetArray, chainSubRuleCount); 478 if (LE_FAILURE(success)) { 479 return 0; 480 } 481 for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) { 482 Offset chainSubRuleTableOffset = 483 SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]); 484 LEReferenceTo<ChainSubRuleTable> 485 chainSubRuleTable = LEReferenceTo<ChainSubRuleTable>(chainSubRuleSetTable, success, chainSubRuleTableOffset); 486 if( LE_FAILURE(success) ) { return 0; } 487 le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount); 488 LEReferenceToArrayOf<TTGlyphID> backtrackGlyphArray(base, success, chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount); 489 if( LE_FAILURE(success) ) { return 0; } 490 le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1; 491 LEReferenceToArrayOf<TTGlyphID> inputGlyphArray(base, success, &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1], inputGlyphCount+2); 492 493 if( LE_FAILURE(success) ) { return 0; } 494 le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]); 495 LEReferenceToArrayOf<TTGlyphID> lookaheadGlyphArray(base, success, inputGlyphArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2); 496 if( LE_FAILURE(success) ) { return 0; } 497 le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]); 498 499 tempIterator.setCurrStreamPosition(position); 500 501 if (! tempIterator.prev(backtrackGlyphCount)) { 502 continue; 503 } 504 505 tempIterator.prev(); 506 507 if (! matchGlyphIDs(backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) { 508 continue; 509 } 510 511 tempIterator.setCurrStreamPosition(position); 512 tempIterator.next(inputGlyphCount); 513 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) { 514 continue; 515 } 516 517 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) { 518 LEReferenceToArrayOf<SubstitutionLookupRecord> 519 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadGlyphArray.getAlias(lookaheadGlyphCount + 1,success), substCount); 520 521 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 522 523 return inputGlyphCount + 1; 524 } 525 526 glyphIterator->setCurrStreamPosition(position); 527 } 528 } 529 530 // XXX If we get here, the table is mal-formed... 531 } 532 533 return 0; 534} 535 536le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 537 GlyphIterator *glyphIterator, 538 const LEFontInstance *fontInstance, 539 LEErrorCode& success) const 540{ 541 if (LE_FAILURE(success)) { 542 return 0; 543 } 544 545 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 546 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 547 if (LE_FAILURE(success)) { 548 return 0; 549 } 550 551 if (coverageIndex >= 0) { 552 LEReferenceTo<ClassDefinitionTable> 553 backtrackClassDefinitionTable(base, success, (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset))); 554 LEReferenceTo<ClassDefinitionTable> 555 inputClassDefinitionTable(base, success, (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset))); 556 LEReferenceTo<ClassDefinitionTable> 557 lookaheadClassDefinitionTable(base, success, (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset))); 558 le_uint16 scSetCount = SWAPW(chainSubClassSetCount); 559 le_int32 setClass = inputClassDefinitionTable->getGlyphClass(inputClassDefinitionTable, 560 glyphIterator->getCurrGlyphID(), 561 success); 562 LEReferenceToArrayOf<Offset> 563 chainSubClassSetTableOffsetArrayRef(base, success, chainSubClassSetTableOffsetArray, setClass); 564 if (LE_FAILURE(success)) { 565 return 0; 566 } 567 568 if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) { 569 Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]); 570 LEReferenceTo<ChainSubClassSetTable> 571 chainSubClassSetTable(base, success, (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset)); 572 le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount); 573 le_int32 position = glyphIterator->getCurrStreamPosition(); 574 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 575 LEReferenceToArrayOf<Offset> 576 chainSubClassRuleTableOffsetArrayRef(base, success, chainSubClassSetTable->chainSubClassRuleTableOffsetArray, chainSubClassRuleCount); 577 if (LE_FAILURE(success)) { 578 return 0; 579 } 580 for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) { 581 Offset chainSubClassRuleTableOffset = 582 SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]); 583 LEReferenceTo<ChainSubClassRuleTable> 584 chainSubClassRuleTable(chainSubClassSetTable, success, chainSubClassRuleTableOffset); 585 le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount); 586 LEReferenceToArrayOf<le_uint16> backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount); 587 if( LE_FAILURE(success) ) { return 0; } 588 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1; 589 LEReferenceToArrayOf<le_uint16> inputClassArray(base, success, &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1],inputGlyphCount+2); // +2 for the lookaheadGlyphCount count 590 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray.getObject(inputGlyphCount, success)); 591 LEReferenceToArrayOf<le_uint16> lookaheadClassArray(base, success, inputClassArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2); // +2 for the substCount 592 593 if( LE_FAILURE(success) ) { return 0; } 594 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]); 595 596 597 tempIterator.setCurrStreamPosition(position); 598 599 if (! tempIterator.prev(backtrackGlyphCount)) { 600 continue; 601 } 602 603 tempIterator.prev(); 604 if (! matchGlyphClasses(backtrackClassArray, backtrackGlyphCount, 605 &tempIterator, backtrackClassDefinitionTable, success, TRUE)) { 606 continue; 607 } 608 609 tempIterator.setCurrStreamPosition(position); 610 tempIterator.next(inputGlyphCount); 611 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable, success)) { 612 continue; 613 } 614 615 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable, success)) { 616 LEReferenceToArrayOf<SubstitutionLookupRecord> 617 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadClassArray.getAlias(lookaheadGlyphCount + 1, success), substCount); 618 if (LE_FAILURE(success)) { return 0; } 619 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 620 621 return inputGlyphCount + 1; 622 } 623 624 glyphIterator->setCurrStreamPosition(position); 625 } 626 } 627 628 // XXX If we get here, the table is mal-formed... 629 } 630 631 return 0; 632} 633 634le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 635 GlyphIterator *glyphIterator, 636 const LEFontInstance *fontInstance, 637 LEErrorCode & success) const 638{ 639 if (LE_FAILURE(success)) { 640 return 0; 641 } 642 643 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount); 644 LEReferenceToArrayOf<Offset> backtrackGlyphArrayRef(base, success, backtrackCoverageTableOffsetArray, backtrkGlyphCount); 645 if (LE_FAILURE(success)) { 646 return 0; 647 } 648 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]); 649 LEReferenceToArrayOf<Offset> inputCoverageTableOffsetArray(base, success, &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1], inputGlyphCount+2); // offset 650 if (LE_FAILURE(success)) { return 0; } 651 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]); 652 LEReferenceToArrayOf<Offset> lookaheadCoverageTableOffsetArray(base, success, inputCoverageTableOffsetArray.getAlias(inputGlyphCount + 1, success), lookaheadGlyphCount+2); 653 654 if( LE_FAILURE(success) ) { return 0; } 655 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]); 656 le_int32 position = glyphIterator->getCurrStreamPosition(); 657 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 658 659 if (! tempIterator.prev(backtrkGlyphCount)) { 660 return 0; 661 } 662 663 tempIterator.prev(); 664 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray, 665 backtrkGlyphCount, &tempIterator, base, success, TRUE)) { 666 return 0; 667 } 668 669 tempIterator.setCurrStreamPosition(position); 670 tempIterator.next(inputGlyphCount - 1); 671 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray, 672 lookaheadGlyphCount, &tempIterator, base, success)) { 673 return 0; 674 } 675 676 // Back up the glyph iterator so that we 677 // can call next() before the check, which 678 // will leave it pointing at the last glyph 679 // that matched when we're done. 680 glyphIterator->prev(); 681 682 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray, 683 inputGlyphCount, glyphIterator, base, success)) { 684 LEReferenceToArrayOf<SubstitutionLookupRecord> 685 substLookupRecordArray(base, success, 686 (const SubstitutionLookupRecord *) lookaheadCoverageTableOffsetArray.getAlias(lookaheadGlyphCount + 1,success), substCount); 687 688 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 689 690 return inputGlyphCount; 691 } 692 693 glyphIterator->setCurrStreamPosition(position); 694 695 return 0; 696} 697 698U_NAMESPACE_END 699