summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@gnome.org>2006-01-30 22:37:48 +0000
committerBehdad Esfahbod <behdad@src.gnome.org>2006-01-30 22:37:48 +0000
commit2c640e84f1ac6c02fe0838595d79e883d4fe5e12 (patch)
tree8c6c32a32159b928308f50ea36d1d0923d7c8816
parent1a00555cd87c8454301b65fe7939e277b7d67998 (diff)
downloadpango-2c640e84f1ac6c02fe0838595d79e883d4fe5e12.tar.gz
Handle GSUB Lookup type 8, and ReverseChainContextualSubst table. (bug
2006-01-30 Behdad Esfahbod <behdad@gnome.org> * pango/opentype/ftxgsub.c: Handle GSUB Lookup type 8, and ReverseChainContextualSubst table. (bug #149696, patch from Aamir Wali)
-rw-r--r--ChangeLog6
-rw-r--r--pango/opentype/ftxgsub.c545
-rw-r--r--pango/opentype/ftxgsub.h47
-rw-r--r--pango/opentype/ftxopen.c7
-rw-r--r--pango/opentype/ftxopenf.h5
5 files changed, 493 insertions, 117 deletions
diff --git a/ChangeLog b/ChangeLog
index 444ced9b..5f6591db 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2006-01-30 Behdad Esfahbod <behdad@gnome.org>
+
+ * pango/opentype/ftxgsub.c: Handle GSUB Lookup type 8,
+ and ReverseChainContextualSubst table. (bug #149696,
+ patch from Aamir Wali)
+
2006-01-29 Behdad Esfahbod <behdad@gnome.org>
* modules/arabic/arabic-fc.c, modules/basic/basic-fc.c
diff --git a/pango/opentype/ftxgsub.c b/pango/opentype/ftxgsub.c
index dac69aa2..ce306976 100644
--- a/pango/opentype/ftxgsub.c
+++ b/pango/opentype/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/pango/opentype/ftxgsub.h b/pango/opentype/ftxgsub.h
index a8ffa438..53409d68 100644
--- a/pango/opentype/ftxgsub.h
+++ b/pango/opentype/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/pango/opentype/ftxopen.c b/pango/opentype/ftxopen.c
index e086bd19..8afb8f2c 100644
--- a/pango/opentype/ftxopen.c
+++ b/pango/opentype/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/pango/opentype/ftxopenf.h b/pango/opentype/ftxopenf.h
index 4c5998ef..2c274c35 100644
--- a/pango/opentype/ftxopenf.h
+++ b/pango/opentype/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 */