📄 ftxgsub.c
字号:
Free_Coverage( &ls->Coverage ); return error; } void Free_LigatureSubst( TTO_LigatureSubst* ls ) { 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] ); FREE( lset ); } Free_Coverage( &ls->Coverage ); } static TT_Error Lookup_LigatureSubst( TTO_LigatureSubst* ls, TTO_GSUB_String* in, TTO_GSUB_String* out, UShort flags, UShort context_length, TTO_GDEFHeader* gdef ) { UShort index, property; TT_Error error; UShort numlig, i, j, is_mark, first_is_mark = FALSE; UShort first_ligID, first_comp; UShort *s_in, *lig_in, *comp_in; UShort* c; TTO_Ligature* lig; if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) return error; if ( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) first_is_mark = TRUE; error = Coverage_Index( &ls->Coverage, in->string[in->pos], &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 ( in->pos + lig->ComponentCount > in->length ) continue; /* Not enough glyphs in input */ s_in = &in->string[in->pos]; lig_in = &in->ligIDs[in->pos]; comp_in = &in->components[in->pos]; first_ligID = *lig_in; first_comp = *comp_in; c = lig->Component; is_mark = first_is_mark; if ( context_length != 0xFFFF && context_length < lig->ComponentCount ) break; for ( i = 1, j = 1; i < lig->ComponentCount; i++, j++ ) { while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; if ( in->pos + j < in->length ) j++; else break; } /* don't apply a ligature lookup to glyphs with different ligature IDs. Example: ' ^' ' ^ f ^ l ' -> fl ^ ' -> fl but not fl ^ -> fl */ if ( first_ligID != lig_in[j] ) break; /* don't apply a ligature lookup to glyphs with different component values. Example: ' ^' ' ^ f ^ f ' l -> ffl ^ ' -> ffl but not ffl ^ -> ffl */ if ( first_comp != comp_in[j] ) break; if ( !( property == TTO_MARK || property & IGNORE_SPECIAL_MARKS ) ) is_mark = FALSE; if ( s_in[j] != c[i - 1] ) break; } if ( i == lig->ComponentCount ) { 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 ( i == j ) { /* We don't use a new ligature ID if there are no skipped glyphs and the ligature already has an ID. */ if ( in->ligIDs[in->pos] ) { if ( ADD_String( in, i, out, 1, &lig->LigGlyph, 0xFFFF, 0xFFFF ) ) return error; } else { if ( ADD_String( in, i, out, 1, &lig->LigGlyph, 0xFFFF, in->max_ligID ) ) return error; (in->max_ligID)++; } } else { if ( ADD_String( in, 1, out, 1, &lig->LigGlyph, 0xFFFF, in->max_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->string[in->pos], flags, &property ) ) if ( ADD_String( in, 1, out, 1, &in->string[in->pos], i, in->max_ligID ) ) return error; (in->pos)++; } (in->max_ligID)++; } return TT_Err_Ok; } } 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 TT_Error Do_ContextSubst( TTO_GSUBHeader* gsub, UShort GlyphCount, UShort SubstCount, TTO_SubstLookupRecord* subst, TTO_GSUB_String* in, TTO_GSUB_String* out, int nesting_level ) { TT_Error error; UShort i, old_pos; i = 0; while ( i < GlyphCount ) { if ( SubstCount && i == subst->SequenceIndex ) { old_pos = in->pos; /* Do a substitution */ error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, in, out, GlyphCount, nesting_level ); subst++; SubstCount--; i += in->pos - old_pos; if ( error == TTO_Err_Not_Covered ) { /* XXX "can't happen" -- but don't count on it */ if ( ADD_String( in, 1, out, 1, &in->string[in->pos], 0xFFFF, 0xFFFF ) ) return error; i++; } else if ( error ) return error; } else { /* No substitution for this index */ if ( ADD_String( in, 1, out, 1, &in->string[in->pos], 0xFFFF, 0xFFFF ) ) return error; i++; } } return TT_Err_Ok; } /* LookupType 5 */ /* SubRule */ static TT_Error Load_SubRule( TTO_SubRule* sr, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; UShort* i; TTO_SubstLookupRecord* slr; if ( ACCESS_Frame( 4L ) ) return error; sr->GlyphCount = GET_UShort(); sr->SubstCount = GET_UShort(); FORGET_Frame(); sr->Input = NULL; count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */ if ( ALLOC_ARRAY( sr->Input, count, UShort ) ) return error; i = sr->Input; if ( ACCESS_Frame( count * 2L ) ) goto Fail2; for ( n = 0; n < count; n++ ) i[n] = GET_UShort(); FORGET_Frame(); sr->SubstLookupRecord = NULL; count = sr->SubstCount; if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, TTO_SubstLookupRecord ) ) goto Fail2; slr = sr->SubstLookupRecord; if ( ACCESS_Frame( count * 4L ) ) goto Fail1; for ( n = 0; n < count; n++ ) { slr[n].SequenceIndex = GET_UShort(); slr[n].LookupListIndex = GET_UShort(); } FORGET_Frame(); return TT_Err_Ok; Fail1: FREE( slr ); Fail2: FREE( i ); return error; } static void Free_SubRule( TTO_SubRule* sr ) { FREE( sr->SubstLookupRecord ); FREE( sr->Input ); } /* SubRuleSet */ static TT_Error Load_SubRuleSet( TTO_SubRuleSet* srs, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; ULong cur_offset, new_offset, base_offset; TTO_SubRule* sr; base_offset = FILE_Pos(); if ( ACCESS_Frame( 2L ) ) return error; count = srs->SubRuleCount = GET_UShort(); FORGET_Frame(); srs->SubRule = NULL; if ( ALLOC_ARRAY( srs->SubRule, count, TTO_SubRule ) ) return error; sr = srs->SubRule; 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_SubRule( &sr[n], input ) ) != TT_Err_Ok ) goto Fail; (void)FILE_Seek( cur_offset ); } return TT_Err_Ok; Fail: for ( n = 0; n < count; n++ ) Free_SubRule( &sr[n] ); FREE( sr ); return error; } static void Free_SubRuleSet( TTO_SubRuleSet* srs ) { UShort n, count; TTO_SubRule* sr; if ( srs->SubRule ) { count = srs->SubRuleCount; sr = srs->SubRule; for ( n = 0; n < count; n++ ) Free_SubRule( &sr[n] ); FREE( sr ); } } /* ContextSubstFormat1 */ static TT_Error Load_ContextSubst1( TTO_ContextSubstFormat1* csf1, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; ULong cur_offset, new_offset, base_offset; TTO_SubRuleSet* srs; base_offset = FILE_Pos() - 2L; 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( &csf1->Coverage, input ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail2; count = csf1->SubRuleSetCount = GET_UShort(); FORGET_Frame(); csf1->SubRuleSet = NULL; if ( ALLOC_ARRAY( csf1->SubRuleSet, count, TTO_SubRuleSet ) ) goto Fail2; srs = csf1->SubRuleSet; 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_SubRuleSet( &srs[n], input ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } return TT_Err_Ok; Fail1: for ( n = 0; n < count; n++ ) Free_SubRuleSet( &srs[n] ); FREE( srs ); Fail2: Free_Coverage( &csf1->Coverage ); return error; } static void Free_Context1( TTO_ContextSubstFormat1* csf1 ) { UShort n, count; TTO_SubRuleSet* srs; if ( csf1->SubRuleSet ) { count = csf1->SubRuleSetCount; srs = csf1->SubRuleSet; for ( n = 0; n < count; n++ ) Free_SubRuleSet( &srs[n] ); FREE( srs ); } Free_Coverage( &csf1->Coverage ); } /* SubClassRule */ static TT_Error Load_SubClassRule( TTO_ContextSubstFormat2* csf2, TTO_SubClassRule* scr, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; UShort* c; TTO_SubstLookupRecord* slr; Bool* d; if ( ACCESS_Frame( 4L ) ) return error; scr->GlyphCount = GET_UShort(); scr->SubstCount = GET_UShort(); if ( scr->GlyphCount > csf2->MaxContextLength ) csf2->MaxContextLength = scr->GlyphCount; FORGET_Frame(); scr->Class = NULL; count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */ if ( ALLOC_ARRAY( scr->Class, count, UShort ) ) return error; c = scr->Class; d = csf2->ClassDef.Defined; if ( ACCESS_Frame( count * 2L ) ) goto Fail2; for ( n = 0; n < count; n++ ) { c[n] = GET_UShort(); /* We check whether the specific class is used at all. If not, class 0 is used instead. */ if ( !d[c[n]] ) c[n] = 0; } FORGET_Frame(); scr->SubstLookupRecord = NULL; count = scr->SubstCount; if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, TTO_SubstLookupRecord ) ) goto Fail2; slr = scr->SubstLookupRecord; if ( ACCESS_Frame( count * 4L ) ) goto Fail1; for ( n = 0; n < count; n++ ) { slr[n].SequenceIndex = GET_UShort(); slr[n].LookupListIndex = GET_UShort(); } FORGET_Frame(); return TT_Err_Ok; Fail1: FREE( slr ); Fail2: FREE( c ); return error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -