📄 ftxgsub.c
字号:
for ( n = 0; n < count; n++ ) a[n] = GET_UShort(); FORGET_Frame(); return TT_Err_Ok; } static void Free_AlternateSet( TTO_AlternateSet* as, FT_Memory memory ) { FREE( as->Alternate ); } /* AlternateSubstFormat1 */ FT_Error Load_AlternateSubst( TTO_AlternateSubst* as, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n = 0, m, count; FT_ULong cur_offset, new_offset, base_offset; TTO_AlternateSet* aset; base_offset = FILE_Pos(); if ( ACCESS_Frame( 4L ) ) return error; as->SubstFormat = GET_UShort(); /* should be 1 */ new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Coverage( &as->Coverage, stream ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail2; count = as->AlternateSetCount = GET_UShort(); FORGET_Frame(); as->AlternateSet = NULL; if ( ALLOC_ARRAY( as->AlternateSet, count, TTO_AlternateSet ) ) goto Fail2; aset = as->AlternateSet; for ( n = 0; n < count; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_AlternateSet( &aset[n], stream ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } return TT_Err_Ok; Fail1: for ( m = 0; m < n; m++ ) Free_AlternateSet( &aset[m], memory ); FREE( aset ); Fail2: Free_Coverage( &as->Coverage, memory ); return error; } void Free_AlternateSubst( TTO_AlternateSubst* as, FT_Memory memory ) { FT_UShort n, count; TTO_AlternateSet* aset; if ( as->AlternateSet ) { count = as->AlternateSetCount; aset = as->AlternateSet; for ( n = 0; n < count; n++ ) Free_AlternateSet( &aset[n], memory ); FREE( aset ); } Free_Coverage( &as->Coverage, memory ); } static FT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub, TTO_AlternateSubst* as, OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) { FT_Error error; FT_UShort index, alt_index, property; TTO_AlternateSet aset; if ( context_length != 0xFFFF && context_length < 1 ) return TTO_Err_Not_Covered; if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) return error; error = Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index ); if ( error ) return error; aset = as->AlternateSet[index]; /* we use a user-defined callback function to get the alternate index */ if ( gsub->altfunc ) alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(), aset.GlyphCount, aset.Alternate, gsub->data ); else alt_index = 0; if ( ADD_Glyph( buffer, aset.Alternate[alt_index], 0xFFFF, 0xFFFF ) ) return error; if ( gdef && gdef->NewGlyphClasses ) { /* we inherit the old glyph class to the substituted glyph */ error = Add_Glyph_Property( gdef, aset.Alternate[alt_index], property ); if ( error && error != TTO_Err_Not_Covered ) return error; } return TT_Err_Ok; } /* LookupType 4 */ /* Ligature */ static FT_Error Load_Ligature( TTO_Ligature* l, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n, count; FT_UShort* c; if ( ACCESS_Frame( 4L ) ) return error; l->LigGlyph = GET_UShort(); l->ComponentCount = GET_UShort(); FORGET_Frame(); l->Component = NULL; count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */ if ( ALLOC_ARRAY( l->Component, count, FT_UShort ) ) return error; c = l->Component; if ( ACCESS_Frame( count * 2L ) ) { FREE( c ); return error; } for ( n = 0; n < count; n++ ) c[n] = GET_UShort(); FORGET_Frame(); return TT_Err_Ok; } static void Free_Ligature( TTO_Ligature* l, FT_Memory memory ) { FREE( l->Component ); } /* LigatureSet */ static FT_Error Load_LigatureSet( TTO_LigatureSet* ls, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n = 0, m, count; FT_ULong cur_offset, new_offset, base_offset; TTO_Ligature* l; base_offset = FILE_Pos(); if ( ACCESS_Frame( 2L ) ) return error; count = ls->LigatureCount = GET_UShort(); FORGET_Frame(); ls->Ligature = NULL; if ( ALLOC_ARRAY( ls->Ligature, count, TTO_Ligature ) ) return error; l = ls->Ligature; for ( n = 0; n < count; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Ligature( &l[n], stream ) ) != TT_Err_Ok ) goto Fail; (void)FILE_Seek( cur_offset ); } return TT_Err_Ok; Fail: for ( m = 0; m < n; m++ ) Free_Ligature( &l[m], memory ); FREE( l ); return error; } static void Free_LigatureSet( TTO_LigatureSet* ls, FT_Memory memory ) { FT_UShort n, count; TTO_Ligature* l; if ( ls->Ligature ) { count = ls->LigatureCount; l = ls->Ligature; for ( n = 0; n < count; n++ ) Free_Ligature( &l[n], memory ); FREE( l ); } } /* LigatureSubstFormat1 */ FT_Error Load_LigatureSubst( TTO_LigatureSubst* ls, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n = 0, m, count; FT_ULong cur_offset, new_offset, base_offset; TTO_LigatureSet* lset; base_offset = FILE_Pos(); if ( ACCESS_Frame( 4L ) ) return error; ls->SubstFormat = GET_UShort(); /* should be 1 */ new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Coverage( &ls->Coverage, stream ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail2; count = ls->LigatureSetCount = GET_UShort(); FORGET_Frame(); ls->LigatureSet = NULL; if ( ALLOC_ARRAY( ls->LigatureSet, count, TTO_LigatureSet ) ) goto Fail2; lset = ls->LigatureSet; for ( n = 0; n < count; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_LigatureSet( &lset[n], stream ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } return TT_Err_Ok; Fail1: for ( m = 0; m < n; m++ ) Free_LigatureSet( &lset[m], memory ); FREE( lset ); Fail2: Free_Coverage( &ls->Coverage, memory ); return error; } void Free_LigatureSubst( TTO_LigatureSubst* ls, FT_Memory memory ) { FT_UShort n, count; TTO_LigatureSet* lset; if ( ls->LigatureSet ) { count = ls->LigatureSetCount; lset = ls->LigatureSet; for ( n = 0; n < count; n++ ) Free_LigatureSet( &lset[n], memory ); FREE( lset ); } Free_Coverage( &ls->Coverage, memory ); } static FT_Error Lookup_LigatureSubst( TTO_LigatureSubst* ls, OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) { FT_UShort index, property; FT_Error error; FT_UShort numlig, i, j, is_mark, first_is_mark = FALSE; FT_UShort* c; TTO_Ligature* lig; if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) return error; if ( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) first_is_mark = TRUE; error = Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index ); if ( error ) return error; if ( index >= ls->LigatureSetCount ) return TTO_Err_Invalid_GSUB_SubTable; lig = ls->LigatureSet[index].Ligature; for ( numlig = ls->LigatureSet[index].LigatureCount; numlig; numlig--, lig++ ) { if ( buffer->in_pos + lig->ComponentCount > buffer->in_length ) goto next_ligature; /* Not enough glyphs in input */ c = lig->Component; is_mark = first_is_mark; if ( context_length != 0xFFFF && context_length < lig->ComponentCount ) break; for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ ) { while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; if ( j + lig->ComponentCount - i == (FT_Int)buffer->in_length ) goto next_ligature; j++; } if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) ) is_mark = FALSE; if ( IN_GLYPH( j ) != c[i - 1] ) goto next_ligature; } if ( gdef && gdef->NewGlyphClasses ) { /* this is just a guess ... */ error = Add_Glyph_Property( gdef, lig->LigGlyph, is_mark ? TTO_MARK : TTO_LIGATURE ); if ( error && error != TTO_Err_Not_Covered ) return error; } if ( j == buffer->in_pos + i ) /* No input glyphs skipped */ { /* We don't use a new ligature ID if there are no skipped glyphs and the ligature already has an ID. */ if ( IN_LIGID( buffer->in_pos ) ) { if ( ADD_String( buffer, i, 1, &lig->LigGlyph, 0xFFFF, 0xFFFF ) ) return error; } else { FT_UShort ligID = otl_buffer_allocate_ligid( buffer ); if ( ADD_String( buffer, i, 1, &lig->LigGlyph, 0xFFFF, ligID ) ) return error; } } else { FT_UShort ligID = otl_buffer_allocate_ligid( buffer ); if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) ) return error; /* Now we must do a second loop to copy the skipped glyphs to `out' and assign component values to it. We start with the glyph after the first component. Glyphs between component i and i+1 belong to component i. Together with the ligID value it is later possible to check whether a specific component value really belongs to a given ligature. */ for ( i = 0; i < lig->ComponentCount - 1; i++ ) { while ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) ) return error; (buffer->in_pos)++; } } return TT_Err_Ok; next_ligature: ; } return TTO_Err_Not_Covered; } /* Do the actual substitution for a context substitution (either format 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 ) { FT_Error error; FT_UShort i, old_pos; i = 0; while ( i < GlyphCount ) { if ( SubstCount && i == subst->SequenceIndex ) { old_pos = buffer->in_pos; /* Do a substitution */ error = GSub_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer, GlyphCount, nesting_level ); subst++; SubstCount--; i += buffer->in_pos - old_pos; if ( error == TTO_Err_Not_Covered ) { /* XXX "can't happen" -- but don't count on it */ if ( ADD_Glyph( buffer, IN_CURGLYPH(), 0xFFFF, 0xFFFF ) ) return error; i++; } else if ( error ) return error; } else { /* No substitution for this index */ if ( ADD_Glyph( buffer, IN_CURGLYPH(), 0xFFFF, 0xFFFF ) ) return error; i++; } } return TT_Err_Ok;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -