diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index c884402..906406d 100644 --- a/src/truetype/ttobjs.c +++ b/src/truetype/ttobjs.c @@ -147,7 +147,7 @@ /* This list shall be expanded as we find more of them. */ static FT_Bool - tt_check_trickyness( FT_String* name ) + tt_check_trickyness_family( FT_String* name ) { #define TRICK_NAMES_MAX_CHARACTERS 16 #define TRICK_NAMES_COUNT 8 @@ -163,16 +163,165 @@ "MingLi43", /* mingli.ttf */ }; int nn; + for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) + if ( ft_strstr( name, trick_names[nn] ) ) + return TRUE; + return FALSE; + } - if ( !name ) - return TRUE; + + /* XXX: this function should be in sfnt module */ + /* some PDF generators clear the checksum in TrueType header */ + /* (Quartz ContextPDF clears all, Bullzip PDF Printer clears */ + /* for the subsetted subtables), we have to recalculate when */ + /* it is cleared. */ + static FT_UInt32 + tt_synth_sfnt_checksum( FT_Stream stream, + FT_ULong length ) + { + FT_Error error; + FT_UInt32 checksum = 0; + int i; + + + if ( FT_FRAME_ENTER( length ) ) + return 0; + + for ( ; length > 3; length -= 4 ) + checksum += (FT_UInt32)FT_GET_ULONG(); + + for ( i = 3; length > 0; length --, i-- ) + checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) ); + + FT_FRAME_EXIT(); + + return checksum; + } + + + /* XXX: this function should be in sfnt module */ + static FT_ULong + tt_get_sfnt_checksum( TT_Face face, + FT_UShort i ) + { + if ( face->dir_tables[i].CheckSum ) + return face->dir_tables[i].CheckSum; + else if ( !face->goto_table ) + return 0; + else if ( !face->goto_table( face, + face->dir_tables[i].Tag, + face->root.stream, + NULL ) ) + return 0; + + return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, + face->dir_tables[i].Length ); + } + + + typedef struct tt_sfnt_id_rec_ + { + FT_ULong CheckSum; + FT_ULong Length; + } tt_sfnt_id_rec; + + + static FT_Bool + tt_check_trickyness_sfnt_ids( TT_Face face ) + { +#define TRICK_SFNT_IDS_PER_FACE 3 +#define TRICK_SFNT_IDS_NUM_FACES 5 + static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] + [TRICK_SFNT_IDS_PER_FACE] = { +#define TRICK_SFNT_ID_cvt 0 +#define TRICK_SFNT_ID_fpgm 1 +#define TRICK_SFNT_ID_prep 2 + { /* MingLiU 1995 */ + { 0x05bcf058, 0x000002e4 }, /* cvt */ + { 0x28233bf1, 0x000087c4 }, /* fpgm */ + { 0xa344a1ea, 0x000001e1 } /* prep */ + }, + { /* MingLiU 1996- */ + { 0x05bcf058, 0x000002e4 }, /* cvt */ + { 0x28233bf1, 0x000087c4 }, /* fpgm */ + { 0xa344a1eb, 0x000001e1 } /* prep */ + }, + { /* DFKaiShu */ + { 0x11e5ead4, 0x00000350 }, /* cvt */ + { 0x5a30ca3b, 0x00009063 }, /* fpgm */ + { 0x13a42602, 0x0000007e } /* prep */ + }, + { /* HuaTianKaiTi */ + { 0xfffbfffc, 0x00000008 }, /* cvt */ + { 0x9c9e48b8, 0x0000bea2 }, /* fpgm */ + { 0x70020112, 0x00000008 } /* prep */ + }, + { /* HuaTianSongTi */ + { 0xfffbfffc, 0x00000008 }, /* cvt */ + { 0x0a5a0483, 0x00017c39 }, /* fpgm */ + { 0x70020112, 0x00000008 } /* prep */ + } + }; + FT_ULong checksum; + int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; + int i, j, k; + + FT_MEM_SET( num_matched_ids, 0, sizeof( int ) * TRICK_SFNT_IDS_NUM_FACES ); + + for ( i = 0; i < face->num_tables; i++ ) + { + checksum = 0; + switch( face->dir_tables[i].Tag ) + { + case TTAG_cvt: + k = TRICK_SFNT_ID_cvt; + break; + case TTAG_fpgm: + k = TRICK_SFNT_ID_fpgm; + break; + case TTAG_prep: + k = TRICK_SFNT_ID_prep; + break; + default: + continue; + } + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) + { + if ( !checksum ) + checksum = tt_get_sfnt_checksum( face, i ); + if ( sfnt_id[j][k].CheckSum == checksum ) + num_matched_ids[j] ++; + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + } + + return FALSE; + } + + + static FT_Bool + tt_check_trickyness( FT_Face face ) + { + if ( !face ) + return FALSE; /* Note that we only check the face name at the moment; it might */ /* be worth to do more checks for a few special cases. */ - for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) - if ( ft_strstr( name, trick_names[nn] ) ) + if ( face->family_name ) + { + if ( tt_check_trickyness_family( face->family_name ) ) return TRUE; + else + return FALSE; + } + + /* Type42 may lack `name' tables, try to identfiy tricky fonts by */ + /* the checksums of Type42-persistent sfnt tables; cvt, fpgm, prep */ + if ( tt_check_trickyness_sfnt_ids( ( TT_Face )face ) ) + return TRUE; return FALSE; } @@ -252,7 +401,7 @@ if ( error ) goto Exit; - if ( tt_check_trickyness( ttface->family_name ) ) + if ( tt_check_trickyness( ttface ) ) ttface->face_flags |= FT_FACE_FLAG_TRICKY; error = tt_face_load_hdmx( face, stream );