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)
This commit is contained in:
parent
e040f68196
commit
8228828e1e
545
src/ftxgsub.c
545
src/ftxgsub.c
|
@ -210,12 +210,12 @@
|
||||||
* SubTable related functions
|
* SubTable related functions
|
||||||
*****************************/
|
*****************************/
|
||||||
|
|
||||||
static FT_Error Lookup_DefaultSubst( TTO_GSUBHeader* gsub,
|
static FT_Error Lookup_DefaultSubst( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUB_SubTable* st,
|
TTO_GSUB_SubTable* st,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
FT_UShort flags,
|
FT_UShort flags,
|
||||||
FT_UShort context_length,
|
FT_UShort context_length,
|
||||||
int nesting_level )
|
int nesting_level )
|
||||||
{
|
{
|
||||||
return TTO_Err_Not_Covered;
|
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,
|
TTO_GSUB_SubTable* st,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
FT_UShort flags,
|
FT_UShort flags,
|
||||||
FT_UShort context_length,
|
FT_UShort context_length,
|
||||||
int nesting_level )
|
int nesting_level )
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_UShort index, property, n, count;
|
FT_UShort index, property, n, count;
|
||||||
|
@ -728,12 +728,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub,
|
static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUB_SubTable* st,
|
TTO_GSUB_SubTable* st,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
FT_UShort flags,
|
FT_UShort flags,
|
||||||
FT_UShort context_length,
|
FT_UShort context_length,
|
||||||
int nesting_level )
|
int nesting_level )
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_UShort index, alt_index, property;
|
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,
|
TTO_GSUB_SubTable* st,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
FT_UShort flags,
|
FT_UShort flags,
|
||||||
FT_UShort context_length,
|
FT_UShort context_length,
|
||||||
int nesting_level )
|
int nesting_level )
|
||||||
{
|
{
|
||||||
FT_UShort index, property;
|
FT_UShort index, property;
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
@ -1145,12 +1145,12 @@
|
||||||
5 or 6). This is only called after we've determined that the input
|
5 or 6). This is only called after we've determined that the input
|
||||||
matches the subrule. */
|
matches the subrule. */
|
||||||
|
|
||||||
static FT_Error Do_ContextSubst( TTO_GSUBHeader* gsub,
|
static FT_Error Do_ContextSubst( TTO_GSUBHeader* gsub,
|
||||||
FT_UShort GlyphCount,
|
FT_UShort GlyphCount,
|
||||||
FT_UShort SubstCount,
|
FT_UShort SubstCount,
|
||||||
TTO_SubstLookupRecord* subst,
|
TTO_SubstLookupRecord* subst,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
int nesting_level )
|
int nesting_level )
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_UShort i, old_pos;
|
FT_UShort i, old_pos;
|
||||||
|
@ -1911,13 +1911,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ContextSubst1(
|
static FT_Error Lookup_ContextSubst1( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_ContextSubstFormat1* csf1,
|
||||||
TTO_ContextSubstFormat1* csf1,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
FT_UShort index, property;
|
FT_UShort index, property;
|
||||||
FT_UShort i, j, k, numsr;
|
FT_UShort i, j, k, numsr;
|
||||||
|
@ -1975,13 +1974,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ContextSubst2(
|
static FT_Error Lookup_ContextSubst2( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_ContextSubstFormat2* csf2,
|
||||||
TTO_ContextSubstFormat2* csf2,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
FT_UShort index, property;
|
FT_UShort index, property;
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
@ -2083,13 +2081,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ContextSubst3(
|
static FT_Error Lookup_ContextSubst3( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_ContextSubstFormat3* csf3,
|
||||||
TTO_ContextSubstFormat3* csf3,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_UShort index, i, j, property;
|
FT_UShort index, i, j, property;
|
||||||
|
@ -3187,13 +3184,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ChainContextSubst1(
|
static FT_Error Lookup_ChainContextSubst1( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_ChainContextSubstFormat1* ccsf1,
|
||||||
TTO_ChainContextSubstFormat1* ccsf1,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
FT_UShort index, property;
|
FT_UShort index, property;
|
||||||
FT_UShort i, j, k, num_csr;
|
FT_UShort i, j, k, num_csr;
|
||||||
|
@ -3315,13 +3311,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ChainContextSubst2(
|
static FT_Error Lookup_ChainContextSubst2( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_ChainContextSubstFormat2* ccsf2,
|
||||||
TTO_ChainContextSubstFormat2* ccsf2,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
FT_UShort index, property;
|
FT_UShort index, property;
|
||||||
FT_Memory memory;
|
FT_Memory memory;
|
||||||
|
@ -3518,13 +3513,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ChainContextSubst3(
|
static FT_Error Lookup_ChainContextSubst3( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_ChainContextSubstFormat3* ccsf3,
|
||||||
TTO_ChainContextSubstFormat3* ccsf3,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
FT_UShort index, i, j, property;
|
FT_UShort index, i, j, property;
|
||||||
FT_UShort bgc, igc, lgc;
|
FT_UShort bgc, igc, lgc;
|
||||||
|
@ -3628,13 +3622,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FT_Error Lookup_ChainContextSubst(
|
static FT_Error Lookup_ChainContextSubst( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUBHeader* gsub,
|
TTO_GSUB_SubTable* st,
|
||||||
TTO_GSUB_SubTable* st,
|
OTL_Buffer buffer,
|
||||||
OTL_Buffer buffer,
|
FT_UShort flags,
|
||||||
FT_UShort flags,
|
FT_UShort context_length,
|
||||||
FT_UShort context_length,
|
int nesting_level )
|
||||||
int nesting_level )
|
|
||||||
{
|
{
|
||||||
TTO_ChainContextSubst* ccs = &st->chain;
|
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
|
* GSUB API
|
||||||
***********/
|
***********/
|
||||||
|
@ -3958,31 +4232,36 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef FT_Error (*Lookup_Func_Type) ( TTO_GSUBHeader* gsub,
|
typedef FT_Error (*Lookup_Func_Type)( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUB_SubTable* st,
|
TTO_GSUB_SubTable* st,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
FT_UShort flags,
|
FT_UShort flags,
|
||||||
FT_UShort context_length,
|
FT_UShort context_length,
|
||||||
int nesting_level );
|
int nesting_level );
|
||||||
static const Lookup_Func_Type Lookup_Call_Table[] = {
|
static const Lookup_Func_Type Lookup_Call_Table[] = {
|
||||||
Lookup_DefaultSubst,
|
Lookup_DefaultSubst,
|
||||||
Lookup_SingleSubst, /* GSUB_LOOKUP_SINGLE 1 */
|
Lookup_SingleSubst, /* GSUB_LOOKUP_SINGLE 1 */
|
||||||
Lookup_MultipleSubst, /* GSUB_LOOKUP_MULTIPLE 2 */
|
Lookup_MultipleSubst, /* GSUB_LOOKUP_MULTIPLE 2 */
|
||||||
Lookup_AlternateSubst, /* GSUB_LOOKUP_ALTERNATE 3 */
|
Lookup_AlternateSubst, /* GSUB_LOOKUP_ALTERNATE 3 */
|
||||||
Lookup_LigatureSubst, /* GSUB_LOOKUP_LIGATURE 4 */
|
Lookup_LigatureSubst, /* GSUB_LOOKUP_LIGATURE 4 */
|
||||||
Lookup_ContextSubst, /* GSUB_LOOKUP_CONTEXT 5 */
|
Lookup_ContextSubst, /* GSUB_LOOKUP_CONTEXT 5 */
|
||||||
Lookup_ChainContextSubst, /* GSUB_LOOKUP_CHAIN 6 */
|
Lookup_ChainContextSubst, /* GSUB_LOOKUP_CHAIN 6 */
|
||||||
Lookup_DefaultSubst, /* GSUB_LOOKUP_EXTENSION 7 */
|
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
|
/* Do an individual subtable lookup. Returns TT_Err_Ok if substitution
|
||||||
has been done, or TTO_Err_Not_Covered if not. */
|
has been done, or TTO_Err_Not_Covered if not. */
|
||||||
|
|
||||||
static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
|
static FT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
|
||||||
FT_UShort lookup_index,
|
FT_UShort lookup_index,
|
||||||
OTL_Buffer buffer,
|
OTL_Buffer buffer,
|
||||||
FT_UShort context_length,
|
FT_UShort context_length,
|
||||||
int nesting_level )
|
int nesting_level )
|
||||||
{
|
{
|
||||||
FT_Error error = TTO_Err_Not_Covered;
|
FT_Error error = TTO_Err_Not_Covered;
|
||||||
FT_UShort i, flags, lookup_count;
|
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
|
EXPORT_FUNC
|
||||||
FT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub,
|
FT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub,
|
||||||
FT_UShort feature_index,
|
FT_UShort feature_index,
|
||||||
|
@ -4145,8 +4465,7 @@
|
||||||
OTL_Buffer buffer )
|
OTL_Buffer buffer )
|
||||||
{
|
{
|
||||||
FT_Error error, retError = TTO_Err_Not_Covered;
|
FT_Error error, retError = TTO_Err_Not_Covered;
|
||||||
FT_UShort i, j, feature_index, lookup_count;
|
FT_UShort i, j, lookup_count;
|
||||||
TTO_Feature feature;
|
|
||||||
|
|
||||||
if ( !gsub ||
|
if ( !gsub ||
|
||||||
!buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
|
!buffer || buffer->in_length == 0 || buffer->in_pos >= buffer->in_length )
|
||||||
|
@ -4156,18 +4475,37 @@
|
||||||
|
|
||||||
for ( i = 0; i < gsub->FeatureList.ApplyCount; i++)
|
for ( i = 0; i < gsub->FeatureList.ApplyCount; i++)
|
||||||
{
|
{
|
||||||
|
FT_UShort feature_index;
|
||||||
|
TTO_Feature feature;
|
||||||
|
|
||||||
feature_index = gsub->FeatureList.ApplyOrder[i];
|
feature_index = gsub->FeatureList.ApplyOrder[i];
|
||||||
feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
|
feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
|
||||||
|
|
||||||
for ( j = 0; j < feature.LookupListCount; j++ )
|
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 */
|
/* Skip nonexistant lookups */
|
||||||
if (lookup_index >= lookup_count)
|
if (lookup_index >= lookup_count)
|
||||||
continue;
|
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 )
|
||||||
{
|
{
|
||||||
if ( error != TTO_Err_Not_Covered )
|
if ( error != TTO_Err_Not_Covered )
|
||||||
|
@ -4176,9 +4514,12 @@
|
||||||
else
|
else
|
||||||
retError = error;
|
retError = error;
|
||||||
|
|
||||||
error = otl_buffer_swap( buffer );
|
if ( need_swap )
|
||||||
if ( error )
|
{
|
||||||
goto End;
|
error = otl_buffer_swap( buffer );
|
||||||
|
if ( error )
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,14 @@ extern "C" {
|
||||||
|
|
||||||
/* Lookup types for glyph substitution */
|
/* Lookup types for glyph substitution */
|
||||||
|
|
||||||
#define GSUB_LOOKUP_SINGLE 1
|
#define GSUB_LOOKUP_SINGLE 1
|
||||||
#define GSUB_LOOKUP_MULTIPLE 2
|
#define GSUB_LOOKUP_MULTIPLE 2
|
||||||
#define GSUB_LOOKUP_ALTERNATE 3
|
#define GSUB_LOOKUP_ALTERNATE 3
|
||||||
#define GSUB_LOOKUP_LIGATURE 4
|
#define GSUB_LOOKUP_LIGATURE 4
|
||||||
#define GSUB_LOOKUP_CONTEXT 5
|
#define GSUB_LOOKUP_CONTEXT 5
|
||||||
#define GSUB_LOOKUP_CHAIN 6
|
#define GSUB_LOOKUP_CHAIN 6
|
||||||
#define GSUB_LOOKUP_EXTENSION 7
|
#define GSUB_LOOKUP_EXTENSION 7
|
||||||
|
#define GSUB_LOOKUP_REVERSE_CHAIN 8
|
||||||
|
|
||||||
/* Use this if a feature applies to all glyphs */
|
/* Use this if a feature applies to all glyphs */
|
||||||
|
|
||||||
|
@ -467,14 +467,33 @@ extern "C" {
|
||||||
typedef struct TTO_ChainContextSubst_ TTO_ChainContextSubst;
|
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_
|
union TTO_GSUB_SubTable_
|
||||||
{
|
{
|
||||||
TTO_SingleSubst single;
|
TTO_SingleSubst single;
|
||||||
TTO_MultipleSubst multiple;
|
TTO_MultipleSubst multiple;
|
||||||
TTO_AlternateSubst alternate;
|
TTO_AlternateSubst alternate;
|
||||||
TTO_LigatureSubst ligature;
|
TTO_LigatureSubst ligature;
|
||||||
TTO_ContextSubst context;
|
TTO_ContextSubst context;
|
||||||
TTO_ChainContextSubst chain;
|
TTO_ChainContextSubst chain;
|
||||||
|
TTO_ReverseChainContextSubst reverse;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union TTO_GSUB_SubTable_ TTO_GSUB_SubTable;
|
typedef union TTO_GSUB_SubTable_ TTO_GSUB_SubTable;
|
||||||
|
|
|
@ -469,6 +469,9 @@
|
||||||
|
|
||||||
case GSUB_LOOKUP_CHAIN:
|
case GSUB_LOOKUP_CHAIN:
|
||||||
return Load_ChainContextSubst( &st->st.gsub.chain, stream );
|
return Load_ChainContextSubst( &st->st.gsub.chain, stream );
|
||||||
|
|
||||||
|
case GSUB_LOOKUP_REVERSE_CHAIN:
|
||||||
|
return Load_ReverseChainContextSubst( &st->st.gsub.reverse, stream );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return TTO_Err_Invalid_GSUB_SubTable_Format;
|
return TTO_Err_Invalid_GSUB_SubTable_Format;
|
||||||
|
@ -536,6 +539,10 @@
|
||||||
Free_ContextSubst( &st->st.gsub.context, memory );
|
Free_ContextSubst( &st->st.gsub.context, memory );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GSUB_LOOKUP_REVERSE_CHAIN:
|
||||||
|
Free_ReverseChainContextSubst( &st->st.gsub.reverse, memory );
|
||||||
|
break;
|
||||||
|
|
||||||
case GSUB_LOOKUP_CHAIN:
|
case GSUB_LOOKUP_CHAIN:
|
||||||
Free_ChainContextSubst( &st->st.gsub.chain, memory );
|
Free_ChainContextSubst( &st->st.gsub.chain, memory );
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -74,6 +74,8 @@ extern "C" {
|
||||||
FT_Stream input );
|
FT_Stream input );
|
||||||
FT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs,
|
FT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs,
|
||||||
FT_Stream input );
|
FT_Stream input );
|
||||||
|
FT_Error Load_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs,
|
||||||
|
FT_Stream input );
|
||||||
|
|
||||||
void Free_SingleSubst( TTO_SingleSubst* ss,
|
void Free_SingleSubst( TTO_SingleSubst* ss,
|
||||||
FT_Memory memory );
|
FT_Memory memory );
|
||||||
|
@ -87,7 +89,8 @@ extern "C" {
|
||||||
FT_Memory memory );
|
FT_Memory memory );
|
||||||
void Free_ChainContextSubst( TTO_ChainContextSubst* ccs,
|
void Free_ChainContextSubst( TTO_ChainContextSubst* ccs,
|
||||||
FT_Memory memory );
|
FT_Memory memory );
|
||||||
|
void Free_ReverseChainContextSubst( TTO_ReverseChainContextSubst* rccs,
|
||||||
|
FT_Memory memory );
|
||||||
|
|
||||||
/* functions from ftxgpos.c */
|
/* functions from ftxgpos.c */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue