📄 ftxgsub.c
字号:
/******************************************************************* * * ftxgsub.c * * TrueType Open GSUB table support. * * Copyright 1996-2000 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used * modified and distributed under the terms of the FreeType project * license, LICENSE.TXT. By continuing to use, modify, or distribute * this file you indicate that you have read the license and * understand and accept it fully. * ******************************************************************//* XXX There is *a lot* of duplicated code (cf. formats 5 and 6), but I don't care currently. I believe that it would be possible to save about 50% of TTO code by carefully designing the structures, sharing as much as possible with extensive use of macros. This is something for a volunteer :-) */#define EXPORT_FUNC#include "ftxopen.h"#include "ftxopenf.h"#include "ftglue.h"#include FT_TRUETYPE_TAGS_H#define GSUB_ID Build_Extension_ID( 'G', 'S', 'U', 'B' ) static FT_Error GSub_Do_Glyph_Lookup( TTO_GSUBHeader* gsub, FT_UShort lookup_index, OTL_Buffer buffer, FT_UShort context_length, int nesting_level ); /********************** * Auxiliary functions **********************/ EXPORT_FUNC FT_Error TT_Load_GSUB_Table( FT_Face face, TTO_GSUBHeader** retptr, TTO_GDEFHeader* gdef ) { FT_Stream stream = face->stream; FT_Memory memory = face->memory; FT_Error error; FT_ULong cur_offset, new_offset, base_offset; FT_UShort i, num_lookups; TTO_GSUBHeader* gsub; TTO_Lookup* lo; if ( !retptr ) return TT_Err_Invalid_Argument; if (( error = ftglue_face_goto_table( face, TTAG_GSUB, stream ) )) return error; base_offset = FILE_Pos(); if ( ALLOC ( gsub, sizeof( *gsub ) ) ) return error; gsub->memory = memory; /* skip version */ if ( FILE_Seek( base_offset + 4L ) || ACCESS_Frame( 2L ) ) goto Fail4; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_ScriptList( &gsub->ScriptList, stream ) ) != TT_Err_Ok ) goto Fail4; (void)FILE_Seek( cur_offset ); 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_FeatureList( &gsub->FeatureList, stream ) ) != TT_Err_Ok ) goto Fail3; (void)FILE_Seek( cur_offset ); 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_LookupList( &gsub->LookupList, stream, GSUB ) ) != TT_Err_Ok ) goto Fail2; gsub->gdef = gdef; /* can be NULL */ /* We now check the LookupFlags for values larger than 0xFF to find out whether we need to load the `MarkAttachClassDef' field of the GDEF table -- this hack is necessary for OpenType 1.2 tables since the version field of the GDEF table hasn't been incremented. For constructed GDEF tables, we only load it if `MarkAttachClassDef_offset' is not zero (nevertheless, a build of a constructed mark attach table is not supported currently). */ if ( gdef && gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) { lo = gsub->LookupList.Lookup; num_lookups = gsub->LookupList.LookupCount; for ( i = 0; i < num_lookups; i++ ) { if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS ) { if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef, 256, stream ) ) != TT_Err_Ok ) goto Fail1; break; } } } *retptr = gsub; return TT_Err_Ok; Fail1: Free_LookupList( &gsub->LookupList, GSUB, memory ); Fail2: Free_FeatureList( &gsub->FeatureList, memory ); Fail3: Free_ScriptList( &gsub->ScriptList, memory ); Fail4: FREE ( gsub ); return error; } EXPORT_FUNC FT_Error TT_Done_GSUB_Table( TTO_GSUBHeader* gsub ) { FT_Memory memory = gsub->memory; Free_LookupList( &gsub->LookupList, GSUB, memory ); Free_FeatureList( &gsub->FeatureList, memory ); Free_ScriptList( &gsub->ScriptList, memory ); FREE( gsub ); return TT_Err_Ok; } /***************************** * SubTable related functions *****************************/ /* LookupType 1 */ /* SingleSubstFormat1 */ /* SingleSubstFormat2 */ FT_Error Load_SingleSubst( TTO_SingleSubst* ss, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n, count; FT_ULong cur_offset, new_offset, base_offset; FT_UShort* s; base_offset = FILE_Pos(); if ( ACCESS_Frame( 4L ) ) return error; ss->SubstFormat = GET_UShort(); new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Coverage( &ss->Coverage, stream ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); switch ( ss->SubstFormat ) { case 1: if ( ACCESS_Frame( 2L ) ) goto Fail2; ss->ssf.ssf1.DeltaGlyphID = GET_UShort(); FORGET_Frame(); break; case 2: if ( ACCESS_Frame( 2L ) ) goto Fail2; count = ss->ssf.ssf2.GlyphCount = GET_UShort(); FORGET_Frame(); ss->ssf.ssf2.Substitute = NULL; if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, FT_UShort ) ) goto Fail2; s = ss->ssf.ssf2.Substitute; if ( ACCESS_Frame( count * 2L ) ) goto Fail1; for ( n = 0; n < count; n++ ) s[n] = GET_UShort(); FORGET_Frame(); break; default: return TTO_Err_Invalid_GSUB_SubTable_Format; } return TT_Err_Ok; Fail1: FREE( s ); Fail2: Free_Coverage( &ss->Coverage, memory ); return error; } void Free_SingleSubst( TTO_SingleSubst* ss, FT_Memory memory ) { switch ( ss->SubstFormat ) { case 1: break; case 2: FREE( ss->ssf.ssf2.Substitute ); break; } Free_Coverage( &ss->Coverage, memory ); } static FT_Error Lookup_SingleSubst( TTO_SingleSubst* ss, OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) { FT_UShort index, value, property; FT_Error error; 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( &ss->Coverage, IN_CURGLYPH(), &index ); if ( error ) return error; switch ( ss->SubstFormat ) { case 1: value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF; if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) return error; break; case 2: if ( index >= ss->ssf.ssf2.GlyphCount ) return TTO_Err_Invalid_GSUB_SubTable; value = ss->ssf.ssf2.Substitute[index]; if ( ADD_Glyph( buffer, value, 0xFFFF, 0xFFFF ) ) return error; break; default: return TTO_Err_Invalid_GSUB_SubTable; } if ( gdef && gdef->NewGlyphClasses ) { /* we inherit the old glyph class to the substituted glyph */ error = Add_Glyph_Property( gdef, value, property ); if ( error && error != TTO_Err_Not_Covered ) return error; } return TT_Err_Ok; } /* LookupType 2 */ /* Sequence */ static FT_Error Load_Sequence( TTO_Sequence* s, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n, count; FT_UShort* sub; if ( ACCESS_Frame( 2L ) ) return error; count = s->GlyphCount = GET_UShort(); FORGET_Frame(); s->Substitute = NULL; if ( count ) { if ( ALLOC_ARRAY( s->Substitute, count, FT_UShort ) ) return error; sub = s->Substitute; if ( ACCESS_Frame( count * 2L ) ) { FREE( sub ); return error; } for ( n = 0; n < count; n++ ) sub[n] = GET_UShort(); FORGET_Frame(); } return TT_Err_Ok; } static void Free_Sequence( TTO_Sequence* s, FT_Memory memory ) { FREE( s->Substitute ); } /* MultipleSubstFormat1 */ FT_Error Load_MultipleSubst( TTO_MultipleSubst* ms, 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_Sequence* s; base_offset = FILE_Pos(); if ( ACCESS_Frame( 4L ) ) return error; ms->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( &ms->Coverage, stream ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail2; count = ms->SequenceCount = GET_UShort(); FORGET_Frame(); ms->Sequence = NULL; if ( ALLOC_ARRAY( ms->Sequence, count, TTO_Sequence ) ) goto Fail2; s = ms->Sequence; 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_Sequence( &s[n], stream ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } return TT_Err_Ok; Fail1: for ( m = 0; m < n; m++ ) Free_Sequence( &s[m], memory ); FREE( s ); Fail2: Free_Coverage( &ms->Coverage, memory ); return error; } void Free_MultipleSubst( TTO_MultipleSubst* ms, FT_Memory memory ) { FT_UShort n, count; TTO_Sequence* s; if ( ms->Sequence ) { count = ms->SequenceCount; s = ms->Sequence; for ( n = 0; n < count; n++ ) Free_Sequence( &s[n], memory ); FREE( s ); } Free_Coverage( &ms->Coverage, memory ); } static FT_Error Lookup_MultipleSubst( TTO_MultipleSubst* ms, OTL_Buffer buffer, FT_UShort flags, FT_UShort context_length, TTO_GDEFHeader* gdef ) { FT_Error error; FT_UShort index, property, n, count; FT_UShort*s; 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( &ms->Coverage, IN_CURGLYPH(), &index ); if ( error ) return error; if ( index >= ms->SequenceCount ) return TTO_Err_Invalid_GSUB_SubTable; count = ms->Sequence[index].GlyphCount; s = ms->Sequence[index].Substitute; if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) ) return error; if ( gdef && gdef->NewGlyphClasses ) { /* this is a guess only ... */ if ( property == TTO_LIGATURE ) property = TTO_BASE_GLYPH; for ( n = 0; n < count; n++ ) { error = Add_Glyph_Property( gdef, s[n], property ); if ( error && error != TTO_Err_Not_Covered ) return error; } } return TT_Err_Ok; } /* LookupType 3 */ /* AlternateSet */ static FT_Error Load_AlternateSet( TTO_AlternateSet* as, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort n, count; FT_UShort* a; if ( ACCESS_Frame( 2L ) ) return error; count = as->GlyphCount = GET_UShort(); FORGET_Frame(); as->Alternate = NULL; if ( ALLOC_ARRAY( as->Alternate, count, FT_UShort ) ) return error; a = as->Alternate; if ( ACCESS_Frame( count * 2L ) ) { FREE( a ); return error; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -