From 8228828e1e4c8dd6f9435fb718ad4394bba95655 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 30 Jan 2006 22:37:48 +0000 Subject: [PATCH] Handle GSUB Lookup type 8, and ReverseChainContextualSubst table. (bug 2006-01-30 Behdad Esfahbod * pango/opentype/ftxgsub.c: Handle GSUB Lookup type 8, and ReverseChainContextualSubst table. (bug #149696, patch from Aamir Wali) --- src/ftxgsub.c | 545 ++++++++++++++++++++++++++++++++++++++++++++++----------- src/ftxgsub.h | 47 +++-- src/ftxopen.c | 7 + src/ftxopenf.h | 5 +- 4 files changed, 487 insertions(+), 117 deletions(-) diff --git a/src/ftxgsub.c b/src/ftxgsub.c index dac69aa..ce30697 100644 --- a/src/ftxgsub.c +++ b/src/ftxgsub.c @@ -210,12 +210,12 @@ * SubTable related functions *****************************/ - static FT_Error Lookup_DefaultSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_DefaultSubst( TTO_GSUBHeader* gsub, + TTO_GSUB_SubTable* st, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { return TTO_Err_Not_Covered; } @@ -529,12 +529,12 @@ } - static FT_Error Lookup_MultipleSubst( TTO_GSUBHeader* gsub, + static FT_Error Lookup_MultipleSubst( TTO_GSUBHeader* gsub, TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_Error error; FT_UShort index, property, n, count; @@ -728,12 +728,12 @@ } - static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub, + TTO_GSUB_SubTable* st, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_Error error; FT_UShort index, alt_index, property; @@ -1011,12 +1011,12 @@ } - static FT_Error Lookup_LigatureSubst( TTO_GSUBHeader* gsub, + static FT_Error Lookup_LigatureSubst( TTO_GSUBHeader* gsub, TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_UShort index, property; FT_Error error; @@ -1145,12 +1145,12 @@ 5 or 6). This is only called after we've determined that the input matches the subrule. */ - static FT_Error Do_ContextSubst( TTO_GSUBHeader* gsub, - FT_UShort GlyphCount, - FT_UShort SubstCount, - TTO_SubstLookupRecord* subst, - OTL_Buffer buffer, - int nesting_level ) + static FT_Error Do_ContextSubst( TTO_GSUBHeader* gsub, + FT_UShort GlyphCount, + FT_UShort SubstCount, + TTO_SubstLookupRecord* subst, + OTL_Buffer buffer, + int nesting_level ) { FT_Error error; FT_UShort i, old_pos; @@ -1911,13 +1911,12 @@ } - static FT_Error Lookup_ContextSubst1( - TTO_GSUBHeader* gsub, - TTO_ContextSubstFormat1* csf1, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ContextSubst1( TTO_GSUBHeader* gsub, + TTO_ContextSubstFormat1* csf1, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_UShort index, property; FT_UShort i, j, k, numsr; @@ -1975,13 +1974,12 @@ } - static FT_Error Lookup_ContextSubst2( - TTO_GSUBHeader* gsub, - TTO_ContextSubstFormat2* csf2, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ContextSubst2( TTO_GSUBHeader* gsub, + TTO_ContextSubstFormat2* csf2, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_UShort index, property; FT_Error error; @@ -2083,13 +2081,12 @@ } - static FT_Error Lookup_ContextSubst3( - TTO_GSUBHeader* gsub, - TTO_ContextSubstFormat3* csf3, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ContextSubst3( TTO_GSUBHeader* gsub, + TTO_ContextSubstFormat3* csf3, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_Error error; FT_UShort index, i, j, property; @@ -3187,13 +3184,12 @@ } - static FT_Error Lookup_ChainContextSubst1( - TTO_GSUBHeader* gsub, - TTO_ChainContextSubstFormat1* ccsf1, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ChainContextSubst1( TTO_GSUBHeader* gsub, + TTO_ChainContextSubstFormat1* ccsf1, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_UShort index, property; FT_UShort i, j, k, num_csr; @@ -3315,13 +3311,12 @@ } - static FT_Error Lookup_ChainContextSubst2( - TTO_GSUBHeader* gsub, - TTO_ChainContextSubstFormat2* ccsf2, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ChainContextSubst2( TTO_GSUBHeader* gsub, + TTO_ChainContextSubstFormat2* ccsf2, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_UShort index, property; FT_Memory memory; @@ -3518,13 +3513,12 @@ } - static FT_Error Lookup_ChainContextSubst3( - TTO_GSUBHeader* gsub, - TTO_ChainContextSubstFormat3* ccsf3, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ChainContextSubst3( TTO_GSUBHeader* gsub, + TTO_ChainContextSubstFormat3* ccsf3, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { FT_UShort index, i, j, property; FT_UShort bgc, igc, lgc; @@ -3628,13 +3622,12 @@ } - static FT_Error Lookup_ChainContextSubst( - TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ) + static FT_Error Lookup_ChainContextSubst( TTO_GSUBHeader* gsub, + TTO_GSUB_SubTable* st, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ) { TTO_ChainContextSubst* ccs = &st->chain; @@ -3663,7 +3656,288 @@ } + FT_Error Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort m, count; + + FT_UShort nb = 0, nl = 0, n; + FT_UShort backtrack_count, lookahead_count; + FT_ULong cur_offset, new_offset, base_offset; + + TTO_Coverage* b; + TTO_Coverage* l; + FT_UShort* sub; + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + rccs->SubstFormat = GET_UShort(); + + if ( rccs->SubstFormat != 1 ) + return TTO_Err_Invalid_GSUB_SubTable_Format; + + FORGET_Frame(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Coverage( &rccs->Coverage, stream ) ) != TT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + + + if ( ACCESS_Frame( 2L ) ) + goto Fail4; + + rccs->BacktrackGlyphCount = GET_UShort(); + + FORGET_Frame(); + + rccs->BacktrackCoverage = NULL; + + backtrack_count = rccs->BacktrackGlyphCount; + + if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count, + TTO_Coverage ) ) + goto Fail4; + + b = rccs->BacktrackCoverage; + + for ( nb = 0; nb < backtrack_count; nb++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Coverage( &b[nb], stream ) ) != TT_Err_Ok ) + goto Fail3; + (void)FILE_Seek( cur_offset ); + } + + + if ( ACCESS_Frame( 2L ) ) + goto Fail3; + + rccs->LookaheadGlyphCount = GET_UShort(); + + FORGET_Frame(); + + rccs->LookaheadCoverage = NULL; + + lookahead_count = rccs->LookaheadGlyphCount; + + if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count, + TTO_Coverage ) ) + goto Fail3; + + l = rccs->LookaheadCoverage; + + for ( nl = 0; nl < lookahead_count; nl++ ) + { + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Coverage( &l[nl], stream ) ) != TT_Err_Ok ) + goto Fail2; + (void)FILE_Seek( cur_offset ); + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + rccs->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + rccs->Substitute = NULL; + + count = rccs->GlyphCount; + + if ( ALLOC_ARRAY( rccs->Substitute, count, + FT_UShort ) ) + goto Fail2; + + sub = rccs->Substitute; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail1; + + for ( n = 0; n < count; n++ ) + sub[n] = GET_UShort(); + + FORGET_Frame(); + + return TT_Err_Ok; + + Fail1: + FREE( sub ); + + Fail2: + for ( m = 0; m < nl; m++ ) + Free_Coverage( &l[m], memory ); + + FREE( l ); + + Fail3: + for ( m = 0; m < nb; m++ ) + Free_Coverage( &b[m], memory ); + + FREE( b ); + + Fail4: + Free_Coverage( &rccs->Coverage, memory ); + return error; + } + + + void Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, + FT_Memory memory ) + { + FT_UShort n, count; + + TTO_Coverage* c; + + Free_Coverage( &rccs->Coverage, memory ); + + if ( rccs->LookaheadCoverage ) + { + count = rccs->LookaheadGlyphCount; + c = rccs->LookaheadCoverage; + + for ( n = 0; n < count; n++ ) + Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + if ( rccs->BacktrackCoverage ) + { + count = rccs->BacktrackGlyphCount; + c = rccs->BacktrackCoverage; + + for ( n = 0; n < count; n++ ) + Free_Coverage( &c[n], memory ); + + FREE( c ); + } + + FREE ( rccs->Substitute ); + } + + + static FT_Error Lookup_ReverseChainContextSubst( TTO_GSUBHeader* gsub, + TTO_GSUB_SubTable* st, + OTL_Buffer buffer, + FT_UShort flags, + /* note different signature here: */ FT_ULong string_index ) + { + FT_UShort index, input_index, i, j, property; + FT_UShort bgc, lgc; + FT_Error error; + TTO_ReverseChainContextSubst* rccs = &st->reverse; + TTO_Coverage* bc; + TTO_Coverage* lc; + TTO_GDEFHeader* gdef; + + gdef = gsub->gdef; + + if ( CHECK_Property( gdef, IN_ITEM( string_index ), flags, &property ) ) + return error; + + bgc = rccs->BacktrackGlyphCount; + lgc = rccs->LookaheadGlyphCount; + + /* check whether context is too long; it is a first guess only */ + + if ( bgc > string_index || string_index + 1 + lgc > buffer->in_length ) + return TTO_Err_Not_Covered; + + if ( bgc ) + { + /* Since we don't know in advance the number of glyphs to inspect, + we search backwards for matches in the backtrack glyph array */ + + bc = rccs->BacktrackCoverage; + + for ( i = 0, j = string_index - 1; i < bgc; i++, j-- ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != TTO_Err_Not_Covered ) + return error; + + if ( j + 1 == bgc - i ) + return TTO_Err_Not_Covered; + j--; + } + + error = Coverage_Index( &bc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + } + + j = string_index; + + error = Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index ); + if ( error ) + return error; + + /* we are starting for lookahead glyphs right after the last context + glyph */ + + j += 1; + + lc = rccs->LookaheadCoverage; + + for ( i = 0; i < lgc; i++, j++ ) + { + while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) + { + if ( error && error != TTO_Err_Not_Covered ) + return error; + + if ( j + lgc - i == buffer->in_length ) + return TTO_Err_Not_Covered; + j++; + } + + error = Coverage_Index( &lc[i], IN_GLYPH( j ), &index ); + if ( error ) + return error; + } + + IN_GLYPH( string_index ) = rccs->Substitute[input_index]; + + return error; + } + + + /*********** * GSUB API ***********/ @@ -3958,31 +4232,36 @@ } - typedef FT_Error (*Lookup_Func_Type) ( TTO_GSUBHeader* gsub, - TTO_GSUB_SubTable* st, - OTL_Buffer buffer, - FT_UShort flags, - FT_UShort context_length, - int nesting_level ); + typedef FT_Error (*Lookup_Func_Type)( TTO_GSUBHeader* gsub, + TTO_GSUB_SubTable* st, + OTL_Buffer buffer, + FT_UShort flags, + FT_UShort context_length, + int nesting_level ); static const Lookup_Func_Type Lookup_Call_Table[] = { Lookup_DefaultSubst, - Lookup_SingleSubst, /* GSUB_LOOKUP_SINGLE 1 */ - Lookup_MultipleSubst, /* GSUB_LOOKUP_MULTIPLE 2 */ - Lookup_AlternateSubst, /* GSUB_LOOKUP_ALTERNATE 3 */ - Lookup_LigatureSubst, /* GSUB_LOOKUP_LIGATURE 4 */ - Lookup_ContextSubst, /* GSUB_LOOKUP_CONTEXT 5 */ - Lookup_ChainContextSubst, /* GSUB_LOOKUP_CHAIN 6 */ - Lookup_DefaultSubst, /* GSUB_LOOKUP_EXTENSION 7 */ + Lookup_SingleSubst, /* GSUB_LOOKUP_SINGLE 1 */ + Lookup_MultipleSubst, /* GSUB_LOOKUP_MULTIPLE 2 */ + Lookup_AlternateSubst, /* GSUB_LOOKUP_ALTERNATE 3 */ + Lookup_LigatureSubst, /* GSUB_LOOKUP_LIGATURE 4 */ + Lookup_ContextSubst, /* GSUB_LOOKUP_CONTEXT 5 */ + Lookup_ChainContextSubst, /* GSUB_LOOKUP_CHAIN 6 */ + Lookup_DefaultSubst, /* GSUB_LOOKUP_EXTENSION 7 */ }; + /* Note that the following lookup does not belong to the table above: + * Lookup_ReverseChainContextSubst, GSUB_LOOKUP_REVERSE_CHAIN 8 + * because it's invalid to happen where this table is used. It's + * signature is different too... + */ /* Do an individual subtable lookup. Returns TT_Err_Ok if substitution has been done, or TTO_Err_Not_Covered if not. */ - static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub, - FT_UShort lookup_index, - OTL_Buffer buffer, - FT_UShort context_length, - int nesting_level ) + static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub, + FT_UShort lookup_index, + OTL_Buffer buffer, + FT_UShort context_length, + int nesting_level ) { FT_Error error = TTO_Err_Not_Covered; FT_UShort i, flags, lookup_count; @@ -4065,6 +4344,47 @@ } + static FT_Error Apply_ReverseChainContextSubst( TTO_GSUBHeader* gsub, + FT_UShort lookup_index, + OTL_Buffer buffer ) + { + FT_UInt* properties = gsub->LookupList.Properties; + FT_Error error, retError = TTO_Err_Not_Covered; + FT_ULong subtable_Count, string_index; + FT_UShort flags; + TTO_Lookup* lo; + + if ( buffer->in_length == 0 ) + return TTO_Err_Not_Covered; + + lo = &gsub->LookupList.Lookup[lookup_index]; + flags = lo->LookupFlag; + + for ( subtable_Count = 0; subtable_Count < lo->SubTableCount; subtable_Count++ ) + { + string_index = buffer->in_length - 1; + do + { + if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] ) + { + error = Lookup_ReverseChainContextSubst( gsub, &lo->SubTable[subtable_Count].st.gsub, + buffer, flags, string_index ); + if ( error ) + { + if ( error != TTO_Err_Not_Covered ) + return error; + } + else + retError = error; + } + } + while (string_index--); + } + + return retError; + } + + EXPORT_FUNC FT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub, FT_UShort feature_index, @@ -4145,8 +4465,7 @@ OTL_Buffer buffer ) { FT_Error error, retError = TTO_Err_Not_Covered; - FT_UShort i, j, feature_index, lookup_count; - TTO_Feature feature; + FT_UShort i, j, lookup_count; if ( !gsub || !buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length ) @@ -4156,18 +4475,37 @@ for ( i = 0; i < gsub->FeatureList.ApplyCount; i++) { + FT_UShort feature_index; + TTO_Feature feature; + feature_index = gsub->FeatureList.ApplyOrder[i]; feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; for ( j = 0; j < feature.LookupListCount; j++ ) { - FT_UShort lookup_index = feature.LookupListIndex[j]; + FT_UShort lookup_index; + TTO_Lookup* lookup; + FT_Bool need_swap; + + lookup_index = feature.LookupListIndex[j]; /* Skip nonexistant lookups */ if (lookup_index >= lookup_count) continue; - error = Do_String_Lookup( gsub, lookup_index, buffer ); + lookup = &gsub->LookupList.Lookup[lookup_index]; + + if ( lookup->LookupType == GSUB_LOOKUP_REVERSE_CHAIN ) + { + error = Apply_ReverseChainContextSubst( gsub, lookup_index, buffer); + need_swap = FALSE; /* We do ReverseChainContextSubst in-place */ + } + else + { + error = Do_String_Lookup( gsub, lookup_index, buffer ); + need_swap = TRUE; + } + if ( error ) { if ( error != TTO_Err_Not_Covered ) @@ -4176,9 +4514,12 @@ else retError = error; - error = otl_buffer_swap( buffer ); - if ( error ) - goto End; + if ( need_swap ) + { + error = otl_buffer_swap( buffer ); + if ( error ) + goto End; + } } } diff --git a/src/ftxgsub.h b/src/ftxgsub.h index a8ffa43..53409d6 100644 --- a/src/ftxgsub.h +++ b/src/ftxgsub.h @@ -32,14 +32,14 @@ extern "C" { /* Lookup types for glyph substitution */ -#define GSUB_LOOKUP_SINGLE 1 -#define GSUB_LOOKUP_MULTIPLE 2 -#define GSUB_LOOKUP_ALTERNATE 3 -#define GSUB_LOOKUP_LIGATURE 4 -#define GSUB_LOOKUP_CONTEXT 5 -#define GSUB_LOOKUP_CHAIN 6 -#define GSUB_LOOKUP_EXTENSION 7 - +#define GSUB_LOOKUP_SINGLE 1 +#define GSUB_LOOKUP_MULTIPLE 2 +#define GSUB_LOOKUP_ALTERNATE 3 +#define GSUB_LOOKUP_LIGATURE 4 +#define GSUB_LOOKUP_CONTEXT 5 +#define GSUB_LOOKUP_CHAIN 6 +#define GSUB_LOOKUP_EXTENSION 7 +#define GSUB_LOOKUP_REVERSE_CHAIN 8 /* Use this if a feature applies to all glyphs */ @@ -467,14 +467,33 @@ extern "C" { typedef struct TTO_ChainContextSubst_ TTO_ChainContextSubst; + /* LookupType 8 */ + struct TTO_ReverseChainContextSubst_ + { + FT_UShort SubstFormat; /* always 1 */ + TTO_Coverage Coverage; /* coverage table for input glyphs */ + FT_UShort BacktrackGlyphCount; /* number of backtrack glyphs */ + TTO_Coverage* BacktrackCoverage; /* array of backtrack Coverage + tables */ + FT_UShort LookaheadGlyphCount; /* number of lookahead glyphs */ + TTO_Coverage* LookaheadCoverage; /* array of lookahead Coverage + tables */ + FT_UShort GlyphCount; /* number of Glyph IDs */ + FT_UShort* Substitute; /* array of substitute Glyph ID */ + }; + + typedef struct TTO_ReverseChainContextSubst_ TTO_ReverseChainContextSubst; + + union TTO_GSUB_SubTable_ { - TTO_SingleSubst single; - TTO_MultipleSubst multiple; - TTO_AlternateSubst alternate; - TTO_LigatureSubst ligature; - TTO_ContextSubst context; - TTO_ChainContextSubst chain; + TTO_SingleSubst single; + TTO_MultipleSubst multiple; + TTO_AlternateSubst alternate; + TTO_LigatureSubst ligature; + TTO_ContextSubst context; + TTO_ChainContextSubst chain; + TTO_ReverseChainContextSubst reverse; }; typedef union TTO_GSUB_SubTable_ TTO_GSUB_SubTable; diff --git a/src/ftxopen.c b/src/ftxopen.c index e086bd1..8afb8f2 100644 --- a/src/ftxopen.c +++ b/src/ftxopen.c @@ -469,6 +469,9 @@ case GSUB_LOOKUP_CHAIN: return Load_ChainContextSubst( &st->st.gsub.chain, stream ); + + case GSUB_LOOKUP_REVERSE_CHAIN: + return Load_ReverseChainContextSubst( &st->st.gsub.reverse, stream ); default: return TTO_Err_Invalid_GSUB_SubTable_Format; @@ -536,6 +539,10 @@ Free_ContextSubst( &st->st.gsub.context, memory ); break; + case GSUB_LOOKUP_REVERSE_CHAIN: + Free_ReverseChainContextSubst( &st->st.gsub.reverse, memory ); + break; + case GSUB_LOOKUP_CHAIN: Free_ChainContextSubst( &st->st.gsub.chain, memory ); break; diff --git a/src/ftxopenf.h b/src/ftxopenf.h index 4c5998e..2c274c3 100644 --- a/src/ftxopenf.h +++ b/src/ftxopenf.h @@ -74,6 +74,8 @@ extern "C" { FT_Stream input ); FT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs, FT_Stream input ); + FT_Error Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, + FT_Stream input ); void Free_SingleSubst( TTO_SingleSubst* ss, FT_Memory memory ); @@ -87,7 +89,8 @@ extern "C" { FT_Memory memory ); void Free_ChainContextSubst( TTO_ChainContextSubst* ccs, FT_Memory memory ); - + void Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs, + FT_Memory memory ); /* functions from ftxgpos.c */ -- 2.7.4