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> 247 subRuleSetTableOffsetArrayRef(base, success, subRuleSetTableOffsetArray, srSetCount); 248 if (LE_FAILURE(success)) { 249 return 0; 250 } 251 Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]); 252 LEReferenceTo<SubRuleSetTable> subRuleSetTable(base, success, subRuleSetTableOffset); 253 if (LE_FAILURE(success)) { return 0; } 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 if (LE_FAILURE(success)) { return 0; } 268 le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1; 269 le_uint16 substCount = SWAPW(subRuleTable->substCount); 270 LEReferenceToArrayOf<TTGlyphID> inputGlyphArray(base, success, subRuleTable->inputGlyphArray, matchCount+2); 271 if (LE_FAILURE(success)) { return 0; } 272 if (matchGlyphIDs(inputGlyphArray, matchCount, glyphIterator)) { 273 LEReferenceToArrayOf<SubstitutionLookupRecord> 274 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount], substCount); 275 276 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 277 278 return matchCount + 1; 279 } 280 281 glyphIterator->setCurrStreamPosition(position); 282 } 283 } 284 285 // XXX If we get here, the table is mal-formed... 286 } 287 288 return 0; 289} 290 291le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference &base, 292 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 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 302 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 303 if (LE_FAILURE(success)) { 304 return 0; 305 } 306 307 if (coverageIndex >= 0) { 308 LEReferenceTo<ClassDefinitionTable> classDefinitionTable(base, success, SWAPW(classDefTableOffset)); 309 if (LE_FAILURE(success)) { return 0; } 310 le_uint16 scSetCount = SWAPW(subClassSetCount); 311 le_int32 setClass = classDefinitionTable->getGlyphClass(classDefinitionTable, 312 glyphIterator->getCurrGlyphID(), 313 success); 314 315 if (setClass < scSetCount) { 316 LEReferenceToArrayOf<Offset> 317 subClassSetTableOffsetArrayRef(base, success, subClassSetTableOffsetArray, scSetCount); 318 if (LE_FAILURE(success)) { return 0; } 319 if (subClassSetTableOffsetArray[setClass] != 0) { 320 321 Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]); 322 LEReferenceTo<SubClassSetTable> subClassSetTable(base, success, subClassSetTableOffset); 323 if (LE_FAILURE(success)) { return 0; } 324 le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount); 325 le_int32 position = glyphIterator->getCurrStreamPosition(); 326 LEReferenceToArrayOf<Offset> 327 subClassRuleTableOffsetArrayRef(base, success, subClassSetTable->subClassRuleTableOffsetArray, subClassRuleCount); 328 if (LE_FAILURE(success)) { 329 return 0; 330 } 331 for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) { 332 Offset subClassRuleTableOffset = 333 SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]); 334 LEReferenceTo<SubClassRuleTable> 335 subClassRuleTable(subClassSetTable, success, subClassRuleTableOffset); 336 if (LE_FAILURE(success)) { return 0; } 337 le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1; 338 le_uint16 substCount = SWAPW(subClassRuleTable->substCount); 339 340 LEReferenceToArrayOf<le_uint16> classArray(base, success, subClassRuleTable->classArray, matchCount+1); 341 342 if (LE_FAILURE(success)) { return 0; } 343 if (matchGlyphClasses(classArray, matchCount, glyphIterator, classDefinitionTable, success)) { 344 LEReferenceToArrayOf<SubstitutionLookupRecord> 345 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount], substCount); 346 347 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 348 349 return matchCount + 1; 350 } 351 352 glyphIterator->setCurrStreamPosition(position); 353 } 354 } 355 } 356 357 // XXX If we get here, the table is mal-formed... 358 } 359 360 return 0; 361} 362 363le_uint32 ContextualSubstitutionFormat3Subtable::process(const LETableReference &base, 364 const LookupProcessor *lookupProcessor, 365 GlyphIterator *glyphIterator, 366 const LEFontInstance *fontInstance, 367 LEErrorCode& success)const 368{ 369 if (LE_FAILURE(success)) { 370 return 0; 371 } 372 373 le_uint16 gCount = SWAPW(glyphCount); 374 le_uint16 subCount = SWAPW(substCount); 375 le_int32 position = glyphIterator->getCurrStreamPosition(); 376 377 // Back up the glyph iterator so that we 378 // can call next() before the check, which 379 // will leave it pointing at the last glyph 380 // that matched when we're done. 381 glyphIterator->prev(); 382 383 LEReferenceToArrayOf<Offset> covTableOffsetArray(base, success, coverageTableOffsetArray, gCount); 384 385 if( LE_FAILURE(success) ) { return 0; } 386 387 if (ContextualSubstitutionBase::matchGlyphCoverages(covTableOffsetArray, gCount, glyphIterator, base, success)) { 388 LEReferenceToArrayOf<SubstitutionLookupRecord> 389 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount], subCount); 390 391 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success); 392 393 return gCount + 1; 394 } 395 396 glyphIterator->setCurrStreamPosition(position); 397 398 return 0; 399} 400 401le_uint32 ChainingContextualSubstitutionSubtable::process(const LEReferenceTo<ChainingContextualSubstitutionSubtable> &base, 402 const LookupProcessor *lookupProcessor, 403 GlyphIterator *glyphIterator, 404 const LEFontInstance *fontInstance, 405 LEErrorCode& success) const 406{ 407 if (LE_FAILURE(success)) { 408 return 0; 409 } 410 411 switch(SWAPW(subtableFormat)) 412 { 413 case 0: 414 return 0; 415 416 case 1: 417 { 418 LEReferenceTo<ChainingContextualSubstitutionFormat1Subtable> subtable(base, success, (ChainingContextualSubstitutionFormat1Subtable *) this); 419 if(LE_FAILURE(success)) return 0; 420 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 421 } 422 423 case 2: 424 { 425 LEReferenceTo<ChainingContextualSubstitutionFormat2Subtable> subtable(base, success, (const ChainingContextualSubstitutionFormat2Subtable *) this); 426 if( LE_FAILURE(success) ) { return 0; } 427 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 428 } 429 430 case 3: 431 { 432 LEReferenceTo<ChainingContextualSubstitutionFormat3Subtable> subtable(base, success, (const ChainingContextualSubstitutionFormat3Subtable *) this); 433 if( LE_FAILURE(success) ) { return 0; } 434 return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success); 435 } 436 437 default: 438 return 0; 439 } 440} 441 442// NOTE: This could be a #define, but that seems to confuse 443// the Visual Studio .NET 2003 compiler on the calls to the 444// GlyphIterator constructor. It somehow can't decide if 445// emptyFeatureList matches an le_uint32 or an le_uint16... 446static const FeatureMask emptyFeatureList = 0x00000000UL; 447 448le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 449 GlyphIterator *glyphIterator, 450 const LEFontInstance *fontInstance, 451 LEErrorCode& success) const 452{ 453 if (LE_FAILURE(success)) { 454 return 0; 455 } 456 457 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 458 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 459 if (LE_FAILURE(success)) { 460 return 0; 461 } 462 463 if (coverageIndex >= 0) { 464 le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); 465 466 if (coverageIndex < srSetCount) { 467 LEReferenceToArrayOf<Offset> 468 chainSubRuleSetTableOffsetArrayRef(base, success, chainSubRuleSetTableOffsetArray, srSetCount); 469 if (LE_FAILURE(success)) { 470 return 0; 471 } 472 Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]); 473 LEReferenceTo<ChainSubRuleSetTable> chainSubRuleSetTable(base, success, chainSubRuleSetTableOffset); 474 if (LE_FAILURE(success)) { return 0; } 475 le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount); 476 le_int32 position = glyphIterator->getCurrStreamPosition(); 477 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 478 LEReferenceToArrayOf<Offset> 479 chainSubRuleTableOffsetArrayRef(base, success, chainSubRuleSetTable->chainSubRuleTableOffsetArray, chainSubRuleCount); 480 if (LE_FAILURE(success)) { 481 return 0; 482 } 483 for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) { 484 Offset chainSubRuleTableOffset = 485 SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]); 486 LEReferenceTo<ChainSubRuleTable> 487 chainSubRuleTable = LEReferenceTo<ChainSubRuleTable>(chainSubRuleSetTable, success, chainSubRuleTableOffset); 488 if( LE_FAILURE(success) ) { return 0; } 489 le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount); 490 LEReferenceToArrayOf<TTGlyphID> backtrackGlyphArray(base, success, chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount); 491 if( LE_FAILURE(success) ) { return 0; } 492 le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1; 493 LEReferenceToArrayOf<TTGlyphID> inputGlyphArray(base, success, &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1], inputGlyphCount+2); 494 495 if( LE_FAILURE(success) ) { return 0; } 496 le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]); 497 LEReferenceToArrayOf<TTGlyphID> lookaheadGlyphArray(base, success, inputGlyphArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2); 498 if( LE_FAILURE(success) ) { return 0; } 499 le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]); 500 501 tempIterator.setCurrStreamPosition(position); 502 503 if (! tempIterator.prev(backtrackGlyphCount)) { 504 continue; 505 } 506 507 tempIterator.prev(); 508 509 if (! matchGlyphIDs(backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) { 510 continue; 511 } 512 513 tempIterator.setCurrStreamPosition(position); 514 tempIterator.next(inputGlyphCount); 515 if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) { 516 continue; 517 } 518 519 if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) { 520 LEReferenceToArrayOf<SubstitutionLookupRecord> 521 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadGlyphArray.getAlias(lookaheadGlyphCount + 1,success), substCount); 522 523 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 524 525 return inputGlyphCount + 1; 526 } 527 528 glyphIterator->setCurrStreamPosition(position); 529 } 530 } 531 532 // XXX If we get here, the table is mal-formed... 533 } 534 535 return 0; 536} 537 538le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 539 GlyphIterator *glyphIterator, 540 const LEFontInstance *fontInstance, 541 LEErrorCode& success) const 542{ 543 if (LE_FAILURE(success)) { 544 return 0; 545 } 546 547 LEGlyphID glyph = glyphIterator->getCurrGlyphID(); 548 le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success); 549 if (LE_FAILURE(success)) { 550 return 0; 551 } 552 553 if (coverageIndex >= 0) { 554 LEReferenceTo<ClassDefinitionTable> 555 backtrackClassDefinitionTable(base, success, SWAPW(backtrackClassDefTableOffset)); 556 LEReferenceTo<ClassDefinitionTable> 557 inputClassDefinitionTable(base, success, SWAPW(inputClassDefTableOffset)); 558 LEReferenceTo<ClassDefinitionTable> 559 lookaheadClassDefinitionTable(base, success, SWAPW(lookaheadClassDefTableOffset)); 560 le_uint16 scSetCount = SWAPW(chainSubClassSetCount); 561 le_int32 setClass = inputClassDefinitionTable->getGlyphClass(inputClassDefinitionTable, 562 glyphIterator->getCurrGlyphID(), 563 success); 564 LEReferenceToArrayOf<Offset> 565 chainSubClassSetTableOffsetArrayRef(base, success, chainSubClassSetTableOffsetArray, scSetCount); 566 if (LE_FAILURE(success)) { 567 return 0; 568 } 569 570 if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) { 571 Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]); 572 LEReferenceTo<ChainSubClassSetTable> 573 chainSubClassSetTable(base, success, chainSubClassSetTableOffset); 574 if (LE_FAILURE(success)) { return 0; } 575 le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount); 576 le_int32 position = glyphIterator->getCurrStreamPosition(); 577 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 578 LEReferenceToArrayOf<Offset> 579 chainSubClassRuleTableOffsetArrayRef(base, success, chainSubClassSetTable->chainSubClassRuleTableOffsetArray, chainSubClassRuleCount); 580 if (LE_FAILURE(success)) { 581 return 0; 582 } 583 for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) { 584 Offset chainSubClassRuleTableOffset = 585 SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]); 586 LEReferenceTo<ChainSubClassRuleTable> 587 chainSubClassRuleTable(chainSubClassSetTable, success, chainSubClassRuleTableOffset); 588 if (LE_FAILURE(success)) { return 0; } 589 le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount); 590 LEReferenceToArrayOf<le_uint16> backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount); 591 if( LE_FAILURE(success) ) { return 0; } 592 le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1; 593 LEReferenceToArrayOf<le_uint16> inputClassArray(base, success, &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1],inputGlyphCount+2); // +2 for the lookaheadGlyphCount count 594 le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray.getObject(inputGlyphCount, success)); 595 LEReferenceToArrayOf<le_uint16> lookaheadClassArray(base, success, inputClassArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2); // +2 for the substCount 596 597 if( LE_FAILURE(success) ) { return 0; } 598 le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]); 599 600 601 tempIterator.setCurrStreamPosition(position); 602 603 if (! tempIterator.prev(backtrackGlyphCount)) { 604 continue; 605 } 606 607 tempIterator.prev(); 608 if (! matchGlyphClasses(backtrackClassArray, backtrackGlyphCount, 609 &tempIterator, backtrackClassDefinitionTable, success, TRUE)) { 610 continue; 611 } 612 613 tempIterator.setCurrStreamPosition(position); 614 tempIterator.next(inputGlyphCount); 615 if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable, success)) { 616 continue; 617 } 618 619 if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable, success)) { 620 LEReferenceToArrayOf<SubstitutionLookupRecord> 621 substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadClassArray.getAlias(lookaheadGlyphCount + 1, success), substCount); 622 if (LE_FAILURE(success)) { return 0; } 623 applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 624 625 return inputGlyphCount + 1; 626 } 627 628 glyphIterator->setCurrStreamPosition(position); 629 } 630 } 631 632 // XXX If we get here, the table is mal-formed... 633 } 634 635 return 0; 636} 637 638le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor, 639 GlyphIterator *glyphIterator, 640 const LEFontInstance *fontInstance, 641 LEErrorCode & success) const 642{ 643 if (LE_FAILURE(success)) { 644 return 0; 645 } 646 647 le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount); 648 LEReferenceToArrayOf<Offset> backtrackGlyphArrayRef(base, success, backtrackCoverageTableOffsetArray, backtrkGlyphCount); 649 if (LE_FAILURE(success)) { 650 return 0; 651 } 652 le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]); 653 LEReferenceToArrayOf<Offset> inputCoverageTableOffsetArray(base, success, &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1], inputGlyphCount+2); // offset 654 if (LE_FAILURE(success)) { return 0; } 655 const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]); 656 LEReferenceToArrayOf<Offset> lookaheadCoverageTableOffsetArray(base, success, inputCoverageTableOffsetArray.getAlias(inputGlyphCount + 1, success), lookaheadGlyphCount+2); 657 658 if( LE_FAILURE(success) ) { return 0; } 659 le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]); 660 le_int32 position = glyphIterator->getCurrStreamPosition(); 661 GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); 662 663 if (! tempIterator.prev(backtrkGlyphCount)) { 664 return 0; 665 } 666 667 tempIterator.prev(); 668 if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray, 669 backtrkGlyphCount, &tempIterator, base, success, TRUE)) { 670 return 0; 671 } 672 673 tempIterator.setCurrStreamPosition(position); 674 tempIterator.next(inputGlyphCount - 1); 675 if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray, 676 lookaheadGlyphCount, &tempIterator, base, success)) { 677 return 0; 678 } 679 680 // Back up the glyph iterator so that we 681 // can call next() before the check, which 682 // will leave it pointing at the last glyph 683 // that matched when we're done. 684 glyphIterator->prev(); 685 686 if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray, 687 inputGlyphCount, glyphIterator, base, success)) { 688 LEReferenceToArrayOf<SubstitutionLookupRecord> 689 substLookupRecordArray(base, success, 690 (const SubstitutionLookupRecord *) lookaheadCoverageTableOffsetArray.getAlias(lookaheadGlyphCount + 1,success), substCount); 691 692 ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); 693 694 return inputGlyphCount; 695 } 696 697 glyphIterator->setCurrStreamPosition(position); 698 699 return 0; 700} 701 702U_NAMESPACE_END 703