Commit d232f593832f55b6101b6cda1c688a4c5f6add07

Werner Lemberg 2004-08-02T05:38:33

* docs/CHANGES: Updated. FreeType now can read kerning values from PFM files. * src/type1/t1afm.c (T1_Done_AFM): Renamed to... (T1_Done_Metrics): This. Update all callers. (T1_Read_AFM): Make it static. Don't enter and leave a frame. (LITTLE_ENDIAN_USHORT, LITTLE_ENDIAN_UINT): New macros. (T1_Read_PFM): New function. (T1_Read_Metrics): New higher-level function to be used instead of T1Read_AFM. Update all callers.

diff --git a/ChangeLog b/ChangeLog
index 455e186..49bf148 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2004-08-01  Werner Lemberg  <wl@gnu.org>
+
+	* docs/CHANGES: Updated.
+
+2004-08-01  George Williams  <gww@silcom.com>
+
+	FreeType now can read kerning values from PFM files.
+
+	* src/type1/t1afm.c (T1_Done_AFM): Renamed to...
+	(T1_Done_Metrics): This.
+	Update all callers.
+	(T1_Read_AFM): Make it static.
+	Don't enter and leave a frame.
+	(LITTLE_ENDIAN_USHORT, LITTLE_ENDIAN_UINT): New macros.
+	(T1_Read_PFM): New function.
+	(T1_Read_Metrics): New higher-level function to be used instead of
+	T1Read_AFM.
+	Update all callers.
+
 2004-07-31  Werner Lemberg  <wl@gnu.org>
 
 	* src/pcf/pcfread (pcf_load_font), src/bdf/bdfdrivr.c
diff --git a/docs/CHANGES b/docs/CHANGES
index 55164a3..5b11097 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -1,3 +1,25 @@
+LATEST CHANGES BETWEEN 2.1.10 and 2.1.9
+
+  I. IMPORTANT BUG FIXES
+
+    - The size comparison for BDF and PCF files could fail sometimes.
+
+    - Some  CFF files  were still not  loaded  correctly.   Patch from
+      Derek Noonburg.
+
+    - The stroker still had some serious bugs.
+
+
+  II. IMPORTANT CHANGES
+
+    - George Williams  contributed code to read  kerning data from PFM
+      files.
+
+    - FreeType   now   uses    the   TT_NAME_ID_PREFERRED_FAMILY   and
+      TT_NAME_ID_PREFERRED_SUBFAMILY   strings   (if   available)  for
+      setting  family  and  style in SFNT  fonts  (patch from Kornfeld
+      Eliyahu Peter).
+
 
 LATEST CHANGES BETWEEN 2.1.9 and 2.1.8
 
diff --git a/src/type1/t1afm.c b/src/type1/t1afm.c
index 65d86fa..c56ba65 100644
--- a/src/type1/t1afm.c
+++ b/src/type1/t1afm.c
@@ -33,8 +33,8 @@
 
 
   FT_LOCAL_DEF( void )
-  T1_Done_AFM( FT_Memory  memory,
-               T1_AFM*    afm )
+  T1_Done_Metrics( FT_Memory  memory,
+                   T1_AFM*    afm )
   {
     FT_FREE( afm->kern_pairs );
     afm->num_pairs = 0;
@@ -153,11 +153,11 @@
 
 
   /* parse an AFM file -- for now, only read the kerning pairs */
-  FT_LOCAL_DEF( FT_Error )
+  static FT_Error
   T1_Read_AFM( FT_Face    t1_face,
                FT_Stream  stream )
   {
-    FT_Error       error;
+    FT_Error       error = T1_Err_Ok;
     FT_Memory      memory = stream->memory;
     FT_Byte*       start;
     FT_Byte*       limit;
@@ -168,9 +168,6 @@
     T1_AFM*        afm   = 0;
 
 
-    if ( FT_FRAME_ENTER( stream->size ) )
-      return error;
-
     start = (FT_Byte*)stream->cursor;
     limit = (FT_Byte*)stream->limit;
     p     = start;
@@ -233,6 +230,173 @@
     if ( error )
       FT_FREE( afm );
 
+    return error;
+  }
+
+
+#define LITTLE_ENDIAN_USHORT( p )  (FT_UShort)( ( (p)[0]       ) | \
+                                                ( (p)[1] <<  8 ) )
+
+#define LITTLE_ENDIAN_UINT( p )  (FT_UInt)( ( (p)[0]       ) | \
+                                            ( (p)[1] <<  8 ) | \
+                                            ( (p)[2] << 16 ) | \
+                                            ( (p)[3] << 24 ) )
+
+
+  /* parse a PFM file -- for now, only read the kerning pairs */
+  static FT_Error
+  T1_Read_PFM( FT_Face    t1_face,
+               FT_Stream  stream )
+  {
+    FT_Error       error = T1_Err_Ok;
+    FT_Memory      memory = stream->memory;
+    FT_Byte*       start;
+    FT_Byte*       limit;
+    FT_Byte*       p;
+    FT_Int         kern_count = 0;
+    T1_Kern_Pair*  pair;
+    T1_AFM*        afm = 0;
+    FT_Int         width_table_length;
+    FT_CharMap     oldcharmap;
+    FT_CharMap     charmap;
+    FT_Int         n;
+
+
+    start = (FT_Byte*)stream->cursor;
+    limit = (FT_Byte*)stream->limit;
+    p     = start;
+
+    /* Figure out how long the width table is.          */
+    /* This info is a little-endian short at offset 99. */
+    p = start + 99;
+    if ( p + 2 > limit )
+    {
+      error = T1_Err_Unknown_File_Format;
+      goto Exit;
+    }
+    width_table_length = LITTLE_ENDIAN_USHORT( p );
+
+    p += 18 + width_table_length;
+    if ( p + 0x12 > limit || LITTLE_ENDIAN_USHORT( p ) < 0x12 )
+      /* extension table is probably optional */
+      goto Exit;
+
+    /* Kerning offset is 14 bytes from start of extensions table. */
+    p += 14;
+    p = start + LITTLE_ENDIAN_UINT( p );
+    if ( p + 2 > limit )
+    {
+      error = T1_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    kern_count = LITTLE_ENDIAN_USHORT( p );
+    p += 2;
+    if ( p + 4 * kern_count > limit )
+    {
+      error = T1_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* Actually, kerning pairs are simply optional! */
+    if ( kern_count == 0 )
+      goto Exit;
+
+    /* allocate the pairs */
+    if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, kern_count ) )
+      goto Exit;
+
+    /* save in face object */
+    ((T1_Face)t1_face)->afm_data = afm;
+
+    t1_face->face_flags |= FT_FACE_FLAG_KERNING;
+
+    /* now, read each kern pair */
+    pair           = afm->kern_pairs;
+    afm->num_pairs = kern_count;
+    limit          = p + 4 * kern_count;
+
+    /* PFM kerning data are stored by encoding rather than glyph index, */
+    /* so find the PostScript charmap of this font and install it       */
+    /* temporarily.  If we find no PostScript charmap, then just use    */
+    /* the default and hope it is the right one.                        */
+    oldcharmap = t1_face->charmap;
+    charmap    = NULL;
+
+    for ( n = 0; n < t1_face->num_charmaps; n++ )
+    {
+      charmap = t1_face->charmaps[n];
+      /* check against PostScript pseudo platform */
+      if ( charmap->platform_id == 7 )
+      {
+        error = FT_Set_Charmap( t1_face, charmap );
+        if ( error )
+          goto Exit;
+        break;
+      }
+    }
+
+    /* Kerning info is stored as:             */
+    /*                                        */
+    /*   encoding of first glyph (1 byte)     */
+    /*   encoding of second glyph (1 byte)    */
+    /*   offset (little-endian short)         */
+    for ( ; p < limit ; p+=4 )
+    {
+      pair->glyph1 = FT_Get_Char_Index( t1_face, p[0] );
+      pair->glyph2 = FT_Get_Char_Index( t1_face, p[1] );
+
+      pair->kerning.x = (FT_Short)LITTLE_ENDIAN_USHORT(p + 2);
+      pair->kerning.y = 0;
+
+      pair++;
+    }
+
+    if ( oldcharmap != NULL )
+      error = FT_Set_Charmap( t1_face, oldcharmap );
+    if ( error )
+      goto Exit;
+
+    /* now, sort the kern pairs according to their glyph indices */
+    ft_qsort( afm->kern_pairs, kern_count, sizeof ( T1_Kern_Pair ),
+              compare_kern_pairs );
+
+  Exit:
+    if ( error )
+      FT_FREE( afm );
+
+    return error;
+  }
+
+
+  /* parse a metrics file -- either AFM or PFM depending on what */
+  /* it turns out to be                                          */
+  FT_LOCAL_DEF( FT_Error )
+  T1_Read_Metrics( FT_Face    t1_face,
+                   FT_Stream  stream )
+  {
+    FT_Error  error;
+    FT_Byte*  start;
+
+
+    if ( FT_FRAME_ENTER( stream->size ) )
+      return error;
+
+    start = (FT_Byte*)stream->cursor;
+
+    if ( stream->size >= ft_strlen( "StartFontMetrics" )    &&
+         ft_strncmp( (const char*)start, "StartFontMetrics",
+                     ft_strlen( "StartFontMetrics" ) ) == 0 )
+      error = T1_Read_AFM( t1_face, stream );
+
+    else if ( stream->size > 6                                &&
+              start[0] == 0x00 && start[1] == 0x01            &&
+              LITTLE_ENDIAN_UINT( start + 2 ) == stream->size )
+      error = T1_Read_PFM( t1_face, stream );
+
+    else
+      error = T1_Err_Unknown_File_Format;
+
     FT_FRAME_EXIT();
 
     return error;
diff --git a/src/type1/t1afm.h b/src/type1/t1afm.h
index 77cc6a6..5aaeb67 100644
--- a/src/type1/t1afm.h
+++ b/src/type1/t1afm.h
@@ -44,12 +44,12 @@ FT_BEGIN_HEADER
 
 
   FT_LOCAL( FT_Error )
-  T1_Read_AFM( FT_Face    face,
-               FT_Stream  stream );
+  T1_Read_Metrics( FT_Face    face,
+                   FT_Stream  stream );
 
   FT_LOCAL( void )
-  T1_Done_AFM( FT_Memory  memory,
-               T1_AFM*    afm );
+  T1_Done_Metrics( FT_Memory  memory,
+                   T1_AFM*    afm );
 
   FT_LOCAL( void )
   T1_Get_Kerning( T1_AFM*     afm,
diff --git a/src/type1/t1driver.c b/src/type1/t1driver.c
index b37ae77..652eebc 100644
--- a/src/type1/t1driver.c
+++ b/src/type1/t1driver.c
@@ -294,7 +294,7 @@
     (FT_Face_AttachFunc)      0,
 #else
     (FT_Face_GetKerningFunc)  Get_Kerning,
-    (FT_Face_AttachFunc)      T1_Read_AFM,
+    (FT_Face_AttachFunc)      T1_Read_Metrics,
 #endif
     (FT_Face_GetAdvancesFunc) 0
   };
diff --git a/src/type1/t1objs.c b/src/type1/t1objs.c
index a832ee0..519fa08 100644
--- a/src/type1/t1objs.c
+++ b/src/type1/t1objs.c
@@ -233,7 +233,7 @@
 #ifndef T1_CONFIG_OPTION_NO_AFM
       /* release afm data if present */
       if ( face->afm_data )
-        T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
+        T1_Done_Metrics( memory, (T1_AFM*)face->afm_data );
 #endif
 
       /* release unicode map, if any */