diff options
Diffstat (limited to 'src/ftxopen.c')
-rw-r--r-- | src/ftxopen.c | 1467 |
1 files changed, 1467 insertions, 0 deletions
diff --git a/src/ftxopen.c b/src/ftxopen.c new file mode 100644 index 00000000..5ffe030a --- /dev/null +++ b/src/ftxopen.c @@ -0,0 +1,1467 @@ +/******************************************************************* + * + * ftxopen.c + * + * TrueType Open common 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. + * + ******************************************************************/ + +#include <freetype/internal/ftstream.h> +#include <freetype/internal/ftmemory.h> +#include <freetype/internal/tterrors.h> +#include <freetype/internal/tttypes.h> + +#include "ftxopen.h" +#include "ftxopenf.h" + + + /*************************** + * Script related functions + ***************************/ + + + /* LangSys */ + + static FT_Error Load_LangSys( TTO_LangSys* ls, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort n, count; + FT_UShort* fi; + + + if ( ACCESS_Frame( 6L ) ) + return error; + + ls->LookupOrderOffset = GET_UShort(); /* should be 0 */ + ls->ReqFeatureIndex = GET_UShort(); + count = ls->FeatureCount = GET_UShort(); + + FORGET_Frame(); + + ls->FeatureIndex = NULL; + + if ( ALLOC_ARRAY( ls->FeatureIndex, count, FT_UShort ) ) + return error; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( ls->FeatureIndex ); + return error; + } + + fi = ls->FeatureIndex; + + for ( n = 0; n < count; n++ ) + fi[n] = GET_UShort(); + + FORGET_Frame(); + + return TT_Err_Ok; + } + + + static void Free_LangSys( TTO_LangSys* ls, + FT_Memory memory ) + { + FREE( ls->FeatureIndex ); + } + + + /* Script */ + + static FT_Error Load_Script( TTO_Script* s, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + TTO_LangSysRecord* lsr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + if ( new_offset != base_offset ) /* not a NULL offset */ + { + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LangSys( &s->DefaultLangSys, + stream ) ) != TT_Err_Ok ) + return error; + (void)FILE_Seek( cur_offset ); + } + else + { + /* we create a DefaultLangSys table with no entries */ + + s->DefaultLangSys.LookupOrderOffset = 0; + s->DefaultLangSys.ReqFeatureIndex = 0xFFFF; + s->DefaultLangSys.FeatureCount = 0; + s->DefaultLangSys.FeatureIndex = NULL; + } + + if ( ACCESS_Frame( 2L ) ) + goto Fail2; + + count = s->LangSysCount = GET_UShort(); + + /* safety check; otherwise the official handling of TrueType Open + fonts won't work */ + + if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 ) + { + error = TTO_Err_Invalid_SubTable; + goto Fail2; + } + + FORGET_Frame(); + + s->LangSysRecord = NULL; + + if ( ALLOC_ARRAY( s->LangSysRecord, count, TTO_LangSysRecord ) ) + goto Fail2; + + lsr = s->LangSysRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 6L ) ) + goto Fail1; + + lsr[n].LangSysTag = GET_ULong(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != TT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return TT_Err_Ok; + + Fail1: + for ( n = 0; n < count; n++ ) + Free_LangSys( &lsr[n].LangSys, memory ); + + FREE( s->LangSysRecord ); + + Fail2: + Free_LangSys( &s->DefaultLangSys, memory ); + return error; + } + + + static void Free_Script( TTO_Script* s, + FT_Memory memory ) + { + FT_UShort n, count; + + TTO_LangSysRecord* lsr; + + + Free_LangSys( &s->DefaultLangSys, memory ); + + if ( s->LangSysRecord ) + { + count = s->LangSysCount; + lsr = s->LangSysRecord; + + for ( n = 0; n < count; n++ ) + Free_LangSys( &lsr[n].LangSys, memory ); + + FREE( lsr ); + } + } + + + /* ScriptList */ + + FT_Error Load_ScriptList( TTO_ScriptList* sl, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + TTO_ScriptRecord* sr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = sl->ScriptCount = GET_UShort(); + + FORGET_Frame(); + + sl->ScriptRecord = NULL; + + if ( ALLOC_ARRAY( sl->ScriptRecord, count, TTO_ScriptRecord ) ) + return error; + + sr = sl->ScriptRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 6L ) ) + goto Fail; + + sr[n].ScriptTag = GET_ULong(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Script( &sr[n].Script, stream ) ) != TT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return TT_Err_Ok; + + Fail: + for ( n = 0; n < count; n++ ) + Free_Script( &sr[n].Script, memory ); + + FREE( sl->ScriptRecord ); + return error; + } + + + void Free_ScriptList( TTO_ScriptList* sl, + FT_Memory memory ) + { + FT_UShort n, count; + + TTO_ScriptRecord* sr; + + + if ( sl->ScriptRecord ) + { + count = sl->ScriptCount; + sr = sl->ScriptRecord; + + for ( n = 0; n < count; n++ ) + Free_Script( &sr[n].Script, memory ); + + FREE( sr ); + } + } + + + + /********************************* + * Feature List related functions + *********************************/ + + + /* Feature */ + + static FT_Error Load_Feature( TTO_Feature* f, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* lli; + + + if ( ACCESS_Frame( 4L ) ) + return error; + + f->FeatureParams = GET_UShort(); /* should be 0 */ + count = f->LookupListCount = GET_UShort(); + + FORGET_Frame(); + + f->LookupListIndex = NULL; + + if ( ALLOC_ARRAY( f->LookupListIndex, count, FT_UShort ) ) + return error; + + lli = f->LookupListIndex; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( f->LookupListIndex ); + return error; + } + + for ( n = 0; n < count; n++ ) + lli[n] = GET_UShort(); + + FORGET_Frame(); + + return TT_Err_Ok; + } + + + static void Free_Feature( TTO_Feature* f, + FT_Memory memory ) + { + FREE( f->LookupListIndex ); + } + + + /* FeatureList */ + + FT_Error Load_FeatureList( TTO_FeatureList* fl, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + TTO_FeatureRecord* fr; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = fl->FeatureCount = GET_UShort(); + + FORGET_Frame(); + + fl->FeatureRecord = NULL; + + if ( ALLOC_ARRAY( fl->FeatureRecord, count, TTO_FeatureRecord ) ) + return error; + + fr = fl->FeatureRecord; + + for ( n = 0; n < count; n++ ) + { + if ( ACCESS_Frame( 6L ) ) + goto Fail; + + fr[n].FeatureTag = GET_ULong(); + new_offset = GET_UShort() + base_offset; + + FORGET_Frame(); + + cur_offset = FILE_Pos(); + if ( FILE_Seek( new_offset ) || + ( error = Load_Feature( &fr[n].Feature, stream ) ) != TT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return TT_Err_Ok; + + Fail: + for ( n = 0; n < count; n++ ) + Free_Feature( &fr[n].Feature, memory ); + + FREE( fl->FeatureRecord ); + return error; + } + + + void Free_FeatureList( TTO_FeatureList* fl, + FT_Memory memory) + { + FT_UShort n, count; + + TTO_FeatureRecord* fr; + + + if ( fl->FeatureRecord ) + { + count = fl->FeatureCount; + fr = fl->FeatureRecord; + + for ( n = 0; n < count; n++ ) + Free_Feature( &fr[n].Feature, memory ); + + FREE( fr ); + } + } + + + + /******************************** + * Lookup List related functions + ********************************/ + + /* the subroutines of the following two functions are defined in + ftxgsub.c and ftxgpos.c respectively */ + + + /* SubTable */ + + static FT_Error Load_SubTable( TTO_SubTable* st, + FT_Stream stream, + TTO_Type table_type, + FT_UShort lookup_type ) + { + if ( table_type == GSUB ) + switch ( lookup_type ) + { + case GSUB_LOOKUP_SINGLE: + return Load_SingleSubst( &st->st.gsub.single, stream ); + + case GSUB_LOOKUP_MULTIPLE: + return Load_MultipleSubst( &st->st.gsub.multiple, stream ); + + case GSUB_LOOKUP_ALTERNATE: + return Load_AlternateSubst( &st->st.gsub.alternate, stream ); + + case GSUB_LOOKUP_LIGATURE: + return Load_LigatureSubst( &st->st.gsub.ligature, stream ); + + case GSUB_LOOKUP_CONTEXT: + return Load_ContextSubst( &st->st.gsub.context, stream ); + + case GSUB_LOOKUP_CHAIN: + return Load_ChainContextSubst( &st->st.gsub.chain, stream ); + + default: + return TTO_Err_Invalid_GSUB_SubTable_Format; + } + else + switch ( lookup_type ) + { +#if 0 + case GPOS_LOOKUP_SINGLE: + return Load_SinglePos( &st->st.gpos.single, stream ); + + case GPOS_LOOKUP_PAIR: + return Load_PairPos( &st->st.gpos.pair, stream ); + + case GPOS_LOOKUP_CURSIVE: + return Load_CursivePos( &st->st.gpos.cursive, stream ); + + case GPOS_LOOKUP_MARKBASE: + return Load_MarkBasePos( &st->st.gpos.markbase, stream ); + + case GPOS_LOOKUP_MARKLIG: + return Load_MarkLigPos( &st->st.gpos.marklig, stream ); + + case GPOS_LOOKUP_MARKMARK: + return Load_MarkMarkPos( &st->st.gpos.markmark, stream ); + + case GPOS_LOOKUP_CONTEXT: + return Load_ContextPos( &st->st.gpos.context, stream ); + + case GPOS_LOOKUP_CHAIN: + return Load_ChainContextPos( &st->st.gpos.chain, stream ); + +#endif + default: + return TTO_Err_Invalid_GPOS_SubTable_Format; + } + + return TT_Err_Ok; /* never reached */ + } + + + static void Free_SubTable( TTO_SubTable* st, + TTO_Type table_type, + FT_UShort lookup_type, + FT_Memory memory ) + { + if ( table_type == GSUB ) + switch ( lookup_type ) + { + case GSUB_LOOKUP_SINGLE: + Free_SingleSubst( &st->st.gsub.single, memory ); + break; + + case GSUB_LOOKUP_MULTIPLE: + Free_MultipleSubst( &st->st.gsub.multiple, memory ); + break; + + case GSUB_LOOKUP_ALTERNATE: + Free_AlternateSubst( &st->st.gsub.alternate, memory ); + break; + + case GSUB_LOOKUP_LIGATURE: + Free_LigatureSubst( &st->st.gsub.ligature, memory ); + break; + + case GSUB_LOOKUP_CONTEXT: + Free_ContextSubst( &st->st.gsub.context, memory ); + break; + + case GSUB_LOOKUP_CHAIN: + Free_ChainContextSubst( &st->st.gsub.chain, memory ); + break; + } + else + switch ( lookup_type ) + { +#if 0 + case GPOS_LOOKUP_SINGLE: + Free_SinglePos( &st->st.gpos.single ); + break; + + case GPOS_LOOKUP_PAIR: + Free_PairPos( &st->st.gpos.pair ); + break; + + case GPOS_LOOKUP_CURSIVE: + Free_CursivePos( &st->st.gpos.cursive ); + break; + + case GPOS_LOOKUP_MARKBASE: + Free_MarkBasePos( &st->st.gpos.markbase ); + break; + + case GPOS_LOOKUP_MARKLIG: + Free_MarkLigPos( &st->st.gpos.marklig ); + break; + + case GPOS_LOOKUP_MARKMARK: + Free_MarkMarkPos( &st->st.gpos.markmark ); + break; + + case GPOS_LOOKUP_CONTEXT: + Free_ContextPos( &st->st.gpos.context ); + break; + + case GPOS_LOOKUP_CHAIN: + Free_ChainContextPos ( &st->st.gpos.chain ); + break; +#endif + } + } + + + /* Lookup */ + + static FT_Error Load_Lookup( TTO_Lookup* l, + FT_Stream stream, + TTO_Type type ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + TTO_SubTable* st; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 6L ) ) + return error; + + l->LookupType = GET_UShort(); + l->LookupFlag = GET_UShort(); + count = l->SubTableCount = GET_UShort(); + + FORGET_Frame(); + + l->SubTable = NULL; + + if ( ALLOC_ARRAY( l->SubTable, count, TTO_SubTable ) ) + return error; + + st = l->SubTable; + + 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_SubTable( &st[n], stream, + type, l->LookupType ) ) != TT_Err_Ok ) + goto Fail; + (void)FILE_Seek( cur_offset ); + } + + return TT_Err_Ok; + + Fail: + for ( n = 0; n < count; n++ ) + Free_SubTable( &st[n], type, l->LookupType, memory ); + + FREE( l->SubTable ); + return error; + } + + + static void Free_Lookup( TTO_Lookup* l, + TTO_Type type, + FT_Memory memory) + { + FT_UShort n, count; + + TTO_SubTable* st; + + + if ( l->SubTable ) + { + count = l->SubTableCount; + st = l->SubTable; + + for ( n = 0; n < count; n++ ) + Free_SubTable( &st[n], type, l->LookupType, memory ); + + FREE( st ); + } + } + + + /* LookupList */ + + FT_Error Load_LookupList( TTO_LookupList* ll, + FT_Stream stream, + TTO_Type type ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + FT_ULong cur_offset, new_offset, base_offset; + + TTO_Lookup* l; + + + base_offset = FILE_Pos(); + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = ll->LookupCount = GET_UShort(); + + FORGET_Frame(); + + ll->Lookup = NULL; + + if ( ALLOC_ARRAY( ll->Lookup, count, TTO_Lookup ) ) + return error; + if ( ALLOC_ARRAY( ll->Properties, count, FT_UShort ) ) + goto Fail2; + + l = ll->Lookup; + + 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_Lookup( &l[n], stream, type ) ) != TT_Err_Ok ) + goto Fail1; + (void)FILE_Seek( cur_offset ); + } + + return TT_Err_Ok; + + Fail1: + FREE( ll->Properties ); + + for ( n = 0; n < count; n++ ) + Free_Lookup( &l[n], type, memory ); + + Fail2: + FREE( ll->Lookup ); + return error; + } + + + void Free_LookupList( TTO_LookupList* ll, + TTO_Type type, + FT_Memory memory ) + { + FT_UShort n, count; + + TTO_Lookup* l; + + + FREE( ll->Properties ); + + if ( ll->Lookup ) + { + count = ll->LookupCount; + l = ll->Lookup; + + for ( n = 0; n < count; n++ ) + Free_Lookup( &l[n], type, memory ); + + FREE( l ); + } + } + + + + /***************************** + * Coverage related functions + *****************************/ + + + /* CoverageFormat1 */ + + static FT_Error Load_Coverage1( TTO_CoverageFormat1* cf1, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* ga; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cf1->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + cf1->GlyphArray = NULL; + + if ( ALLOC_ARRAY( cf1->GlyphArray, count, FT_UShort ) ) + return error; + + ga = cf1->GlyphArray; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( cf1->GlyphArray ); + return error; + } + + for ( n = 0; n < count; n++ ) + ga[n] = GET_UShort(); + + FORGET_Frame(); + + return TT_Err_Ok; + } + + + static void Free_Coverage1( TTO_CoverageFormat1* cf1, + FT_Memory memory) + { + FREE( cf1->GlyphArray ); + } + + + /* CoverageFormat2 */ + + static FT_Error Load_Coverage2( TTO_CoverageFormat2* cf2, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + TTO_RangeRecord* rr; + + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cf2->RangeCount = GET_UShort(); + + FORGET_Frame(); + + cf2->RangeRecord = NULL; + + if ( ALLOC_ARRAY( cf2->RangeRecord, count, TTO_RangeRecord ) ) + return error; + + rr = cf2->RangeRecord; + + if ( ACCESS_Frame( count * 6L ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + rr[n].Start = GET_UShort(); + rr[n].End = GET_UShort(); + rr[n].StartCoverageIndex = GET_UShort(); + + /* sanity check; we are limited to 16bit integers */ + if ( rr[n].Start > rr[n].End || + ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >= + 0x10000L ) + { + error = TTO_Err_Invalid_SubTable; + goto Fail; + } + } + + FORGET_Frame(); + + return TT_Err_Ok; + + Fail: + FREE( cf2->RangeRecord ); + return error; + } + + + static void Free_Coverage2( TTO_CoverageFormat2* cf2, + FT_Memory memory ) + { + FREE( cf2->RangeRecord ); + } + + + FT_Error Load_Coverage( TTO_Coverage* c, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + if ( ACCESS_Frame( 2L ) ) + return error; + + c->CoverageFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( c->CoverageFormat ) + { + case 1: + return Load_Coverage1( &c->cf.cf1, stream ); + + case 2: + return Load_Coverage2( &c->cf.cf2, stream ); + + default: + return TTO_Err_Invalid_SubTable_Format; + } + + return TT_Err_Ok; /* never reached */ + } + + + void Free_Coverage( TTO_Coverage* c, + FT_Memory memory ) + { + switch ( c->CoverageFormat ) + { + case 1: + Free_Coverage1( &c->cf.cf1, memory ); + break; + + case 2: + Free_Coverage2( &c->cf.cf2, memory ); + break; + } + } + + + static FT_Error Coverage_Index1( TTO_CoverageFormat1* cf1, + FT_UShort glyphID, + FT_UShort* index ) + { + FT_UShort min, max, new_min, new_max, middle; + + FT_UShort* array = cf1->GlyphArray; + + + /* binary search */ + + new_min = 0; + new_max = cf1->GlyphCount - 1; + + do + { + min = new_min; + max = new_max; + + /* we use (min + max) / 2 = max - (max - min) / 2 to avoid + overflow and rounding errors */ + + middle = max - ( ( max - min ) >> 1 ); + + if ( glyphID == array[middle] ) + { + *index = middle; + return TT_Err_Ok; + } + else if ( glyphID < array[middle] ) + { + if ( middle == min ) + break; + new_max = middle - 1; + } + else + { + if ( middle == max ) + break; + new_min = middle + 1; + } + } while ( min < max ); + + return TTO_Err_Not_Covered; + } + + + static FT_Error Coverage_Index2( TTO_CoverageFormat2* cf2, + FT_UShort glyphID, + FT_UShort* index ) + { + FT_UShort min, max, new_min, new_max, middle; + + TTO_RangeRecord* rr = cf2->RangeRecord; + + + /* binary search */ + + new_min = 0; + new_max = cf2->RangeCount - 1; + + do + { + min = new_min; + max = new_max; + + /* we use (min + max) / 2 = max - (max - min) / 2 to avoid + overflow and rounding errors */ + + middle = max - ( ( max - min ) >> 1 ); + + if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End ) + { + *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start; + return TT_Err_Ok; + } + else if ( glyphID < rr[middle].Start ) + { + if ( middle == min ) + break; + new_max = middle - 1; + } + else + { + if ( middle == max ) + break; + new_min = middle + 1; + } + } while ( min < max ); + + return TTO_Err_Not_Covered; + } + + + FT_Error Coverage_Index( TTO_Coverage* c, + FT_UShort glyphID, + FT_UShort* index ) + { + switch ( c->CoverageFormat ) + { + case 1: + return Coverage_Index1( &c->cf.cf1, glyphID, index ); + + case 2: + return Coverage_Index2( &c->cf.cf2, glyphID, index ); + + default: + return TTO_Err_Invalid_SubTable_Format; + } + + return TT_Err_Ok; /* never reached */ + } + + + + /************************************* + * Class Definition related functions + *************************************/ + + + /* ClassDefFormat1 */ + + static FT_Error Load_ClassDef1( TTO_ClassDefinition* cd, + FT_UShort limit, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* cva; + FT_Bool* d; + + TTO_ClassDefFormat1* cdf1; + + + cdf1 = &cd->cd.cd1; + + if ( ACCESS_Frame( 4L ) ) + return error; + + cdf1->StartGlyph = GET_UShort(); + count = cdf1->GlyphCount = GET_UShort(); + + FORGET_Frame(); + + /* sanity check; we are limited to 16bit integers */ + + if ( cdf1->StartGlyph + (long)count >= 0x10000L ) + return TTO_Err_Invalid_SubTable; + + cdf1->ClassValueArray = NULL; + + if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, FT_UShort ) ) + return error; + + d = cd->Defined; + cva = cdf1->ClassValueArray; + + if ( ACCESS_Frame( count * 2L ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + cva[n] = GET_UShort(); + if ( cva[n] >= limit ) + { + error = TTO_Err_Invalid_SubTable; + goto Fail; + } + d[cva[n]] = TRUE; + } + + FORGET_Frame(); + + return TT_Err_Ok; + + Fail: + FREE( cva ); + + return error; + } + + + static void Free_ClassDef1( TTO_ClassDefFormat1* cdf1, + FT_Memory memory ) + { + FREE( cdf1->ClassValueArray ); + } + + + /* ClassDefFormat2 */ + + static FT_Error Load_ClassDef2( TTO_ClassDefinition* cd, + FT_UShort limit, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + TTO_ClassRangeRecord* crr; + FT_Bool* d; + + TTO_ClassDefFormat2* cdf2; + + + cdf2 = &cd->cd.cd2; + + if ( ACCESS_Frame( 2L ) ) + return error; + + count = cdf2->ClassRangeCount = GET_UShort(); + + FORGET_Frame(); + + cdf2->ClassRangeRecord = NULL; + + if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, TTO_ClassRangeRecord ) ) + return error; + + d = cd->Defined; + crr = cdf2->ClassRangeRecord; + + if ( ACCESS_Frame( count * 6L ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + crr[n].Start = GET_UShort(); + crr[n].End = GET_UShort(); + crr[n].Class = GET_UShort(); + + /* sanity check */ + + if ( crr[n].Start > crr[n].End || + crr[n].Class >= limit ) + { + error = TTO_Err_Invalid_SubTable; + goto Fail; + } + d[crr[n].Class] = TRUE; + } + + FORGET_Frame(); + + return TT_Err_Ok; + + Fail: + FREE( crr ); + + return error; + } + + + static void Free_ClassDef2( TTO_ClassDefFormat2* cdf2, + FT_Memory memory ) + { + FREE( cdf2->ClassRangeRecord ); + } + + + /* ClassDefinition */ + + FT_Error Load_ClassDefinition( TTO_ClassDefinition* cd, + FT_UShort limit, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + + if ( ALLOC_ARRAY( cd->Defined, limit, FT_Bool ) ) + return error; + + if ( ACCESS_Frame( 2L ) ) + goto Fail; + + cd->ClassFormat = GET_UShort(); + + FORGET_Frame(); + + switch ( cd->ClassFormat ) + { + case 1: + error = Load_ClassDef1( cd, limit, stream ); + break; + + case 2: + error = Load_ClassDef2( cd, limit, stream ); + break; + + default: + error = TTO_Err_Invalid_SubTable_Format; + break; + } + + if ( error ) + goto Fail; + + cd->loaded = TRUE; + + return TT_Err_Ok; + + Fail: + FREE( cd->Defined ); + return error; + } + + + void Free_ClassDefinition( TTO_ClassDefinition* cd, + FT_Memory memory ) + { + if ( !cd->loaded ) + return; + + FREE( cd->Defined ); + + switch ( cd->ClassFormat ) + { + case 1: + Free_ClassDef1( &cd->cd.cd1, memory ); + break; + + case 2: + Free_ClassDef2( &cd->cd.cd2, memory ); + break; + } + } + + + static FT_Error Get_Class1( TTO_ClassDefFormat1* cdf1, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ) + { + FT_UShort* cva = cdf1->ClassValueArray; + + + *index = 0; + + if ( glyphID >= cdf1->StartGlyph && + glyphID <= cdf1->StartGlyph + cdf1->GlyphCount ) + { + *class = cva[glyphID - cdf1->StartGlyph]; + return TT_Err_Ok; + } + else + { + *class = 0; + return TTO_Err_Not_Covered; + } + } + + + /* we need the index value of the last searched class range record + in case of failure for constructed GDEF tables */ + + static FT_Error Get_Class2( TTO_ClassDefFormat2* cdf2, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ) + { + FT_Error error = TT_Err_Ok; + FT_UShort min, max, new_min, new_max, middle; + + TTO_ClassRangeRecord* crr = cdf2->ClassRangeRecord; + + + /* binary search */ + + new_min = 0; + new_max = cdf2->ClassRangeCount - 1; + + do + { + min = new_min; + max = new_max; + + /* we use (min + max) / 2 = max - (max - min) / 2 to avoid + overflow and rounding errors */ + + middle = max - ( ( max - min ) >> 1 ); + + if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End ) + { + *class = crr[middle].Class; + error = TT_Err_Ok; + break; + } + else if ( glyphID < crr[middle].Start ) + { + if ( middle == min ) + { + *class = 0; + error = TTO_Err_Not_Covered; + break; + } + new_max = middle - 1; + } + else + { + if ( middle == max ) + { + *class = 0; + error = TTO_Err_Not_Covered; + break; + } + new_min = middle + 1; + } + } while ( min < max ); + + if ( index ) + *index = middle; + + return error; + } + + + FT_Error Get_Class( TTO_ClassDefinition* cd, + FT_UShort glyphID, + FT_UShort* class, + FT_UShort* index ) + { + switch ( cd->ClassFormat ) + { + case 1: + return Get_Class1( &cd->cd.cd1, glyphID, class, index ); + + case 2: + return Get_Class2( &cd->cd.cd2, glyphID, class, index ); + + default: + return TTO_Err_Invalid_SubTable_Format; + } + + return TT_Err_Ok; /* never reached */ + } + + + + /*************************** + * Device related functions + ***************************/ + + + FT_Error Load_Device( TTO_Device* d, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort n, count; + + FT_UShort* dv; + + + if ( ACCESS_Frame( 6L ) ) + return error; + + d->StartSize = GET_UShort(); + d->EndSize = GET_UShort(); + d->DeltaFormat = GET_UShort(); + + FORGET_Frame(); + + if ( d->StartSize > d->EndSize || + d->DeltaFormat == 0 || d->DeltaFormat > 3 ) + return TTO_Err_Invalid_SubTable; + + d->DeltaValue = NULL; + + count = ( ( d->EndSize - d->StartSize + 1 ) >> + ( 4 - d->DeltaFormat ) ) + 1; + + if ( ALLOC_ARRAY( d->DeltaValue, count, FT_UShort ) ) + return error; + + if ( ACCESS_Frame( count * 2L ) ) + { + FREE( d->DeltaValue ); + return error; + } + + dv = d->DeltaValue; + + for ( n = 0; n < count; n++ ) + dv[n] = GET_UShort(); + + FORGET_Frame(); + + return TT_Err_Ok; + } + + + void Free_Device( TTO_Device* d, + FT_Memory memory ) + { + FREE( d->DeltaValue ); + } + + + /* Since we have the delta values stored in compressed form, we must + uncompress it now. To simplify the interface, the function always + returns a meaningful value in `value'; the error is just for + information. + | | + format = 1: 0011223344556677|8899101112131415|... + | | + byte 1 byte 2 + + 00: (byte >> 14) & mask + 11: (byte >> 12) & mask + ... + + mask = 0x0003 + | | + format = 2: 0000111122223333|4444555566667777|... + | | + byte 1 byte 2 + + 0000: (byte >> 12) & mask + 1111: (byte >> 8) & mask + ... + + mask = 0x000F + | | + format = 3: 0000000011111111|2222222233333333|... + | | + byte 1 byte 2 + + 00000000: (byte >> 8) & mask + 11111111: (byte >> 0) & mask + .... + + mask = 0x00FF */ + + FT_Error Get_Device( TTO_Device* d, + FT_UShort size, + FT_Short* value ) + { + FT_UShort byte, bits, mask, f, s; + + + f = d->DeltaFormat; + + if ( size >= d->StartSize && size <= d->EndSize ) + { + s = size - d->StartSize; + byte = d->DeltaValue[s >> ( 4 - f )]; + bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) ); + mask = 0xFFFF >> ( 16 - ( 1 << f ) ); + + *value = (FT_Short)( bits & mask ); + + /* conversion to a signed value */ + + if ( *value >= ( ( mask + 1 ) >> 1 ) ) + *value -= mask + 1; + + return TT_Err_Ok; + } + else + { + *value = 0; + return TTO_Err_Not_Covered; + } + } + + +/* END */ |