shithub: freetype+ttf2subf

Download patch

ref: 0f991b4312c1662a82fed697bb14d5f1bfcb69c6
parent: e1d5dd78f4a75697a2584deac4af71dd21939f6a
author: David Turner <[email protected]>
date: Wed Jun 7 16:04:34 EDT 2000

new version of the CFF driver, this one works :-)

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/internal/t2types.h
+++ b/include/freetype/internal/t2types.h
@@ -167,6 +167,11 @@
     CFF_Top_Dict   top_dict;
     CFF_Private    private_dict;
 
+    FT_UInt        num_global_subrs;
+    FT_UInt        num_local_subrs;
+    FT_Byte**      global_subrs;
+    FT_Byte**      local_subrs;
+
   } CFF_Font;
 
 #ifdef __cplusplus
--- a/src/cff/cff.c
+++ b/src/cff/cff.c
@@ -45,5 +45,6 @@
 #include <t2parse.c>     /* token parser         */
 #include <t2load.c>      /* tables loader        */
 #include <t2objs.c>      /* object management    */
+#include <t2gload.c>     /* glyph loader         */
 
 /* END */
--- a/src/cff/t2driver.c
+++ b/src/cff/t2driver.c
@@ -288,19 +288,15 @@
     if ( size )
     {
       /* these two object must have the same parent */
-      if ( size->face != slot->face )
+      if ( size->face != slot->root.face )
         return FT_Err_Invalid_Face_Handle;
     }
 
     /* now load the glyph outline if necessary */
-#if 1 /* XXXX: TODO */
-    error = FT_Err_Unimplemented_Feature;
-#else    
-    error = T2_Load_Glyph( size, slot, glyph_index, load_flags );
-#endif
+    error = T2_Load_Glyph( slot, size, glyph_index, load_flags );
+
     /* force drop-out mode to 2 - irrelevant now */
     /* slot->outline.dropout_mode = 2; */
-
     return error;
   }
 
@@ -382,7 +378,7 @@
     sizeof ( T2_DriverRec ),
     sizeof ( TT_FaceRec ),
     sizeof ( FT_SizeRec ),
-    sizeof ( FT_GlyphSlotRec ),
+    sizeof ( T2_GlyphSlotRec ),
 
     "cff",           /* driver name                           */
     100,             /* driver version == 1.0                 */
--- a/src/cff/t2gload.c
+++ b/src/cff/t2gload.c
@@ -22,1156 +22,1562 @@
 #include <freetype/internal/sfnt.h>
 #include <freetype/tttags.h>
 
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1gload
 
 #include <t2gload.h>
 
+  typedef enum T2_Operator_
+  {
+    t2_op_unknown = 0,
+    t2_op_rmoveto,
+    t2_op_hmoveto,
+    t2_op_vmoveto,
+    t2_op_rlineto,
+    t2_op_hlineto,
+    t2_op_vlineto,
+    t2_op_rrcurveto,
+    t2_op_hhcurveto,
+    t2_op_hvcurveto,
+    t2_op_rcurveline,
+    t2_op_rlinecurve,
+    t2_op_vhcurveto,
+    t2_op_vvcurveto,
+    t2_op_flex,
+    t2_op_hflex,
+    t2_op_hflex1,
+    t2_op_flex1,
+    t2_op_endchar,
+    t2_op_hstem,
+    t2_op_vstem,
+    t2_op_hstemhm,
+    t2_op_vstemhm,
+    t2_op_hintmask,
+    t2_op_cntrmask,
+    t2_op_abs,
+    t2_op_add,
+    t2_op_sub,
+    t2_op_div,
+    t2_op_neg,
+    t2_op_random,
+    t2_op_mul,
+    t2_op_sqrt,
+    t2_op_blend,
+    t2_op_drop,
+    t2_op_exch,
+    t2_op_index,
+    t2_op_roll,
+    t2_op_dup,
+    t2_op_put,
+    t2_op_get,
+    t2_op_store,
+    t2_op_load,
+    t2_op_and,
+    t2_op_or,
+    t2_op_not,
+    t2_op_eq,
+    t2_op_ifelse,
+    t2_op_callsubr,
+    t2_op_callgsubr,
+    t2_op_return,
+    /* do not remove */
+    t2_op_max
+    
+  } T2_Operator;
+
+  #define T2_COUNT_CHECK_WIDTH  0x80
+  #define T2_COUNT_EXACT        0x40
+  #define T2_COUNT_CLEAR_STACK  0x20
+
+  static const FT_Byte  t2_argument_counts[] =
+  {
+    0,  /* unknown */
+    
+    2 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT, /* rmoveto */
+    1 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT,
+    1 | T2_COUNT_CHECK_WIDTH | T2_COUNT_EXACT,
+
+    0 | T2_COUNT_CLEAR_STACK,  /* rlineto */
+    0 | T2_COUNT_CLEAR_STACK,
+    0 | T2_COUNT_CLEAR_STACK,
+
+    0 | T2_COUNT_CLEAR_STACK,  /* rrcurveto */
+    0 | T2_COUNT_CLEAR_STACK,
+    0 | T2_COUNT_CLEAR_STACK,
+    0 | T2_COUNT_CLEAR_STACK,
+    0 | T2_COUNT_CLEAR_STACK,
+    0 | T2_COUNT_CLEAR_STACK,
+    0 | T2_COUNT_CLEAR_STACK,
+
+    13, /* flex */
+    7,
+    9,
+    11,
+
+    0, /* enchar */
+    
+    2 | T2_COUNT_CHECK_WIDTH, /* hstem */
+    2 | T2_COUNT_CHECK_WIDTH,
+    2 | T2_COUNT_CHECK_WIDTH,
+    2 | T2_COUNT_CHECK_WIDTH,
+    
+    0, /* hintmask */
+    0, /* cntrmask */
+    
+    1, /* abs */
+    2,
+    2,
+    2,
+    1,
+    0,
+    2,
+    1,
+    
+    1, /* blend */
+    
+    1, /* drop */
+    2,
+    1,
+    2,
+    1,
+    
+    2, /* put */
+    1,
+    4,
+    3,
+    
+    2, /* and */
+    2,
+    1,
+    2,
+    4,
+    
+    1, /* callsubr */
+    1,
+    0
+  };
+
   /* required for the tracing mode */
 #undef  FT_COMPONENT
 #define FT_COMPONENT  trace_ttgload
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Composite font flags.                                                 */
-  /*                                                                       */
-#define ARGS_ARE_WORDS       0x001
-#define ARGS_ARE_XY_VALUES   0x002
-#define ROUND_XY_TO_GRID     0x004
-#define WE_HAVE_A_SCALE      0x008
-/* reserved                  0x010 */
-#define MORE_COMPONENTS      0x020
-#define WE_HAVE_AN_XY_SCALE  0x040
-#define WE_HAVE_A_2X2        0x080
-#define WE_HAVE_INSTR        0x100
-#define USE_MY_METRICS       0x200
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********                                                   *********/
+  /**********                                                   *********/
+  /**********           GENERIC CHARSTRINGS PARSING             *********/
+  /**********                                                   *********/
+  /**********                                                   *********/
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********************************************************************/
 
+/*********************************************************************
+ *
+ * <Function>
+ *    T2_Init_Builder
+ *
+ * <Description>
+ *    Initialise a given glyph builder.
+ *
+ * <Input>
+ *    builder :: glyph builder to initialise
+ *    face    :: current face object
+ *    size    :: current size object
+ *    glyph   :: current glyph object
+ *
+ *********************************************************************/
 
-
-  /*************************************************************************/
-  /*    Returns the horizontal or vertical metrics in font units for a     */
-  /*    given glyph.  The metrics are the left side bearing (resp. top     */
-  /*    side bearing) and advance width (resp. advance height).            */
-  /*                                                                       */
-  LOCAL_FUNC
-  void  T2_Get_Metrics( TT_HoriHeader*  header,
-                        FT_UInt       index,
-                        FT_Short*       bearing,
-                        FT_UShort*      advance )
+  static
+  void  T2_Init_Builder( T2_Builder*   builder,
+                         TT_Face       face,
+                         T2_Size       size,
+                         T2_GlyphSlot  glyph )
   {
-    TT_LongMetrics*  longs_m;
-    TT_UShort        k = header->number_Of_HMetrics;
+    builder->path_begun  = 0;
+    builder->load_points = 1;
 
+    builder->face   = face;
+    builder->glyph  = glyph;
+    builder->memory = face->root.memory;
 
-    if ( index < k )
+    if (glyph)
     {
-      longs_m  = (TT_LongMetrics*)header->long_metrics + index;
-      *bearing = longs_m->bearing;
-      *advance = longs_m->advance;
+      builder->base         = glyph->root.outline;
+      builder->max_points   = glyph->max_points;
+      builder->max_contours = glyph->max_contours;
     }
-    else
+
+    if (size)
     {
-      *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k];
-      *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance;
+      builder->scale_x = size->metrics.x_scale;
+      builder->scale_y = size->metrics.y_scale;
     }
-  }
 
+    builder->pos_x = 0;
+    builder->pos_y = 0;
 
-  /*************************************************************************/
-  /*    Returns the horizontal metrics in font units for a given glyph.    */
-  /*    If `check' is true, take care of monospaced fonts by returning the */
-  /*    advance width maximum.                                             */
-  /*                                                                       */
-  static
-  void Get_HMetrics( T2_Face     face,
-                     FT_UInt     index,
-                     FT_Bool     check,
-                     FT_Short*   lsb,
-                     FT_UShort*  aw )
-  {
-    T2_Get_Metrics( &face->horizontal, index, lsb, aw );
+    builder->left_bearing.x = 0;
+    builder->left_bearing.y = 0;
+    builder->advance.x      = 0;
+    builder->advance.y      = 0;
 
-    if ( check && face->postscript.isFixedPitch )
-      *aw = face->horizontal.advance_Width_Max;
+    builder->base.n_points   = 0;
+    builder->base.n_contours = 0;
+    builder->current         = builder->base;
   }
 
 
-  /*************************************************************************/
-  /*    Returns the advance width table for a given pixel size if it is    */
-  /*    found in the font's `hdmx' table (if any).                         */
-  /*                                                                       */
+/*********************************************************************
+ *
+ * <Function>
+ *    T2_Done_Builder
+ *
+ * <Description>
+ *    Finalise a given glyph builder. Its content can still be
+ *    used after the call, but the function saves important information
+ *    within the corresponding glyph slot.
+ *
+ * <Input>
+ *    builder :: glyph builder to initialise
+ *
+ *********************************************************************/
+
   static
-  FT_Byte*  Get_Advance_Widths( T2_Face    face,
-                                FT_UShort  ppem )
+  void T2_Done_Builder( T2_Builder*  builder )
   {
-    FT_UShort  n;
+    T2_GlyphSlot  glyph = builder->glyph;
 
-    for ( n = 0; n < face->hdmx.num_records; n++ )
-      if ( face->hdmx.records[n].ppem == ppem )
-        return face->hdmx.records[n].widths;
-
-    return NULL;
+    if (glyph)
+    {
+      glyph->root.outline = builder->base;
+      glyph->max_points   = builder->max_points;
+      glyph->max_contours = builder->max_contours;
+    }
   }
 
 
-#define cur_to_org( n, zone )  \
-          MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( TT_Vector ) )
 
-#define org_to_cur( n, zone )  \
-          MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( TT_Vector ) )
+/*********************************************************************
+ *
+ * <Function>
+ *    T2_Init_Decoder
+ *
+ * <Description>
+ *    Initialise a given Type 2 decoder for parsing
+ *
+ * <Input>
+ *    decoder :: Type 1 decoder to initialise
+ *    funcs   :: hinter functions interface
+ *
+ *********************************************************************/
 
-
-  /*************************************************************************/
-  /*    Translates an array of coordinates.                                */
-  /*                                                                       */
-  static
-  void  translate_array( FT_UInt     n,
-                         FT_Vector*  coords,
-                         FT_Pos      delta_x,
-                         FT_Pos      delta_y )
+  static FT_Int  t2_compute_bias( FT_UInt  num_subrs )
   {
-    FT_UInt  k;
-
-    if ( delta_x )
-      for ( k = 0; k < n; k++ )
-        coords[k].x += delta_x;
-
-    if ( delta_y )
-      for ( k = 0; k < n; k++ )
-        coords[k].y += delta_y;
+    FT_Int  result;
+    
+    if (num_subrs < 1240)
+      result = 107;
+    else if (num_subrs < 33900)
+      result = 1131;
+    else
+      result = 32768;
+      
+    return result;
   }
 
 
-
-  /*************************************************************************/
-  /*    Mounts one glyph zone on top of another.  This is needed to        */
-  /*    assemble composite glyphs.                                         */
-  /*                                                                       */
-  static
-  void  mount_zone( FT_GlyphZone*  source,
-                    FT_GlyphZone*  target )
+  LOCAL_FUNC
+  void  T2_Init_Decoder( T2_Decoder*  decoder,
+                         TT_Face      face,
+                         T2_Size      size,
+                         T2_GlyphSlot slot )
   {
-    FT_UInt  np;
-    FT_Int   nc;
+    CFF_Font*  cff = (CFF_Font*)face->other;
+    
+    /* clear everything */
+    MEM_Set( decoder, 0, sizeof(*decoder) );
 
-    np = source->n_points;
-    nc = source->n_contours;
-
-    target->org   = source->org + np;
-    target->cur   = source->cur + np;
-    target->tags = source->tags + np;
-
-    target->contours = source->contours + nc;
-
-    target->n_points   = 0;
-    target->n_contours = 0;
+    /* initialise builder */
+    T2_Init_Builder( &decoder->builder, face, size, slot );
+    
+    /* initialise Type2 decoder */
+    decoder->num_locals   = cff->num_local_subrs;
+    decoder->num_globals  = cff->num_global_subrs;
+    decoder->locals       = cff->local_subrs;
+    decoder->globals      = cff->global_subrs;
+    decoder->locals_bias  = t2_compute_bias( decoder->num_locals );
+    decoder->globals_bias = t2_compute_bias( decoder->num_globals );
+    
+    decoder->glyph_width   = cff->private_dict.default_width;
+    decoder->nominal_width = cff->private_dict.nominal_width;
   }
 
 
-#undef  IS_HINTED
-#define IS_HINTED(flags)  ((flags & FT_LOAD_NO_HINTING) == 0)
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    Load_Simple_Glyph                                                  */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Loads a simple (i.e, non-composite) glyph.  This function is used  */
-  /*    for the `Load_Simple' state of TT_Load_Glyph().  All composite     */
-  /*    glyphs elements will be loaded with routine.                       */
-  /*                                                                       */
+  /* check that there is enough room for "count" more points */
   static
-  FT_Error  Load_Simple( T2_Loader*       load,
-                         FT_UInt          byte_count,
-                         FT_Int           n_contours,
-                         FT_Bool          debug )
+  FT_Error  check_points( T2_Builder*  builder,
+                          FT_Int       count )
   {
-    FT_Error       error;
-    FT_Stream      stream = load->stream;
-    FT_GlyphZone*  zone   = &load->zone;
-    T2_Face        face = load->face;
+    FT_Outline*  base    = &builder->base;
+    FT_Outline*  outline = &builder->current;
 
-    FT_UShort      n_ins;
-    FT_Int         n, n_points;
+    if (!builder->load_points)
+      return FT_Err_Ok;
 
-    /*********************************************************************/
-    /* simple check                                                      */
+    count += base->n_points + outline->n_points;
 
-    if ( n_contours > load->left_contours )
+    /* realloc points table if necessary */
+    if ( count >= builder->max_points )
     {
-      FT_TRACE0(( "ERROR: Glyph index %ld has %d contours > left %d\n",
-                   load->glyph_index,
-                   n_contours,
-                   load->left_contours ));
-      return TT_Err_Too_Many_Contours;
-    }
+      FT_Error   error;
+      FT_Memory  memory    = builder->memory;
+      FT_Int     increment = outline->points - base->points;
+      FT_Int     current   = builder->max_points;
 
-    /* preparing the execution context */
-    mount_zone( &load->base, zone );
+      while ( builder->max_points < count )
+        builder->max_points += 8;
 
-    /*********************************************************************/
-    /* reading the contours endpoints                                    */
+      if ( REALLOC_ARRAY( base->points, current,
+                          builder->max_points, FT_Vector )  ||
 
-    if ( ACCESS_Frame( byte_count ) )
-      return error;
-
-    for ( n = 0; n < n_contours; n++ )
-      zone->contours[n] = GET_UShort();
-
-    n_points = 0;
-    if ( n_contours > 0 )
-      n_points = zone->contours[n_contours - 1] + 1;
-
-
-    /*********************************************************************/
-    /* reading the bytecode instructions                                 */
-
-    n_ins = GET_UShort();
-    load->face->root.glyph->control_len = n_ins;
-
-    if ( n_points > load->left_points )
-    {
-      FT_TRACE0(( "ERROR: Too many points in glyph %ld\n", load->glyph_index ));
-      error = TT_Err_Too_Many_Points;
-      goto Fail;
-    }
-
-    FT_TRACE4(( "Instructions size : %d\n", n_ins ));
-
-    if ( n_ins > face->max_profile.maxSizeOfInstructions )
-    {
-      FT_TRACE0(( "ERROR: Too many instructions!\n" ));
-      error = TT_Err_Too_Many_Ins;
-      goto Fail;
-    }
-
-    if (stream->cursor + n_ins > stream->limit)
-    {
-      FT_TRACE0(( "ERROR: Instruction count mismatch!\n" ));
-      error = TT_Err_Too_Many_Ins;
-      goto Fail;
-    }
-
-    stream->cursor += n_ins;
-
-    /*********************************************************************/
-    /* reading the point tags                                           */
-
-    {
-      FT_Byte*  flag  = load->zone.tags;
-      FT_Byte*  limit = flag + n_points;
-      FT_Byte   c, count;
-
-      for (; flag < limit; flag++)
+           REALLOC_ARRAY( base->tags, current,
+                          builder->max_points, FT_Byte )    )
       {
-        *flag = c = GET_Byte();
-        if ( c & 8 )
-        {
-          for ( count = GET_Byte(); count > 0; count-- )
-            *++flag = c;
-        }
+        builder->error = error;
+        return error;
       }
-    }
 
-    /*********************************************************************/
-    /* reading the X coordinates                                         */
-
-    {
-      FT_Vector*  vec   = zone->org;
-      FT_Vector*  limit = vec + n_points;
-      FT_Byte*    flag  = zone->tags;
-      FT_Pos      x     = 0;
-
-      for ( ; vec < limit; vec++, flag++ )
-      {
-        FT_Pos  y = 0;
-
-        if ( *flag & 2 )
-        {
-          y = GET_Byte();
-          if ((*flag & 16) == 0) y = -y;
-        }
-        else if ((*flag & 16) == 0)
-          y = GET_Short();
-
-        x     += y;
-        vec->x = x;
-      }
+      outline->points = base->points + increment;
+      outline->tags  = base->tags  + increment;
     }
+    return FT_Err_Ok;
+  }
 
-    /*********************************************************************/
-    /* reading the Y coordinates                                         */
 
+  /* add a new point, do not check room */
+  static
+  void  add_point( T2_Builder*  builder,
+                   FT_Pos       x,
+                   FT_Pos       y,
+                   FT_Byte      flag )
+  {
+    FT_Outline*  outline = &builder->current;
+
+    if (builder->load_points)
     {
-      FT_Vector*  vec   = zone->org;
-      FT_Vector*  limit = vec + n_points;
-      FT_Byte*    flag  = zone->tags;
-      FT_Pos      x     = 0;
+      FT_Vector*  point   = outline->points + outline->n_points;
+      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
 
-      for ( ; vec < limit; vec++, flag++ )
-      {
-        FT_Pos  y = 0;
+      point->x = x >> 16;
+      point->y = y >> 16;
+      *control = ( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
 
-        if ( *flag & 4 )
-        {
-          y = GET_Byte();
-          if ((*flag & 32) == 0) y = -y;
-        }
-        else if ((*flag & 32) == 0)
-          y = GET_Short();
-
-        x     += y;
-        vec->y = x;
-      }
+      builder->last = *point;
     }
 
-    FORGET_Frame();
+    outline->n_points++;
+  }
 
-    /*********************************************************************/
-    /* Add shadow points                                                  */
 
-    /* Now add the two shadow points at n and n + 1.    */
-    /* We need the left side bearing and advance width. */
+  /* check room for a new on-curve point, then add it */
+  static
+  FT_Error  add_point1( T2_Builder*  builder,
+                        FT_Pos       x,
+                        FT_Pos       y )
+  {
+    FT_Error  error;
 
-    {
-      FT_Vector*  pp1;
-      FT_Vector*  pp2;
+    error = check_points(builder,1);
+    if (!error)
+      add_point( builder, x, y, 1 );
 
-      /* pp1 = xMin - lsb */
-      pp1    = zone->org + n_points;
-      pp1->x = load->bbox.xMin - load->left_bearing;
-      pp1->y = 0;
+    return error;
+  }
 
-      /* pp2 = pp1 + aw */
-      pp2    = pp1 + 1;
-      pp2->x = pp1->x + load->advance;
-      pp2->y = 0;
 
-      /* clear the touch tags */
-      for ( n = 0; n < n_points; n++ )
-        zone->tags[n] &= FT_Curve_Tag_On;
+  /* check room for a new contour, then add it */
+  static
+  FT_Error  add_contour( T2_Builder*  builder )
+  {
+    FT_Outline*  base    = &builder->base;
+    FT_Outline*  outline = &builder->current;
 
-      zone->tags[n_points    ] = 0;
-      zone->tags[n_points + 1] = 0;
+    if (!builder->load_points)
+    {
+      outline->n_contours++;
+      return FT_Err_Ok;
     }
-    /* Note that we return two more points that are not */
-    /* part of the glyph outline.                       */
 
-    zone->n_points   = n_points;
-    zone->n_contours = n_contours;
-    n_points        += 2;
-
-    /*******************************************/
-    /* now eventually scale and hint the glyph */
-
-    if (load->load_flags & FT_LOAD_NO_SCALE)
+    /* realloc contours array if necessary */
+    if ( base->n_contours + outline->n_contours >= builder->max_contours &&
+         builder->load_points )
     {
-      /* no scaling, just copy the orig arrays into the cur ones */
-      org_to_cur( n_points, zone );
-    }
-    else
-    {
-      FT_Vector*  vec = zone->org;
-      FT_Vector*  limit = vec + n_points;
-      FT_Fixed    x_scale = load->size->root.metrics.x_scale;
-      FT_Fixed    y_scale = load->size->root.metrics.y_scale;
+      FT_Error  error;
+      FT_Memory memory = builder->memory;
+      FT_Int    increment = outline->contours - base->contours;
+      FT_Int    current   = builder->max_contours;
 
-      /* first scale the glyph points */
-      for (; vec < limit; vec++)
-      {
-        vec->x = FT_MulFix( vec->x, x_scale );
-        vec->y = FT_MulFix( vec->y, y_scale );
-      }
+      builder->max_contours += 4;
 
-      /* if hinting, round pp1, and shift the glyph accordingly */
-      if ( !IS_HINTED(load->load_flags) )
+      if ( REALLOC_ARRAY( base->contours,
+                          current, builder->max_contours, FT_Short ) )
       {
-        org_to_cur( n_points, zone );
+        builder->error = error;
+        return error;
       }
-      else
-      {
-        FT_Pos  x = zone->org[n_points-2].x;
-        x = ((x + 32) & -64) - x;
-        translate_array( n_points, zone->org, x, 0 );
 
-        org_to_cur( n_points, zone );
-
-        zone->cur[n_points-1].x = (zone->cur[n_points-1].x + 32) & -64;
-
-      }
+      outline->contours = base->contours + increment;
     }
 
-    /* save glyph phantom points */
-    if ( !load->preserve_pps )
-    {
-      load->pp1 = zone->cur[n_points - 2];
-      load->pp2 = zone->cur[n_points - 1];
-    }
+    if (outline->n_contours > 0)
+      outline->contours[ outline->n_contours-1 ] = outline->n_points-1;
 
+    outline->n_contours++;
     return FT_Err_Ok;
-
-  Fail:
-    FORGET_Frame();
-    return error;
   }
 
-
-
-
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    load_opentype_glyph                                                */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Loads a given truetype glyph. Handles composites and uses a        */
-  /*    T2_Loader object..                                                 */
-  /*                                                                       */
+  /* if a path was begun, add its first on-curve point */
   static
-  FT_Error  load_opentype_glyph( T2_Loader*  loader,
-                                 FT_UInt     glyph_index )
+  FT_Error  start_point( T2_Builder*  builder,
+                         FT_Pos       x,
+                         FT_Pos       y )
   {
-    FT_Stream    stream = loader->stream;
-    FT_Error     error;
-    T2_Face      face   = loader->face;
-    FT_ULong     offset;
-    FT_Int       num_subglyphs = 0, contours_count;
-    FT_UInt      index, num_points, num_contours, count;
-    FT_Fixed     x_scale, y_scale;
-    FT_ULong     ins_offset;
-
-    /* check glyph index */
-    index = glyph_index;
-    if ( index >= (TT_UInt)face->root.num_glyphs )
+    /* test wether we're building a new contour */
+    if (!builder->path_begun)
     {
-      error = TT_Err_Invalid_Glyph_Index;
-      goto Fail;
-    }
+      FT_Error  error;
 
-    loader->glyph_index = glyph_index;
-    num_contours = 0;
-    num_points   = 0;
-    ins_offset   = 0;
-
-    x_scale = 0x10000;
-    y_scale = 0x10000;
-    if ( (loader->load_flags & FT_LOAD_NO_SCALE)==0 )
-    {
-      x_scale = loader->size->root.metrics.x_scale;
-      y_scale = loader->size->root.metrics.y_scale;
+      builder->path_begun = 1;
+      error = add_contour( builder );
+      if (error) return error;
     }
+    return add_point1( builder, x, y );
+  }
 
-    /* get horizontal metrics */
-    {
-      FT_Short   left_bearing;
-      FT_UShort  advance_width;
 
-      Get_HMetrics( face, index,
-                    (FT_Bool)!(loader->load_flags &
-                                 FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH),
-                    &left_bearing,
-                    &advance_width );
+  /* close the current contour */
+  static
+  void  close_contour( T2_Builder*  builder )
+  {
+    FT_Outline*  outline = &builder->current;
 
-      loader->left_bearing = left_bearing;
-      loader->advance      = advance_width;
-    }
+    if ( outline->n_contours > 0 )
+      outline->contours[outline->n_contours-1] = outline->n_points-1;
+  }
 
-    /* load glyph header */
-    offset = face->glyph_locations[index];
-    count  = 0;
-    if (index < (TT_UInt)face->num_locations-1)
-       count = face->glyph_locations[index+1] - offset;
 
+/*********************************************************************
+ *
+ * <Function>
+ *    T2_Parse_CharStrings
+ *
+ * <Description>
+ *    Parses a given Type 1 charstrings program
+ *
+ * <Input>
+ *    decoder          :: current Type 1 decoder
+ *    charstring_base  :: base of the charstring stream
+ *    charstring_len   :: length in bytes of the charstring stream
+ *    num_subrs        :: number of sub-routines
+ *    subrs_base       :: array of sub-routines addresses
+ *    subrs_len        :: array of sub-routines lengths
+ *
+ * <Return>
+ *    Error code. 0 means success.
+ *
+ *********************************************************************/
 
-    if (count == 0)
-    {
-      /* as described by Frederic Loyer, these are spaces, and */
-      /* not the unknown glyph.                                */
-      loader->bbox.xMin = 0;
-      loader->bbox.xMax = 0;
-      loader->bbox.yMin = 0;
-      loader->bbox.yMax = 0;
+#define USE_ARGS(n)  top -= n; if (top < decoder->stack) goto Stack_Underflow
 
-      loader->pp1.x = 0;
-      loader->pp2.x = loader->advance;
 
-      if ( (loader->load_flags & FT_LOAD_NO_SCALE)==0 )
-        loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+  LOCAL_FUNC
+  FT_Error   T2_Parse_CharStrings( T2_Decoder*  decoder,
+                                   FT_Byte*     charstring_base,
+                                   FT_Int       charstring_len )
+  {
+    FT_Error            error;
+    T2_Decoder_Zone*    zone;
+    FT_Byte*            ip;
+    FT_Byte*            limit;
+    T2_Builder*         builder = &decoder->builder;
+    FT_Outline*         outline;
+    FT_Pos              x, y;
+    FT_Fixed            seed;
+    FT_Fixed*           stack;
 
-      goto Load_End;
-    }
+    /* set default width */
+    decoder->num_hints   = 0;
+    decoder->read_width  = 1;
+    
+    /* compute random seed from stack address of parameter */
+    seed                 = (FT_Fixed)(char*)&seed ^
+                           (FT_Fixed)(char*)&decoder ^
+                           (FT_Fixed)(char*)&charstring_base;
+    seed = (seed ^ (seed >> 10) ^ (seed >> 20)) & 0xFFFF;
+    if (seed == 0)
+      seed = 0x7384;
+    
+    /* First of all, initialise the decoder */
+    decoder->top  = decoder->stack;
+    decoder->zone = decoder->zones;
+    zone          = decoder->zones;
+    stack         = decoder->top;
 
-    offset = loader->glyf_offset + offset;
+    builder->path_begun  = 0;
 
-    /* read first glyph header */
-    if ( FILE_Seek( offset ) || ACCESS_Frame( 10L ) )
-      goto Fail;
+    zone->base           = charstring_base;
+    limit = zone->limit  = charstring_base + charstring_len;
+    ip    = zone->cursor = zone->base;
 
-    contours_count = GET_Short();
+    error   = FT_Err_Ok;
+    outline = &builder->current;
+                                  
+    x = builder->pos_x;
+    y = builder->pos_y;
 
-    loader->bbox.xMin = GET_Short();
-    loader->bbox.yMin = GET_Short();
-    loader->bbox.xMax = GET_Short();
-    loader->bbox.yMax = GET_Short();
-
-    FORGET_Frame();
-
-    FT_TRACE6(( "Glyph %ld\n", index ));
-    FT_TRACE6(( " # of contours : %d\n", num_contours ));
-    FT_TRACE6(( " xMin: %4d  xMax: %4d\n", loader->bbox.xMin,
-                                           loader->bbox.xMax ));
-    FT_TRACE6(( " yMin: %4d  yMax: %4d\n", loader->bbox.yMin,
-                                           loader->bbox.yMax ));
-    FT_TRACE6(( "-" ));
-
-    count -= 10;
-
-    if ( contours_count > loader->left_contours )
+    /* now, execute loop */
+    while ( ip < limit )
     {
-      FT_TRACE0(( "ERROR: Too many contours for glyph %ld\n", index ));
-      error = TT_Err_Too_Many_Contours;
-      goto Fail;
-    }
+      T2_Operator  op;
+      FT_Byte      v;
+      FT_Byte      count;
 
-    loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
-    loader->pp1.y = 0;
-    loader->pp2.x = loader->pp1.x + loader->advance;
-    loader->pp2.y = 0;
-
-    if ((loader->load_flags & FT_LOAD_NO_SCALE)==0)
-    {
-      loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
-      loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
-    }
-
-    /*************************************************************************/
-    /*************************************************************************/
-    /*************************************************************************/
-
-    /**********************************************************************/
-    /* if it is a simple glyph, load it                                   */
-    if (contours_count >= 0)
-    {
-      FT_UInt  num_base_points;
-
-      error = Load_Simple( loader, count, contours_count, 0 );
-      if ( error ) goto Fail;
-
-      /* Note: We could have put the simple loader source there */
-      /*       but the code is fat enough already :-)           */
-      num_points   = loader->zone.n_points;
-      num_contours = loader->zone.n_contours;
-
-      num_base_points = loader->base.n_points;
+      /********************************************************************/
+      /*                                                                  */
+      /* Decode operator or operand                                       */
+      /*                                                                  */
+      /*                                                                  */
+      v = *ip++;
+      if (v >= 32 || v == 28)
       {
-        FT_UInt  k;
-        for ( k = 0; k < num_contours; k++ )
-          loader->zone.contours[k] += num_base_points;
-      }
-
-      loader->base.n_points   += num_points;
-      loader->base.n_contours += num_contours;
-
-      loader->zone.n_points    = 0;
-      loader->zone.n_contours  = 0;
-
-      loader->left_points   -= num_points;
-      loader->left_contours -= num_contours;
-    }
-    /*************************************************************************/
-    /*************************************************************************/
-    /*************************************************************************/
-
-    /************************************************************************/
-    else /* otherwise, load a composite !!                                  */
-    {
-      /* for each subglyph, read composite header */
-	  T2_GlyphSlot  glyph    = loader->glyph;
-      FT_SubGlyph*  subglyph = glyph->subglyphs + glyph->num_subglyphs;
-
-      if (ACCESS_Frame(count)) goto Fail;
-
-      num_subglyphs = 0;
-      do
-      {
-        TT_Fixed  xx, xy, yy, yx;
-		FT_UInt   total_subglyphs;
-
-        /* grow the 'glyph->subglyphs' table if necessary */
-		total_subglyphs = glyph->num_subglyphs + num_subglyphs;
-		if ( total_subglyphs >= glyph->max_subglyphs )
-		{
-		  FT_UInt    new_max = glyph->max_subglyphs;
-		  FT_Memory  memory = loader->face->root.memory;
-
-          while (new_max <= total_subglyphs)
-		    new_max += 4;
-			
-		  if ( REALLOC_ARRAY( glyph->subglyphs, glyph->max_subglyphs,
-		                      new_max, FT_SubGlyph ) )
-            goto Fail;							  
-			
-		  glyph->max_subglyphs = new_max;
-		  subglyph = glyph->subglyphs + glyph->num_subglyphs + num_subglyphs;
-		}
-
-        subglyph->arg1 = subglyph->arg2 = 0;
-
-        subglyph->flags = GET_UShort();
-        subglyph->index = GET_UShort();
-
-        /* read arguments */
-        if (subglyph->flags & ARGS_ARE_WORDS)
+        FT_Int  shift = 16;
+        FT_Long val;
+        
+        /* this is an operand, push it on the stack */
+        if ( v == 28)
         {
-          subglyph->arg1 = GET_Short();
-          subglyph->arg2 = GET_Short();
+          if ( ip+1 >= limit ) goto Syntax_Error;
+          val = (FT_Short)(((FT_Int)ip[0] << 8) + ip[1]);
+          ip += 2;
         }
-        else
+        else if ( v < 247 )
+          val = v - 139;
+        else if ( v < 251 )
         {
-          subglyph->arg1 = GET_Char();
-          subglyph->arg2 = GET_Char();
+          if ( ip >= limit ) goto Syntax_Error;
+          val = (v-247)*256 + *ip++ + 108;
         }
-
-        /* read transform */
-        xx = yy = 0x10000;
-        xy = yx = 0;
-
-        if (subglyph->flags & WE_HAVE_A_SCALE)
+        else if ( v < 255 )
         {
-          xx = (TT_Fixed)GET_Short() << 2;
-          yy = xx;
+          if ( ip >= limit ) goto Syntax_Error;
+          val = -((v-251)*256) - *ip++ - 108;
         }
-        else if (subglyph->flags & WE_HAVE_AN_XY_SCALE)
+        else
         {
-          xx = (TT_Fixed)GET_Short() << 2;
-          yy = (TT_Fixed)GET_Short() << 2;
+          if ( ip + 3 >= limit ) goto Syntax_Error;
+          val = ((FT_Long)ip[0] << 24) |
+                ((FT_Long)ip[1] << 16) |
+                ((FT_Long)ip[2] <<  8) | ip[3];
+          ip    += 4;
+          shift = 0;
         }
-        else if (subglyph->flags & WE_HAVE_A_2X2)
-        {
-          xx = (TT_Fixed)GET_Short() << 2;
-          xy = (TT_Fixed)GET_Short() << 2;
-          yx = (TT_Fixed)GET_Short() << 2;
-          yy = (TT_Fixed)GET_Short() << 2;
-        }
-
-        subglyph->transform.xx = xx;
-        subglyph->transform.xy = xy;
-        subglyph->transform.yx = yx;
-        subglyph->transform.yy = yy;
-
-        subglyph++;
-        num_subglyphs++;
+        if (decoder->top - stack >= T2_MAX_OPERANDS)
+          goto Stack_Overflow;
+          
+        val <<= shift;
+        *decoder->top ++ = val;
+        
+        #ifdef FT_DEBUG_LEVEL_TRACE
+        if (!(val & 0xFFFF))
+          FT_TRACE4(( " %d", (FT_Int)(val >> 16) ));
+        else
+          FT_TRACE4(( " %.2f", val/65536.0 ));
+        #endif
       }
-      while (subglyph[-1].flags & MORE_COMPONENTS);
-
-      FORGET_Frame();
-
-      /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
-      /* "as is" in the glyph slot (the client application will be     */
-      /* responsible for interpreting this data..)                     */
-      if ( loader->load_flags & FT_LOAD_NO_RECURSE )
+      else
       {
-        /* set up remaining glyph fields */
-        glyph->num_subglyphs += num_subglyphs;
-        glyph->format         = ft_glyph_format_composite;
-        goto Load_End;
-      }
-
-
-    /*************************************************************************/
-    /*************************************************************************/
-    /*************************************************************************/
-
-      /*********************************************************************/
-      /* Now, read each subglyph independently..                           */
-      {
-        FT_Int  n, num_base_points, num_new_points;
-
-        subglyph = glyph->subglyphs + glyph->num_subglyphs;
-		glyph->num_subglyphs += num_subglyphs;
-		
-        for ( n = 0; n < num_subglyphs; n++, subglyph++ )
+        FT_Fixed*  args    = decoder->top;
+        FT_Int     num_args = args - decoder->stack;
+        FT_Int     req_args;
+        
+        /* find operator */
+        op = t2_op_unknown;
+        switch (v)
         {
-          FT_Vector  pp1, pp2;
-          FT_Pos     x, y;
+          case 1:  op = t2_op_hstem; break;
+          case 3:  op = t2_op_vstem; break;
+          case 4:  op = t2_op_vmoveto; break;
+          case 5:  op = t2_op_rlineto; break;
+          case 6:  op = t2_op_hlineto; break;
+          case 7:  op = t2_op_vlineto; break;
+          case 8:  op = t2_op_rrcurveto; break;
+          case 10: op = t2_op_callsubr; break;
+          case 11: op = t2_op_return;   break;
+          case 12:
+            {
+              if (ip >= limit) goto Syntax_Error;
+              v = *ip++;
+              switch (v)
+              {
+                case 3:  op = t2_op_and; break;
+                case 4:  op = t2_op_or; break;
+                case 5:  op = t2_op_not; break;
+                case 8:  op = t2_op_store; break;
+                case 9:  op = t2_op_abs; break;
+                case 10: op = t2_op_add; break;
+                case 11: op = t2_op_sub; break;
+                case 12: op = t2_op_div; break;
+                case 13: op = t2_op_load; break;
+                case 14: op = t2_op_neg; break;
+                case 15: op = t2_op_eq; break;
+                case 18: op = t2_op_drop; break;
+                case 20: op = t2_op_put; break;
+                case 21: op = t2_op_get; break;
+                case 22: op = t2_op_ifelse; break;
+                case 23: op = t2_op_random; break;
+                case 24: op = t2_op_mul; break;
+                case 26: op = t2_op_sqrt; break;
+                case 27: op = t2_op_dup; break;
+                case 28: op = t2_op_exch; break;
+                case 29: op = t2_op_index; break;
+                case 30: op = t2_op_roll; break;
+                case 34: op = t2_op_hflex; break;
+                case 35: op = t2_op_flex; break;
+                case 36: op = t2_op_hflex1; break;
+                case 37: op = t2_op_flex1; break;
+              default:
+                /* decrement ip for syntax error message */
+                ip--;
+              }
+            }
+            break;
+            
+          case 14: op = t2_op_endchar;   break;
+          case 16: op = t2_op_blend;     break;
+          case 18: op = t2_op_hstemhm; break;
+          case 19: op = t2_op_hintmask; break;
+          case 20: op = t2_op_cntrmask; break;
+          case 21: op = t2_op_rmoveto; break;
+          case 22: op = t2_op_hmoveto; break;
+          case 23: op = t2_op_vstemhm; break;
+          case 24: op = t2_op_rcurveline; break;
+          case 25: op = t2_op_rlinecurve; break;
+          case 26: op = t2_op_vvcurveto; break;
+          case 27: op = t2_op_hhcurveto; break;
+          case 29: op = t2_op_callgsubr; break;
+          case 30: op = t2_op_vhcurveto; break;
+          case 31: op = t2_op_hvcurveto; break;
+          default:
+            ;
+        }
+        if ( op == t2_op_unknown )
+          goto Syntax_Error;
 
-          pp1 = loader->pp1;
-          pp2 = loader->pp2;
-
-          num_base_points = loader->base.n_points;
-
-          error = load_truetype_glyph( loader, subglyph->index );
-		  if (error) goto Fail;
-
-          if ( subglyph->flags & USE_MY_METRICS )
+        /* check arguments */
+        req_args = count = t2_argument_counts[op];
+        if (req_args & T2_COUNT_CHECK_WIDTH)
+        {
+          args = stack;
+          if ( decoder->read_width )
           {
-            pp1 = loader->pp1;
-            pp2 = loader->pp2;
+            decoder->glyph_width = decoder->nominal_width + (stack[0] >> 16);
+            decoder->read_width  = 0;
+            num_args--;
+            args++;
           }
-          else
-          {
-            loader->pp1 = pp1;
-            loader->pp2 = pp2;
-          }
+          req_args = 0;
+        }
+        
+        req_args &= 15;
+        if (num_args < req_args) goto Stack_Underflow;
+        args     -= req_args;
+        num_args -= req_args;
+        
+        switch (op)
+        {
+          case t2_op_hstem:
+          case t2_op_vstem:
+          case t2_op_hstemhm:
+          case t2_op_vstemhm:
+            {
+              /* if the number of arguments is no even, the first one  */
+              /* is simply the glyph width.. encoded as the difference */
+              /* to nominalWidthX                                      */
+              FT_TRACE4(( op == t2_op_hstem ? " hstem" :
+                          op == t2_op_vstem ? " vstem" :
+                          op == t2_op_hstemhm ? " hstemhm" :
+                          " vstemhm" ));
+              decoder->num_hints += num_args/2;
+              args = stack;
+            }
+            break;
+            
+          case t2_op_hintmask:
+          case t2_op_cntrmask:
+            {
+              FT_TRACE4(( op == t2_op_hintmask ? " hintmask" : " cntrmask" ));
+              decoder->num_hints += num_args/2;
+              ip += (decoder->num_hints+7) >> 3;
+              if (ip >= limit) goto Syntax_Error;
+              args = stack;
+            }
+            break;
+            
+          case t2_op_rmoveto:
+            {
+              FT_TRACE4(( " rmoveto" ));
+              close_contour( builder );
+              builder->path_begun = 0;
+              x   += args[0];
+              y   += args[1];
+              args = stack;
+            }
+            break;
+          
+          case t2_op_vmoveto:
+            {
+              FT_TRACE4(( " vmoveto" ));
+              close_contour( builder );
+              builder->path_begun = 0;
+              y   += args[0];
+              args = stack;
+            }
+            break;
+            
+          case t2_op_hmoveto:
+            {
+              FT_TRACE4(( " vmoveto" ));
+              close_contour( builder );
+              builder->path_begun = 0;
+              x   += args[0];
+              args = stack;
+            }
+            break;
+            
+          case t2_op_rlineto:
+            {
+              FT_TRACE4(( " rlineto" ));
 
-          num_points   = loader->base.n_points;
-          num_contours = loader->base.n_contours;
+              if ( start_point ( builder, x, y )       ||
+                   check_points( builder, num_args/2 ) ) goto Memory_Error;
 
-          num_new_points = num_points - num_base_points;
+              if ( num_args < 2 || num_args & 1 ) goto Stack_Underflow;
+              args = stack;
+              while ( args < decoder->top )
+              {
+                x += args[0];
+                y += args[1];
+                add_point( builder, x, y, 1 );
+                args += 2;
+              }
+              args = stack;
+            }
+            break;
 
-          /********************************************************/
-          /* now perform the transform required for this subglyph */
-
-          if ( subglyph->flags & ( WE_HAVE_A_SCALE     |
-                                   WE_HAVE_AN_XY_SCALE |
-                                   WE_HAVE_A_2X2       ) )
-          {
-            FT_Vector*  cur = loader->zone.cur;
-            FT_Vector*  org = loader->zone.org;
-            FT_Vector*  limit = cur + num_new_points;
-
-            for ( ; cur < limit; cur++, org++ )
+          case t2_op_hlineto:
+          case t2_op_vlineto:
             {
-              TT_Pos  nx, ny;
+              FT_Int  phase = ( op == t2_op_hlineto );
 
-              nx = FT_MulFix( cur->x, subglyph->transform.xx ) +
-                   FT_MulFix( cur->y, subglyph->transform.yx );
+              FT_TRACE4(( op == t2_op_hlineto ? " hlineto" : " vlineto" ));
 
-              ny = FT_MulFix( cur->x, subglyph->transform.xy ) +
-                   FT_MulFix( cur->y, subglyph->transform.yy );
+              if ( start_point ( builder, x, y )     ||
+                   check_points( builder, num_args ) ) goto Memory_Error;
 
-              cur->x = nx;
-              cur->y = ny;
+              args = stack;
+              while (args < decoder->top )
+              {
+                if (phase) x += args[0];
+                      else y += args[0];
+                      
+                if (add_point1( builder, x, y )) goto Memory_Error;
+                args++;
+                phase ^= 1;
+              }
+              args = stack;
+            }
+            break;
 
-              nx = FT_MulFix( org->x, subglyph->transform.xx ) +
-                   FT_MulFix( org->y, subglyph->transform.yx );
+          case t2_op_rrcurveto:
+            {
+              FT_TRACE4(( " rrcurveto" ));
 
-              ny = FT_MulFix( org->x, subglyph->transform.xy ) +
-                   FT_MulFix( org->y, subglyph->transform.yy );
+              /* check number of arguments, must be a multiple of 6 */
+              if (num_args % 6 != 0) goto Stack_Underflow;
+              
+              if ( start_point ( builder, x, y )       ||
+                   check_points( builder, num_args/2 ) ) goto Memory_Error;
+                   
+              args = stack;
+              while (args < decoder->top)
+              {
+                x += args[0];
+                y += args[1];
+                add_point( builder, x, y, 0 );
+                x += args[2];
+                y += args[3];
+                add_point( builder, x, y, 0 );
+                x += args[4];
+                y += args[5];
+                add_point( builder, x, y, 1 );
+                args += 6;
+              }
+              args = stack;
+            }
+            break;
+            
+          case t2_op_vvcurveto:
+            {
+              FT_TRACE4(( " vvcurveto" ));
+              
+              if ( start_point ( builder, x, y ) ) goto Memory_Error;
+              
+              args = stack;
+              if (num_args & 1)
+              {
+                x += args[0];
+                args++;
+                num_args--;
+              }
+              if (num_args % 4 != 0) goto Stack_Underflow;
+              if (check_points( builder, 3*(num_args/4) )) goto Memory_Error;
 
-              org->x = nx;
-              org->y = ny;
+              while (args < decoder->top)
+              {
+                y += args[0];
+                add_point( builder, x, y, 0 );
+                x += args[1];
+                y += args[2];
+                add_point( builder, x, y, 0 );
+                y += args[3];
+                add_point( builder, x, y, 1 );
+                args += 4;
+              }
+              args = stack;
             }
-          }
+            break;
 
-          /* apply offset */
+          case t2_op_hhcurveto:
+            {
+              FT_TRACE4(( " hhcurveto" ));
+              
+              if ( start_point ( builder, x, y ) ) goto Memory_Error;
+              args = stack;
+              if (num_args & 1)
+              {
+                y += args[0];
+                args++;
+                num_args--;
+              }
+              if (num_args % 4 != 0) goto Stack_Underflow;
+              if (check_points( builder, 3*(num_args/4) )) goto Memory_Error;
 
-          if ( !(subglyph->flags & ARGS_ARE_XY_VALUES) )
-          {
-            FT_Int   k = subglyph->arg1;
-            FT_UInt  l = subglyph->arg2;
+              while (args < decoder->top)
+              {
+                x += args[0];
+                add_point( builder, x, y, 0 );
+                x += args[1];
+                y += args[2];
+                add_point( builder, x, y, 0 );
+                x += args[3];
+                add_point( builder, x, y, 1 );
+                args += 4;
+              }
+              args = stack;
+            }
+            break;
 
-            if ( k >= num_base_points ||
-                 l >= (TT_UInt)num_new_points  )
+          case t2_op_vhcurveto:
+          case t2_op_hvcurveto:
             {
-              error = TT_Err_Invalid_Composite;
-              goto Fail;
+              FT_Int  phase;
+              
+              FT_TRACE4(( op == t2_op_vhcurveto ? " vhcurveto" : " hvcurveto" ));
+              
+              if ( start_point ( builder, x, y ) ) goto Memory_Error;
+              args = stack;
+              if (num_args < 4 || (num_args % 4) > 1 ) goto Stack_Underflow;
+              if (check_points( builder, (num_args/4)*3 )) goto Stack_Underflow;
+              phase = ( op == t2_op_hvcurveto );
+              while (num_args >= 4)
+              {
+                num_args -= 4;
+                if (phase)
+                {
+                  x += args[0];
+                  add_point( builder, x, y, 0 );
+                  x += args[1];
+                  y += args[2];
+                  add_point( builder, x, y, 0 );
+                  y += args[3];
+                  if (num_args == 1)
+                    x += args[4];
+                  add_point( builder, x, y, 1 );
+                }
+                else
+                {
+                  y += args[0];
+                  add_point( builder, x, y, 0 );
+                  x += args[1];
+                  y += args[2];
+                  add_point( builder, x, y, 0 );
+                  x += args[3];
+                  if (num_args == 1)
+                    y += args[4];
+                  add_point( builder, x, y, 1 );
+                }
+                args     += 4;
+                phase    ^= 1;
+              }
+              args = stack;
             }
+            break;
 
-            l += num_base_points;
+          case t2_op_rlinecurve:
+          case t2_op_rcurveline:
+            {
+              FT_Int  mod6 = num_args % 6;
+              
+              FT_TRACE4(( op == t2_op_rcurveline ? " rcurveline" :
+                                                   " rlinecurve" ));
+              
+              if ( num_args < 8 || (mod6 != 0 && mod6 != 2) )
+                goto Stack_Underflow;
 
-            x = loader->base.cur[k].x - loader->base.cur[l].x;
-            y = loader->base.cur[k].y - loader->base.cur[l].y;
-          }
-          else
-          {
-            x = subglyph->arg1;
-            y = subglyph->arg2;
-
-            if (!(loader->load_flags & FT_LOAD_NO_SCALE))
+              if ( start_point ( builder, x, y ) ||
+                   check_points( builder, (num_args/6)*3 + mod6/2 ) )
+                goto Memory_Error;
+              
+              args = stack;
+              if (op == t2_op_rlinecurve && mod6)
+              {
+                x += args[0];
+                y += args[1];
+                add_point( builder, x, y, 1 );
+                args     += 2;
+                num_args -= 2;
+              }
+              while (num_args >= 6)
+              {
+                x += args[0];
+                y += args[1];
+                add_point( builder, x, y, 0 );
+                x += args[2];
+                y += args[3];
+                add_point( builder, x, y, 0 );
+                x += args[4];
+                y += args[5];
+                add_point( builder, x, y, 1 );
+                args     += 6;
+                num_args -= 6;
+              }
+              if ( op == t2_op_rcurveline && num_args)
+              {
+                x += args[0];
+                y += args[1];
+                add_point( builder, x, y, 1 );
+              }
+              args = stack;
+            }
+            break;
+            
+          case t2_op_endchar:
+            {
+              FT_TRACE4(( " endchar" ));
+              close_contour( builder );
+  
+              /* add current outline to the glyph slot */
+              builder->base.n_points   += builder->current.n_points;
+              builder->base.n_contours += builder->current.n_contours;
+  
+              /* return now !! */
+              FT_TRACE4(( "\n\n" ));
+              return FT_Err_Ok;
+            }
+            
+          case t2_op_abs:
+            {
+              FT_TRACE4(( " abs" ));
+              if (args[0] < 0)
+                args[0] = -args[0];
+              args++;
+            }
+            break;
+            
+          case t2_op_add:
+            {
+              FT_TRACE4(( " add" ));
+              args[0] += args[1];
+              args++;
+            }
+            break;
+            
+          case t2_op_sub:
+            {
+              FT_TRACE4(( " sub" ));
+              args[0] -= args[1];
+              args++;
+            }
+            break;
+          
+          case t2_op_div:
+            {
+              FT_TRACE4(( " div" ));
+              args[0] = FT_DivFix( args[0], args[1] );
+              args++;
+            }
+            break;
+          
+          case t2_op_neg:
+            {
+              FT_TRACE4(( " neg" ));
+              args[0] = -args[0];
+              args++;
+            }
+            break;
+            
+          case t2_op_random:
+            {
+              FT_Fixed  rand;
+              
+              FT_TRACE4(( " rand" ));
+              rand = seed;
+              if (rand >= 0x8000)
+                rand++;
+                   
+              args[0] = rand;
+              seed    = FT_MulFix( seed, 0x10000 - seed );
+              if (seed == 0) seed += 0x2873;
+              args++;
+            }
+            break;
+            
+          case t2_op_mul:
+            {
+              FT_TRACE4(( " mul" ));
+              args[0] = FT_MulFix( args[0], args[1] );
+              args++;
+            }
+            break;
+          
+          case t2_op_sqrt:
+            {
+              FT_TRACE4(( " sqrt" ));
+              if (args[0] > 0)
+              {
+                FT_Int    count = 9;
+                FT_Fixed  root  = args[0];
+                FT_Fixed  new_root;
+                
+                for (;;)
+                {
+                  new_root = ( root + FT_DivFix(args[0],root) + 1 ) >> 1;
+                  if (new_root == root || count <= 0)
+                    break;
+                  root = new_root;
+                }
+                args[0] = new_root;
+              }
+              else
+                args[0] = 0;
+              args++;
+            }
+            break;
+            
+          case t2_op_drop:
             {
-              x = FT_MulFix( x, x_scale );
-              y = FT_MulFix( y, y_scale );
-
-              if ( subglyph->flags & ROUND_XY_TO_GRID )
-	          {
-	            x = (x + 32) & -64;
-	            y = (y + 32) & -64;
-	          }
+              /* nothing */
+              FT_TRACE4(( " drop" ));
+            }
+            break;  
+            
+          case t2_op_exch:
+            {
+              FT_Fixed  tmp;
+              FT_TRACE4(( " exch" ));
+              tmp     = args[0];
+              args[0] = args[1];
+              args[1] = tmp;
+              args   += 2;
+            }
+            break;
+            
+          case t2_op_index:
+            {
+              FT_Int  index = args[0] >> 16;
+              FT_TRACE4(( " index" ));
+              if (index < 0)
+                index = 0;
+              else if (index > num_args-2)
+                index = num_args-2;
+              args[0] = args[-(index+1)];
+              args++;
+            }
+            break;
+            
+          case t2_op_roll:
+            {
+              FT_Int count = (FT_Int)(args[0] >> 16);
+              FT_Int index = (FT_Int)(args[1] >> 16);
+              
+              FT_TRACE4(( " roll" ));
+              
+              if (count <= 0)
+                count = 1;
+                
+              args -= count;
+              if (args < stack) goto Stack_Underflow;
+              if (index >= 0)
+              {
+                while (index > 0)
+                {
+                  FT_Fixed tmp = args[count-1];
+                  FT_Int   i;
+                  for ( i = count-2; i >= 0; i-- )
+                    args[i+1] = args[i];
+                  args[0] = tmp;
+                  index--;
+                }
+              }
+              else
+              {
+                while (index < 0)
+                {
+                  FT_Fixed  tmp = args[0];
+                  FT_Int    i;
+                  for ( i = 0; i < count-1; i++ )
+                    args[i] = args[i+1];
+                  args[count-1] = tmp;
+                  index++;
+                }
+              }
+              args += count;
             }
-          }
-
-          translate_array( num_new_points, loader->zone.cur, x, y );
-          cur_to_org( num_new_points, &loader->zone );
-        }
+            break;
+            
+          case t2_op_dup:
+            {
+              FT_TRACE4(( " dup" ));
+              args[1] = args[0];
+              args++;
+            }
+            break;
+            
+          case t2_op_put:
+            {
+              FT_Fixed  val   = args[0];
+              FT_Int    index = (FT_Int)(args[1] >> 16);
+              
+              FT_TRACE4(( " put" ));
+              if (index >= 0 && index < decoder->len_buildchar)
+                decoder->buildchar[index] = val;
+            }
+            break;
+                      
+          case t2_op_get:
+            {
+              FT_Int   index = (FT_Int)(args[0] >> 16);
+              FT_Fixed val   = 0;
+              FT_TRACE4(( " get" ));
+              
+              if (index >= 0 && index < decoder->len_buildchar)
+                val = decoder->buildchar[index];
+                
+              args[0] = val;
+              args++;
+            }
+            break;
 
-    /*************************************************************************/
-    /*************************************************************************/
-    /*************************************************************************/
+         case t2_op_store:
+           FT_TRACE4(( " store "));
+           goto Unimplemented;
+           
+         case t2_op_load:
+           FT_TRACE4(( " load" ));
+           goto Unimplemented;
 
-        /* we have finished loading all sub-glyphs, now, look for */
-        /* instructions for this composite !!                     */
+         case t2_op_and:
+           {
+             FT_Fixed  cond = args[0] && args[1];
+             FT_TRACE4(( " and" ));
+             args[0] = cond ? 0x10000 : 0;
+             args++;
+           }
+           break;
 
-      }
-	  /* end of composite loading */
-    }
+         case t2_op_or:
+           {
+             FT_Fixed  cond = args[0] || args[1];
+             FT_TRACE4(( " or" ));
+             args[0] = cond ? 0x10000 : 0;
+             args++;
+           }
+           break;
+           
+         case t2_op_eq:
+           {
+             FT_Fixed  cond = !args[0];
+             FT_TRACE4(( " eq" ));
+             args[0] = cond ? 0x10000 : 0;
+             args++;
+           }
+           break;
+           
+         case t2_op_ifelse:
+           {
+             FT_Fixed  cond = args[2] <= args[3];
+             FT_TRACE4(( " ifelse" ));
+             if (!cond)
+               args[0] = args[1];
+             args++;
+           }
+           break;
+         
+         case t2_op_callsubr:
+           {
+             FT_UInt  index = (FT_UInt)((args[0] >> 16) + decoder->locals_bias);
+             
+             FT_TRACE4(( " callsubr(%d)", index ));
+             if (index >= decoder->num_locals)
+             {
+               FT_ERROR(( "T2.Parse_Charstrings: invalid local subr index\n" ));
+               goto Syntax_Error;
+             }
+             
+             if ( zone - decoder->zones >= T2_MAX_SUBRS_CALLS )
+             {
+               FT_ERROR(( "T2.Parse_CharStrings : too many nested subrs\n" ));
+               goto Syntax_Error;
+             }
+ 
+             zone->cursor = ip;  /* save current instruction pointer */
+ 
+             zone++;
+             zone->base    = decoder->locals[index];
+             zone->limit   = decoder->locals[index+1];
+             zone->cursor  = zone->base;
+ 
+             if (!zone->base)
+             {
+               FT_ERROR(( "T2.Parse_CharStrings : invoking empty subrs !!\n" ));
+               goto Syntax_Error;
+             }
+ 
+             decoder->zone = zone;
+             ip            = zone->base;
+             limit         = zone->limit;
+           }
+           break;
+           
+         case t2_op_callgsubr:
+           {
+             FT_UInt  index = (FT_UInt)((args[0] >> 16) + decoder->globals_bias);
+             
+             FT_TRACE4(( " callgsubr(%d)", index ));
+             if (index >= decoder->num_globals)
+             {
+               FT_ERROR(( "T2.Parse_Charstrings: invalid global subr index\n" ));
+               goto Syntax_Error;
+             }
 
-    /*************************************************************************/
-    /*************************************************************************/
-    /*************************************************************************/
-    /*************************************************************************/
+             if ( zone - decoder->zones >= T2_MAX_SUBRS_CALLS )
+             {
+               FT_ERROR(( "T2.Parse_CharStrings : too many nested subrs\n" ));
+               goto Syntax_Error;
+             }
+ 
+             zone->cursor = ip;  /* save current instruction pointer */
+ 
+             zone++;
+             zone->base    = decoder->globals[index];
+             zone->limit   = decoder->globals[index+1];
+             zone->cursor  = zone->base;
+ 
+             if (!zone->base)
+             {
+               FT_ERROR(( "T2.Parse_CharStrings : invoking empty subrs !!\n" ));
+               goto Syntax_Error;
+             }
+ 
+             decoder->zone = zone;
+             ip            = zone->base;
+             limit         = zone->limit;
+           }
+           break;
+           
+         case t2_op_return:
+           {
+             FT_TRACE4(( " return" ));
+             if ( decoder->zone <= decoder->zones )
+             {
+               FT_ERROR(( "T2.Parse_CharStrings : unexpected return\n" ));
+               goto Syntax_Error;
+             }
+ 
+             decoder->zone--;
+             zone  = decoder->zone;
+             ip    = zone->cursor;
+             limit = zone->limit;
+           }
+           break;
 
-  Load_End:
-    error = FT_Err_Ok;
+         default:
+         
+       Unimplemented:  
+           FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
+           if (ip[-1] == 12)
+           {
+             FT_ERROR(( " %d", ip[0] ));
+           }
+           FT_ERROR(( "\n" ));
+           return FT_Err_Unimplemented_Feature;
+        }
+        decoder->top = args;
+        
+      } /* general operator processing */
 
-  Fail:
+    } /* while ip < limit */
+    FT_TRACE4(( "..end..\n\n" ));
     return error;
-  }
 
+  Syntax_Error:
+    return FT_Err_Invalid_File_Format;
 
+  Stack_Underflow:
+    return T2_Err_Too_Few_Arguments;
 
+  Stack_Overflow:
+    return T2_Err_Stack_Overflow;
+    
+  Memory_Error:
+    return builder->error;
+  }
 
 
-  static
-  void  compute_glyph_metrics( T2_Loader*    loader,
-                               FT_UInt       glyph_index )
-  {
-    FT_UInt       num_points   = loader->base.n_points;
-    FT_UInt       num_contours = loader->base.n_contours;
-    FT_BBox       bbox;
-    T2_Face       face = loader->face;
-    FT_Fixed      x_scale, y_scale;
-    T2_GlyphSlot  glyph = loader->glyph;
-    T2_Size       size = loader->size;
 
-    /* when a simple glyph was loaded, the value of        */
-    /* "base.n_points" and "base.n_contours" is 0, we must */
-    /* take those in the "zone" instead..                  */
-    if ( num_points == 0 && num_contours == 0 )
-    {
-      num_points   = loader->zone.n_points;
-      num_contours = loader->zone.n_contours;
-    }
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********                                                   *********/
+  /**********                                                   *********/
+  /**********           COMPUTE THE MAXIMUM ADVANCE WIDTH       *********/
+  /**********                                                   *********/
+  /**********   The following code is in charge of computing    *********/
+  /**********   the maximum advance width of the font. It       *********/
+  /**********   quickly process each glyph charstring to        *********/
+  /**********   extract the value from either a "sbw" or "seac" *********/
+  /**********   operator.                                       *********/
+  /**********                                                   *********/
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********************************************************************/
 
-    x_scale = 0x10000;
-    y_scale = 0x10000;
-    if ( (loader->load_flags & FT_LOAD_NO_SCALE) == 0)
-    {
-      x_scale = size->root.metrics.x_scale;
-      y_scale = size->root.metrics.y_scale;
-    }
+#if 0 /* unused until we support pure CFF fonts */
+  LOCAL_FUNC
+  FT_Error  T2_Compute_Max_Advance( TT_Face  face,
+                                    FT_Int  *max_advance )
+  {
+    FT_Error    error = 0;
+    T2_Decoder  decoder;
+    FT_Int      glyph_index;
+    CFF_Font*   cff = (CFF_Font*)face->other;
 
-    if ( glyph->format != ft_glyph_format_composite )
-    {
-      FT_UInt  u;
-      for ( u = 0; u < num_points + 2; u++ )
-      {
-        glyph->outline.points[u] = loader->base.cur[u];
-        glyph->outline.tags [u] = loader->base.tags[u];
-      }
+    *max_advance = 0;
 
-      for ( u = 0; u < num_contours; u++ )
-        glyph->outline.contours[u] = loader->base.contours[u];
+    /* Initialise load decoder */
+    T2_Init_Decoder( &decoder, face, 0, 0 );
 
-      /* glyph->outline.second_pass = TRUE; */
-      glyph->outline.flags      &= ~ft_outline_single_pass;
-      glyph->outline.n_points    = num_points;
-      glyph->outline.n_contours  = num_contours;
+    decoder.builder.metrics_only = 1;
+    decoder.builder.load_points  = 0;
 
-      /* translate array so that (0,0) is the glyph's origin */
-      translate_array( (TT_UShort)(num_points + 2),
-                       glyph->outline.points,
-                       -loader->pp1.x,
-                       0 );
-
-      FT_Outline_Get_CBox( &glyph->outline, &bbox );
-
-      if ( IS_HINTED(loader->load_flags) )
+    /* For each glyph, parse the glyph charstring and extract */
+    /* the advance width..                                    */
+    for ( glyph_index = 0; glyph_index < face->root.num_glyphs; glyph_index++ )
+    {
+      FT_Byte*  charstring;
+      FT_ULong  charstring_len;
+      
+      /* now get load the unscaled outline */
+      error = T2_Access_Element( &cff->charstrings_index, glyph_index,
+                                 &charstring, &charstring_len );
+      if (!error)
       {
-        /* grid-fit the bounding box */
-        bbox.xMin &= -64;
-        bbox.yMin &= -64;
-        bbox.xMax  = (bbox.xMax + 63) & -64;
-        bbox.yMax  = (bbox.yMax + 63) & -64;
+        error = T2_Parse_CharStrings( &decoder, charstring, charstring_len );
+                                      
+        T2_Forget_Element( &cff->charstrings_index, &charstring );
       }
+      /* ignore the error if one occured - skip to next glyph */
+      error = 0;
     }
-    else
-      bbox = loader->bbox;
 
-    /* get the device-independent scaled horizontal metrics */
-    /* take care of fixed-pitch fonts...                    */
-    {
-      FT_Pos  left_bearing;
-      FT_Pos  advance;
+    *max_advance = decoder.builder.advance.x;
+    return FT_Err_Ok;
+  }
+#endif
 
-      left_bearing = loader->left_bearing;
-      advance      = loader->advance;
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********                                                   *********/
+  /**********                                                   *********/
+  /**********              UNHINTED GLYPH LOADER                *********/
+  /**********                                                   *********/
+  /**********   The following code is in charge of loading a    *********/
+  /**********   single outline. It completely ignores hinting   *********/
+  /**********   and is used when FT_LOAD_NO_HINTING is set.     *********/
+  /**********                                                   *********/
+  /**********************************************************************/
+  /**********************************************************************/
+  /**********************************************************************/
 
-     /* the flag FT_LOAD_NO_ADVANCE_CHECK was introduced to       */
-     /* correctly support DynaLab fonts, who have an incorrect    */
-     /* "advance_Width_Max" field !! It is used, to my knowledge  */
-     /* exclusively in the X-TrueType font server..               */
-     /*                                                           */
-      if ( face->postscript.isFixedPitch                        &&
-           (loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH) == 0 )
-        advance = face->horizontal.advance_Width_Max;
 
-      if ( !(loader->load_flags & FT_LOAD_NO_SCALE) )
-      {
-        left_bearing = FT_MulFix( left_bearing, x_scale );
-        advance      = FT_MulFix( advance, x_scale );
-      }
+  LOCAL_FUNC
+  FT_Error  T2_Load_Glyph( T2_GlyphSlot  glyph,
+                           T2_Size       size,
+                           FT_Int        glyph_index,
+                           FT_Int        load_flags )
+  {
+    FT_Error        error;
+    T2_Decoder      decoder;
+    TT_Face         face = (TT_Face)glyph->root.face;
+    FT_Bool         hinting;
+    CFF_Font*       cff = (CFF_Font*)face->other;
 
-      glyph->metrics2.horiBearingX = left_bearing;
-      glyph->metrics2.horiAdvance  = advance;
-    }
+    if (load_flags & FT_LOAD_NO_RECURSE)
+      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 
-    glyph->metrics.horiBearingX = bbox.xMin;
-    glyph->metrics.horiBearingY = bbox.yMax;
-    glyph->metrics.horiAdvance  = loader->pp2.x - loader->pp1.x;
+    glyph->x_scale = size->metrics.x_scale;
+    glyph->y_scale = size->metrics.y_scale;
 
-    /* Now take care of vertical metrics.  In the case where there is    */
-    /* no vertical information within the font (relatively common), make */
-    /* up some metrics by `hand'...                                      */
+    glyph->root.outline.n_points   = 0;
+    glyph->root.outline.n_contours = 0;
 
-    {
-      FT_Short   top_bearing;    /* vertical top side bearing (EM units) */
-      FT_UShort  advance_height; /* vertical advance height   (EM units) */
+    hinting = ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
+              ( load_flags & FT_LOAD_NO_HINTING ) == 0;
 
-      FT_Pos  left;     /* scaled vertical left side bearing         */
-      FT_Pos  Top;      /* scaled original vertical top side bearing */
-      FT_Pos  top;      /* scaled vertical top side bearing          */
-      FT_Pos  advance;  /* scaled vertical advance height            */
+    glyph->root.format = ft_glyph_format_none;
 
+    {
+      FT_Byte*  charstring;
+      FT_ULong  charstring_len;
+      
+      T2_Init_Decoder( &decoder, face, size, glyph );
 
-      /* Get the unscaled `tsb' and `ah' */
-      if ( face->vertical_info                   &&
-           face->vertical.number_Of_VMetrics > 0 )
-      {
-        /* Don't assume that both the vertical header and vertical */
-        /* metrics are present in the same font :-)                */
+      decoder.builder.no_recurse = (FT_Bool)!!(load_flags & FT_LOAD_NO_RECURSE);
 
-        T2_Get_Metrics( (TT_HoriHeader*)&face->vertical,
-                        glyph_index,
-                        &top_bearing,
-                        &advance_height );
-      }
-      else
+      /* now load the unscaled outline */
+      error = T2_Access_Element( &cff->charstrings_index, glyph_index,
+                                 &charstring, &charstring_len );
+      if (!error)
       {
-        /* Make up the distances from the horizontal header..     */
-
-        /* NOTE: The OS/2 values are the only `portable' ones,    */
-        /*       which is why we use them, when there is an       */
-        /*       OS/2 table in the font. Otherwise, we use the    */
-        /*       values defined in the horizontal header..        */
-        /*                                                        */
-        /* NOTE2: The sTypoDescender is negative, which is why    */
-        /*        we compute the baseline-to-baseline distance    */
-        /*        here with:                                      */
-        /*             ascender - descender + linegap             */
-        /*                                                        */
-        if ( face->os2.version != 0xFFFF )
-        {
-          top_bearing    = face->os2.sTypoLineGap / 2;
-          advance_height = (TT_UShort)(face->os2.sTypoAscender -
-                                       face->os2.sTypoDescender +
-                                       face->os2.sTypoLineGap);
-        }
-        else
-        {
-          top_bearing    = face->horizontal.Line_Gap / 2;
-          advance_height = (TT_UShort)(face->horizontal.Ascender  +
-                                       face->horizontal.Descender +
-                                       face->horizontal.Line_Gap);
-        }
+        error = T2_Parse_CharStrings( &decoder, charstring, charstring_len );
+                                      
+        T2_Forget_Element( &cff->charstrings_index, &charstring );
       }
 
-      /* We must adjust the top_bearing value from the bounding box given
-         in the glyph header to te bounding box calculated with
-         TT_Get_Outline_BBox()                                            */
+      /* save new glyph tables */
+      T2_Done_Builder( &decoder.builder );
+    }
 
-      /* scale the metrics */
-      if ( !(loader->load_flags & FT_LOAD_NO_SCALE) )
+    /* Now, set the metrics.. - this is rather simple, as : */
+    /* the left side bearing is the xMin, and the top side  */
+    /* bearing the yMax..                                   */
+    if (!error)
+    {
+      /* for composite glyphs, return only the left side bearing and the */
+      /* advance width..                                                 */
+      if ( load_flags & FT_LOAD_NO_RECURSE )
       {
-        Top     = FT_MulFix( top_bearing, y_scale );
-        top     = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale )
-                    - bbox.yMax;
-        advance = FT_MulFix( advance_height, y_scale );
+#if 0      
+        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+        glyph->root.metrics.horiAdvance  = decoder.builder.advance.x;
+#else
+        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+        glyph->root.metrics.horiAdvance  = decoder.glyph_width;
+#endif        
       }
       else
       {
-        Top     = top_bearing;
-        top     = top_bearing + loader->bbox.yMax - bbox.yMax;
-        advance = advance_height;
-      }
+        FT_BBox           cbox;
+        FT_Glyph_Metrics* metrics = &glyph->root.metrics;
 
-      glyph->metrics2.vertBearingY = Top;
-      glyph->metrics2.vertAdvance  = advance;
+        /* copy the _unscaled_ advance width */
+#if 0        
+        metrics->horiAdvance  = decoder.builder.advance.x;
+#else
+        metrics->horiAdvance  = decoder.glyph_width;
+#endif
+        /* make up vertical metrics */
+        metrics->vertBearingX = 0;
+        metrics->vertBearingY = 0;
+        metrics->vertAdvance  = 0;
 
-      /* XXX: for now, we have no better algorithm for the lsb, but it    */
-      /*      should work fine.                                           */
-      /*                                                                  */
-      left = ( bbox.xMin - bbox.xMax ) / 2;
+        glyph->root.format = ft_glyph_format_outline;
 
-      /* grid-fit them if necessary */
-      if ( IS_HINTED(loader->load_flags) )
-      {
-        left   &= -64;
-        top     = (top + 63) & -64;
-        advance = (advance + 32) & -64;
-      }
+        glyph->root.outline.flags &= ft_outline_owner;
+        if ( size && size->metrics.y_ppem < 24 )
+          glyph->root.outline.flags |= ft_outline_high_precision;
 
-      glyph->metrics.vertBearingX = left;
-      glyph->metrics.vertBearingY = top;
-      glyph->metrics.vertAdvance  = advance;
-    }
+        glyph->root.outline.flags |= ft_outline_reverse_fill;
 
-    /* Adjust advance width to the value contained in the hdmx table. */
-    if ( !face->postscript.isFixedPitch && size &&
-         IS_HINTED(loader->load_flags) )
-    {
-      FT_Byte* widths = Get_Advance_Widths( face,
-                                   size->root.metrics.x_ppem );
-      if ( widths )
-        glyph->metrics.horiAdvance = widths[glyph_index] << 6;
-    }
+        /*
+        glyph->root.outline.second_pass    = TRUE;
+        glyph->root.outline.high_precision = ( size->root.metrics.y_ppem < 24 );
+        glyph->root.outline.dropout_mode   = 2;
+        */
 
-    /* set glyph dimensions */
-    glyph->metrics.width  = bbox.xMax - bbox.xMin;
-    glyph->metrics.height = bbox.yMax - bbox.yMin;
-  }
+        if ( (load_flags & FT_LOAD_NO_SCALE) == 0 )
+        {
+          /* scale the outline and the metrics */
+          FT_Int       n;
+          FT_Outline*  cur = &decoder.builder.base;
+          FT_Vector*   vec = cur->points;
+          FT_Fixed     x_scale = glyph->x_scale;
+          FT_Fixed     y_scale = glyph->y_scale;
 
+          /* First of all, scale the points */
+          for ( n = cur->n_points; n > 0; n--, vec++ )
+          {
+            vec->x = FT_MulFix( vec->x, x_scale );
+            vec->y = FT_MulFix( vec->y, y_scale );
+          }
 
+          FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
 
+          /* Then scale the metrics */
+          metrics->horiAdvance  = FT_MulFix( metrics->horiAdvance,  x_scale );
 
+          metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+          metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+          metrics->vertAdvance  = FT_MulFix( metrics->vertAdvance,  x_scale );
+        }
 
+        /* apply the font matrix */
+        /* FT_Outline_Transform( &glyph->root.outline, cff->font_matrix ); */
 
+        /* compute the other metrics */
+        FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
 
+        /* grid fit the bounding box if necessary */
+        if (hinting)
+        {
+          cbox.xMin &= -64;
+          cbox.yMin &= -64;
+          cbox.xMax = ( cbox.xMax+63 ) & -64;
+          cbox.yMax = ( cbox.yMax+63 ) & -64;
+        }
 
+        metrics->width  = cbox.xMax - cbox.xMin;
+        metrics->height = cbox.yMax - cbox.yMin;
 
-
-
-
-  LOCAL_FUNC
-  FT_Error  TT_Load_Glyph( T2_Size       size,
-                           T2_GlyphSlot  glyph,
-                           FT_UShort     glyph_index,
-                           FT_UInt       load_flags )
-  {
-    SFNT_Interface*  sfnt;
-    T2_Face          face;
-    FT_Stream        stream;
-    FT_Memory        memory;
-    FT_Error         error;
-    T2_Loader        loader;
-    FT_GlyphZone*    zone;
-
-    face   = (TT_Face)glyph->face;
-    sfnt   = (SFNT_Interface*)face->sfnt;
-    stream = face->root.stream;
-    memory = face->root.memory;
-    error  = 0;
-
-    if ( !size || (load_flags & FT_LOAD_NO_SCALE)  ||
-                  (load_flags & FT_LOAD_NO_RECURSE ))
-    {
-      size        = NULL;
-      load_flags |= FT_LOAD_NO_SCALE   |
-                    FT_LOAD_NO_HINTING |
-                    FT_LOAD_NO_BITMAP;
-    }
-
-    glyph->num_subglyphs = 0;
-
-#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
-    /*********************************************************************/
-    /* Try to load embedded bitmap if any                                */
-    if ( size && (load_flags & FT_LOAD_NO_BITMAP) == 0 && sfnt->load_sbits )
-    {
-      TT_SBit_Metrics  metrics;
-
-      error = sfnt->load_sbit_image( face,
-                                     size->root.metrics.x_ppem,
-                                     size->root.metrics.y_ppem,
-                                     glyph_index,
-                                     load_flags,
-                                     stream,
-                                     &glyph->bitmap,
-                                     &metrics );
-      if ( !error )
-      {
-        glyph->outline.n_points   = 0;
-        glyph->outline.n_contours = 0;
-
-        glyph->metrics.width  = (FT_Pos)metrics.width  << 6;
-        glyph->metrics.height = (FT_Pos)metrics.height << 6;
-
-        glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
-        glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
-        glyph->metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  << 6;
-
-        glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
-        glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
-        glyph->metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  << 6;
-
-        glyph->format = ft_glyph_format_bitmap;
-        return error;
+        metrics->horiBearingX = cbox.xMin;
+        metrics->horiBearingY = cbox.yMax;
       }
     }
-#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
-
-    if ( load_flags & FT_LOAD_NO_OUTLINE )
-      return ( error ? error : TT_Err_Unavailable_Bitmap );
-
-   /* seek to the beginning of the glyph table. For Type 43 fonts       */
-   /* the table might be accessed from a Postscript stream or something */
-   /* else...                                                           */
-    error = face->goto_table( face, TTAG_glyf, stream, 0 );
-    if (error)
-    {
-      FT_ERROR(( "TT.GLoad: could not access glyph table\n" ));
-      goto Exit;
-    }
-
-    MEM_Set( &loader, 0, sizeof(loader) );
-
-    /* update the glyph zone bounds */
-    zone   = &((TT_Driver)face->root.driver)->zone;
-    error  = FT_Update_GlyphZone( zone,
-                                  face->root.max_points,
-                                  face->root.max_contours );
-    if (error)
-    {
-      FT_ERROR(( "TT.GLoad: could not update loader glyph zone\n" ));
-      goto Exit;
-    }
-    loader.base = *zone;
-
-    loader.zone.n_points   = 0;
-    loader.zone.n_contours = 0;
-
-    /* clear all outline flags, except the "owner" one */
-    glyph->outline.flags &= ft_outline_owner;
-
-    if (size && size->root.metrics.y_ppem < 24 )
-      glyph->outline.flags |= ft_outline_high_precision;
-
-    /************************************************************************/
-    /* let's initialise the rest of our loader now                          */
-    loader.left_points   = face->root.max_points;
-    loader.left_contours = face->root.max_contours;
-    loader.load_flags    = load_flags;
-
-    loader.face   = face;
-    loader.size   = size;
-    loader.glyph  = glyph;
-    loader.stream = stream;
-
-    loader.glyf_offset = FILE_Pos();
-
-    /* Main loading loop */
-    glyph->format        = ft_glyph_format_outline;
-	glyph->num_subglyphs = 0;
-    error = load_truetype_glyph( &loader, glyph_index );
-    if (!error)
-      compute_glyph_metrics( &loader, glyph_index );
-
-  Exit:
     return error;
   }
-
-
 
 /* END */
--- a/src/cff/t2gload.h
+++ b/src/cff/t2gload.h
@@ -25,109 +25,159 @@
   extern "C" {
 #endif
 
-  typedef struct T2_Loader_
+  #define T2_MAX_OPERANDS     48
+  #define T2_MAX_SUBRS_CALLS  32
+
+/*************************************************************************/
+/*                                                                       */
+/* <Structure> T2_Builder                                                */
+/*                                                                       */
+/* <Description>                                                         */
+/*     a structure used during glyph loading to store its outline.       */
+/*                                                                       */
+/* <Fields>                                                              */
+/*    system :: current system object                                    */
+/*    face   :: current face object                                      */
+/*    glyph  :: current glyph slot                                       */
+/*                                                                       */
+/*    current :: current glyph outline                                   */
+/*    base    :: base glyph outline                                      */
+/*                                                                       */
+/*    max_points   :: maximum points in builder outline                  */
+/*    max_contours :: maximum contours in builder outline                */
+/*                                                                       */
+/*    last     :: last point position                                    */
+/*                                                                       */
+/*    scale_x  :: horizontal scale ( FUnits to sub-pixels )              */
+/*    scale_y  :: vertical scale   ( FUnits to sub-pixels )              */
+/*    pos_x    :: horizontal translation (composite glyphs)              */
+/*    pos_y    :: vertical translation   (composite glyph)               */
+/*                                                                       */
+/*    left_bearing  :: left side bearing point                           */
+/*    advance       :: horizontal advance vector                         */
+/*                                                                       */
+/*    path_begun    :: flag, indicates that a new path has begun         */
+/*    load_points   :: flag, if not set, no points are loaded            */
+/*                                                                       */
+/*    error         :: an error code that is only used to report         */
+/*                     memory allocation problems..                      */
+/*                                                                       */
+/*    metrics_only  :: a boolean indicating that we only want to         */
+/*                     compute the metrics of a given glyph, not load    */
+/*                     all of its points..                               */
+/*                                                                       */
+
+  typedef struct T2_Builder_
   {
-    T2_Face         face;
-    T2_Size         size;
-    T2_GlyphSlot    glyph;
+    FT_Memory     memory;
+    TT_Face       face;
+    T2_GlyphSlot  glyph;
 
-    FT_ULong        load_flags;
-    FT_UInt         glyph_index;
+    FT_Outline    current;       /* the current glyph outline   */
+    FT_Outline    base;          /* the composite glyph outline */
 
-    FT_Stream       stream;
-    FT_Int          byte_len;
-    FT_Int          left_points;
-    FT_Int          left_contours;
+    FT_Int        max_points;    /* capacity of base outline in points   */
+    FT_Int        max_contours;  /* capacity of base outline in contours */
 
-    FT_BBox         bbox;
-    FT_Int          left_bearing;
-    FT_Int          advance;
-    FT_Bool         preserve_pps;
-    FT_Vector       pp1;
-    FT_Vector       pp2;
+    FT_Vector     last;
 
-    FT_ULong        glyf_offset;
+    FT_Fixed      scale_x;
+    FT_Fixed      scale_y;
 
-    /* the zone where we load our glyphs */
-    FT_GlyphZone    base;
-    FT_GlyphZone    zone;
+    FT_Pos        pos_x;
+    FT_Pos        pos_y;
 
-  } T2_Loader;
+    FT_Vector     left_bearing;
+    FT_Vector     advance;
 
+    FT_BBox       bbox;          /* bounding box */
+    FT_Bool       path_begun;
+    FT_Bool       load_points;
+    FT_Bool       no_recurse;
 
-#if 0
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    T2_Get_Metrics                                                     */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Returns the horizontal or vertical metrics in font units for a     */
-  /*    given glyph.  The metrics are the left side bearing (resp. top     */
-  /*    side bearing) and advance width (resp. advance height).            */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    header  :: A pointer to either the horizontal or vertical metrics  */
-  /*               structure.                                              */
-  /*                                                                       */
-  /*    index   :: The glyph index.                                        */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    bearing :: The bearing, either left side or top side.              */
-  /*                                                                       */
-  /*    advance :: The advance width resp. advance height.                 */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    This function will much probably move to another component in the  */
-  /*    near future, but I haven't decided which yet.                      */
-  /*                                                                       */
+    FT_Error      error;         /* only used for memory errors */
+    FT_Bool       metrics_only;
+
+  } T2_Builder;
+
+
+  /* execution context charstring zone */
+  typedef struct T2_Decoder_Zone_
+  {
+    FT_Byte*  base;
+    FT_Byte*  limit;
+    FT_Byte*  cursor;
+
+  } T2_Decoder_Zone;
+
+
+  typedef struct T2_Decoder_
+  {
+    T2_Builder         builder;
+    CFF_Font*          cff;
+
+    FT_Fixed           stack[ T2_MAX_OPERANDS+1 ];
+    FT_Fixed*          top;
+
+    T2_Decoder_Zone    zones[ T2_MAX_SUBRS_CALLS+1 ];
+    T2_Decoder_Zone*   zone;
+
+    FT_Int             flex_state;
+    FT_Int             num_flex_vectors;
+    FT_Vector          flex_vectors[7];
+
+    FT_Pos             glyph_width;
+    FT_Pos             nominal_width;
+    
+    FT_Bool            read_width;
+    FT_Int             num_hints;
+    FT_Fixed*          buildchar;
+    FT_Int             len_buildchar;
+
+    FT_UInt            num_locals;
+    FT_UInt            num_globals;
+    
+    FT_Int             locals_bias;
+    FT_Int             globals_bias;
+    
+    FT_Byte**          locals;
+    FT_Byte**          globals;
+
+
+  } T2_Decoder;
+
+
+
   LOCAL_DEF
-  void  T2_Get_Metrics( TT_HoriHeader*  header,
-                        FT_UInt         index,
-                        FT_Short*       bearing,
-                        FT_UShort*      advance );
+  void  T2_Init_Decoder( T2_Decoder*  decoder,
+                         TT_Face      face,
+                         T2_Size      size,
+                         T2_GlyphSlot slot );
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    T2_Load_Glyph                                                      */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A function used to load a single glyph within a given glyph slot,  */
-  /*    for a given size.                                                  */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    glyph       :: A handle to a target slot object where the glyph    */
-  /*                   will be loaded.                                     */
-  /*                                                                       */
-  /*    size        :: A handle to the source face size at which the glyph */
-  /*                   must be scaled/loaded.                              */
-  /*                                                                       */
-  /*    glyph_index :: The index of the glyph in the font file.            */
-  /*                                                                       */
-  /*    load_flags  :: A flag indicating what to load for this glyph.  The */
-  /*                   FT_LOAD_XXX constants can be used to control the    */
-  /*                   glyph loading process (e.g., whether the outline    */
-  /*                   should be scaled, whether to load bitmaps or not,   */
-  /*                   whether to hint the outline, etc).                  */
-  /* <Output>                                                              */
-  /*    result      :: A set of bit flags indicating the type of data that */
-  /*                   was loaded in the glyph slot (outline or bitmap,    */
-  /*                   etc).                                               */
-  /*                                                                       */
-  /*                   You can set this field to 0 if you don't want this  */
-  /*                   information.                                        */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
+#if 0  /* unused until we support pure CFF fonts */
+  /* Compute the maximum advance width of a font through quick parsing */
   LOCAL_DEF
-  FT_Error  T2_Load_Glyph( T2_Size       size,
-                           T2_GlyphSlot  glyph,
-                           FT_UShort     glyph_index,
-                           FT_UInt       load_flags );
+  FT_Error  T2_Compute_Max_Advance( TT_Face  face,
+                                    FT_Int  *max_advance );
 #endif
+
+  /* This function is exported, because it is used by the T1Dump utility */
+  LOCAL_DEF
+  FT_Error   T2_Parse_CharStrings( T2_Decoder*  decoder,
+                                   FT_Byte*     charstring_base,
+                                   FT_Int       charstring_len );
+
+
+
+  LOCAL_DEF
+  FT_Error  T2_Load_Glyph( T2_GlyphSlot  glyph,
+                           T2_Size       size,
+                           FT_Int        glyph_index,
+                           FT_Int        load_flags );
+
+
+
 
 #ifdef __cplusplus
   }
--- a/src/cff/t2load.c
+++ b/src/cff/t2load.c
@@ -25,7 +25,7 @@
 #include <freetype/tttags.h>
 #include <t2load.h>
 #include <t2parse.h>
-#include <freetype/internal/t2errors.h>
+#include <t2errors.h>
 
 #undef  FT_COMPONENT
 #define FT_COMPONENT  trace_ttload
@@ -53,6 +53,7 @@
     FT_UShort count;
 
     MEM_Set( index, 0, sizeof(*index) );
+    index->stream = stream;
     if ( !READ_UShort( count ) &&
           count > 0            )
     {
@@ -127,7 +128,36 @@
 
 
   static
-  FT_Error  t2_access_element( CFF_Index*   index,
+  FT_Error  t2_explicit_cff_index( CFF_Index*  index,
+                                   FT_Byte**  *table )
+  {
+    FT_Error  error  = 0;
+    FT_Memory memory = index->stream->memory;
+    FT_UInt   n, offset, old_offset;
+    FT_Byte** t;
+
+    *table  = 0;
+    if ( index->count > 0 && !ALLOC_ARRAY( t, index->count+1, FT_Byte* ) )
+    {
+      old_offset = 1;
+      for ( n = 0; n <= index->count; n++ )
+      {
+        offset = index->offsets[n];
+        if (!offset)
+          offset = old_offset;
+        
+        t[n] = index->bytes + offset - 1;
+        
+        old_offset = offset;
+      }
+      *table = t;
+    }
+    return error;    
+  }
+
+
+  LOCAL_FUNC
+  FT_Error  T2_Access_Element( CFF_Index*   index,
                                FT_UInt      element,
                                FT_Byte*    *pbytes,
                                FT_ULong    *pbyte_len )
@@ -187,8 +217,8 @@
   }
 
 
-  static
-  void  t2_forget_element( CFF_Index*  index,
+  LOCAL_FUNC
+  void  T2_Forget_Element( CFF_Index*  index,
                            FT_Byte*   *pbytes )
   {
     if (index->bytes == 0)
@@ -199,8 +229,8 @@
   }                           
 
 
-  static
-  FT_String*  t2_get_name( CFF_Index*  index,
+  LOCAL_FUNC
+  FT_String*  T2_Get_Name( CFF_Index*  index,
                            FT_UInt     element )
   {
     FT_Memory  memory = index->stream->memory;
@@ -209,7 +239,7 @@
     FT_Error   error;
     FT_String* name = 0;
     
-    error = t2_access_element( index, element, &bytes, &byte_len );
+    error = T2_Access_Element( index, element, &bytes, &byte_len );
     if (error) goto Exit;
     
     if ( !ALLOC( name, byte_len+1 ) )
@@ -217,14 +247,14 @@
       MEM_Copy( name, bytes, byte_len );
       name[byte_len] = 0;
     }
-    t2_forget_element( index, &bytes );
-    
+    T2_Forget_Element( index, &bytes );
+
   Exit:
     return name;
   }                           
 
 
-#if 0
+#if 0 /* unused until we fully support pure-CFF fonts */
   LOCAL_FUNC
   FT_String*  T2_Get_String( CFF_Index*          index,
                              FT_UInt             sid,
@@ -232,7 +262,7 @@
   {
     /* if it's not a standard string, return it */
     if ( sid > 390 )
-      return t2_get_name( index, sid - 390 );
+      return T2_Get_Name( index, sid - 390 );
       
     /* that's a standard string, fetch a copy from the psnamed module */
     {
@@ -318,21 +348,40 @@
       FT_Byte*   dict;
       FT_ULong   dict_len;
       CFF_Index* index = &font->top_dict_index;
+      CFF_Top_Dict*  top = &font->top_dict;
 
       /* parse the top-level font dictionary */      
       T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->top_dict );
+
+      /* set defaults */
+      memset( top, 0, sizeof(*top) );
+      top->underline_position  = -100;
+      top->underline_thickness = 50;
+      top->charstring_type     = 2;
+      top->font_matrix.xx      = 0x10000;
+      top->font_matrix.yy      = 0x10000;
+      top->cid_count           = 8720;
       
-      error = t2_access_element( index, face_index, &dict, &dict_len ) ||
+      error = T2_Access_Element( index, face_index, &dict, &dict_len ) ||
               T2_Parser_Run( &parser, dict, dict + dict_len );
 
-      t2_forget_element( &font->top_dict_index, &dict );
+      T2_Forget_Element( &font->top_dict_index, &dict );
       if (error) goto Exit;
       
       /* parse the private dictionary, if any */
       if (font->top_dict.private_offset && font->top_dict.private_size)
       {
-        T2_Parser_Init( &parser, T2CODE_PRIVATE, &font->private_dict );
+        CFF_Private*  priv = &font->private_dict;
         
+        /* set defaults */
+        priv->blue_shift       = 7;
+        priv->blue_fuzz        = 1;
+        priv->lenIV            = -1;
+        priv->expansion_factor = (FT_Fixed)0.06*0x10000;
+        priv->blue_scale       = (FT_Fixed)0.039625*0x10000;
+
+        T2_Parser_Init( &parser, T2CODE_PRIVATE, priv );
+        
         if ( FILE_Seek( base_offset + font->top_dict.private_offset ) ||
              ACCESS_Frame( font->top_dict.private_size )               )
           goto Exit;
@@ -357,10 +406,28 @@
         
       error = t2_new_cff_index( &font->charstrings_index, stream, 0 );
       if (error) goto Exit;
+
+      /* read the local subrs */      
+      if ( FILE_Seek( base_offset + font->top_dict.private_offset +
+                      font->private_dict.local_subrs_offset ) )
+        goto Exit;
+        
+      error = t2_new_cff_index( &font->local_subrs_index, stream, 1 );
+      if (error) goto Exit;
+      
+      /* explicit the global and local subrs */
+      font->num_local_subrs  = font->local_subrs_index.count;
+      font->num_global_subrs = font->global_subrs_index.count;
+      
+      error = t2_explicit_cff_index( &font->global_subrs_index,
+                                     &font->global_subrs ) ||
+              t2_explicit_cff_index( &font->local_subrs_index,
+                                     &font->local_subrs );
+      if (error) goto Exit;
     }
 
     /* get the font name */      
-    font->font_name = t2_get_name( &font->name_index, face_index );
+    font->font_name = T2_Get_Name( &font->name_index, face_index );
 
   Exit:
     return error;
@@ -369,11 +436,17 @@
   LOCAL_FUNC
   void  T2_Done_CFF_Font( CFF_Font*  font )
   {
+    FT_Memory  memory = font->memory;
+    
     t2_done_cff_index( &font->global_subrs_index );
     t2_done_cff_index( &font->string_index );
     t2_done_cff_index( &font->top_dict_index );
     t2_done_cff_index( &font->name_index );
     t2_done_cff_index( &font->charstrings_index );
+
+    FREE( font->local_subrs );
+    FREE( font->global_subrs );    
+    FREE( font->font_name );
   }
 
 
--- a/src/cff/t2load.h
+++ b/src/cff/t2load.h
@@ -25,6 +25,28 @@
   extern "C" {
 #endif
 
+  LOCAL_FUNC
+  FT_String*  T2_Get_Name( CFF_Index*  index,
+                           FT_UInt     element );
+
+#if 0  /* will be used later for pure-CFF font support */
+  LOCAL_DEF
+  FT_String*  T2_Get_String( CFF_Index*          index,
+                             FT_UInt             sid,
+                             PSNames_Interface*  interface );
+#endif
+
+  LOCAL_DEF
+  FT_Error  T2_Access_Element( CFF_Index*   index,
+                               FT_UInt      element,
+                               FT_Byte*    *pbytes,
+                               FT_ULong    *pbyte_len );
+
+  LOCAL_DEF
+  void  T2_Forget_Element( CFF_Index*  index,
+                           FT_Byte*   *pbytes );
+
+
 #ifdef __cplusplus
   }
 #endif
--- a/src/cff/t2objs.c
+++ b/src/cff/t2objs.c
@@ -104,6 +104,7 @@
     {
       CFF_Font*  cff;
       FT_Memory  memory = face->root.memory;
+      FT_Face    root;
       
       if ( ALLOC( cff, sizeof(*cff) ) )
         goto Exit;
@@ -110,6 +111,12 @@
         
       face->other = cff;
       error = T2_Load_CFF_Font( stream, face_index, cff );
+      if (error) goto Exit;
+
+      /* complement the root flags with some interesting information  */
+      /* note that for OpenType/CFF, there is no need to do this, but */
+      /* this will be necessary for pure CFF fonts through..          */
+      root = &face->root;
     }
 
   Exit:
@@ -258,17 +265,13 @@
   LOCAL_FUNC
   FT_Error  T2_Init_GlyphSlot( T2_GlyphSlot  slot )
   {
-    /* allocate the outline space */
-    FT_Face     face    = slot->face;
-    FT_Library  library = face->driver->library;
+    FT_Library  library = slot->root.face->driver->library;
 
-    FT_TRACE4(( "TT.Init_GlyphSlot: Creating outline maxp = %d, maxc = %d\n",
-                face->max_points, face->max_contours ));
+    slot->max_points         = 0;
+    slot->max_contours       = 0;
+    slot->root.bitmap.buffer = 0;
 
-    return FT_Outline_New( library,
-                           face->max_points + 2,
-                           face->max_contours,
-                           &slot->outline );
+    return FT_Outline_New( library, 0, 0, &slot->root.outline );
   }
 
 
@@ -286,13 +289,13 @@
   LOCAL_FUNC
   void  T2_Done_GlyphSlot( T2_GlyphSlot  slot )
   {
-    FT_Library  library = slot->face->driver->library;
+    FT_Library  library = slot->root.face->driver->library;
     FT_Memory   memory  = library->memory;
 
-    if (slot->flags & ft_glyph_own_bitmap)
-      FREE( slot->bitmap.buffer );
+    if (slot->root.flags & ft_glyph_own_bitmap)
+      FREE( slot->root.bitmap.buffer );
 
-    FT_Outline_Done( library, &slot->outline );
+    FT_Outline_Done( library, &slot->root.outline );
     return;
   }
 
--- a/src/cff/t2objs.h
+++ b/src/cff/t2objs.h
@@ -65,7 +65,21 @@
   /*    This is a direct typedef of FT_GlyphSlot, as there is nothing      */
   /*    specific about the OpenType glyph slot.                            */
   /*                                                                       */
-  typedef FT_GlyphSlot  T2_GlyphSlot;
+
+  typedef struct T2_GlyphSlotRec_
+  {
+    FT_GlyphSlotRec  root;
+
+    FT_Bool          hint;
+    FT_Bool          scaled;
+
+    FT_Int           max_points;
+    FT_Int           max_contours;
+
+    FT_Fixed         x_scale;
+    FT_Fixed         y_scale;
+
+  } T2_GlyphSlotRec, *T2_GlyphSlot;
 
 
 
--- a/src/cff/t2parse.c
+++ b/src/cff/t2parse.c
@@ -64,7 +64,7 @@
     if (v == 28)
     {
       if ( p+2 > limit ) goto Bad;
-      val = ((FT_Long)p[0] << 8) | p[1];
+      val = (FT_Short)(((FT_Int)p[0] << 8) | p[1]);
       p  += 2;
     }
     else if (v == 29)
@@ -261,10 +261,10 @@
     error = T2_Err_Stack_Underflow;
     if (parser->top >= parser->stack + 4)
     {
-      bbox->xMin = t2_parse_fixed( data++ );
-      bbox->yMin = t2_parse_fixed( data++ );
-      bbox->xMax = t2_parse_fixed( data++ );
-      bbox->yMax = t2_parse_fixed( data   );
+      bbox->xMin = t2_parse_num( data++ );
+      bbox->yMin = t2_parse_num( data++ );
+      bbox->xMax = t2_parse_num( data++ );
+      bbox->yMax = t2_parse_num( data   );
       error = 0;
     }
     return error;
@@ -281,8 +281,8 @@
     error = T2_Err_Stack_Underflow;
     if (parser->top >= parser->stack + 2)
     {
-      dict->private_offset = t2_parse_num( data++ );
-      dict->private_size   = t2_parse_num( data );
+      dict->private_size   = t2_parse_num( data++ );
+      dict->private_offset = t2_parse_num( data   );
       error = 0;
     }
     return error;
@@ -319,7 +319,7 @@
 #define T2_REF(s,f)   (((s*)0)->f)
 
 #define T2_FIELD_CALLBACK( code, name ) \
-     { t2_kind_callback, code, 0, 0, parse_ ## name, 0, 0 },
+     { t2_kind_callback, code | T2CODE, 0, 0, parse_ ## name, 0, 0 },
      
 #undef  T2_FIELD
 #define T2_FIELD( code, name, kind )           \
@@ -363,7 +363,7 @@
     while (p < limit)
     {
       FT_Byte  v = *p;
-      if ( v >= 27 || v != 31 )
+      if ( v >= 27 && v != 31 )
       {
         /* its a number, we'll push its position on the stack */
         if (parser->top - parser->stack >= T2_MAX_STACK_DEPTH)
@@ -404,6 +404,7 @@
         /* first of all, a trivial check */
         if ( num_args < 1 ) goto Stack_Underflow;
 
+        *parser->top = p;
         code = v;
         if (v == 12)
         {
@@ -476,16 +477,14 @@
                   error = field->reader( parser );
                   if (error) goto Exit;
             }
-            /* clear stack */
-            parser->top = parser->stack;
+            goto Found;
           }
-          goto Found;  /* exit loop */
         }
 
         /* this is an unknown operator, or it is unsupported, we will ignore */
         /* it for now...                                                     */
-        
-      Found:
+
+  Found:        
         /* clear stack */
         parser->top = parser->stack;
       }