/*******************************************************************
 *
 *  ttgload.c                                                   1.0
 *
 *    TrueType Glyph Loader.                           
 *
 *  Copyright 1996, 1997 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 "tttypes.h"
#include "tterror.h"
#include "ttcalc.h"
#include "ttfile.h"

#include "tttables.h"
#include "ttobjs.h"
#include "ttgload.h"

#include "ttmemory.h"
#include "tttags.h"
#include "ttload.h"


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


  static void  Get_HMetrics( PFace  face,
                             Int    index,
                             Bool   check,
                             Int*   lsb,
                             Int*   aw    )
  {
    Int  k;

    k = face->horizontalHeader.number_Of_HMetrics;

    if ( index < k )
    {
      *lsb = face->longHMetrics[index].lsb;
      *aw  = face->longHMetrics[index].advance_Width;
    }
    else
    {
      *lsb = face->shortMetrics[index-k];
      *aw  = face->longHMetrics[k-1].advance_Width;
    }
    if ( check && face->postscript.isFixedPitch )
      *aw = face->horizontalHeader.advance_Width_Max;
  }


  static PByte  Get_Advance_Widths( PFace  face,
                                    Int    ppem )
  {
    Int  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;
  }


 static TT_Error  Append_Outline( PSubglyph_Record  subg,
                                  Int*              left_contours,
                                  Int*              left_points,
                                  TT_Outline*       outline )
 {               
   PCoordinates org_x, org_y, cur_x, cur_y;
   PTouchTable  flag;
   UShort*      cons;
   Int          k;

   if ( outline->contours > *left_contours )
     return TT_Err_Too_Many_Contours;

   if ( outline->points > *left_points )
     return TT_Err_Too_Many_Points;

   org_x = subg->org_x + subg->n_points;
   org_y = subg->org_y + subg->n_points;
   cur_x = subg->cur_x + subg->n_points;
   cur_y = subg->cur_y + subg->n_points;
   flag  = subg->flag  + subg->n_points;

   cons = subg->contours + subg->n_contours;

   for ( k = 0; k < outline->points; k++ )
   {
     org_x[k] = cur_x[k] = outline->xCoord[k];
     org_y[k] = cur_y[k] = outline->yCoord[k];
     flag[k]  = outline->flag[k];
   }

   for ( k = 0; k < outline->contours; k++ )
     cons[k] = subg->n_points + outline->conEnds[k];

   subg->n_points   += outline->points;
   subg->n_contours += outline->contours;

   *left_points   -= outline->points;
   *left_contours -= outline->contours;

   return TT_Err_Ok;
 }


 static TT_Error  Load_Simple_Glyph( PExecution_Context  exec,
                                     TT_Stream           input,
                                     Int                 n_contours,
                                     Int                 left_contours,
                                     Int                 left_points,
                                     Int                 load_flags,
                                     PSubglyph_Record    subg )
  {
    DEFINE_LOAD_LOCALS( input );

    Int   k, n_points, n_ins;
    Byte  c, cnt;

    PFace  face;

    PCoordinates  xs, ys;
    PTouchTable   flag;

    TT_F26Dot6  x, y, xmin, ymin, xmax, ymax;

    PVecRecord  pts;

    Int  leftSideBearing;
    Int  advanceWidth;


    face = exec->owner;


    /* simple check */

    if ( n_contours > left_contours )
    {
      DebugTrace(( "ERROR: Glyph index %d has %d contours > left %d\n",
                   subg->index, n_contours, left_contours ));
      return TT_Err_Too_Many_Contours;
    }


    /* preparing the execution context */

    exec->pts.n     = 0;
    exec->pts.org_x = subg->org_x + subg->n_points;
    exec->pts.org_y = subg->org_y + subg->n_points;
    exec->pts.cur_x = subg->cur_x + subg->n_points;
    exec->pts.cur_y = subg->cur_y + subg->n_points;
    exec->pts.touch = subg->flag  + subg->n_points;

    exec->numContours = 0;
    exec->endContours = subg->contours + subg->n_contours;


    /* reading the contours endpoints */

    if ( ACCESS_Frame( (n_contours + 1) * 2L ) )
      return error;

    n_points = 0;

    for ( k = 0; k < n_contours; k++ )
    {
      DebugTrace(( "%d ", n_points ));
      exec->endContours[k] = n_points = GET_Short();
      n_points++;
    }

    n_ins = GET_Short();

    FORGET_Frame();

    if ( n_points > left_points )
    {
      DebugTrace(( "ERROR: Too many points in glyph %d\n", subg->index ));
      return TT_Err_Too_Many_Points;
    }

    /* loading instructions */

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

    if ( n_ins > face->maxProfile.maxSizeOfInstructions )
    {
      DebugTrace(( "ERROR: Too many instructions!\n" ));
      return TT_Err_Too_Many_Ins;
    }

    if ( FILE_Read( exec->glyphIns,  n_ins ) )
      return error;

    exec->glyphSize = n_ins;

    if ( ( error = Set_CodeRange( exec, 
                                  TT_CodeRange_Glyph, 
                                  exec->glyphIns, 
                                  exec->glyphSize ) ) )
      return error;  


    /* read the flags */

    if ( CHECK_ACCESS_Frame( n_points * 5L ) )
      return error;

    k    = 0;
    flag = exec->pts.touch;

    while ( k < n_points )
    {
      flag[k] = c = GET_Byte();
      k++;

      if ( c & 8 )
      {
        cnt = GET_Byte();
        while( cnt > 0 )
        {
          flag[k++] = c;
          cnt--;
        }
      }
    }


    /* read the X */

    x    = 0;
    xmin = 0;
    xmax = 0;
    xs   = exec->pts.org_x;

    for ( k = 0; k < n_points; k++ )
    {
      if ( flag[k] & 2 )
      {
        if ( flag[k] & 16 )
          x += GET_Byte();
        else
          x -= GET_Byte();
      }
      else
      {
        if ( (flag[k] & 16) == 0 )
          x += GET_Short();
      }

      xs[k] = x;

      if ( x < xmin ) xmin = x;
      if ( x > xmax ) xmax = x;
    }


   /* read the Y */

    y    = 0;
    ymin = 0;
    ymax = 0;
    ys   = exec->pts.org_y;

    for ( k = 0; k < n_points; k++ )
    {
      if ( flag[k] & 4 )
      {
        if ( flag[k] & 32 )
          y += GET_Byte();
        else
          y -= GET_Byte();
      }
      else
      {
        if ( (flag[k] & 32) == 0 )
          y += GET_Short();
      }

      ys[k] = y;

      if ( y < ymin ) ymin = y;
      if ( y > ymax ) ymax = y;
    }

    FORGET_Frame();

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

    Get_HMetrics( face, subg->index, FALSE, &leftSideBearing, &advanceWidth );

    subg->leftSideBearing = leftSideBearing;
    subg->advanceWidth    = advanceWidth;

    /* pp1 = xMin - lsb */
    xs[n_points] = subg->xMin - leftSideBearing;
    ys[n_points] = 0;

    /* pp2 = pp1 + aw */
    xs[n_points+1] = xs[n_points] + advanceWidth;
    ys[n_points+1] = 0;

    /* clear the touch flags */

    for ( k = 0; k < n_points; k++ )
      exec->pts.touch[k] &= TT_Flag_On_Curve;

    exec->pts.touch[n_points    ] = 0;
    exec->pts.touch[n_points + 1] = 0;

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

    n_points += 2;

    /* now eventually scale and hint the glyph */

    pts    = &exec->pts;
    pts->n = n_points;

    exec->numContours = n_contours;

    if ( (load_flags & TTLOAD_SCALE_GLYPH) == 0 )
    {
      /* no scaling, just copy the orig arrays into the cur ones */

      for ( k = 0; k < n_points; k++ )
      {
        pts->cur_x[k] = pts->org_x[k];
        pts->cur_y[k] = pts->org_y[k];
      }
    }
    else
    {
     /* first scale the glyph points */

      for ( k = 0; k < n_points; k++ )
      {
        x = MulDiv_Round( pts->org_x[k],
                          exec->metrics.x_scale1, 
                          exec->metrics.x_scale2 );

        y = MulDiv_Round( pts->org_y[k], 
                          exec->metrics.y_scale1, 
                          exec->metrics.y_scale2 );

        pts->org_x[k] = x;
        pts->org_y[k] = y;
        pts->cur_x[k] = x;
        pts->cur_y[k] = y;
      }


      /* scale advance width and left side bearing too */

      subg->leftSideBearing =
        MulDiv_Round( leftSideBearing,
                      exec->metrics.x_scale1,
                      exec->metrics.x_scale2 ) & -64;

      subg->advanceWidth =
        ( MulDiv_Round( advanceWidth,
                        exec->metrics.x_scale1,
                        exec->metrics.x_scale2 ) + 32 ) & -64;

      /* then round the phantom points. This is critical for correct */
      /* hinting at low ppems                                        */

      x = pts->cur_x[n_points-2];
      y = pts->cur_x[n_points-1];

      if ( x >= 0 )
        x = x & -64;
      else
        x = -( (-x) & -64 );

      y = ( y + 32 ) & -64;

      pts->cur_x[n_points-2] = x;
      pts->cur_x[n_points-1] = y;


      /* now consider hinting */

      if ( subg->is_hinted && n_ins > 0 )
        if ( ( error = Context_Run( exec, FALSE ) ) )
          return error;

      /* adjust advance width to its grid-fitted value */

      if (!exec->owner->postscript.isFixedPitch)
        subg->advanceWidth = pts->cur_x[n_points - 1] -
                             pts->cur_x[n_points - 2];
      else
        subg->advanceWidth = MulDiv_Round(
           exec->owner->horizontalHeader.advance_Width_Max,
           exec->metrics.x_scale1,
           exec->metrics.x_scale2 );
    }

    return TT_Err_Ok;
  }


  static
  TT_Error  Load_Composite_Instructions( Int                 n_points,
                                         Int                 n_contours,
                                         PExecution_Context  exec,
                                         PSubglyph_Record    subg )
  {
    Int  k;

    PVecRecord  pts;
    TT_Error    error;


    /* prepare the execution context */

    exec->pts.n     = n_points+2;
    exec->pts.org_x = subg->org_x;
    exec->pts.org_y = subg->org_y;
    exec->pts.cur_x = subg->cur_x;
    exec->pts.cur_y = subg->cur_y;
    exec->pts.touch = subg->flag;

    exec->numContours = n_contours;
    exec->endContours = subg->contours;

    pts = &exec->pts;


    /* add phantom points */

    pts->cur_x[n_points] = subg->xMin - subg->leftSideBearing;
    pts->cur_y[n_points] = 0;
    /* pp1 = xMin - lsb */

    pts->cur_x[n_points+1]   = subg->xMin - subg->leftSideBearing +
                                 subg->advanceWidth;
    pts->cur_y[n_points + 1] = 0;
    /* pp2 = pp1 + aw */

    for ( k = 0; k < n_points + 2; k++ )
    {
      pts->org_x[k] = pts->cur_x[k];
      pts->org_y[k] = pts->cur_y[k];
      pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve;
    }

    if ( ( error = Set_CodeRange( exec, 
                                  TT_CodeRange_Glyph, 
                                  exec->glyphIns, 
                                  exec->glyphSize ) ) )
     return error;  


    /* now consider hinting */

    if ( subg->is_hinted && 
         exec->glyphSize > 0 )
      return Context_Run( exec, FALSE );
    else
      return TT_Err_Ok;
  }


  static
  void  Init_Glyph_Component( PSubglyph_Record    element,
                              PSubglyph_Record    original,
                              PExecution_Context  exec )
  {
    Int  n;


    element->index     = -1;
    element->is_scaled = FALSE;

    element->n_contours = 0;
    element->n_points   = 0;

    if ( original )
    {
      element->is_hinted = original->is_hinted;

      n = original->n_points;
      element->org_x = original->org_x + n;
      element->org_y = original->org_y + n;
      element->cur_x = original->cur_x + n;
      element->cur_y = original->cur_y + n;
      element->flag  = original->flag  + n;

      n = original->n_contours;
      element->contours = original->contours + n;
    }
    else
    {
      element->is_hinted = FALSE;

      element->org_x = exec->pts.org_x;
      element->org_y = exec->pts.org_y;
      element->cur_x = exec->pts.cur_x;
      element->cur_y = exec->pts.cur_y;
      element->flag  = exec->pts.touch;

      element->contours = exec->endContours;
    }

    element->arg1 = 0;
    element->arg2 = 0;

    element->element_flag = 0;

    element->transform.xx = 1 << 16;
    element->transform.xy = 0;
    element->transform.yx = 0;
    element->transform.yy = 1 << 16;

    element->transform.ox = 0;
    element->transform.oy = 0;

    element->leftSideBearing = 0;
    element->advanceWidth    = 0;
  }



  TT_Error  Load_TrueType_Glyph(  PInstance   instance,
                                  PGlyph      glyph,
                                  Int         glyph_index,
                                  Int         load_flags )
  {
    enum _TPhases
    {
      Load_Exit,
      Load_Glyph,
      Load_Header,
      Load_Simple,
      Load_Composite,
      Load_End
    };

    typedef enum _TPhases  TPhases;

    DEFINE_ALL_LOCALS;

    PFace   face;

    Int  num_points;
    Int  num_contours;
    Int  left_points;
    Int  left_contours;

    Int  table, index, load_top, new_flags, k, l;

    Long  glyph_offset, offset;

    TT_F26Dot6  x, y, nx, ny;
    TT_F26Dot6  xmin, xmax, ymin, ymax;

    Fixed  xx, xy, yx, yy;

    PExecution_Context  exec;

    PSubglyph_Record  subglyph, subglyph2;

    TVecRecord  base_pts;
    Int         base_n_contours;
    PUShort     base_contours;

    TPhases     phase;
    PByte       widths;

    TT_Glyph_Loader_Callback  cacheCb;
    TT_Outline                cached_outline;

    /* first of all, check arguments */
    if ( !glyph )
      return TT_Err_Invalid_Glyph_Handle;

    face = glyph->face;
    if ( !face )
      return TT_Err_Invalid_Glyph_Handle;

    if (glyph_index < 0 || glyph_index >= face->numGlyphs )
      return TT_Err_Invalid_Glyph_Index;

    if ( instance && (load_flags & TTLOAD_SCALE_GLYPH) == 0)
    {
      instance    = 0;
      load_flags &= ~( TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH );
    }

    table = LookUp_TrueType_Table( face, TTAG_glyf );
    if ( table < 0 )
    {
      DebugTrace(( "ERROR: there is no glyph table in this font file!\n" ));
      return TT_Err_Table_Missing;
    }

    glyph_offset = face->dirTables[table].Offset;


    /* query new execution context */

    if ( instance && instance->debug )
      exec = instance->context;
    else
      exec = New_Context( face );

    if ( !exec )
      return TT_Err_Out_Of_Memory;

    if (instance)
    {
      Context_Load( exec, instance );
  
      if ( instance->GS.instruct_control & 2 )
        exec->GS = Default_GraphicsState;
      else
        exec->GS = instance->GS;
      /* load default graphics state */
    }

    /* save its critical pointers, as they'll be modified during load */

    base_pts        = exec->pts;
    base_n_contours = exec->numContours;
    base_contours   = exec->endContours;

    /* init variables */

    left_points   = face->maxPoints;
    left_contours = face->maxContours;

    num_points   = 0;
    num_contours = 0;

    load_top = 0;
    subglyph = exec->loadStack;

    Init_Glyph_Component( subglyph, NULL, exec );

    subglyph->index     = glyph_index;
    subglyph->is_hinted = load_flags & TTLOAD_HINT_GLYPH;

    /* when the cvt program has disabled hinting, the argument */
    /* is ignored.                                             */
    if ( instance && instance->GS.instruct_control & 1 )
      subglyph->is_hinted = FALSE;


    /* now access stream */

    if ( USE_Stream( face->stream, stream ) )
      goto Fin;

    /* Main loading loop */

    phase = Load_Glyph;
    index = 0;

    while ( phase != Load_Exit )
    {
      subglyph = exec->loadStack + load_top;

      switch (phase)
      {
        /************************************************************/
        /*                                                          */
        /* Load_Glyph state                                         */
        /*                                                          */
        /*   reading a glyph's generic header to determine          */
        /*   wether it's simple or composite                        */
        /*                                                          */
        /* exit states: Load_Header and Load_End                    */
  
      case Load_Glyph:
        /* check glyph index and table */

        index = subglyph->index;

        if ( index < 0 || index >= face->numGlyphs )
        {
          error = TT_Err_Invalid_Glyph_Index;
          goto Fail;
        }

        /* get horizontal metrics */

        Get_HMetrics( face, index, TRUE, &k, &l );

        if ( load_flags & TTLOAD_SCALE_GLYPH )
        {
          k = MulDiv_Round( k, 
                            exec->metrics.x_scale1, 
                            exec->metrics.x_scale2 );

          l = MulDiv_Round( l, 
                            exec->metrics.x_scale1, 
                            exec->metrics.x_scale2 );
        }

        subglyph->leftSideBearing = k;
        subglyph->advanceWidth    = l;

        phase = Load_Header;

        if (instance)
        {
          /* is the glyph in an outline cache ? */
          cacheCb = instance->owner->engine->glCallback;
          if (cacheCb)
          {
            /* we have a callback */
            error = cacheCb( instance->generic,
                             index, &cached_outline, &x, &y );
            if (!error)
            {
              /* no error, then append the outline to the current subglyph */
              error = Append_Outline( subglyph, 
                                      &left_points, 
                                      &left_contours,
                                      &cached_outline );
              if (!error)
              {
                subglyph->leftSideBearing = x;
                subglyph->advanceWidth    = y;
                phase = Load_End;
              }
            }
          }
        }
        break;

        /************************************************************/
        /*                                                          */
        /* Load_Header state                                        */
        /*                                                          */
        /*   reading a glyph's generic header to determine          */
        /*   wether it's simple or composite                        */
        /*                                                          */
        /* exit states: Load_Simple and Load_Composite              */

      case Load_Header : /* load glyph */

        if ( index + 1 < face->numLocations &&
             face->glyphLocations[index] ==
               face->glyphLocations[index + 1] )
        {
          /* as described by Frederic Loyer, these are spaces, and */
          /* not the unknown glyph.                                */

          num_contours = 0;
          num_points   = 0;

          subglyph->xMin = 0;
          subglyph->xMax = 0;
          subglyph->yMin = 0;
          subglyph->yMax = 0;

          phase = Load_End;

          break;
        }

        offset = glyph_offset + face->glyphLocations[index];

        /* read first glyph header */
        if ( FILE_Seek( offset ) ||
             ACCESS_Frame( 10L ) )
          goto Fail_File;

        num_contours   = GET_Short();
        subglyph->xMin = GET_Short();
        subglyph->yMin = GET_Short();
        subglyph->xMax = GET_Short();
        subglyph->yMax = GET_Short();

        FORGET_Frame();

        DebugTrace(( "Glyph %d\n", index ));
        DebugTrace(( " # of contours : %d\n", num_contours ));
        DebugTrace(( " xMin: %4d  xMax: %4d\n", 
                     subglyph->xMin, 
                     subglyph->xMax ));
        DebugTrace(( " yMin: %4d  yMax: %4d\n", 
                     subglyph->yMin, 
                     subglyph->yMax ));
        DebugTrace(( "-" ));

        if ( num_contours > left_contours )
        {
          DebugTrace(( "ERROR: Too many contours for glyph %d\n", index ));
          error = TT_Err_Too_Many_Contours;
          goto Fail;
        }

        /* is it a simple glyph ? */

        if ( num_contours > 0 )
          phase = Load_Simple;
        else
          phase = Load_Composite;

        break;


        /************************************************************/
        /*                                                          */
        /* Load_Simple state                                        */
        /*                                                          */
        /*   reading a simple glyph (num_contours must be set to    */
        /*   the glyph's number of contours.)                       */
        /*                                                          */
        /* exit states : Load_End                                   */
        /*                                                          */
 
      case Load_Simple:
        new_flags = load_flags;

        /* disable hinting when scaling */

        if ( !subglyph->is_hinted )
          new_flags &= ~TTLOAD_HINT_GLYPH;

        error = Load_Simple_Glyph( exec,
                                   stream,
                                   num_contours,
                                   left_contours,
                                   left_points,
                                   new_flags,
                                   subglyph );
        if ( error )
          goto Fail;

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

        num_points = exec->pts.n - 2;

        phase = Load_End;

        break;


        /************************************************************/
        /*                                                          */
        /* Load_Composite state                                     */
        /*                                                          */
        /*   reading a composite glyph header a pushing a new       */
        /*   load element on the stack.                             */
        /*                                                          */
        /* exit states: Load_Glyph                                  */
        /*                                                          */
 
      case Load_Composite:

        /* create a new element on the stack */
        load_top++;

        if ( load_top > face->maxComponents )
        {
          error = TT_Err_Invalid_Composite;
          goto Fail;
        }

        subglyph2 = exec->loadStack + load_top;

        Init_Glyph_Component( subglyph2, subglyph, NULL );

        /* now read composite header */

        if ( ACCESS_Frame( 4 ) )
          goto Fail_File;

        subglyph->element_flag = new_flags = GET_UShort();

        subglyph2->index = GET_UShort();

        FORGET_Frame();

        k = 2;

        if ( new_flags & ARGS_ARE_WORDS )
          k += 2;

        if ( new_flags & WE_HAVE_A_SCALE )
          k += 2;

        if ( new_flags & WE_HAVE_AN_XY_SCALE )
          k += 4;

        if ( new_flags & WE_HAVE_A_2X2 )
          k += 8;

        if ( ACCESS_Frame( k ) )
          goto Fail_File;

        if ( new_flags & ARGS_ARE_WORDS )
        {
          k = GET_Short();
          l = GET_Short();
        }
        else
        {
          l = GET_UShort();
          k = (signed char)(l >> 8);
          l = (signed char)(l & 0xFF);
        }

        subglyph->arg1 = k;
        subglyph->arg2 = l;

        if ( new_flags & ARGS_ARE_XY_VALUES )
        {
          subglyph->transform.ox = k;
          subglyph->transform.oy = l;
        }

        xx = 1 << 16;
        xy = 0;
        yx = 0;
        yy = 1 << 16;

        if ( new_flags & WE_HAVE_A_SCALE )
        {
          xx = (Fixed)GET_Short() << 2;
          yy = xx;
          subglyph2->is_scaled = TRUE;
        }
        else if ( new_flags & WE_HAVE_AN_XY_SCALE )
        {
          xx = (Fixed)GET_Short() << 2;
          yy = (Fixed)GET_Short() << 2;
          subglyph2->is_scaled = TRUE;
        }
        else if ( new_flags & WE_HAVE_A_2X2 )
        {
          xx = (Fixed)GET_Short() << 2;
          xy = (Fixed)GET_Short() << 2;
          yx = (Fixed)GET_Short() << 2;
          yy = (Fixed)GET_Short() << 2;
          subglyph2->is_scaled = TRUE;
        }

        FORGET_Frame();

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

        k = MulDiv_Round( xx, yy, 1 << 16 ) -
            MulDiv_Round( xy, yx, 1 << 16 );

 
        /* disable hinting in case of scaling/slanting */
        if ( k < -(1 << 16) || k > (1 << 16) )
          subglyph2->is_hinted = FALSE;
 
        subglyph->file_offset = FILE_Pos();

        phase = Load_Glyph;

        break;


        /************************************************************/
        /*                                                          */
        /* Load_End state                                           */
        /*                                                          */
        /*   after loading a glyph, apply transformation and offset */
        /*   where necessary, pops element and continue or          */
        /*   stop process.                                          */
        /*                                                          */
        /* exit states : Load_Composite and Load_Exit               */
        /*                                                          */
 
      case Load_End:
        if ( load_top > 0 )
        {
          subglyph2 = subglyph;

          load_top--;
          subglyph = exec->loadStack + load_top;

          /* check advance width and left side bearing */

          if ( subglyph->element_flag & USE_MY_METRICS  ||
               subglyph->advanceWidth == 0 )
          {
            subglyph->leftSideBearing = subglyph2->leftSideBearing;
            subglyph->advanceWidth    = subglyph2->advanceWidth;
          }

          /* apply scale */

          if ( subglyph2->is_scaled )
          {
            for ( k = 0; k < num_points; k++ )
            {
              x = subglyph2->cur_x[k];
              y = subglyph2->cur_y[k];

              nx = MulDiv_Round( x, subglyph->transform.xx, 1 << 16 ) +
                   MulDiv_Round( y, subglyph->transform.yx, 1 << 16 );

              ny = MulDiv_Round( x, subglyph->transform.xy, 1 << 16 ) +
                   MulDiv_Round( y, subglyph->transform.yy, 1 << 16 );

              subglyph2->cur_x[k] = nx;
              subglyph2->cur_y[k] = ny;

              x = subglyph2->org_x[k];
              y = subglyph2->org_y[k];

              nx = MulDiv_Round( x, subglyph->transform.xx, 1 << 16 ) +
                   MulDiv_Round( y, subglyph->transform.yx, 1 << 16 );

              ny = MulDiv_Round( x, subglyph->transform.xy, 1 << 16 ) +
                   MulDiv_Round( y, subglyph->transform.yy, 1 << 16 );

              subglyph2->org_x[k] = nx;
              subglyph2->org_y[k] = ny;
            }
          }

          /* adjust counts */

          for ( k = 0; k < num_contours; k++ )
            subglyph2->contours[k] += subglyph->n_points;

          subglyph->n_points   += num_points;
          subglyph->n_contours += num_contours;

          left_points   -= num_points;
          left_contours -= num_contours;

          /* apply offset */

          if ( !(subglyph->element_flag & ARGS_ARE_XY_VALUES) )
          {
            k = subglyph->arg1;
            l = subglyph->arg2;

            if ( k < 0 || k >= subglyph->n_points ||
                 l < 0 || l >= subglyph->n_points )
            {
              error = TT_Err_Invalid_Composite;
              goto Fail;
            }

            subglyph->transform.ox = subglyph->org_x[l] -
                                     subglyph->org_x[k];

            subglyph->transform.oy = subglyph->org_y[l] -
                                     subglyph->org_y[k];
          }

          x = subglyph->transform.ox;
          y = subglyph->transform.oy;

          if ( load_flags & TTLOAD_SCALE_GLYPH )
          {
            x = MulDiv_Round( x, 
                              exec->metrics.x_scale1, 
                              exec->metrics.x_scale2 );

            y = MulDiv_Round( y, 
                              exec->metrics.y_scale1, 
                              exec->metrics.y_scale2 );
          }

          if ( subglyph->element_flag & ARGS_ARE_XY_VALUES  &&
               subglyph->element_flag & ROUND_XY_TO_GRID )
          {
            x = ROUND_F26DOT6( x );
            y = ROUND_F26DOT6( y );
          }

          for ( k = 0; k < num_points; k++ )
          {
            subglyph2->org_x[k] += x;
            subglyph2->org_y[k] += y;
            subglyph2->cur_x[k] += x;
            subglyph2->cur_y[k] += y;
          }

          num_points   = subglyph->n_points;
          num_contours = subglyph->n_contours;

          /* check for last component */

          if ( FILE_Seek( subglyph->file_offset ) )
            goto Fail_File;

          if ( subglyph->element_flag & MORE_COMPONENTS )
            phase = Load_Composite;
          else
          {
            if ( subglyph->is_hinted    &&
                 subglyph->element_flag & WE_HAVE_INSTR )
            {
              if ( ACCESS_Frame( 2 ) )
                goto Fail;

              k = GET_UShort();     /* read size of instructions */

              FORGET_Frame();

              DebugTrace(( "Instructions size = %d\n", k ));

              if ( k > face->maxProfile.maxSizeOfInstructions )
              {
                DebugTrace(( "Too many instructions\n" ));
                error = TT_Err_Too_Many_Ins;
                goto Fail;
              }

              if ( FILE_Read( exec->glyphIns, k ) )
                goto Fail;

              exec->glyphSize = k;
                
              error = Load_Composite_Instructions( num_points,
                                                   num_contours,
                                                   exec,
                                                   subglyph );
              if ( error )
                goto Fail;
            }

            phase = Load_End;
          }
        }
        else
          phase = Load_Exit;

        break;


      case Load_Exit:
        break;
      } 
    }

    /* finally, copy the points arrays to the glyph object */

    exec->pts         = base_pts;
    exec->numContours = base_n_contours;
    exec->endContours = base_contours;

    if ( num_points > 0 )
    {
      xmin = xmax = exec->pts.cur_x[0];
      ymin = ymax = exec->pts.cur_y[0];

      for ( k = 1; k < num_points; k++ )
      {
        x = exec->pts.cur_x[k];
        if ( x < xmin ) xmin = x;
        if ( x > xmax ) xmax = x;

        y = exec->pts.cur_y[k];
        if ( y < ymin ) ymin = y;
        if ( y > ymax ) ymax = y;
      }

      subglyph->xMin = xmin;
      subglyph->xMax = xmax;
      subglyph->yMin = ymin;
      subglyph->yMax = ymax;
    }

    num_points += 2;

    for ( k = 0; k < num_points - 1; k++ )
    {
      glyph->x_coord[k] = exec->pts.cur_x[k];
      glyph->y_coord[k] = exec->pts.cur_y[k];
      glyph->touch  [k] = exec->pts.touch[k];
    }

    for ( k = 0; k < num_contours; k++ )
      glyph->endContours[k] = exec->endContours[k];

    /* Adjust advance width to the value contained in the hdmx table. */

    if ( !exec->owner->postscript.isFixedPitch && instance &&
         (load_flags & TTLOAD_DEFAULT) == TTLOAD_DEFAULT )
    {
      widths = Get_Advance_Widths( exec->owner,
                                   exec->instance->metrics.x_ppem );
      if ( widths )
        subglyph->advanceWidth = widths[glyph_index] << 6;
    }

    glyph->num_points   = num_points;
    glyph->num_contours = num_contours;

    glyph->leftSideBearing = subglyph->leftSideBearing;
    glyph->advanceWidth    = subglyph->advanceWidth;

    glyph->scan_type = exec->GS.scan_type;

    if (instance)
      glyph->high_precision = ( instance->metrics.y_ppem < 24 );
    else
      glyph->high_precision = 0;
    /* We use high precision whenever the render size is below 24 ppems */

    glyph->xMin = subglyph->xMin;
    glyph->yMin = subglyph->yMin;
    glyph->xMax = subglyph->xMax;
    glyph->yMax = subglyph->yMax;

    error = TT_Err_Ok;


  Fail_File:
  Fail:
    TT_Done_Stream( &stream );

  Fin:

    /* reset the execution context */

    exec->pts         = base_pts;
    exec->numContours = base_n_contours;
    exec->endContours = base_contours;

    if ( !instance || !instance->debug )
      Done_Context( exec );

    return error;
  }


/* END */
