shithub: freetype+ttf2subf

ref: 13217f25096025df83ddcabeff15651acd0f5d4d
dir: /src/truetype/ttgload.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  ttgload.c                                                              */
/*                                                                         */
/*    TrueType Glyph Loader (body).                                        */
/*                                                                         */
/*  Copyright 1996-2001, 2002 by                                           */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_CALC_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_SFNT_H
#include FT_TRUETYPE_TAGS_H
#include FT_OUTLINE_H

#include "ttgload.h"

#include "tterrors.h"


  /*************************************************************************/
  /*                                                                       */
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_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



  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    TT_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.                                              */
  /*                                                                       */
  /*    idx     :: 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_LOCAL_DEF( void )
  TT_Get_Metrics( TT_HoriHeader*  header,
                  FT_UInt         idx,
                  FT_Short*       bearing,
                  FT_UShort*      advance )
  {
    TT_LongMetrics  longs_m;
    FT_UShort       k = header->number_Of_HMetrics;


    if ( idx < (FT_UInt)k )
    {
      longs_m  = (TT_LongMetrics )header->long_metrics + idx;
      *bearing = longs_m->bearing;
      *advance = longs_m->advance;
    }
    else
    {
      *bearing = ((TT_ShortMetrics*)header->short_metrics)[idx - k];
      *advance = ((TT_LongMetrics )header->long_metrics)[k - 1].advance;
    }
  }


  /*************************************************************************/
  /*                                                                       */
  /* 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( TT_Face     face,
                FT_UInt     idx,
                FT_Bool     check,
                FT_Short*   lsb,
                FT_UShort*  aw )
  {
    TT_Get_Metrics( &face->horizontal, idx, lsb, aw );

    if ( check && face->postscript.isFixedPitch )
      *aw = face->horizontal.advance_Width_Max;
  }


  /*************************************************************************/
  /*                                                                       */
  /* Returns the advance width table for a given pixel size if it is found */
  /* in the font's `hdmx' table (if any).                                  */
  /*                                                                       */
  static FT_Byte*
  Get_Advance_Widths( TT_Face    face,
                      FT_UShort  ppem )
  {
    FT_UShort  n;


    for ( n = 0; n < face->hdmx.num_records; n++ )
      if ( face->hdmx.records[n].ppem == ppem )
        return face->hdmx.records[n].widths;

    return NULL;
  }


#define cur_to_org( n, zone ) \
          FT_MEM_COPY( (zone)->org, (zone)->cur, (n) * sizeof ( FT_Vector ) )

#define org_to_cur( n, zone ) \
          FT_MEM_COPY( (zone)->cur, (zone)->org, (n) * sizeof ( FT_Vector ) )


  /*************************************************************************/
  /*                                                                       */
  /* Translates an array of coordinates.                                   */
  /*                                                                       */
  static void
  translate_array( FT_UInt     n,
                   FT_Vector*  coords,
                   FT_Pos      delta_x,
                   FT_Pos      delta_y )
  {
    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;
  }


  static void
  tt_prepare_zone( TT_GlyphZone  zone,
                   FT_GlyphLoad  load,
                   FT_UInt       start_point,
                   FT_UInt       start_contour )
  {
    zone->n_points   = (FT_UShort)( load->outline.n_points - start_point );
    zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour );
    zone->org        = load->extra_points + start_point;
    zone->cur        = load->outline.points + start_point;
    zone->tags       = (FT_Byte*)load->outline.tags + start_point;
    zone->contours   = (FT_UShort*)load->outline.contours + start_contour;
  }


#undef  IS_HINTED
#define IS_HINTED( flags )  ( ( flags & FT_LOAD_NO_HINTING ) == 0 )


  /*************************************************************************/
  /*                                                                       */
  /* The following functions are used by default with TrueType fonts.      */
  /* However, they can be replaced by alternatives if we need to support   */
  /* TrueType-compressed formats (like MicroType) in the future.           */
  /*                                                                       */
  /*************************************************************************/

  FT_CALLBACK_DEF( FT_Error )
  TT_Access_Glyph_Frame( TT_Loader  loader,
                         FT_UInt    glyph_index,
                         FT_ULong   offset,
                         FT_UInt    byte_count )
  {
    FT_Error   error;
    FT_Stream  stream = loader->stream;

    /* for non-debug mode */
    FT_UNUSED( glyph_index );


    FT_TRACE5(( "Glyph %ld\n", glyph_index ));

    /* the following line sets the `error' variable through macros! */
    if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) )
      return error;

    return TT_Err_Ok;
  }


  FT_CALLBACK_DEF( void )
  TT_Forget_Glyph_Frame( TT_Loader  loader )
  {
    FT_Stream  stream = loader->stream;


    FT_FRAME_EXIT();
  }


  FT_CALLBACK_DEF( FT_Error )
  TT_Load_Glyph_Header( TT_Loader  loader )
  {
    FT_Stream  stream   = loader->stream;
    FT_Int     byte_len = loader->byte_len - 10;


    if ( byte_len < 0 )
      return TT_Err_Invalid_Outline;

    loader->n_contours = FT_GET_SHORT();

    loader->bbox.xMin = FT_GET_SHORT();
    loader->bbox.yMin = FT_GET_SHORT();
    loader->bbox.xMax = FT_GET_SHORT();
    loader->bbox.yMax = FT_GET_SHORT();

    FT_TRACE5(( "  # of contours: %d\n", loader->n_contours ));
    FT_TRACE5(( "  xMin: %4d  xMax: %4d\n", loader->bbox.xMin,
                                            loader->bbox.xMax ));
    FT_TRACE5(( "  yMin: %4d  yMax: %4d\n", loader->bbox.yMin,
                                            loader->bbox.yMax ));
    loader->byte_len = byte_len;

    return TT_Err_Ok;
  }


  FT_CALLBACK_DEF( FT_Error )
  TT_Load_Simple_Glyph( TT_Loader  load )
  {
    FT_Error        error;
    FT_Stream       stream     = load->stream;
    FT_GlyphLoader  gloader    = load->gloader;
    FT_Int          n_contours = load->n_contours;
    FT_Outline*     outline;
    TT_Face         face       = (TT_Face)load->face;
    TT_GlyphSlot    slot       = (TT_GlyphSlot)load->glyph;
    FT_UShort       n_ins;
    FT_Int          n, n_points;
    FT_Int          byte_len   = load->byte_len;


    /* reading the contours endpoints & number of points */
    {
      short*  cur   = gloader->current.outline.contours;
      short*  limit = cur + n_contours;


      /* check space for contours array + instructions count */
      byte_len -= 2 * ( n_contours + 1 );
      if ( byte_len < 0 )
        goto Invalid_Outline;

      for ( ; cur < limit; cur++ )
        cur[0] = FT_GET_USHORT();

      n_points = 0;
      if ( n_contours > 0 )
        n_points = cur[-1] + 1;

      error = FT_GlyphLoader_CheckPoints( gloader, n_points + 2, 0 );
      if ( error )
        goto Fail;

      /* we'd better check the contours table right now */
      outline = &gloader->current.outline;

      for ( cur = outline->contours + 1; cur < limit; cur++ )
        if ( cur[-1] >= cur[0] )
          goto Invalid_Outline;
    }

    /* reading the bytecode instructions */
    slot->control_len  = 0;
    slot->control_data = 0;

    n_ins = FT_GET_USHORT();

    FT_TRACE5(( "  Instructions size: %d\n", n_ins ));

    if ( n_ins > face->max_profile.maxSizeOfInstructions )
    {
      FT_TRACE0(( "TT_Load_Simple_Glyph: Too many instructions!\n" ));
      error = TT_Err_Too_Many_Hints;
      goto Fail;
    }

    byte_len -= n_ins;
    if ( byte_len < 0 )
    {
      FT_TRACE0(( "TT_Load_Simple_Glyph: Instruction count mismatch!\n" ));
      error = TT_Err_Too_Many_Hints;
      goto Fail;
    }

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

    if ( ( load->load_flags                        &
         ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 &&
           load->instructions )
    {
      slot->control_len  = n_ins;
      slot->control_data = load->instructions;

      FT_MEM_COPY( load->instructions, stream->cursor, n_ins );
    }

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

    stream->cursor += n_ins;

    /* reading the point tags */
    {
      FT_Byte*  flag  = (FT_Byte*)outline->tags;
      FT_Byte*  limit = flag + n_points;
      FT_Byte   c, count;


      while ( flag < limit )
      {
        if ( --byte_len < 0 )
          goto Invalid_Outline;

        *flag++ = c = FT_GET_BYTE();
        if ( c & 8 )
        {
          if ( --byte_len < 0 )
            goto Invalid_Outline;

          count = FT_GET_BYTE();
          if ( flag + count > limit )
            goto Invalid_Outline;

          for ( ; count > 0; count-- )
            *flag++ = c;
        }
      }

      /* check that there is enough room to load the coordinates */
      for ( flag = (FT_Byte*)outline->tags; flag < limit; flag++ )
      {
        if ( *flag & 2 )
          byte_len -= 1;
        else if ( ( *flag & 16 ) == 0 )
          byte_len -= 2;

        if ( *flag & 4 )
          byte_len -= 1;
        else if ( ( *flag & 32 ) == 0 )
          byte_len -= 2;
      }

      if ( byte_len < 0 )
        goto Invalid_Outline;
    }

    /* reading the X coordinates */

    {
      FT_Vector*  vec   = outline->points;
      FT_Vector*  limit = vec + n_points;
      FT_Byte*    flag  = (FT_Byte*)outline->tags;
      FT_Pos      x     = 0;


      for ( ; vec < limit; vec++, flag++ )
      {
        FT_Pos  y = 0;


        if ( *flag & 2 )
        {
          y = FT_GET_BYTE();
          if ( ( *flag & 16 ) == 0 )
            y = -y;
        }
        else if ( ( *flag & 16 ) == 0 )
          y = FT_GET_SHORT();

        x     += y;
        vec->x = x;
      }
    }

    /* reading the Y coordinates */

    {
      FT_Vector*  vec   = gloader->current.outline.points;
      FT_Vector*  limit = vec + n_points;
      FT_Byte*    flag  = (FT_Byte*)outline->tags;
      FT_Pos      x     = 0;


      for ( ; vec < limit; vec++, flag++ )
      {
        FT_Pos  y = 0;


        if ( *flag & 4 )
        {
          y = FT_GET_BYTE();
          if ( ( *flag & 32 ) == 0 )
            y = -y;
        }
        else if ( ( *flag & 32 ) == 0 )
          y = FT_GET_SHORT();

        x     += y;
        vec->y = x;
      }
    }

    /* clear the touch tags */
    for ( n = 0; n < n_points; n++ )
      outline->tags[n] &= FT_Curve_Tag_On;

    outline->n_points   = (FT_UShort)n_points;
    outline->n_contours = (FT_Short) n_contours;

    load->byte_len = byte_len;

  Fail:
    return error;

  Invalid_Outline:
    error = TT_Err_Invalid_Outline;
    goto Fail;
  }


  FT_CALLBACK_DEF( FT_Error )
  TT_Load_Composite_Glyph( TT_Loader  loader )
  {
    FT_Error        error;
    FT_Stream       stream  = loader->stream;
    FT_GlyphLoader  gloader = loader->gloader;
    FT_SubGlyph     subglyph;
    FT_UInt         num_subglyphs;
    FT_Int          byte_len = loader->byte_len;


    num_subglyphs = 0;

    do
    {
      FT_Fixed  xx, xy, yy, yx;


      /* check that we can load a new subglyph */
      error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 );
      if ( error )
        goto Fail;

      /* check space */
      byte_len -= 4;
      if ( byte_len < 0 )
        goto Invalid_Composite;

      subglyph = gloader->current.subglyphs + num_subglyphs;

      subglyph->arg1 = subglyph->arg2 = 0;

      subglyph->flags = FT_GET_USHORT();
      subglyph->index = FT_GET_USHORT();

      /* check space */
      byte_len -= 2;
      if ( subglyph->flags & ARGS_ARE_WORDS )
        byte_len -= 2;
      if ( subglyph->flags & WE_HAVE_A_SCALE )
        byte_len -= 2;
      else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
        byte_len -= 4;
      else if ( subglyph->flags & WE_HAVE_A_2X2 )
        byte_len -= 8;

      if ( byte_len < 0 )
        goto Invalid_Composite;

      /* read arguments */
      if ( subglyph->flags & ARGS_ARE_WORDS )
      {
        subglyph->arg1 = FT_GET_SHORT();
        subglyph->arg2 = FT_GET_SHORT();
      }
      else
      {
        subglyph->arg1 = FT_GET_CHAR();
        subglyph->arg2 = FT_GET_CHAR();
      }

      /* read transform */
      xx = yy = 0x10000L;
      xy = yx = 0;

      if ( subglyph->flags & WE_HAVE_A_SCALE )
      {
        xx = (FT_Fixed)FT_GET_SHORT() << 2;
        yy = xx;
      }
      else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
      {
        xx = (FT_Fixed)FT_GET_SHORT() << 2;
        yy = (FT_Fixed)FT_GET_SHORT() << 2;
      }
      else if ( subglyph->flags & WE_HAVE_A_2X2 )
      {
        xx = (FT_Fixed)FT_GET_SHORT() << 2;
        yx = (FT_Fixed)FT_GET_SHORT() << 2;
        xy = (FT_Fixed)FT_GET_SHORT() << 2;
        yy = (FT_Fixed)FT_GET_SHORT() << 2;
      }

      subglyph->transform.xx = xx;
      subglyph->transform.xy = xy;
      subglyph->transform.yx = yx;
      subglyph->transform.yy = yy;

      num_subglyphs++;

    } while ( subglyph->flags & MORE_COMPONENTS );

    gloader->current.num_subglyphs = num_subglyphs;

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
    {
      /* we must undo the FT_FRAME_ENTER in order to point to the */
      /* composite instructions, if we find some.               */
      /* we will process them later...                          */
      /*                                                        */
      loader->ins_pos = (FT_ULong)( FT_STREAM_POS() +
                                    stream->cursor - stream->limit );
    }
#endif

    loader->byte_len = byte_len;

  Fail:
    return error;

  Invalid_Composite:
    error = TT_Err_Invalid_Composite;
    goto Fail;
  }


  FT_LOCAL_DEF( void )
  TT_Init_Glyph_Loading( TT_Face  face )
  {
    face->access_glyph_frame   = TT_Access_Glyph_Frame;
    face->read_glyph_header    = TT_Load_Glyph_Header;
    face->read_simple_glyph    = TT_Load_Simple_Glyph;
    face->read_composite_glyph = TT_Load_Composite_Glyph;
    face->forget_glyph_frame   = TT_Forget_Glyph_Frame;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    TT_Process_Simple_Glyph                                            */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Once a simple glyph has been loaded, it needs to be processed.     */
  /*    Usually, this means scaling and hinting through bytecode           */
  /*    interpretation.                                                    */
  /*                                                                       */
  static FT_Error
  TT_Process_Simple_Glyph( TT_Loader  load,
                           FT_Bool    debug )
  {
    FT_GlyphLoader  gloader  = load->gloader;
    FT_Outline*     outline  = &gloader->current.outline;
    FT_UInt         n_points = outline->n_points;
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
    FT_UInt         n_ins;
#endif
    TT_GlyphZone    zone     = &load->zone;
    FT_Error        error    = TT_Err_Ok;

    FT_UNUSED( debug );  /* used by truetype interpreter only */


#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
    n_ins = load->glyph->control_len;
#endif

    /* add shadow points */

    /* Now add the two shadow points at n and n + 1.    */
    /* We need the left side bearing and advance width. */

    {
      FT_Vector*  pp1;
      FT_Vector*  pp2;


      /* pp1 = xMin - lsb */
      pp1    = outline->points + n_points;
      pp1->x = load->bbox.xMin - load->left_bearing;
      pp1->y = 0;

      /* pp2 = pp1 + aw */
      pp2    = pp1 + 1;
      pp2->x = pp1->x + load->advance;
      pp2->y = 0;

      outline->tags[n_points    ] = 0;
      outline->tags[n_points + 1] = 0;
    }

    /* Note that we return two more points that are not */
    /* part of the glyph outline.                       */

    n_points += 2;

    /* set up zone for hinting */
    tt_prepare_zone( zone, &gloader->current, 0, 0 );

    /* eventually scale the glyph */
    if ( !( load->load_flags & FT_LOAD_NO_SCALE ) )
    {
      FT_Vector*  vec     = zone->cur;
      FT_Vector*  limit   = vec + n_points;
      FT_Fixed    x_scale = load->size->metrics.x_scale;
      FT_Fixed    y_scale = load->size->metrics.y_scale;


      /* 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 );
      }
    }

    cur_to_org( n_points, zone );

    /* eventually hint the glyph */
    if ( IS_HINTED( load->load_flags ) )
    {
      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;

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

      /* now consider hinting */
      if ( n_ins > 0 )
      {
        error = TT_Set_CodeRange( load->exec, tt_coderange_glyph,
                                  load->exec->glyphIns, n_ins );
        if ( error )
          goto Exit;

        load->exec->is_composite     = FALSE;
        load->exec->pedantic_hinting = (FT_Bool)( load->load_flags &
                                                  FT_LOAD_PEDANTIC );
        load->exec->pts              = *zone;
        load->exec->pts.n_points    += 2;

        error = TT_Run_Context( load->exec, debug );
        if ( error && load->exec->pedantic_hinting )
          goto Exit;

        error = TT_Err_Ok;  /* ignore bytecode errors in non-pedantic mode */
      }

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

    }

    /* save glyph phantom points */
    if ( !load->preserve_pps )
    {
      load->pp1 = zone->cur[n_points - 2];
      load->pp2 = zone->cur[n_points - 1];
    }

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
  Exit:
#endif
    return error;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    load_truetype_glyph                                                */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Loads a given truetype glyph.  Handles composites and uses a       */
  /*    TT_Loader object.                                                  */
  /*                                                                       */
  static FT_Error
  load_truetype_glyph( TT_Loader  loader,
                       FT_UInt    glyph_index )
  {

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
    FT_Stream       stream = loader->stream;
#endif

    FT_Error        error;
    TT_Face         face   = (TT_Face)loader->face;
    FT_ULong        offset;
    FT_Int          contours_count;
    FT_UInt         num_points, count;
    FT_Fixed        x_scale, y_scale;
    FT_GlyphLoader  gloader = loader->gloader;
    FT_Bool         opened_frame = 0;

#ifdef FT_CONFIG_OPTION_INCREMENTAL
	struct FT_StreamRec_ inc_stream;
#endif

    /* check glyph index */
    glyph_index;
    if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
    {
      error = TT_Err_Invalid_Glyph_Index;
      goto Exit;
    }

    loader->glyph_index = glyph_index;
    num_points          = 0;

    x_scale = 0x10000L;
    y_scale = 0x10000L;
    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
    {
      x_scale = loader->size->metrics.x_scale;
      y_scale = loader->size->metrics.y_scale;
    }

    /* get horizontal metrics */
    {
      FT_Short   left_bearing = 0;
      FT_UShort  advance_width = 0;

#ifdef FT_CONFIG_OPTION_INCREMENTAL
	  FT_Bool metrics_found = FALSE;

	  /* If this is an incrementally loaded font see if there are overriding metrics for this glyph. */
      if (face->root.incremental_interface && face->root.incremental_interface->funcs->get_glyph_metrics)
      {
        FT_Basic_Glyph_Metrics m;
        error = face->root.incremental_interface->funcs->get_glyph_metrics(face->root.incremental_interface->object,
            glyph_index,FALSE,&m,&metrics_found);
        if (error)
	      goto Exit;
        left_bearing = (FT_Short)m.bearing_x;
        advance_width = (FT_UShort)m.advance;
      }

	  if (!metrics_found)
        Get_HMetrics( face, glyph_index,
                      (FT_Bool)!( loader->load_flags &
                                  FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ),
                      &left_bearing,
                      &advance_width );

#else
      Get_HMetrics( face, glyph_index,
                    (FT_Bool)!( loader->load_flags &
                                FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ),
                    &left_bearing,
                    &advance_width );

#endif

      loader->left_bearing = left_bearing;
      loader->advance      = advance_width;

      if ( !loader->linear_def )
      {
        loader->linear_def = 1;
        loader->linear     = advance_width;
      }
    }

#ifdef FT_CONFIG_OPTION_INCREMENTAL
	/*
	Set 'offset' to the start of the glyph program relative to the start of the 'glyf' table,
	and 'count' to the length of the glyph program in bytes.

	If we are loading glyph data via the incremental interface, set the loader stream to a memory
	stream reading the data returned by the interface.
	*/
    if (face->root.incremental_interface)
    {
      FT_Data data;
      error = face->root.incremental_interface->funcs->get_glyph_data(face->root.incremental_interface->object,
	          glyph_index,&data);
      if (error)
        goto Exit;
      offset = 0;
      count = data.length;
      memset(&inc_stream,0,sizeof(inc_stream));
      FT_Stream_OpenMemory(&inc_stream,data.pointer,data.length);
      loader->stream = &inc_stream;
    }
    else
#endif

    {
      offset = face->glyph_locations[glyph_index];
      count  = 0;

      if ( glyph_index < (FT_UInt)face->num_locations - 1 )
        count = face->glyph_locations[glyph_index + 1] - offset;
    }

    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;

      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 );

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

      if ( loader->exec )
        loader->exec->glyphSize = 0;

#endif

      error = TT_Err_Ok;
      goto Exit;
    }

    loader->byte_len = (FT_Int)count;

    offset = loader->glyf_offset + offset;

    /* access glyph frame */
    error = face->access_glyph_frame( loader, glyph_index, offset, count );
    if ( error )
      goto Exit;

    opened_frame = 1;

    /* read first glyph header */
    error = face->read_glyph_header( loader );
    if ( error )
      goto Fail;

    contours_count = loader->n_contours;

    count -= 10;

    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 )
    {
      /* check that we can add the contours to the glyph */
      error = FT_GlyphLoader_CheckPoints( gloader, 0, contours_count );
      if ( error )
        goto Fail;

      error = face->read_simple_glyph( loader );
      if ( error )
        goto Fail;

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

      {
        TT_Size  size = (TT_Size)loader->size;


        error = TT_Process_Simple_Glyph( loader,
                                         (FT_Bool)( size && size->debug ) );
      }

#else

      error = TT_Process_Simple_Glyph( loader, 0 );

#endif

      if ( error )
        goto Fail;

      FT_GlyphLoader_Add( gloader );

      /* Note: We could have put the simple loader source there */
      /*       but the code is fat enough already :-)           */
    }

    /***********************************************************************/
    /***********************************************************************/
    /***********************************************************************/

    /* otherwise, load a composite! */
    else
    {
      TT_GlyphSlot  glyph = (TT_GlyphSlot)loader->glyph;
      FT_UInt       start_point;
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
      FT_UInt       start_contour;
      FT_ULong      ins_pos;  /* position of composite instructions, if any */
#endif


      /* for each subglyph, read composite header */
      start_point   = gloader->base.outline.n_points;
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
      start_contour = gloader->base.outline.n_contours;
#endif

      error = face->read_composite_glyph( loader );
      if ( error )
        goto Fail;

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
      ins_pos = loader->ins_pos;
#endif
      face->forget_glyph_frame( loader );
      opened_frame = 0;

      /* 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 )
      {
        /* set up remaining glyph fields */
        FT_GlyphLoader_Add( gloader );

        glyph->num_subglyphs = gloader->base.num_subglyphs;
        glyph->format        = ft_glyph_format_composite;
        glyph->subglyphs     = gloader->base.subglyphs;

        goto Exit;
      }

      /*********************************************************************/
      /*********************************************************************/
      /*********************************************************************/

      /* Now, read each subglyph independently. */
      {
        FT_Int       n, num_base_points, num_new_points;
        FT_SubGlyph  subglyph       = 0;

        FT_UInt      num_subglyphs  = gloader->current.num_subglyphs;
        FT_UInt      num_base_subgs = gloader->base.num_subglyphs;


        FT_GlyphLoader_Add( gloader );

        for ( n = 0; n < (FT_Int)num_subglyphs; n++ )
        {
          FT_Vector  pp1, pp2;
          FT_Pos     x, y;


          /* Each time we call load_truetype_glyph in this loop, the   */
          /* value of `gloader.base.subglyphs' can change due to table */
          /* reallocations.  We thus need to recompute the subglyph    */
          /* pointer on each iteration.                                */
          subglyph = gloader->base.subglyphs + num_base_subgs + n;

          pp1 = loader->pp1;
          pp2 = loader->pp2;

          num_base_points = gloader->base.outline.n_points;

          error = load_truetype_glyph( loader, subglyph->index );
          if ( error )
            goto Fail;

          /* restore subglyph pointer */
          subglyph = gloader->base.subglyphs + num_base_subgs + n;

          if ( subglyph->flags & USE_MY_METRICS )
          {
            pp1 = loader->pp1;
            pp2 = loader->pp2;
          }
          else
          {
            loader->pp1 = pp1;
            loader->pp2 = pp2;
          }

          num_points = gloader->base.outline.n_points;

          num_new_points = num_points - num_base_points;

          /* now perform the transform required for this subglyph */

          if ( subglyph->flags & ( WE_HAVE_A_SCALE     |
                                   WE_HAVE_AN_XY_SCALE |
                                   WE_HAVE_A_2X2       ) )
          {
            FT_Vector*  cur   = gloader->base.outline.points +
                                  num_base_points;
            FT_Vector*  org   = gloader->base.extra_points +
                                  num_base_points;
            FT_Vector*  limit = cur + num_new_points;


            for ( ; cur < limit; cur++, org++ )
            {
              FT_Vector_Transform( cur, &subglyph->transform );
              FT_Vector_Transform( org, &subglyph->transform );
            }
          }

          /* apply offset */

          if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
          {
            FT_UInt     k = subglyph->arg1;
            FT_UInt     l = subglyph->arg2;
            FT_Vector*  p1;
            FT_Vector*  p2;


            if ( start_point + k >= (FT_UInt)num_base_points ||
                               l >= (FT_UInt)num_new_points  )
            {
              error = TT_Err_Invalid_Composite;
              goto Fail;
            }

            l += num_base_points;

            p1 = gloader->base.outline.points + start_point + k;
            p2 = gloader->base.outline.points + start_point + l;

            x = p1->x - p2->x;
            y = p1->y - p2->y;
          }
          else
          {
            x = subglyph->arg1;
            y = subglyph->arg2;

            if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
            {
              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;
              }
            }
          }

          if ( x || y )
          {
            translate_array( num_new_points,
                             gloader->base.outline.points + num_base_points,
                             x, y );

            translate_array( num_new_points,
                             gloader->base.extra_points + num_base_points,
                             x, y );
          }
        }

        /*******************************************************************/
        /*******************************************************************/
        /*******************************************************************/

        /* we have finished loading all sub-glyphs; now, look for */
        /* instructions for this composite!                       */

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

        if ( num_subglyphs > 0               &&
             loader->exec                    &&
             ins_pos > 0                     &&
             subglyph->flags & WE_HAVE_INSTR )
        {
          FT_UShort       n_ins;
          TT_ExecContext  exec = loader->exec;
          TT_GlyphZone    pts;
          FT_Vector*      pp1;


          /* read size of instructions */
          if ( FT_STREAM_SEEK( ins_pos ) ||
               FT_READ_USHORT( n_ins ) )
            goto Fail;
          FT_TRACE5(( "  Instructions size = %d\n", n_ins ));

          /* in some fonts? */
          if ( n_ins == 0xFFFFU )
            n_ins = 0;

          /* check it */
          if ( n_ins > face->max_profile.maxSizeOfInstructions )
          {
            FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n",
                        n_ins, subglyph->index ));
            error = TT_Err_Too_Many_Hints;
            goto Fail;
          }

          /* read the instructions */
          if ( FT_STREAM_READ( exec->glyphIns, n_ins ) )
            goto Fail;

          glyph->control_data = exec->glyphIns;
          glyph->control_len  = n_ins;

          error = TT_Set_CodeRange( exec,
                                    tt_coderange_glyph,
                                    exec->glyphIns,
                                    n_ins );
          if ( error )
            goto Fail;

          /* prepare the execution context */
          tt_prepare_zone( &exec->pts, &gloader->base,
                           start_point, start_contour );
          pts = &exec->pts;

          pts->n_points   = (short)(num_points + 2);
          pts->n_contours = gloader->base.outline.n_contours;

          /* add phantom points */
          pp1    = pts->cur + num_points;
          pp1[0] = loader->pp1;
          pp1[1] = loader->pp2;

          pts->tags[num_points    ] = 0;
          pts->tags[num_points + 1] = 0;

          /* if hinting, round the phantom points */
          if ( IS_HINTED( loader->load_flags ) )
          {
            pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 );
            pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 );
          }

          {
            FT_UInt  k;


            for ( k = 0; k < num_points; k++ )
              pts->tags[k] &= FT_Curve_Tag_On;
          }

          cur_to_org( num_points + 2, pts );

          /* now consider hinting */
          if ( IS_HINTED( loader->load_flags ) && n_ins > 0 )
          {
            exec->is_composite     = TRUE;
            exec->pedantic_hinting =
              (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC );

            error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug );
            if ( error && exec->pedantic_hinting )
              goto Fail;
          }

          /* save glyph origin and advance points */
          loader->pp1 = pp1[0];
          loader->pp2 = pp1[1];
        }

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

      }
      /* end of composite loading */
    }

    /***********************************************************************/
    /***********************************************************************/
    /***********************************************************************/

  Fail:
    if ( opened_frame )
      face->forget_glyph_frame( loader );

  Exit:
    return error;
  }


  static FT_Error
  compute_glyph_metrics( TT_Loader   loader,
                         FT_UInt     glyph_index )
  {
    FT_BBox       bbox;
    TT_Face       face = (TT_Face)loader->face;
    FT_Fixed      y_scale;
    TT_GlyphSlot  glyph = loader->glyph;
    TT_Size       size = (TT_Size)loader->size;


    y_scale = 0x10000L;
    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
      y_scale = size->root.metrics.y_scale;

    if ( glyph->format != ft_glyph_format_composite )
    {
      glyph->outline.flags &= ~ft_outline_single_pass;

      /* copy outline to our glyph slot */
      FT_GlyphLoader_CopyPoints( glyph->internal->loader, loader->gloader );
      glyph->outline = glyph->internal->loader->base.outline;

      /* translate array so that (0,0) is the glyph's origin */
      FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 );

      FT_Outline_Get_CBox( &glyph->outline, &bbox );

      if ( IS_HINTED( loader->load_flags ) )
      {
        /* grid-fit the bounding box */
        bbox.xMin &= -64;
        bbox.yMin &= -64;
        bbox.xMax  = ( bbox.xMax + 63 ) & -64;
        bbox.yMax  = ( bbox.yMax + 63 ) & -64;
      }
    }
    else
      bbox = loader->bbox;

    /* get the device-independent horizontal advance.  It is scaled later */
    /* by the base layer.                                                 */
    {
      FT_Pos  advance = loader->linear;


      /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */
      /* correctly support DynaLab fonts, which 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;

      /* we need to return the advance in font units in linearHoriAdvance, */
      /* it will be scaled later by the base layer.                        */
      glyph->linearHoriAdvance = advance;
    }

    glyph->metrics.horiBearingX = bbox.xMin;
    glyph->metrics.horiBearingY = bbox.yMax;
    glyph->metrics.horiAdvance  = loader->pp2.x - loader->pp1.x;

    /* don't forget to hint the advance when we need to */
    if ( IS_HINTED( loader->load_flags ) )
      glyph->metrics.horiAdvance = ( glyph->metrics.horiAdvance + 32 ) & -64;

    /* 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'...                                      */

    {
      FT_Short   top_bearing;    /* vertical top side bearing (EM units) */
      FT_UShort  advance_height; /* vertical advance height   (EM units) */

      FT_Pos     left;     /* scaled vertical left side bearing */
      FT_Pos     top;      /* scaled vertical top side bearing  */
      FT_Pos     advance;  /* scaled vertical advance height    */
      FT_Bool    metrics_found = FALSE;

#ifdef FT_CONFIG_OPTION_INCREMENTAL
      /* If this is an incrementally loaded font see if there are overriding metrics for this glyph. */
      if (face->root.incremental_interface && face->root.incremental_interface->funcs->get_glyph_metrics)
      {
        FT_Basic_Glyph_Metrics m;
        FT_Error error =
          face->root.incremental_interface->funcs->get_glyph_metrics(face->root.incremental_interface->object,
            glyph_index,TRUE,&m,&metrics_found);
        if (error)
          return error;
        top_bearing = (FT_Short)m.bearing_y;
        advance_height = (FT_UShort)m.advance;
      }
#endif

      /* Get the unscaled top bearing and advance height. */
      if ( !metrics_found && 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 :-)                */

        TT_Get_Metrics( (TT_HoriHeader*)&face->vertical,
                        glyph_index,
                        &top_bearing,
                        &advance_height );
      }
      else
      {
        /* Make up the distances from the horizontal header.   */

        /* NOTE: The OS/2 values are the only `portable' ones, */
        /*       which is why we use them, if 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 != 0xFFFFU )
        {
          top_bearing    = (FT_Short)( face->os2.sTypoLineGap / 2 );
          advance_height = (FT_UShort)( face->os2.sTypoAscender -
                                        face->os2.sTypoDescender +
                                        face->os2.sTypoLineGap );
        }
        else
        {
          top_bearing    = (FT_Short)( face->horizontal.Line_Gap / 2 );
          advance_height = (FT_UShort)( face->horizontal.Ascender  +
                                        face->horizontal.Descender +
                                        face->horizontal.Line_Gap );
        }
      }

      /* We must adjust the top_bearing value from the bounding box given */
      /* in the glyph header to te bounding box calculated with           */
      /* FT_Get_Outline_CBox().                                           */

      /* scale the metrics */
      if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
      {
        top     = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale )
                    - bbox.yMax;
        advance = FT_MulFix( advance_height, y_scale );
      }
      else
      {
        top     = top_bearing + loader->bbox.yMax - bbox.yMax;
        advance = advance_height;
      }

      /* set the advance height in design units.  It is scaled later by */
      /* the base layer.                                                */
      glyph->linearVertAdvance = advance_height;

      /* XXX: for now, we have no better algorithm for the lsb, but it */
      /*      should work fine.                                        */
      /*                                                               */
      left = ( bbox.xMin - bbox.xMax ) / 2;

      /* grid-fit them if necessary */
      if ( IS_HINTED( loader->load_flags ) )
      {
        left   &= -64;
        top     = ( top + 63     ) & -64;
        advance = ( advance + 32 ) & -64;
      }

      glyph->metrics.vertBearingX = left;
      glyph->metrics.vertBearingY = top;
      glyph->metrics.vertAdvance  = advance;
    }

    /* 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;
    }

    /* set glyph dimensions */
    glyph->metrics.width  = bbox.xMax - bbox.xMin;
    glyph->metrics.height = bbox.yMax - bbox.yMin;

    return 0;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    TT_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).                  */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  FT_LOCAL_DEF( FT_Error )
  TT_Load_Glyph( TT_Size       size,
                 TT_GlyphSlot  glyph,
                 FT_UShort     glyph_index,
                 FT_UInt       load_flags )
  {
    SFNT_Service  sfnt;
    TT_Face       face;
    FT_Stream     stream;
    FT_Error      error;
    TT_LoaderRec  loader;


    face   = (TT_Face)glyph->face;
    sfnt   = (SFNT_Service)face->sfnt;
    stream = face->root.stream;
    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              */
    /*                                                 */
    /* XXX: The convention should be emphasized in     */
    /*      the documents because it can be confusing. */
    if ( size                                    &&
         size->strike_index != 0xFFFFU           &&
         sfnt->load_sbits                        &&
         ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )

    {
      TT_SBit_MetricsRec  metrics;


      error = sfnt->load_sbit_image( face,
                                     size->strike_index,
                                     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;
        if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
        {
          glyph->bitmap_left = metrics.vertBearingX;
          glyph->bitmap_top  = metrics.vertBearingY;
        }
        else
        {
          glyph->bitmap_left = metrics.horiBearingX;
          glyph->bitmap_top  = metrics.horiBearingY;
        }
        return error;
      }
    }

#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */

    /* return immediately if we only want the embedded bitmaps */
    if ( load_flags & FT_LOAD_SBITS_ONLY )
      return FT_Err_Invalid_Argument;

    /* seek to the beginning of the glyph table.  For Type 42 fonts      */
    /* the table might be accessed from a Postscript stream or something */
    /* else...                                                           */
#ifdef FT_CONFIG_OPTION_INCREMENTAL
	/* Don't look for the glyph table if this is an incremental font. */
    if (!face->root.incremental_interface)
#endif
	{
      error = face->goto_table( face, TTAG_glyf, stream, 0 );
      if ( error )
      {
        FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" ));
        goto Exit;
      }
	}

    FT_MEM_SET( &loader, 0, sizeof ( loader ) );

    /* update the glyph zone bounds */
    {
      FT_GlyphLoader  gloader = FT_FACE_DRIVER(face)->glyph_loader;


      loader.gloader = gloader;

      FT_GlyphLoader_Rewind( gloader );

      tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 );
      tt_prepare_zone( &loader.base, &gloader->base, 0, 0 );
    }

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

    if ( size )
    {
      /* query new execution context */
      loader.exec = size->debug ? size->context : TT_New_Context( face );
      if ( !loader.exec )
        return TT_Err_Could_Not_Find_Context;

      TT_Load_Context( loader.exec, face, size );
      loader.instructions = loader.exec->glyphIns;

      /* load default graphics state - if needed */
      if ( size->GS.instruct_control & 2 )
        loader.exec->GS = tt_default_graphics_state;
    }

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

    /* clear all outline flags, except the `owner' one */
    glyph->outline.flags = 0;

    /* let's initialize the rest of our loader now */

    loader.load_flags    = load_flags;

    loader.face   = (FT_Face)face;
    loader.size   = (FT_Size)size;
    loader.glyph  = (FT_GlyphSlot)glyph;
    loader.stream = stream;

#ifdef FT_CONFIG_OPTION_INCREMENTAL
    if (face->root.incremental_interface)
      loader.glyf_offset = 0;
	else
#endif
      loader.glyf_offset  = FT_STREAM_POS();

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

    /* if the cvt program has disabled hinting, the argument */
    /* is ignored.                                           */
    if ( size && ( size->GS.instruct_control & 1 ) )
      loader.load_flags |= FT_LOAD_NO_HINTING;

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

    /* 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 );

#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER

    if ( !size || !size->debug )
      TT_Done_Context( loader.exec );

#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */

    /* Set the `high precision' bit flag.                           */
    /* This is _critical_ to get correct output for monochrome      */
    /* TrueType glyphs at all sizes using the bytecode interpreter. */
    /*                                                              */
    if ( size && size->root.metrics.y_ppem < 24 )
      glyph->outline.flags |= ft_outline_high_precision;

  Exit:
    return error;
  }


/* END */