- Remove svn:needs-lock, svn:eol-type, and svn:eol-tyle properties.
[reactos.git] / reactos / lib / 3rdparty / freetype / src / type1 / t1afm.c
index 7bc64df..b81a8df 100644 (file)
-/***************************************************************************/\r
-/*                                                                         */\r
-/*  t1afm.c                                                                */\r
-/*                                                                         */\r
-/*    AFM support for Type 1 fonts (body).                                 */\r
-/*                                                                         */\r
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by             */\r
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */\r
-/*                                                                         */\r
-/*  This file is part of the FreeType project, and may only be used,       */\r
-/*  modified, and distributed under the terms of the FreeType project      */\r
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */\r
-/*  this file you indicate that you have read the license and              */\r
-/*  understand and accept it fully.                                        */\r
-/*                                                                         */\r
-/***************************************************************************/\r
-\r
-\r
-#include <ft2build.h>\r
-#include "t1afm.h"\r
-#include "t1errors.h"\r
-#include FT_INTERNAL_STREAM_H\r
-#include FT_INTERNAL_POSTSCRIPT_AUX_H\r
-\r
-\r
-  /*************************************************************************/\r
-  /*                                                                       */\r
-  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */\r
-  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */\r
-  /* messages during execution.                                            */\r
-  /*                                                                       */\r
-#undef  FT_COMPONENT\r
-#define FT_COMPONENT  trace_t1afm\r
-\r
-\r
-  FT_LOCAL_DEF( void )\r
-  T1_Done_Metrics( FT_Memory     memory,\r
-                   AFM_FontInfo  fi )\r
-  {\r
-    FT_FREE( fi->KernPairs );\r
-    fi->NumKernPair = 0;\r
-\r
-    FT_FREE( fi->TrackKerns );\r
-    fi->NumTrackKern = 0;\r
-\r
-    FT_FREE( fi );\r
-  }\r
-\r
-\r
-  /* read a glyph name and return the equivalent glyph index */\r
-  static FT_Int\r
-  t1_get_index( const char*  name,\r
-                FT_UInt      len,\r
-                void*        user_data )\r
-  {\r
-    T1_Font  type1 = (T1_Font)user_data;\r
-    FT_Int   n;\r
-\r
-\r
-    for ( n = 0; n < type1->num_glyphs; n++ )\r
-    {\r
-      char*  gname = (char*)type1->glyph_names[n];\r
-\r
-\r
-      if ( gname && gname[0] == name[0]        &&\r
-           ft_strlen( gname ) == len           &&\r
-           ft_strncmp( gname, name, len ) == 0 )\r
-        return n;\r
-    }\r
-\r
-    return 0;\r
-  }\r
-\r
-\r
-#undef  KERN_INDEX\r
-#define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )\r
-\r
-\r
-  /* compare two kerning pairs */\r
-  FT_CALLBACK_DEF( int )\r
-  compare_kern_pairs( const void*  a,\r
-                      const void*  b )\r
-  {\r
-    AFM_KernPair  pair1 = (AFM_KernPair)a;\r
-    AFM_KernPair  pair2 = (AFM_KernPair)b;\r
-\r
-    FT_ULong  index1 = KERN_INDEX( pair1->index1, pair1->index2 );\r
-    FT_ULong  index2 = KERN_INDEX( pair2->index1, pair2->index2 );\r
-\r
-\r
-    return (int)( index1 - index2 );\r
-  }\r
-\r
-\r
-  /* parse a PFM file -- for now, only read the kerning pairs */\r
-  static FT_Error\r
-  T1_Read_PFM( FT_Face       t1_face,\r
-               FT_Stream     stream,\r
-               AFM_FontInfo  fi )\r
-  {\r
-    FT_Error      error = T1_Err_Ok;\r
-    FT_Memory     memory = stream->memory;\r
-    FT_Byte*      start;\r
-    FT_Byte*      limit;\r
-    FT_Byte*      p;\r
-    AFM_KernPair  kp;\r
-    FT_Int        width_table_length;\r
-    FT_CharMap    oldcharmap;\r
-    FT_CharMap    charmap;\r
-    FT_Int        n;\r
-\r
-\r
-    start = (FT_Byte*)stream->cursor;\r
-    limit = (FT_Byte*)stream->limit;\r
-    p     = start;\r
-\r
-    /* Figure out how long the width table is.          */\r
-    /* This info is a little-endian short at offset 99. */\r
-    p = start + 99;\r
-    if ( p + 2 > limit )\r
-    {\r
-      error = T1_Err_Unknown_File_Format;\r
-      goto Exit;\r
-    }\r
-    width_table_length = FT_PEEK_USHORT_LE( p );\r
-\r
-    p += 18 + width_table_length;\r
-    if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )\r
-      /* extension table is probably optional */\r
-      goto Exit;\r
-\r
-    /* Kerning offset is 14 bytes from start of extensions table. */\r
-    p += 14;\r
-    p = start + FT_PEEK_ULONG_LE( p );\r
-\r
-    if ( p == start )\r
-      /* zero offset means no table */\r
-      goto Exit;\r
-\r
-    if ( p + 2 > limit )\r
-    {\r
-      error = T1_Err_Unknown_File_Format;\r
-      goto Exit;\r
-    }\r
-\r
-    fi->NumKernPair = FT_PEEK_USHORT_LE( p );\r
-    p += 2;\r
-    if ( p + 4 * fi->NumKernPair > limit )\r
-    {\r
-      error = T1_Err_Unknown_File_Format;\r
-      goto Exit;\r
-    }\r
-\r
-    /* Actually, kerning pairs are simply optional! */\r
-    if ( fi->NumKernPair == 0 )\r
-      goto Exit;\r
-\r
-    /* allocate the pairs */\r
-    if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )\r
-      goto Exit;\r
-\r
-    /* now, read each kern pair */\r
-    kp             = fi->KernPairs;\r
-    limit          = p + 4 * fi->NumKernPair;\r
-\r
-    /* PFM kerning data are stored by encoding rather than glyph index, */\r
-    /* so find the PostScript charmap of this font and install it       */\r
-    /* temporarily.  If we find no PostScript charmap, then just use    */\r
-    /* the default and hope it is the right one.                        */\r
-    oldcharmap = t1_face->charmap;\r
-    charmap    = NULL;\r
-\r
-    for ( n = 0; n < t1_face->num_charmaps; n++ )\r
-    {\r
-      charmap = t1_face->charmaps[n];\r
-      /* check against PostScript pseudo platform */\r
-      if ( charmap->platform_id == 7 )\r
-      {\r
-        error = FT_Set_Charmap( t1_face, charmap );\r
-        if ( error )\r
-          goto Exit;\r
-        break;\r
-      }\r
-    }\r
-\r
-    /* Kerning info is stored as:             */\r
-    /*                                        */\r
-    /*   encoding of first glyph (1 byte)     */\r
-    /*   encoding of second glyph (1 byte)    */\r
-    /*   offset (little-endian short)         */\r
-    for ( ; p < limit ; p += 4 )\r
-    {\r
-      kp->index1 = FT_Get_Char_Index( t1_face, p[0] );\r
-      kp->index2 = FT_Get_Char_Index( t1_face, p[1] );\r
-\r
-      kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);\r
-      kp->y = 0;\r
-\r
-      kp++;\r
-    }\r
-\r
-    if ( oldcharmap != NULL )\r
-      error = FT_Set_Charmap( t1_face, oldcharmap );\r
-    if ( error )\r
-      goto Exit;\r
-\r
-    /* now, sort the kern pairs according to their glyph indices */\r
-    ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),\r
-              compare_kern_pairs );\r
-\r
-  Exit:\r
-    if ( error )\r
-    {\r
-      FT_FREE( fi->KernPairs );\r
-      fi->NumKernPair = 0;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  /* parse a metrics file -- either AFM or PFM depending on what */\r
-  /* it turns out to be                                          */\r
-  FT_LOCAL_DEF( FT_Error )\r
-  T1_Read_Metrics( FT_Face    t1_face,\r
-                   FT_Stream  stream )\r
-  {\r
-    PSAux_Service  psaux;\r
-    FT_Memory      memory = stream->memory;\r
-    AFM_ParserRec  parser;\r
-    AFM_FontInfo   fi;\r
-    FT_Error       error = T1_Err_Unknown_File_Format;\r
-    T1_Font        t1_font = &( (T1_Face)t1_face )->type1;\r
-\r
-\r
-    if ( FT_NEW( fi )                   ||\r
-         FT_FRAME_ENTER( stream->size ) )\r
-      goto Exit;\r
-\r
-    fi->FontBBox  = t1_font->font_bbox;\r
-    fi->Ascender  = t1_font->font_bbox.yMax;\r
-    fi->Descender = t1_font->font_bbox.yMin;\r
-\r
-    psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;\r
-    if ( psaux && psaux->afm_parser_funcs )\r
-    {\r
-      error = psaux->afm_parser_funcs->init( &parser,\r
-                                             stream->memory,\r
-                                             stream->cursor,\r
-                                             stream->limit );\r
-\r
-      if ( !error )\r
-      {\r
-        parser.FontInfo  = fi;\r
-        parser.get_index = t1_get_index;\r
-        parser.user_data = t1_font;\r
-\r
-        error = psaux->afm_parser_funcs->parse( &parser );\r
-        psaux->afm_parser_funcs->done( &parser );\r
-      }\r
-    }\r
-\r
-    if ( error == T1_Err_Unknown_File_Format )\r
-    {\r
-      FT_Byte*  start = stream->cursor;\r
-\r
-\r
-      /* MS Windows allows versions up to 0x3FF without complaining */\r
-      if ( stream->size > 6                              &&\r
-           start[1] < 4                                  &&\r
-           FT_PEEK_ULONG_LE( start + 2 ) == stream->size )\r
-        error = T1_Read_PFM( t1_face, stream, fi );\r
-    }\r
-\r
-    if ( !error )\r
-    {\r
-      t1_font->font_bbox = fi->FontBBox;\r
-\r
-      t1_face->bbox.xMin =   fi->FontBBox.xMin             >> 16;\r
-      t1_face->bbox.yMin =   fi->FontBBox.yMin             >> 16;\r
-      t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFFU ) >> 16;\r
-      t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFFU ) >> 16;\r
-\r
-      t1_face->ascender  = (FT_Short)( ( fi->Ascender  + 0x8000U ) >> 16 );\r
-      t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000U ) >> 16 );\r
-\r
-      if ( fi->NumKernPair )\r
-      {\r
-        t1_face->face_flags |= FT_FACE_FLAG_KERNING;\r
-        ( (T1_Face)t1_face )->afm_data = fi;\r
-        fi = NULL;\r
-      }\r
-    }\r
-\r
-    FT_FRAME_EXIT();\r
-\r
-  Exit:\r
-    if ( fi != NULL )\r
-      T1_Done_Metrics( memory, fi );\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  /* find the kerning for a given glyph pair */\r
-  FT_LOCAL_DEF( void )\r
-  T1_Get_Kerning( AFM_FontInfo  fi,\r
-                  FT_UInt       glyph1,\r
-                  FT_UInt       glyph2,\r
-                  FT_Vector*    kerning )\r
-  {\r
-    AFM_KernPair  min, mid, max;\r
-    FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );\r
-\r
-\r
-    /* simple binary search */\r
-    min = fi->KernPairs;\r
-    max = min + fi->NumKernPair - 1;\r
-\r
-    while ( min <= max )\r
-    {\r
-      FT_ULong  midi;\r
-\r
-\r
-      mid  = min + ( max - min ) / 2;\r
-      midi = KERN_INDEX( mid->index1, mid->index2 );\r
-\r
-      if ( midi == idx )\r
-      {\r
-        kerning->x = mid->x;\r
-        kerning->y = mid->y;\r
-\r
-        return;\r
-      }\r
-\r
-      if ( midi < idx )\r
-        min = mid + 1;\r
-      else\r
-        max = mid - 1;\r
-    }\r
-\r
-    kerning->x = 0;\r
-    kerning->y = 0;\r
-  }\r
-\r
-\r
-  FT_LOCAL_DEF( FT_Error )\r
-  T1_Get_Track_Kerning( FT_Face    face,\r
-                        FT_Fixed   ptsize,\r
-                        FT_Int     degree,\r
-                        FT_Fixed*  kerning )\r
-  {\r
-    AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;\r
-    FT_Int        i;\r
-\r
-\r
-    if ( !fi )\r
-      return T1_Err_Invalid_Argument;\r
-\r
-    for ( i = 0; i < fi->NumTrackKern; i++ )\r
-    {\r
-      AFM_TrackKern  tk = fi->TrackKerns + i;\r
-\r
-\r
-      if ( tk->degree != degree )\r
-        continue;\r
-\r
-      if ( ptsize < tk->min_ptsize )\r
-        *kerning = tk->min_kern;\r
-      else if ( ptsize > tk->max_ptsize )\r
-        *kerning = tk->max_kern;\r
-      else\r
-      {\r
-        *kerning = FT_MulDiv( ptsize - tk->min_ptsize,\r
-                              tk->max_kern - tk->min_kern,\r
-                              tk->max_ptsize - tk->min_ptsize ) +\r
-                   tk->min_kern;\r
-      }\r
-    }\r
-\r
-    return T1_Err_Ok;\r
-  }\r
-\r
-\r
-/* END */\r
+/***************************************************************************/
+/*                                                                         */
+/*  t1afm.c                                                                */
+/*                                                                         */
+/*    AFM support for Type 1 fonts (body).                                 */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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 "t1afm.h"
+#include "t1errors.h"
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_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_t1afm
+
+
+  FT_LOCAL_DEF( void )
+  T1_Done_Metrics( FT_Memory     memory,
+                   AFM_FontInfo  fi )
+  {
+    FT_FREE( fi->KernPairs );
+    fi->NumKernPair = 0;
+
+    FT_FREE( fi->TrackKerns );
+    fi->NumTrackKern = 0;
+
+    FT_FREE( fi );
+  }
+
+
+  /* read a glyph name and return the equivalent glyph index */
+  static FT_Int
+  t1_get_index( const char*  name,
+                FT_UInt      len,
+                void*        user_data )
+  {
+    T1_Font  type1 = (T1_Font)user_data;
+    FT_Int   n;
+
+
+    for ( n = 0; n < type1->num_glyphs; n++ )
+    {
+      char*  gname = (char*)type1->glyph_names[n];
+
+
+      if ( gname && gname[0] == name[0]        &&
+           ft_strlen( gname ) == len           &&
+           ft_strncmp( gname, name, len ) == 0 )
+        return n;
+    }
+
+    return 0;
+  }
+
+
+#undef  KERN_INDEX
+#define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )
+
+
+  /* compare two kerning pairs */
+  FT_CALLBACK_DEF( int )
+  compare_kern_pairs( const void*  a,
+                      const void*  b )
+  {
+    AFM_KernPair  pair1 = (AFM_KernPair)a;
+    AFM_KernPair  pair2 = (AFM_KernPair)b;
+
+    FT_ULong  index1 = KERN_INDEX( pair1->index1, pair1->index2 );
+    FT_ULong  index2 = KERN_INDEX( pair2->index1, pair2->index2 );
+
+
+    return (int)( index1 - index2 );
+  }
+
+
+  /* parse a PFM file -- for now, only read the kerning pairs */
+  static FT_Error
+  T1_Read_PFM( FT_Face       t1_face,
+               FT_Stream     stream,
+               AFM_FontInfo  fi )
+  {
+    FT_Error      error = T1_Err_Ok;
+    FT_Memory     memory = stream->memory;
+    FT_Byte*      start;
+    FT_Byte*      limit;
+    FT_Byte*      p;
+    AFM_KernPair  kp;
+    FT_Int        width_table_length;
+    FT_CharMap    oldcharmap;
+    FT_CharMap    charmap;
+    FT_Int        n;
+
+
+    start = (FT_Byte*)stream->cursor;
+    limit = (FT_Byte*)stream->limit;
+    p     = start;
+
+    /* Figure out how long the width table is.          */
+    /* This info is a little-endian short at offset 99. */
+    p = start + 99;
+    if ( p + 2 > limit )
+    {
+      error = T1_Err_Unknown_File_Format;
+      goto Exit;
+    }
+    width_table_length = FT_PEEK_USHORT_LE( p );
+
+    p += 18 + width_table_length;
+    if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
+      /* extension table is probably optional */
+      goto Exit;
+
+    /* Kerning offset is 14 bytes from start of extensions table. */
+    p += 14;
+    p = start + FT_PEEK_ULONG_LE( p );
+
+    if ( p == start )
+      /* zero offset means no table */
+      goto Exit;
+
+    if ( p + 2 > limit )
+    {
+      error = T1_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    fi->NumKernPair = FT_PEEK_USHORT_LE( p );
+    p += 2;
+    if ( p + 4 * fi->NumKernPair > limit )
+    {
+      error = T1_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* Actually, kerning pairs are simply optional! */
+    if ( fi->NumKernPair == 0 )
+      goto Exit;
+
+    /* allocate the pairs */
+    if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
+      goto Exit;
+
+    /* now, read each kern pair */
+    kp             = fi->KernPairs;
+    limit          = p + 4 * fi->NumKernPair;
+
+    /* PFM kerning data are stored by encoding rather than glyph index, */
+    /* so find the PostScript charmap of this font and install it       */
+    /* temporarily.  If we find no PostScript charmap, then just use    */
+    /* the default and hope it is the right one.                        */
+    oldcharmap = t1_face->charmap;
+    charmap    = NULL;
+
+    for ( n = 0; n < t1_face->num_charmaps; n++ )
+    {
+      charmap = t1_face->charmaps[n];
+      /* check against PostScript pseudo platform */
+      if ( charmap->platform_id == 7 )
+      {
+        error = FT_Set_Charmap( t1_face, charmap );
+        if ( error )
+          goto Exit;
+        break;
+      }
+    }
+
+    /* Kerning info is stored as:             */
+    /*                                        */
+    /*   encoding of first glyph (1 byte)     */
+    /*   encoding of second glyph (1 byte)    */
+    /*   offset (little-endian short)         */
+    for ( ; p < limit ; p += 4 )
+    {
+      kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
+      kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
+
+      kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
+      kp->y = 0;
+
+      kp++;
+    }
+
+    if ( oldcharmap != NULL )
+      error = FT_Set_Charmap( t1_face, oldcharmap );
+    if ( error )
+      goto Exit;
+
+    /* now, sort the kern pairs according to their glyph indices */
+    ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
+              compare_kern_pairs );
+
+  Exit:
+    if ( error )
+    {
+      FT_FREE( fi->KernPairs );
+      fi->NumKernPair = 0;
+    }
+
+    return error;
+  }
+
+
+  /* parse a metrics file -- either AFM or PFM depending on what */
+  /* it turns out to be                                          */
+  FT_LOCAL_DEF( FT_Error )
+  T1_Read_Metrics( FT_Face    t1_face,
+                   FT_Stream  stream )
+  {
+    PSAux_Service  psaux;
+    FT_Memory      memory = stream->memory;
+    AFM_ParserRec  parser;
+    AFM_FontInfo   fi;
+    FT_Error       error = T1_Err_Unknown_File_Format;
+    T1_Font        t1_font = &( (T1_Face)t1_face )->type1;
+
+
+    if ( FT_NEW( fi )                   ||
+         FT_FRAME_ENTER( stream->size ) )
+      goto Exit;
+
+    fi->FontBBox  = t1_font->font_bbox;
+    fi->Ascender  = t1_font->font_bbox.yMax;
+    fi->Descender = t1_font->font_bbox.yMin;
+
+    psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
+    if ( psaux && psaux->afm_parser_funcs )
+    {
+      error = psaux->afm_parser_funcs->init( &parser,
+                                             stream->memory,
+                                             stream->cursor,
+                                             stream->limit );
+
+      if ( !error )
+      {
+        parser.FontInfo  = fi;
+        parser.get_index = t1_get_index;
+        parser.user_data = t1_font;
+
+        error = psaux->afm_parser_funcs->parse( &parser );
+        psaux->afm_parser_funcs->done( &parser );
+      }
+    }
+
+    if ( error == T1_Err_Unknown_File_Format )
+    {
+      FT_Byte*  start = stream->cursor;
+
+
+      /* MS Windows allows versions up to 0x3FF without complaining */
+      if ( stream->size > 6                              &&
+           start[1] < 4                                  &&
+           FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
+        error = T1_Read_PFM( t1_face, stream, fi );
+    }
+
+    if ( !error )
+    {
+      t1_font->font_bbox = fi->FontBBox;
+
+      t1_face->bbox.xMin =   fi->FontBBox.xMin             >> 16;
+      t1_face->bbox.yMin =   fi->FontBBox.yMin             >> 16;
+      t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFFU ) >> 16;
+      t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFFU ) >> 16;
+
+      t1_face->ascender  = (FT_Short)( ( fi->Ascender  + 0x8000U ) >> 16 );
+      t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000U ) >> 16 );
+
+      if ( fi->NumKernPair )
+      {
+        t1_face->face_flags |= FT_FACE_FLAG_KERNING;
+        ( (T1_Face)t1_face )->afm_data = fi;
+        fi = NULL;
+      }
+    }
+
+    FT_FRAME_EXIT();
+
+  Exit:
+    if ( fi != NULL )
+      T1_Done_Metrics( memory, fi );
+
+    return error;
+  }
+
+
+  /* find the kerning for a given glyph pair */
+  FT_LOCAL_DEF( void )
+  T1_Get_Kerning( AFM_FontInfo  fi,
+                  FT_UInt       glyph1,
+                  FT_UInt       glyph2,
+                  FT_Vector*    kerning )
+  {
+    AFM_KernPair  min, mid, max;
+    FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );
+
+
+    /* simple binary search */
+    min = fi->KernPairs;
+    max = min + fi->NumKernPair - 1;
+
+    while ( min <= max )
+    {
+      FT_ULong  midi;
+
+
+      mid  = min + ( max - min ) / 2;
+      midi = KERN_INDEX( mid->index1, mid->index2 );
+
+      if ( midi == idx )
+      {
+        kerning->x = mid->x;
+        kerning->y = mid->y;
+
+        return;
+      }
+
+      if ( midi < idx )
+        min = mid + 1;
+      else
+        max = mid - 1;
+    }
+
+    kerning->x = 0;
+    kerning->y = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Get_Track_Kerning( FT_Face    face,
+                        FT_Fixed   ptsize,
+                        FT_Int     degree,
+                        FT_Fixed*  kerning )
+  {
+    AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
+    FT_Int        i;
+
+
+    if ( !fi )
+      return T1_Err_Invalid_Argument;
+
+    for ( i = 0; i < fi->NumTrackKern; i++ )
+    {
+      AFM_TrackKern  tk = fi->TrackKerns + i;
+
+
+      if ( tk->degree != degree )
+        continue;
+
+      if ( ptsize < tk->min_ptsize )
+        *kerning = tk->min_kern;
+      else if ( ptsize > tk->max_ptsize )
+        *kerning = tk->max_kern;
+      else
+      {
+        *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
+                              tk->max_kern - tk->min_kern,
+                              tk->max_ptsize - tk->min_ptsize ) +
+                   tk->min_kern;
+      }
+    }
+
+    return T1_Err_Ok;
+  }
+
+
+/* END */