📄 harfbuzz-gsub.c
字号:
/* * Copyright (C) 1998-2004 David Turner and Werner Lemberg * Copyright (C) 2006 Behdad Esfahbod * Copyright (C) 2007 Red Hat, Inc. * * This is part of HarfBuzz, an OpenType Layout engine library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod */#include "harfbuzz-impl.h"#include "harfbuzz-gsub-private.h"#include "harfbuzz-open-private.h"#include "harfbuzz-gdef-private.h"static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub, HB_UShort lookup_index, HB_Buffer buffer, HB_UShort context_length, int nesting_level );/********************** * Auxiliary functions **********************/HB_Error HB_Load_GSUB_Table( HB_Font font, HB_GSUBHeader** retptr, HB_GDEFHeader* gdef ){ HB_Stream stream = font->stream; HB_Error error; HB_UInt cur_offset, new_offset, base_offset; HB_GSUBHeader* gsub; if ( !retptr ) return ERR(HB_Err_Invalid_Argument); if ( GOTO_Table( TTAG_GSUB ) ) return error; base_offset = FILE_Pos(); if ( ALLOC ( gsub, sizeof( *gsub ) ) ) return error; /* 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 = _HB_OPEN_Load_ScriptList( &gsub->ScriptList, stream ) ) != HB_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 = _HB_OPEN_Load_FeatureList( &gsub->FeatureList, stream ) ) != HB_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 = _HB_OPEN_Load_LookupList( &gsub->LookupList, stream, HB_Type_GSUB ) ) != HB_Err_Ok ) goto Fail2; gsub->gdef = gdef; /* can be NULL */ if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream, gsub->LookupList.Lookup, gsub->LookupList.LookupCount ) ) ) goto Fail1; *retptr = gsub; return HB_Err_Ok;Fail1: _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );Fail2: _HB_OPEN_Free_FeatureList( &gsub->FeatureList );Fail3: _HB_OPEN_Free_ScriptList( &gsub->ScriptList );Fail4: FREE ( gsub ); return error;}HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub ){ _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB ); _HB_OPEN_Free_FeatureList( &gsub->FeatureList ); _HB_OPEN_Free_ScriptList( &gsub->ScriptList ); FREE( gsub ); return HB_Err_Ok;}/***************************** * SubTable related functions *****************************//* LookupType 1 *//* SingleSubstFormat1 *//* SingleSubstFormat2 */static HB_Error Load_SingleSubst( HB_GSUB_SubTable* st, HB_Stream stream ){ HB_Error error; HB_SingleSubst* ss = &st->single; HB_UShort n, count; HB_UInt cur_offset, new_offset, base_offset; HB_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 = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_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, HB_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 ERR(HB_Err_Invalid_SubTable_Format); } return HB_Err_Ok;Fail1: FREE( s );Fail2: _HB_OPEN_Free_Coverage( &ss->Coverage ); return error;}static void Free_SingleSubst( HB_GSUB_SubTable* st ){ HB_SingleSubst* ss = &st->single; switch ( ss->SubstFormat ) { case 1: break; case 2: FREE( ss->ssf.ssf2.Substitute ); break; default: break; } _HB_OPEN_Free_Coverage( &ss->Coverage );}static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub, HB_GSUB_SubTable* st, HB_Buffer buffer, HB_UShort flags, HB_UShort context_length, int nesting_level ){ HB_UShort index, value, property; HB_Error error; HB_SingleSubst* ss = &st->single; HB_GDEFHeader* gdef = gsub->gdef; HB_UNUSED(nesting_level); if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_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 ( REPLACE_Glyph( buffer, value, nesting_level ) ) return error; break; case 2: if ( index >= ss->ssf.ssf2.GlyphCount ) return ERR(HB_Err_Invalid_SubTable); value = ss->ssf.ssf2.Substitute[index]; if ( REPLACE_Glyph( buffer, value, nesting_level ) ) return error; break; default: return ERR(HB_Err_Invalid_SubTable); } if ( gdef && gdef->NewGlyphClasses ) { /* we inherit the old glyph class to the substituted glyph */ error = _HB_GDEF_Add_Glyph_Property( gdef, value, property ); if ( error && error != HB_Err_Not_Covered ) return error; } return HB_Err_Ok;}/* LookupType 2 *//* Sequence */static HB_Error Load_Sequence( HB_Sequence* s, HB_Stream stream ){ HB_Error error; HB_UShort n, count; HB_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, HB_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 HB_Err_Ok;}static void Free_Sequence( HB_Sequence* s ){ FREE( s->Substitute );}/* MultipleSubstFormat1 */static HB_Error Load_MultipleSubst( HB_GSUB_SubTable* st, HB_Stream stream ){ HB_Error error; HB_MultipleSubst* ms = &st->multiple; HB_UShort n = 0, m, count; HB_UInt cur_offset, new_offset, base_offset; HB_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 = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_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, HB_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 ) ) != HB_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } return HB_Err_Ok;Fail1: for ( m = 0; m < n; m++ ) Free_Sequence( &s[m] ); FREE( s );Fail2: _HB_OPEN_Free_Coverage( &ms->Coverage ); return error;}static void Free_MultipleSubst( HB_GSUB_SubTable* st ){ HB_UShort n, count; HB_MultipleSubst* ms = &st->multiple; HB_Sequence* s; if ( ms->Sequence ) { count = ms->SequenceCount; s = ms->Sequence; for ( n = 0; n < count; n++ ) Free_Sequence( &s[n] ); FREE( s ); } _HB_OPEN_Free_Coverage( &ms->Coverage );}static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub, HB_GSUB_SubTable* st, HB_Buffer buffer, HB_UShort flags, HB_UShort context_length, int nesting_level ){ HB_Error error; HB_UShort index, property, n, count; HB_UShort*s; HB_MultipleSubst* ms = &st->multiple; HB_GDEFHeader* gdef = gsub->gdef; HB_UNUSED(nesting_level); if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index ); if ( error ) return error; if ( index >= ms->SequenceCount ) return ERR(HB_Err_Invalid_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 == HB_GDEF_LIGATURE ) property = HB_GDEF_BASE_GLYPH; for ( n = 0; n < count; n++ ) { error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property ); if ( error && error != HB_Err_Not_Covered ) return error; } } return HB_Err_Ok;}/* LookupType 3 *//* AlternateSet */static HB_Error Load_AlternateSet( HB_AlternateSet* as, HB_Stream stream ){ HB_Error error; HB_UShort n, count; HB_UShort* a; if ( ACCESS_Frame( 2L ) ) return error; count = as->GlyphCount = GET_UShort(); FORGET_Frame(); as->Alternate = NULL; if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) ) return error; a = as->Alternate; if ( ACCESS_Frame( count * 2L ) ) { FREE( a ); return error; } for ( n = 0; n < count; n++ ) a[n] = GET_UShort(); FORGET_Frame(); return HB_Err_Ok;}static void Free_AlternateSet( HB_AlternateSet* as ){ FREE( as->Alternate );}/* AlternateSubstFormat1 */static HB_Error Load_AlternateSubst( HB_GSUB_SubTable* st, HB_Stream stream ){ HB_Error error; HB_AlternateSubst* as = &st->alternate; HB_UShort n = 0, m, count; HB_UInt cur_offset, new_offset, base_offset; HB_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 = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_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, HB_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 ) ) != HB_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } return HB_Err_Ok;Fail1:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -