shithub: freetype+ttf2subf

Download patch

ref: ff9d2415a7a192520ea198187dbdb6408625e210
parent: 03f06f0f08f1ad864261a5e5644862ef654506d4
author: David Turner <[email protected]>
date: Sun Nov 23 16:39:51 EST 2003

* src/autofit/*: more updates

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2003-11-22  David Turner    <[email protected]>
+
+        * src/autofit/*: more updates
+
 2003-11-13  John A. Boyd Jr.  <[email protected]>
 
 	* src/bdf/bdfdrivr.c (bdf_interpret_style), src/pcf/pcfread.c
--- a/README
+++ b/README
@@ -9,7 +9,7 @@
   is called `libttf'.  They are *not* compatible!
 
 
-  FreeType 2.1.7
+  FreeType 2.1.8
   ==============
 
   Please read the docs/CHANGES file, it contains IMPORTANT INFORMATION.
@@ -19,9 +19,9 @@
   Note  that  the FreeType  2  documentation  is  now available  as  a
   separate package from our sites.  See:
 
-    ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.7.tar.bz2
-    ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.7.tar.gz
-    ftp://ftp.freetype.org/pub/freetype2/ftdoc216.zip
+    ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.8.tar.bz2
+    ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.8.tar.gz
+    ftp://ftp.freetype.org/pub/freetype2/ftdoc218.zip
 
 
   Bugs
--- a/builds/unix/configure.ac
+++ b/builds/unix/configure.ac
@@ -8,7 +8,7 @@
 
 # Don't forget to update docs/VERSION.DLL!
 
-version_info='9:5:3'
+version_info='9:6:3'
 AC_SUBST([version_info])
 ft_version=`echo $version_info | tr : .`
 AC_SUBST([ft_version])
--- a/docs/VERSION.DLL
+++ b/docs/VERSION.DLL
@@ -52,6 +52,7 @@
 
     release    libtool      so
   -------------------------------
+     2.1.8      9.6.3     6.3.6
      2.1.7      9.5.3     6.3.5
      2.1.6      9.5.3     6.3.5
      2.1.5      9.4.3     6.3.4
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -44,7 +44,7 @@
   /*                                                                       */
 #define FREETYPE_MAJOR 2
 #define FREETYPE_MINOR 1
-#define FREETYPE_PATCH 7
+#define FREETYPE_PATCH 8
 
 
 #include <ft2build.h>
--- a/src/autofit/afangles.c
+++ b/src/autofit/afangles.c
@@ -9,6 +9,7 @@
     90, 64, 38, 20, 10, 5, 3, 1, 1 
   };
 
+
   static FT_Int
   af_angle_prenorm( FT_Vector*  vec )
   {
@@ -162,3 +163,29 @@
     return delta;
   }                 
 
+ 
+ /* well, this needs to be somewhere, right :-)
+  */
+
+  FT_LOCAL_DEF( void )
+  af_sort_pos( FT_UInt   count,
+               FT_Pos*   table )
+  {
+    FT_Int  i, j;
+    FT_Pos  swap;
+
+
+    for ( i = 1; i < count; i++ )
+    {
+      for ( j = i; j > 0; j-- )
+      {
+        if ( table[j] > table[j - 1] )
+          break;
+
+        swap         = table[j];
+        table[j]     = table[j - 1];
+        table[j - 1] = swap;
+      }
+    }
+  }               
+ 
\ No newline at end of file
--- /dev/null
+++ b/src/autofit/afglobal.c
@@ -1,0 +1,231 @@
+#include "afglobal.h"
+#include "aflatin.h"
+
+ /* populate this list when you add new scripts
+  */
+  static AF_ScriptClass const   af_script_class_list[] =
+  {
+    & af_latin_script_class,
+
+    NULL  /* do not remove */
+  };
+
+#define AF_SCRIPT_LIST_DEFAULT   0    /* index of default script in 'af_script_class_list' */
+#define AF_SCRIPT_LIST_NONE      255  /* indicates an uncovered glyph                      */
+
+ /*
+  *  note that glyph_scripts[] is used to map each glyph into
+  *  an index into the 'af_script_class_list' array.
+  *
+  */
+  typedef struct AF_FaceGlobalsRec_
+  {
+    FT_Face            face;
+    FT_UInt            glyph_count;    /* same as face->num_glyphs     */
+    FT_Byte*           glyph_scripts;
+
+    AF_ScriptMetrics   metrics[ AF_SCRIPT_MAX ];
+
+  } AF_FaceGlobalsRec, *AF_FaceGlobals;
+
+
+
+
+ /* this function is used to compute the script index of each glyph
+  * within a given face
+  */
+  static FT_Error
+  af_face_globals_compute_script_coverage( AF_FaceGlobals  globals )
+  {
+    FT_Error    error       = 0;
+    FT_Face     face        = globals->face;
+    FT_CharMap  old_charmap = face->charmap;
+    FT_Byte*    gscripts    = globals->glyph_scripts;
+    FT_UInt     ss;
+
+   /* the value 255 means "uncovered glyph"
+    */
+    FT_MEM_SET( globals->glyph_scripts,
+                AF_SCRIPT_LIST_NONE,
+                globals->glyph_count );
+
+    error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+    if ( error )
+    {
+     /* ignore this error, we'll simply use Latin as the standard
+      * script. XXX: Shouldn't we rather disable hinting ??
+      */
+      error = 0;
+      goto Exit;
+    }
+
+   /* scan each script in a Unicode charmap
+    */
+    for ( ss = 0; af_script_classes[ss]; ss++ )
+    {
+      AF_ScriptClass      clazz = af_script_classes[ss];
+      AF_Script_UniRange  range;
+
+     /* scan all unicode points in the range, and set the corresponding
+      * glyph script index
+      */
+      for ( range = clazz->script_uni_ranges; range->first != 0; range++ )
+      {
+        FT_ULong  charcode = range->first;
+        FT_UInt   gindex;
+
+        gindex = FT_Get_Char_Index( face, charcode );
+
+        if ( gindex != 0                               &&
+             gindex < globals->glyph_count             &&
+             gscripts[ gindex ] == AF_SCRIPT_LIST_NONE )
+        {
+          gscripts[ gindex ] = (FT_Byte) ss;
+        }
+        for (;;)
+        {
+          charcode = FT_Get_Next_Char( face, charcode, &gindex );
+
+          if ( gindex == 0 || charcode > range->last )
+            break;
+
+          if ( gindex < globals->glyph_count       &&
+               gscripts[ gindex ] == AF_SCRIPT_LIST_NONE )
+          {
+            gscripts[ gindex ] = (FT_Byte) ss;
+          }
+        }
+      }
+    }
+
+  Exit:
+   /* by default, all uncovered glyphs are set to the latin script
+    * XXX: shouldnt' we disable hinting or do something similar ?
+    */
+    {
+      FT_UInt  nn;
+
+      for ( nn = 0; nn < globals->glyph_count; nn++ )
+      {
+        if ( gscripts[ nn ] == AF_SCRIPT_LIST_NONE )
+          gscripts[ nn ] = AF_SCRIPT_LIST_DEFAULT;
+      }
+    }
+
+    FT_Set_Charmap( face, old_charmap );
+    return error;
+  }
+
+
+
+  FT_LOCAL_DEF( FT_Error )
+  af_face_globals_new( FT_Face          face,
+                       AF_FaceGlobals  *aglobals )
+  {
+    FT_Error        error;
+    FT_Memory       memory;
+    AF_FaceGlobals  globals;
+
+    memory = face->memory;
+
+    if ( !FT_ALLOC( globals, sizeof(*globals) +
+                             face->num_glyphs*sizeof(FT_Byte) ) )
+    {
+      globals->face          = face;
+      globals->glyph_count   = face->num_glyphs;
+      globals->glyph_scripts = (FT_Byte*)( globals+1 );
+
+      error = af_face_globals_compute_script_coverage( globals );
+      if ( error )
+      {
+        af_face_globals_free( globals );
+        globals = NULL;
+      }
+    }
+
+  Exit:
+    *aglobals = globals;
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  af_face_globals_free( AF_FaceGlobals  globals )
+  {
+    if ( globals )
+    {
+      FT_Memory  memory = globals->face->memory;
+      FT_UInt    nn;
+
+      for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
+      {
+        if ( globals->metrics[nn] )
+        {
+          AF_ScriptClass  clazz = af_script_classes[nn];
+
+          FT_ASSERT( globals->metrics[nn].clazz == clazz );
+
+          if ( clazz->script_metrics_done )
+            clazz->script_metrics_done( globals->metrics[nn] );
+
+          FT_FREE( globals->metrics[nn] );
+        }
+      }
+
+      globals->glyph_count   = NULL;
+      globals->glyph_scripts = NULL;  /* no need to free this one !! */
+      globals->face          = NULL;
+      FT_FREE( globals );
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  af_face_globals_get_metrics( AF_FaceGlobals     globals,
+                               FT_UInt            gindex,
+                               AF_ScriptMetrics  *ametrics )
+  {
+    FT_Script         script;
+    AF_ScriptMetrics  metrics = NULL;
+    FT_UInt           index;
+    AF_ScriptClass    clazz;
+    FT_Error          error;
+
+    if ( gindex >= globals->glyph_count )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    index   = globals->glyph_scripts[ gindex ];
+    clazz   = af_script_class_list[ index ];
+    metrics = globals->metrics[ clazz->script ];
+    if ( metrics == NULL )
+    {
+     /* create the global metrics object when needed
+      */
+      if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
+        goto Exit;
+
+      metrics->clazz = clazz;
+
+      if ( clazz->script_metrics_init )
+      {
+        error = clazz->script_metrics_init( metrics, face );
+        if ( error )
+        {
+          if ( clazz->script_metrics_done )
+            clazz->script_metrics_done( metrics );
+
+          FT_FREE( metrics );
+          goto Exit;
+        }
+      }
+
+      globals->metrics[ script ] = metrics;
+    }
+
+  Exit:
+    *ametrics = metrics;
+    return error;
+  }
--- /dev/null
+++ b/src/autofit/afglobal.h
@@ -1,0 +1,42 @@
+#ifndef __AF_GLOBAL_H__
+#define __AF_GLOBAL_H__
+
+#include "aftypes.h"
+
+FT_BEGIN_HEADER
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /*****                                                                *****/
+ /*****                F A C E   G L O B A L S                         *****/
+ /*****                                                                *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+ /*
+  *  models the global hints data for a given face, decomposed into
+  *  script-specific items..
+  *
+  */
+  typedef struct AF_FaceGlobalsRec_*   AF_FaceGlobals;
+  
+
+  FT_LOCAL( FT_Error )
+  af_face_globals_new( FT_Face          face,
+                       AF_FaceGlobals  *aglobals );
+
+
+  FT_LOCAL( FT_Error )
+  af_face_globals_get_metrics( AF_FaceGlobals     globals,
+                               FT_UInt            gindex,
+                               AF_ScriptMetrics  *ametrics );
+
+  FT_LOCAL( void )
+  af_face_globals_free( AF_FaceGlobals  globals );
+
+ /* */
+ 
+FT_END_HEADER
+
+#endif /* __AF_GLOBALS_H__ */
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -5,7 +5,7 @@
 #include <stdio.h>
 
   void
-  af_outline_hints_dump_edges( AF_OutlineHints  hints )
+  af_glyph_hints_dump_edges( AF_GlyphHints  hints )
   {
     AF_Edge     edges;
     AF_Edge     edge_limit;
@@ -57,7 +57,7 @@
 
   /* A function used to dump the array of linked segments */
   void
-  af_outline_hints_dump_segments( AF_OutlineHints  hints )
+  af_glyph_hints_dump_segments( AF_GlyphHints  hints )
   {
     AF_Segment  segments;
     AF_Segment  segment_limit;
@@ -139,15 +139,12 @@
 
   /* compute all inflex points in a given glyph */
   static void
-  af_outline_hints_compute_inflections( AF_OutlineHints  hints )
+  af_glyph_hints_compute_inflections( AF_GlyphHints  hints )
   {
     AF_Point*  contour       = hints->contours;
     AF_Point*  contour_limit = contour + hints->num_contours;
 
 
-    /* load original coordinates in (u,v) */
-    af_outline_hints_setup_uv( hints, outline, AF_UV_FXY );
-
     /* do each contour separately */
     for ( ; contour < contour_limit; contour++ )
     {
@@ -172,10 +169,10 @@
         if ( end == first )
           goto Skip;
 
-      } while ( end->u == first->u && end->v == first->v );
+      } while ( end->fx == first->fx && end->fy == first->fy );
 
-      angle_seg = af_angle( end->u - start->u, 
-                            end->v - start->v );
+      angle_seg = af_angle( end->fx - start->fx,
+                            end->fy - start->fy );
 
       /* extend the segment start whenever possible */
       before = start;
@@ -188,10 +185,10 @@
           if ( before == first )
             goto Skip;
 
-        } while ( before->u == start->u && before->v == start->v );
+        } while ( before->fx == start->fx && before->fy == start->fy );
 
-        angle_in = af_angle( start->u - before->u, 
-                             start->v - before->v );
+        angle_in = af_angle( start->fx - before->fx,
+                             start->fy - before->fy );
 
       } while ( angle_in == angle_seg );
 
@@ -212,12 +209,12 @@
             if ( after == first )
               finished = 1;
 
-          } while ( end->u == after->u && end->v == after->v );
+          } while ( end->fx == after->fx && end->fy == after->fy );
 
-          vec.x     = after->u - end->u;
-          vec.y     = after->v - end->v;
-          angle_out = af_angle( after->u - end->u,
-                                after->v - end->v );
+          vec.x     = after->fx - end->fx;
+          vec.y     = after->fy - end->fy;
+          angle_out = af_angle( after->fx - end->fx,
+                                after->fy - end->fy );
 
         } while ( angle_out == angle_seg );
 
@@ -252,17 +249,17 @@
 
 
   FT_LOCAL_DEF( void )
-  af_outline_hints_init( AF_OutlineHints  hints,
-                         FT_Memory        memory )
+  af_glyph_hints_init( AF_GlyphHints  hints,
+                       FT_Memory      memory )
   {
     FT_ZERO( hints );
     hints->memory = memory;
-  }                         
+  }
 
 
 
   FT_LOCAL_DEF( void )
-  af_outline_hints_done( AF_OutlineHints  hints )
+  af_glyph_hints_done( AF_GlyphHints  hints )
   {
     if ( hints && hints->memory )
     {
@@ -275,7 +272,7 @@
       for ( dim = 0; dim < 2; dim++ )
       {
         AF_AxisHints  axis = &hints->axis[ dim ];
-        
+
         axis->num_segments = 0;
         axis->num_edges    = 0;
         axis->segments     = NULL;
@@ -285,11 +282,11 @@
       FT_FREE( hints->contours );
       hints->max_contours = 0;
       hints->num_contours = 0;
-      
+
       FT_FREE( hints->points );
       hints->num_points = 0;
       hints->max_points = 0;
-      
+
       hints->memory = NULL;
     }
   }
@@ -297,23 +294,25 @@
 
 
   FT_LOCAL_DEF( FT_Error )
-  af_outline_hints_reset( AF_OutlineHints  hints,
-                          FT_Outline*      outline,
-                          FT_Fixed         x_scale,
-                          FT_Fixed         y_scale )
+  af_glyph_hints_reset( AF_GlyphHints  hints,
+                        FT_Outline*    outline,
+                        FT_Fixed       x_scale,
+                        FT_Fixed       y_scale,
+                        FT_Pos         x_delta,
+                        FT_Pos         y_delta )
   {
     FT_Error     error        = AF_Err_Ok;
-    
+
     FT_UInt      old_max, new_max;
 
     hints->num_points    = 0;
     hints->num_contours  = 0;
-    
+
     hints->axis[0].num_segments = 0;
     hints->axis[0].num_edges    = 0;
     hints->axis[1].num_segments = 0;
     hints->axis[1].num_edges    = 0;
-    
+
    /* first of all, reallocate the contours array when necessary
     */
     new_max = (FT_UInt) outline->n_contours;
@@ -321,17 +320,17 @@
     if ( new_max > old_max )
     {
       new_max = (new_max + 3) & ~3;
-      
+
       if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
         goto Exit;
-      
+
       hints->max_contours = new_max;
     }
 
-   /* then, reallocate the points, segments & edges arrays if needed --   
-    * note that we reserved two additional point positions, used to       
-    * hint metrics appropriately                                          
-    */                                                                    
+   /* then, reallocate the points, segments & edges arrays if needed --
+    * note that we reserved two additional point positions, used to
+    * hint metrics appropriately
+    */
     new_max = (FT_UInt)( outline->n_points + 2 );
     old_max = hints->max_points;
     if ( new_max > old_max )
@@ -338,17 +337,17 @@
     {
       FT_Byte*    items;
       FT_ULong    off1, off2, off3;
-      
+
      /* we store in a single buffer the following arrays:
       *
       *  - an array of   N  AF_PointRec   items
       *  - an array of 2*N  AF_SegmentRec items
-      *  - an array of 2*N  AF_EdgeRec    items 
+      *  - an array of 2*N  AF_EdgeRec    items
       *
       */
-      
+
       new_max = ( new_max + 2 + 7 ) & ~7;
-      
+
 #undef  OFF_INCREMENT
 #define OFF_INCREMENT( _off, _type, _count )   \
      ((((_off) + sizeof(_type)) & ~(sizeof(_type)) + ((_count)*sizeof(_type)))
@@ -368,15 +367,15 @@
         hints->axis[1].edges    = NULL;
         goto Exit;
       }
-      
+
      /* readjust some pointers
       */
       hints->max_points       = new_max;
       hints->points           = (AF_Point) items;
-      
+
       hints->axis[0].segments = (AF_Segment)( items + off1 );
       hints->axis[1].segments = hints->axis[0].segments + new_max;
-      
+
       hints->axis[0].edges    = (AF_Edge)   ( items + off2 );
       hints->axis[1].edges    = hints->axis[0].edges + new_max;
     }
@@ -422,8 +421,8 @@
         {
           point->fx = vec->x;
           point->fy = vec->y;
-          point->ox = point->x = FT_MulFix( vec->x, x_scale );
-          point->oy = point->y = FT_MulFix( vec->y, y_scale );
+          point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
+          point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
 
           switch ( FT_CURVE_TAG( *tag ) )
           {
@@ -503,7 +502,7 @@
           prev   = point->prev;
           in_x   = point->fx - prev->fx;
           in_y   = point->fy - prev->fy;
-          
+
           point->in_dir = af_compute_direction( in_x, in_y );
 
           next   = point->next;
@@ -539,8 +538,8 @@
     }
 
    /* compute inflection points
-    */    
-    af_outline_hints_compute_inflections( hints );
+    */
+    af_glyph_hints_compute_inflections( hints );
 
   Exit:
     return error;
@@ -547,80 +546,392 @@
   }
 
 
+
+
+ /*
+  *
+  *  E D G E   P O I N T   G R I D - F I T T I N G
+  *
+  */
+
+
   FT_LOCAL_DEF( void )
-  af_outline_hints_setup_uv( AF_OutlineHints  hints,
-                             AF_UV            source )
+  af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
+                                    AF_Dimension   dim )
   {
-    AF_Point  point       = hints->points;
-    AF_Point  point_limit = point + hints->num_points;
+    AF_AxisHints  axis       = & hints->axis[ dim ];
+    AF_Edge       edges      = axis->edges;
+    AF_Edge       edge_limit = edges + axis->num_edges;
+    AF_Edge       edge;
 
-
-    switch ( source )
+    for ( edge = edges; edge < edge_limit; edge++ )
     {
-    case AF_UV_FXY:
-      for ( ; point < point_limit; point++ )
+      /* move the points of each segment     */
+      /* in each edge to the edge's position */
+      AF_Segment  seg = edge->first;
+
+
+      do
       {
-        point->u = point->fx;
-        point->v = point->fy;
-      }
-      break;
+        AF_Point  point = seg->first;
 
-    case AF_UV_FYX:
-      for ( ; point < point_limit; point++ )
+
+        for (;;)
+        {
+          if ( dim == AF_DIMENSION_HORZ )
+          {
+            point->x      = edge->pos;
+            point->flags |= AF_FLAG_TOUCH_X;
+          }
+          else
+          {
+            point->y      = edge->pos;
+            point->flags |= AF_FLAG_TOUCH_Y;
+          }
+
+          if ( point == seg->last )
+            break;
+
+          point = point->next;
+        }
+
+        seg = seg->edge_next;
+
+      } while ( seg != edge->first );
+    }
+  }
+
+
+ /*
+  *
+  *  S T R O N G   P O I N T   I N T E R P O L A T I O N
+  *
+  */
+
+
+  /* hint the strong points -- this is equivalent to the TrueType `IP' */
+  /* hinting instruction                                               */
+  FT_LOCAL_DEF( void )
+  af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
+                                      AF_Dimension   dim )
+  {
+    AF_Point      points      = hints->points;
+    AF_Point      point_limit = points + hints->num_points;;
+    AF_AxisHints  axis        = &hints->axis[dim];
+    AF_Edge       edges       = axis->edges;
+    AF_Edge       edge_limit  = edges + axis->num_edges;
+    AF_Flags      touch_flag;
+    AF_Point      point;
+    AF_Edge       edge;
+
+
+    if ( dim == AF_DIMENSION_HORZ )
+      touch_flag = AF_FLAG_TOUCH_X;
+    else
+      touch_flag  = AF_FLAG_TOUCH_Y;
+
+    if ( edges < edge_limit )
+    {
+      AF_Point  point;
+      AF_Edge   edge;
+
+      for ( point = points; point < point_limit; point++ )
       {
-        point->u = point->fy;
-        point->v = point->fx;
+        FT_Pos  u, ou, fu;  /* point position */
+        FT_Pos  delta;
+
+
+        if ( point->flags & touch_flag )
+          continue;
+
+        /* if this point is candidate to weak interpolation, we will  */
+        /* interpolate it after all strong points have been processed */
+        if (  ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
+             !( point->flags & AF_FLAG_INFLECTION )         )
+          continue;
+
+        if ( dimension )
+        {
+          u  = point->fy;
+          ou = point->oy;
+        }
+        else
+        {
+          u  = point->fx;
+          ou = point->ox;
+        }
+
+        fu = u;
+
+        /* is the point before the first edge? */
+        edge  = edges;
+        delta = edge->fpos - u;
+        if ( delta >= 0 )
+        {
+          u = edge->pos - ( edge->opos - ou );
+          goto Store_Point;
+        }
+
+        /* is the point after the last edge? */
+        edge  = edge_limit - 1;
+        delta = u - edge->fpos;
+        if ( delta >= 0 )
+        {
+          u = edge->pos + ( ou - edge->opos );
+          goto Store_Point;
+        }
+
+        {
+          FT_UInt  min, max, mid;
+          FT_Pos   fpos;
+
+
+          /* find enclosing edges */
+          min = 0;
+          max = edge_limit - edges;
+
+          while ( min < max )
+          {
+            mid  = ( max + min ) >> 1;
+            edge = edges + mid;
+            fpos = edge->fpos;
+
+            if ( u < fpos )
+              max = mid;
+            else if ( u > fpos )
+              min = mid + 1;
+            else
+            {
+              /* we are on the edge */
+              u = edge->pos;
+              goto Store_Point;
+            }
+          }
+
+          {
+            AF_Edge  before = edges + min - 1;
+            AF_Edge  after  = edges + min + 0;
+
+
+            /* assert( before && after && before != after ) */
+            if ( before->scale == 0 )
+              before->scale = FT_DivFix( after->pos - before->pos,
+                                         after->fpos - before->fpos );
+
+            u = before->pos + FT_MulFix( fu - before->fpos,
+                                         before->scale );
+          }
+        }
+
+
+      Store_Point:
+
+        /* save the point position */
+        if ( dim == AF_DIMENSION_HORZ )
+          point->x = u;
+        else
+          point->y = u;
+
+        point->flags |= touch_flag;
       }
-      break;
+    }
+  }
 
-    case AF_UV_OXY:
-      for ( ; point < point_limit; point++ )
+
+ /*
+  *
+  *  W E A K   P O I N T   I N T E R P O L A T I O N
+  *
+  */
+
+  static void
+  af_iup_shift( AF_Point  p1,
+                AF_Point  p2,
+                AF_Point  ref )
+  {
+    AF_Point  p;
+    FT_Pos    delta = ref->u - ref->v;
+
+
+    for ( p = p1; p < ref; p++ )
+      p->u = p->v + delta;
+
+    for ( p = ref + 1; p <= p2; p++ )
+      p->u = p->v + delta;
+  }
+
+
+  static void
+  af_iup_interp( AF_Point  p1,
+                 AF_Point  p2,
+                 AF_Point  ref1,
+                 AF_Point  ref2 )
+  {
+    AF_Point  p;
+    FT_Pos    u;
+    FT_Pos    v1 = ref1->v;
+    FT_Pos    v2 = ref2->v;
+    FT_Pos    d1 = ref1->u - v1;
+    FT_Pos    d2 = ref2->u - v2;
+
+
+    if ( p1 > p2 )
+      return;
+
+    if ( v1 == v2 )
+    {
+      for ( p = p1; p <= p2; p++ )
       {
-        point->u = point->ox;
-        point->v = point->oy;
+        u = p->v;
+
+        if ( u <= v1 )
+          u += d1;
+        else
+          u += d2;
+
+        p->u = u;
       }
-      break;
+      return;
+    }
 
-    case AF_UV_OYX:
-      for ( ; point < point_limit; point++ )
+    if ( v1 < v2 )
+    {
+      for ( p = p1; p <= p2; p++ )
       {
-        point->u = point->oy;
-        point->v = point->ox;
-      }
-      break;
+        u = p->v;
 
-    case AF_UV_YX:
-      for ( ; point < point_limit; point++ )
+        if ( u <= v1 )
+          u += d1;
+        else if ( u >= v2 )
+          u += d2;
+        else
+          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+        p->u = u;
+      }
+    }
+    else
+    {
+      for ( p = p1; p <= p2; p++ )
       {
-        point->u = point->y;
-        point->v = point->x;
+        u = p->v;
+
+        if ( u <= v2 )
+          u += d2;
+        else if ( u >= v1 )
+          u += d1;
+        else
+          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+        p->u = u;
       }
-      break;
+    }
+  }
 
-    case AF_UV_OX:
-      for ( ; point < point_limit; point++ )
+
+  FT_LOCAL_DEF( void )
+  af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
+                                    AF_Dimension   dim )
+  {
+    AF_Point    points        = hints->points;
+    AF_Point    point_limit   = points + hints->num_points;
+    AF_Point*   contour       = hints->contours;
+    AF_Point*   contour_limit = contour + hints->num_contours;
+    AF_Flags    touch_flag;
+    AF_Point    point;
+    AF_Point    end_point;
+    AF_Point    first_point;
+
+
+    /* PASS 1: Move segment points to edge positions */
+
+    if ( dim == AF_DIMENSION_HORZ )
+    {
+      touch_flag = AF_FLAG_TOUCH_X;
+
+      for ( point = points; point < point_limit; point++ )
       {
         point->u = point->x;
         point->v = point->ox;
       }
-      break;
+    }
+    else
+    {
+      touch_flag = AF_FLAG_TOUCH_Y;
 
-    case AF_UV_OY:
-      for ( ; point < point_limit; point++ )
+      for ( point = points; point < point_limit; points++ )
       {
         point->u = point->y;
         point->v = point->oy;
       }
-      break;
+    }
 
-    default:
-      for ( ; point < point_limit; point++ )
+    point   = points;
+
+    for ( ; contour < contour_limit; contour++ )
+    {
+      point       = *contour;
+      end_point   = point->prev;
+      first_point = point;
+
+      while ( point <= end_point && !( point->flags & touch_flag ) )
+        point++;
+
+      if ( point <= end_point )
       {
-        point->u = point->x;
-        point->v = point->y;
+        AF_Point  first_touched = point;
+        AF_Point  cur_touched   = point;
+
+
+        point++;
+        while ( point <= end_point )
+        {
+          if ( point->flags & touch_flag )
+          {
+            /* we found two successive touched points; we interpolate */
+            /* all contour points between them                        */
+            af_iup_interp( cur_touched + 1, point - 1,
+                           cur_touched, point );
+            cur_touched = point;
+          }
+          point++;
+        }
+
+        if ( cur_touched == first_touched )
+        {
+          /* this is a special case: only one point was touched in the */
+          /* contour; we thus simply shift the whole contour           */
+          af_iup_shift( first_point, end_point, cur_touched );
+        }
+        else
+        {
+          /* now interpolate after the last touched point to the end */
+          /* of the contour                                          */
+          af_iup_interp( cur_touched + 1, end_point,
+                         cur_touched, first_touched );
+
+          /* if the first contour point isn't touched, interpolate */
+          /* from the contour start to the first touched point     */
+          if ( first_touched > points )
+            af_iup_interp( first_point, first_touched - 1,
+                           cur_touched, first_touched );
+        }
       }
     }
+
+    /* now save the interpolated values back to x/y */
+    if ( dim == AF_DIMENSION_HORZ )
+    {
+      for ( point = points; point < point_limit; point++ )
+        point->x = point->u;
+    }
+    else
+    {
+      for ( point = points; point < point_limit; point++ )
+        point->y = point->u;
+    }
   }
+
 
 
 
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -6,8 +6,8 @@
 FT_BEGIN_HEADER
 
  /*
-  *  The definition of outline hints. These are shared by all
-  *  script analysis routines
+  *  The definition of outline glyph hints. These are shared by all
+  *  script analysis routines (until now)
   *
   */
 
@@ -17,7 +17,7 @@
     AF_DIMENSION_VERT = 1,  /* y coordinates, i.e. horizontal segments & edges */
 
     AF_DIMENSION_MAX  /* do not remove */
-  
+
   } AF_Dimension;
 
 
@@ -30,7 +30,7 @@
     AF_DIR_LEFT  = -1,
     AF_DIR_UP    =  2,
     AF_DIR_DOWN  = -2
-    
+
   } AF_Direction;
 
 
@@ -38,33 +38,33 @@
   typedef enum
   {
     AF_FLAG_NONE    = 0,
-    
+
    /* point type flags */
     AF_FLAG_CONIC   = (1 << 0),
     AF_FLAG_CUBIC   = (1 << 1),
     AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC,
-    
+
    /* point extremum flags */
     AF_FLAG_EXTREMA_X = (1 << 2),
     AF_FLAG_EXTREMA_Y = (1 << 3),
-    
+
    /* point roundness flags */
     AF_FLAG_ROUND_X = (1 << 4),
     AF_FLAG_ROUND_Y = (1 << 5),
-    
+
    /* point touch flags */
     AF_FLAG_TOUCH_X = (1 << 6),
     AF_FLAG_TOUCH_Y = (1 << 7),
-    
+
    /* candidates for weak interpolation have this flag set */
     AF_FLAG_WEAK_INTERPOLATION = (1 << 8),
-    
+
    /* all inflection points in the outline have this flag set */
     AF_FLAG_INFLECTION         = (1 << 9)
-  
+
   } AF_Flags;
-  
 
+
   /* edge hint flags */
   typedef enum
   {
@@ -72,7 +72,7 @@
     AF_EDGE_ROUND  = (1 << 0),
     AF_EDGE_SERIF  = (1 << 1),
     AF_EDGE_DONE   = (1 << 2)
-  
+
   } AF_Edge_Flags;
 
 
@@ -110,10 +110,10 @@
     AF_Edge        edge;        /* the segment's parent edge */
     AF_Segment     edge_next;   /* link to next segment in parent edge */
 
-    AF_Segment     link;        /* link segment               */
+    AF_Segment     link;        /* (stem) link segment        */
     AF_Segment     serif;       /* primary segment for serifs */
     FT_Pos         num_linked;  /* number of linked segments  */
-    FT_Pos         score;
+    FT_Pos         score;       /* used during stem matching  */
 
     AF_Point       first;       /* first point in edge segment             */
     AF_Point       last;        /* last point in edge segment              */
@@ -131,7 +131,7 @@
     AF_Edge_Flags  flags;      /* edge flags */
     AF_Direction   dir;        /* edge direction */
     FT_Fixed       scale;      /* used to speed up interpolation between edges */
-    FT_Pos*        blue_edge;  /* non-NULL if this is a blue edge              */
+    AF_Width       blue_edge;  /* non-NULL if this is a blue edge              */
 
     AF_Edge        link;
     AF_Edge        serif;
@@ -142,7 +142,6 @@
     AF_Segment     first;
     AF_Segment     last;
 
-
   } AF_EdgeRec;
 
 
@@ -150,7 +149,7 @@
   {
     FT_Int        num_segments;
     AF_Segment    segments;
-  
+
     FT_Int        num_edges;
     AF_Edge       edges;
 
@@ -158,8 +157,8 @@
 
   } AF_AxisHintsRec, *AF_AxisHints;
 
-  
-  typedef struct AF_OutlineHintsRec_
+
+  typedef struct AF_GlyphHintsRec_
   {
     FT_Memory     memory;
 
@@ -177,7 +176,7 @@
 
     AF_AxisHintsRec  axis[ AF_DIMENSION_MAX ];
 
-  } AF_OutlineHintsRec;
+  } AF_GlyphHintsRec;
 
 
 
@@ -188,43 +187,36 @@
 
 
   FT_LOCAL( void )
-  af_outline_hints_init( AF_OutlineHints  hints );
+  af_glyph_hints_init( AF_GlyphHints  hints,
+                       FT_Memory      memory );
 
 
- /*  used to set the (u,v) fields of each AF_Point in a AF_OutlineHints
-  *  object.
-  */
-  typedef enum  AH_UV_
-  {
-    AH_UV_FXY,  /* (u,v) = (fx,fy) */
-    AH_UV_FYX,  /* (u,v) = (fy,fx) */
-    AH_UV_OXY,  /* (u,v) = (ox,oy) */
-    AH_UV_OYX,  /* (u,v) = (oy,ox) */
-    AH_UV_OX,   /* (u,v) = (ox,x)  */
-    AH_UV_OY,   /* (u,v) = (oy,y)  */
-    AH_UV_YX,   /* (u,v) = (y,x)   */
-    AH_UV_XY    /* (u,v) = (x,y)   *   should always be last! */
 
-  } AH_UV;
-
-  FT_LOCAL_DEF( void )
-  af_outline_hints_setup_uv( AF_OutlineHints  hints,
-                             AF_UV            source );
-
-
- /*  recomputes all AF_Point in a AF_OutlineHints from the definitions
+ /*  recomputes all AF_Point in a AF_GlyphHints from the definitions
   *  in a source outline
   */
   FT_LOCAL( FT_Error )
-  af_outline_hints_reset( AF_OutlineHints  hints,
-                          FT_Outline*      outline,
-                          FT_Fixed         x_scale,
-                          FT_Fixed         y_scale );
+  af_glyph_hints_reset( AF_GlyphHints  hints,
+                        FT_Outline*    outline,
+                        FT_Fixed       x_scale,
+                        FT_Fixed       y_scale,
+                        FT_Pos         x_delta,
+                        FT_Pos         y_delta );
 
   FT_LOCAL( void )
-  af_outline_hints_done( AF_OutlineHints  hints );
+  af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
+                                    AF_Dimension   dim );
 
+  FT_LOCAL( void )
+  af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
+                                      AF_Dimension   dim );
 
+  FT_LOCAL( void )
+  af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
+                                    AF_Dimension   dim );
+
+  FT_LOCAL( void )
+  af_glyph_hints_done( AF_GlyphHints  hints );
 
 /* */
 
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -1,9 +1,439 @@
 #include "aflatin.h"
 
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****       L A T I N   G L O B A L   M E T R I C S                   *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  static void
+  af_latin_metrics_init_widths( AF_LatinMetrics  metrics,
+                                FT_Face          face )
+  {
+    /* scan the array of segments in each direction */
+    AF_GlyphHintsRec  hints[1];
+
+    af_glyph_hints_init( hints, face->memory );
+
+    metrics->axis[ AF_DIMENSION_HORZ ].width_count = 0;
+    metrics->axis[ AF_DIMENSION_VERT ].width_count = 0;
+
+    /* For now, compute the standard width and height from the `o'       */
+    /* character.  I started computing the stem width of the `i' and the */
+    /* stem height of the "-", but it wasn't too good.  Moreover, we now */
+    /* have a single character that gives us standard width and height.  */
+    {
+      FT_UInt       glyph_index;
+      AF_Dimension  dim;
+
+
+      glyph_index = FT_Get_Char_Index( face, 'o' );
+      if ( glyph_index == 0 )
+        goto Exit;
+
+      error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE );
+      if ( error || face->glyph->outline.n_points <= 0 )
+        goto Exit;
+
+      error = af_glyph_hints_reset( hints, &face->glyph->outline,
+                                    0x10000L, 0x10000L );
+      if ( error )
+        goto Exit;
+
+      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+      {
+        AF_LatinAxis  axis    = & metrics->axis[ dim ];
+        AF_AxisHints  axhints = & hints->axis[ dim ];
+        AF_Segment    seg, limit, link;
+        FT_UInt       num_widths = 0;
+        FT_Pos        edge_distance_threshold = 32000;
+
+        af_latin_hints_compute_segments( hints, dim );
+        af_latin_hints_link_segments   ( hints, dim );
+
+        seg   = axhints->segments;
+        limit = seg + axhints->num_segments;
+
+        for ( ; seg < limit; seg++ )
+        {
+          link = seg->link;
+          /* we only consider stem segments there! */
+          if ( link && link->link == seg && link > seg )
+          {
+            FT_Pos  dist;
+
+
+            dist = seg->pos - link->pos;
+            if ( dist < 0 )
+              dist = -dist;
+
+            if ( num_widths < AF_LATIN_MAX_WIDTHS )
+              axis->widths[ num_widths++ ] = dist;
+          }
+        }
+
+        af_sort_pos( axis->widths, num_widths );
+        axis->width_count = num_widths;
+
+        /* we will now try to find the smallest width */
+        if ( num_widths > 0 && axis->widths[0] < edge_distance_threshold )
+          edge_distance_threshold = axis->widths[0];
+
+        /* Now, compute the edge distance threshold as a fraction of the */
+        /* smallest width in the font. Set it in `hinter->glyph' too!    */
+        if ( edge_distance_threshold == 32000 )
+          edge_distance_threshold = 50;
+
+        /* let's try 20% */
+        axis->edge_distance_threshold = edge_distance_threshold / 5;
+      }
+    }
+
+  Exit:
+    af_glyph_hints_done( hints );
+  }
+
+
+
+#define AF_LATIN_MAX_TEST_CHARACTERS  12
+
+
+  static  const char* const  af_latin_blue_chars[ AF_LATIN_MAX_BLUES ] =
+  {
+    "THEZOCQS",
+    "HEZLOCUS",
+    "fijkdbh",
+    "xzroesc",
+    "xzroesc",
+    "pqgjy"
+  };
+
+
+  static void
+  af_latin_metrics_init_blues( AF_LatinMetrics  metrics,
+                               FT_Face          face )
+  {
+    FT_Pos        flats [ AF_LATIN_MAX_TEST_CHARACTERS ];
+    FT_Pos        rounds[ AF_LATIN_MAX_TEST_CHARACTERS ];
+    FT_Int        num_flats;
+    FT_Int        num_rounds;
+    FT_Int        bb;
+    AF_LatinBlue  blue;
+    FT_Error      error;
+    AF_LatinAxis  axis  = &metrics->axis[ AF_DIMENSION_VERT ];
+    FT_GlyphSlot  glyph = face->glyph;
+
+    /* we compute the blues simply by loading each character from the    */
+    /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */
+    /* bottom-most points (depending on `AF_IS_TOP_BLUE')                */
+
+    AF_LOG(( "blue zones computation\n" ));
+    AF_LOG(( "------------------------------------------------\n" ));
+
+    for ( bb = 0; bb < AF_BLUE_MAX; bb++ )
+    {
+      const char*  p     = af_latin_blue_chars[bb];
+      const char*  limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
+      FT_Pos*      blue_ref;
+      FT_Pos*      blue_shoot;
+
+      AF_LOG(( "blue %3d: ", blue ));
+
+      num_flats  = 0;
+      num_rounds = 0;
+
+      for ( ; p < limit && *p; p++ )
+      {
+        FT_UInt     glyph_index;
+        FT_Vector*  extremum;
+        FT_Vector*  points;
+        FT_Vector*  point_limit;
+        FT_Vector*  point;
+        FT_Bool     round;
+
+
+        AF_LOG(( "'%c'", *p ));
+
+        /* load the character in the face -- skip unknown or empty ones */
+        glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
+        if ( glyph_index == 0 )
+          continue;
+
+        error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+        if ( error || glyph->outline.n_points <= 0 )
+          continue;
+
+        /* now compute min or max point indices and coordinates */
+        points      = glyph->outline.points;
+        point_limit = points + glyph->outline.n_points;
+        point       = points;
+        extremum    = point;
+        point++;
+
+        if ( AF_IS_TOP_BLUE( bb ) )
+        {
+          for ( ; point < point_limit; point++ )
+            if ( point->y > extremum->y )
+              extremum = point;
+        }
+        else
+        {
+          for ( ; point < point_limit; point++ )
+            if ( point->y < extremum->y )
+              extremum = point;
+        }
+
+        AF_LOG(( "%5d", (int)extremum->y ));
+
+        /* now, check whether the point belongs to a straight or round  */
+        /* segment; we first need to find in which contour the extremum */
+        /* lies, then see its previous and next points                  */
+        {
+          FT_Int  idx = (FT_Int)( extremum - points );
+          FT_Int  n;
+          FT_Int  first, last, prev, next, end;
+          FT_Pos  dist;
+
+
+          last  = -1;
+          first = 0;
+
+          for ( n = 0; n < glyph->outline.n_contours; n++ )
+          {
+            end = glyph->outline.contours[n];
+            if ( end >= idx )
+            {
+              last = end;
+              break;
+            }
+            first = end + 1;
+          }
+
+          /* XXX: should never happen! */
+          if ( last < 0 )
+            continue;
+
+          /* now look for the previous and next points that are not on the */
+          /* same Y coordinate.  Threshold the `closeness'...              */
+
+          prev = idx;
+          next = prev;
+
+          do
+          {
+            if ( prev > first )
+              prev--;
+            else
+              prev = last;
+
+            dist = points[prev].y - extremum->y;
+            if ( dist < -5 || dist > 5 )
+              break;
+
+          } while ( prev != idx );
+
+          do
+          {
+            if ( next < last )
+              next++;
+            else
+              next = first;
+
+            dist = points[next].y - extremum->y;
+            if ( dist < -5 || dist > 5 )
+              break;
+
+          } while ( next != idx );
+
+          /* now, set the `round' flag depending on the segment's kind */
+          round = FT_BOOL(
+            FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
+            FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
+
+          AF_LOG(( "%c ", round ? 'r' : 'f' ));
+        }
+
+        if ( round )
+          rounds[num_rounds++] = extremum->y;
+        else
+          flats[num_flats++] = extremum->y;
+      }
+
+      AF_LOG(( "\n" ));
+
+      if ( num_flats == 0 && num_rounds == 0 )
+      {
+       /* we couldn't find a single glyph to compute this blue zone,
+        * we will simply ignore it then
+        */
+        AF_LOG(( "empty !!\n" ));
+        continue;
+      }
+
+      /* we have computed the contents of the `rounds' and `flats' tables, */
+      /* now determine the reference and overshoot position of the blue -- */
+      /* we simply take the median value after a simple sort               */
+      af_sort_pos( num_rounds, rounds );
+      af_sort_pos( num_flats,  flats );
+
+      blue       = axis->blues[ axis->blue_count ];
+      blue_ref   = & blue->ref.org;
+      blue_shoot = & blue->shoot.org;
+
+      axis->blue_count ++;
+
+      if ( num_flats == 0 )
+      {
+        *blue_ref    =
+        *blue->shoot = rounds[num_rounds / 2];
+      }
+      else if ( num_rounds == 0 )
+      {
+        *blue_ref   =
+        *blue_shoot = flats[num_flats / 2];
+      }
+      else
+      {
+        *blue_ref   = flats[num_flats / 2];
+        *blue_shoot = rounds[num_rounds / 2];
+      }
+
+      /* there are sometimes problems: if the overshoot position of top     */
+      /* zones is under its reference position, or the opposite for bottom  */
+      /* zones.  We must thus check everything there and correct the errors */
+      if ( *blue_shoot != *blue_ref )
+      {
+        FT_Pos   ref      = *blue_ref;
+        FT_Pos   shoot    = *blue_shoot;
+        FT_Bool  over_ref = FT_BOOL( shoot > ref );
+
+
+        if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
+          *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+      }
+
+      blue->flags = 0;
+      if ( AF_LATIN_IS_TOP_BLUE(bb) )
+        blue->flags |= AF_LATIN_BLUE_TOP;
+
+      AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+    }
+
+  Exit:
+    return;
+  }
+
+
+  static FT_Error
+  af_latin_metrics_init( AF_LatinMetrics  metrics,
+                         FT_Face          face )
+  {
+    FT_Error      error;
+    FT_CharMap    oldmap = face->charmap;
+
+    /* do we have a Unicode charmap in there? */
+    error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+    if ( error ) goto Exit;
+
+    metrics->units_per_em = face->units_per_EM;
+
+    af_latin_metrics_init_widths( metrics, face );
+    af_latin_metrics_init_blues( metrics, face );
+
+  Exit:
+    FT_Set_Charmap( face, oldmap );
+    return error;
+  }
+
+
+  static void
+  af_latin_metrics_scale_dim( AF_LatinMetrics   metrics,
+                              AF_Scaler         scaler,
+                              AF_Dimension      dim )
+  {
+    FT_Fixed      scale;
+    FT_Pos        delta;
+    AF_LatinAxis  axis;
+    FT_UInt       nn;
+
+    if ( dim == AF_DIMENSION_HORZ )
+    {
+      scale = scaler->x_scale;
+      delta = scaler->x_delta;
+    }
+    else
+    {
+      scale = scaler->y_scale;
+      delta = scaler->y_delta;
+    }
+
+    axis = metrics->axis[ dim ];
+
+    if ( axis->scale == scale && axis->delta == delta )
+      return;
+
+    axis->scale = scale;
+    axis->delta = delta;
+
+   /* scale the standard widths
+    */
+    for ( nn = 0; nn < axis->width_count; nn++ )
+    {
+      AF_Width  width = axis->widths + nn;
+
+      width->cur = FT_MulFix( width->org, scale );
+      width->fit = width->cur;
+    }
+
+    if ( dim == AF_DIMENSION_VERT )
+    {
+     /* scale the blue zones
+      */
+      for ( nn = 0; nn < axis->blue_count; nn++ )
+      {
+        AF_LatinBlue  blue  = & axis->blues[nn];
+        FT_UInt       flags = blue->flags & ~AF_LATIN_BLUE_ACTIVE;
+        FT_Pos        dist;
+
+        blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
+        blue->ref.fit = blue->ref.cur;
+
+        blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
+        blue->shoot.fit = blue->shoot.cur;
+
+       /* a blue zone is only active when it is less than 3/4 pixels tall
+        */
+        dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
+        if ( dist >= 48 || dist <= -48 )
+          blue->flags |= ~AF_LATIN_BLUE_ACTIVE;
+      }
+    }
+  }
+
+
   FT_LOCAL_DEF( void )
-  af_latin_hints_compute_segments( AF_OutlineHints  hints,
-                                   AF_Dimension     dim )
+  af_latin_metrics_scale( AF_LatinMetrics  metrics,
+                          AF_Scaler        scaler )
   {
+    af_latin_metrics_scale( metrics, scaler, AF_DIMENSION_HORZ );
+    af_latin_metrics_scale( metrics, scaler, AF_DIMENSION_VERT );
+  }
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****            L A T I N   G L Y P H   A N A L Y S I S              *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  af_latin_hints_compute_segments( AF_GlyphHints  hints,
+                                   AF_Dimension   dim )
+  {
     AF_AxisHints  axis = &hints->axis[dim];
     AF_Segment    segments = axis->segments;
     AF_Segment    segment       =  segments;
@@ -23,11 +453,30 @@
     segment_dir = major_dir;
 
     /* set up (u,v) in each point */
-    af_setup_uv( outline, (dim == AF_DIMENSION_HORZ)
-                        ? AF_UV_FXY,
-                        : AF_UV_FYX );
+    if ( dim == AF_DIMENSION_HORZ )
+    {
+      AF_Point  point = hints->points;
+      AF_Point  limit = point + hints->num_points;
 
+      for ( ; point < limit; point++ )
+      {
+        point->u = point->fx;
+        point->v = point->fy;
+      }
+    }
+    else
+    {
+      AF_Point  point = hints->points;
+      AF_Point  limit = point + hints->num_points;
 
+      for ( ; point < limit; point++ )
+      {
+        point->u = point->fy;
+        point->v = point->fx;
+      }
+    }
+
+
     /* do each contour separately */
     for ( ; contour < contour_limit; contour++ )
     {
@@ -238,8 +687,8 @@
 
 
   FT_LOCAL_DEF( void )
-  af_latin_hints_link_segments( AF_OutlineHints  hints,
-                                AF_Dimension     dim )
+  af_latin_hints_link_segments( AF_GlyphHints  hints,
+                                AF_Dimension   dim )
   {
     AF_AxisHints  axis          = &hints->axis[dim];
     AF_Segment    segments      = axis->segments;
@@ -318,17 +767,17 @@
 
 
   FT_LOCAL_DEF( void )
-  af_latin_hints_compute_edges( AF_OutlineHints  hints,
-                                AF_Dimension     dim )
+  af_latin_hints_compute_edges( AF_GlyphHints  hints,
+                                AF_Dimension   dim )
   {
     AF_AxisHints  axis = &hints->axis[dim];
     AF_Edge       edges = axis->edges;
     AF_Edge       edge, edge_limit;
-    
+
     AF_Segment    segments = axis->segments;
     AF_Segment    segment_limit = segments + axis->num_segments;
     AF_Segment    seg;
-    
+
     AF_Direction  up_dir;
     FT_Fixed      scale;
     FT_Pos        edge_distance_threshold;
@@ -519,7 +968,6 @@
           else
             edge2 = seg2->edge;
 
-#ifdef FT_CONFIG_CHESTER_SERIF
           if ( is_serif )
           {
             edge->serif   = edge2;
@@ -527,12 +975,6 @@
           }
           else
             edge->link  = edge2;
-#else /* !FT_CONFIG_CHESTER_SERIF */
-          if ( is_serif )
-            edge->serif = edge2;
-          else
-            edge->link  = edge2;
-#endif /* !FT_CONFIG_CHESTER_SERIF */
         }
 
         seg = seg->edge_next;
@@ -567,17 +1009,9 @@
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    af_outline_detect_features                                         */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Performs feature detection on a given AF_OutlineRec object.        */
-  /*                                                                       */
   FT_LOCAL_DEF( void )
-  af_latin_hints_detect_features( AF_OutlineHints  hints,
-                                  AF_Dimension     dim )
+  af_latin_hints_detect_features( AF_GlyphHints  hints,
+                                  AF_Dimension   dim )
   {
     af_latin_hints_compute_segments( hints, dim );
     af_latin_hints_link_segments   ( hints, dim );
@@ -585,93 +1019,51 @@
   }
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    af_outline_compute_blue_edges                                      */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Computes the `blue edges' in a given outline (i.e. those that must */
-  /*    be snapped to a blue zone edge (top or bottom).                    */
-  /*                                                                       */
   FT_LOCAL_DEF( void )
-  af_latin_hints_compute_blue_edges( AF_OutlineHints  outline,
-                                     AF_Face_Globals  face_globals )
+  af_latin_hints_compute_blue_edges( AF_GlyphHints    hints,
+                                     AF_LatinMetrics  metrics )
   {
-    AF_Edge     edge       = outline->horz_edges;
-    AF_Edge     edge_limit = edge + outline->num_hedges;
-    AF_Globals  globals    = &face_globals->design;
-    FT_Fixed    y_scale    = outline->y_scale;
+    AF_AxisHints  axis       = &hints->axis[ AF_DIMENSION_VERT ];
+    AF_Edge       edge       = axis->edges;
+    AF_Edge       edge_limit = edge + axis->num_edges;
+    AF_LatinAxis  latin      = &metrics->axis[ AF_DIMENSION_VERT ];
+    FT_Fixed      scale      = latin->scale;
 
-    FT_Bool     blue_active[AF_BLUE_MAX];
 
-
     /* compute which blue zones are active, i.e. have their scaled */
     /* size < 3/4 pixels                                           */
-    {
-      AF_Blue  blue;
-      FT_Bool  check = 0;
 
-
-      for ( blue = AF_BLUE_CAPITAL_TOP; blue < AF_BLUE_MAX; blue++ )
-      {
-        FT_Pos  ref, shoot, dist;
-
-
-        ref   = globals->blue_refs[blue];
-        shoot = globals->blue_shoots[blue];
-        dist  = ref - shoot;
-        if ( dist < 0 )
-          dist = -dist;
-
-        blue_active[blue] = 0;
-
-        if ( FT_MulFix( dist, y_scale ) < 48 )
-        {
-          blue_active[blue] = 1;
-          check = 1;
-        }
-      }
-
-      /* return immediately if no blue zone is active */
-      if ( !check )
-        return;
-    }
-
-    /* for each horizontal edge search the blue zone which is closest */
+   /* for each horizontal edge search the blue zone which is closest */
     for ( ; edge < edge_limit; edge++ )
     {
-      AF_Blue  blue;
-      FT_Pos*  best_blue = 0;
-      FT_Pos   best_dist;  /* initial threshold */
+      FT_Int     bb;
+      AF_Width   best_blue = NULL;
+      FT_Pos     best_dist;  /* initial threshold */
 
 
       /* compute the initial threshold as a fraction of the EM size */
-      best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale );
+      best_dist = FT_MulFix( metrics->units_pe_EM / 40, scale );
 
-#ifdef FT_CONFIG_CHESTER_SMALL_F
       if ( best_dist > 64 / 2 )
         best_dist = 64 / 2;
-#else
-      if ( best_dist > 64 / 4 )
-        best_dist = 64 / 4;
-#endif
 
-      for ( blue = AF_BLUE_CAPITAL_TOP; blue < AF_BLUE_MAX; blue++ )
+      for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
       {
+        AF_LatinBlue  blue = latin->blues + bb;
+        FT_Bool       is_top_blue, is_major_dir;
+
+       /* skip inactive blue zones (i.e. those that are too small
+        */
+        if ( !(bb->flags & AF_LATIN_BLUE_ACTIVE) )
+          continue;
+
         /* if it is a top zone, check for right edges -- if it is a bottom */
         /* zone, check for left edges                                      */
         /*                                                                 */
         /* of course, that's for TrueType XXX                              */
-        FT_Bool  is_top_blue  =
-                   FT_BOOL( AF_IS_TOP_BLUE( blue ) );
-        FT_Bool  is_major_dir =
-                   FT_BOOL( edge->dir == outline->horz_major_dir );
+        is_top_blue  = (bb->flags & AF_LATIN_BLUE_TOP) != 0;
+        is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
 
-
-        if ( !blue_active[blue] )
-          continue;
-
         /* if it is a top zone, the edge must be against the major    */
         /* direction; if it is a bottom zone, it must be in the major */
         /* direction                                                  */
@@ -678,11 +1070,10 @@
         if ( is_top_blue ^ is_major_dir )
         {
           FT_Pos   dist;
-          FT_Pos*  blue_pos = globals->blue_refs + blue;
 
 
           /* first of all, compare it to the reference position */
-          dist = edge->fpos - *blue_pos;
+          dist = edge->fpos - blue->ref.org;
           if ( dist < 0 )
             dist = -dist;
 
@@ -690,7 +1081,7 @@
           if ( dist < best_dist )
           {
             best_dist = dist;
-            best_blue = blue_pos;
+            best_blue = & blue->ref;
           }
 
           /* now, compare it to the overshoot position if the edge is     */
@@ -698,13 +1089,13 @@
           /* top zone, or under the reference position of a bottom zone   */
           if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
           {
-            FT_Bool  is_under_ref = FT_BOOL( edge->fpos < *blue_pos );
+            FT_Bool  is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
 
 
             if ( is_top_blue ^ is_under_ref )
             {
-              blue_pos = globals->blue_shoots + blue;
-              dist = edge->fpos - *blue_pos;
+              blue = _pos = globals->blue_shoots + blue;
+              dist = edge->fpos - blue->shoot.org;
               if ( dist < 0 )
                 dist = -dist;
 
@@ -712,7 +1103,7 @@
               if ( dist < best_dist )
               {
                 best_dist = dist;
-                best_blue = blue_pos;
+                best_blue = & blue->shoot;
               }
             }
           }
@@ -725,31 +1116,600 @@
   }
 
 
+  static FT_Error
+  af_latin_hints_init( AF_GlyphHints    hints,
+                       AF_Scaler        scaler,
+                       AF_LatinMetrics  metrics )
+  {
+    FT_Error  error;
+
+    error = af_glyph_hints_reset( hints, &scaler->outline,
+                                  scaler->x_scale,
+                                  scaler->y_scale,
+                                  scaler->x_delta,
+                                  scaler->y_delta );
+   if (error)
+     goto Exit;
+
+   af_latin_hints_detect_features( hints, metrics );
+   af_latin_hints_compute_blue_edges( hints, metrics );
+
+ Exit:
+   return error;
+  }
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****         L A T I N   G L Y P H   G R I D - F I T T I N G         *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  /* snap a given width in scaled coordinates to one of the */
+  /* current standard widths                                */
+  static FT_Pos
+  af_latin_snap_width( AF_Width  widths,
+                       FT_Int    count,
+                       FT_Pos    width )
+  {
+    int     n;
+    FT_Pos  best      = 64 + 32 + 2;
+    FT_Pos  reference = width;
+    FT_Pos  scaled;
+
+
+    for ( n = 0; n < count; n++ )
+    {
+      FT_Pos  w;
+      FT_Pos  dist;
+
+
+      w = widths[n].cur;
+      dist = width - w;
+      if ( dist < 0 )
+        dist = -dist;
+      if ( dist < best )
+      {
+        best      = dist;
+        reference = w;
+      }
+    }
+
+    scaled = ( reference + 32 ) & -64;
+
+    if ( width >= reference )
+    {
+      if ( width < scaled + 48 )
+        width = reference;
+    }
+    else
+    {
+      if ( width > scaled - 48 )
+        width = reference;
+    }
+
+    return width;
+  }
+
+
+  /* compute the snapped width of a given stem */
+
+  static FT_Pos
+  af_latin_compute_stem_width( AF_GylphHints  hints,
+                               AF_Dimension   dim,
+                               FT_Pos         width,
+                               AF_Edge_Flags  base_flags,
+                               AF_Edge_Flags  stem_flags )
+  {
+    AF_Globals  globals  = &hinter->globals->scaled;
+    FT_Pos      dist     = width;
+    FT_Int      sign     = 0;
+    FT_Bool     vertical = FT_BOOL( dim == AF_DIMENSION_VERT );
+
+
+    if ( dist < 0 )
+    {
+      dist = -width;
+      sign = 1;
+    }
+
+    if ( !hinter->do_stem_adjust )
+    {
+      /* leave stem widths unchanged */
+    }
+    else if ( (  vertical && !hinter->do_vert_snapping ) ||
+              ( !vertical && !hinter->do_horz_snapping ) )
+    {
+      /* smooth hinting process: very lightly quantize the stem width */
+      /*                                                              */
+
+      /* leave the widths of serifs alone */
+
+      if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
+        goto Done_Width;
+
+      else if ( ( base_flags & AF_EDGE_ROUND ) )
+      {
+        if ( dist < 80 )
+          dist = 64;
+      }
+      else if ( dist < 56 )
+        dist = 56;
+
+      {
+        FT_Pos  delta = dist - globals->stds[vertical];
+
+
+        if ( delta < 0 )
+          delta = -delta;
+
+        if ( delta < 40 )
+        {
+          dist = globals->stds[vertical];
+          if ( dist < 48 )
+            dist = 48;
+
+          goto Done_Width;
+        }
+
+        if ( dist < 3 * 64 )
+        {
+          delta  = dist & 63;
+          dist  &= -64;
+
+          if ( delta < 10 )
+            dist += delta;
+
+          else if ( delta < 32 )
+            dist += 10;
+
+          else if ( delta < 54 )
+            dist += 54;
+
+          else
+            dist += delta;
+        }
+        else
+          dist = ( dist + 32 ) & -64;
+      }
+    }
+    else
+    {
+      /* strong hinting process: snap the stem width to integer pixels */
+      /*                                                               */
+      if ( vertical )
+      {
+        dist = af_snap_width( globals->heights, globals->num_heights, dist );
+
+        /* in the case of vertical hinting, always round */
+        /* the stem heights to integer pixels            */
+        if ( dist >= 64 )
+          dist = ( dist + 16 ) & -64;
+        else
+          dist = 64;
+      }
+      else
+      {
+        dist = af_snap_width( globals->widths, globals->num_widths, dist );
+
+        if ( hinter->flags & AF_HINTER_MONOCHROME )
+        {
+          /* monochrome horizontal hinting: snap widths to integer pixels */
+          /* with a different threshold                                   */
+          if ( dist < 64 )
+            dist = 64;
+          else
+            dist = ( dist + 32 ) & -64;
+        }
+        else
+        {
+          /* for horizontal anti-aliased hinting, we adopt a more subtle */
+          /* approach: we strengthen small stems, round stems whose size */
+          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
+          if ( dist < 48 )
+            dist = ( dist + 64 ) >> 1;
+
+          else if ( dist < 128 )
+            dist = ( dist + 22 ) & -64;
+          else
+            /* XXX: round otherwise to prevent color fringes in LCD mode */
+            dist = ( dist + 32 ) & -64;
+        }
+      }
+    }
+
+  Done_Width:
+    if ( sign )
+      dist = -dist;
+
+    return dist;
+  }
+
+
+
+  /* align one stem edge relative to the previous stem edge */
+  static void
+  af_latin_align_linked_edge( AF_GlyphHints  hints,
+                              AF_Dimension   dim,
+                              AF_Edge        base_edge,
+                              AF_Edge        stem_edge )
+  {
+    FT_Pos  dist = stem_edge->opos - base_edge->opos;
+
+    FT_Pos  fitted_width = af_latin_compute_stem_width( hints,
+                                                        dim,
+                                                        dist,
+                                                        base_edge->flags,
+                                                        stem_edge->flags );
+
+    stem_edge->pos = base_edge->pos + fitted_width;
+  }
+
+
+  static void
+  af_latin_align_serif_edge( AF_GlyphHints  hints,
+                             AF_Edge        base,
+                             AF_Edge        serif )
+  {
+    FT_UNUSED( hints );
+
+    serif->pos = base->pos + (serif->opos - base->opos);
+  }
+
   /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    af_outline_scale_blue_edges                                        */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    This function must be called before hinting in order to re-adjust  */
-  /*    the contents of the detected edges (basically change the `blue     */
-  /*    edge' pointer from `design units' to `scaled ones').               */
-  /*                                                                       */
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****       E D G E   H I N T I N G                                   ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
   FT_LOCAL_DEF( void )
-  af_outline_hints_scale_blue_edges( AF_OutlineHints  hints )       outline,
+  af_latin_hint_edges( AF_GlyphHints   hints,
+                       AF_Dimension    dim )
   {
-    AF_AxisHints  axis       = &hints->axis[ AF_DIMENSION_VERT ];
-    AF_Edge       edge       = axis->edges;
-    AF_Edge       edge_limit = edge + axis->num_edges;
-    FT_Pos        delta;
+    AF_AxisHints  axis = & hints->axis[dim];
+    AF_Edge       edges = axis->edges;
+    AF_Edge       edge_limit = edges + axis->num_edges;
+    FT_Int        n_edges;
+    AF_Edge       edge;
+    AF_Edge       anchor = 0;
+    FT_Int        has_serifs = 0;
 
 
-    delta = globals->scaled.blue_refs - globals->design.blue_refs;
+    /* we begin by aligning all stems relative to the blue zone */
+    /* if needed -- that's only for horizontal edges            */
+    if ( dim == AF_DIMENSION_VERT )
+    {
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        AF_Width*  blue;
+        AF_Edge    edge1, edge2;
 
-    for ( ; edge < edge_limit; edge++ )
+
+        if ( edge->flags & AF_EDGE_DONE )
+          continue;
+
+        blue  = edge->blue_edge;
+        edge1 = NULL;
+        edge2 = edge->link;
+
+        if ( blue )
+        {
+          edge1 = edge;
+        }
+        else if ( edge2 && edge2->blue_edge )
+        {
+          blue  = edge2->blue_edge;
+          edge1 = edge2;
+          edge2 = edge;
+        }
+
+        if ( !edge1 )
+          continue;
+
+        edge1->pos    = blue->fit;
+        edge1->flags |= AF_EDGE_DONE;
+
+        if ( edge2 && !edge2->blue_edge )
+        {
+          af_latin_align_linked_edge( hints, dim, edge1, edge2 );
+          edge2->flags |= AF_EDGE_DONE;
+        }
+
+        if ( !anchor )
+          anchor = edge;
+      }
+    }
+
+    /* now we will align all stem edges, trying to maintain the */
+    /* relative order of stems in the glyph                     */
+    for ( edge = edges; edge < edge_limit; edge++ )
     {
-      if ( edge->blue_edge )
-        edge->blue_edge += delta;
+      AF_Edge  edge2;
+
+
+      if ( edge->flags & AF_EDGE_DONE )
+        continue;
+
+      /* skip all non-stem edges */
+      edge2 = edge->link;
+      if ( !edge2 )
+      {
+        has_serifs++;
+        continue;
+      }
+
+      /* now align the stem */
+
+      /* this should not happen, but it's better to be safe */
+      if ( edge2->blue_edge || edge2 < edge )
+      {
+        af_latin_align_linked_edge( hinter, edge2, edge, dimension );
+        edge->flags |= AF_EDGE_DONE;
+        continue;
+      }
+
+      if ( !anchor )
+      {
+        FT_Pos  org_len, org_center, cur_len;
+        FT_Pos  cur_pos1, error1, error2, u_off, d_off;
+
+
+        org_len = edge2->opos - edge->opos;
+        cur_len = af_latin_compute_stem_width( hints, dim, org_len,
+                                               edge->flags, edge2->flags );
+        if ( cur_len <= 64 )
+          u_off = d_off = 32;
+        else
+        {
+          u_off = 38;
+          d_off = 26;
+        }
+
+        if ( cur_len < 96 )
+        {
+          org_center = edge->opos + ( org_len >> 1 );
+
+          cur_pos1   = ( org_center + 32 ) & -64;
+
+          error1 = org_center - ( cur_pos1 - u_off );
+          if ( error1 < 0 )
+            error1 = -error1;
+
+          error2 = org_center - ( cur_pos1 + d_off );
+          if ( error2 < 0 )
+            error2 = -error2;
+
+          if ( error1 < error2 )
+            cur_pos1 -= u_off;
+          else
+            cur_pos1 += d_off;
+
+          edge->pos  = cur_pos1 - cur_len / 2;
+          edge2->pos = cur_pos1 + cur_len / 2;
+
+        }
+        else
+          edge->pos = ( edge->opos + 32 ) & -64;
+
+        anchor = edge;
+
+        edge->flags |= AF_EDGE_DONE;
+
+        af_latin_align_linked_edge( hints, dim, edge, edge2 );
+      }
+      else
+      {
+        FT_Pos  org_pos, org_len, org_center, cur_len;
+        FT_Pos  cur_pos1, cur_pos2, delta1, delta2;
+
+
+        org_pos    = anchor->pos + ( edge->opos - anchor->opos );
+        org_len    = edge2->opos - edge->opos;
+        org_center = org_pos + ( org_len >> 1 );
+
+        cur_len = af_compute_stem_width( hinter, dimension, org_len,
+                                         edge->flags, edge2->flags  );
+
+        if ( cur_len < 96 )
+        {
+          FT_Pos  u_off, d_off;
+
+
+          cur_pos1 = ( org_center + 32 ) & -64;
+
+          if (cur_len <= 64 )
+            u_off = d_off = 32;
+          else
+          {
+            u_off = 38;
+            d_off = 26;
+          }
+
+          delta1 = org_center - ( cur_pos1 - u_off );
+          if ( delta1 < 0 )
+            delta1 = -delta1;
+
+          delta2 = org_center - ( cur_pos1 + d_off );
+          if ( delta2 < 0 )
+            delta2 = -delta2;
+
+          if ( delta1 < delta2 )
+            cur_pos1 -= u_off;
+          else
+            cur_pos1 += d_off;
+
+          edge->pos  = cur_pos1 - cur_len / 2;
+          edge2->pos = cur_pos1 + cur_len / 2;
+        }
+        else
+        {
+          org_pos    = anchor->pos + ( edge->opos - anchor->opos );
+          org_len    = edge2->opos - edge->opos;
+          org_center = org_pos + ( org_len >> 1 );
+
+          cur_len    = af_compute_stem_width( hinter, dimension, org_len,
+                                              edge->flags, edge2->flags );
+
+          cur_pos1   = ( org_pos + 32 ) & -64;
+          delta1     = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
+          if ( delta1 < 0 )
+            delta1 = -delta1;
+
+          cur_pos2   = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len;
+          delta2     = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
+          if ( delta2 < 0 )
+            delta2 = -delta2;
+
+          edge->pos  = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
+          edge2->pos = edge->pos + cur_len;
+        }
+
+        edge->flags  |= AF_EDGE_DONE;
+        edge2->flags |= AF_EDGE_DONE;
+
+        if ( edge > edges && edge->pos < edge[-1].pos )
+          edge->pos = edge[-1].pos;
+      }
     }
+
+    /* make sure that lowercase m's maintain their symmetry */
+
+    /* In general, lowercase m's have six vertical edges if they are sans */
+    /* serif, or twelve if they are avec serif.  This implementation is   */
+    /* based on that assumption, and seems to work very well with most    */
+    /* faces.  However, if for a certain face this assumption is not      */
+    /* true, the m is just rendered like before.  In addition, any stem   */
+    /* correction will only be applied to symmetrical glyphs (even if the */
+    /* glyph is not an m), so the potential for unwanted distortion is    */
+    /* relatively low.                                                    */
+
+    /* We don't handle horizontal edges since we can't easily assure that */
+    /* the third (lowest) stem aligns with the base line; it might end up */
+    /* one pixel higher or lower.                                         */
+
+    n_edges = edge_limit - edges;
+    if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
+    {
+      AF_Edge  edge1, edge2, edge3;
+      FT_Pos   dist1, dist2, span, delta;
+
+
+      if ( n_edges == 6 )
+      {
+        edge1 = edges;
+        edge2 = edges + 2;
+        edge3 = edges + 4;
+      }
+      else
+      {
+        edge1 = edges + 1;
+        edge2 = edges + 5;
+        edge3 = edges + 9;
+      }
+
+      dist1 = edge2->opos - edge1->opos;
+      dist2 = edge3->opos - edge2->opos;
+
+      span = dist1 - dist2;
+      if ( span < 0 )
+        span = -span;
+
+      if ( span < 8 )
+      {
+        delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
+        edge3->pos -= delta;
+        if ( edge3->link )
+          edge3->link->pos -= delta;
+
+        /* move the serifs along with the stem */
+        if ( n_edges == 12 )
+        {
+          ( edges + 8 )->pos -= delta;
+          ( edges + 11 )->pos -= delta;
+        }
+
+        edge3->flags |= AF_EDGE_DONE;
+        if ( edge3->link )
+          edge3->link->flags |= AF_EDGE_DONE;
+      }
+    }
+
+    if ( has_serifs || !anchor )
+    {
+     /* now hint the remaining edges (serifs and single) in order
+      * to complete our processing
+      */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        if ( edge->flags & AF_EDGE_DONE )
+          continue;
+
+        if ( edge->serif )
+          af_align_serif_edge( hinter, edge->serif, edge, dimension );
+        else if ( !anchor )
+        {
+          edge->pos = ( edge->opos + 32 ) & -64;
+          anchor    = edge;
+        }
+        else
+          edge->pos = anchor->pos +
+                      ( ( edge->opos-anchor->opos + 32 ) & -64 );
+
+        edge->flags |= AF_EDGE_DONE;
+
+        if ( edge > edges && edge->pos < edge[-1].pos )
+          edge->pos = edge[-1].pos;
+
+        if ( edge + 1 < edge_limit        &&
+             edge[1].flags & AF_EDGE_DONE &&
+             edge->pos > edge[1].pos      )
+          edge->pos = edge[1].pos;
+      }
+    }
   }
+
+
+  static FT_Error
+  af_latin_hints_apply( AF_GlyphHints    hints,
+                        AF_Scaler        scaler,
+                        AF_LatinMetrics  metrics )
+  {
+    /* XXX */
+    return FT_Err_Unimplemented;
+  }
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****      L A T I N   S C R I P T   C L A S S                        *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  static const AF_Script_UniRangeRec  af_latin_uniranges[] =
+  {
+    { 32, 127 },    /* XXX: TODO: Add new Unicode ranges here !! */
+    { 160, 255 },
+    { 0, 0 }
+  };
+
+  FT_LOCAL_DEF( const AF_ScriptClassRec )  af_latin_script_class =
+  {
+    AF_SCRIPT_LATIN,
+    &af_latin_script_uniranges,
+
+    sizeof( AF_LatinMetricsRec ),
+    (AF_Script_InitMetricsFunc)  af_latin_metrics_init,
+    (AF_Script_ScaleMetricsFunc) af_latin_metrics_scale,
+    (AF_Script_DoneMetricsFunc)  NULL,
+
+    (AF_Script_InitHintsFunc)    af_latin_hints_init,
+    (AF_Script_ApplyHintsFunc)   af_latin_hints_apply
+  };
 
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -11,6 +11,14 @@
   */
   FT_LOCAL( const FT_ScriptClassRec )    af_latin_script_class;
 
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****       L A T I N   G L O B A L   M E T R I C S                   *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
  /*
   * the following declarations could be embedded in the file "aflatin.c"
   * they've been made semi-public to allow alternate script hinters to
@@ -21,29 +29,65 @@
   *  Latin (global) metrics management
   *
   */
-  
+
+  enum
+  {
+    AF_LATIN_BLUE_CAPITAL_TOP,
+    AF_LATIN_BLUE_CAPITAL_BOTTOM,
+    AF_LATIN_BLUE_SMALL_F_TOP,
+    AF_LATIN_BLUE_SMALL_TOP,
+    AF_LATIN_BLUE_SMALL_BOTTOM,
+    AF_LATIN_BLUE_SMALL_MINOR,
+    
+    AF_LATIN_BLUE_MAX
+  };
+
+#define AF_LATIN_IS_TOP_BLUE( b )  ( (b) == AF_LATIN_BLUE_CAPITAL_TOP || \
+                                     (b) == AF_LATIN_BLUE_SMALL_F_TOP || \
+                                     (b) == AF_LATIN_BLUE_SMALL_TOP   )
+
 #define  AF_LATIN_MAX_WIDTHS     16
-#define  AF_LATIN_MAX_BLUES      32
+#define  AF_LATIN_MAX_BLUES      AF_LATIN_BLUE_MAX
 
+  enum
+  {
+    AF_LATIN_BLUE_ACTIVE = (1 << 0),
+    AF_LATIN_BLUE_TOP    = (1 << 1),
+    
+    AF_LATIN_BLUE_MAX
+  };
+
+
+  typedef struct AF_LatinBlueRec_
+  {
+    AF_WidthRec   ref;
+    AF_WidthRec   shoot;
+    FT_UInt       flags;
+  
+  } AF_LatinBlueRec, *AF_LatinBlue;
+
+
   typedef struct AF_LatinAxisRec_
   {
-    FT_Fixed     scale;
-    FT_Pos       delta;
+    FT_Fixed         scale;
+    FT_Pos           delta;
     
-    FT_UInt      width_count;
-    AF_WidthRec  widths[ AF_LATIN_MAX_WIDTHS ];
+    FT_UInt          width_count;
+    AF_WidthRec      widths[ AF_LATIN_MAX_WIDTHS ];
+    FT_Pos           edge_distance_threshold;
     
    /* ignored for horizontal metrics */
-    FT_Bool      control_overshoot;
-    FT_UInt      blue_count;
-    AF_WidthRec  blue_refs  [ AF_MAX_BLUES ];
-    AF_WidthRec  blue_shoots[ AF_MAX_BLUES ];
-    
+    FT_Bool          control_overshoot;
+    FT_UInt          blue_count;
+    AF_LatinBlueRec  blues;
+
   } AF_LatinAxisRec, *AF_LatinAxis;
-  
+
+
   typedef struct AF_LatinMetricsRec_
   {
-    AF_OutlineMetricsRec  root;
+    AF_ScriptMetricsRec   root;
+    FT_UInt               units_per_em;
     AF_LatinAxisRec       axis[ AF_DIMENSION_MAX ];
   
   } AF_LatinMetricsRec, *AF_LatinMetrics;
@@ -58,29 +102,40 @@
                           AF_Scaler        scaler );
 
 
- /* 
-  *  Latin (glyph) hints management
-  *
-  */
 
-  FT_LOCAL( 
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****            L A T I N   G L Y P H   A N A L Y S I S              *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
 
-  FT_LOCAL( void )
-  af_latin_hints_compute_segments( AF_OutlineHints  hints,
-                                   AF_Dimension     dim );
 
+ /* this shouldn't normally be exported. However, other scripts might
+  * like to use this function as-is
+  */
   FT_LOCAL( void )
-  af_latin_hints_link_segments( AF_OutlineHints  hints,
-                                AF_Dimension     dim );
+  af_latin_hints_compute_segments( AF_GlyphHints  hints,
+                                   AF_Dimension   dim );
 
+ /* this shouldn't normally be exported. However, other scripts might
+  * want to use this function as-is
+  */
   FT_LOCAL( void )
-  af_latin_hints_compute_edges( AF_OutlineHints  hints,
-                                AF_Dimension     dim );
+  af_latin_hints_link_segments( AF_GlyphHints  hints,
+                                AF_Dimension   dim );
 
+ /* this shouldn't normally be exported. However, other scripts might
+  * want to use this function as-is
+  */
   FT_LOCAL( void )
-  af_latin_hints_init( AF_OutlineHints  hints,
-                                  AF_Dimension     dim );
+  af_latin_hints_compute_edges( AF_GlyphHints  hints,
+                                AF_Dimension   dim );
 
+  FT_LOCAL( void )
+  af_latin_hints_detect_features( AF_GlyphHints  hints,
+                                  AF_Dimension   dim );
 
 /* */
 
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -1,6 +1,9 @@
 #ifndef __AFTYPES_H__
 #define __AFTYPES_H__
 
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
 FT_BEGIN_HEADER
 
  /**************************************************************************/
@@ -27,6 +30,27 @@
  /**************************************************************************/
  /**************************************************************************/
  /*****                                                                *****/
+ /*****                U T I L I T Y                                   *****/
+ /*****                                                                *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+  typedef struct AF_WidthRec_
+  {
+    FT_Pos  org;  /* original position/width in font units              */
+    FT_Pos  cur;  /* current/scaled position/width in device sub-pixels */
+    FT_Pos  fit;  /* current/fitted position/width in device sub-pixels */
+  
+  } AF_WidthRec, *AF_Width;
+  
+
+  AF_LOCAL( void )
+  af_sort_pos( FT_UInt   count,
+               FT_Pos*   table );
+ 
+ /**************************************************************************/
+ /**************************************************************************/
+ /*****                                                                *****/
  /*****                A N G L E   T Y P E S                           *****/
  /*****                                                                *****/
  /**************************************************************************/
@@ -73,13 +97,17 @@
  /**************************************************************************/
  /**************************************************************************/
 
-  typedef struct AF_OutlineHintsRec_*  AF_OutlineHints;
+ /* opaque handle to glyph-specific hints. see "afhints.h" for more
+  * details
+  */
+  typedef struct AF_GlyphHintsRec_*     AF_GlyphHints;
 
-  typedef struct AF_GlobalHintsRec_*   AF_GlobalHints;
-
+ /* this structure is used to model an input glyph outline to
+  * the auto-hinter. The latter will set the "hints" field
+  * depending on the glyph's script
+  */
   typedef struct AF_OutlineRec_
   {
-    FT_Memory        memory;
     FT_Face          face;
     FT_OutlineRec    outline;
     FT_UInt          outline_resolution;
@@ -87,54 +115,11 @@
     FT_Int           advance;
     FT_UInt          metrics_resolution;
     
-    AF_OutlineHints  hints;
+    AF_GlyphHints    hints;
 
   } AF_OutlineRec;
 
- /**************************************************************************/
- /**************************************************************************/
- /*****                                                                *****/
- /*****                G L O B A L   M E T R I C S                     *****/
- /*****                                                                *****/
- /**************************************************************************/
- /**************************************************************************/
 
-  /*
-   * the following define global metrics in a _single_ dimension
-   *
-   * the "blue_refs" and "blue_shoots" arrays are ignored in
-   * the horizontal dimension
-   */
-
-  typedef struct AF_WidthRec_
-  {
-    FT_Pos  org;  /* original position/width in font units              */
-    FT_Pos  cur;  /* current/scaled position/width in device sub-pixels */
-    FT_Pos  fit;  /* current/fitted position/width in device sub-pixels */
-  
-  } AF_WidthRec, *AF_Width;
-  
-
-#define  AF_MAX_WIDTHS     16
-#define  AF_MAX_BLUES      32
-
-  typedef struct  AF_GlobalMetricsRec_
-  {
-    FT_Int       num_widths;
-    AF_WidthRec  widths[ AF_MAX_WIDTHS ];
-
-    FT_Fixed     scale;  /* used to scale from org to cur with:   */
-    FT_Pos       delta;  /*   x_cur = x_org * scale + delta       */
-
-    /* ignored for horizontal metrics */
-    AF_WidthRec  blue_refs  [ AF_MAX_BLUES ];
-    AF_WidthRec  blue_shoots[ AF_MAX_BLUES ];
-
-    FT_Bool      control_overshoot;
-
-  } AF_GlobalMetricsRec, *AF_GlobalMetrics;
-
-
  /**************************************************************************/
  /**************************************************************************/
  /*****                                                                *****/
@@ -190,14 +175,20 @@
   *   - a specific global analyzer that will compute global metrics
   *     specific to the script.
   *
-  *   - a specific hinting routine
+  *   - a specific glyph analyzer that will compute segments and
+  *     edges for each glyph covered by the script
   *
-  *  all scripts should share the same analysis routine though
+  *   - a specific grid-fitting algorithm that will distort the
+  *     scaled glyph outline according to the results of the glyph
+  *     analyzer
+  *
+  *  note that a given analyzer and/or grid-fitting algorithm can be
+  *  used by more than one script
   */
   typedef enum
   {
     AF_SCRIPT_LATIN = 0,
-    /* add new scripts here */
+    /* add new scripts here. don't forget to update the list in "afglobal.c" */
     
     AF_SCRIPT_MAX   /* do not remove */
   
@@ -204,16 +195,12 @@
   } AF_Script;
 
 
+
   typedef struct AF_ScriptClassRec_ const*  AF_ScriptClass;
 
- /*
-  *  root class for script-specific metrics
-  */
   typedef struct AF_ScriptMetricsRec_
   {
-    AF_ScriptClass        script_class;
-    AF_GlobalMetricsRec   horz_metrics;
-    AF_GlobalMetricsRec   vert_metrics;
+    AF_ScriptClass    clazz;
 
   } AF_ScriptMetricsRec, *AF_ScriptMetrics;
 
@@ -221,22 +208,24 @@
  /* this function parses a FT_Face to compute global metrics for
   * a specific script
   */ 
-  typedef FT_Error  (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics  metrics,
-                                                  FT_Face           face );
+  typedef FT_Error  (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics   metrics,
+                                                  FT_Face            face );
 
   typedef void      (*AF_Script_ScaleMetricsFunc)( AF_ScriptMetrics  metrics,
                                                    AF_Scaler         scaler );
 
-  typedef void      (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics  metrics );
+  typedef void      (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics   metrics );
 
 
-  typedef FT_Error  (*AF_Script_InitHintsFunc)( AF_OutlineHints   hints,
+  typedef FT_Error  (*AF_Script_InitHintsFunc)( AF_GlyphHints     hints,
                                                 AF_Scaler         scaler,
                                                 AF_ScriptMetrics  metrics );
 
-  typedef void      (*AF_Script_ApplyHintsFunc)( AF_OutlineHints  hints );
-                                                 
+  typedef void      (*AF_Script_ApplyHintsFunc)( AF_GlyphHints     hints,
+                                                 AF_Scaler         scaler,
+                                                 AF_ScriptMetrics  metrics );
 
+
   typedef struct AF_Script_UniRangeRec_
   {
     FT_UInt32    first;
@@ -248,7 +237,7 @@
   typedef struct AF_ScriptClassRec_
   {
     AF_Script                   script;
-    AF_Scipt_UniRange           script_uni_ranges;  /* last must be { 0, 0 } */
+    AF_Script_UniRange          script_uni_ranges;  /* last must be { 0, 0 } */
 
     FT_UInt                     script_metrics_size;
     AF_Script_InitMetricsFunc   script_metrics_init;
@@ -255,33 +244,12 @@
     AF_Script_ScaleMetricsFunc  script_metrics_scale;
     AF_Script_DoneMetricsFunc   script_metrics_done;
 
+    AF_Script_InitHintsFunc     script_hints_init;
+    AF_Script_ApplyHintsFunc    script_hints_apply;
+
   } AF_ScriptClassRec;
 
 
-
- /**************************************************************************/
- /**************************************************************************/
- /*****                                                                *****/
- /*****                F A C E   G L O B A L S                         *****/
- /*****                                                                *****/
- /**************************************************************************/
- /**************************************************************************/
-
- /*
-  *  models the global hints data for a given face, decomposed into
-  *  script-specific items..
-  *
-  */
-  typedef struct AF_FaceGlobalsRec_
-  {
-    FT_Face               face;
-    FT_UInt               glyph_count;    /* same as face->num_glyphs     */
-    FT_Byte*              glyph_scripts;  /* maps each gindex to a script */
-    
-    FT_ScriptMetrics      metrics[ AF_SCRIPT_MAX ];
-
-  } AF_FaceGlobalsRec, *AF_FaceGlobals;
- 
 /* */
 
 FT_END_HEADER