shithub: freetype+ttf2subf

Download patch

ref: f5aa47beb077998675f5adc38c94aaf7ee8a447e
parent: d39fda2b5598fcedf4edab8343b32a30c13b9efa
author: Wu, Chia-I (吳佳一) <[email protected]>
date: Tue Feb 14 01:40:10 EST 2006

Clean up the SFNT_Interface.  Table loading functions are now named
after the tables' tags;  `hdmx' is TrueType-specific and thus the code
is moved to the truetype module; `get_metrics' is moved here from the
truetype module so that the code can be shared with the cff module.

This pass involves no real changes.  That is, the code is moved
verbatim mostly.  The only exception is the return value of
`tt_face_get_metrics'.

* include/freetype/internal/sfnt.h, src/sfnt/rules.mk,
src/sfnt/sfdriver.c, src/sfnt/sfnt.c, src/sfnt/sfobjs.c,
src/sfnt/ttload.c, src/sfnt/ttload.h, src/sfnt/ttsbit.c,
src/sfnt/ttsbit.h, src/sfnt/ttsbit0.c: Clean up the SFNT_Interface.

* src/sfnt/ttmtx.c, src/sfnt/ttmtx.h: Metrics-related tables' loading
and parsing code is moved here.
Move `tt_face_get_metrics' here from the truetype module.  The return
value is changed from `void' to `FT_Error'.

* include/freetype/internal/fttrace.h: New trace: ttmtx.

* src/truetype/ttpload.c, src/truetype/ttpload.h: `hdmx' loading and
parsing code is moved here.
New function `tt_face_load_prep' splitted from `tt_face_load_fpgm'.
`tt_face_load_fpgm' returns `FT_Err_Ok' if `fpgm' doesn't exist.

* src/cff/cffgload.c, src/cff/cffobjs.c: Update.

* src/truetype/ttgload.c, src/truetype/ttobjs.c: Update.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2006-02-13  Chia-I Wu  <[email protected]>
+
+	Clean up the SFNT_Interface.  Table loading functions are now named
+	after the tables' tags;  `hdmx' is TrueType-specific and thus the code
+	is moved to the truetype module; `get_metrics' is moved here from the
+	truetype module so that the code can be shared with the cff module.
+
+	This pass involves no real changes.  That is, the code is moved
+	verbatim mostly.  The only exception is the return value of
+	`tt_face_get_metrics'.
+
+	* include/freetype/internal/sfnt.h, src/sfnt/rules.mk,
+	src/sfnt/sfdriver.c, src/sfnt/sfnt.c, src/sfnt/sfobjs.c,
+	src/sfnt/ttload.c, src/sfnt/ttload.h, src/sfnt/ttsbit.c,
+	src/sfnt/ttsbit.h, src/sfnt/ttsbit0.c: Clean up the SFNT_Interface.
+	
+	* src/sfnt/ttmtx.c, src/sfnt/ttmtx.h: Metrics-related tables' loading
+	and parsing code is moved here.
+	Move `tt_face_get_metrics' here from the truetype module.  The return
+	value is changed from `void' to `FT_Error'.
+
+	* include/freetype/internal/fttrace.h: New trace: ttmtx.
+
+	* src/truetype/ttpload.c, src/truetype/ttpload.h: `hdmx' loading and
+	parsing code is moved here.
+	New function `tt_face_load_prep' splitted from `tt_face_load_fpgm'.
+	`tt_face_load_fpgm' returns `FT_Err_Ok' if `fpgm' doesn't exist.
+
+	* src/cff/cffgload.c, src/cff/cffobjs.c: Update.
+
+	* src/truetype/ttgload.c, src/truetype/ttobjs.c: Update.
+
 2006-02-11  Chia-I Wu  <[email protected]>
 
 	* src/autofit/afcjk.c (af_cjk_metrics_init): Fix a stupid bug...
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -45,6 +45,7 @@
 FT_TRACE_DEF( ttcmap )    /* charmap handler         (ttcmap.c)   */
 FT_TRACE_DEF( ttkern )    /* kerning handler         (ttkern.c)   */
 FT_TRACE_DEF( ttload )    /* basic TrueType tables   (ttload.c)   */
+FT_TRACE_DEF( ttmtx )     /* metrics-related tables  (ttmtx.c)    */
 FT_TRACE_DEF( ttpost )    /* PS table processing     (ttpost.c)   */
 FT_TRACE_DEF( ttsbit )    /* TrueType sbit handling  (ttsbit.c)   */
 
--- a/include/freetype/internal/sfnt.h
+++ b/include/freetype/internal/sfnt.h
@@ -442,7 +442,8 @@
   /*    TT_Load_Metrics_Func                                               */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    Load the horizontal or vertical header in a face object.           */
+  /*    Load a metrics table, which is a table comes with a horizontal     */
+  /*    and a vertical version.                                            */
   /*                                                                       */
   /* <Input>                                                               */
   /*    face     :: A handle to the target face object.                    */
@@ -449,7 +450,7 @@
   /*                                                                       */
   /*    stream   :: The input stream.                                      */
   /*                                                                       */
-  /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
+  /*    vertical :: A boolean flag.  If set, load the vertical one.        */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0 means success.                             */
@@ -463,6 +464,32 @@
   /*************************************************************************/
   /*                                                                       */
   /* <FuncType>                                                            */
+  /*    TT_Get_Metrics_Func                                                */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Load the horizontal or vertical header in a face object.           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  typedef FT_Error
+  (*TT_Get_Metrics_Func)( TT_Face     face,
+                          FT_Bool     vertical,
+                          FT_UInt     gindex,
+                          FT_Short*   abearing,
+                          FT_UShort*  aadvance );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <FuncType>                                                            */
   /*    TT_Load_Table_Func                                                 */
   /*                                                                       */
   /* <Description>                                                         */
@@ -548,39 +575,38 @@
 
     /* these functions are called by `load_face' but they can also  */
     /* be called from external modules, if there is a need to do so */
-    TT_Load_Table_Func           load_header;
-    TT_Load_Metrics_Func         load_metrics;
-    TT_Load_Table_Func           load_charmaps;
-    TT_Load_Table_Func           load_max_profile;
+    TT_Load_Table_Func           load_head;
+    TT_Load_Metrics_Func         load_hhea;
+    TT_Load_Table_Func           load_cmap;
+    TT_Load_Table_Func           load_maxp;
     TT_Load_Table_Func           load_os2;
-    TT_Load_Table_Func           load_psnames;
+    TT_Load_Table_Func           load_post;
+    TT_Load_Table_Func           load_name;
+    TT_Free_Table_Func           free_name;
 
-    TT_Load_Table_Func           load_names;
-    TT_Free_Table_Func           free_names;
-
     /* optional tables */
-    TT_Load_Table_Func           load_hdmx;
-    TT_Free_Table_Func           free_hdmx;
-
-    TT_Load_Table_Func           load_kerning;
+    TT_Load_Table_Func           load_kern;
     TT_Load_Table_Func           load_gasp;
     TT_Load_Table_Func           load_pclt;
 
     /* see `ttload.h' */
-    TT_Load_Table_Func           load_bitmap_header;
+    TT_Load_Table_Func           load_bhed;
 
     /* see `ttsbit.h' */
+    TT_Load_Table_Func           load_eblc;
+    TT_Free_Table_Func           free_eblc;
+
     TT_Set_SBit_Strike_Func      set_sbit_strike;
     TT_Load_Strike_Metrics_Func  load_strike_metrics;
-    TT_Load_Table_Func           load_sbits;
     TT_Find_SBit_Image_Func      find_sbit_image;
     TT_Load_SBit_Metrics_Func    load_sbit_metrics;
     TT_Load_SBit_Image_Func      load_sbit_image;
-    TT_Free_Table_Func           free_sbits;
 
     /* see `ttkern.h' */
     TT_Face_GetKerningFunc       get_kerning;
     
+    TT_Get_Metrics_Func          get_metrics;
+
     /* see `ttpost.h' */
     TT_Get_PS_Name_Func          get_psname;
     TT_Free_Table_Func           free_psnames;
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -569,117 +569,6 @@
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    cff_face_get_vertical_metrics                                      */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Return the vertical metrics in font units for a given glyph.  The  */
-  /*    metrics are the top side bearing and advance height.               */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    header  :: A pointer to the vertical metrics structure.            */
-  /*                                                                       */
-  /*    idx     :: The glyph index.                                        */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    bearing :: The top side bearing.                                   */
-  /*                                                                       */
-  /*    advance :: The advance height.                                     */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    Horizontal metric values are directly computed from the CFF data,  */
-  /*    bypassing the `hmtx' table completely.                             */
-  /*                                                                       */
-#ifdef FT_OPTIMIZE_MEMORY
-
-  static void
-  cff_face_get_vertical_metrics( TT_Face     face,
-                                 FT_UInt     idx,
-                                 FT_Short   *abearing,
-                                 FT_UShort  *aadvance )
-  {
-    TT_VertHeader*  header;
-    FT_Byte*        p;
-    FT_Byte*        limit;
-    FT_UShort       k;
-
-
-    header = &face->vertical;
-    p      = face->vert_metrics;
-    limit  = p + face->vert_metrics_size;
-    
-    k = header->number_Of_VMetrics;
-    
-    if ( k > 0 )
-    {
-      if ( idx < (FT_UInt)k )
-      {
-        p += 4 * idx;
-        if ( p + 4 > limit )
-          goto NoData;
-          
-        *aadvance = FT_NEXT_USHORT( p );
-        *abearing = FT_NEXT_SHORT( p );
-      }
-      else
-      {
-        p += 4 * ( k - 1 );
-        if ( p + 4 > limit )
-          goto NoData;
-          
-        *aadvance = FT_NEXT_USHORT( p );
-        p += 2 + 2 * ( idx - k );
-        if ( p + 2 > limit )
-          *abearing = 0;
-        else
-          *abearing = FT_PEEK_SHORT( p );
-      }
-    }
-    else
-    {
-    NoData:
-      *abearing = 0;
-      *aadvance = 0;
-    }
-  }
-
-#else /* !FT_OPTIMIZE_MEMORY */
-
-  static void
-  cff_face_get_vertical_metrics( TT_Face     face,
-                                 FT_UInt     idx,
-                                 FT_Short   *abearing,
-                                 FT_UShort  *aadvance )
-  {
-    TT_VertHeader*  header = &face->vertical;
-    TT_LongMetrics  longs_m;
-    FT_UShort       k      = header->number_Of_VMetrics;
-
-
-    if ( k == 0 )
-    {
-      *abearing = *aadvance = 0;
-      return;
-    }
-
-    if ( idx < (FT_UInt)k )
-    {
-      longs_m   = (TT_LongMetrics)header->long_metrics + idx;
-      *abearing = longs_m->bearing;
-      *aadvance = longs_m->advance;
-    }
-    else
-    {
-      *abearing = ((TT_ShortMetrics*)header->short_metrics)[idx - k];
-      *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
-    }
-  }
-
-#endif /* !FT_OPTIMIZE_MEMORY */
-
-
   static FT_Error
   cff_get_glyph_data( TT_Face    face,
                       FT_UInt    glyph_index,
@@ -2421,7 +2310,7 @@
 
 
       if ( size->strike_index != 0xFFFFFFFFUL      &&
-           sfnt->load_sbits                        &&
+           sfnt->load_eblc                         &&
            ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
       {
         TT_SBit_MetricsRec  metrics;
@@ -2621,8 +2510,10 @@
           FT_UShort  vertAdvance  = 0;
 
 
-          cff_face_get_vertical_metrics( face, glyph_index,
-                                         &vertBearingY, &vertAdvance );
+          ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
+                                                     glyph_index,
+                                                     &vertBearingY,
+                                                     &vertAdvance );
           metrics->vertBearingY = vertBearingY;
           metrics->vertAdvance  = vertAdvance;
         }
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -380,7 +380,7 @@
       else
       {
         /* load the `cmap' table explicitly */
-        error = sfnt->load_charmaps( face, stream );
+        error = sfnt->load_cmap( face, stream );
         if ( error )
           goto Exit;
 
--- a/src/sfnt/rules.mk
+++ b/src/sfnt/rules.mk
@@ -26,6 +26,7 @@
 # SFNT driver sources (i.e., C files)
 #
 SFNT_DRV_SRC := $(SFNT_DIR)/ttload.c   \
+                $(SFNT_DIR)/ttmtx.c    \
                 $(SFNT_DIR)/ttcmap.c   \
                 $(SFNT_DIR)/ttsbit.c   \
                 $(SFNT_DIR)/ttpost.c   \
--- a/src/sfnt/sfdriver.c
+++ b/src/sfnt/sfdriver.c
@@ -389,19 +389,16 @@
     tt_face_load_sfnt_header,
     tt_face_load_directory,
 
-    tt_face_load_header,
-    tt_face_load_metrics_header,
+    tt_face_load_head,
+    tt_face_load_hhea,
     tt_face_load_cmap,
-    tt_face_load_max_profile,
+    tt_face_load_maxp,
     tt_face_load_os2,
-    tt_face_load_postscript,
+    tt_face_load_post,
 
-    tt_face_load_names,
-    tt_face_free_names,
+    tt_face_load_name,
+    tt_face_free_name,
 
-    tt_face_load_hdmx,
-    tt_face_free_hdmx,
-
     tt_face_load_kern,
     tt_face_load_gasp,
     tt_face_load_pclt,
@@ -409,12 +406,15 @@
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
     /* see `ttload.h' */
-    tt_face_load_bitmap_header,
+    tt_face_load_bhed,
 
+
     /* see `ttsbit.h' and `sfnt.h' */
+    tt_face_load_eblc,
+    tt_face_free_eblc,
+
     tt_face_set_sbit_strike,
     tt_face_load_strike_metrics,
-    tt_face_load_sbit_strikes,
 #ifdef FT_OPTIMIZE_MEMORY
     0,
     0,
@@ -423,7 +423,6 @@
     tt_load_sbit_metrics,
 #endif
     tt_face_load_sbit_image,
-    tt_face_free_sbit_strikes,
 
 #else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
@@ -439,6 +438,8 @@
 
     /* see `ttkern.h' */
     tt_face_get_kerning,
+
+    tt_face_get_metrics,
 
 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
 
--- a/src/sfnt/sfnt.c
+++ b/src/sfnt/sfnt.c
@@ -20,6 +20,7 @@
 
 #include <ft2build.h>
 #include "ttload.c"
+#include "ttmtx.c"
 #include "ttcmap.c"
 #include "ttkern.c"
 #include "sfobjs.c"
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -457,24 +457,24 @@
     /* if this font doesn't contain outlines, we try to load */
     /* a `bhed' table                                        */
     if ( !has_outline )
-      is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
+      is_apple_sbit = FT_BOOL( !LOAD_( bhed ) );
 
 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
     /* load the font header (`head' table) if this isn't an Apple */
     /* sbit font file                                             */
-    if ( !is_apple_sbit && LOAD_( header ) )
+    if ( !is_apple_sbit && LOAD_( head ) )
       goto Exit;
 
     /* the following tables are often not present in embedded TrueType */
     /* fonts within PDF documents, so don't check for them.            */
-    (void)LOAD_( max_profile );
-    (void)LOAD_( charmaps );
+    (void)LOAD_( maxp );
+    (void)LOAD_( cmap );
 
     /* the following tables are optional in PCL fonts -- */
     /* don't check for errors                            */
-    (void)LOAD_( names );
-    psnames_error = LOAD_( psnames );
+    (void)LOAD_( name );
+    psnames_error = LOAD_( post );
 
     /* do not load the metrics headers and tables if this is an Apple */
     /* sbit font file                                                 */
@@ -481,12 +481,12 @@
     if ( !is_apple_sbit )
     {
       /* load the `hhea' and `hmtx' tables at once */
-      error = sfnt->load_metrics( face, stream, 0 );
+      error = sfnt->load_hhea( face, stream, 0 );
       if ( error )
         goto Exit;
 
       /* try to load the `vhea' and `vmtx' tables at once */
-      error = sfnt->load_metrics( face, stream, 1 );
+      error = sfnt->load_hhea( face, stream, 1 );
       if ( error )
         goto Exit;
 
@@ -499,7 +499,7 @@
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
     /* embedded bitmap support. */
-    if ( sfnt->load_sbits && LOAD_( sbits ) )
+    if ( sfnt->load_eblc && LOAD_( eblc ) )
     {
       /* return an error if this font file has no outlines */
       if ( error == SFNT_Err_Table_Missing && has_outline )
@@ -510,13 +510,12 @@
 
 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
-    if ( LOAD_( hdmx )    ||
-         LOAD_( pclt )    )
+    if ( LOAD_( pclt )    )
       goto Exit;
 
     /* consider the kerning and gasp tables as optional */
     (void)LOAD_( gasp );
-    (void)LOAD_( kerning );
+    (void)LOAD_( kern );
 
     error = SFNT_Err_Ok;
 
@@ -755,8 +754,8 @@
         sfnt->free_psnames( face );
 
       /* destroy the embedded bitmaps table if it is loaded */
-      if ( sfnt->free_sbits )
-        sfnt->free_sbits( face );
+      if ( sfnt->free_eblc )
+        sfnt->free_eblc( face );
     }
 
 #ifdef TT_CONFIG_OPTION_BDF
@@ -813,10 +812,7 @@
     face->gasp.numRanges = 0;
 
     /* freeing the name table */
-    sfnt->free_names( face );
-
-    /* freeing the hdmx table */
-    sfnt->free_hdmx( face );
+    sfnt->free_name( face );
 
     /* freeing family and style name */
     FT_FREE( face->root.family_name );
--- a/src/sfnt/ttload.c
+++ b/src/sfnt/ttload.c
@@ -657,8 +657,8 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_header( TT_Face    face,
-                       FT_Stream  stream )
+  tt_face_load_head( TT_Face    face,
+                     FT_Stream  stream )
   {
     return tt_face_load_generic_header( face, stream, TTAG_head );
   }
@@ -667,8 +667,8 @@
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_bitmap_header( TT_Face    face,
-                              FT_Stream  stream )
+  tt_face_load_bhed( TT_Face    face,
+                     FT_Stream  stream )
   {
     return tt_face_load_generic_header( face, stream, TTAG_bhed );
   }
@@ -693,8 +693,8 @@
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_max_profile( TT_Face    face,
-                            FT_Stream  stream )
+  tt_face_load_maxp( TT_Face    face,
+                     FT_Stream  stream )
   {
     FT_Error        error;
     TT_MaxProfile*  maxProfile = &face->max_profile;
@@ -801,358 +801,6 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
-  /*    tt_face_load_metrics                                               */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Loads the horizontal or vertical metrics table into a face object. */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    face     :: A handle to the target face object.                    */
-  /*                                                                       */
-  /*    stream   :: The input stream.                                      */
-  /*                                                                       */
-  /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-#ifdef FT_OPTIMIZE_MEMORY
-
-  static FT_Error
-  tt_face_load_metrics( TT_Face    face,
-                        FT_Stream  stream,
-                        FT_Bool    vertical )
-  {
-    FT_Error   error;
-    FT_ULong   table_size;
-    FT_Byte**  ptable;
-    FT_ULong*  ptable_size;
-    
-    
-    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
-                                                       : "Horizontal",
-                                              face ));
-
-    if ( vertical )
-    {
-      ptable      = &face->vert_metrics;
-      ptable_size = &face->vert_metrics_size;
-      
-      /* The table is optional, quit silently if it wasn't found.      */
-      /*                                                               */
-      /* XXX: Some fonts have a valid vertical header with a non-null  */
-      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
-      /*      table to get the metrics from (e.g. mingliu).            */
-      /*                                                               */
-      /*      For safety, we set the field to 0!                       */
-      /*                                                               */
-      error = face->goto_table( face, TTAG_vmtx, stream, &table_size );
-      if ( error )
-      {
-        /* Set number_Of_VMetrics to 0! */
-        FT_TRACE2(( "  no vertical header in file.\n" ));
-        error = SFNT_Err_Ok;
-        goto Exit;
-      }
-    }
-    else
-    {
-      ptable      = &face->horz_metrics;
-      ptable_size = &face->horz_metrics_size;
-
-      error = face->goto_table( face, TTAG_hmtx, stream, &table_size );
-      if ( error )
-      {
-#ifdef FT_CONFIG_OPTION_INCREMENTAL
-        /* If this is an incrementally loaded font and there are */
-        /* overriding metrics, tolerate a missing `hmtx' table.  */
-        if ( face->root.internal->incremental_interface          &&
-             face->root.internal->incremental_interface->funcs->
-               get_glyph_metrics                                 )
-        {
-          face->horizontal.number_Of_HMetrics = 0;
-          error = SFNT_Err_Ok;
-          goto Exit;
-        }
-#endif
-
-        FT_ERROR(( " no horizontal metrics in file!\n" ));
-        error = SFNT_Err_Hmtx_Table_Missing;
-        goto Exit;
-      }
-    }
-    
-    if ( FT_FRAME_EXTRACT( table_size, *ptable ) )
-      goto Exit;
-      
-    *ptable_size = table_size;
-    
-  Exit:
-    return error;
-  }
-
-#else /* !OPTIMIZE_MEMORY */
-
-  static FT_Error
-  tt_face_load_metrics( TT_Face    face,
-                        FT_Stream  stream,
-                        FT_Bool    vertical )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    FT_ULong   table_len;
-    FT_Long    num_shorts, num_longs, num_shorts_checked;
-
-    TT_LongMetrics *   longs;
-    TT_ShortMetrics**  shorts;
-
-
-    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
-                                                       : "Horizontal",
-                                              face ));
-
-    if ( vertical )
-    {
-      /* The table is optional, quit silently if it wasn't found.      */
-      /*                                                               */
-      /* XXX: Some fonts have a valid vertical header with a non-null  */
-      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
-      /*      table to get the metrics from (e.g. mingliu).            */
-      /*                                                               */
-      /*      For safety, we set the field to 0!                       */
-      /*                                                               */
-      error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
-      if ( error )
-      {
-        /* Set number_Of_VMetrics to 0! */
-        FT_TRACE2(( "  no vertical header in file.\n" ));
-        face->vertical.number_Of_VMetrics = 0;
-        error = SFNT_Err_Ok;
-        goto Exit;
-      }
-
-      num_longs = face->vertical.number_Of_VMetrics;
-      longs     = (TT_LongMetrics *)&face->vertical.long_metrics;
-      shorts    = (TT_ShortMetrics**)&face->vertical.short_metrics;
-    }
-    else
-    {
-      error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
-      if ( error )
-      {
-
-#ifdef FT_CONFIG_OPTION_INCREMENTAL
-        /* If this is an incrementally loaded font and there are */
-        /* overriding metrics, tolerate a missing `hmtx' table.  */
-        if ( face->root.internal->incremental_interface          &&
-             face->root.internal->incremental_interface->funcs->
-               get_glyph_metrics                                 )
-        {
-          face->horizontal.number_Of_HMetrics = 0;
-          error = SFNT_Err_Ok;
-          goto Exit;
-        }
-#endif
-
-        FT_ERROR(( " no horizontal metrics in file!\n" ));
-        error = SFNT_Err_Hmtx_Table_Missing;
-        goto Exit;
-      }
-
-      num_longs = face->horizontal.number_Of_HMetrics;
-      longs     = (TT_LongMetrics *)&face->horizontal.long_metrics;
-      shorts    = (TT_ShortMetrics**)&face->horizontal.short_metrics;
-    }
-
-    /* never trust derived values */
-
-    num_shorts         = face->max_profile.numGlyphs - num_longs;
-    num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
-
-    if ( num_shorts < 0 )
-    {
-      FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
-                 vertical ? "Vertical"
-                          : "Horizontal" ));
-
-      /* Adobe simply ignores this problem.  So we shall do the same. */
-#if 0
-      error = vertical ? SFNT_Err_Invalid_Vert_Metrics
-                       : SFNT_Err_Invalid_Horiz_Metrics;
-      goto Exit;
-#else
-      num_shorts = 0;
-#endif
-    }
-
-    if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
-         FT_QNEW_ARRAY( *shorts, num_shorts ) )
-      goto Exit;
-
-    if ( FT_FRAME_ENTER( table_len ) )
-      goto Exit;
-
-    {
-      TT_LongMetrics  cur   = *longs;
-      TT_LongMetrics  limit = cur + num_longs;
-
-
-      for ( ; cur < limit; cur++ )
-      {
-        cur->advance = FT_GET_USHORT();
-        cur->bearing = FT_GET_SHORT();
-      }
-    }
-
-    /* do we have an inconsistent number of metric values? */
-    {
-      TT_ShortMetrics*  cur   = *shorts;
-      TT_ShortMetrics*  limit = cur +
-                                FT_MIN( num_shorts, num_shorts_checked );
-
-
-      for ( ; cur < limit; cur++ )
-        *cur = FT_GET_SHORT();
-
-      /* We fill up the missing left side bearings with the     */
-      /* last valid value.  Since this will occur for buggy CJK */
-      /* fonts usually only, nothing serious will happen.       */
-      if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
-      {
-        FT_Short  val = (*shorts)[num_shorts_checked - 1];
-
-
-        limit = *shorts + num_shorts;
-        for ( ; cur < limit; cur++ )
-          *cur = val;
-      }
-    }
-
-    FT_FRAME_EXIT();
-
-    FT_TRACE2(( "loaded\n" ));
-
-  Exit:
-    return error;
-  }
-
-#endif /* !FT_OPTIMIZE_METRICS */
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    tt_face_load_metrics_header                                        */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Loads the horizontal or vertical header in a face object.          */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    face     :: A handle to the target face object.                    */
-  /*                                                                       */
-  /*    stream   :: The input stream.                                      */
-  /*                                                                       */
-  /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  FT_LOCAL_DEF( FT_Error )
-  tt_face_load_metrics_header( TT_Face    face,
-                               FT_Stream  stream,
-                               FT_Bool    vertical )
-  {
-    FT_Error        error;
-    TT_HoriHeader*  header;
-
-    const FT_Frame_Field  metrics_header_fields[] =
-    {
-#undef  FT_STRUCTURE
-#define FT_STRUCTURE  TT_HoriHeader
-
-      FT_FRAME_START( 36 ),
-        FT_FRAME_ULONG ( Version ),
-        FT_FRAME_SHORT ( Ascender ),
-        FT_FRAME_SHORT ( Descender ),
-        FT_FRAME_SHORT ( Line_Gap ),
-        FT_FRAME_USHORT( advance_Width_Max ),
-        FT_FRAME_SHORT ( min_Left_Side_Bearing ),
-        FT_FRAME_SHORT ( min_Right_Side_Bearing ),
-        FT_FRAME_SHORT ( xMax_Extent ),
-        FT_FRAME_SHORT ( caret_Slope_Rise ),
-        FT_FRAME_SHORT ( caret_Slope_Run ),
-        FT_FRAME_SHORT ( caret_Offset ),
-        FT_FRAME_SHORT ( Reserved[0] ),
-        FT_FRAME_SHORT ( Reserved[1] ),
-        FT_FRAME_SHORT ( Reserved[2] ),
-        FT_FRAME_SHORT ( Reserved[3] ),
-        FT_FRAME_SHORT ( metric_Data_Format ),
-        FT_FRAME_USHORT( number_Of_HMetrics ),
-      FT_FRAME_END
-    };
-
-
-    FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
-
-    if ( vertical )
-    {
-      face->vertical_info = 0;
-
-      /* The vertical header table is optional, so return quietly if */
-      /* we don't find it.                                           */
-      error = face->goto_table( face, TTAG_vhea, stream, 0 );
-      if ( error )
-      {
-        error = SFNT_Err_Ok;
-        goto Exit;
-      }
-
-      face->vertical_info = 1;
-      header = (TT_HoriHeader*)&face->vertical;
-    }
-    else
-    {
-      /* The horizontal header is mandatory for most fonts; return */
-      /* an error if we don't find it.                             */
-      error = face->goto_table( face, TTAG_hhea, stream, 0 );
-      if ( error )
-      {
-        error = SFNT_Err_Horiz_Header_Missing;
-
-        /* No `hhea' table necessary for SFNT Mac fonts. */
-        if ( face->format_tag == TTAG_true )
-        {
-          FT_TRACE2(( "missing.  This is an SFNT Mac font.\n"));
-          error = SFNT_Err_Ok;
-        }
-
-        goto Exit;
-      }
-
-      header = &face->horizontal;
-    }
-
-    if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
-      goto Exit;
-
-    header->long_metrics  = NULL;
-    header->short_metrics = NULL;
-
-    FT_TRACE2(( "loaded\n" ));
-
-    /* Now try to load the corresponding metrics */
-
-    error = tt_face_load_metrics( face, stream, vertical );
-
-  Exit:
-    return error;
-  }
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
   /*    tt_face_load_names                                                 */
   /*                                                                       */
   /* <Description>                                                         */
@@ -1167,8 +815,8 @@
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_names( TT_Face    face,
-                      FT_Stream  stream )
+  tt_face_load_name( TT_Face    face,
+                     FT_Stream  stream )
   {
     FT_Error      error;
     FT_Memory     memory = stream->memory;
@@ -1306,7 +954,7 @@
   /*    face :: A handle to the target face object.                        */
   /*                                                                       */
   FT_LOCAL_DEF( void )
-  tt_face_free_names( TT_Face  face )
+  tt_face_free_name( TT_Face  face )
   {
     FT_Memory     memory = face->root.driver->root.memory;
     TT_NameTable  table  = &face->name_table;
@@ -1539,8 +1187,8 @@
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_postscript( TT_Face    face,
-                           FT_Stream  stream )
+  tt_face_load_post( TT_Face    face,
+                     FT_Stream  stream )
   {
     FT_Error        error;
     TT_Postscript*  post = &face->postscript;
@@ -1717,189 +1365,6 @@
   Exit:
     return error;
   }
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    tt_face_load_hdmx                                                  */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Loads the horizontal device metrics table.                         */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    face   :: A handle to the target face object.                      */
-  /*                                                                       */
-  /*    stream :: A handle to the input stream.                            */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-#ifdef FT_OPTIMIZE_MEMORY
-
-  FT_LOCAL_DEF( FT_Error )
-  tt_face_load_hdmx( TT_Face    face,
-                     FT_Stream  stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-    FT_UInt    version, nn, num_records;
-    FT_ULong   table_size, record_size;
-    FT_Byte*   p;
-    FT_Byte*   limit;
-
-
-    /* this table is optional */
-    error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
-    if ( error || table_size < 8 )
-      return SFNT_Err_Ok;
-
-    if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
-      goto Exit;
-
-    p     = face->hdmx_table;
-    limit = p + table_size;
-
-    version     = FT_NEXT_USHORT( p );
-    num_records = FT_NEXT_USHORT( p );
-    record_size = FT_NEXT_ULONG( p );
-
-    if ( version != 0 || num_records > 255 || record_size > 0x40000 )
-    {
-      error = SFNT_Err_Invalid_File_Format;
-      goto Fail;
-    }
-
-    if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
-      goto Fail;
-
-    for ( nn = 0; nn < num_records; nn++ )
-    {
-      if ( p + record_size > limit )
-        break;
-        
-      face->hdmx_record_sizes[nn] = p[0];
-      p                          += record_size;
-    }
-    
-    face->hdmx_record_count = nn;
-    face->hdmx_table_size   = table_size;
-
-  Exit:
-    return error;
-    
-  Fail:
-    FT_FRAME_RELEASE( face->hdmx_table );
-    face->hdmx_table_size = 0;
-    goto Exit;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  tt_face_free_hdmx( TT_Face  face )
-  {
-    FT_Stream  stream = face->root.stream;
-    FT_Memory  memory = stream->memory;
-    
-
-    FT_FREE( face->hdmx_record_sizes );
-    FT_FRAME_RELEASE( face->hdmx_table );
-  }
-
-#else /* !FT_OPTIMIZE_MEMORY */
-
-  FT_LOCAL_DEF( FT_Error )
-  tt_face_load_hdmx( TT_Face    face,
-                     FT_Stream  stream )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-
-    TT_Hdmx    hdmx = &face->hdmx;
-    FT_Short   num_records;
-    FT_Long    num_glyphs;
-    FT_Long    record_size;
-
-
-    hdmx->version     = 0;
-    hdmx->num_records = 0;
-    hdmx->records     = 0;
-
-    /* this table is optional */
-    error = face->goto_table( face, TTAG_hdmx, stream, 0 );
-    if ( error )
-      return SFNT_Err_Ok;
-
-    if ( FT_FRAME_ENTER( 8L ) )
-      goto Exit;
-
-    hdmx->version = FT_GET_USHORT();
-    num_records   = FT_GET_SHORT();
-    record_size   = FT_GET_LONG();
-
-    FT_FRAME_EXIT();
-
-    if ( record_size < 0 || num_records < 0 )
-      return SFNT_Err_Invalid_File_Format;
-
-    /* Only recognize format 0 */
-    if ( hdmx->version != 0 )
-      goto Exit;
-
-    /* we can't use FT_QNEW_ARRAY here; otherwise tt_face_free_hdmx */
-    /* could fail during deallocation                               */
-    if ( FT_NEW_ARRAY( hdmx->records, num_records ) )
-      goto Exit;
-
-    hdmx->num_records = num_records;
-    num_glyphs        = face->root.num_glyphs;
-    record_size      -= num_glyphs + 2;
-
-    {
-      TT_HdmxEntry  cur   = hdmx->records;
-      TT_HdmxEntry  limit = cur + hdmx->num_records;
-
-
-      for ( ; cur < limit; cur++ )
-      {
-        /* read record */
-        if ( FT_READ_BYTE( cur->ppem      ) ||
-             FT_READ_BYTE( cur->max_width ) )
-          goto Exit;
-
-        if ( FT_QALLOC( cur->widths, num_glyphs )      ||
-             FT_STREAM_READ( cur->widths, num_glyphs ) )
-          goto Exit;
-
-        /* skip padding bytes */
-        if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
-          goto Exit;
-      }
-    }
-
-  Exit:
-    return error;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  tt_face_free_hdmx( TT_Face  face )
-  {
-    if ( face )
-    {
-      FT_Int     n;
-      FT_Memory  memory = face->root.driver->root.memory;
-
-
-      for ( n = 0; n < face->hdmx.num_records; n++ )
-        FT_FREE( face->hdmx.records[n].widths );
-
-      FT_FREE( face->hdmx.records );
-      face->hdmx.num_records = 0;
-    }
-  }
-
-#endif /* !OPTIMIZE_MEMORY */
 
 
 /* END */
--- a/src/sfnt/ttload.h
+++ b/src/sfnt/ttload.h
@@ -60,29 +60,23 @@
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_header( TT_Face    face,
-                       FT_Stream  stream );
+  tt_face_load_head( TT_Face    face,
+                     FT_Stream  stream );
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_metrics_header( TT_Face    face,
-                               FT_Stream  stream,
-                               FT_Bool    vertical );
-
-
-  FT_LOCAL( FT_Error )
   tt_face_load_cmap( TT_Face    face,
                      FT_Stream  stream );
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_max_profile( TT_Face    face,
-                            FT_Stream  stream );
+  tt_face_load_maxp( TT_Face    face,
+                     FT_Stream  stream );
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_names( TT_Face    face,
-                      FT_Stream  stream );
+  tt_face_load_name( TT_Face    face,
+                     FT_Stream  stream );
 
 
   FT_LOCAL( FT_Error )
@@ -91,26 +85,18 @@
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_postscript( TT_Face    face,
-                           FT_Stream  stream );
+  tt_face_load_post( TT_Face    face,
+                     FT_Stream  stream );
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_hdmx( TT_Face    face,
-                     FT_Stream  stream );
-
-  FT_LOCAL( FT_Error )
   tt_face_load_pclt( TT_Face    face,
                      FT_Stream  stream );
 
   FT_LOCAL( void )
-  tt_face_free_names( TT_Face  face );
+  tt_face_free_name( TT_Face  face );
 
 
-  FT_LOCAL( void )
-  tt_face_free_hdmx ( TT_Face  face );
-
-
   FT_LOCAL( FT_Error )
   tt_face_load_gasp( TT_Face    face,
                      FT_Stream  stream );
@@ -118,8 +104,8 @@
 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
 
   FT_LOCAL( FT_Error )
-  tt_face_load_bitmap_header( TT_Face    face,
-                              FT_Stream  stream );
+  tt_face_load_bhed( TT_Face    face,
+                     FT_Stream  stream );
 
 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
 
--- /dev/null
+++ b/src/sfnt/ttmtx.c
@@ -1,0 +1,1038 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttmtx.c                                                                */
+/*                                                                         */
+/*    Load the metrics tables common to TTF and OTF fonts (body).          */
+/*                                                                         */
+/*  Copyright 2006 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 <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttmtx.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttmtx
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_hmtx                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Load the `hmtx' or `vmtx' table into a face object.                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load `vmtx'.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+#ifdef FT_OPTIMIZE_MEMORY
+
+  static FT_Error
+  tt_face_load_hmtx( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical )
+  {
+    FT_Error   error;
+    FT_ULong   table_size;
+    FT_Byte**  ptable;
+    FT_ULong*  ptable_size;
+    
+    
+    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+                                                       : "Horizontal",
+                                              face ));
+
+    if ( vertical )
+    {
+      ptable      = &face->vert_metrics;
+      ptable_size = &face->vert_metrics_size;
+      
+      /* The table is optional, quit silently if it wasn't found.      */
+      /*                                                               */
+      /* XXX: Some fonts have a valid vertical header with a non-null  */
+      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
+      /*      table to get the metrics from (e.g. mingliu).            */
+      /*                                                               */
+      /*      For safety, we set the field to 0!                       */
+      /*                                                               */
+      error = face->goto_table( face, TTAG_vmtx, stream, &table_size );
+      if ( error )
+      {
+        /* Set number_Of_VMetrics to 0! */
+        FT_TRACE2(( "  no vertical header in file.\n" ));
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+    }
+    else
+    {
+      ptable      = &face->horz_metrics;
+      ptable_size = &face->horz_metrics_size;
+
+      error = face->goto_table( face, TTAG_hmtx, stream, &table_size );
+      if ( error )
+      {
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        /* If this is an incrementally loaded font and there are */
+        /* overriding metrics, tolerate a missing `hmtx' table.  */
+        if ( face->root.internal->incremental_interface          &&
+             face->root.internal->incremental_interface->funcs->
+               get_glyph_metrics                                 )
+        {
+          face->horizontal.number_Of_HMetrics = 0;
+          error = SFNT_Err_Ok;
+          goto Exit;
+        }
+#endif
+
+        FT_ERROR(( " no horizontal metrics in file!\n" ));
+        error = SFNT_Err_Hmtx_Table_Missing;
+        goto Exit;
+      }
+    }
+    
+    if ( FT_FRAME_EXTRACT( table_size, *ptable ) )
+      goto Exit;
+      
+    *ptable_size = table_size;
+    
+  Exit:
+    return error;
+  }
+
+#else /* !OPTIMIZE_MEMORY */
+
+  static FT_Error
+  tt_face_load_hmtx( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    FT_ULong   table_len;
+    FT_Long    num_shorts, num_longs, num_shorts_checked;
+
+    TT_LongMetrics *   longs;
+    TT_ShortMetrics**  shorts;
+
+
+    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+                                                       : "Horizontal",
+                                              face ));
+
+    if ( vertical )
+    {
+      /* The table is optional, quit silently if it wasn't found.      */
+      /*                                                               */
+      /* XXX: Some fonts have a valid vertical header with a non-null  */
+      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
+      /*      table to get the metrics from (e.g. mingliu).            */
+      /*                                                               */
+      /*      For safety, we set the field to 0!                       */
+      /*                                                               */
+      error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
+      if ( error )
+      {
+        /* Set number_Of_VMetrics to 0! */
+        FT_TRACE2(( "  no vertical header in file.\n" ));
+        face->vertical.number_Of_VMetrics = 0;
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+
+      num_longs = face->vertical.number_Of_VMetrics;
+      longs     = (TT_LongMetrics *)&face->vertical.long_metrics;
+      shorts    = (TT_ShortMetrics**)&face->vertical.short_metrics;
+    }
+    else
+    {
+      error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
+      if ( error )
+      {
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        /* If this is an incrementally loaded font and there are */
+        /* overriding metrics, tolerate a missing `hmtx' table.  */
+        if ( face->root.internal->incremental_interface          &&
+             face->root.internal->incremental_interface->funcs->
+               get_glyph_metrics                                 )
+        {
+          face->horizontal.number_Of_HMetrics = 0;
+          error = SFNT_Err_Ok;
+          goto Exit;
+        }
+#endif
+
+        FT_ERROR(( " no horizontal metrics in file!\n" ));
+        error = SFNT_Err_Hmtx_Table_Missing;
+        goto Exit;
+      }
+
+      num_longs = face->horizontal.number_Of_HMetrics;
+      longs     = (TT_LongMetrics *)&face->horizontal.long_metrics;
+      shorts    = (TT_ShortMetrics**)&face->horizontal.short_metrics;
+    }
+
+    /* never trust derived values */
+
+    num_shorts         = face->max_profile.numGlyphs - num_longs;
+    num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
+
+    if ( num_shorts < 0 )
+    {
+      FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
+                 vertical ? "Vertical"
+                          : "Horizontal" ));
+
+      /* Adobe simply ignores this problem.  So we shall do the same. */
+#if 0
+      error = vertical ? SFNT_Err_Invalid_Vert_Metrics
+                       : SFNT_Err_Invalid_Horiz_Metrics;
+      goto Exit;
+#else
+      num_shorts = 0;
+#endif
+    }
+
+    if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
+         FT_QNEW_ARRAY( *shorts, num_shorts ) )
+      goto Exit;
+
+    if ( FT_FRAME_ENTER( table_len ) )
+      goto Exit;
+
+    {
+      TT_LongMetrics  cur   = *longs;
+      TT_LongMetrics  limit = cur + num_longs;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        cur->advance = FT_GET_USHORT();
+        cur->bearing = FT_GET_SHORT();
+      }
+    }
+
+    /* do we have an inconsistent number of metric values? */
+    {
+      TT_ShortMetrics*  cur   = *shorts;
+      TT_ShortMetrics*  limit = cur +
+                                FT_MIN( num_shorts, num_shorts_checked );
+
+
+      for ( ; cur < limit; cur++ )
+        *cur = FT_GET_SHORT();
+
+      /* We fill up the missing left side bearings with the     */
+      /* last valid value.  Since this will occur for buggy CJK */
+      /* fonts usually only, nothing serious will happen.       */
+      if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
+      {
+        FT_Short  val = (*shorts)[num_shorts_checked - 1];
+
+
+        limit = *shorts + num_shorts;
+        for ( ; cur < limit; cur++ )
+          *cur = val;
+      }
+    }
+
+    FT_FRAME_EXIT();
+
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+#endif /* !FT_OPTIMIZE_METRICS */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_hhea                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Load the `hhea' or 'vhea' table into a face object.                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load `vhea'.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_hhea( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical )
+  {
+    FT_Error        error;
+    TT_HoriHeader*  header;
+
+    const FT_Frame_Field  metrics_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_HoriHeader
+
+      FT_FRAME_START( 36 ),
+        FT_FRAME_ULONG ( Version ),
+        FT_FRAME_SHORT ( Ascender ),
+        FT_FRAME_SHORT ( Descender ),
+        FT_FRAME_SHORT ( Line_Gap ),
+        FT_FRAME_USHORT( advance_Width_Max ),
+        FT_FRAME_SHORT ( min_Left_Side_Bearing ),
+        FT_FRAME_SHORT ( min_Right_Side_Bearing ),
+        FT_FRAME_SHORT ( xMax_Extent ),
+        FT_FRAME_SHORT ( caret_Slope_Rise ),
+        FT_FRAME_SHORT ( caret_Slope_Run ),
+        FT_FRAME_SHORT ( caret_Offset ),
+        FT_FRAME_SHORT ( Reserved[0] ),
+        FT_FRAME_SHORT ( Reserved[1] ),
+        FT_FRAME_SHORT ( Reserved[2] ),
+        FT_FRAME_SHORT ( Reserved[3] ),
+        FT_FRAME_SHORT ( metric_Data_Format ),
+        FT_FRAME_USHORT( number_Of_HMetrics ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
+
+    if ( vertical )
+    {
+      face->vertical_info = 0;
+
+      /* The vertical header table is optional, so return quietly if */
+      /* we don't find it.                                           */
+      error = face->goto_table( face, TTAG_vhea, stream, 0 );
+      if ( error )
+      {
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+
+      face->vertical_info = 1;
+      header = (TT_HoriHeader*)&face->vertical;
+    }
+    else
+    {
+      /* The horizontal header is mandatory for most fonts; return */
+      /* an error if we don't find it.                             */
+      error = face->goto_table( face, TTAG_hhea, stream, 0 );
+      if ( error )
+      {
+        error = SFNT_Err_Horiz_Header_Missing;
+
+        /* No `hhea' table necessary for SFNT Mac fonts. */
+        if ( face->format_tag == TTAG_true )
+        {
+          FT_TRACE2(( "missing.  This is an SFNT Mac font.\n"));
+          error = SFNT_Err_Ok;
+        }
+
+        goto Exit;
+      }
+
+      header = &face->horizontal;
+    }
+
+    if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
+      goto Exit;
+
+    header->long_metrics  = NULL;
+    header->short_metrics = NULL;
+
+    FT_TRACE2(( "loaded\n" ));
+
+    /* Now try to load the corresponding metrics */
+
+    error = tt_face_load_hmtx( face, stream, vertical );
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_get_metrics                                                */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns the horizontal or vertical metrics in font units for a     */
+  /*    given glyph.  The metrics are the left side bearing (resp. top     */
+  /*    side bearing) and advance width (resp. advance height).            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    header  :: A pointer to either the horizontal or vertical metrics  */
+  /*               structure.                                              */
+  /*                                                                       */
+  /*    idx     :: The glyph index.                                        */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    bearing :: The bearing, either left side or top side.              */
+  /*                                                                       */
+  /*    advance :: The advance width resp. advance height.                 */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This function will much probably move to another component in the  */
+  /*    near future, but I haven't decided which yet.                      */
+  /*                                                                       */
+#ifdef FT_OPTIMIZE_MEMORY
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_get_metrics( TT_Face     face,
+                       FT_Bool     vertical,
+                       FT_UInt     gindex,
+                       FT_Short   *abearing,
+                       FT_UShort  *aadvance )
+  {
+    TT_HoriHeader*  header;
+    FT_Byte*        p;
+    FT_Byte*        limit;
+    FT_UShort       k;
+
+
+    if ( vertical )
+    {
+      header = (TT_HoriHeader*)&face->vertical;
+      p      = face->vert_metrics;
+      limit  = p + face->vert_metrics_size;
+    }
+    else
+    {
+      header = &face->horizontal;
+      p      = face->horz_metrics;
+      limit  = p + face->horz_metrics_size;
+    }
+
+    k = header->number_Of_HMetrics;
+
+    if ( k > 0 )
+    {
+      if ( gindex < (FT_UInt)k )
+      {
+        p += 4 * gindex;
+        if ( p + 4 > limit )
+          goto NoData;
+
+        *aadvance = FT_NEXT_USHORT( p );
+        *abearing = FT_NEXT_SHORT( p );
+      }
+      else
+      {
+        p += 4 * ( k - 1 );
+        if ( p + 4 > limit )
+          goto NoData;
+
+        *aadvance = FT_NEXT_USHORT( p );
+        p += 2 + 2 * ( gindex - k );
+        if ( p + 2 > limit )
+          *abearing = 0;
+        else
+          *abearing = FT_PEEK_SHORT( p );
+      }
+    }
+    else
+    {
+    NoData:
+      *abearing = 0;
+      *aadvance = 0;
+    }
+
+    return SFNT_Err_Ok;
+  }
+
+#else /* !FT_OPTIMIZE_MEMORY */
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_get_metrics( TT_Face     face,
+                       FT_Bool     vertical,
+                       FT_UInt     gindex,
+                       FT_Short*   abearing,
+                       FT_UShort*  aadvance )
+  {
+    TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)&face->vertical
+                                      :                 &face->horizontal;
+    TT_LongMetrics  longs_m;
+    FT_UShort       k      = header->number_Of_HMetrics;
+
+
+    if ( k == 0 )
+    {
+      *abearing = *aadvance = 0;
+      return SFNT_Err_Ok;
+    }
+
+    if ( gindex < (FT_UInt)k )
+    {
+      longs_m   = (TT_LongMetrics)header->long_metrics + gindex;
+      *abearing = longs_m->bearing;
+      *aadvance = longs_m->advance;
+    }
+    else
+    {
+      *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
+      *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
+    }
+
+    return SFNT_Err_Ok;
+  }
+
+#endif /* !FT_OPTIMIZE_MEMORY */
+
+
+/* END */
+/***************************************************************************/
+/*                                                                         */
+/*  ttmtx.c                                                                */
+/*                                                                         */
+/*    Load the metrics tables common to TTF and OTF fonts (body).          */
+/*                                                                         */
+/*  Copyright 2006 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 <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttmtx.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttmtx
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_hmtx                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Load the `hmtx' or `vmtx' table into a face object.                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load `vmtx'.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+#ifdef FT_OPTIMIZE_MEMORY
+
+  static FT_Error
+  tt_face_load_hmtx( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical )
+  {
+    FT_Error   error;
+    FT_ULong   table_size;
+    FT_Byte**  ptable;
+    FT_ULong*  ptable_size;
+    
+    
+    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+                                                       : "Horizontal",
+                                              face ));
+
+    if ( vertical )
+    {
+      ptable      = &face->vert_metrics;
+      ptable_size = &face->vert_metrics_size;
+      
+      /* The table is optional, quit silently if it wasn't found.      */
+      /*                                                               */
+      /* XXX: Some fonts have a valid vertical header with a non-null  */
+      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
+      /*      table to get the metrics from (e.g. mingliu).            */
+      /*                                                               */
+      /*      For safety, we set the field to 0!                       */
+      /*                                                               */
+      error = face->goto_table( face, TTAG_vmtx, stream, &table_size );
+      if ( error )
+      {
+        /* Set number_Of_VMetrics to 0! */
+        FT_TRACE2(( "  no vertical header in file.\n" ));
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+    }
+    else
+    {
+      ptable      = &face->horz_metrics;
+      ptable_size = &face->horz_metrics_size;
+
+      error = face->goto_table( face, TTAG_hmtx, stream, &table_size );
+      if ( error )
+      {
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        /* If this is an incrementally loaded font and there are */
+        /* overriding metrics, tolerate a missing `hmtx' table.  */
+        if ( face->root.internal->incremental_interface          &&
+             face->root.internal->incremental_interface->funcs->
+               get_glyph_metrics                                 )
+        {
+          face->horizontal.number_Of_HMetrics = 0;
+          error = SFNT_Err_Ok;
+          goto Exit;
+        }
+#endif
+
+        FT_ERROR(( " no horizontal metrics in file!\n" ));
+        error = SFNT_Err_Hmtx_Table_Missing;
+        goto Exit;
+      }
+    }
+    
+    if ( FT_FRAME_EXTRACT( table_size, *ptable ) )
+      goto Exit;
+      
+    *ptable_size = table_size;
+    
+  Exit:
+    return error;
+  }
+
+#else /* !OPTIMIZE_MEMORY */
+
+  static FT_Error
+  tt_face_load_hmtx( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    FT_ULong   table_len;
+    FT_Long    num_shorts, num_longs, num_shorts_checked;
+
+    TT_LongMetrics *   longs;
+    TT_ShortMetrics**  shorts;
+
+
+    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+                                                       : "Horizontal",
+                                              face ));
+
+    if ( vertical )
+    {
+      /* The table is optional, quit silently if it wasn't found.      */
+      /*                                                               */
+      /* XXX: Some fonts have a valid vertical header with a non-null  */
+      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
+      /*      table to get the metrics from (e.g. mingliu).            */
+      /*                                                               */
+      /*      For safety, we set the field to 0!                       */
+      /*                                                               */
+      error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
+      if ( error )
+      {
+        /* Set number_Of_VMetrics to 0! */
+        FT_TRACE2(( "  no vertical header in file.\n" ));
+        face->vertical.number_Of_VMetrics = 0;
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+
+      num_longs = face->vertical.number_Of_VMetrics;
+      longs     = (TT_LongMetrics *)&face->vertical.long_metrics;
+      shorts    = (TT_ShortMetrics**)&face->vertical.short_metrics;
+    }
+    else
+    {
+      error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
+      if ( error )
+      {
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        /* If this is an incrementally loaded font and there are */
+        /* overriding metrics, tolerate a missing `hmtx' table.  */
+        if ( face->root.internal->incremental_interface          &&
+             face->root.internal->incremental_interface->funcs->
+               get_glyph_metrics                                 )
+        {
+          face->horizontal.number_Of_HMetrics = 0;
+          error = SFNT_Err_Ok;
+          goto Exit;
+        }
+#endif
+
+        FT_ERROR(( " no horizontal metrics in file!\n" ));
+        error = SFNT_Err_Hmtx_Table_Missing;
+        goto Exit;
+      }
+
+      num_longs = face->horizontal.number_Of_HMetrics;
+      longs     = (TT_LongMetrics *)&face->horizontal.long_metrics;
+      shorts    = (TT_ShortMetrics**)&face->horizontal.short_metrics;
+    }
+
+    /* never trust derived values */
+
+    num_shorts         = face->max_profile.numGlyphs - num_longs;
+    num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
+
+    if ( num_shorts < 0 )
+    {
+      FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
+                 vertical ? "Vertical"
+                          : "Horizontal" ));
+
+      /* Adobe simply ignores this problem.  So we shall do the same. */
+#if 0
+      error = vertical ? SFNT_Err_Invalid_Vert_Metrics
+                       : SFNT_Err_Invalid_Horiz_Metrics;
+      goto Exit;
+#else
+      num_shorts = 0;
+#endif
+    }
+
+    if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
+         FT_QNEW_ARRAY( *shorts, num_shorts ) )
+      goto Exit;
+
+    if ( FT_FRAME_ENTER( table_len ) )
+      goto Exit;
+
+    {
+      TT_LongMetrics  cur   = *longs;
+      TT_LongMetrics  limit = cur + num_longs;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        cur->advance = FT_GET_USHORT();
+        cur->bearing = FT_GET_SHORT();
+      }
+    }
+
+    /* do we have an inconsistent number of metric values? */
+    {
+      TT_ShortMetrics*  cur   = *shorts;
+      TT_ShortMetrics*  limit = cur +
+                                FT_MIN( num_shorts, num_shorts_checked );
+
+
+      for ( ; cur < limit; cur++ )
+        *cur = FT_GET_SHORT();
+
+      /* We fill up the missing left side bearings with the     */
+      /* last valid value.  Since this will occur for buggy CJK */
+      /* fonts usually only, nothing serious will happen.       */
+      if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
+      {
+        FT_Short  val = (*shorts)[num_shorts_checked - 1];
+
+
+        limit = *shorts + num_shorts;
+        for ( ; cur < limit; cur++ )
+          *cur = val;
+      }
+    }
+
+    FT_FRAME_EXIT();
+
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+#endif /* !FT_OPTIMIZE_METRICS */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_hhea                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Load the `hhea' or 'vhea' table into a face object.                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load `vhea'.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_hhea( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical )
+  {
+    FT_Error        error;
+    TT_HoriHeader*  header;
+
+    const FT_Frame_Field  metrics_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_HoriHeader
+
+      FT_FRAME_START( 36 ),
+        FT_FRAME_ULONG ( Version ),
+        FT_FRAME_SHORT ( Ascender ),
+        FT_FRAME_SHORT ( Descender ),
+        FT_FRAME_SHORT ( Line_Gap ),
+        FT_FRAME_USHORT( advance_Width_Max ),
+        FT_FRAME_SHORT ( min_Left_Side_Bearing ),
+        FT_FRAME_SHORT ( min_Right_Side_Bearing ),
+        FT_FRAME_SHORT ( xMax_Extent ),
+        FT_FRAME_SHORT ( caret_Slope_Rise ),
+        FT_FRAME_SHORT ( caret_Slope_Run ),
+        FT_FRAME_SHORT ( caret_Offset ),
+        FT_FRAME_SHORT ( Reserved[0] ),
+        FT_FRAME_SHORT ( Reserved[1] ),
+        FT_FRAME_SHORT ( Reserved[2] ),
+        FT_FRAME_SHORT ( Reserved[3] ),
+        FT_FRAME_SHORT ( metric_Data_Format ),
+        FT_FRAME_USHORT( number_Of_HMetrics ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
+
+    if ( vertical )
+    {
+      face->vertical_info = 0;
+
+      /* The vertical header table is optional, so return quietly if */
+      /* we don't find it.                                           */
+      error = face->goto_table( face, TTAG_vhea, stream, 0 );
+      if ( error )
+      {
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+
+      face->vertical_info = 1;
+      header = (TT_HoriHeader*)&face->vertical;
+    }
+    else
+    {
+      /* The horizontal header is mandatory for most fonts; return */
+      /* an error if we don't find it.                             */
+      error = face->goto_table( face, TTAG_hhea, stream, 0 );
+      if ( error )
+      {
+        error = SFNT_Err_Horiz_Header_Missing;
+
+        /* No `hhea' table necessary for SFNT Mac fonts. */
+        if ( face->format_tag == TTAG_true )
+        {
+          FT_TRACE2(( "missing.  This is an SFNT Mac font.\n"));
+          error = SFNT_Err_Ok;
+        }
+
+        goto Exit;
+      }
+
+      header = &face->horizontal;
+    }
+
+    if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
+      goto Exit;
+
+    header->long_metrics  = NULL;
+    header->short_metrics = NULL;
+
+    FT_TRACE2(( "loaded\n" ));
+
+    /* Now try to load the corresponding metrics */
+
+    error = tt_face_load_hmtx( face, stream, vertical );
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_get_metrics                                                */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns the horizontal or vertical metrics in font units for a     */
+  /*    given glyph.  The metrics are the left side bearing (resp. top     */
+  /*    side bearing) and advance width (resp. advance height).            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    header  :: A pointer to either the horizontal or vertical metrics  */
+  /*               structure.                                              */
+  /*                                                                       */
+  /*    idx     :: The glyph index.                                        */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    bearing :: The bearing, either left side or top side.              */
+  /*                                                                       */
+  /*    advance :: The advance width resp. advance height.                 */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This function will much probably move to another component in the  */
+  /*    near future, but I haven't decided which yet.                      */
+  /*                                                                       */
+#ifdef FT_OPTIMIZE_MEMORY
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_get_metrics( TT_Face     face,
+                       FT_Bool     vertical,
+                       FT_UInt     gindex,
+                       FT_Short   *abearing,
+                       FT_UShort  *aadvance )
+  {
+    TT_HoriHeader*  header;
+    FT_Byte*        p;
+    FT_Byte*        limit;
+    FT_UShort       k;
+
+
+    if ( vertical )
+    {
+      header = (TT_HoriHeader*)&face->vertical;
+      p      = face->vert_metrics;
+      limit  = p + face->vert_metrics_size;
+    }
+    else
+    {
+      header = &face->horizontal;
+      p      = face->horz_metrics;
+      limit  = p + face->horz_metrics_size;
+    }
+
+    k = header->number_Of_HMetrics;
+
+    if ( k > 0 )
+    {
+      if ( gindex < (FT_UInt)k )
+      {
+        p += 4 * gindex;
+        if ( p + 4 > limit )
+          goto NoData;
+
+        *aadvance = FT_NEXT_USHORT( p );
+        *abearing = FT_NEXT_SHORT( p );
+      }
+      else
+      {
+        p += 4 * ( k - 1 );
+        if ( p + 4 > limit )
+          goto NoData;
+
+        *aadvance = FT_NEXT_USHORT( p );
+        p += 2 + 2 * ( gindex - k );
+        if ( p + 2 > limit )
+          *abearing = 0;
+        else
+          *abearing = FT_PEEK_SHORT( p );
+      }
+    }
+    else
+    {
+    NoData:
+      *abearing = 0;
+      *aadvance = 0;
+    }
+
+    return SFNT_Err_Ok;
+  }
+
+#else /* !FT_OPTIMIZE_MEMORY */
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_get_metrics( TT_Face     face,
+                       FT_Bool     vertical,
+                       FT_UInt     gindex,
+                       FT_Short*   abearing,
+                       FT_UShort*  aadvance )
+  {
+    TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)&face->vertical
+                                      :                 &face->horizontal;
+    TT_LongMetrics  longs_m;
+    FT_UShort       k      = header->number_Of_HMetrics;
+
+
+    if ( k == 0 )
+    {
+      *abearing = *aadvance = 0;
+      return SFNT_Err_Ok;
+    }
+
+    if ( gindex < (FT_UInt)k )
+    {
+      longs_m   = (TT_LongMetrics)header->long_metrics + gindex;
+      *abearing = longs_m->bearing;
+      *aadvance = longs_m->advance;
+    }
+    else
+    {
+      *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
+      *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
+    }
+
+    return SFNT_Err_Ok;
+  }
+
+#endif /* !FT_OPTIMIZE_MEMORY */
+
+
+/* END */
--- /dev/null
+++ b/src/sfnt/ttmtx.h
@@ -1,0 +1,98 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttmtx.h                                                                */
+/*                                                                         */
+/*    Load the metrics tables common to TTF and OTF fonts (specification). */
+/*                                                                         */
+/*  Copyright 2006 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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTMTX_H__
+#define __TTMTX_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_hhea( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_get_metrics( TT_Face     face,
+                       FT_Bool     vertical,
+                       FT_UInt     gindex,
+                       FT_Short*   abearing,
+                       FT_UShort*  aadvance );
+
+FT_END_HEADER
+
+#endif /* __TTMTX_H__ */
+
+
+/* END */
+/***************************************************************************/
+/*                                                                         */
+/*  ttmtx.h                                                                */
+/*                                                                         */
+/*    Load the metrics tables common to TTF and OTF fonts (specification). */
+/*                                                                         */
+/*  Copyright 2006 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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTMTX_H__
+#define __TTMTX_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_hhea( TT_Face    face,
+                     FT_Stream  stream,
+                     FT_Bool    vertical );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_get_metrics( TT_Face     face,
+                       FT_Bool     vertical,
+                       FT_UInt     gindex,
+                       FT_Short*   abearing,
+                       FT_UShort*  aadvance );
+
+FT_END_HEADER
+
+#endif /* __TTMTX_H__ */
+
+
+/* END */
--- a/src/sfnt/ttsbit.c
+++ b/src/sfnt/ttsbit.c
@@ -406,8 +406,8 @@
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_sbit_strikes( TT_Face    face,
-                             FT_Stream  stream )
+  tt_face_load_eblc( TT_Face    face,
+                     FT_Stream  stream )
   {
     FT_Error   error  = 0;
     FT_Memory  memory = stream->memory;
@@ -635,7 +635,7 @@
   /*    face :: The target face object.                                    */
   /*                                                                       */
   FT_LOCAL_DEF( void )
-  tt_face_free_sbit_strikes( TT_Face  face )
+  tt_face_free_eblc( TT_Face  face )
   {
     FT_Memory       memory       = face->root.memory;
     TT_SBit_Strike  strike       = face->sbit_strikes;
--- a/src/sfnt/ttsbit.h
+++ b/src/sfnt/ttsbit.h
@@ -28,11 +28,11 @@
 
 
   FT_LOCAL( FT_Error )
-  tt_face_load_sbit_strikes( TT_Face    face,
-                             FT_Stream  stream );
+  tt_face_load_eblc( TT_Face    face,
+                     FT_Stream  stream );
 
   FT_LOCAL( void )
-  tt_face_free_sbit_strikes( TT_Face  face );
+  tt_face_free_eblc( TT_Face  face );
 
 
   FT_LOCAL( FT_Error )
--- a/src/sfnt/ttsbit0.c
+++ b/src/sfnt/ttsbit0.c
@@ -86,8 +86,8 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  tt_face_load_sbit_strikes( TT_Face    face,
-                             FT_Stream  stream )
+  tt_face_load_eblc( TT_Face    face,
+                     FT_Stream  stream )
   {
     FT_Error   error  = SFNT_Err_Ok;
     FT_Fixed   version;
@@ -197,7 +197,7 @@
 
 
   FT_LOCAL_DEF( void )
-  tt_face_free_sbit_strikes( TT_Face  face )
+  tt_face_free_eblc( TT_Face  face )
   {
     FT_Stream  stream = face->root.stream;
 
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -65,131 +65,6 @@
 
   /*************************************************************************/
   /*                                                                       */
-  /* <Function>                                                            */
-  /*    tt_face_get_metrics                                                */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Returns the horizontal or vertical metrics in font units for a     */
-  /*    given glyph.  The metrics are the left side bearing (resp. top     */
-  /*    side bearing) and advance width (resp. advance height).            */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    header  :: A pointer to either the horizontal or vertical metrics  */
-  /*               structure.                                              */
-  /*                                                                       */
-  /*    idx     :: The glyph index.                                        */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    bearing :: The bearing, either left side or top side.              */
-  /*                                                                       */
-  /*    advance :: The advance width resp. advance height.                 */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    This function will much probably move to another component in the  */
-  /*    near future, but I haven't decided which yet.                      */
-  /*                                                                       */
-#ifdef FT_OPTIMIZE_MEMORY
-
-  static void
-  tt_face_get_metrics( TT_Face     face,
-                       FT_Bool     vertical,
-                       FT_UInt     idx,
-                       FT_Short   *abearing,
-                       FT_UShort  *aadvance )
-  {
-    TT_HoriHeader*  header;
-    FT_Byte*        p;
-    FT_Byte*        limit;
-    FT_UShort       k;
-
-
-    if ( vertical )
-    {
-      header = (TT_HoriHeader*)&face->vertical;
-      p      = face->vert_metrics;
-      limit  = p + face->vert_metrics_size;
-    }
-    else
-    {
-      header = &face->horizontal;
-      p      = face->horz_metrics;
-      limit  = p + face->horz_metrics_size;
-    }
-
-    k = header->number_Of_HMetrics;
-
-    if ( k > 0 )
-    {
-      if ( idx < (FT_UInt)k )
-      {
-        p += 4 * idx;
-        if ( p + 4 > limit )
-          goto NoData;
-
-        *aadvance = FT_NEXT_USHORT( p );
-        *abearing = FT_NEXT_SHORT( p );
-      }
-      else
-      {
-        p += 4 * ( k - 1 );
-        if ( p + 4 > limit )
-          goto NoData;
-
-        *aadvance = FT_NEXT_USHORT( p );
-        p += 2 + 2 * ( idx - k );
-        if ( p + 2 > limit )
-          *abearing = 0;
-        else
-          *abearing = FT_PEEK_SHORT( p );
-      }
-    }
-    else
-    {
-    NoData:
-      *abearing = 0;
-      *aadvance = 0;
-    }
-  }
-
-#else /* !FT_OPTIMIZE_MEMORY */
-
-  static void
-  tt_face_get_metrics( TT_Face     face,
-                       FT_Bool     vertical,
-                       FT_UInt     idx,
-                       FT_Short   *abearing,
-                       FT_UShort  *aadvance )
-  {
-    TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)&face->vertical
-                                      :                 &face->horizontal;
-    TT_LongMetrics  longs_m;
-    FT_UShort       k      = header->number_Of_HMetrics;
-
-
-    if ( k == 0 )
-    {
-      *abearing = *aadvance = 0;
-      return;
-    }
-
-    if ( idx < (FT_UInt)k )
-    {
-      longs_m   = (TT_LongMetrics)header->long_metrics + idx;
-      *abearing = longs_m->bearing;
-      *aadvance = longs_m->advance;
-    }
-    else
-    {
-      *abearing = ((TT_ShortMetrics*)header->short_metrics)[idx - k];
-      *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
-    }
-  }
-
-#endif /* !FT_OPTIMIZE_MEMORY */
-
-
-  /*************************************************************************/
-  /*                                                                       */
   /* Returns the horizontal metrics in font units for a given glyph.  If   */
   /* `check' is true, take care of monospaced fonts by returning the       */
   /* advance width maximum.                                                */
@@ -201,7 +76,7 @@
                 FT_Short*   lsb,
                 FT_UShort*  aw )
   {
-    tt_face_get_metrics( face, 0, idx, lsb, aw );
+    ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw );
 
     if ( check && face->postscript.isFixedPitch )
       *aw = face->horizontal.advance_Width_Max;
@@ -210,50 +85,6 @@
 
   /*************************************************************************/
   /*                                                                       */
-  /* Returns the advance width table for a given pixel size if it is found */
-  /* in the font's `hdmx' table (if any).                                  */
-  /*                                                                       */
-  static FT_Byte*
-  Get_Advance_WidthPtr( TT_Face  face,
-                        FT_Int   ppem,
-                        FT_UInt  gindex )
-  {
-#ifdef FT_OPTIMIZE_MEMORY
-
-    FT_UInt   nn;
-    FT_Byte*  result      = NULL;
-    FT_ULong  record_size = face->hdmx_record_size;
-    FT_Byte*  record      = face->hdmx_table + 8;
-
-
-    for ( nn = 0; nn < face->hdmx_record_count; nn++ )
-      if ( face->hdmx_record_sizes[nn] == ppem )
-      {
-        gindex += 2;
-        if ( gindex < record_size )
-          result = record + gindex;
-        break;
-      }
-
-    return result;
-
-#else
-
-    FT_UShort  n;
-
-
-    for ( n = 0; n < face->hdmx.num_records; n++ )
-      if ( face->hdmx.records[n].ppem == ppem )
-        return &face->hdmx.records[n].widths[gindex];
-
-    return NULL;
-
-#endif
-  }
-
-
-  /*************************************************************************/
-  /*                                                                       */
   /* Returns the vertical metrics in font units for a given glyph.         */
   /* Greg Hitchcock from Microsoft told us that if there were no `vmtx'    */
   /* table, typoAscender/Descender from the `OS/2' table would be used     */
@@ -275,7 +106,7 @@
     FT_UNUSED( check );
 
     if ( face->vertical_info )
-      tt_face_get_metrics( face, 1, idx, tsb, ah );
+      ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah );
 
 #if 1             /* Emperically determined, at variance with what MS said */
 
@@ -1769,10 +1600,12 @@
     if ( !face->postscript.isFixedPitch &&
          IS_HINTED( loader->load_flags )        )
     {
-      FT_Byte*  widthp = Get_Advance_WidthPtr( face,
-                                               size->root.metrics.x_ppem,
-                                               glyph_index );
+      FT_Byte*  widthp;
 
+
+      widthp = tt_face_get_device_metrics( face,
+                                           size->root.metrics.x_ppem,
+                                           glyph_index );
 
       if ( widthp )
         glyph->metrics.horiAdvance = *widthp << 6;
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -216,6 +216,10 @@
     if ( error )
       goto Exit;
 
+    error = tt_face_load_hdmx( face, stream );
+    if ( error )
+      goto Exit;
+
     if ( face->root.face_flags & FT_FACE_FLAG_SCALABLE )
     {
 
@@ -224,11 +228,9 @@
       if ( !face->root.internal->incremental_interface )
         error = tt_face_load_loca( face, stream );
       if ( !error )
-      {
-        error = tt_face_load_cvt( face, stream );
-        if ( !error )
-          error = tt_face_load_fpgm( face, stream );
-      }
+        error = tt_face_load_cvt( face, stream )  ||
+                tt_face_load_fpgm( face, stream ) ||
+                tt_face_load_prep( face, stream );
 
 #else
 
@@ -235,7 +237,8 @@
       if ( !error )
         error = tt_face_load_loca( face, stream ) ||
                 tt_face_load_cvt( face, stream )  ||
-                tt_face_load_fpgm( face, stream );
+                tt_face_load_fpgm( face, stream ) ||
+                tt_face_load_prep( face, stream );
 
 #endif
 
@@ -300,6 +303,8 @@
 
     /* freeing the locations table */
     tt_face_done_loca( face );
+
+    tt_face_free_hdmx( face );
 
     /* freeing the CVT */
     FT_FREE( face->cvt );
--- a/src/truetype/ttpload.c
+++ b/src/truetype/ttpload.c
@@ -2,7 +2,7 @@
 /*                                                                         */
 /*  ttpload.c                                                              */
 /*                                                                         */
-/*    TrueType glyph data/program tables loader (body).                    */
+/*    TrueType-specific tables loader (body).                              */
 /*                                                                         */
 /*  Copyright 1996-2001, 2002, 2004, 2005, 2006 by                         */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
@@ -400,7 +400,7 @@
   /*    tt_face_load_fpgm                                                  */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    Loads the font program and the cvt program.                        */
+  /*    Loads the font program.                                            */
   /*                                                                       */
   /* <InOut>                                                               */
   /*    face   :: A handle to the target face object.                      */
@@ -429,6 +429,7 @@
     {
       face->font_program      = NULL;
       face->font_program_size = 0;
+      error                   = TT_Err_Ok;
 
       FT_TRACE2(( "is missing!\n" ));
     }
@@ -441,6 +442,47 @@
       FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
     }
 
+  Exit:
+    return error;
+
+#else /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    FT_UNUSED( face   );
+    FT_UNUSED( stream );
+
+    return TT_Err_Ok;
+
+#endif
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_prep                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the cvt program.                                             */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_prep( TT_Face    face,
+                     FT_Stream  stream )
+  {
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    FT_Error   error;
+    FT_ULong   table_len;
+
+
     FT_TRACE2(( "Prep program " ));
 
     error = face->goto_table( face, TTAG_prep, stream, &table_len );
@@ -470,6 +512,232 @@
     FT_UNUSED( stream );
 
     return TT_Err_Ok;
+
+#endif
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_hdmx                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the `hdmx' table into the face object.                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+#ifdef FT_OPTIMIZE_MEMORY
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_hdmx( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+    FT_UInt    version, nn, num_records;
+    FT_ULong   table_size, record_size;
+    FT_Byte*   p;
+    FT_Byte*   limit;
+
+
+    /* this table is optional */
+    error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
+    if ( error || table_size < 8 )
+      return TT_Err_Ok;
+
+    if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
+      goto Exit;
+
+    p     = face->hdmx_table;
+    limit = p + table_size;
+
+    version     = FT_NEXT_USHORT( p );
+    num_records = FT_NEXT_USHORT( p );
+    record_size = FT_NEXT_ULONG( p );
+
+    if ( version != 0 || num_records > 255 || record_size > 0x40000 )
+    {
+      error = TT_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
+    if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
+      goto Fail;
+
+    for ( nn = 0; nn < num_records; nn++ )
+    {
+      if ( p + record_size > limit )
+        break;
+        
+      face->hdmx_record_sizes[nn] = p[0];
+      p                          += record_size;
+    }
+    
+    face->hdmx_record_count = nn;
+    face->hdmx_table_size   = table_size;
+
+  Exit:
+    return error;
+    
+  Fail:
+    FT_FRAME_RELEASE( face->hdmx_table );
+    face->hdmx_table_size = 0;
+    goto Exit;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  tt_face_free_hdmx( TT_Face  face )
+  {
+    FT_Stream  stream = face->root.stream;
+    FT_Memory  memory = stream->memory;
+    
+
+    FT_FREE( face->hdmx_record_sizes );
+    FT_FRAME_RELEASE( face->hdmx_table );
+  }
+
+#else /* !FT_OPTIMIZE_MEMORY */
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_hdmx( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    TT_Hdmx    hdmx = &face->hdmx;
+    FT_Short   num_records;
+    FT_Long    num_glyphs;
+    FT_Long    record_size;
+
+
+    hdmx->version     = 0;
+    hdmx->num_records = 0;
+    hdmx->records     = 0;
+
+    /* this table is optional */
+    error = face->goto_table( face, TTAG_hdmx, stream, 0 );
+    if ( error )
+      return TT_Err_Ok;
+
+    if ( FT_FRAME_ENTER( 8L ) )
+      goto Exit;
+
+    hdmx->version = FT_GET_USHORT();
+    num_records   = FT_GET_SHORT();
+    record_size   = FT_GET_LONG();
+
+    FT_FRAME_EXIT();
+
+    if ( record_size < 0 || num_records < 0 )
+      return TT_Err_Invalid_File_Format;
+
+    /* Only recognize format 0 */
+    if ( hdmx->version != 0 )
+      goto Exit;
+
+    /* we can't use FT_QNEW_ARRAY here; otherwise tt_face_free_hdmx */
+    /* could fail during deallocation                               */
+    if ( FT_NEW_ARRAY( hdmx->records, num_records ) )
+      goto Exit;
+
+    hdmx->num_records = num_records;
+    num_glyphs        = face->root.num_glyphs;
+    record_size      -= num_glyphs + 2;
+
+    {
+      TT_HdmxEntry  cur   = hdmx->records;
+      TT_HdmxEntry  limit = cur + hdmx->num_records;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        /* read record */
+        if ( FT_READ_BYTE( cur->ppem      ) ||
+             FT_READ_BYTE( cur->max_width ) )
+          goto Exit;
+
+        if ( FT_QALLOC( cur->widths, num_glyphs )      ||
+             FT_STREAM_READ( cur->widths, num_glyphs ) )
+          goto Exit;
+
+        /* skip padding bytes */
+        if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
+          goto Exit;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  tt_face_free_hdmx( TT_Face  face )
+  {
+    if ( face )
+    {
+      FT_Int     n;
+      FT_Memory  memory = face->root.driver->root.memory;
+
+
+      for ( n = 0; n < face->hdmx.num_records; n++ )
+        FT_FREE( face->hdmx.records[n].widths );
+
+      FT_FREE( face->hdmx.records );
+      face->hdmx.num_records = 0;
+    }
+  }
+
+#endif /* !OPTIMIZE_MEMORY */
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Returns the advance width table for a given pixel size if it is found */
+  /* in the font's `hdmx' table (if any).                                  */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Byte* )
+  tt_face_get_device_metrics( TT_Face  face,
+                              FT_Byte  ppem,
+                              FT_UInt  gindex )
+  {
+#ifdef FT_OPTIMIZE_MEMORY
+
+    FT_UInt   nn;
+    FT_Byte*  result      = NULL;
+    FT_ULong  record_size = face->hdmx_record_size;
+    FT_Byte*  record      = face->hdmx_table + 8;
+
+
+    for ( nn = 0; nn < face->hdmx_record_count; nn++ )
+      if ( face->hdmx_record_sizes[nn] == ppem )
+      {
+        gindex += 2;
+        if ( gindex < record_size )
+          result = record + gindex;
+        break;
+      }
+
+    return result;
+
+#else
+
+    FT_UShort  n;
+
+
+    for ( n = 0; n < face->hdmx.num_records; n++ )
+      if ( face->hdmx.records[n].ppem == ppem )
+        return &face->hdmx.records[n].widths[gindex];
+
+    return NULL;
 
 #endif
   }
--- a/src/truetype/ttpload.h
+++ b/src/truetype/ttpload.h
@@ -2,9 +2,9 @@
 /*                                                                         */
 /*  ttpload.h                                                              */
 /*                                                                         */
-/*    TrueType glyph data/program tables loader (specification).           */
+/*    TrueType-specific tables loader (specification).                     */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2005 by                                     */
+/*  Copyright 1996-2001, 2002, 2005, 2006 by                               */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -47,6 +47,25 @@
   tt_face_load_fpgm( TT_Face    face,
                      FT_Stream  stream );
 
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_prep( TT_Face    face,
+                     FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_hdmx( TT_Face    face,
+                     FT_Stream  stream );
+
+
+  FT_LOCAL( void )
+  tt_face_free_hdmx( TT_Face  face );
+
+
+  FT_LOCAL( FT_Byte* )
+  tt_face_get_device_metrics( TT_Face    face,
+                              FT_Byte    ppem,
+                              FT_UInt    gindex );
 
 FT_END_HEADER