shithub: freetype+ttf2subf

Download patch

ref: 9f5dd61bf3deee315da14d3aca7f436bbf9cc76a
parent: ec4372f56552b7370d6693db8b4d44d412e2dd6a
author: suzuki toshiya <[email protected]>
date: Mon Nov 22 21:47:10 EST 2010

[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.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2010-11-22  suzuki toshiya  <[email protected]>
+
+	[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  <[email protected]>
 
 	[truetype] Fix `loca' handling for inconsistent number of glyphs.
--- 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,17 +163,166 @@
       "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 );