[truetype] Identify the tricky fonts by cvt/fpgm/prep checksums.
Some Latin TrueType fonts are still expected to be unhinted. Fix Savannah bug #31645. * src/truetype/ttobjs.c (tt_check_trickyness): Divided to... (tt_check_trickyness_family): this checking family name, and (tt_check_trickyness_sfnt_ids): this checking cvt/fpgm/prep. (tt_get_sfnt_checksum): Function to retrieve the sfnt checksum for specified subtable even if cleared by lazy PDF generators. (tt_synth_sfnt_checksum): Function to calculate the checksum.
This commit is contained in:
parent
ec4372f565
commit
9f5dd61bf3
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
2010-11-22 suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
|
||||
|
||||
[truetype] Identify the tricky fonts by cvt/fpgm/prep checksums.
|
||||
Some Latin TrueType fonts are still expected to be unhinted.
|
||||
Fix Savannah bug #31645.
|
||||
|
||||
* src/truetype/ttobjs.c (tt_check_trickyness): Divided to...
|
||||
(tt_check_trickyness_family): this checking family name, and
|
||||
(tt_check_trickyness_sfnt_ids): this checking cvt/fpgm/prep.
|
||||
(tt_get_sfnt_checksum): Function to retrieve the sfnt checksum
|
||||
for specified subtable even if cleared by lazy PDF generators.
|
||||
(tt_synth_sfnt_checksum): Function to calculate the checksum.
|
||||
|
||||
2010-11-18 Werner Lemberg <wl@gnu.org>
|
||||
|
||||
[truetype] Fix `loca' handling for inconsistent number of glyphs.
|
||||
|
@ -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,13 +163,6 @@
|
||||
"MingLi43", /* mingli.ttf */
|
||||
};
|
||||
int nn;
|
||||
|
||||
|
||||
if ( !name )
|
||||
return TRUE;
|
||||
|
||||
/* 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] ) )
|
||||
return TRUE;
|
||||
@ -178,6 +171,162 @@
|
||||
}
|
||||
|
||||
|
||||
/* 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. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
@ -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 );
|
||||
|
Loading…
Reference in New Issue
Block a user