Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp
38918 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425/*26* (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved27*28*/2930#include "LETypes.h"31#include "LEFontInstance.h"32#include "OpenTypeTables.h"33#include "GlyphSubstitutionTables.h"34#include "ContextualSubstSubtables.h"35#include "GlyphIterator.h"36#include "LookupProcessor.h"37#include "CoverageTables.h"38#include "LESwaps.h"3940U_NAMESPACE_BEGIN4142/*43NOTE: This could be optimized somewhat by keeping track44of the previous sequenceIndex in the loop and doing next()45or prev() of the delta between that and the current46sequenceIndex instead of always resetting to the front.47*/48void ContextualSubstitutionBase::applySubstitutionLookups(49const LookupProcessor *lookupProcessor,50const LEReferenceToArrayOf<SubstitutionLookupRecord>& substLookupRecordArray,51le_uint16 substCount,52GlyphIterator *glyphIterator,53const LEFontInstance *fontInstance,54le_int32 position,55LEErrorCode& success)56{57if (LE_FAILURE(success)) {58return;59}6061GlyphIterator tempIterator(*glyphIterator);62const SubstitutionLookupRecord *substLookupRecordArrayPtr = substLookupRecordArray.getAlias(); // OK to dereference, range checked against substCount below.6364for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {65le_uint16 sequenceIndex = SWAPW(substLookupRecordArrayPtr[subst].sequenceIndex);66le_uint16 lookupListIndex = SWAPW(substLookupRecordArrayPtr[subst].lookupListIndex);6768tempIterator.setCurrStreamPosition(position);69if (!tempIterator.next(sequenceIndex)) {70success = LE_INTERNAL_ERROR;71return;72}7374lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);75}76}7778le_bool ContextualSubstitutionBase::matchGlyphIDs(const LEReferenceToArrayOf<TTGlyphID>& glyphArray, le_uint16 glyphCount,79GlyphIterator *glyphIterator, le_bool backtrack)80{81le_int32 direction = 1;82le_int32 match = 0;8384if (backtrack) {85match = glyphCount -1;86direction = -1;87}8889while (glyphCount > 0) {90if (! glyphIterator->next()) {91return FALSE;92}9394TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();9596if (glyph != SWAPW(glyphArray[match])) {97return FALSE;98}99100glyphCount -= 1;101match += direction;102}103104return TRUE;105}106107le_bool ContextualSubstitutionBase::matchGlyphClasses(108const LEReferenceToArrayOf<le_uint16> &classArray,109le_uint16 glyphCount,110GlyphIterator *glyphIterator,111const LEReferenceTo<ClassDefinitionTable> &classDefinitionTable,112LEErrorCode &success,113le_bool backtrack)114{115if (LE_FAILURE(success)) { return FALSE; }116117le_int32 direction = 1;118le_int32 match = 0;119120if (backtrack) {121match = glyphCount - 1;122direction = -1;123}124125while (glyphCount > 0) {126if (! glyphIterator->next()) {127return FALSE;128}129130LEGlyphID glyph = glyphIterator->getCurrGlyphID();131le_int32 glyphClass = classDefinitionTable->getGlyphClass(classDefinitionTable, glyph, success);132le_int32 matchClass = SWAPW(classArray[match]);133134if (glyphClass != matchClass) {135// Some fonts, e.g. Traditional Arabic, have classes136// in the class array which aren't in the class definition137// table. If we're looking for such a class, pretend that138// we found it.139if (classDefinitionTable->hasGlyphClass(classDefinitionTable, matchClass, success)) {140return FALSE;141}142}143144glyphCount -= 1;145match += direction;146}147148return TRUE;149}150151le_bool ContextualSubstitutionBase::matchGlyphCoverages(const LEReferenceToArrayOf<Offset> &coverageTableOffsetArray, le_uint16 glyphCount,152GlyphIterator *glyphIterator, const LETableReference &offsetBase, LEErrorCode &success, le_bool backtrack)153{154le_int32 direction = 1;155le_int32 glyph = 0;156157if (backtrack) {158glyph = glyphCount - 1;159direction = -1;160}161162while (glyphCount > 0) {163Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);164LEReferenceTo<CoverageTable> coverageTable(offsetBase, success, coverageTableOffset);165166if (LE_FAILURE(success) || ! glyphIterator->next()) {167return FALSE;168}169170if (coverageTable->getGlyphCoverage(coverageTable,171(LEGlyphID) glyphIterator->getCurrGlyphID(),172success) < 0) {173return FALSE;174}175176glyphCount -= 1;177glyph += direction;178}179180return TRUE;181}182183le_uint32 ContextualSubstitutionSubtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor,184GlyphIterator *glyphIterator,185const LEFontInstance *fontInstance,186LEErrorCode& success) const187{188if (LE_FAILURE(success)) {189return 0;190}191192switch(SWAPW(subtableFormat))193{194case 0:195return 0;196197case 1:198{199LEReferenceTo<ContextualSubstitutionFormat1Subtable> subtable(base, success, (const ContextualSubstitutionFormat1Subtable *) this);200if( LE_FAILURE(success) ) {201return 0;202}203return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success);204}205206case 2:207{208LEReferenceTo<ContextualSubstitutionFormat2Subtable> subtable(base, success, (const ContextualSubstitutionFormat2Subtable *) this);209if( LE_FAILURE(success) ) {210return 0;211}212return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success);213}214215case 3:216{217LEReferenceTo<ContextualSubstitutionFormat3Subtable> subtable(base, success, (const ContextualSubstitutionFormat3Subtable *) this);218if( LE_FAILURE(success) ) {219return 0;220}221return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success);222}223224default:225return 0;226}227}228229le_uint32 ContextualSubstitutionFormat1Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor,230GlyphIterator *glyphIterator,231const LEFontInstance *fontInstance,232LEErrorCode& success) const233{234if (LE_FAILURE(success)) {235return 0;236}237238LEGlyphID glyph = glyphIterator->getCurrGlyphID();239le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);240if (LE_FAILURE(success)) {241return 0;242}243244if (coverageIndex >= 0) {245le_uint16 srSetCount = SWAPW(subRuleSetCount);246247if (coverageIndex < srSetCount) {248LEReferenceToArrayOf<Offset>249subRuleSetTableOffsetArrayRef(base, success, subRuleSetTableOffsetArray, srSetCount);250if (LE_FAILURE(success)) {251return 0;252}253Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);254LEReferenceTo<SubRuleSetTable> subRuleSetTable(base, success, subRuleSetTableOffset);255if (LE_FAILURE(success)) { return 0; }256le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);257le_int32 position = glyphIterator->getCurrStreamPosition();258259LEReferenceToArrayOf<Offset> subRuleTableOffsetArrayRef(base, success,260subRuleSetTable->subRuleTableOffsetArray, subRuleCount);261if (LE_FAILURE(success)) {262return 0;263}264for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {265Offset subRuleTableOffset =266SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);267LEReferenceTo<SubRuleTable>268subRuleTable(subRuleSetTable, success, subRuleTableOffset);269if (LE_FAILURE(success)) { return 0; }270le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;271le_uint16 substCount = SWAPW(subRuleTable->substCount);272LEReferenceToArrayOf<TTGlyphID> inputGlyphArray(base, success, subRuleTable->inputGlyphArray, matchCount+2);273if (LE_FAILURE(success)) { return 0; }274if (matchGlyphIDs(inputGlyphArray, matchCount, glyphIterator)) {275LEReferenceToArrayOf<SubstitutionLookupRecord>276substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount], substCount);277278applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);279280return matchCount + 1;281}282283glyphIterator->setCurrStreamPosition(position);284}285}286287// XXX If we get here, the table is mal-formed...288}289290return 0;291}292293le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference &base,294const LookupProcessor *lookupProcessor,295GlyphIterator *glyphIterator,296const LEFontInstance *fontInstance,297LEErrorCode& success) const298{299if (LE_FAILURE(success)) {300return 0;301}302303LEGlyphID glyph = glyphIterator->getCurrGlyphID();304le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);305if (LE_FAILURE(success)) {306return 0;307}308309if (coverageIndex >= 0) {310LEReferenceTo<ClassDefinitionTable> classDefinitionTable(base, success, SWAPW(classDefTableOffset));311if (LE_FAILURE(success)) { return 0; }312le_uint16 scSetCount = SWAPW(subClassSetCount);313le_int32 setClass = classDefinitionTable->getGlyphClass(classDefinitionTable,314glyphIterator->getCurrGlyphID(),315success);316317if (setClass < scSetCount) {318LEReferenceToArrayOf<Offset>319subClassSetTableOffsetArrayRef(base, success, subClassSetTableOffsetArray, scSetCount);320if (LE_FAILURE(success)) { return 0; }321if (subClassSetTableOffsetArray[setClass] != 0) {322323Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);324LEReferenceTo<SubClassSetTable> subClassSetTable(base, success, subClassSetTableOffset);325if (LE_FAILURE(success)) { return 0; }326le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);327le_int32 position = glyphIterator->getCurrStreamPosition();328LEReferenceToArrayOf<Offset>329subClassRuleTableOffsetArrayRef(base, success, subClassSetTable->subClassRuleTableOffsetArray, subClassRuleCount);330if (LE_FAILURE(success)) {331return 0;332}333for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {334Offset subClassRuleTableOffset =335SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);336LEReferenceTo<SubClassRuleTable>337subClassRuleTable(subClassSetTable, success, subClassRuleTableOffset);338if (LE_FAILURE(success)) { return 0; }339le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;340le_uint16 substCount = SWAPW(subClassRuleTable->substCount);341342LEReferenceToArrayOf<le_uint16> classArray(base, success, subClassRuleTable->classArray, matchCount+1);343344if (LE_FAILURE(success)) { return 0; }345if (matchGlyphClasses(classArray, matchCount, glyphIterator, classDefinitionTable, success)) {346LEReferenceToArrayOf<SubstitutionLookupRecord>347substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount], substCount);348349applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);350351return matchCount + 1;352}353354glyphIterator->setCurrStreamPosition(position);355}356}357}358359// XXX If we get here, the table is mal-formed...360}361362return 0;363}364365le_uint32 ContextualSubstitutionFormat3Subtable::process(const LETableReference &base,366const LookupProcessor *lookupProcessor,367GlyphIterator *glyphIterator,368const LEFontInstance *fontInstance,369LEErrorCode& success)const370{371if (LE_FAILURE(success)) {372return 0;373}374375le_uint16 gCount = SWAPW(glyphCount);376le_uint16 subCount = SWAPW(substCount);377le_int32 position = glyphIterator->getCurrStreamPosition();378379// Back up the glyph iterator so that we380// can call next() before the check, which381// will leave it pointing at the last glyph382// that matched when we're done.383glyphIterator->prev();384385LEReferenceToArrayOf<Offset> covTableOffsetArray(base, success, coverageTableOffsetArray, gCount);386387if( LE_FAILURE(success) ) { return 0; }388389if (ContextualSubstitutionBase::matchGlyphCoverages(covTableOffsetArray, gCount, glyphIterator, base, success)) {390LEReferenceToArrayOf<SubstitutionLookupRecord>391substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount], subCount);392393ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success);394395return gCount + 1;396}397398glyphIterator->setCurrStreamPosition(position);399400return 0;401}402403le_uint32 ChainingContextualSubstitutionSubtable::process(const LEReferenceTo<ChainingContextualSubstitutionSubtable> &base,404const LookupProcessor *lookupProcessor,405GlyphIterator *glyphIterator,406const LEFontInstance *fontInstance,407LEErrorCode& success) const408{409if (LE_FAILURE(success)) {410return 0;411}412413switch(SWAPW(subtableFormat))414{415case 0:416return 0;417418case 1:419{420LEReferenceTo<ChainingContextualSubstitutionFormat1Subtable> subtable(base, success, (ChainingContextualSubstitutionFormat1Subtable *) this);421if(LE_FAILURE(success)) return 0;422return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success);423}424425case 2:426{427LEReferenceTo<ChainingContextualSubstitutionFormat2Subtable> subtable(base, success, (const ChainingContextualSubstitutionFormat2Subtable *) this);428if( LE_FAILURE(success) ) { return 0; }429return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success);430}431432case 3:433{434LEReferenceTo<ChainingContextualSubstitutionFormat3Subtable> subtable(base, success, (const ChainingContextualSubstitutionFormat3Subtable *) this);435if( LE_FAILURE(success) ) { return 0; }436return subtable->process(subtable, lookupProcessor, glyphIterator, fontInstance, success);437}438439default:440return 0;441}442}443444// NOTE: This could be a #define, but that seems to confuse445// the Visual Studio .NET 2003 compiler on the calls to the446// GlyphIterator constructor. It somehow can't decide if447// emptyFeatureList matches an le_uint32 or an le_uint16...448static const FeatureMask emptyFeatureList = 0x00000000UL;449450le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor,451GlyphIterator *glyphIterator,452const LEFontInstance *fontInstance,453LEErrorCode& success) const454{455if (LE_FAILURE(success)) {456return 0;457}458459LEGlyphID glyph = glyphIterator->getCurrGlyphID();460le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);461if (LE_FAILURE(success)) {462return 0;463}464465if (coverageIndex >= 0) {466le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);467468if (coverageIndex < srSetCount) {469LEReferenceToArrayOf<Offset>470chainSubRuleSetTableOffsetArrayRef(base, success, chainSubRuleSetTableOffsetArray, srSetCount);471if (LE_FAILURE(success)) {472return 0;473}474Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);475LEReferenceTo<ChainSubRuleSetTable> chainSubRuleSetTable(base, success, chainSubRuleSetTableOffset);476if (LE_FAILURE(success)) { return 0; }477le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);478le_int32 position = glyphIterator->getCurrStreamPosition();479GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);480LEReferenceToArrayOf<Offset>481chainSubRuleTableOffsetArrayRef(base, success, chainSubRuleSetTable->chainSubRuleTableOffsetArray, chainSubRuleCount);482if (LE_FAILURE(success)) {483return 0;484}485for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {486Offset chainSubRuleTableOffset =487SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);488LEReferenceTo<ChainSubRuleTable>489chainSubRuleTable = LEReferenceTo<ChainSubRuleTable>(chainSubRuleSetTable, success, chainSubRuleTableOffset);490if( LE_FAILURE(success) ) { return 0; }491le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);492LEReferenceToArrayOf<TTGlyphID> backtrackGlyphArray(base, success, chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount);493if( LE_FAILURE(success) ) { return 0; }494le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;495LEReferenceToArrayOf<TTGlyphID> inputGlyphArray(base, success, &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1], inputGlyphCount+2);496497if( LE_FAILURE(success) ) { return 0; }498le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);499LEReferenceToArrayOf<TTGlyphID> lookaheadGlyphArray(base, success, inputGlyphArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2);500if( LE_FAILURE(success) ) { return 0; }501le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);502503tempIterator.setCurrStreamPosition(position);504505if (! tempIterator.prev(backtrackGlyphCount)) {506continue;507}508509tempIterator.prev();510511if (! matchGlyphIDs(backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {512continue;513}514515tempIterator.setCurrStreamPosition(position);516tempIterator.next(inputGlyphCount);517if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {518continue;519}520521if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {522LEReferenceToArrayOf<SubstitutionLookupRecord>523substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadGlyphArray.getAlias(lookaheadGlyphCount + 1,success), substCount);524525applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);526527return inputGlyphCount + 1;528}529530glyphIterator->setCurrStreamPosition(position);531}532}533534// XXX If we get here, the table is mal-formed...535}536537return 0;538}539540le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor,541GlyphIterator *glyphIterator,542const LEFontInstance *fontInstance,543LEErrorCode& success) const544{545if (LE_FAILURE(success)) {546return 0;547}548549LEGlyphID glyph = glyphIterator->getCurrGlyphID();550le_int32 coverageIndex = getGlyphCoverage(lookupProcessor->getReference(), glyph, success);551if (LE_FAILURE(success)) {552return 0;553}554555if (coverageIndex >= 0) {556LEReferenceTo<ClassDefinitionTable>557backtrackClassDefinitionTable(base, success, SWAPW(backtrackClassDefTableOffset));558LEReferenceTo<ClassDefinitionTable>559inputClassDefinitionTable(base, success, SWAPW(inputClassDefTableOffset));560LEReferenceTo<ClassDefinitionTable>561lookaheadClassDefinitionTable(base, success, SWAPW(lookaheadClassDefTableOffset));562le_uint16 scSetCount = SWAPW(chainSubClassSetCount);563le_int32 setClass = inputClassDefinitionTable->getGlyphClass(inputClassDefinitionTable,564glyphIterator->getCurrGlyphID(),565success);566LEReferenceToArrayOf<Offset>567chainSubClassSetTableOffsetArrayRef(base, success, chainSubClassSetTableOffsetArray, scSetCount);568if (LE_FAILURE(success)) {569return 0;570}571572if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {573Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);574LEReferenceTo<ChainSubClassSetTable>575chainSubClassSetTable(base, success, chainSubClassSetTableOffset);576if (LE_FAILURE(success)) { return 0; }577le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);578le_int32 position = glyphIterator->getCurrStreamPosition();579GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);580LEReferenceToArrayOf<Offset>581chainSubClassRuleTableOffsetArrayRef(base, success, chainSubClassSetTable->chainSubClassRuleTableOffsetArray, chainSubClassRuleCount);582if (LE_FAILURE(success)) {583return 0;584}585for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {586Offset chainSubClassRuleTableOffset =587SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);588LEReferenceTo<ChainSubClassRuleTable>589chainSubClassRuleTable(chainSubClassSetTable, success, chainSubClassRuleTableOffset);590if (LE_FAILURE(success)) { return 0; }591le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);592LEReferenceToArrayOf<le_uint16> backtrackClassArray(base, success, chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount);593if( LE_FAILURE(success) ) { return 0; }594le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;595LEReferenceToArrayOf<le_uint16> inputClassArray(base, success, &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1],inputGlyphCount+2); // +2 for the lookaheadGlyphCount count596le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray.getObject(inputGlyphCount, success));597LEReferenceToArrayOf<le_uint16> lookaheadClassArray(base, success, inputClassArray.getAlias(inputGlyphCount + 1,success), lookaheadGlyphCount+2); // +2 for the substCount598599if( LE_FAILURE(success) ) { return 0; }600le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);601602603tempIterator.setCurrStreamPosition(position);604605if (! tempIterator.prev(backtrackGlyphCount)) {606continue;607}608609tempIterator.prev();610if (! matchGlyphClasses(backtrackClassArray, backtrackGlyphCount,611&tempIterator, backtrackClassDefinitionTable, success, TRUE)) {612continue;613}614615tempIterator.setCurrStreamPosition(position);616tempIterator.next(inputGlyphCount);617if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable, success)) {618continue;619}620621if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable, success)) {622LEReferenceToArrayOf<SubstitutionLookupRecord>623substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadClassArray.getAlias(lookaheadGlyphCount + 1, success), substCount);624if (LE_FAILURE(success)) { return 0; }625applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);626627return inputGlyphCount + 1;628}629630glyphIterator->setCurrStreamPosition(position);631}632}633634// XXX If we get here, the table is mal-formed...635}636637return 0;638}639640le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LETableReference &base, const LookupProcessor *lookupProcessor,641GlyphIterator *glyphIterator,642const LEFontInstance *fontInstance,643LEErrorCode & success) const644{645if (LE_FAILURE(success)) {646return 0;647}648649le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);650LEReferenceToArrayOf<Offset> backtrackGlyphArrayRef(base, success, backtrackCoverageTableOffsetArray, backtrkGlyphCount);651if (LE_FAILURE(success)) {652return 0;653}654le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);655LEReferenceToArrayOf<Offset> inputCoverageTableOffsetArray(base, success, &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1], inputGlyphCount+2); // offset656if (LE_FAILURE(success)) { return 0; }657const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);658LEReferenceToArrayOf<Offset> lookaheadCoverageTableOffsetArray(base, success, inputCoverageTableOffsetArray.getAlias(inputGlyphCount + 1, success), lookaheadGlyphCount+2);659660if( LE_FAILURE(success) ) { return 0; }661le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);662le_int32 position = glyphIterator->getCurrStreamPosition();663GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);664665if (! tempIterator.prev(backtrkGlyphCount)) {666return 0;667}668669tempIterator.prev();670if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,671backtrkGlyphCount, &tempIterator, base, success, TRUE)) {672return 0;673}674675tempIterator.setCurrStreamPosition(position);676tempIterator.next(inputGlyphCount - 1);677if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,678lookaheadGlyphCount, &tempIterator, base, success)) {679return 0;680}681682// Back up the glyph iterator so that we683// can call next() before the check, which684// will leave it pointing at the last glyph685// that matched when we're done.686glyphIterator->prev();687688if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,689inputGlyphCount, glyphIterator, base, success)) {690LEReferenceToArrayOf<SubstitutionLookupRecord>691substLookupRecordArray(base, success,692(const SubstitutionLookupRecord *) lookaheadCoverageTableOffsetArray.getAlias(lookaheadGlyphCount + 1,success), substCount);693694ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);695696return inputGlyphCount;697}698699glyphIterator->setCurrStreamPosition(position);700701return 0;702}703704U_NAMESPACE_END705706707