shithub: freetype+ttf2subf

Download patch

ref: 8ccb4552a965821f2e5e9913b9c600322667483c
parent: 75820e207297f83d7a7bf89c82f21ce166bcef3e
author: David Turner <[email protected]>
date: Fri Jan 16 04:51:00 EST 2004

updates

git/fs: mount .git/fs: mount/attach disallowed
--- /dev/null
+++ b/src/autofit/Jamfile
@@ -1,0 +1,18 @@
+SubDir FT2_TOP src autofit ;
+
+{
+  local  _sources ;
+
+  if $(FT2_MULTI)
+  {
+    _sources = afangles afglobal afhints aflatin ;
+  }
+  else
+  {
+    _sources = autofit ;
+  }
+
+  Library  $(FT2_LIB) : $(_sources).c ;
+}
+
+# end of src/autofir Jamfile
--- a/src/autofit/afglobal.c
+++ b/src/autofit/afglobal.c
@@ -184,11 +184,10 @@
                                FT_UInt            gindex,
                                AF_ScriptMetrics  *ametrics )
   {
-    AF_Script         script;
     AF_ScriptMetrics  metrics = NULL;
     FT_UInt           index;
     AF_ScriptClass    clazz;
-    FT_Error          error;
+    FT_Error          error = 0;
 
     if ( gindex >= globals->glyph_count )
     {
@@ -203,6 +202,8 @@
     {
      /* create the global metrics object when needed
       */
+      FT_Memory  memory = globals->face->memory;
+
       if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
         goto Exit;
 
@@ -221,7 +222,7 @@
         }
       }
 
-      globals->metrics[ script ] = metrics;
+      globals->metrics[ clazz->script ] = metrics;
     }
 
   Exit:
--- a/src/autofit/afglobal.h
+++ b/src/autofit/afglobal.h
@@ -20,13 +20,12 @@
   *
   */
   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,
@@ -36,7 +35,7 @@
   af_face_globals_free( AF_FaceGlobals  globals );
 
  /* */
- 
+
 FT_END_HEADER
 
 #endif /* __AF_GLOBALS_H__ */
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -303,6 +303,7 @@
     FT_Fixed     y_scale = scaler->y_scale;
     FT_Pos       x_delta = scaler->x_delta;
     FT_Pos       y_delta = scaler->y_delta;
+    FT_Memory    memory  = hints->memory;
 
     hints->scaler_flags = scaler->flags;
     hints->other_flags  = 0;
@@ -505,13 +506,13 @@
           in_x   = point->fx - prev->fx;
           in_y   = point->fy - prev->fy;
 
-          point->in_dir = af_compute_direction( in_x, in_y );
+          point->in_dir = af_direction_compute( in_x, in_y );
 
           next   = point->next;
           out_x  = next->fx - point->fx;
           out_y  = next->fy - point->fy;
 
-          point->out_dir = af_compute_direction( out_x, out_y );
+          point->out_dir = af_direction_compute( out_x, out_y );
 
           if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
           {
@@ -623,8 +624,6 @@
     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 )
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -176,7 +176,7 @@
         extremum    = point;
         point++;
 
-        if ( AF_IS_TOP_BLUE( bb ) )
+        if ( AF_LATIN_IS_TOP_BLUE( bb ) )
         {
           for ( ; point < point_limit; point++ )
             if ( point->y > extremum->y )
@@ -325,7 +325,6 @@
       AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
     }
 
-  Exit:
     return;
   }
 
@@ -398,7 +397,6 @@
       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;
@@ -1150,7 +1148,7 @@
     */
     if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
       hints->other_flags |= AF_LATIN_HINTS_VERT_SNAP;
-      
+
    /* XXX
     */
     if ( mode != FT_RENDER_MODE_LIGHT )
@@ -1163,7 +1161,7 @@
     */
     if ( AF_HINTS_DO_HORIZONTAL(hints) )
       af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ );
-     
+
     if ( AF_HINTS_DO_VERTICAL(hints) )
     {
       af_latin_hints_detect_features( hints, AF_DIMENSION_VERT );
@@ -1243,8 +1241,8 @@
     FT_Pos           dist     = width;
     FT_Int           sign     = 0;
     FT_Int           vertical = AF_HINTS_DO_VERTICAL( hints );
-      
 
+
     if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
       return width;
 
@@ -1254,8 +1252,8 @@
       sign = 1;
     }
 
-    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAPPING( hints ) ) ||
-         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAPPING( hints ) ) )
+    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
+         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
     {
       /* smooth hinting process: very lightly quantize the stem width */
       /*                                                              */
@@ -1282,7 +1280,7 @@
         if ( axis->width_count > 0 )
         {
           delta = dist - axis->widths[0].cur;
-          
+
           if ( delta < 0 )
             delta = -delta;
 
@@ -1699,7 +1697,7 @@
           anchor    = edge;
         }
         else
-          edge->pos = anchor->pos + 
+          edge->pos = anchor->pos +
                       FT_PIX_ROUND( edge->opos - anchor->opos );
 
         edge->flags |= AF_EDGE_DONE;
@@ -1722,11 +1720,14 @@
                         AF_LatinMetrics  metrics )
   {
     AF_Dimension  dim;
-    
+
+    FT_UNUSED( scaler );
+    FT_UNUSED( metrics );
+
     for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
     {
-      if ( (dim == AF_DIMENSION_HORZ && AF_LATIN_HINTS_DO_HORIZONTAL(hints)) ||
-           (dim == AF_DIMENSION_VERT && AF_LATIN_HINTS_DO_VERTICAL(hints))   )
+      if ( (dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL(hints)) ||
+           (dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL(hints))   )
       {
         af_latin_hint_edges( hints, dim );
         af_glyph_hints_align_edge_points( hints, dim );
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -4,8 +4,8 @@
 #include "afhints.h"
 
 FT_BEGIN_HEADER
- 
- /* 
+
+ /*
   * the latin-specific script class
   *
   */
@@ -38,7 +38,7 @@
     AF_LATIN_BLUE_SMALL_TOP,
     AF_LATIN_BLUE_SMALL_BOTTOM,
     AF_LATIN_BLUE_SMALL_MINOR,
-    
+
     AF_LATIN_BLUE_MAX
   };
 
@@ -53,7 +53,7 @@
   {
     AF_LATIN_BLUE_ACTIVE = (1 << 0),
     AF_LATIN_BLUE_TOP    = (1 << 1),
-    
+
     AF_LATIN_BLUE_FLAG_MAX
   };
 
@@ -63,7 +63,7 @@
     AF_WidthRec   ref;
     AF_WidthRec   shoot;
     FT_UInt       flags;
-  
+
   } AF_LatinBlueRec, *AF_LatinBlue;
 
 
@@ -71,11 +71,11 @@
   {
     FT_Fixed         scale;
     FT_Pos           delta;
-    
+
     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;
@@ -89,7 +89,7 @@
     AF_ScriptMetricsRec   root;
     FT_UInt               units_per_em;
     AF_LatinAxisRec       axis[ AF_DIMENSION_MAX ];
-  
+
   } AF_LatinMetricsRec, *AF_LatinMetrics;
 
 
@@ -117,7 +117,7 @@
     AF_LATIN_HINTS_HORZ_SNAP   = (1 << 0),  /* enable stem width snapping  */
     AF_LATIN_HINTS_VERT_SNAP   = (1 << 1),  /* enable stem height snapping */
     AF_LATIN_HINTS_STEM_ADJUST = (1 << 2),  /* enable stem width/height adjustment */
-    AF_LATIN_HINTS_MONO        = (1 << 3),  /* indicate monochrome rendering */
+    AF_LATIN_HINTS_MONO        = (1 << 3)   /* indicate monochrome rendering */
   };
 
 #define  AF_LATIN_HINTS_DO_HORZ_SNAP(h) \
--- /dev/null
+++ b/src/autofit/afloader.c
@@ -1,0 +1,505 @@
+#include "afloader.h"
+#include "afhints.h"
+#include "afglobal.h"
+#include "aflatin.h"
+
+  FT_LOCAL_DEF( void )
+  af_loader_init( AF_Loader  loader,
+                  FT_Memory  memory )
+  {
+    FT_ZERO( loader );
+
+    af_glyph_hints_init( &loader->hints, memory );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  af_loader_reset( AF_Loader   loader,
+                   FT_Face     face )
+  {
+    FT_Error   error = 0;
+
+    FT_ZERO( loader );
+
+    loader->face    = face;
+    loader->gloader = face->slot->internal->loader;
+    loader->globals = (AF_FaceGlobals) face->autohint.data;
+
+    if ( loader->globals == NULL )
+    {
+      error = af_face_globals_new( &face, &loader->globals );
+      if ( !error )
+      {
+        face->autohint.data      = (FT_Pointer) loader->globals;
+        face->autohint.finalizer = (FT_Generic_Finalizer) af_face_globals_free;
+      }
+    }
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  af_loader_done( AF_Loader   loader )
+  {
+    loader->face    = face;
+    loader->globals = NULL;
+    loader->gloader = NULL;
+  }
+
+
+  static FT_Error
+  af_hinter_load_g( AF_Loader  loader,
+                    AF_Scaler  scaler,
+                    FT_UInt    glyph_index,
+                    FT_Int32   load_flags,
+                    FT_UInt    depth )
+  {
+    FT_Error          error    = 0;
+    FT_Face           face     = loader->face;
+    AF_FaceGlobals    globals  = loader->globals;
+    FT_GlyphLoader    gloader  = loader->gloader;
+    AF_ScriptMetrics  metrics  = loader->metrics;
+    AF_GlyphHints     hints    = &loader->hints;
+    FT_GlyphSlot      slot     = face->glyph;
+    FT_Slot_Internal  internal = slot->internal;
+
+    error = FT_Load_Glyph( face, glyph_index, load_flags );
+    if ( error )
+      goto Exit;
+
+    loader->transformed = internal->glyph_transformed;
+    if ( loader->transformed )
+    {
+      FT_Matrix  inverse;
+
+      loader->trans_matrix = internal->glyph_matrix;
+      loader->trans_delta  = internal->glyph_delta;
+
+      inverse = loader->trans_matrix;
+      FT_Matrix_Invert( &inverse );
+      FT_Vector_Transform( &loader->trans_delta, &inverse );
+    }
+
+    /* set linear metrics */
+    slot->linearHoriAdvance = slot->metrics.horiAdvance;
+    slot->linearVertAdvance = slot->metrics.vertAdvance;
+
+    switch ( slot->format )
+    {
+      case FT_GLYPH_FORMAT_OUTLINE:
+       /* translate the loaded glyph when an internal transform
+        * is needed
+        */
+        if ( loader->transformed )
+        {
+          FT_Vector*  point = slot->outline.points;
+          FT_Vector*  limit = point + slot->outline.n_points;
+
+          for ( ; point < limit; point++ )
+          {
+            point->x += loader->trans_delta.x;
+            point->y += loader->trans_delta.y;
+          }
+        }
+
+        /* copy the outline points in the loader's current               */
+        /* extra points which is used to keep original glyph coordinates */
+        error = FT_GlyphLoader_CheckPoints( gloader,
+                                            slot->outline.n_points + 2,
+                                            slot->outline.n_contours );
+        if ( error )
+          goto Exit;
+
+        FT_ARRAY_COPY( gloader->current.extra_points,
+                       slot->outline.points,
+                       slot->outline.n_points );
+
+        FT_ARRAY_COPY( gloader->current.outline.contours,
+                       slot->outline.contours,
+                       slot->outline.n_contours );
+
+        FT_ARRAY_COPY( gloader->current.outline.tags,
+                       slot->outline.tags,
+                       slot->outline.n_points );
+
+        gloader->current.outline.n_points   = slot->outline.n_points;
+        gloader->current.outline.n_contours = slot->outline.n_contours;
+
+        /* compute original phantom points */
+        loader->pp1.x = hints->x_delta;
+        loader->pp1.y = hints->y_delta;
+        loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
+                                   hints->x_scale ) + hints->x_delta;
+        loader->pp2.y = hints->y_delta;
+
+        /* be sure to check for spacing glyphs */
+        if ( slot->outline.n_points == 0 )
+          goto Hint_Metrics;
+
+        /* now load the slot image into the auto-outline and run the */
+        /* automatic hinting process                                 */
+        error = metrics->clazz->script_hints_init( hints, scaler,
+                                                   &gloader->current.outline,
+                                                   metrics );
+        if ( error )
+          goto Exit;
+
+        /* apply the hints */
+        error = metrics->clazz->script_hints_apply( hints, scaler,
+                                                    &gloader->current.outline,
+                                                    metrics );
+        if ( error )
+          goto Exit;
+
+        /* we now need to hint the metrics according to the change in */
+        /* width/positioning that occured during the hinting process  */
+        {
+          FT_Pos   old_advance, old_rsb, old_lsb, new_lsb;
+          AF_Edge  edge1 = outline->vert_edges;     /* leftmost edge  */
+          AF_Edge  edge2 = edge1 +
+                           outline->num_vedges - 1; /* rightmost edge */
+
+
+          old_advance = hinter->pp2.x;
+          old_rsb     = old_advance - edge2->opos;
+          old_lsb     = edge1->opos;
+          new_lsb     = edge1->pos;
+
+          hinter->pp1.x = FT_PIX_ROUND( new_lsb    - old_lsb );
+          hinter->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb );
+
+#if 0
+          /* try to fix certain bad advance computations */
+          if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
+            hinter->pp2.x += 64;
+#endif
+        }
+
+        /* good, we simply add the glyph to our loader's base */
+        FT_GlyphLoader_Add( gloader );
+        break;
+
+    case FT_GLYPH_FORMAT_COMPOSITE:
+      {
+        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
+        FT_UInt      num_base_subgs, start_point;
+        FT_SubGlyph  subglyph;
+
+
+        start_point = gloader->base.outline.n_points;
+
+        /* first of all, copy the subglyph descriptors in the glyph loader */
+        error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
+        if ( error )
+          goto Exit;
+
+        FT_ARRAY_COPY( gloader->current.subglyphs,
+                       slot->subglyphs,
+                       num_subglyphs );
+
+        gloader->current.num_subglyphs = num_subglyphs;
+        num_base_subgs = gloader->base.num_subglyphs;
+
+        /* now, read each subglyph independently */
+        for ( nn = 0; nn < num_subglyphs; nn++ )
+        {
+          FT_Vector  pp1, pp2;
+          FT_Pos     x, y;
+          FT_UInt    num_points, num_new_points, num_base_points;
+
+
+          /* gloader.current.subglyphs can change during glyph loading due */
+          /* to re-allocation -- we must recompute the current subglyph on */
+          /* each iteration                                                */
+          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+          pp1 = hinter->pp1;
+          pp2 = hinter->pp2;
+
+          num_base_points = gloader->base.outline.n_points;
+
+          error = af_loader_load_g( loader, scaler, subglyph->index,
+                                  load_flags, depth + 1 );
+          if ( error )
+            goto Exit;
+
+          /* recompute subglyph pointer */
+          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
+          {
+            pp1 = hinter->pp1;
+            pp2 = hinter->pp2;
+          }
+          else
+          {
+            hinter->pp1 = pp1;
+            hinter->pp2 = pp2;
+          }
+
+          num_points     = gloader->base.outline.n_points;
+          num_new_points = num_points - num_base_points;
+
+          /* now perform the transform required for this subglyph */
+
+          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
+                                   FT_SUBGLYPH_FLAG_XY_SCALE |
+                                   FT_SUBGLYPH_FLAG_2X2      ) )
+          {
+            FT_Vector*  cur   = gloader->base.outline.points +
+                                num_base_points;
+            FT_Vector*  org   = gloader->base.extra_points +
+                                num_base_points;
+            FT_Vector*  limit = cur + num_new_points;
+
+
+            for ( ; cur < limit; cur++, org++ )
+            {
+              FT_Vector_Transform( cur, &subglyph->transform );
+              FT_Vector_Transform( org, &subglyph->transform );
+            }
+          }
+
+          /* apply offset */
+
+          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
+          {
+            FT_Int      k = subglyph->arg1;
+            FT_UInt     l = subglyph->arg2;
+            FT_Vector*  p1;
+            FT_Vector*  p2;
+
+
+            if ( start_point + k >= num_base_points         ||
+                               l >= (FT_UInt)num_new_points )
+            {
+              error = FT_Err_Invalid_Composite;
+              goto Exit;
+            }
+
+            l += num_base_points;
+
+            /* for now, only use the current point coordinates;    */
+            /* we may consider another approach in the near future */
+            p1 = gloader->base.outline.points + start_point + k;
+            p2 = gloader->base.outline.points + start_point + l;
+
+            x = p1->x - p2->x;
+            y = p1->y - p2->y;
+          }
+          else
+          {
+            x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
+            y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;
+
+            x = FT_PIX_ROUND(x);
+            y = FT_PIX_ROUND(y);
+          }
+
+          {
+            FT_Outline  dummy = gloader->base.outline;
+
+
+            dummy.points  += num_base_points;
+            dummy.n_points = (short)num_new_points;
+
+            FT_Outline_Translate( &dummy, x, y );
+          }
+        }
+      }
+      break;
+
+    default:
+      /* we don't support other formats (yet?) */
+      error = AF_Err_Unimplemented_Feature;
+    }
+
+  Hint_Metrics:
+    if ( depth == 0 )
+    {
+      FT_BBox  bbox;
+
+
+      /* transform the hinted outline if needed */
+      if ( hinter->transformed )
+        FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
+
+      /* we must translate our final outline by -pp1.x and compute */
+      /* the new metrics                                           */
+      if ( hinter->pp1.x )
+        FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
+
+      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
+      bbox.xMin  = FT_PIX_FLOOR(  bbox.xMin );
+      bbox.yMin  = FT_PIX_FLOOR(  bbox.yMin );
+      bbox.xMax  = FT_PIX_CEIL( bbox.xMax );
+      bbox.yMax  = FT_PIX_CEIL( bbox.yMax );
+
+      slot->metrics.width        = bbox.xMax - bbox.xMin;
+      slot->metrics.height       = bbox.yMax - bbox.yMin;
+      slot->metrics.horiBearingX = bbox.xMin;
+      slot->metrics.horiBearingY = bbox.yMax;
+
+      /* for mono-width fonts (like Andale, Courier, etc.) we need */
+      /* to keep the original rounded advance width                */
+      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+        slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
+      else
+        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
+                                               x_scale );
+
+      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
+
+      /* now copy outline into glyph slot */
+      af_loader_rewind( slot->internal->loader );
+      error = af_loader_copy_points( slot->internal->loader, gloader );
+      if ( error )
+        goto Exit;
+
+      slot->outline = slot->internal->loader->base.outline;
+      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
+    }
+
+#ifdef DEBUG_HINTER
+    af_debug_hinter = hinter;
+#endif
+
+  Exit:
+    return error;
+  }
+
+
+
+
+
+  /* load and hint a given glyph */
+  FT_LOCAL_DEF( FT_Error )
+  af_loader_load_g( AF_Hinter     hinter,
+                    FT_GlyphSlot  slot,
+                    FT_Size       size,
+                    FT_UInt       glyph_index,
+                    FT_Int32      load_flags )
+  {
+    FT_Face          face         = slot->face;
+    FT_Error         error;
+    FT_Fixed         x_scale      = size->metrics.x_scale;
+    FT_Fixed         y_scale      = size->metrics.y_scale;
+    AF_Face_Globals  face_globals = FACE_GLOBALS( face );
+    FT_Render_Mode   hint_mode    = FT_LOAD_TARGET_MODE( load_flags );
+
+
+    /* first of all, we need to check that we're using the correct face and */
+    /* global hints to load the glyph                                       */
+    if ( hinter->face != face || hinter->globals != face_globals )
+    {
+      hinter->face = face;
+      if ( !face_globals )
+      {
+        error = af_hinter_new_face_globals( hinter, face, 0 );
+        if ( error )
+          goto Exit;
+
+      }
+      hinter->globals = FACE_GLOBALS( face );
+      face_globals    = FACE_GLOBALS( face );
+
+    }
+
+#ifdef FT_CONFIG_CHESTER_BLUE_SCALE
+
+   /* try to optimize the y_scale so that the top of non-capital letters
+    * is aligned on a pixel boundary whenever possible
+    */
+    {
+      AF_Globals  design = &face_globals->design;
+      FT_Pos      shoot  = design->blue_shoots[AF_BLUE_SMALL_TOP];
+
+
+      /* the value of 'shoot' will be -1000 if the font doesn't have */
+      /* small latin letters; we simply check the sign here...       */
+      if ( shoot > 0 )
+      {
+        FT_Pos  scaled = FT_MulFix( shoot, y_scale );
+        FT_Pos  fitted = FT_PIX_ROUND( scaled );
+
+
+        if ( scaled != fitted )
+        {
+         /* adjust y_scale
+          */
+          y_scale = FT_MulDiv( y_scale, fitted, scaled );
+
+         /* adust x_scale
+          */
+          if ( fitted < scaled )
+            x_scale -= x_scale / 50;  /* x_scale*0.98 with integers */
+        }
+      }
+    }
+
+#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */
+
+    /* now, we must check the current character pixel size to see if we */
+    /* need to rescale the global metrics                               */
+    if ( face_globals->x_scale != x_scale ||
+         face_globals->y_scale != y_scale )
+      af_hinter_scale_globals( hinter, x_scale, y_scale );
+
+    af_loader_rewind( hinter->loader );
+
+    /* reset hinting flags according to load flags and current render target */
+    hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
+    hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
+
+#ifdef DEBUG_HINTER
+    hinter->do_horz_hints = !af_debug_disable_vert;  /* not a bug, the meaning */
+    hinter->do_vert_hints = !af_debug_disable_horz;  /* of h/v is inverted!    */
+#endif
+
+    /* we snap the width of vertical stems for the monochrome and         */
+    /* horizontal LCD rendering targets only.  Corresponds to X snapping. */
+    hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+                                        hint_mode == FT_RENDER_MODE_LCD  );
+
+    /* we snap the width of horizontal stems for the monochrome and     */
+    /* vertical LCD rendering targets only.  Corresponds to Y snapping. */
+    hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO   ||
+                                        hint_mode == FT_RENDER_MODE_LCD_V  );
+
+    hinter->do_stem_adjust   = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
+
+    load_flags |= FT_LOAD_NO_SCALE
+                | FT_LOAD_IGNORE_TRANSFORM;
+    load_flags &= ~FT_LOAD_RENDER;
+
+    error = af_hinter_load( hinter, glyph_index, load_flags, 0 );
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  af_loader_load_glyph( AF_Loader   loader,
+                        AF_Scaler   scaler,
+                        FT_UInt     glyph_index )
+  {
+    FT_Error  error;
+    FT_Face   face = scaler->face;
+
+    error = af_loader_reset( loader, face );
+    if ( !error )
+    {
+      AF_ScriptMetrics  metrics;
+
+      error = af_face_globals_get_metrics( globals, gindex, &metrics );
+      if ( !error )
+      {
+        metrics->clazz->script_metrics_scale( metrics, scaler );
+
+        error = af_loader_load_g( loader, scaler, metrics, glyph_index,
+                                  /* load_flags */, 0 );
+      }
+    }
+    return error;
+  }
--- /dev/null
+++ b/src/autofit/afloader.h
@@ -1,0 +1,46 @@
+#ifndef __AF_LOADER_H__
+#define __AF_LOADER_H__
+
+#include "afhints.h"
+#include "afglobal.h"
+
+FT_BEGIN_HEADER
+
+  typedef struct AF_LoaderRec_
+  {
+    FT_Face           face;           /* current face */
+    AF_FaceGlobals    globals;        /* current face globals */
+    FT_GlyphLoader    gloader;        /* glyph loader */
+    AF_GlyphHintsRec  hints;
+    AF_ScriptMetrics  metrics;
+    FT_Bool           transformed;
+    FT_Matrix         trans_matrix;
+    FT_Vector         trans_delta;
+    FT_Vector         pp1;
+    FT_Vector         pp2;
+
+  } AF_LoaderRec, *AF_Loader;
+
+  FT_LOCAL( void )
+  af_loader_init( AF_Loader  loader,
+                  FT_Memory  memory );
+
+  FT_LOCAL( FT_Error )
+  af_loader_reset( AF_Loader   loader,
+                   FT_Face     face );
+
+  FT_LOCAL( void )
+  af_loader_done( AF_Loader   loader );
+
+  FT_LOCAL( FT_Error )
+  af_loader_load_glyph( AF_Loader   loader,
+                        FT_UInt     gindex,
+                        FT_UInt32   load_flags,
+                        FT_UInt     depth );
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AF_LOADER_H__ */
+
--- /dev/null
+++ b/src/autofit/afmodule.c
@@ -1,0 +1,437 @@
+#include "afmodule.h"
+#include "afhints.h"
+#include "afglobal.h"
+#include "aflatin.h"
+
+  static FT_Error
+  af_hinter_load( AF_Hinter  hinter,
+                  FT_UInt    glyph_index,
+                  FT_Int32   load_flags,
+                  FT_UInt    depth )
+  {
+    FT_Face           face     = hinter->face;
+    FT_GlyphSlot      slot     = face->glyph;
+    FT_Slot_Internal  internal = slot->internal;
+    FT_Fixed          x_scale  = hinter->globals->x_scale;
+    FT_Fixed          y_scale  = hinter->globals->y_scale;
+    FT_Error          error;
+    AF_Outline        outline  = hinter->glyph;
+    AF_Loader         gloader  = hinter->loader;
+
+
+    /* load the glyph */
+    error = FT_Load_Glyph( face, glyph_index, load_flags );
+    if ( error )
+      goto Exit;
+
+    /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
+    hinter->transformed = internal->glyph_transformed;
+
+    if ( hinter->transformed )
+    {
+      FT_Matrix  imatrix;
+
+
+      imatrix              = internal->glyph_matrix;
+      hinter->trans_delta  = internal->glyph_delta;
+      hinter->trans_matrix = imatrix;
+
+      FT_Matrix_Invert( &imatrix );
+      FT_Vector_Transform( &hinter->trans_delta, &imatrix );
+    }
+
+    /* set linear horizontal metrics */
+    slot->linearHoriAdvance = slot->metrics.horiAdvance;
+    slot->linearVertAdvance = slot->metrics.vertAdvance;
+
+    switch ( slot->format )
+    {
+    case FT_GLYPH_FORMAT_OUTLINE:
+
+      /* translate glyph outline if we need to */
+      if ( hinter->transformed )
+      {
+        FT_UInt     n     = slot->outline.n_points;
+        FT_Vector*  point = slot->outline.points;
+
+
+        for ( ; n > 0; point++, n-- )
+        {
+          point->x += hinter->trans_delta.x;
+          point->y += hinter->trans_delta.y;
+        }
+      }
+
+      /* copy the outline points in the loader's current               */
+      /* extra points which is used to keep original glyph coordinates */
+      error = af_loader_check_points( gloader, slot->outline.n_points + 2,
+                                      slot->outline.n_contours );
+      if ( error )
+        goto Exit;
+
+      FT_ARRAY_COPY( gloader->current.extra_points, slot->outline.points,
+                     slot->outline.n_points );
+
+      FT_ARRAY_COPY( gloader->current.outline.contours, slot->outline.contours,
+                     slot->outline.n_contours );
+
+      FT_ARRAY_COPY( gloader->current.outline.tags, slot->outline.tags,
+                     slot->outline.n_points );
+
+      gloader->current.outline.n_points   = slot->outline.n_points;
+      gloader->current.outline.n_contours = slot->outline.n_contours;
+
+      /* compute original phantom points */
+      hinter->pp1.x = 0;
+      hinter->pp1.y = 0;
+      hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
+      hinter->pp2.y = 0;
+
+      /* be sure to check for spacing glyphs */
+      if ( slot->outline.n_points == 0 )
+        goto Hint_Metrics;
+
+      /* now load the slot image into the auto-outline and run the */
+      /* automatic hinting process                                 */
+      error = af_outline_load( outline, x_scale, y_scale, face );
+      if ( error )
+        goto Exit;
+
+      /* perform feature detection */
+      af_outline_detect_features( outline );
+
+      if ( hinter->do_vert_hints )
+      {
+        af_outline_compute_blue_edges( outline, hinter->globals );
+        af_outline_scale_blue_edges( outline, hinter->globals );
+      }
+
+      /* perform alignment control */
+      af_hinter_hint_edges( hinter );
+      af_hinter_align( hinter );
+
+      /* now save the current outline into the loader's current table */
+      af_outline_save( outline, gloader );
+
+      /* we now need to hint the metrics according to the change in */
+      /* width/positioning that occured during the hinting process  */
+      {
+        FT_Pos   old_advance, old_rsb, old_lsb, new_lsb;
+        AF_Edge  edge1 = outline->vert_edges;     /* leftmost edge  */
+        AF_Edge  edge2 = edge1 +
+                         outline->num_vedges - 1; /* rightmost edge */
+
+
+        old_advance = hinter->pp2.x;
+        old_rsb     = old_advance - edge2->opos;
+        old_lsb     = edge1->opos;
+        new_lsb     = edge1->pos;
+
+        hinter->pp1.x = FT_PIX_ROUND( new_lsb    - old_lsb );
+        hinter->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb );
+
+#if 0
+        /* try to fix certain bad advance computations */
+        if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
+          hinter->pp2.x += 64;
+#endif
+      }
+
+      /* good, we simply add the glyph to our loader's base */
+      af_loader_add( gloader );
+      break;
+
+    case FT_GLYPH_FORMAT_COMPOSITE:
+      {
+        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
+        FT_UInt      num_base_subgs, start_point;
+        FT_SubGlyph  subglyph;
+
+
+        start_point = gloader->base.outline.n_points;
+
+        /* first of all, copy the subglyph descriptors in the glyph loader */
+        error = af_loader_check_subglyphs( gloader, num_subglyphs );
+        if ( error )
+          goto Exit;
+
+        FT_ARRAY_COPY( gloader->current.subglyphs, slot->subglyphs,
+                       num_subglyphs );
+
+        gloader->current.num_subglyphs = num_subglyphs;
+        num_base_subgs = gloader->base.num_subglyphs;
+
+        /* now, read each subglyph independently */
+        for ( nn = 0; nn < num_subglyphs; nn++ )
+        {
+          FT_Vector  pp1, pp2;
+          FT_Pos     x, y;
+          FT_UInt    num_points, num_new_points, num_base_points;
+
+
+          /* gloader.current.subglyphs can change during glyph loading due */
+          /* to re-allocation -- we must recompute the current subglyph on */
+          /* each iteration                                                */
+          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+          pp1 = hinter->pp1;
+          pp2 = hinter->pp2;
+
+          num_base_points = gloader->base.outline.n_points;
+
+          error = af_hinter_load( hinter, subglyph->index,
+                                  load_flags, depth + 1 );
+          if ( error )
+            goto Exit;
+
+          /* recompute subglyph pointer */
+          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
+          {
+            pp1 = hinter->pp1;
+            pp2 = hinter->pp2;
+          }
+          else
+          {
+            hinter->pp1 = pp1;
+            hinter->pp2 = pp2;
+          }
+
+          num_points     = gloader->base.outline.n_points;
+          num_new_points = num_points - num_base_points;
+
+          /* now perform the transform required for this subglyph */
+
+          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
+                                   FT_SUBGLYPH_FLAG_XY_SCALE |
+                                   FT_SUBGLYPH_FLAG_2X2      ) )
+          {
+            FT_Vector*  cur   = gloader->base.outline.points +
+                                num_base_points;
+            FT_Vector*  org   = gloader->base.extra_points +
+                                num_base_points;
+            FT_Vector*  limit = cur + num_new_points;
+
+
+            for ( ; cur < limit; cur++, org++ )
+            {
+              FT_Vector_Transform( cur, &subglyph->transform );
+              FT_Vector_Transform( org, &subglyph->transform );
+            }
+          }
+
+          /* apply offset */
+
+          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
+          {
+            FT_Int      k = subglyph->arg1;
+            FT_UInt     l = subglyph->arg2;
+            FT_Vector*  p1;
+            FT_Vector*  p2;
+
+
+            if ( start_point + k >= num_base_points         ||
+                               l >= (FT_UInt)num_new_points )
+            {
+              error = AF_Err_Invalid_Composite;
+              goto Exit;
+            }
+
+            l += num_base_points;
+
+            /* for now, only use the current point coordinates;    */
+            /* we may consider another approach in the near future */
+            p1 = gloader->base.outline.points + start_point + k;
+            p2 = gloader->base.outline.points + start_point + l;
+
+            x = p1->x - p2->x;
+            y = p1->y - p2->y;
+          }
+          else
+          {
+            x = FT_MulFix( subglyph->arg1, x_scale );
+            y = FT_MulFix( subglyph->arg2, y_scale );
+
+            x = FT_PIX_ROUND(x);
+            y = FT_PIX_ROUND(y);
+          }
+
+          {
+            FT_Outline  dummy = gloader->base.outline;
+
+
+            dummy.points  += num_base_points;
+            dummy.n_points = (short)num_new_points;
+
+            FT_Outline_Translate( &dummy, x, y );
+          }
+        }
+      }
+      break;
+
+    default:
+      /* we don't support other formats (yet?) */
+      error = AF_Err_Unimplemented_Feature;
+    }
+
+  Hint_Metrics:
+    if ( depth == 0 )
+    {
+      FT_BBox  bbox;
+
+
+      /* transform the hinted outline if needed */
+      if ( hinter->transformed )
+        FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
+
+      /* we must translate our final outline by -pp1.x and compute */
+      /* the new metrics                                           */
+      if ( hinter->pp1.x )
+        FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
+
+      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
+      bbox.xMin  = FT_PIX_FLOOR(  bbox.xMin );
+      bbox.yMin  = FT_PIX_FLOOR(  bbox.yMin );
+      bbox.xMax  = FT_PIX_CEIL( bbox.xMax );
+      bbox.yMax  = FT_PIX_CEIL( bbox.yMax );
+
+      slot->metrics.width        = bbox.xMax - bbox.xMin;
+      slot->metrics.height       = bbox.yMax - bbox.yMin;
+      slot->metrics.horiBearingX = bbox.xMin;
+      slot->metrics.horiBearingY = bbox.yMax;
+
+      /* for mono-width fonts (like Andale, Courier, etc.) we need */
+      /* to keep the original rounded advance width                */
+      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+        slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
+      else
+        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
+                                               x_scale );
+
+      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
+
+      /* now copy outline into glyph slot */
+      af_loader_rewind( slot->internal->loader );
+      error = af_loader_copy_points( slot->internal->loader, gloader );
+      if ( error )
+        goto Exit;
+
+      slot->outline = slot->internal->loader->base.outline;
+      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
+    }
+
+#ifdef DEBUG_HINTER
+    af_debug_hinter = hinter;
+#endif
+
+  Exit:
+    return error;
+  }
+
+
+  /* load and hint a given glyph */
+  FT_LOCAL_DEF( FT_Error )
+  af_hinter_load_glyph( AF_Hinter     hinter,
+                        FT_GlyphSlot  slot,
+                        FT_Size       size,
+                        FT_UInt       glyph_index,
+                        FT_Int32      load_flags )
+  {
+    FT_Face          face         = slot->face;
+    FT_Error         error;
+    FT_Fixed         x_scale      = size->metrics.x_scale;
+    FT_Fixed         y_scale      = size->metrics.y_scale;
+    AF_Face_Globals  face_globals = FACE_GLOBALS( face );
+    FT_Render_Mode   hint_mode    = FT_LOAD_TARGET_MODE( load_flags );
+
+
+    /* first of all, we need to check that we're using the correct face and */
+    /* global hints to load the glyph                                       */
+    if ( hinter->face != face || hinter->globals != face_globals )
+    {
+      hinter->face = face;
+      if ( !face_globals )
+      {
+        error = af_hinter_new_face_globals( hinter, face, 0 );
+        if ( error )
+          goto Exit;
+
+      }
+      hinter->globals = FACE_GLOBALS( face );
+      face_globals    = FACE_GLOBALS( face );
+
+    }
+
+#ifdef FT_CONFIG_CHESTER_BLUE_SCALE
+
+   /* try to optimize the y_scale so that the top of non-capital letters
+    * is aligned on a pixel boundary whenever possible
+    */
+    {
+      AF_Globals  design = &face_globals->design;
+      FT_Pos      shoot  = design->blue_shoots[AF_BLUE_SMALL_TOP];
+
+
+      /* the value of 'shoot' will be -1000 if the font doesn't have */
+      /* small latin letters; we simply check the sign here...       */
+      if ( shoot > 0 )
+      {
+        FT_Pos  scaled = FT_MulFix( shoot, y_scale );
+        FT_Pos  fitted = FT_PIX_ROUND( scaled );
+
+
+        if ( scaled != fitted )
+        {
+         /* adjust y_scale
+          */
+          y_scale = FT_MulDiv( y_scale, fitted, scaled );
+
+         /* adust x_scale
+          */
+          if ( fitted < scaled )
+            x_scale -= x_scale / 50;  /* x_scale*0.98 with integers */
+        }
+      }
+    }
+
+#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */
+
+    /* now, we must check the current character pixel size to see if we */
+    /* need to rescale the global metrics                               */
+    if ( face_globals->x_scale != x_scale ||
+         face_globals->y_scale != y_scale )
+      af_hinter_scale_globals( hinter, x_scale, y_scale );
+
+    af_loader_rewind( hinter->loader );
+
+    /* reset hinting flags according to load flags and current render target */
+    hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
+    hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
+
+#ifdef DEBUG_HINTER
+    hinter->do_horz_hints = !af_debug_disable_vert;  /* not a bug, the meaning */
+    hinter->do_vert_hints = !af_debug_disable_horz;  /* of h/v is inverted!    */
+#endif
+
+    /* we snap the width of vertical stems for the monochrome and         */
+    /* horizontal LCD rendering targets only.  Corresponds to X snapping. */
+    hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+                                        hint_mode == FT_RENDER_MODE_LCD  );
+
+    /* we snap the width of horizontal stems for the monochrome and     */
+    /* vertical LCD rendering targets only.  Corresponds to Y snapping. */
+    hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO   ||
+                                        hint_mode == FT_RENDER_MODE_LCD_V  );
+
+    hinter->do_stem_adjust   = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
+
+    load_flags |= FT_LOAD_NO_SCALE
+                | FT_LOAD_IGNORE_TRANSFORM;
+    load_flags &= ~FT_LOAD_RENDER;
+
+    error = af_hinter_load( hinter, glyph_index, load_flags, 0 );
+
+  Exit:
+    return error;
+  }
--- /dev/null
+++ b/src/autofit/afmodule.h
@@ -1,0 +1,5 @@
+#ifndef __AFMODULE_H__
+#define __AFMODULE_H__
+
+#endif /* __AFMODULE_H__ */
+
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -227,10 +227,12 @@
 
   typedef FT_Error  (*AF_Script_InitHintsFunc)( AF_GlyphHints     hints,
                                                 AF_Scaler         scaler,
+                                                FT_Outline*       outline,
                                                 AF_ScriptMetrics  metrics );
 
   typedef void      (*AF_Script_ApplyHintsFunc)( AF_GlyphHints     hints,
                                                  AF_Scaler         scaler,
+                                                 FT_Outline*       outline,
                                                  AF_ScriptMetrics  metrics );
 
 
--- /dev/null
+++ b/src/autofit/autofit.c
@@ -1,0 +1,7 @@
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "afangles.c"
+#include "afglobal.c"
+#include "afhints.c"
+#include "aflatin.c"