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:
Behdad Esfahbod 2006-01-30 22:37:48 +00:00 committed by Behdad Esfahbod
parent e040f68196
commit 8228828e1e
4 changed files with 487 additions and 117 deletions

View File

@ -1911,8 +1911,7 @@
}
static FT_Error Lookup_ContextSubst1(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ContextSubst1( TTO_GSUBHeader* gsub,
TTO_ContextSubstFormat1* csf1,
OTL_Buffer buffer,
FT_UShort flags,
@ -1975,8 +1974,7 @@
}
static FT_Error Lookup_ContextSubst2(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ContextSubst2( TTO_GSUBHeader* gsub,
TTO_ContextSubstFormat2* csf2,
OTL_Buffer buffer,
FT_UShort flags,
@ -2083,8 +2081,7 @@
}
static FT_Error Lookup_ContextSubst3(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ContextSubst3( TTO_GSUBHeader* gsub,
TTO_ContextSubstFormat3* csf3,
OTL_Buffer buffer,
FT_UShort flags,
@ -3187,8 +3184,7 @@
}
static FT_Error Lookup_ChainContextSubst1(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ChainContextSubst1( TTO_GSUBHeader* gsub,
TTO_ChainContextSubstFormat1* ccsf1,
OTL_Buffer buffer,
FT_UShort flags,
@ -3315,8 +3311,7 @@
}
static FT_Error Lookup_ChainContextSubst2(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ChainContextSubst2( TTO_GSUBHeader* gsub,
TTO_ChainContextSubstFormat2* ccsf2,
OTL_Buffer buffer,
FT_UShort flags,
@ -3518,8 +3513,7 @@
}
static FT_Error Lookup_ChainContextSubst3(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ChainContextSubst3( TTO_GSUBHeader* gsub,
TTO_ChainContextSubstFormat3* ccsf3,
OTL_Buffer buffer,
FT_UShort flags,
@ -3628,8 +3622,7 @@
}
static FT_Error Lookup_ChainContextSubst(
TTO_GSUBHeader* gsub,
static FT_Error Lookup_ChainContextSubst( TTO_GSUBHeader* gsub,
TTO_GSUB_SubTable* st,
OTL_Buffer buffer,
FT_UShort flags,
@ -3663,6 +3656,287 @@
}
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
@ -3974,6 +4248,11 @@
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. */
@ -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;
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,11 +4514,14 @@
else
retError = error;
if ( need_swap )
{
error = otl_buffer_swap( buffer );
if ( error )
goto End;
}
}
}
error = retError;

View File

@ -39,7 +39,7 @@ extern "C" {
#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,6 +467,24 @@ 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;
@ -475,6 +493,7 @@ extern "C" {
TTO_LigatureSubst ligature;
TTO_ContextSubst context;
TTO_ChainContextSubst chain;
TTO_ReverseChainContextSubst reverse;
};
typedef union TTO_GSUB_SubTable_ TTO_GSUB_SubTable;

View File

@ -470,6 +470,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;

View File

@ -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 */