commited new Postscript hinter module
diff --git a/Jamfile b/Jamfile
index fa774b3..8fc419b 100644
--- a/Jamfile
+++ b/Jamfile
@@ -15,6 +15,13 @@
 
 FT2_LIB     = $(LIBPREFIX)freetype ;
 
+if $(DEBUG_HINTER)
+{
+  CCFLAGS += -DDEBUG_HINTER ;
+}
+
+
+
 # We need "freetype2/include" in the current include path in order to
 # compile any part of FreeType 2.
 #
@@ -38,8 +45,11 @@
 SubInclude  FT2_TOP src ;
 
 
-# tests files
+# tests files (hinter debugging)
 #
-SubInclude FT2_TOP tests ;
+if $(DEBUG_HINTER)
+{
+  SubInclude FT2_TOP tests ;
+}
 
 # end of top Jamfile
diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c
index d3af416..2ceaccc 100644
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -141,7 +141,7 @@
       FT_String*  name = (FT_String*)decoder->glyph_names[n];
 
 
-      if ( name && strcmp( name,glyph_name ) == 0 )
+      if ( name && name[0] == glyph_name[0] && strcmp( name,glyph_name ) == 0 )
         return n;
     }
 
@@ -245,6 +245,7 @@
       glyph->format        = ft_glyph_format_composite;
 
       loader->current.num_subglyphs = 2;
+      goto Exit;
     }
 
     /* First load `bchar' in builder */
@@ -318,7 +319,7 @@
     FT_Byte*          ip;
     FT_Byte*          limit;
     T1_Builder*       builder = &decoder->builder;
-    FT_Pos            x, y;
+    FT_Pos            x, y, orig_x, orig_y;
 
     T1_Hints_Funcs    hinter;
 
@@ -345,8 +346,8 @@
 
     error = PSaux_Err_Ok;
 
-    x = builder->pos_x;
-    y = builder->pos_y;
+    x = orig_x = builder->pos_x;
+    y = orig_y = builder->pos_y;
 
     /* begin hints recording session, if any */
     if ( hinter )
@@ -740,8 +741,8 @@
           builder->advance.x       = top[1];
           builder->advance.y       = 0;
 
-          builder->last.x = x = builder->pos_x + top[0];
-          builder->last.y = y = builder->pos_y;
+          orig_x = builder->last.x = x = builder->pos_x + top[0];
+          orig_y = builder->last.y = y = builder->pos_y;
 
           /* the `metrics_only' indicates that we only want to compute */
           /* the glyph's metrics (lsb + advance width), not load the   */
@@ -1016,7 +1017,7 @@
           /* record vertical  hint */
           if ( hinter )
           {
-            top[0] += builder->left_bearing.x;
+            top[0] += orig_x;
             hinter->stem( hinter->hints, 1, top );
           }
 
@@ -1027,8 +1028,14 @@
 
           /* record vertical counter-controlled hints */
           if ( hinter )
+          {
+            FT_Pos  dx = orig_x;
+            
+            top[0] += dx;
+            top[2] += dx;
+            top[4] += dx;
             hinter->stem3( hinter->hints, 1, top );
-                           
+          }
           break;
 
         case op_setcurrentpoint:
diff --git a/src/pshinter/Jamfile b/src/pshinter/Jamfile
index 081ded4..3b749f1 100644
--- a/src/pshinter/Jamfile
+++ b/src/pshinter/Jamfile
@@ -10,7 +10,7 @@
 
   if $(FT2_MULTI)
   {
-    _sources = pshrec pshglob pshfit pshmod pshoptim ;
+    _sources = pshrec pshglob pshalgo1 pshalgo2 pshmod ;
   }
   else
   {
diff --git a/src/pshinter/pshalgo.h b/src/pshinter/pshalgo.h
new file mode 100644
index 0000000..6419311
--- /dev/null
+++ b/src/pshinter/pshalgo.h
@@ -0,0 +1,19 @@
+#ifndef __PS_HINTER_ALGO_H__
+#define __PS_HINTER_ALGO_H__
+
+FT_BEGIN_HEADER
+
+/* define to choose hinting algorithm */
+#define  PSH_ALGORITHM_2
+
+#ifdef PSH_ALGORITHM_1
+#  include  "pshalgo1.h"
+#  define  PS_HINTS_APPLY_FUNC   ps1_hints_apply
+#else
+#  include  "pshalgo2.h"
+#  define  PS_HINTS_APPLY_FUNC   ps2_hints_apply
+#endif
+
+FT_END_HEADER
+
+#endif /* __PS_HINTER_ALGO_H__ */
diff --git a/src/pshinter/pshalgo1.c b/src/pshinter/pshalgo1.c
new file mode 100644
index 0000000..eaa82de
--- /dev/null
+++ b/src/pshinter/pshalgo1.c
@@ -0,0 +1,736 @@
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo1.h"
+
+#ifdef DEBUG_HINTER
+  extern  PSH1_Hint_Table  ps1_debug_hint_table = 0;
+  extern  PSH1_HintFunc    ps1_debug_hint_func  = 0;
+#endif
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 BASIC HINTS RECORDINGS                       *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+ 
+ /* return true iff two stem hints overlap */
+  static FT_Int
+  psh1_hint_overlap( PSH1_Hint  hint1,
+                     PSH1_Hint  hint2 )
+  {
+    return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+             hint2->org_pos + hint2->org_len >= hint1->org_pos );
+  }
+ 
+ 
+ /* destroy hints table */
+  static void
+  psh1_hint_table_done( PSH1_Hint_Table  table,
+                        FT_Memory        memory )
+  {
+    FREE( table->zones );
+    table->num_zones = 0;
+    table->zone      = 0;
+    
+    FREE( table->sort );
+    FREE( table->hints );
+    table->num_hints   = 0;
+    table->max_hints   = 0;
+    table->sort_global = 0;
+  }
+
+
+ /* deactivate all hints in a table */
+  static void
+  psh1_hint_table_deactivate( PSH1_Hint_Table  table )
+  {
+    FT_UInt   count = table->max_hints;
+    PSH1_Hint  hint  = table->hints;
+    
+    for ( ; count > 0; count--, hint++ )
+    {
+      psh1_hint_deactivate(hint);
+      hint->order = -1;
+    }
+  }
+
+
+ /* internal function used to record a new hint */
+  static void
+  psh1_hint_table_record( PSH1_Hint_Table  table,
+                          FT_UInt          index )
+  {
+    PSH1_Hint  hint = table->hints + index;
+
+    if ( index >= table->max_hints )
+    {
+      FT_ERROR(( "%s.activate: invalid hint index %d\n", index ));
+      return;
+    }
+        
+    /* ignore active hints */
+    if ( psh1_hint_is_active(hint) )
+      return;
+    
+    psh1_hint_activate(hint);
+    
+    /* now scan the current active hint set in order to determine */
+    /* if we're overlapping with another segment..                */
+    {
+      PSH1_Hint*  sorted = table->sort_global;
+      FT_UInt     count  = table->num_hints;
+      PSH1_Hint   hint2;
+
+      hint->parent = 0;      
+      for ( ; count > 0; count--, sorted++ )
+      {
+        hint2 = sorted[0];
+        
+        if ( psh1_hint_overlap( hint, hint2 ) )
+        {
+          hint->parent = hint2;
+          break;
+        }
+      }
+    }
+    
+    if ( table->num_hints < table->max_hints )
+      table->sort_global[ table->num_hints++ ] = hint;
+    else
+    {
+      FT_ERROR(( "%s.activate: too many sorted hints !! BUG !!\n",
+                 "ps.fitter" ));
+    }
+  }
+
+
+  static void
+  psh1_hint_table_record_mask( PSH1_Hint_Table  table,
+                               PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   index, limit;
+
+    limit = hint_mask->num_bits; 
+    
+    if ( limit != table->max_hints )
+    {
+      FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
+                 "ps.fitter", hint_mask->num_bits, table->max_hints ));
+    }
+        
+    for ( index = 0; index < limit; index++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+      
+      if ( val & mask )
+        psh1_hint_table_record( table, index );
+        
+      mask >>= 1;
+    }
+  }
+
+
+ /* create hints table */
+  static FT_Error
+  psh1_hint_table_init( PSH1_Hint_Table  table,
+                        PS_Hint_Table    hints,
+                        PS_Mask_Table    hint_masks,
+                        PS_Mask_Table    counter_masks,
+                        FT_Memory        memory )
+  {
+    FT_UInt   count = hints->num_hints;
+    FT_Error  error;
+
+    FT_UNUSED(counter_masks);
+    
+    /* allocate our tables */
+    if ( ALLOC_ARRAY( table->sort,  2*count,   PSH1_Hint    ) ||
+         ALLOC_ARRAY( table->hints,   count,   PSH1_HintRec ) ||
+         ALLOC_ARRAY( table->zones, 2*count+1, PSH1_ZoneRec ) )
+      goto Exit;
+    
+    table->max_hints   = count;
+    table->sort_global = table->sort + count;
+    table->num_hints   = 0;
+    table->num_zones   = 0;
+    table->zone        = 0;
+    
+    /* now, initialise the "hints" array */
+    {
+      PSH1_Hint  write = table->hints;
+      PS_Hint   read  = hints->hints;
+      
+      for ( ; count > 0; count--, write++, read++ )
+      {
+        write->org_pos = read->pos;
+        write->org_len = read->len;
+        write->flags   = read->flags;
+      }
+    }
+
+    /* we now need to determine the initial "parent" stems, first  */
+    /* activate the hints that are given by the initial hint masks */
+    if ( hint_masks )
+    {
+      FT_UInt  count = hint_masks->num_masks;
+      PS_Mask  mask  = hint_masks->masks;
+
+      table->hint_masks = hint_masks;
+      
+      for ( ; count > 0; count--, mask++ )
+        psh1_hint_table_record_mask( table, mask );
+    }
+    
+    /* now, do a linear parse in case some hints were left alone */
+    if ( table->num_hints != table->max_hints )
+    {
+      FT_UInt   index, count;
+      
+      FT_ERROR(( "%s.init: missing/incorrect hint masks !!\n" ));
+      count = table->max_hints;
+      for ( index = 0; index < count; index++ )
+        psh1_hint_table_record( table, index );
+    }    
+    
+  Exit:
+    return error;
+  }
+
+
+
+  static void
+  psh1_hint_table_activate_mask( PSH1_Hint_Table  table,
+                                 PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   index, limit, count;
+
+    limit = hint_mask->num_bits; 
+    count = 0;
+
+    psh1_hint_table_deactivate( table );
+    
+    for ( index = 0; index < limit; index++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+      
+      if ( val & mask )
+      {
+        PSH1_Hint  hint = &table->hints[index];
+        
+        if ( !psh1_hint_is_active(hint) )
+        {
+          PSH1_Hint*  sort   = table->sort;
+          FT_UInt    count2;
+          PSH1_Hint   hint2;
+          
+          for ( count2 = count; count2 > 0; count2--, sort++ )
+          {
+            hint2 = sort[0];
+            if ( psh1_hint_overlap( hint, hint2 ) )
+            {
+              FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+                         "psf.hint" ));
+              break;
+            }
+          }
+          
+          if ( count2 == 0 )
+          {
+            psh1_hint_activate( hint );
+            if ( count < table->max_hints )
+              table->sort[count++] = hint;
+            else
+            {
+              FT_ERROR(( "%s.activate_mask: too many active hints\n",
+                         "psf.hint" ));
+            } 
+          }
+        }
+      }
+        
+      mask >>= 1;
+    }
+    table->num_hints = count;
+    
+    /* now, sort the hints, they're guaranteed to not overlap */
+    /* so we can compare their "org_pos" field directly..     */
+    {
+      FT_Int     i1, i2;
+      PSH1_Hint   hint1, hint2;
+      PSH1_Hint*  sort = table->sort;
+
+      /* a simple bubble sort will do, since in 99% of cases, the hints */
+      /* will be already sorted.. and the sort will be linear           */
+      for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+      {
+        hint1 = sort[i1];
+        for ( i2 = i1-1; i2 >= 0; i2-- )
+        {
+          hint2 = sort[i2];
+          if ( hint2->org_pos < hint1->org_pos )
+            break;
+            
+          sort[i1] = hint2;
+          sort[i2] = hint1;
+        }
+      }
+    }
+  }
+
+
+
+
+
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****               HINTS GRID-FITTING AND OPTIMISATION            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+ 
+#ifdef DEBUG_HINTER
+  void
+  ps_simple_scale( PSH1_Hint_Table  table,
+                   FT_Fixed         scale,
+                   FT_Fixed         delta,
+                   FT_Bool          vertical )
+  {
+    PSH1_Hint  hint;
+    FT_UInt    count;
+  
+    for ( count = 0; count < table->num_hints; count++ )
+    {
+      hint = table->sort[count];
+      if ( psh1_hint_is_active(hint) )
+      {
+        hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+        hint->cur_len = FT_MulFix( hint->org_len, scale );
+        
+        if (ps1_debug_hint_func)
+          ps1_debug_hint_func( hint, vertical );
+      }
+    }
+  }                
+#endif
+
+  FT_LOCAL_DEF  FT_Error
+  psh1_hint_table_optimize( PSH1_Hint_Table  table,
+                            PSH_Globals      globals,
+                            FT_Outline*      outline,
+                            FT_Bool          vertical )
+  {
+    PSH_Dimension  dim   = &globals->dimension[vertical];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+#ifdef DEBUG_HINTER
+    if ( ps_debug_no_vert_hints && vertical )
+    {
+      ps_simple_scale( table, scale, delta, vertical );
+      return 0;
+    }
+      
+    if ( ps_debug_no_horz_hints && !vertical )
+    {
+      ps_simple_scale( table, scale, delta, vertical );
+      return 0;
+    }
+#endif
+
+    /* XXXX: for now, we only scale the hints to test all other aspects */
+    /*       of the Postscript Hinter..                                 */
+    {  
+      PSH1_Hint  hint;
+      FT_UInt   count;
+    
+      for ( count = 0; count < table->num_hints; count++ )
+      {
+        hint = table->sort[count];
+        if ( psh1_hint_is_active(hint) )
+        {
+# if 1
+          FT_Pos   pos = FT_MulFix( hint->org_pos, scale ) + delta;
+          FT_Pos   len = FT_MulFix( hint->org_len, scale );
+          
+          FT_Pos   fit_center;
+          FT_Pos   fit_len;
+          
+          PSH_AlignmentRec  align;
+
+          /* compute fitted width/height */
+          fit_len = psh_dimension_snap_width( dim, hint->org_len );
+          if ( fit_len < 64 )
+            fit_len = 64;
+          else
+            fit_len = (fit_len + 32 ) & -64;
+            
+          hint->cur_len = fit_len;
+            
+          /* check blue zones for horizontal stems */
+          align.align = 0;
+          if (!vertical)
+          {
+            psh_blues_snap_stem( &globals->blues,
+                                  hint->org_pos + hint->org_len,
+                                  hint->org_pos,
+                                  &align );
+          }
+
+          switch (align.align)
+          {
+            case PSH_BLUE_ALIGN_TOP:
+              {
+                /* the top of the stem is aligned against a blue zone */
+                hint->cur_pos = align.align_top - fit_len;
+                break;
+              }
+              
+            case PSH_BLUE_ALIGN_BOT:
+              {
+                /* the bottom of the stem is aligned against a blue zone */
+                hint->cur_pos = align.align_bot;
+                break;
+              }
+              
+            case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+              {
+                /* both edges of the stem are aligned against blue zones */
+                hint->cur_pos = align.align_bot;
+                hint->cur_len = align.align_top - align.align_bot;
+              }
+              break;
+              
+            default:
+              /* normal processing */
+              if ( (fit_len/64) & 1 )
+              {
+                /* odd number of pixels */
+                fit_center = ((pos + (len >> 1)) & -64) + 32;
+              }
+              else
+              {
+                /* even number of pixels */
+                fit_center = (pos + (len >> 1) + 32) & -64;
+              }
+              
+              hint->cur_pos = fit_center - (fit_len >> 1);
+          }
+# else
+          hint->cur_pos = (FT_MulFix( hint->org_pos, scale ) + delta + 32) & -64;
+          hint->cur_len =  FT_MulFix( hint->org_len, scale );
+# endif          
+
+#ifdef DEBUG_HINTER
+        if (ps1_debug_hint_func)
+          ps1_debug_hint_func( hint, vertical );
+#endif        
+        }
+      }
+    }
+    
+    return 0;
+  }
+
+
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****               POINTS INTERPOLATION ROUTINES                  *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+ 
+#define  PSH1_ZONE_MIN  -3200000
+#define  PSH1_ZONE_MAX  +3200000
+
+
+#define xxDEBUG_ZONES
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+  static void
+  print_zone( PSH1_Zone  zone )
+  {
+    printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+             zone->scale/65536.0,
+             zone->delta/64.0,
+             zone->min,
+             zone->max );
+  }
+
+#else
+#  define  print_zone(x)   do { } while (0)
+#endif
+
+ /* setup interpolation zones once the hints have been grid-fitted */
+ /* by the optimizer..                                             */
+  static void
+  psh1_hint_table_setup_zones( PSH1_Hint_Table  table,
+                               FT_Fixed         scale,
+                               FT_Fixed         delta )
+  {
+    FT_UInt   count;
+    PSH1_Zone  zone;
+    PSH1_Hint *sort, hint, hint2;
+    
+    zone  = table->zones;
+    
+    /* special case, no hints defined */
+    if ( table->num_hints == 0 )
+    {
+      zone->scale = scale;
+      zone->delta = delta;
+      zone->min   = PSH1_ZONE_MIN;
+      zone->max   = PSH1_ZONE_MAX;
+      
+      table->num_zones = 1;
+      table->zone      = zone;
+      return;
+    }
+    
+    /* the first zone is before the first hint */
+    /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
+    sort  = table->sort;
+    hint  = sort[0];
+    
+    zone->scale = scale;
+    zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
+    zone->min   = PSH1_ZONE_MIN;
+    zone->max   = hint->org_pos;
+    
+    print_zone( zone );
+    
+    zone++;
+    
+    for ( count = table->num_hints; count > 0; count-- )
+    {
+      FT_Fixed  scale2;
+
+      if ( hint->org_len > 0 )
+      {
+        /* setup a zone for inner-stem interpolation */
+        /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0)   */
+        /* x' = x*s2 + x0' - x0*s2                   */
+        
+        scale2      = FT_DivFix( hint->cur_len, hint->org_len );
+        zone->scale = scale2;
+        zone->min   = hint->org_pos;
+        zone->max   = hint->org_pos + hint->org_len;
+        zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
+
+        print_zone( zone );
+    
+        zone++;
+      }
+      
+      if ( count == 1 )
+        break;
+        
+      sort++;
+      hint2 = sort[0];
+      
+      /* setup zone for inter-stem interpolation */
+      /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1)     */
+      /* x' = x*s3 + x1' - x1*s3                 */
+      scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
+                          hint2->org_pos - (hint->org_pos + hint->org_len) );
+      zone->scale = scale2;
+      zone->min   = hint->org_pos + hint->org_len;
+      zone->max   = hint2->org_pos;
+      zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
+
+      print_zone( zone );
+    
+      zone++;
+      
+      hint  = hint2;
+    }
+
+    /* the last zone */
+    zone->scale = scale;
+    zone->min   = hint->org_pos + hint->org_len;
+    zone->max   = PSH1_ZONE_MAX;
+    zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale );
+
+    print_zone( zone );
+    
+    zone++;
+    
+    table->num_zones = zone - table->zones;
+    table->zone      = table->zones;
+  }
+
+
+ /* tune a single coordinate with the current interpolation zones */  
+  static FT_Pos
+  psh1_hint_table_tune_coord( PSH1_Hint_Table  table,
+                              FT_Int           coord )
+  {
+    PSH1_Zone   zone;
+    
+    zone = table->zone;
+      
+    if ( coord < zone->min )
+    {
+      do
+      {
+        if ( zone == table->zones )
+          break;
+          
+        zone--;
+      }
+      while ( coord < zone->min );
+      table->zone = zone;
+    }
+    else if ( coord > zone->max )
+    {
+      do
+      {
+        if ( zone == table->zones + table->num_zones - 1 )
+          break;
+          
+        zone++;
+      }
+      while ( coord > zone->max );
+      table->zone = zone;
+    }
+        
+    return FT_MulFix( coord, zone->scale ) + zone->delta;
+  }
+
+
+ /* tune a given outline with current interpolation zones */
+ /* the function only works in a single dimension..       */
+  static void
+  psh1_hint_table_tune_outline( PSH1_Hint_Table  table,
+                                FT_Outline*      outline,
+                                PSH_Globals      globals,
+                                FT_Bool          vertical )
+
+  {
+    FT_UInt         count, first, last;
+    PS_Mask_Table   hint_masks = table->hint_masks;
+    PS_Mask         mask;
+    PSH_Dimension  dim        = &globals->dimension[vertical];
+    FT_Fixed        scale      = dim->scale_mult;
+    FT_Fixed        delta      = dim->scale_delta;
+    
+    if ( hint_masks && hint_masks->num_masks > 0 )
+    {
+      first = 0;
+      mask  = hint_masks->masks;
+      count = hint_masks->num_masks;
+      for ( ; count > 0; count--, mask++ )
+      {
+        last = mask->end_point;
+        
+        if ( last > first )
+        {
+          FT_Vector*   vec;
+          FT_Int       count2;
+          
+          psh1_hint_table_activate_mask( table, mask );
+          psh1_hint_table_optimize( table, globals, outline, vertical );
+          psh1_hint_table_setup_zones( table, scale, delta );
+          last = mask->end_point;
+          
+          vec    = outline->points + first;
+          count2 = last - first;
+          for ( ; count2 > 0; count2--, vec++ )
+          {
+            FT_Pos  x, *px;
+            
+            px  = vertical ? &vec->x : &vec->y;
+            x   = *px;
+            
+            *px = psh1_hint_table_tune_coord( table, (FT_Int)x );
+          }
+        }
+          
+        first = last;
+      }
+    }
+    else    /* no hints in this glyph, simply scale the outline */
+    {
+      FT_Vector*  vec;
+      
+      vec   = outline->points;
+      count = outline->n_points;
+      
+      if ( vertical )
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->x = FT_MulFix( vec->x, scale ) + delta;
+      }
+      else
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->y = FT_MulFix( vec->y, scale ) + delta;
+      }
+    }
+  }
+  
+  
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                     HIGH-LEVEL INTERFACE                     *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+  
+  FT_Error
+  ps1_hints_apply( PS_Hints     ps_hints,
+                   FT_Outline*  outline,
+                   PSH_Globals  globals )
+  {
+    PSH1_Hint_TableRec  hints;
+    FT_Error           error;
+    FT_Int             dimension;
+    
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      PS_Dimension  dim = &ps_hints->dimension[dimension];
+      
+      /* initialise hints table */
+      memset( &hints, 0, sizeof(hints) );
+      error = psh1_hint_table_init( &hints,
+                                    &dim->hints,
+                                    &dim->masks,
+                                    &dim->counters,
+                                    ps_hints->memory );
+      if (error) goto Exit;
+      
+      psh1_hint_table_tune_outline( &hints,
+                                    outline,
+                                    globals,
+                                    dimension );
+                                   
+      psh1_hint_table_done( &hints, ps_hints->memory );
+    }
+    
+  Exit:
+    return error;                                   
+  }
diff --git a/src/pshinter/pshalgo1.h b/src/pshinter/pshalgo1.h
new file mode 100644
index 0000000..1b0dd5d
--- /dev/null
+++ b/src/pshinter/pshalgo1.h
@@ -0,0 +1,100 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo1.h                                                             */
+/*                                                                         */
+/*    First (basic) Postscript hinting routines                            */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#ifndef __PS_HINTER_ALGO1_H__
+#define __PS_HINTER_ALGO1_H__
+
+#include "pshrec.h"
+
+FT_BEGIN_HEADER
+
+  typedef struct PSH1_HintRec_*   PSH1_Hint;
+
+  typedef enum
+  {
+    PSH1_HINT_FLAG_GHOST  = PS_HINT_FLAG_GHOST,
+    PSH1_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
+    PSH1_HINT_FLAG_ACTIVE = 4
+  
+  } PSH1_Hint_Flags;
+
+#define  psh1_hint_is_active(x)  (((x)->flags  & PSH1_HINT_FLAG_ACTIVE) != 0)
+#define  psh1_hint_is_ghost(x)   (((x)->flags  & PSH1_HINT_FLAG_GHOST ) != 0)  
+
+#define  psh1_hint_activate(x)     (x)->flags |= PSH1_HINT_FLAG_ACTIVE
+#define  psh1_hint_deactivate(x)   (x)->flags &= ~PSH1_HINT_FLAG_ACTIVE
+
+  typedef struct PSH1_HintRec_
+  {
+    FT_Int    org_pos;
+    FT_Int    org_len;
+    FT_Pos    cur_pos;
+    FT_Pos    cur_len;
+    
+    FT_UInt   flags;
+    
+    PSH1_Hint  parent;
+    FT_Int    order;
+  
+  } PSH1_HintRec;
+
+
+ /* this is an interpolation zone used for strong points   */
+ /* weak points are interpolated according to their strong */
+ /* neighbours..                                           */
+  typedef struct PSH1_ZoneRec_
+  {
+    FT_Fixed  scale;
+    FT_Fixed  delta;
+    FT_Pos    min;
+    FT_Pos    max;
+    
+  } PSH1_ZoneRec, *PSH1_Zone;
+
+
+  typedef struct PSH1_Hint_TableRec_
+  {
+    FT_UInt        max_hints;
+    FT_UInt        num_hints;
+    PSH1_Hint      hints;
+    PSH1_Hint*     sort;
+    PSH1_Hint*     sort_global;
+    FT_UInt        num_zones;
+    PSH1_Zone      zones;
+    PSH1_Zone      zone;
+    PS_Mask_Table  hint_masks;
+    PS_Mask_Table  counter_masks;
+    
+  } PSH1_Hint_TableRec, *PSH1_Hint_Table;
+
+
+  extern FT_Error
+  ps1_hints_apply( PS_Hints      ps_hints,
+                   FT_Outline*   outline,
+                   PSH_Globals   globals );
+
+
+#ifdef DEBUG_HINTER
+  extern  PSH1_Hint_Table  ps1_debug_hint_table;
+
+  typedef void  (*PSH1_HintFunc)( PSH1_Hint  hint, FT_Bool vertical );
+  extern  PSH1_HintFunc    ps1_debug_hint_func;
+#endif
+
+FT_END_HEADER
+
+#endif /* __PS_HINTER_FITTER_H__ */
diff --git a/src/pshinter/pshalgo2.c b/src/pshinter/pshalgo2.c
new file mode 100644
index 0000000..c98aa78
--- /dev/null
+++ b/src/pshinter/pshalgo2.c
@@ -0,0 +1,1484 @@
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo2.h"
+
+
+#ifdef DEBUG_HINTER  
+  extern  PSH2_Hint_Table  ps2_debug_hint_table  = 0;
+  extern  PSH2_HintFunc    ps2_debug_hint_func   = 0;
+  extern  PSH2_Glyph       ps2_debug_glyph       = 0;
+#endif
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 BASIC HINTS RECORDINGS                       *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+ 
+ /* return true iff two stem hints overlap */
+  static FT_Int
+  psh2_hint_overlap( PSH2_Hint  hint1,
+                     PSH2_Hint  hint2 )
+  {
+    return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+             hint2->org_pos + hint2->org_len >= hint1->org_pos );
+  }
+ 
+ 
+ /* destroy hints table */
+  static void
+  psh2_hint_table_done( PSH2_Hint_Table  table,
+                        FT_Memory        memory )
+  {
+    FREE( table->zones );
+    table->num_zones = 0;
+    table->zone      = 0;
+    
+    FREE( table->sort );
+    FREE( table->hints );
+    table->num_hints   = 0;
+    table->max_hints   = 0;
+    table->sort_global = 0;
+  }
+
+
+ /* deactivate all hints in a table */
+  static void
+  psh2_hint_table_deactivate( PSH2_Hint_Table  table )
+  {
+    FT_UInt   count = table->max_hints;
+    PSH2_Hint  hint  = table->hints;
+    
+    for ( ; count > 0; count--, hint++ )
+    {
+      psh2_hint_deactivate(hint);
+      hint->order = -1;
+    }
+  }
+
+
+ /* internal function used to record a new hint */
+  static void
+  psh2_hint_table_record( PSH2_Hint_Table  table,
+                          FT_UInt          index )
+  {
+    PSH2_Hint  hint = table->hints + index;
+
+    if ( index >= table->max_hints )
+    {
+      FT_ERROR(( "%s.activate: invalid hint index %d\n", index ));
+      return;
+    }
+        
+    /* ignore active hints */
+    if ( psh2_hint_is_active(hint) )
+      return;
+    
+    psh2_hint_activate(hint);
+    
+    /* now scan the current active hint set in order to determine */
+    /* if we're overlapping with another segment..                */
+    {
+      PSH2_Hint*  sorted = table->sort_global;
+      FT_UInt     count  = table->num_hints;
+      PSH2_Hint   hint2;
+
+      hint->parent = 0;      
+      for ( ; count > 0; count--, sorted++ )
+      {
+        hint2 = sorted[0];
+        
+        if ( psh2_hint_overlap( hint, hint2 ) )
+        {
+          hint->parent = hint2;
+          break;
+        }
+      }
+    }
+    
+    if ( table->num_hints < table->max_hints )
+      table->sort_global[ table->num_hints++ ] = hint;
+    else
+    {
+      FT_ERROR(( "%s.activate: too many sorted hints !! BUG !!\n",
+                 "ps.fitter" ));
+    }
+  }
+
+
+  static void
+  psh2_hint_table_record_mask( PSH2_Hint_Table  table,
+                               PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   index, limit;
+
+    limit = hint_mask->num_bits; 
+    
+    if ( limit != table->max_hints )
+    {
+      FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
+                 "ps.fitter", hint_mask->num_bits, table->max_hints ));
+    }
+        
+    for ( index = 0; index < limit; index++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+      
+      if ( val & mask )
+        psh2_hint_table_record( table, index );
+        
+      mask >>= 1;
+    }
+  }
+
+
+ /* create hints table */
+  static FT_Error
+  psh2_hint_table_init( PSH2_Hint_Table  table,
+                        PS_Hint_Table    hints,
+                        PS_Mask_Table    hint_masks,
+                        PS_Mask_Table    counter_masks,
+                        FT_Memory        memory )
+  {
+    FT_UInt   count = hints->num_hints;
+    FT_Error  error;
+
+    FT_UNUSED(counter_masks);
+    
+    /* allocate our tables */
+    if ( ALLOC_ARRAY( table->sort,  2*count,   PSH2_Hint    ) ||
+         ALLOC_ARRAY( table->hints,   count,   PSH2_HintRec ) ||
+         ALLOC_ARRAY( table->zones, 2*count+1, PSH2_ZoneRec ) )
+      goto Exit;
+    
+    table->max_hints   = count;
+    table->sort_global = table->sort + count;
+    table->num_hints   = 0;
+    table->num_zones   = 0;
+    table->zone        = 0;
+    
+    /* now, initialise the "hints" array */
+    {
+      PSH2_Hint  write = table->hints;
+      PS_Hint   read  = hints->hints;
+      
+      for ( ; count > 0; count--, write++, read++ )
+      {
+        write->org_pos = read->pos;
+        write->org_len = read->len;
+        write->flags   = read->flags;
+      }
+    }
+
+    /* we now need to determine the initial "parent" stems, first  */
+    /* activate the hints that are given by the initial hint masks */
+    if ( hint_masks )
+    {
+      FT_UInt  count = hint_masks->num_masks;
+      PS_Mask  mask  = hint_masks->masks;
+
+      table->hint_masks = hint_masks;
+      
+      for ( ; count > 0; count--, mask++ )
+        psh2_hint_table_record_mask( table, mask );
+    }
+    
+    /* now, do a linear parse in case some hints were left alone */
+    if ( table->num_hints != table->max_hints )
+    {
+      FT_UInt   index, count;
+      
+      FT_ERROR(( "%s.init: missing/incorrect hint masks !!\n" ));
+      count = table->max_hints;
+      for ( index = 0; index < count; index++ )
+        psh2_hint_table_record( table, index );
+    }    
+    
+  Exit:
+    return error;
+  }
+
+
+
+  static void
+  psh2_hint_table_activate_mask( PSH2_Hint_Table  table,
+                                 PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   index, limit, count;
+
+    limit = hint_mask->num_bits; 
+    count = 0;
+
+    psh2_hint_table_deactivate( table );
+    
+    for ( index = 0; index < limit; index++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+      
+      if ( val & mask )
+      {
+        PSH2_Hint  hint = &table->hints[index];
+        
+        if ( !psh2_hint_is_active(hint) )
+        {
+          PSH2_Hint*  sort = table->sort;
+          FT_UInt     count2;
+          PSH2_Hint   hint2;
+          
+#if 0
+          for ( count2 = count; count2 > 0; count2--, sort++ )
+          {
+            hint2 = sort[0];
+            if ( psh2_hint_overlap( hint, hint2 ) )
+            {
+              FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+                         "psf.hint" ));
+            }
+          }
+#else
+          count2 = 0;
+#endif
+          
+          if ( count2 == 0 )
+          {
+            psh2_hint_activate( hint );
+            if ( count < table->max_hints )
+              table->sort[count++] = hint;
+            else
+            {
+              FT_ERROR(( "%s.activate_mask: too many active hints\n",
+                         "psf.hint" ));
+            } 
+          }
+        }
+      }
+        
+      mask >>= 1;
+    }
+    table->num_hints = count;
+    
+    /* now, sort the hints, they're guaranteed to not overlap */
+    /* so we can compare their "org_pos" field directly..     */
+    {
+      FT_Int     i1, i2;
+      PSH2_Hint   hint1, hint2;
+      PSH2_Hint*  sort = table->sort;
+
+      /* a simple bubble sort will do, since in 99% of cases, the hints */
+      /* will be already sorted.. and the sort will be linear           */
+      for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+      {
+        hint1 = sort[i1];
+        for ( i2 = i1-1; i2 >= 0; i2-- )
+        {
+          hint2 = sort[i2];
+          if ( hint2->org_pos < hint1->org_pos )
+            break;
+            
+          sort[i1] = hint2;
+          sort[i2] = hint1;
+        }
+      }
+    }
+  }
+
+
+
+
+
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****               HINTS GRID-FITTING AND OPTIMISATION            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+ 
+#ifdef DEBUG_HINTER
+  static void
+  ps_simple_scale( PSH2_Hint_Table  table,
+                   FT_Fixed         scale,
+                   FT_Fixed         delta,
+                   FT_Bool          vertical )
+  {
+    PSH2_Hint  hint;
+    FT_UInt    count;
+  
+    for ( count = 0; count < table->max_hints; count++ )
+    {
+      hint = table->hints + count;
+
+      hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      hint->cur_len = FT_MulFix( hint->org_len, scale );
+        
+      if (ps2_debug_hint_func)
+        ps2_debug_hint_func( hint, vertical );
+    }
+  }                
+#endif
+
+
+  static void
+  psh2_hint_align( PSH2_Hint    hint,
+                   PSH_Globals  globals,
+                   FT_Bool      vertical )
+  {
+    PSH_Dimension  dim   = &globals->dimension[vertical];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+    if ( !psh2_hint_is_fitted(hint) )
+    {      
+      FT_Pos   pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      FT_Pos   len = FT_MulFix( hint->org_len, scale );
+      
+      FT_Pos   fit_center;
+      FT_Pos   fit_len;
+      
+      PSH_AlignmentRec  align;
+
+      /* compute fitted width/height */
+      fit_len = 0;
+      if ( hint->org_len )
+      {
+        fit_len = psh_dimension_snap_width( dim, hint->org_len );
+        if ( fit_len < 64 )
+          fit_len = 64;
+        else
+          fit_len = (fit_len + 32 ) & -64;
+      }
+        
+      hint->cur_len = fit_len;
+        
+      /* check blue zones for horizontal stems */
+      align.align = 0;
+      if (!vertical)
+      {
+        psh_blues_snap_stem( &globals->blues,
+                              hint->org_pos + hint->org_len,
+                              hint->org_pos,
+                              &align );
+      }
+
+      switch (align.align)
+      {
+        case PSH_BLUE_ALIGN_TOP:
+          {
+            /* the top of the stem is aligned against a blue zone */
+            hint->cur_pos = align.align_top - fit_len;
+            break;
+          }
+          
+        case PSH_BLUE_ALIGN_BOT:
+          {
+            /* the bottom of the stem is aligned against a blue zone */
+            hint->cur_pos = align.align_bot;
+            break;
+          }
+          
+        case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+          {
+            /* both edges of the stem are aligned against blue zones */
+            hint->cur_pos = align.align_bot;
+            hint->cur_len = align.align_top - align.align_bot;
+            break;
+          }
+          
+        default:
+          {
+            PSH2_Hint  parent = hint->parent;
+            
+            if ( parent )
+            {
+              FT_Pos  par_org_center, par_cur_center;
+              FT_Pos  cur_org_center, cur_delta;
+              
+              /* ensure that parent is already fitted */
+              if ( !psh2_hint_is_fitted(parent) )
+                psh2_hint_align( parent, globals, vertical );
+                
+              par_org_center = parent->org_pos + (parent->org_len/2);
+              par_cur_center = parent->cur_pos + (parent->cur_len/2);
+              cur_org_center = hint->org_pos + (hint->org_len/2);
+              
+              cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+#if 0              
+              if ( cur_delta >= 0 )
+                cur_delta = (cur_delta+16) & -64;
+              else
+                cur_delta = -((-cur_delta+16) & -64);
+#endif
+              pos = par_cur_center + cur_delta - (len >> 1);
+            }
+
+            /* normal processing */
+            if ( (fit_len/64) & 1 )
+            {
+              /* odd number of pixels */
+              fit_center = ((pos + (len >> 1)) & -64) + 32;
+            }
+            else
+            {
+              /* even number of pixels */
+              fit_center = (pos + (len >> 1) + 32) & -64;
+            }
+          
+            hint->cur_pos = fit_center - (fit_len >> 1);
+          }
+      }
+      
+      psh2_hint_set_fitted(hint);
+      
+#ifdef DEBUG_HINTER
+      if (ps2_debug_hint_func)
+        ps2_debug_hint_func( hint, vertical );
+#endif
+    }
+  }                              
+
+
+  static void
+  psh2_hint_table_align_hints( PSH2_Hint_Table  table,
+                               PSH_Globals      globals,
+                               FT_Bool          vertical )
+  {
+    PSH_Dimension  dim   = &globals->dimension[vertical];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+    PSH2_Hint      hint;
+    FT_UInt        count;
+
+#ifdef DEBUG_HINTER
+    if ( ps_debug_no_vert_hints && vertical )
+    {
+      ps_simple_scale( table, scale, delta, vertical );
+      return;
+    }
+      
+    if ( ps_debug_no_horz_hints && !vertical )
+    {
+      ps_simple_scale( table, scale, delta, vertical );
+      return;
+    }
+#endif
+
+    hint  = table->hints;
+    count = table->max_hints;
+    for ( ; count > 0; count--, hint++ )
+      psh2_hint_align( hint, globals, vertical );
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****               POINTS INTERPOLATION ROUTINES                  *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+ 
+#define  PSH2_ZONE_MIN  -3200000
+#define  PSH2_ZONE_MAX  +3200000
+
+
+#define xxDEBUG_ZONES
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+  static void
+  print_zone( PSH2_Zone  zone )
+  {
+    printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+             zone->scale/65536.0,
+             zone->delta/64.0,
+             zone->min,
+             zone->max );
+  }
+
+#else
+#  define  print_zone(x)   do { } while (0)
+#endif
+
+ /* setup interpolation zones once the hints have been grid-fitted */
+ /* by the optimizer..                                             */
+  static void
+  psh2_hint_table_setup_zones( PSH2_Hint_Table  table,
+                               FT_Fixed         scale,
+                               FT_Fixed         delta )
+  {
+    FT_UInt   count;
+    PSH2_Zone  zone;
+    PSH2_Hint *sort, hint, hint2;
+    
+    zone  = table->zones;
+    
+    /* special case, no hints defined */
+    if ( table->num_hints == 0 )
+    {
+      zone->scale = scale;
+      zone->delta = delta;
+      zone->min   = PSH2_ZONE_MIN;
+      zone->max   = PSH2_ZONE_MAX;
+      
+      table->num_zones = 1;
+      table->zone      = zone;
+      return;
+    }
+    
+    /* the first zone is before the first hint */
+    /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
+    sort  = table->sort;
+    hint  = sort[0];
+    
+    zone->scale = scale;
+    zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
+    zone->min   = PSH2_ZONE_MIN;
+    zone->max   = hint->org_pos;
+    
+    print_zone( zone );
+    
+    zone++;
+    
+    for ( count = table->num_hints; count > 0; count-- )
+    {
+      FT_Fixed  scale2;
+
+      if ( hint->org_len > 0 )
+      {
+        /* setup a zone for inner-stem interpolation */
+        /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0)   */
+        /* x' = x*s2 + x0' - x0*s2                   */
+        
+        scale2      = FT_DivFix( hint->cur_len, hint->org_len );
+        zone->scale = scale2;
+        zone->min   = hint->org_pos;
+        zone->max   = hint->org_pos + hint->org_len;
+        zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
+
+        print_zone( zone );
+    
+        zone++;
+      }
+      
+      if ( count == 1 )
+        break;
+        
+      sort++;
+      hint2 = sort[0];
+      
+      /* setup zone for inter-stem interpolation */
+      /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1)     */
+      /* x' = x*s3 + x1' - x1*s3                 */
+      scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
+                          hint2->org_pos - (hint->org_pos + hint->org_len) );
+      zone->scale = scale2;
+      zone->min   = hint->org_pos + hint->org_len;
+      zone->max   = hint2->org_pos;
+      zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
+
+      print_zone( zone );
+    
+      zone++;
+      
+      hint  = hint2;
+    }
+
+    /* the last zone */
+    zone->scale = scale;
+    zone->min   = hint->org_pos + hint->org_len;
+    zone->max   = PSH2_ZONE_MAX;
+    zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale );
+
+    print_zone( zone );
+    
+    zone++;
+    
+    table->num_zones = zone - table->zones;
+    table->zone      = table->zones;
+  }
+
+
+ /* tune a single coordinate with the current interpolation zones */  
+  static FT_Pos
+  psh2_hint_table_tune_coord( PSH2_Hint_Table  table,
+                              FT_Int           coord )
+  {
+    PSH2_Zone   zone;
+    
+    zone = table->zone;
+      
+    if ( coord < zone->min )
+    {
+      do
+      {
+        if ( zone == table->zones )
+          break;
+          
+        zone--;
+      }
+      while ( coord < zone->min );
+      table->zone = zone;
+    }
+    else if ( coord > zone->max )
+    {
+      do
+      {
+        if ( zone == table->zones + table->num_zones - 1 )
+          break;
+          
+        zone++;
+      }
+      while ( coord > zone->max );
+      table->zone = zone;
+    }
+        
+    return FT_MulFix( coord, zone->scale ) + zone->delta;
+  }
+
+
+#if 0
+ /* tune a given outline with current interpolation zones */
+ /* the function only works in a single dimension..       */
+  static void
+  psh2_hint_table_tune_outline( PSH2_Hint_Table  table,
+                                FT_Outline*      outline,
+                                PSH_Globals      globals,
+                                FT_Bool          vertical )
+
+  {
+    FT_UInt        count, first, last;
+    PS_Mask_Table  hint_masks = table->hint_masks;
+    PS_Mask        mask;
+    PSH_Dimension  dim        = &globals->dimension[vertical];
+    FT_Fixed       scale      = dim->scale_mult;
+    FT_Fixed       delta      = dim->scale_delta;
+    
+    if ( hint_masks && hint_masks->num_masks > 0 )
+    {
+      first = 0;
+      mask  = hint_masks->masks;
+      count = hint_masks->num_masks;
+      for ( ; count > 0; count--, mask++ )
+      {
+        last = mask->end_point;
+        
+        if ( last > first )
+        {
+          FT_Vector*   vec;
+          FT_Int       count2;
+          
+          psh2_hint_table_activate_mask( table, mask );
+          psh2_hint_table_optimize( table, globals, outline, vertical );
+          psh2_hint_table_setup_zones( table, scale, delta );
+          last = mask->end_point;
+          
+          vec    = outline->points + first;
+          count2 = last - first;
+          for ( ; count2 > 0; count2--, vec++ )
+          {
+            FT_Pos  x, *px;
+            
+            px  = vertical ? &vec->x : &vec->y;
+            x   = *px;
+            
+            *px = psh2_hint_table_tune_coord( table, (FT_Int)x );
+          }
+        }
+          
+        first = last;
+      }
+    }
+    else    /* no hints in this glyph, simply scale the outline */
+    {
+      FT_Vector*  vec;
+      
+      vec   = outline->points;
+      count = outline->n_points;
+      
+      if ( vertical )
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->x = FT_MulFix( vec->x, scale ) + delta;
+      }
+      else
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->y = FT_MulFix( vec->y, scale ) + delta;
+      }
+    }
+  }
+#endif
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                    HINTER GLYPH MANAGEMENT                   *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static int
+  psh2_point_is_extremum( PSH2_Point  point )
+  {
+    PSH2_Point  before = point;
+    PSH2_Point  after  = point;
+    FT_Pos      d_before;
+    FT_Pos      d_after;
+
+    do
+    {
+      before = before->prev;
+      if ( before == point )
+        return 0;
+        
+      d_before = before->org_u - point->org_u;
+    }
+    while ( d_before == 0 );
+    
+    do
+    {
+      after = after->next;
+      if ( after == point )
+        return 0;
+        
+      d_after = after->org_u - point->org_u;
+    }
+    while ( d_after == 0 );
+
+    return ( ( d_before > 0 && d_after > 0 ) ||
+             ( d_before < 0 && d_after < 0 ) );
+  }
+
+
+
+  static void
+  psh2_glyph_done( PSH2_Glyph  glyph )
+  {
+    FT_Memory  memory = glyph->memory;
+
+    psh2_hint_table_done( &glyph->hint_tables[1], memory );
+    psh2_hint_table_done( &glyph->hint_tables[0], memory );
+    
+    FREE( glyph->points );
+    FREE( glyph->contours );
+
+    glyph->num_points   = 0;
+    glyph->num_contours = 0;
+
+    glyph->memory = 0;
+  }
+
+
+  static int
+  psh2_compute_dir( FT_Pos  dx, FT_Pos  dy )
+  {
+    FT_Pos  ax, ay;
+    int     result = PSH2_DIR_NONE;
+    
+    ax = ( dx >= 0 ) ? dx : -dx;
+    ay = ( dy >= 0 ) ? dy : -dy;
+    
+    if ( ay*12 < ax )
+    {
+      /* |dy| <<< |dx|  means a near-horizontal segment */
+      result = ( dx >= 0 ) ? PSH2_DIR_RIGHT : PSH2_DIR_LEFT;
+    }
+    else if ( ax*12 < ay )
+    {
+      /* |dx| <<< |dy|  means a near-vertical segment */
+      result = ( dy >= 0 ) ? PSH2_DIR_UP : PSH2_DIR_DOWN;
+    }
+    return result;
+  }
+
+
+  static FT_Error
+  psh2_glyph_init( PSH2_Glyph   glyph,
+                   FT_Outline*  outline,
+                   PS_Hints     ps_hints,
+                   PSH_Globals  globals )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+    
+    /* clear all fields */
+    memset( glyph, 0, sizeof(*glyph) );
+    
+    memory = globals->memory;
+    
+    /* allocate and setup points + contours arrays */
+    if ( ALLOC_ARRAY( glyph->points,   outline->n_points,   PSH2_PointRec   ) ||
+         ALLOC_ARRAY( glyph->contours, outline->n_contours, PSH2_ContourRec ) )
+      goto Exit;
+    
+    glyph->num_points   = outline->n_points;
+    glyph->num_contours = outline->n_contours;
+    
+    {
+      FT_UInt       first = 0, next, n;
+      PSH2_Point    points  = glyph->points;
+      PSH2_Contour  contour = glyph->contours;
+      
+      for ( n = 0; n < glyph->num_contours; n++ )
+      {
+        FT_Int      count;
+        PSH2_Point  point;
+        
+        next  = outline->contours[n] + 1;
+        count = next - first;
+        
+        contour->start = points + first;
+        contour->count = (FT_UInt)count;
+        
+        if ( count > 0 )
+        {
+          point = points + first;
+          
+          point->prev    = points + next - 1;
+          point->contour = contour;
+          for ( ; count > 1; count-- )
+          {
+            point[0].next = point + 1;
+            point[1].prev = point;
+            point++;
+            point->contour = contour;
+          }
+          point->next = points + first;
+        }
+
+        contour++; 
+        first = next;
+      }
+    }
+
+    {
+      PSH2_Point  points = glyph->points;
+      PSH2_Point  point  = points;
+      FT_Vector*  vec    = outline->points;
+      FT_UInt     n;
+      
+      for ( n = 0; n < glyph->num_points; n++, point++ )
+      {
+        FT_Int    n_prev = point->prev - points;
+        FT_Int    n_next = point->next - points;
+        FT_Pos    dxi, dyi, dxo, dyo;
+        
+        if ( !(outline->tags[n] & FT_Curve_Tag_On) )
+          point->flags = PSH2_POINT_OFF;
+        
+        dxi = vec[n].x - vec[n_prev].x;
+        dyi = vec[n].y - vec[n_prev].y;
+        
+        point->dir_in    = psh2_compute_dir( dxi, dyi );
+
+        dxo = vec[n_next].x - vec[n].x;
+        dyo = vec[n_next].y - vec[n].y;
+
+        point->dir_out   = psh2_compute_dir( dxo, dyo );
+        
+        /* detect smooth points */
+        if ( point->flags & PSH2_POINT_OFF )
+        {
+          point->flags |= PSH2_POINT_SMOOTH;
+        }
+        else if ( point->dir_in  != PSH2_DIR_NONE ||
+                  point->dir_out != PSH2_DIR_NONE )
+        {
+          if ( point->dir_in == point->dir_out )
+            point->flags |= PSH2_POINT_SMOOTH;
+        }
+        else
+        {
+          FT_Angle  angle_in, angle_out, diff;
+          
+          angle_in  = FT_Atan2( dxi, dyi );
+          angle_out = FT_Atan2( dxo, dyo );
+          
+          diff = angle_in - angle_out;
+          if ( diff < 0 )
+            diff = -diff;
+            
+          if ( diff > FT_ANGLE_PI )
+            diff = FT_ANGLE_2PI - diff;
+            
+          if ( (diff < FT_ANGLE_PI/16) )
+            point->flags |= PSH2_POINT_SMOOTH;
+        }
+      }
+    }
+
+    glyph->memory  = memory;
+    glyph->outline = outline;
+    glyph->globals = globals;
+
+    /* now deal with hints tables */
+    error = psh2_hint_table_init( &glyph->hint_tables [0],
+                                  &ps_hints->dimension[0].hints,
+                                  &ps_hints->dimension[0].masks,
+                                  &ps_hints->dimension[0].counters,
+                                  memory );
+    if (error) goto Exit;
+    
+    error = psh2_hint_table_init( &glyph->hint_tables [1],
+                                  &ps_hints->dimension[1].hints,
+                                  &ps_hints->dimension[1].masks,
+                                  &ps_hints->dimension[1].counters,
+                                  memory );
+    if (error) goto Exit;
+    
+  Exit:
+    return error;
+  }
+
+
+ /* load outline point coordinates into hinter glyph */
+  static void
+  psh2_glyph_load_points( PSH2_Glyph  glyph,
+                          FT_Bool     vertical )
+  {
+    FT_Vector*  vec   = glyph->outline->points;
+    PSH2_Point  point = glyph->points;
+    FT_UInt     count = glyph->num_points;
+
+    for ( ; count > 0; count--, point++, vec++ )
+    {
+      point->flags &= PSH2_POINT_OFF | PSH2_POINT_SMOOTH;
+      point->hint   = 0;
+      if (vertical)
+        point->org_u = vec->x;
+      else
+        point->org_u = vec->y;
+        
+#ifdef DEBUG_HINTER
+      point->org_x  = vec->x;
+      point->org_y  = vec->y;
+#endif        
+    }
+  }
+
+  
+ /* save hinted point coordinates back to outline */
+  static void
+  psh2_glyph_save_points( PSH2_Glyph  glyph,
+                          FT_Bool     vertical )
+  {
+    FT_UInt     n;
+    PSH2_Point  point = glyph->points;
+    FT_Vector*  vec   = glyph->outline->points;
+    char*       tags  = glyph->outline->tags;
+    
+    for ( n = 0; n < glyph->num_points; n++ )
+    { 
+      if (vertical)
+        vec[n].x = point->cur_u;
+      else
+        vec[n].y = point->cur_u;
+      
+      if ( psh2_point_is_strong(point) )
+        tags[n] |= vertical ? 32 : 64;
+
+#ifdef DEBUG_HINTER
+      if (vertical)
+      {
+        point->cur_x   = point->cur_u;
+        point->flags_x = point->flags;
+      }
+      else
+      {
+        point->cur_y   = point->cur_u;
+        point->flags_y = point->flags;
+      }
+#endif            
+      point++;
+    }
+  }
+
+
+  static void
+  psh2_hint_table_find_strong_point( PSH2_Hint_Table  table,
+                                     PSH2_Point       point,
+                                     FT_Int           major_dir )
+  {
+    PSH2_Hint*   sort      = table->sort;
+    FT_UInt      num_hints = table->num_hints;
+    
+    for ( ; num_hints > 0; num_hints--, sort++ )
+    {
+      PSH2_Hint  hint = sort[0];
+      
+      if ( ABS(point->dir_in)  == major_dir ||
+           ABS(point->dir_out) == major_dir )
+      {
+        FT_Pos  d;
+        
+        d = point->org_u - hint->org_pos;
+        if ( ABS(d) < 3 )
+        {
+        Is_Strong:
+          psh2_point_set_strong(point);
+          point->hint = hint;
+          break;
+        }
+        
+        d -= hint->org_len;
+        if ( ABS(d) < 3 )
+          goto Is_Strong;
+      }
+
+#if 1              
+      if ( point->org_u >= hint->org_pos &&
+           point->org_u <= hint->org_pos + hint->org_len &&
+           psh2_point_is_extremum( point ) )
+      {
+        /* attach to hint, but don't mark as strong */
+        point->hint = hint;
+        break;
+      }
+#endif                
+    }
+  }
+                                        
+                                         
+
+ /* find strong points in a glyph */
+  static void
+  psh2_glyph_find_strong_points( PSH2_Glyph  glyph,
+                                 FT_Bool     vertical )
+  {
+    /* a point is strong if it is located on a stem                   */
+    /* edge and has an "in" or "out" tangent to the hint's direction  */
+    {
+      PSH2_Hint_Table  table     = &glyph->hint_tables[vertical];
+      PS_Mask          mask      = table->hint_masks->masks;
+      FT_UInt          num_masks = table->hint_masks->num_masks;
+      FT_UInt          first     = 0;
+      FT_Int           major_dir = vertical ? PSH2_DIR_UP    : PSH2_DIR_RIGHT;
+      FT_Int           minor_dir = vertical ? PSH2_DIR_RIGHT : PSH2_DIR_UP;
+      
+      /* process secondary hints to "selected" points */
+      if ( num_masks > 1 )
+      {
+        mask++;
+        for ( ; num_masks > 1; num_masks--, mask++ )
+        {
+          FT_UInt  next;
+          FT_Int   count;
+          
+          next  = mask->end_point;
+          count = next - first;
+          if ( count > 0 )
+          {
+            PSH2_Point  point = glyph->points + first;
+            
+            psh2_hint_table_activate_mask( table, mask );
+            
+            for ( ; count > 0; count--, point++ )
+              psh2_hint_table_find_strong_point( table, point, major_dir );
+          }
+          first = next;
+        }
+      }
+      
+      /* process primary hints for all points */
+      if ( num_masks == 1 )
+      {
+        FT_UInt     count = glyph->num_points;
+        PSH2_Point  point = glyph->points;
+        
+        psh2_hint_table_activate_mask( table, table->hint_masks->masks );
+        for ( ; count > 0; count--, point++ )
+        {
+          if ( !psh2_point_is_strong(point) )
+            psh2_hint_table_find_strong_point( table, point, major_dir );
+        }
+      }
+      
+      /* now, certain points may have been attached to hint and */
+      /* not marked as strong, update their flags then..        */
+      {
+        FT_UInt  count = glyph->num_points;
+        PSH2_Point  point = glyph->points;
+        
+        for ( ; count > 0; count--, point++ )
+          if ( point->hint && !psh2_point_is_strong(point) )
+            psh2_point_set_strong(point);
+      }
+    }
+  }
+
+
+
+ /* interpolate strong points with the help of hinted coordinates */
+  static void
+  psh2_glyph_interpolate_strong_points( PSH2_Glyph  glyph,
+                                        FT_Bool     vertical )
+  {
+    PSH_Dimension    dim   = &glyph->globals->dimension[vertical];
+    FT_Fixed         scale = dim->scale_mult;
+    FT_Fixed         delta = dim->scale_delta;
+
+    {
+      FT_UInt     count = glyph->num_points;
+      PSH2_Point  point = glyph->points;
+      
+      for ( ; count > 0; count--, point++ )
+      {
+        PSH2_Hint  hint = point->hint;
+        
+        if ( hint )
+        {
+          FT_Pos  delta;
+          
+          delta = point->org_u - hint->org_pos;
+          
+          if ( delta <= 0 )
+            point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
+            
+          else if ( delta >= hint->org_len )
+            point->cur_u = hint->cur_pos + hint->cur_len +
+                           FT_MulFix( delta - hint->org_len, scale );
+                           
+          else if ( hint->org_len > 0 )
+            point->cur_u = hint->cur_pos +
+                           FT_MulDiv( delta, hint->cur_len, hint->org_len );
+          else
+            point->cur_u = hint->cur_pos;
+          
+          psh2_point_set_fitted(point);
+        } 
+      }
+    }
+  }
+
+
+  static void
+  psh2_glyph_interpolate_normal_points( PSH2_Glyph  glyph,
+                                        FT_Bool     vertical )
+  {
+#if 1
+    PSH_Dimension    dim   = &glyph->globals->dimension[vertical];
+    FT_Fixed         scale = dim->scale_mult;
+
+    /* first technique: a point is strong if it is a local extrema */
+    {
+      FT_UInt     count = glyph->num_points;
+      PSH2_Point  point = glyph->points;
+      
+      for ( ; count > 0; count--, point++ )
+      {
+        if ( psh2_point_is_strong(point) )
+          continue;
+          
+        /* sometimes, some local extremas are smooth points */
+        if ( psh2_point_is_smooth(point) )
+        {
+          if ( point->dir_in == PSH2_DIR_NONE  ||
+               point->dir_in != point->dir_out )
+            continue;
+            
+          if ( !psh2_point_is_extremum( point ) )
+            continue;
+            
+          point->flags &= ~PSH2_POINT_SMOOTH;
+        }
+          
+        /* find best enclosing point coordinates */
+        {
+          PSH2_Point  before = 0;
+          PSH2_Point  after  = 0;
+          
+          FT_Pos      diff_before = -32000;
+          FT_Pos      diff_after  =  32000;
+          FT_Pos      u = point->org_u;
+          
+          FT_Int      count2 = glyph->num_points;
+          PSH2_Point  cur    = glyph->points;
+          
+          for ( ; count2 > 0; count2--, cur++ )
+          {
+            if ( psh2_point_is_strong(cur) )
+            {
+              FT_Pos   diff = cur->org_u - u;;
+              
+              if ( diff <= 0 )
+              {
+                if ( diff > diff_before )
+                {
+                  diff_before = diff;
+                  before      = cur;
+                }
+              }
+              else if ( diff >= 0 )
+              {
+                if ( diff < diff_after )
+                {
+                  diff_after = diff;
+                  after      = cur;
+                }
+              }
+            }
+          }
+          
+          if ( !before )
+          {
+            if ( !after )
+              continue;
+              
+            /* we're before the first strong point coordinate */
+            /* simply translate the point..                   */
+            point->cur_u = after->cur_u +
+                           FT_MulFix( point->org_u - after->org_u, scale );
+          }
+          else if ( !after )
+          {
+            /* we're after the last strong point coordinate */
+            /* simply translate the point..                 */
+            point->cur_u = before->cur_u +
+                           FT_MulFix( point->org_u - before->org_u, scale );
+          }
+          else
+          {
+            if ( diff_before == 0 )
+              point->cur_u = before->cur_u;
+              
+            else if ( diff_after == 0 )
+              point->cur_u = after->cur_u;
+              
+            else
+              point->cur_u = before->cur_u + 
+                             FT_MulDiv( u - before->org_u,
+                                        after->cur_u - before->cur_u,
+                                        after->org_u - before->org_u );
+          }
+          
+          psh2_point_set_fitted(point);
+        }
+      }
+    }
+#endif    
+  }  
+
+
+
+ /* interpolate other points */
+  static void
+  psh2_glyph_interpolate_other_points( PSH2_Glyph  glyph,
+                                       FT_Bool     vertical )
+  {
+    PSH_Dimension dim          = &glyph->globals->dimension[vertical];
+    FT_Fixed      scale        = dim->scale_mult;
+    FT_Fixed      delta        = dim->scale_delta;
+    PSH2_Contour  contour      = glyph->contours;
+    FT_UInt       num_contours = glyph->num_contours;
+    
+    for ( ; num_contours > 0; num_contours--, contour++ )
+    {
+      PSH2_Point   start = contour->start;
+      PSH2_Point   first, next, point;
+      FT_UInt      fit_count;
+      
+      /* count the number of strong points in this contour */
+      next      = start + contour->count;
+      fit_count = 0;
+      first     = 0;
+      
+      for ( point = start; point < next; point++ )
+        if ( psh2_point_is_fitted(point) )
+        {
+          if ( !first )
+            first = point;
+            
+          fit_count++;
+        }
+      
+      /* if there is less than 2 fitted points in the contour, we'll */
+      /* simply scale and eventually translate the contour points    */
+      if ( fit_count < 2 )
+      {
+        if ( fit_count == 1 )
+          delta = first->cur_u - FT_MulFix( first->org_u, scale );
+          
+        for ( point = start; point < next; point++ )
+          if ( point != first )
+            point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
+            
+        goto Next_Contour;
+      }
+              
+      /* there are more than 2 strong points in this contour, we'll */
+      /* need to interpolate weak points between them..             */
+      start = first;
+      do
+      {
+        point = first;
+        
+        /* skip consecutive fitted points */
+        for (;;)
+        {
+          next = first->next; 
+          if ( next == start )
+            goto Next_Contour;
+            
+          if ( !psh2_point_is_fitted(next) )
+            break;
+            
+          first = next;
+        }
+        
+        /* find next fitted point after unfitted one */
+        for (;;)
+        {
+          next = next->next;
+          if ( psh2_point_is_fitted(next) )
+            break;
+        }
+        
+        /* now interpolate between them */
+        {
+          FT_Pos    org_a, org_ab, cur_a, cur_ab;
+          FT_Pos    org_c, org_ac, cur_c;
+          FT_Fixed  scale_ab;
+
+          if ( first->org_u <= next->org_u )
+          {
+            org_a  = first->org_u;
+            cur_a  = first->cur_u;
+            org_ab = next->org_u - org_a;
+            cur_ab = next->cur_u - cur_a;
+          }
+          else
+          {
+            org_a  = next->org_u;
+            cur_a  = next->cur_u;
+            org_ab = first->org_u - org_a;
+            cur_ab = first->cur_u - cur_a;
+          }
+          
+          scale_ab = 0x10000L;
+          if ( org_ab > 0 )
+            scale_ab = FT_DivFix( cur_ab, org_ab );
+            
+          point = first->next;
+          do
+          {
+            org_c  = point->org_u;
+            org_ac = org_c - org_a;
+            
+            if ( org_ac <= 0 )
+            {
+              /* on the left of the interpolation zone */
+              cur_c = cur_a + FT_MulFix( org_ac, scale );
+            }
+            else if ( org_ac >= org_ab )
+            {
+              /* on the right on the interpolation zone */
+              cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
+            }
+            else
+            { 
+              /* within the interpolation zone */
+              cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
+            }
+            
+            point->cur_u = cur_c;
+            
+            point = point->next;
+          }
+          while ( point != next );
+        }
+        
+        /* keep going until all points in the contours have been processed */  
+        first = next;
+      }
+      while ( first != start );
+      
+    Next_Contour:
+      ;
+    }
+  }
+  
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                     HIGH-LEVEL INTERFACE                     *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+  
+  FT_Error
+  ps2_hints_apply( PS_Hints     ps_hints,
+                   FT_Outline*  outline,
+                   PSH_Globals  globals )
+  {
+    PSH2_Glyph     glyph;
+    PSH2_GlyphRec  glyphrec;
+    FT_Error       error;
+    FT_Memory      memory;
+    FT_Int         dimension;
+
+    memory = globals->memory;
+
+#ifdef DEBUG_HINTER
+    if ( ps2_debug_glyph )
+    {
+      psh2_glyph_done( ps2_debug_glyph );
+      FREE( ps2_debug_glyph );
+    }
+    
+    if ( ALLOC( glyph, sizeof(*glyph) ) )
+      return error;
+      
+    ps2_debug_glyph = glyph;
+#else 
+    glyph = &glyphrec;    
+#endif
+    
+    error = psh2_glyph_init( glyph, outline, ps_hints, globals );
+    if (error) goto Exit;
+    
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      /* load outline coordinates into glyph */
+      psh2_glyph_load_points( glyph, dimension );
+      
+      /* compute aligned stem/hints positions */
+      psh2_hint_table_align_hints( &glyph->hint_tables[dimension],
+                                   glyph->globals,
+                                   dimension );
+
+      /* find strong points, align them, then interpolate others */
+      psh2_glyph_find_strong_points( glyph, dimension );
+      psh2_glyph_interpolate_strong_points( glyph, dimension );
+      psh2_glyph_interpolate_normal_points( glyph, dimension );
+      psh2_glyph_interpolate_other_points( glyph, dimension );
+      
+      /* save hinted coordinates back to outline */
+      psh2_glyph_save_points( glyph, dimension );
+    }
+    
+  Exit:    
+#ifndef DEBUG_HINTER  
+    psh2_glyph_done( glyph );
+#endif
+    return error;
+  }
diff --git a/src/pshinter/pshalgo2.h b/src/pshinter/pshalgo2.h
new file mode 100644
index 0000000..575712c
--- /dev/null
+++ b/src/pshinter/pshalgo2.h
@@ -0,0 +1,185 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo2.h                                                             */
+/*                                                                         */
+/*    First (basic) Postscript hinting routines                            */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#ifndef __PS_HINTER_ALGO2_H__
+#define __PS_HINTER_ALGO2_H__
+
+#include "pshrec.h"
+#include "pshglob.h"
+#include FT_TRIGONOMETRY_H
+
+FT_BEGIN_HEADER
+
+  typedef struct PSH2_HintRec_*   PSH2_Hint;
+
+  typedef enum
+  {
+    PSH2_HINT_GHOST  = PS_HINT_FLAG_GHOST,
+    PSH2_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
+    PSH2_HINT_ACTIVE = 4,
+    PSH2_HINT_FITTED = 8  
+  } PSH2_Hint_Flags;
+
+#define  psh2_hint_is_active(x)  (((x)->flags  & PSH2_HINT_ACTIVE) != 0)
+#define  psh2_hint_is_ghost(x)   (((x)->flags  & PSH2_HINT_GHOST)  != 0)  
+#define  psh2_hint_is_fitted(x)  (((x)->flags  & PSH2_HINT_FITTED) != 0)
+
+#define  psh2_hint_activate(x)     (x)->flags |=  PSH2_HINT_ACTIVE
+#define  psh2_hint_deactivate(x)   (x)->flags &= ~PSH2_HINT_ACTIVE
+#define  psh2_hint_set_fitted(x)   (x)->flags |=  PSH2_HINT_FITTED
+
+  typedef struct PSH2_HintRec_
+  {
+    FT_Int     org_pos;
+    FT_Int     org_len;
+    FT_Pos     cur_pos;
+    FT_Pos     cur_len;
+    FT_UInt    flags;
+    PSH2_Hint  parent;
+    FT_Int     order;
+  
+  } PSH2_HintRec;
+
+
+ /* this is an interpolation zone used for strong points   */
+ /* weak points are interpolated according to their strong */
+ /* neighbours..                                           */
+  typedef struct PSH2_ZoneRec_
+  {
+    FT_Fixed  scale;
+    FT_Fixed  delta;
+    FT_Pos    min;
+    FT_Pos    max;
+    
+  } PSH2_ZoneRec, *PSH2_Zone;
+
+
+  typedef struct PSH2_Hint_TableRec_
+  {
+    FT_UInt        max_hints;
+    FT_UInt        num_hints;
+    PSH2_Hint      hints;
+    PSH2_Hint*     sort;
+    PSH2_Hint*     sort_global;
+    FT_UInt        num_zones;
+    PSH2_Zone      zones;
+    PSH2_Zone      zone;
+    PS_Mask_Table  hint_masks;
+    PS_Mask_Table  counter_masks;
+    
+  } PSH2_Hint_TableRec, *PSH2_Hint_Table;
+
+  typedef struct PSH2_PointRec_*    PSH2_Point;
+  typedef struct PSH2_ContourRec_*  PSH2_Contour;
+  
+  enum
+  {
+    PSH2_DIR_NONE   =  4,
+    PSH2_DIR_UP     =  1,
+    PSH2_DIR_DOWN   = -1,
+    PSH2_DIR_LEFT   = -2,
+    PSH2_DIR_RIGHT  =  2
+  };
+  
+  enum
+  {
+    PSH2_POINT_OFF    = 1,   /* point is off the curve  */
+    PSH2_POINT_STRONG = 2,   /* point is strong         */
+    PSH2_POINT_SMOOTH = 4,   /* point is smooth         */
+    PSH2_POINT_FITTED = 8    /* point is already fitted */
+  };
+
+
+  typedef struct PSH2_PointRec_
+  {
+    PSH2_Point    prev;
+    PSH2_Point    next;
+    PSH2_Contour  contour;
+    FT_UInt       flags;
+    FT_Char       dir_in;
+    FT_Char       dir_out;
+    FT_Angle      angle_in;
+    FT_Angle      angle_out;
+    PSH2_Hint     hint;
+    FT_Pos        org_u;
+    FT_Pos        cur_u;
+#ifdef DEBUG_HINTER
+    FT_Pos        org_x;
+    FT_Pos        cur_x;
+    FT_Pos        org_y;
+    FT_Pos        cur_y;
+    FT_UInt       flags_x;
+    FT_UInt       flags_y;
+#endif    
+    
+  } PSH2_PointRec;
+
+#define  psh2_point_is_strong(p)   ((p)->flags & PSH2_POINT_STRONG)
+#define  psh2_point_is_fitted(p)   ((p)->flags & PSH2_POINT_FITTED)
+#define  psh2_point_is_smooth(p)   ((p)->flags & PSH2_POINT_SMOOTH)
+
+#define  psh2_point_set_strong(p)  (p)->flags |= PSH2_POINT_STRONG
+#define  psh2_point_set_fitted(p)  (p)->flags |= PSH2_POINT_FITTED
+#define  psh2_point_set_smooth(p)  (p)->flags |= PSH2_POINT_SMOOTH
+
+  typedef struct PSH2_ContourRec_
+  {
+    PSH2_Point  start;
+    FT_UInt     count;
+   
+  } PSH2_ContourRec;
+
+  
+
+  typedef struct PSH2_GlyphRec_
+  {
+    FT_UInt             num_points;
+    FT_UInt             num_contours;
+    
+    PSH2_Point          points;
+    PSH2_Contour        contours;
+               
+    FT_Memory           memory;
+    FT_Outline*         outline;
+    PSH_Globals         globals;
+    PSH2_Hint_TableRec  hint_tables[2];
+    
+    FT_Bool             vertical;
+    FT_Int              major_dir;
+    FT_Int              minor_dir;
+    
+  } PSH2_GlyphRec, *PSH2_Glyph;
+
+
+#ifdef DEBUG_HINTER  
+  extern  PSH2_Hint_Table  ps2_debug_hint_table;
+
+  typedef void  (*PSH2_HintFunc)( PSH2_Hint  hint, FT_Bool vertical );
+  extern  PSH2_HintFunc    ps2_debug_hint_func;
+  
+  extern  PSH2_Glyph       ps2_debug_glyph;
+#endif
+
+
+  extern FT_Error
+  ps2_hints_apply( PS_Hints      ps_hints,
+                   FT_Outline*   outline,
+                   PSH_Globals   globals );
+
+FT_END_HEADER
+
+#endif /* __PS_HINTS_ALGO_2_H__ */
diff --git a/src/pshinter/pshfit.c b/src/pshinter/pshfit.c
deleted file mode 100644
index 1f9a70b..0000000
--- a/src/pshinter/pshfit.c
+++ /dev/null
@@ -1,555 +0,0 @@
-#include <ft2build.h>
-#include FT_INTERNAL_OBJECTS_H
-#include FT_INTERNAL_DEBUG_H
-#include "pshfit.h"
-#include "pshoptim.h"
- 
- /* return true iff two stem hints overlap */
-  static FT_Int
-  psh_hint_overlap( PSH_Hint  hint1,
-                    PSH_Hint  hint2 )
-  {
-    return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
-             hint2->org_pos + hint2->org_len >= hint1->org_pos );
-  }
- 
- 
- /* destroy hints table */
-  static void
-  psh_hint_table_done( PSH_Hint_Table  table,
-                       FT_Memory       memory )
-  {
-    FREE( table->zones );
-    table->num_zones = 0;
-    table->zone      = 0;
-    
-    FREE( table->sort );
-    FREE( table->hints );
-    table->num_hints   = 0;
-    table->max_hints   = 0;
-    table->sort_global = 0;
-  }
-
-
- /* deactivate all hints in a table */
-  static void
-  psh_hint_table_deactivate( PSH_Hint_Table  table )
-  {
-    FT_UInt   count = table->max_hints;
-    PSH_Hint  hint  = table->hints;
-    
-    for ( ; count > 0; count--, hint++ )
-    {
-      psh_hint_deactivate(hint);
-      hint->order = -1;
-    }
-  }
-
-
- /* internal function used to record a new hint */
-  static void
-  psh_hint_table_record( PSH_Hint_Table  table,
-                         FT_UInt         index )
-  {
-    PSH_Hint  hint = table->hints + index;
-
-    if ( index >= table->max_hints )
-    {
-      FT_ERROR(( "%s.activate: invalid hint index %d\n", index ));
-      return;
-    }
-        
-    /* ignore active hints */
-    if ( psh_hint_is_active(hint) )
-      return;
-    
-    psh_hint_activate(hint);
-    
-    /* now scan the current active hint set in order to determine */
-    /* if we're overlapping with another segment..                */
-    {
-      PSH_Hint*  sorted = table->sort_global;
-      FT_UInt    count  = table->num_hints;
-      PSH_Hint   hint2;
-
-      hint->parent = 0;      
-      for ( ; count > 0; count--, sorted++ )
-      {
-        hint2 = sorted[0];
-        
-        if ( psh_hint_overlap( hint, hint2 ) )
-        {
-          hint->parent = hint2;
-          break;
-        }
-      }
-    }
-    
-    if ( table->num_hints < table->max_hints )
-      table->sort_global[ table->num_hints++ ] = hint;
-    else
-    {
-      FT_ERROR(( "%s.activate: too many sorted hints !! BUG !!\n",
-                 "ps.fitter" ));
-    }
-  }
-
-
-  static void
-  psh_hint_table_record_mask( PSH_Hint_Table  table,
-                              PS_Mask         hint_mask )
-  {
-    FT_Int    mask = 0, val = 0;
-    FT_Byte*  cursor = hint_mask->bytes;
-    FT_UInt   index, limit;
-
-    limit = hint_mask->num_bits; 
-    
-    if ( limit != table->max_hints )
-    {
-      FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
-                 "ps.fitter", hint_mask->num_bits, table->max_hints ));
-    }
-        
-    for ( index = 0; index < limit; index++ )
-    {
-      if ( mask == 0 )
-      {
-        val  = *cursor++;
-        mask = 0x80;
-      }
-      
-      if ( val & mask )
-        psh_hint_table_record( table, index );
-        
-      mask >>= 1;
-    }
-  }
-
-
- /* create hints table */
-  static FT_Error
-  psh_hint_table_init( PSH_Hint_Table  table,
-                       PS_Hint_Table   hints,
-                       PS_Mask_Table   hint_masks,
-                       PS_Mask_Table   counter_masks,
-                       FT_Memory       memory )
-  {
-    FT_UInt   count = hints->num_hints;
-    FT_Error  error;
-
-    FT_UNUSED(counter_masks);
-    
-    /* allocate our tables */
-    if ( ALLOC_ARRAY( table->sort,  2*count,   PSH_Hint    ) ||
-         ALLOC_ARRAY( table->hints,   count,   PSH_HintRec ) ||
-         ALLOC_ARRAY( table->zones, 2*count+1, PSH_ZoneRec ) )
-      goto Exit;
-    
-    table->max_hints   = count;
-    table->sort_global = table->sort + count;
-    table->num_hints   = 0;
-    table->num_zones   = 0;
-    table->zone        = 0;
-    
-    /* now, initialise the "hints" array */
-    {
-      PSH_Hint  write = table->hints;
-      PS_Hint   read  = hints->hints;
-      
-      for ( ; count > 0; count--, write++, read++ )
-      {
-        write->org_pos = read->pos;
-        write->org_len = read->len;
-        write->flags   = read->flags;
-      }
-    }
-
-    /* we now need to determine the initial "parent" stems, first  */
-    /* activate the hints that are given by the initial hint masks */
-    if ( hint_masks )
-    {
-      FT_UInt  count = hint_masks->num_masks;
-      PS_Mask  mask  = hint_masks->masks;
-
-      table->hint_masks = hint_masks;
-      
-      for ( ; count > 0; count--, mask++ )
-        psh_hint_table_record_mask( table, mask );
-    }
-    
-    /* now, do a linear parse in case some hints were left alone */
-    if ( table->num_hints != table->max_hints )
-    {
-      FT_UInt   index, count;
-      
-      FT_ERROR(( "%s.init: missing/incorrect hint masks !!\n" ));
-      count = table->max_hints;
-      for ( index = 0; index < count; index++ )
-        psh_hint_table_record( table, index );
-    }    
-    
-  Exit:
-    return error;
-  }
-
-
-
-  static void
-  psh_hint_table_activate_mask( PSH_Hint_Table  table,
-                                PS_Mask         hint_mask )
-  {
-    FT_Int    mask = 0, val = 0;
-    FT_Byte*  cursor = hint_mask->bytes;
-    FT_UInt   index, limit, count;
-
-    limit = hint_mask->num_bits; 
-    count = 0;
-
-    psh_hint_table_deactivate( table );
-    
-    for ( index = 0; index < limit; index++ )
-    {
-      if ( mask == 0 )
-      {
-        val  = *cursor++;
-        mask = 0x80;
-      }
-      
-      if ( val & mask )
-      {
-        PSH_Hint  hint = &table->hints[index];
-        
-        if ( !psh_hint_is_active(hint) )
-        {
-          PSH_Hint*  sort   = table->sort;
-          FT_UInt    count2;
-          PSH_Hint   hint2;
-          
-          for ( count2 = count; count2 > 0; count2--, sort++ )
-          {
-            hint2 = sort[0];
-            if ( psh_hint_overlap( hint, hint2 ) )
-            {
-              FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
-                         "psf.hint" ));
-              break;
-            }
-          }
-          
-          if ( count2 == 0 )
-          {
-            psh_hint_activate( hint );
-            if ( count < table->max_hints )
-              table->sort[count++] = hint;
-            else
-            {
-              FT_ERROR(( "%s.activate_mask: too many active hints\n",
-                         "psf.hint" ));
-            } 
-          }
-        }
-      }
-        
-      mask >>= 1;
-    }
-    table->num_hints = count;
-    
-    /* now, sort the hints, they're guaranteed to not overlap */
-    /* so we can compare their "org_pos" field directly..     */
-    {
-      FT_Int     i1, i2;
-      PSH_Hint   hint1, hint2;
-      PSH_Hint*  sort = table->sort;
-
-      /* a simple bubble sort will do, since in 99% of cases, the hints */
-      /* will be already sorted.. and the sort will be linear           */
-      for ( i1 = 1; i1 < (FT_Int)count; i1++ )
-      {
-        hint1 = sort[i1];
-        for ( i2 = i1-1; i2 >= 0; i2-- )
-        {
-          hint2 = sort[i2];
-          if ( hint2->org_pos < hint1->org_pos )
-            break;
-            
-          sort[i1] = hint2;
-          sort[i2] = hint1;
-        }
-      }
-    }
-  }
-
-
-#define  PSH_ZONE_MIN  -3200000
-#define  PSH_ZONE_MAX  +3200000
-
-
-#define xxDEBUG_ZONES
-
-#ifdef DEBUG_ZONES
-
-#include <stdio.h>
-
-  static void
-  print_zone( PSH_Zone  zone )
-  {
-    printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
-             zone->scale/65536.0,
-             zone->delta/64.0,
-             zone->min,
-             zone->max );
-  }
-
-#else
-#  define  print_zone(x)   do { } while (0)
-#endif
-
- /* setup interpolation zones once the hints have been grid-fitted */
- /* by the optimizer..                                             */
-  static void
-  psh_hint_table_setup_zones( PSH_Hint_Table  table,
-                              FT_Fixed        scale,
-                              FT_Fixed        delta )
-  {
-    FT_UInt   count;
-    PSH_Zone  zone;
-    PSH_Hint *sort, hint, hint2;
-    
-    zone  = table->zones;
-    
-    /* special case, no hints defined */
-    if ( table->num_hints == 0 )
-    {
-      zone->scale = scale;
-      zone->delta = delta;
-      zone->min   = PSH_ZONE_MIN;
-      zone->max   = PSH_ZONE_MAX;
-      table->num_zones = 1;
-      return;
-    }
-    
-    /* the first zone is before the first hint */
-    /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
-    sort  = table->sort;
-    hint  = sort[0];
-    
-    zone->scale = scale;
-    zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
-    zone->min   = PSH_ZONE_MIN;
-    zone->max   = hint->org_pos;
-    
-    print_zone( zone );
-    
-    zone++;
-    
-    for ( count = table->num_hints; count > 0; count-- )
-    {
-      FT_Fixed  scale2;
-
-      if ( hint->org_len > 0 )
-      {
-        /* setup a zone for inner-stem interpolation */
-        /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0)   */
-        /* x' = x*s2 + x0' - x0*s2                   */
-        
-        scale2      = FT_DivFix( hint->cur_len, hint->org_len );
-        zone->scale = scale2;
-        zone->min   = hint->org_pos;
-        zone->max   = hint->org_pos + hint->org_len;
-        zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
-
-        print_zone( zone );
-    
-        zone++;
-      }
-      
-      if ( count == 1 )
-        break;
-        
-      sort++;
-      hint2 = sort[0];
-      
-      /* setup zone for inter-stem interpolation */
-      /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1)     */
-      /* x' = x*s3 + x1' - x1*s3                 */
-      scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
-                          hint2->org_pos - (hint->org_pos + hint->org_len) );
-      zone->scale = scale2;
-      zone->min   = hint->org_pos + hint->org_len;
-      zone->max   = hint2->org_pos;
-      zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
-
-      print_zone( zone );
-    
-      zone++;
-      
-      hint  = hint2;
-    }
-
-    /* the last zone */
-    zone->scale = scale;
-    zone->min   = hint->org_pos + hint->org_len;
-    zone->max   = PSH_ZONE_MAX;
-    zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale );
-
-    print_zone( zone );
-    
-    zone++;
-    
-    table->num_zones = zone - table->zones;
-    table->zone      = table->zones;
-  }
-
-
- /* tune a single coordinate with the current interpolation zones */  
-  static FT_Pos
-  psh_hint_table_tune_coord( PSH_Hint_Table  table,
-                             FT_Int          coord )
-  {
-    PSH_Zone   zone;
-    
-    zone = table->zone;
-      
-    if ( coord < zone->min )
-    {
-      do
-      {
-        if ( zone == table->zones )
-          break;
-          
-        zone--;
-      }
-      while ( coord < zone->min );
-      table->zone = zone;
-    }
-    else if ( coord > zone->max )
-    {
-      do
-      {
-        if ( zone == table->zones + table->num_zones - 1 )
-          break;
-          
-        zone++;
-      }
-      while ( coord > zone->max );
-      table->zone = zone;
-    }
-        
-    return FT_MulFix( coord, zone->scale ) + zone->delta;
-  }
-
-
- /* tune a given outline with current interpolation zones */
- /* the function only works in a single dimension..       */
-  static void
-  psh_hint_table_tune_outline( PSH_Hint_Table  table,
-                               FT_Outline*     outline,
-                               PSH_Globals     globals,
-                               FT_Bool         vertical )
-
-  {
-    FT_UInt        count, first, last;
-    PS_Mask_Table  hint_masks = table->hint_masks;
-    PS_Mask        mask;
-    PSH_Dimension  dim        = &globals->dimension[vertical];
-    FT_Fixed       scale      = dim->scale_mult;
-    FT_Fixed       delta      = dim->scale_delta;
-    
-    if ( hint_masks && hint_masks->num_masks > 0 )
-    {
-      first = 0;
-      mask  = hint_masks->masks;
-      count = hint_masks->num_masks;
-      for ( ; count > 0; count--, mask++ )
-      {
-        last = mask->end_point;
-        
-        if ( last > first )
-        {
-          FT_Vector*   vec;
-          FT_Int       count2;
-          
-          psh_hint_table_activate_mask( table, mask );
-          psh_hint_table_optimize( table, globals, outline, vertical );
-          psh_hint_table_setup_zones( table, scale, delta );
-          last = mask->end_point;
-          
-          vec    = outline->points + first;
-          count2 = last - first;
-          for ( ; count2 > 0; count2--, vec++ )
-          {
-            FT_Pos  x, *px;
-            
-            px  = vertical ? &vec->x : &vec->y;
-            x   = *px;
-            
-            *px = psh_hint_table_tune_coord( table, (FT_Int)x );
-          }
-        }
-          
-        first = last;
-      }
-    }
-    else    /* no hints in this glyph, simply scale the outline */
-    {
-      FT_Vector*  vec;
-      
-      vec   = outline->points;
-      count = outline->n_points;
-      
-      if ( vertical )
-      {
-        for ( ; count > 0; count--, vec++ )
-          vec->x = FT_MulFix( vec->x, scale ) + delta;
-      }
-      else
-      {
-        for ( ; count > 0; count--, vec++ )
-          vec->y = FT_MulFix( vec->y, scale ) + delta;
-      }
-    }
-  }
-  
-  
-  
-
-
-  
-  
-  
-  
-  
-  FT_LOCAL_DEF FT_Error
-  ps_hints_apply( PS_Hints     ps_hints,
-                  FT_Outline*  outline,
-                  PSH_Globals  globals )
-  {
-    PSH_Hint_TableRec  hints;
-    FT_Error           error;
-    FT_Int             dimension;
-    
-    for ( dimension = 1; dimension >= 0; dimension-- )
-    {
-      PS_Dimension  dim = &ps_hints->dimension[dimension];
-      
-      /* initialise hints table */
-      memset( &hints, 0, sizeof(hints) );
-      error = psh_hint_table_init( &hints,
-                                   &dim->hints,
-                                   &dim->masks,
-                                   &dim->counters,
-                                   ps_hints->memory );
-      if (error) goto Exit;
-      
-      psh_hint_table_tune_outline( &hints,
-                                   outline,
-                                   globals,
-                                   dimension );
-                                   
-      psh_hint_table_done( &hints, ps_hints->memory );
-    }
-    
-  Exit:
-    return error;                                   
-  }                   
\ No newline at end of file
diff --git a/src/pshinter/pshfit.h b/src/pshinter/pshfit.h
deleted file mode 100644
index 22b8537..0000000
--- a/src/pshinter/pshfit.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  pshfit.h                                                               */
-/*                                                                         */
-/*    Postscript (Type 1/CFF) outline grid-fitter                          */
-/*                                                                         */
-/*  Copyright 2001 by                                                      */
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
-/*                                                                         */
-/*  This file is part of the FreeType project, and may only be used,       */
-/*  modified, and distributed under the terms of the FreeType project      */
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
-/*  this file you indicate that you have read the license and              */
-/*  understand and accept it fully.                                        */
-/*                                                                         */
-/*                                                                         */
-/*  process the hints provided by the Postscript hints recorder. This      */
-/*  means sorting and scaling the hints, calling the "optimiser" to        */
-/*  process them, then grid-fitting the glyph outline based on the         */
-/*  optimised hints information.                                           */
-/*                                                                         */
-/*  (the real hinting "intelligence" is in "pshoptim.h", not here)         */
-/*                                                                         */
-/***************************************************************************/
-
-#ifndef __PS_HINTER_FITTER_H__
-#define __PS_HINTER_FITTER_H__
-
-#include "pshrec.h"
-
-FT_BEGIN_HEADER
-
-  typedef struct PSH_HintRec_*   PSH_Hint;
-
-  typedef enum
-  {
-    PSH_HINT_FLAG_GHOST  = PS_HINT_FLAG_GHOST,
-    PSH_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
-    PSH_HINT_FLAG_ACTIVE = 4
-  
-  } PSH_Hint_Flags;
-
-#define  psh_hint_is_active(x)  (((x)->flags  & PSH_HINT_FLAG_ACTIVE) != 0)
-#define  psh_hint_is_ghost(x)   (((x)->flags  & PSH_HINT_FLAG_GHOST ) != 0)  
-
-#define  psh_hint_activate(x)     (x)->flags |= PSH_HINT_FLAG_ACTIVE
-#define  psh_hint_deactivate(x)   (x)->flags &= ~PSH_HINT_FLAG_ACTIVE
-
-  typedef struct PSH_HintRec_
-  {
-    FT_Int    org_pos;
-    FT_Int    org_len;
-    FT_Pos    cur_pos;
-    FT_Pos    cur_len;
-    
-    FT_UInt   flags;
-    
-    PSH_Hint  parent;
-    FT_Int    order;
-  
-  } PSH_HintRec;
-
-
- /* this is an interpolation zone used for strong points   */
- /* weak points are interpolated according to their strong */
- /* neighbours..                                           */
-  typedef struct PSH_ZoneRec_
-  {
-    FT_Fixed  scale;
-    FT_Fixed  delta;
-    FT_Pos    min;
-    FT_Pos    max;
-    
-  } PSH_ZoneRec, *PSH_Zone;
-
-
-  typedef struct PSH_Hint_TableRec_
-  {
-    FT_UInt        max_hints;
-    FT_UInt        num_hints;
-    PSH_Hint       hints;
-    PSH_Hint*      sort;
-    PSH_Hint*      sort_global;
-    FT_UInt        num_zones;
-    PSH_Zone       zones;
-    PSH_Zone       zone;
-    PS_Mask_Table  hint_masks;
-    PS_Mask_Table  counter_masks;
-    
-  } PSH_Hint_TableRec, *PSH_Hint_Table;
-
-
-  FT_LOCAL FT_Error
-  ps_hints_apply( PS_Hints     ps_hints,
-                  FT_Outline*  outline,
-                  PSH_Globals  globals );
-
-
-#ifdef DEBUG_VIEW
-  extern  int             ps_debug_no_horz_hints;
-  extern  int             ps_debug_no_vert_hints;
-  extern  PSH_Hint_Table  ps_debug_hint_table;
-
-  typedef void  (*PSH_HintFunc)( PSH_Hint  hint, FT_Bool vertical );
-  extern  PSH_HintFunc    ps_debug_hint_func;
-#endif
-
-FT_END_HEADER
-
-#endif /* __PS_HINTER_FITTER_H__ */
diff --git a/src/pshinter/pshglob.c b/src/pshinter/pshglob.c
index 02c2e14..3dfdd24 100644
--- a/src/pshinter/pshglob.c
+++ b/src/pshinter/pshglob.c
@@ -3,6 +3,10 @@
 #include FT_INTERNAL_OBJECTS_H
 #include "pshglob.h"
 
+#ifdef DEBUG_HINTER
+  extern PSH_Globals   ps_debug_globals = 0;
+#endif  
+
 /* "simple" ps hinter globals management, inspired from the new auto-hinter */
 
  /*************************************************************************/
@@ -87,6 +91,7 @@
 
   static void
   psh_blues_set_zones_0( PSH_Blues       target,
+                         FT_Bool         is_others,
                          FT_UInt         read_count,
                          FT_Short*       read,
                          PSH_Blue_Table  top_table,
@@ -94,26 +99,34 @@
   {
     FT_UInt    count_top = top_table->count;
     FT_UInt    count_bot = bot_table->count;
+    FT_Bool    first     = 1;
     
     for ( ; read_count > 0; read_count -= 2 )
     {
       FT_Int         reference, delta;
       FT_UInt        count;
       PSH_Blue_Zone  zones, zone;
+      FT_Bool        top;
       
       /* read blue zone entry, and select target top/bottom zone */
-      reference = read[0];
-      delta     = read[1] - reference;
-      
-      if ( delta >= 0 )
+      top = 0;
+      if ( first || is_others )
       {
-        zones = top_table->zones;
-        count = count_top;
+        reference = read[1];
+        delta     = read[0] - reference;
+
+        zones = bot_table->zones;
+        count = count_bot;
+        first = 0;
       }
       else
       {
-        zones = bot_table->zones;
-        count = count_bot;
+        reference = read[0];
+        delta     = read[1] - reference;
+      
+        zones = top_table->zones;
+        count = count_top;
+        top   = 1;
       }
       
       /* insert into sorted table */
@@ -149,7 +162,7 @@
       zone->org_ref   = reference;
       zone->org_delta = delta;
       
-      if ( delta >= 0 )
+      if ( top )
         count_top ++;
       else
         count_bot ++;
@@ -195,8 +208,8 @@
     bot_table->count = 0;
     
     /* first, the blues */
-    psh_blues_set_zones_0( target, count, blues, top_table, bot_table );
-    psh_blues_set_zones_0( target, count_others, other_blues, top_table, bot_table );
+    psh_blues_set_zones_0( target, 0, count, blues, top_table, bot_table );
+    psh_blues_set_zones_0( target, 1, count_others, other_blues, top_table, bot_table );
     
     count_top = top_table->count;
     count_bot = bot_table->count;
@@ -206,13 +219,16 @@
     {
       PSH_Blue_Zone  zone = top_table->zones;
       
-      for ( count = count_top-1; count > 0; count--, zone++ )
+      for ( count = count_top; count > 0; count--, zone++ )
       {
         FT_Int  delta;
-      
-        delta = zone[1].org_ref - zone[0].org_ref;
-        if ( zone->org_delta > delta )
-          zone->org_delta = delta;
+        
+        if ( count > 1 )
+        {
+          delta = zone[1].org_ref - zone[0].org_ref;
+          if ( zone->org_delta > delta )
+            zone->org_delta = delta;
+        }
           
         zone->org_bottom = zone->org_ref;
         zone->org_top    = zone->org_delta + zone->org_ref;
@@ -224,13 +240,16 @@
     {
       PSH_Blue_Zone  zone = bot_table->zones;
 
-      for ( count = count_bot-1; count > 0; count--, zone++ )
+      for ( count = count_bot; count > 0; count--, zone++ )
       {
         FT_Int  delta;
         
-        delta = zone[0].org_ref - zone[1].org_ref;
-        if ( zone->org_delta < delta )
-          zone->org_delta = delta;
+        if ( count > 1 )
+        {
+          delta = zone[0].org_ref - zone[1].org_ref;
+          if ( zone->org_delta < delta )
+            zone->org_delta = delta;
+        }
           
         zone->org_top    = zone->org_ref;
         zone->org_bottom = zone->org_delta + zone->org_ref;
@@ -256,7 +275,7 @@
           /* checking that the interval is smaller than the fuzz */
           top = zone->org_top;
           
-          for ( count--; count > 0; count--, zone++ )
+          for ( count--; count > 0; count-- )
           {
             bot   = zone[1].org_bottom;
             delta = bot - top;
@@ -318,6 +337,13 @@
         
         /* round scaled reference position */
         zone->cur_ref = ( zone->cur_ref + 32 ) & -64;
+
+#if 0        
+        if ( zone->cur_ref > zone->cur_top )
+          zone->cur_ref -= 64;
+        else if ( zone->cur_ref < zone->cur_bottom )
+          zone->cur_ref += 64;
+#endif          
       }
     }
     
@@ -326,10 +352,10 @@
 
 
   FT_LOCAL_DEF void
-  psh_blues_snap_stem( PSH_Blues            blues,
-                       FT_Int               stem_top,
-                       FT_Int               stem_bot,
-                       PSH_Blue_Alignement  alignment )
+  psh_blues_snap_stem( PSH_Blues      blues,
+                       FT_Int         stem_top,
+                       FT_Int         stem_bot,
+                       PSH_Alignment  alignment )
   {
     PSH_Blue_Table  table;
     FT_UInt         count;
@@ -341,7 +367,7 @@
     table = &blues->normal_top;
     count = table->count;
     zone  = table->zones;
-    for ( ; count > 0; count-- )
+    for ( ; count > 0; count--, zone++ )
     {
       if ( stem_top < zone->org_bottom )
         break;
@@ -358,7 +384,7 @@
     table = &blues->normal_bottom;
     count = table->count;
     zone  = table->zones;
-    for ( ; count > 0; count-- )
+    for ( ; count > 0; count--, zone++ )
     {
       if ( stem_bot < zone->org_bottom )
         break;
@@ -367,6 +393,7 @@
       {
         alignment->align    |= PSH_BLUE_ALIGN_BOT;
         alignment->align_bot = zone->cur_ref;
+        break;
       }
     }
   }
@@ -397,6 +424,10 @@
       globals->blues.family_bottom.count = 0;
       
       FREE( globals );
+
+#ifdef DEBUG_HINTER
+      ps_debug_globals = 0;
+#endif      
     }
   }
 
@@ -467,6 +498,10 @@
       globals->dimension[0].scale_delta = 0;
       globals->dimension[1].scale_mult  = 0;
       globals->dimension[1].scale_delta = 0;
+
+#ifdef DEBUG_HINTER
+      ps_debug_globals = globals;
+#endif      
     }
     
     *aglobals = globals;
diff --git a/src/pshinter/pshglob.h b/src/pshinter/pshglob.h
index 6fdda05..dae74b4 100644
--- a/src/pshinter/pshglob.h
+++ b/src/pshinter/pshglob.h
@@ -141,7 +141,7 @@
     FT_Pos           align_top;
     FT_Pos           align_bot;
     
-  } PSH_Blue_AlignementRec, *PSH_Blue_Alignement;
+  } PSH_AlignmentRec, *PSH_Alignment;
 
 
   FT_LOCAL void
@@ -156,12 +156,15 @@
 
  /* snap a stem to one or two blue zones */
   FT_LOCAL void
-  psh_blues_snap_stem( PSH_Blues            blues,
-                       FT_Int               stem_top,
-                       FT_Int               stem_bot,
-                       PSH_Blue_Alignement  alignment );
+  psh_blues_snap_stem( PSH_Blues      blues,
+                       FT_Int         stem_top,
+                       FT_Int         stem_bot,
+                       PSH_Alignment  alignment );
   /* */
-  
+
+#ifdef DEBUG_HINTER
+  extern PSH_Globals   ps_debug_globals;
+#endif  
 
 FT_END_HEADER
 
diff --git a/src/pshinter/pshinter.c b/src/pshinter/pshinter.c
index 592cda3..07c6330 100644
--- a/src/pshinter/pshinter.c
+++ b/src/pshinter/pshinter.c
@@ -21,8 +21,9 @@
 #include <ft2build.h>
 #include "pshrec.c"  
 #include "pshglob.c"
-#include "pshfit.c"
+#include "pshalgo1.c" 
+#include "pshalgo2.c"
 #include "pshmod.c"
-#include "pshoptim.c"
+
 
 /* END */
diff --git a/src/pshinter/pshmod.c b/src/pshinter/pshmod.c
index 2838400..65b360d 100644
--- a/src/pshinter/pshmod.c
+++ b/src/pshinter/pshmod.c
@@ -18,6 +18,7 @@
 #include <ft2build.h>
 #include FT_INTERNAL_OBJECTS_H
 #include "pshrec.h"
+#include "pshalgo.h"
 
  /* the Postscript Hinter module structure */
   typedef struct
diff --git a/src/pshinter/pshoptim.c b/src/pshinter/pshoptim.c
deleted file mode 100644
index eef2f84..0000000
--- a/src/pshinter/pshoptim.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include "pshoptim.h"
-
-
-#ifdef DEBUG_VIEW
-  void
-  ps_simple_scale( PSH_Hint_Table  table,
-                   FT_Fixed        scale,
-                   FT_Fixed        delta,
-                   FT_Bool         vertical )
-  {
-    PSH_Hint  hint;
-    FT_UInt   count;
-  
-    for ( count = 0; count < table->num_hints; count++ )
-    {
-      hint = table->sort[count];
-      if ( psh_hint_is_active(hint) )
-      {
-        hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
-        hint->cur_len = FT_MulFix( hint->org_len, scale );
-        
-        if (ps_debug_hint_func)
-          ps_debug_hint_func( hint, vertical );
-      }
-    }
-  }                
-#endif
-
-  FT_LOCAL_DEF  FT_Error
-  psh_hint_table_optimize( PSH_Hint_Table  table,
-                           PSH_Globals     globals,
-                           FT_Outline*     outline,
-                           FT_Bool         vertical )
-  {
-    PSH_Dimension  dim   = &globals->dimension[vertical];
-    FT_Fixed       scale = dim->scale_mult;
-    FT_Fixed       delta = dim->scale_delta;
-
-#ifdef DEBUG_VIEW
-    if ( ps_debug_no_vert_hints && vertical )
-    {
-      ps_simple_scale( table, scale, delta, vertical );
-      return 0;
-    }
-      
-    if ( ps_debug_no_horz_hints && !vertical )
-    {
-      ps_simple_scale( table, scale, delta, vertical );
-      return 0;
-    }
-#endif
-
-    /* XXXX: for now, we only scale the hints to test all other aspects */
-    /*       of the Postscript Hinter..                                 */
-    {  
-      PSH_Hint  hint;
-      FT_UInt   count;
-    
-      for ( count = 0; count < table->num_hints; count++ )
-      {
-        hint = table->sort[count];
-        if ( psh_hint_is_active(hint) )
-        {
-# if 1
-          FT_Pos   pos = FT_MulFix( hint->org_pos, scale ) + delta;
-          FT_Pos   len = FT_MulFix( hint->org_len, scale );
-          
-          FT_Pos   fit_center;
-          FT_Pos   fit_len;
-          
-          PSH_Blue_AlignementRec  align;
-
-          /* compute fitted width/height */
-          fit_len = psh_dimension_snap_width( dim, hint->org_len );
-          if ( fit_len < 64 )
-            fit_len = 64;
-          else
-            fit_len = (fit_len + 16 ) & -64;
-            
-          hint->cur_len = fit_len;
-            
-          /* check blue zones for horizontal stems */
-          align.align = 0;
-          if (!vertical)
-          {
-            psh_blues_snap_stem( &globals->blues,
-                                  hint->org_pos + hint->org_len,
-                                  hint->org_pos,
-                                  &align );
-          }
-
-          switch (align.align)
-          {
-            case PSH_BLUE_ALIGN_TOP:
-              {
-                /* the top of the stem is aligned against a blue zone */
-                hint->cur_pos = align.align_top - fit_len;
-                break;
-              }
-              
-            case PSH_BLUE_ALIGN_BOT:
-              {
-                /* the bottom of the stem is aligned against a blue zone */
-                hint->cur_pos = align.align_bot;
-                break;
-              }
-              
-            case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
-              {
-                /* both edges of the stem are aligned against blue zones */
-                hint->cur_pos = align.align_bot;
-                hint->cur_len = align.align_top - align.align_bot;
-              }
-              break;
-              
-            default:
-              /* normal processing */
-              if ( (fit_len/64) & 1 )
-              {
-                /* odd number of pixels */
-                fit_center = ((pos + (len >> 1)) & -64) + 32;
-              }
-              else
-              {
-                /* even number of pixels */
-                fit_center = (pos + (len >> 1) + 32) & -64;
-              }
-              
-              hint->cur_pos = fit_center - (fit_len >> 1);
-          }
-# else
-          hint->cur_pos = (FT_MulFix( hint->org_pos, scale ) + delta + 32) & -64;
-          hint->cur_len =  FT_MulFix( hint->org_len, scale );
-# endif          
-
-#ifdef DEBUG_VIEW
-        if (ps_debug_hint_func)
-          ps_debug_hint_func( hint, vertical );
-#endif        
-        }
-      }
-    }
-    
-    return 0;
-  }
diff --git a/src/pshinter/pshoptim.h b/src/pshinter/pshoptim.h
deleted file mode 100644
index eb1605e..0000000
--- a/src/pshinter/pshoptim.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  pshoptim.h                                                             */
-/*                                                                         */
-/*    Postscript Hints optimiser and grid-fitter                           */
-/*                                                                         */
-/*  Copyright 2001 by                                                      */
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
-/*                                                                         */
-/*  This file is part of the FreeType project, and may only be used,       */
-/*  modified, and distributed under the terms of the FreeType project      */
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
-/*  this file you indicate that you have read the license and              */
-/*  understand and accept it fully.                                        */
-/*                                                                         */
-/*                                                                         */
-/*  process the hints provided by the fitter in order to optimize them     */
-/*  for the pixel grid, depending on the current glyph outline and         */
-/*  globals. This is where most of the PS Hinter's intelligence is         */
-/*                                                                         */
-/*  XXXX: Until now, only a dummy implementation is provided in order      */
-/*        to test all other functions of the Postscript Hinter.            */
-/*                                                                         */
-/***************************************************************************/
-
-#ifndef __PS_HINTER_OPTIMISER_H__
-#define __PS_HINTER_OPTIMISER_H__
-
-#include "pshfit.h"
-
-FT_BEGIN_HEADER
-
-  FT_LOCAL  FT_Error
-  psh_hint_table_optimize( PSH_Hint_Table  table,
-                           PSH_Globals     globals,
-                           FT_Outline*     outline,
-                           FT_Bool         vertical );
-
-FT_END_HEADER
-
-#endif /* __PS_HINTER_OPTIMISER_H__ */
diff --git a/src/pshinter/pshrec.c b/src/pshinter/pshrec.c
index 5c63f68..8eb6810 100644
--- a/src/pshinter/pshrec.c
+++ b/src/pshinter/pshrec.c
@@ -3,7 +3,15 @@
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 #include "pshrec.h"
-#include "pshfit.h"
+#include "pshalgo.h"
+
+
+#ifdef DEBUG_HINTER
+  extern PS_Hints    ps_debug_hints         = 0;
+  extern  int        ps_debug_no_horz_hints = 0;
+  extern  int        ps_debug_no_vert_hints = 0;
+#endif
+
 
  /***********************************************************************/
  /***********************************************************************/
@@ -1041,7 +1049,7 @@
     funcs->stem     = (T1_Hints_SetStemFunc)   t1_hints_stem;
     funcs->stem3    = (T1_Hints_SetStem3Func)  ps_hints_t1stem3;
     funcs->reset    = (T1_Hints_ResetFunc)     ps_hints_t1reset;
-    funcs->apply    = (T1_Hints_ApplyFunc)     ps_hints_apply;
+    funcs->apply    = (T1_Hints_ApplyFunc)     PS_HINTS_APPLY_FUNC;
   }
   
   
@@ -1097,7 +1105,7 @@
     funcs->stems    = (T2_Hints_StemsFunc)    t2_hints_stems;
     funcs->hintmask = (T2_Hints_MaskFunc)     ps_hints_t2mask;
     funcs->counter  = (T2_Hints_CounterFunc)  ps_hints_t2counter;
-    funcs->apply    = (T2_Hints_ApplyFunc)    ps_hints_apply;
+    funcs->apply    = (T2_Hints_ApplyFunc)    PS_HINTS_APPLY_FUNC;
   }
   
 
diff --git a/src/pshinter/pshrec.h b/src/pshinter/pshrec.h
index fbf7ddb..cdcf057 100644
--- a/src/pshinter/pshrec.h
+++ b/src/pshinter/pshrec.h
@@ -151,10 +151,11 @@
   FT_LOCAL void
   t2_hints_funcs_init( T2_Hints_FuncsRec*  funcs );
 
-#define  xxxDEBUG_VIEW
 
-#ifdef DEBUG_VIEW
-  extern PS_Hints   the_ps_hints;
+#ifdef DEBUG_HINTER
+  extern PS_Hints   ps_debug_hints;
+  extern  int       ps_debug_no_horz_hints;
+  extern  int       ps_debug_no_vert_hints;
 #endif
 
  /* */
diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c
index a12a9ec..9de0141 100644
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -82,7 +82,7 @@
 
 
 #include <string.h>             /* for memcpy() */
-
+#include <setjmp.h>
 
   /*************************************************************************/
   /*                                                                       */
@@ -94,6 +94,8 @@
 #define FT_COMPONENT  trace_aaraster
 
 
+#define ErrRaster_MemoryOverflow   -4
+
 #ifdef _STANDALONE_
 
 
@@ -264,12 +266,13 @@
     void*                render_span_data;
     int                  span_y;
 
-    int    band_size;
-    int    band_shoot;
-    int    conic_level;
-    int    cubic_level;
+    int     band_size;
+    int     band_shoot;
+    int     conic_level;
+    int     cubic_level;
 
-    void*  memory;
+    void*   memory;
+    jmp_buf  jump_buffer;
 
   } TRaster, *PRaster;
 
@@ -296,10 +299,11 @@
   /* Compute the outline bounding box.                                     */
   /*                                                                       */
   static
-  void  compute_cbox( RAS_ARG_ FT_Outline*  outline )
+  void  compute_cbox( RAS_ARG )
   {
-    FT_Vector*  vec   = outline->points;
-    FT_Vector*  limit = vec + outline->n_points;
+    FT_Outline*  outline = &ras.outline;
+    FT_Vector*   vec     = outline->points;
+    FT_Vector*   limit   = vec + outline->n_points;
 
 
     if ( outline->n_points <= 0 )
@@ -339,7 +343,7 @@
   /* Record the current cell in the table.                                 */
   /*                                                                       */
   static
-  int  record_cell( RAS_ARG )
+  void  record_cell( RAS_ARG )
   {
     PCell  cell;
 
@@ -347,7 +351,7 @@
     if ( !ras.invalid && ( ras.area | ras.cover ) )
     {
       if ( ras.num_cells >= ras.max_cells )
-        return 1;
+        longjmp( ras.jump_buffer, 1 );
 
       cell        = ras.cells + ras.num_cells++;
       cell->x     = ras.ex - ras.min_ex;
@@ -355,8 +359,6 @@
       cell->area  = ras.area;
       cell->cover = ras.cover;
     }
-
-    return 0;
   }
 
 
@@ -365,8 +367,8 @@
   /* Set the current cell to a new position.                               */
   /*                                                                       */
   static
-  int  set_cell( RAS_ARG_ TScan  ex,
-                          TScan  ey )
+  void  set_cell( RAS_ARG_ TScan  ex,
+                           TScan  ey )
   {
     int  invalid, record, clean;
 
@@ -402,8 +404,8 @@
 
     /* record the previous cell if needed (i.e., if we changed the cell */
     /* position, of changed the `invalid' flag)                         */
-    if ( ( ras.invalid != invalid || record ) && record_cell( RAS_VAR ) )
-      return 1;
+    if ( ras.invalid != invalid || record )
+      record_cell( RAS_VAR );
 
     if ( clean )
     {
@@ -414,7 +416,6 @@
     ras.invalid = invalid;
     ras.ex      = ex;
     ras.ey      = ey;
-    return 0;
   }
 
 
@@ -436,7 +437,7 @@
     ras.last_ey = SUBPIXELS( ey );
     ras.invalid = 0;
 
-    (void)set_cell( RAS_VAR_ ex, ey );
+    set_cell( RAS_VAR_ ex, ey );
   }
 
 
@@ -445,11 +446,11 @@
   /* Render a scanline as one or more cells.                               */
   /*                                                                       */
   static
-  int  render_scanline( RAS_ARG_  TScan  ey,
-                                  TPos   x1,
-                                  TScan  y1,
-                                  TPos   x2,
-                                  TScan  y2 )
+  void  render_scanline( RAS_ARG_  TScan  ey,
+                                   TPos   x1,
+                                   TScan  y1,
+                                   TPos   x2,
+                                   TScan  y2 )
   {
     TScan  ex1, ex2, fx1, fx2, delta;
     long   p, first, dx;
@@ -465,7 +466,10 @@
 
     /* trivial case.  Happens often */
     if ( y1 == y2 )
-      return set_cell( RAS_VAR_ ex2, ey );
+    {
+      set_cell( RAS_VAR_ ex2, ey );
+      return;
+    }
 
     /* everything is located in a single cell.  That is easy! */
     /*                                                        */
@@ -474,7 +478,7 @@
       delta      = y2 - y1;
       ras.area  += ( fx1 + fx2 ) * delta;
       ras.cover += delta;
-      return 0;
+      return;
     }
 
     /* ok, we'll have to render a run of adjacent cells on the same */
@@ -504,8 +508,7 @@
     ras.cover += delta;
 
     ex1 += incr;
-    if ( set_cell( RAS_VAR_ ex1, ey ) )
-      goto Error;
+    set_cell( RAS_VAR_ ex1, ey );
     y1  += delta;
 
     if ( ex1 != ex2 )
@@ -535,19 +538,13 @@
         ras.cover += delta;
         y1        += delta;
         ex1       += incr;
-        if ( set_cell( RAS_VAR_ ex1, ey ) )
-          goto Error;
+        set_cell( RAS_VAR_ ex1, ey );
       }
     }
 
     delta      = y2 - y1;
     ras.area  += ( fx2 + ONE_PIXEL - first ) * delta;
     ras.cover += delta;
-
-    return 0;
-
-  Error:
-    return 1;
   }
 
 
@@ -556,7 +553,7 @@
   /* Render a given line as a series of scanlines.                         */
   /*                                                                       */
   static
-  int  render_line( RAS_ARG_ TPos  to_x,
+  void render_line( RAS_ARG_ TPos  to_x,
                              TPos  to_y )
   {
     TScan  ey1, ey2, fy1, fy2;
@@ -594,8 +591,7 @@
     /* everything is on a single scanline */
     if ( ey1 == ey2 )
     {
-      if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ) )
-        goto Error;
+      render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
       goto End;
     }
 
@@ -621,12 +617,10 @@
     }
 
     x = ras.x + delta;
-    if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ) )
-      goto Error;
+    render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
 
     ey1 += incr;
-    if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) )
-      goto Error;
+    set_cell( RAS_VAR_ TRUNC( x ), ey1 );
 
     if ( ey1 != ey2 )
     {
@@ -651,29 +645,20 @@
         }
 
         x2 = x + delta;
-        if ( render_scanline( RAS_VAR_ ey1,
-                              x, ONE_PIXEL - first, x2, first ) )
-          goto Error;
+        render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, x2, first );
         x = x2;
+
         ey1 += incr;
-        if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) )
-          goto Error;
+        set_cell( RAS_VAR_ TRUNC( x ), ey1 );
       }
     }
 
-    if ( render_scanline( RAS_VAR_ ey1,
-                          x, ONE_PIXEL - first, to_x, fy2 ) )
-      goto Error;
+    render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, to_x, fy2 );
 
   End:
     ras.x       = to_x;
     ras.y       = to_y;
     ras.last_ey = SUBPIXELS( ey2 );
-
-    return 0;
-
-  Error:
-    return 1;
   }
 
 
@@ -698,7 +683,7 @@
 
 
   static
-  int  render_conic( RAS_ARG_ FT_Vector*  control,
+  void render_conic( RAS_ARG_ FT_Vector*  control,
                               FT_Vector*  to )
   {
     TPos        dx, dy;
@@ -737,8 +722,9 @@
       mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
       mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
 
-      return render_line( RAS_VAR_ mid_x, mid_y ) ||
-             render_line( RAS_VAR_ to_x, to_y );
+      render_line( RAS_VAR_ mid_x, mid_y );
+      render_line( RAS_VAR_ to_x, to_y );
+      return;
     }
 
     arc       = ras.bez_stack;
@@ -792,15 +778,14 @@
         mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
         mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
 
-        if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
-             render_line( RAS_VAR_ to_x, to_y )   )
-          return 1;
+        render_line( RAS_VAR_ mid_x, mid_y );
+        render_line( RAS_VAR_ to_x, to_y );
 
         top--;
         arc -= 2;
       }
     }
-    return 0;
+    return;
   }
 
 
@@ -833,7 +818,7 @@
 
 
   static
-  int  render_cubic( RAS_ARG_ FT_Vector*  control1,
+  void render_cubic( RAS_ARG_ FT_Vector*  control1,
                               FT_Vector*  control2,
                               FT_Vector*  to )
   {
@@ -885,8 +870,9 @@
       mid_y = ( ras.y + to_y +
                 3 * UPSCALE( control1->y + control2->y ) ) / 8;
 
-      return render_line( RAS_VAR_ mid_x, mid_y ) ||
-             render_line( RAS_VAR_ to_x, to_y );
+      render_line( RAS_VAR_ mid_x, mid_y );
+      render_line( RAS_VAR_ to_x, to_y );
+      return;
     }
 
     arc      = ras.bez_stack;
@@ -941,14 +927,13 @@
         mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
         mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
 
-        if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
-             render_line( RAS_VAR_ to_x, to_y )   )
-          return 1;
+        render_line( RAS_VAR_ mid_x, mid_y );
+        render_line( RAS_VAR_ to_x, to_y );
         top --;
         arc -= 3;
       }
     }
-    return 0;
+    return;
   }
 
 
@@ -1157,7 +1142,9 @@
     /* start to a new position */
     x = UPSCALE( to->x );
     y = UPSCALE( to->y );
+    
     start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
+      
     ((PRaster)raster)->x = x;
     ((PRaster)raster)->y = y;
     return 0;
@@ -1168,8 +1155,9 @@
   int  Line_To( FT_Vector*  to,
                 FT_Raster   raster )
   {
-    return render_line( (PRaster)raster,
-                        UPSCALE( to->x ), UPSCALE( to->y ) );
+    render_line( (PRaster)raster,
+                  UPSCALE( to->x ), UPSCALE( to->y ) );
+    return 0;
   }
 
 
@@ -1178,7 +1166,8 @@
                  FT_Vector*  to,
                  FT_Raster   raster )
   {
-    return render_conic( (PRaster)raster, control, to );
+    render_conic( (PRaster)raster, control, to );
+    return 0;
   }
 
 
@@ -1188,7 +1177,8 @@
                  FT_Vector*  to,
                  FT_Raster   raster )
   {
-    return render_cubic( (PRaster)raster, control1, control2, to );
+    render_cubic( (PRaster)raster, control1, control2, to );
+    return 0;
   }
 
 
@@ -1487,7 +1477,11 @@
                              void*                    user )
   {
 #undef SCALED
-#define SCALED( x )  ( ( (x) << shift ) - delta )
+#if 0
+#  define SCALED( x )  ( ( (x) << shift ) - delta )
+#else
+#  define SCALED( x)   (x)
+#endif
 
     FT_Vector   v_last;
     FT_Vector   v_control;
@@ -1502,8 +1496,10 @@
     int     error;
     char    tag;       /* current point's state           */
 
+#if 0
     int     shift = interface->shift;
     FT_Pos  delta = interface->delta;
+#endif
 
 
     first = 0;
@@ -1691,8 +1687,8 @@
   } TBand;
 
 
-  static
-  int  grays_convert_glyph( RAS_ARG_ FT_Outline*  outline )
+  static int
+  grays_convert_glyph_inner( RAS_ARG )
   {
     static
     const FT_Outline_Funcs  interface =
@@ -1705,6 +1701,25 @@
       0
     };
 
+    volatile int  error = 0;
+    
+    if ( setjmp( ras.jump_buffer ) == 0 )
+    {
+      error = FT_Outline_Decompose( &ras.outline, &interface, &ras );
+      record_cell( RAS_VAR );
+    }
+    else
+    {
+      error = ErrRaster_MemoryOverflow;
+    }
+
+    return error;
+  }
+
+
+  static
+  int  grays_convert_glyph( RAS_ARG_ FT_Outline*  outline )
+  {
     TBand     bands[40], *band;
     int       n, num_bands;
     TPos      min, max, max_y;
@@ -1712,7 +1727,7 @@
 
 
     /* Set up state in the raster object */
-    compute_cbox( RAS_VAR_ outline );
+    compute_cbox( RAS_VAR );
 
     /* clip to target bitmap, exit if nothing to do */
     clip = &ras.clip_box;
@@ -1776,8 +1791,12 @@
         ras.min_ey    = band->min;
         ras.max_ey    = band->max;
 
+#if 1
+        error = grays_convert_glyph_inner( RAS_VAR );
+#else       
         error = FT_Outline_Decompose( outline, &interface, &ras ) ||
                 record_cell( RAS_VAR );
+#endif
 
         if ( !error )
         {
@@ -1796,6 +1815,8 @@
           band--;
           continue;
         }
+        else if ( error != ErrRaster_MemoryOverflow )
+          return 1;
 
         /* render pool overflow, we will reduce the render band by half */
         bottom = band->min;
diff --git a/tests/Jamfile b/tests/Jamfile
index 74d3aef..06625a9 100644
--- a/tests/Jamfile
+++ b/tests/Jamfile
@@ -16,7 +16,7 @@
     Main  $(t) : $(t).c ;
     
     LinkLibraries $(t) : $(FT2_LIB) ;
-
+    
     if $(TOOLSET) = MINGW
     {
       LINKKLIBS on $(t)$(SUFEXE) = "-luser32 -lgdi32" ;
diff --git a/tests/gview.c b/tests/gview.c
index b894aa2..35d2369 100644
--- a/tests/gview.c
+++ b/tests/gview.c
@@ -7,7 +7,17 @@
 
 /* include FreeType internals to debug hints */
 #include <../src/pshinter/pshrec.h>
-#include <../src/pshinter/pshfit.h>
+#include <../src/pshinter/pshalgo1.h>
+#include <../src/pshinter/pshalgo2.h>
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                     ROOT DEFINITIONS                         *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
 
 #include <time.h>    /* for clock() */
 
@@ -18,7 +28,7 @@
 #define CLOCKS_PER_SEC HZ
 #endif
 
-static int  depth = 0;
+static int  first_glyph = 0;
 
 static NV_Renderer   renderer;
 static NV_Painter    painter;
@@ -42,12 +52,23 @@
 
 static  int   glyph_index;
 static  int   pixel_size = 12;
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 OPTIONS, COLORS and OTHERS                   *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
 static  int   option_show_axis   = 1;
 static  int   option_show_dots   = 1;
-static  int   option_show_stroke = 1;
+static  int   option_show_stroke = 0;
 static  int   option_show_glyph  = 1;
 static  int   option_show_grid   = 1;
 static  int   option_show_em     = 0;
+static  int   option_show_smooth = 1;
+static  int   option_show_blues  = 0;
 
 static  int   option_show_ps_hints   = 1;
 static  int   option_show_horz_hints = 1;
@@ -58,18 +79,18 @@
 
 static  char  temp_message[1024];
 
-PS_Hints      the_ps_hints = 0;
-int           ps_debug_no_horz_hints = 0;
-int           ps_debug_no_vert_hints = 0;
-PSH_HintFunc  ps_debug_hint_func     = 0;
-
 #define  AXIS_COLOR        0xFFFF0000
 #define  GRID_COLOR        0xFFD0D0D0
 #define  ON_COLOR          0xFFFF2000
 #define  OFF_COLOR         0xFFFF0080
+#define  STRONG_COLOR      0xFF404040
+#define  INTERP_COLOR      0xFF206040
+#define  SMOOTH_COLOR      0xF000B040
 #define  BACKGROUND_COLOR  0xFFFFFFFF
 #define  TEXT_COLOR        0xFF000000
 #define  EM_COLOR          0x80008000
+#define  BLUES_TOP_COLOR   0x4000008F
+#define  BLUES_BOT_COLOR   0x40008F00
 
 #define  GHOST_HINT_COLOR  0xE00000FF
 #define  STEM_HINT_COLOR   0xE02020FF
@@ -84,6 +105,13 @@
 }
 
 
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                     COMMON GRID DRAWING ROUTINES             *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
 
 static void
 reset_scale( NV_Scale  scale )
@@ -188,11 +216,114 @@
 }
 
 
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****            POSTSCRIPT GLOBALS ROUTINES                       *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#include <../src/pshinter/pshglob.h>
+
+static void
+draw_ps_blue_zones( void )
+{
+  if ( option_show_blues && ps_debug_globals )
+  {
+    PSH_Blues       blues = &ps_debug_globals->blues;
+    PSH_Blue_Table  table;
+    NV_Vector       v;
+    FT_Int          y1, y2;
+    FT_UInt         count;
+    PSH_Blue_Zone   zone;
+    
+    /* draw top zones */
+    table = &blues->normal_top;
+    count = table->count;
+    zone  = table->zones;
+    
+    for ( ; count > 0; count--, zone++ )
+    {
+      v.x = 0;
+      if ( !ps_debug_no_horz_hints )
+      {
+        v.y = zone->cur_ref + zone->cur_delta;
+        nv_vector_transform( &v, &size_transform );
+      }
+      else
+      {
+        v.y = zone->org_ref + zone->org_delta;
+        nv_vector_transform( &v, &glyph_transform );
+      }
+      y1  = (int)(v.y + 0.5);
+      
+      v.x = 0;
+      if ( !ps_debug_no_horz_hints )
+      {
+        v.y = zone->cur_ref;
+        nv_vector_transform( &v, &size_transform );
+      }
+      else
+      {
+        v.y = zone->org_ref;
+        nv_vector_transform( &v, &glyph_transform );
+      }
+      y2 = (int)(v.y + 0.5);
+      
+      nv_pixmap_fill_rect( target, 0, y1,
+                           target->width, y2-y1+1,
+                           BLUES_TOP_COLOR );
+
+#if 0                           
+      printf( "top [%.3f %.3f]\n", zone->cur_bottom/64.0, zone->cur_top/64.0 );
+#endif      
+    }
+    
+    
+    /* draw bottom zones */
+    table = &blues->normal_bottom;
+    count = table->count;
+    zone  = table->zones;
+    
+    for ( ; count > 0; count--, zone++ )
+    {
+      v.x = 0;
+      v.y = zone->cur_ref;
+      nv_vector_transform( &v, &size_transform );
+      y1  = (int)(v.y + 0.5);
+      
+      v.x = 0;
+      v.y = zone->cur_ref + zone->cur_delta;
+      nv_vector_transform( &v, &size_transform );
+      y2 = (int)(v.y + 0.5);
+      
+      nv_pixmap_fill_rect( target, 0, y1,
+                           target->width, y2-y1+1,
+                           BLUES_BOT_COLOR );
+
+#if 0
+      printf( "bot [%.3f %.3f]\n", zone->cur_bottom/64.0, zone->cur_top/64.0 );
+#endif
+    }
+  }
+}
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****            POSTSCRIPT HINTER ALGORITHM 1 ROUTINES            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#include <../src/pshinter/pshalgo1.h>
+
 static int pshint_cpos     = 0;
 static int pshint_vertical = -1;
 
 static void
-draw_ps_hint( PSH_Hint   hint, FT_Bool  vertical )
+draw_ps1_hint( PSH1_Hint   hint, FT_Bool  vertical )
 {
   int        x1, x2;
   NV_Vector  v;
@@ -224,17 +355,17 @@
     x2 = (int)(v.x + 0.5);
 
     nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
-                         psh_hint_is_ghost(hint)
+                         psh1_hint_is_ghost(hint)
                          ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
 
-    if ( psh_hint_is_ghost(hint) )
+    if ( psh1_hint_is_ghost(hint) )
     {
       x1 --;
       x2 = x1 + 2;
     }
     else
       nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
-                           psh_hint_is_ghost(hint)
+                           psh1_hint_is_ghost(hint)
                            ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
 
     nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
@@ -256,37 +387,208 @@
     x2 = (int)(v.y + 0.5);
 
     nv_pixmap_fill_rect( target, 0, x1, target->width, 1,
-                         psh_hint_is_ghost(hint)
+                         psh1_hint_is_ghost(hint)
                          ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
 
-    if ( psh_hint_is_ghost(hint) )
+    if ( psh1_hint_is_ghost(hint) )
     {
       x1 --;
       x2 = x1 + 2;
     }
     else
       nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
-                           psh_hint_is_ghost(hint)
+                           psh1_hint_is_ghost(hint)
                            ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
 
     nv_pixmap_fill_rect( target, pshint_cpos, x2, 1, x1+1-x2,
                          STEM_JOIN_COLOR );
   }
 
+#if 0
   printf( "[%7.3f %7.3f] %c\n", hint->cur_pos/64.0, (hint->cur_pos+hint->cur_len)/64.0, vertical ? 'v' : 'h' );
+#endif
   
   pshint_cpos += 10;
 }
 
 
 
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****            POSTSCRIPT HINTER ALGORITHM 2 ROUTINES            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#include <../src/pshinter/pshalgo2.h>
+
+static void
+draw_ps2_hint( PSH2_Hint   hint, FT_Bool  vertical )
+{
+  int        x1, x2;
+  NV_Vector  v;
+  
+  if ( pshint_vertical != vertical )
+  {
+    if (vertical)
+      pshint_cpos = 40;
+    else
+      pshint_cpos = 10;
+      
+    pshint_vertical = vertical;
+  }
+  
+  if (vertical)
+  {
+    if ( !option_show_vert_hints )
+      return;
+      
+    v.x = hint->cur_pos;
+    v.y = 0;
+    nv_vector_transform( &v, &size_transform );
+    x1 = (int)(v.x + 0.5);
+
+    v.x = hint->cur_pos + hint->cur_len;
+    v.y = 0;
+    nv_vector_transform( &v, &size_transform );
+    x2 = (int)(v.x + 0.5);
+
+    nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
+                         psh2_hint_is_ghost(hint)
+                         ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+    if ( psh2_hint_is_ghost(hint) )
+    {
+      x1 --;
+      x2 = x1 + 2;
+    }
+    else
+      nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
+                           psh2_hint_is_ghost(hint)
+                           ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+    nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
+                         STEM_JOIN_COLOR );
+  }
+  else
+  {
+    if (!option_show_horz_hints)
+      return;
+      
+    v.y = hint->cur_pos;
+    v.x = 0;
+    nv_vector_transform( &v, &size_transform );
+    x1 = (int)(v.y + 0.5);
+
+    v.y = hint->cur_pos + hint->cur_len;
+    v.x = 0;
+    nv_vector_transform( &v, &size_transform );
+    x2 = (int)(v.y + 0.5);
+
+    nv_pixmap_fill_rect( target, 0, x1, target->width, 1,
+                         psh2_hint_is_ghost(hint)
+                         ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+    if ( psh2_hint_is_ghost(hint) )
+    {
+      x1 --;
+      x2 = x1 + 2;
+    }
+    else
+      nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
+                           psh2_hint_is_ghost(hint)
+                           ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+    nv_pixmap_fill_rect( target, pshint_cpos, x2, 1, x1+1-x2,
+                         STEM_JOIN_COLOR );
+  }
+
+#if 0
+  printf( "[%7.3f %7.3f] %c\n", hint->cur_pos/64.0, (hint->cur_pos+hint->cur_len)/64.0, vertical ? 'v' : 'h' );
+#endif
+  
+  pshint_cpos += 10;
+}
+
+
+static void
+ps2_draw_control_points( void )
+{
+  if ( ps2_debug_glyph )
+  {
+    PSH2_Glyph    glyph = ps2_debug_glyph;
+    PSH2_Point    point = glyph->points;
+    FT_UInt       count = glyph->num_points;
+    NV_Transform  transform, *trans = &transform;
+    NV_Path       vert_rect;
+    NV_Path       horz_rect;
+    NV_Path       dot, circle;
+    
+    nv_path_new_rectangle( renderer, -1, -6, 2, 12, 0, 0, &vert_rect );
+    nv_path_new_rectangle( renderer, -6, -1, 12, 2, 0, 0, &horz_rect );
+    nv_path_new_circle( renderer, 0, 0, 3., &dot );
+    nv_path_stroke( dot, 0.6, nv_path_linecap_butt, nv_path_linejoin_miter, 1., &circle );
+    
+    for ( ; count > 0; count--, point++ )
+    {
+      NV_Vector  vec;
+      
+      vec.x = point->cur_x;
+      vec.y = point->cur_y;
+      nv_vector_transform( &vec, &size_transform );
+      
+      nv_transform_set_translate( trans, vec.x, vec.y );
+
+      if ( option_show_smooth && !psh2_point_is_smooth(point) )
+      {
+        nv_painter_set_color( painter, SMOOTH_COLOR, 256 );
+        nv_painter_fill_path( painter, trans, 0, circle );
+      }
+        
+      if (option_show_horz_hints)
+      {
+        if ( point->flags_y & PSH2_POINT_STRONG )
+        {
+          nv_painter_set_color( painter, STRONG_COLOR, 256 );
+          nv_painter_fill_path( painter, trans, 0, horz_rect );
+        }
+      }
+      
+      if (option_show_vert_hints)
+      {
+        if ( point->flags_x & PSH2_POINT_STRONG )
+        {
+          nv_painter_set_color( painter, STRONG_COLOR, 256 );
+          nv_painter_fill_path( painter, trans, 0, vert_rect );
+        }
+      }
+    }
+
+    nv_path_destroy( circle );
+    nv_path_destroy( dot );    
+    nv_path_destroy( horz_rect );
+    nv_path_destroy( vert_rect );
+  }
+}
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                        MAIN LOOP(S)                          *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
 static void
 draw_glyph( int  glyph_index )
 {
   NV_Path   path;
 
   pshint_vertical    = -1;
-  ps_debug_hint_func = option_show_ps_hints ? draw_ps_hint : 0;
+  
+  ps1_debug_hint_func = option_show_ps_hints ? draw_ps1_hint : 0;
+  ps2_debug_hint_func = option_show_ps_hints ? draw_ps2_hint : 0;
 
   error = FT_Load_Glyph( face, glyph_index, option_hinting
                                           ? FT_LOAD_NO_BITMAP
@@ -334,6 +636,7 @@
     NV_Int      n, first, last;
 
     nv_path_new_circle( renderer, 0, 0, 2., &plot );
+    
     nv_path_get_outline( path, NULL, memory, &out );
     
     first = 0;
@@ -355,8 +658,10 @@
         vec = out.points + m;
 
         nv_transform_set_translate( &trans, vec->x/64.0, vec->y/64.0 );        
+
         nv_painter_set_color( painter, color, 256 );
         nv_painter_fill_path( painter, &trans, 0, plot );
+
       }
       
       first = last + 1;
@@ -390,105 +695,25 @@
 }
 
 
-#if 0
 
-static void
-draw_ps_hints( void )
-{
-  if ( option_show_ps_hints && the_ps_hints )
-  {
-    PS_Dimension  dim;
-    PS_Hint       hint;
-    NV_UInt       count;
-    NV_Int        cpos;
-    NV_Vector     v;
-    
-    /* draw vertical stems */
-    if ( option_show_vert_hints )
-    {
-      dim  = &the_ps_hints->dimension[1];
-      hint = dim->hints.hints;
-      cpos = 40;
-      for ( count = dim->hints.num_hints; count > 0; count--, hint++ )
-      {
-        NV_Int   x1, x2;
-  
-        v.x = hint->pos;
-        v.y = 0;
-        nv_vector_transform( &v, &glyph_transform );
-        x1  = (int)(v.x+0.5);
-        x1  = glyph_org_x + hint->pos*glyph_scale;
-        nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
-                                  ps_hint_is_ghost(hint)
-                                  ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
-        
-        if ( !ps_hint_is_ghost(hint) )
-        {
-          v.x = hint->pos + hint->len;
-          v.y = 0;
-          nv_vector_transform( &v, &glyph_transform );
-          x2  = (int)(v.x+0.5);
-          x2  = glyph_org_x + (hint->pos + hint->len)*glyph_scale;
-          nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
-                                    STEM_HINT_COLOR );
-        }
-        else
-        {
-          x1 -= 1;
-          x2  = x1 + 2;
-        }
-        
-        nv_pixmap_fill_rect( target, x1, cpos, x2-x1+1, 1,
-                                  STEM_JOIN_COLOR );
-        cpos += 10;
-      }
-    }
+#define  TOGGLE_OPTION(var,prefix)                           \
+            {                                                \
+              var = !var;                                    \
+              sprintf( temp_message, prefix " is now %s",    \
+                       var ? "on" : "off" );                 \
+              break;                                         \
+            }
 
-    /* draw horizontal stems */
-    if ( option_show_horz_hints )
-    {
-      dim  = &the_ps_hints->dimension[0];
-      hint = dim->hints.hints;
-      cpos = 10;
-      for ( count = dim->hints.num_hints; count > 0; count--, hint++ )
-      {
-        NV_Int   y1, y2;
-  
-        v.x = 0;
-        v.y = hint->pos;
-        nv_vector_transform( &v, &glyph_transform );
-        y1  = (int)(v.y+0.5);
-        y1  = glyph_org_y - hint->pos*glyph_scale;
-        nv_pixmap_fill_rect( target, 0, y1, target->width, 1,
-                                  ps_hint_is_ghost(hint)
-                                  ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
-        
-        if ( !ps_hint_is_ghost(hint) )
-        {
-          v.x = 0;
-          v.y = hint->pos + hint->len;
-          nv_vector_transform( &v, &glyph_transform );
-          y2  = (int)(v.y+0.5);
-          y2  = glyph_org_y - (hint->pos + hint->len)*glyph_scale;
-          nv_pixmap_fill_rect( target, 0, y2, target->width, 1,
-                                    STEM_HINT_COLOR );
-        }
-        else
-        {
-          y1 -= 1;
-          y2  = y1 + 2;
-        }
-        
-        nv_pixmap_fill_rect( target, cpos, y2, 1, y1-y2+1,
-                                  STEM_JOIN_COLOR );
-        cpos += 10;
-      }
-    }
-  }
-}
 
-#endif
+#define  TOGGLE_OPTION_NEG(var,prefix)                       \
+            {                                                \
+              var = !var;                                    \
+              sprintf( temp_message, prefix " is now %s",    \
+                       !var ? "on" : "off" );                \
+              break;                                         \
+            }
 
+            
 static void
 handle_event( NVV_EventRec*   ev )
 {
@@ -509,34 +734,19 @@
       }
 
     case NVV_KEY('x'):
-      {
-        option_show_axis = !option_show_axis;
-        break;
-      }
+      TOGGLE_OPTION( option_show_axis, "grid axis display" )
 
     case NVV_KEY('s'):
-      {
-        option_show_stroke = !option_show_stroke;
-        break;
-      }
+      TOGGLE_OPTION( option_show_stroke, "glyph stroke display" )
     
     case NVV_KEY('g'):
-      {
-        option_show_glyph = !option_show_glyph;
-        break;
-      }
+      TOGGLE_OPTION( option_show_glyph, "glyph fill display" )
       
     case NVV_KEY('d'):
-      {
-        option_show_dots = !option_show_dots;
-        break;
-      }
+      TOGGLE_OPTION( option_show_dots, "control points display" )
       
     case NVV_KEY('e'):
-      {
-        option_show_em = !option_show_em;
-        break;
-      }
+      TOGGLE_OPTION( option_show_em, "EM square display" )
     
     case NVV_KEY('+'):
       {
@@ -575,51 +785,90 @@
       }
 
     case NVV_KEY('z'):
-      {
-        ps_debug_no_vert_hints = !ps_debug_no_vert_hints;
-        sprintf( temp_message, "vertical hints processing is now %s",
-                 ps_debug_no_vert_hints ? "off" : "on" );
-        break;
-      }      
+      TOGGLE_OPTION_NEG( ps_debug_no_vert_hints, "vertical hints processing" )
 
     case NVV_KEY('a'):
-      {
-        ps_debug_no_horz_hints = !ps_debug_no_horz_hints;
-        sprintf( temp_message, "horizontal hints processing is now %s",
-                 ps_debug_no_horz_hints ? "off" : "on" );
-        break;
-      }      
+      TOGGLE_OPTION_NEG( ps_debug_no_horz_hints, "horizontal hints processing" )
 
     case NVV_KEY('Z'):
-      {
-        option_show_vert_hints = !option_show_vert_hints;
-        sprintf( temp_message, "vertical hints display is now %s",
-                 option_show_vert_hints ? "off" : "on" );
-        break;
-      }      
+      TOGGLE_OPTION( option_show_vert_hints, "vertical hints display" )
 
     case NVV_KEY('A'):
-      {
-        option_show_horz_hints = !option_show_horz_hints;
-        sprintf( temp_message, "horizontal hints display is now %s",
-                 option_show_horz_hints ? "off" : "on" );
-        break;
-      }      
+      TOGGLE_OPTION( option_show_horz_hints, "horizontal hints display" )
 
+    case NVV_KEY('S'):
+      TOGGLE_OPTION( option_show_smooth, "smooth points display" );
+
+    case NVV_KEY('b'):
+      TOGGLE_OPTION( option_show_blues, "blue zones display" );
 
     case NVV_KEY('h'):
-      {
-        option_hinting = !option_hinting;
-        sprintf( temp_message, "hinting is now %s",
-                 option_hinting ? "off" : "on" );
-        break;
-      }      
+      TOGGLE_OPTION( option_hinting, "hinting" )
+      
+    default:
+      ;
   }
 }
 
 
+
+static void
+usage()
+{
+  Panic( "no usage" );
+}
+
+
+#define  OPTION1(n,code)   \
+           case n :        \
+             code          \
+             argc--;       \
+             argv++;       \
+             break;
+
+#define  OPTION2(n,code)     \
+           case n :          \
+             code            \
+             argc -= 2;      \
+             argv += 2;      \
+             break;
+
+
+static void
+parse_options( int*  argc_p, char*** argv_p )
+{
+  int    argc = *argc_p;
+  char** argv = *argv_p;
+  
+  while (argc > 2 && argv[1][0] == '-')
+  {
+    switch (argv[1][1])
+    {
+      OPTION2( 'f', first_glyph = atoi( argv[2] ); )
+
+      OPTION2( 's', pixel_size = atoi( argv[2] ); )
+      
+      default:
+        usage();
+    }
+  }
+  
+  *argc_p = argc;
+  *argv_p = argv;
+}
+  
+  
+
 int  main( int  argc, char**  argv )
 {
+  char*  filename = "/fonts/lcdxsr.pfa";
+  
+  parse_options( &argc, &argv );
+  
+  if ( argc >= 2 )
+    filename = argv[1];
+   
+  
   /* create library */
   error = nv_renderer_new( 0, &renderer );
   if (error) Panic( "could not create Nirvana renderer" );
@@ -629,7 +878,7 @@
   error = nvv_display_new( renderer, &display );
   if (error) Panic( "could not create display" );
   
-  error = nvv_surface_new( display, 400, 400, nv_pixmap_type_argb, &surface );
+  error = nvv_surface_new( display, 460, 460, nv_pixmap_type_argb, &surface );
   if (error) Panic( "could not create surface" );
 
   target = nvv_surface_get_pixmap( surface );
@@ -644,7 +893,7 @@
   error = FT_Init_FreeType( &freetype );
   if (error) Panic( "could not initialise FreeType" );
   
-  error = FT_New_Face( freetype, "h:/fonts/cour.pfa", 0, &face );
+  error = FT_New_Face( freetype, filename, 0, &face );
   if (error) Panic( "could not open font face" );
 
   reset_size( pixel_size, grid_scale );
@@ -655,15 +904,16 @@
   {
     NVV_EventRec  event;
 
-    glyph_index = 0;    
+    glyph_index = first_glyph;    
     for ( ;; )
     {
       clear_background();
       draw_grid();
 
-      the_ps_hints = 0;
+      ps_debug_hints = 0;
+      draw_ps_blue_zones();
       draw_glyph( glyph_index );
-      /* draw_ps_hints(); */
+      ps2_draw_control_points();
       
       nvv_surface_refresh( surface, NULL );