T168_111\appl\Text\Freetype文件:第29~41个文件

TTLOAD.C   、、、、、、、、、、、、、、、、、、、、、、、、、、、、、


/*******************************************************************
 *
 *  ttload.c                                                    1.0
 *
 *    TrueType Tables Loader.
 *
 *  Copyright 1996-1999 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 "ttdebug.h"
#include "ttcalc.h"
#include "ttfile.h"

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

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

/* required by the tracing mode */
#undef  TT_COMPONENT
#define TT_COMPONENT      trace_load

/* In all functions, the stream is taken from the 'face' object */
#define DEFINE_LOCALS           DEFINE_LOAD_LOCALS( face->stream )
#define DEFINE_LOCALS_WO_FRAME  DEFINE_LOAD_LOCALS_WO_FRAME( face->stream )


/*******************************************************************
 *
 *  Function    :  LookUp_TrueType_Table
 *
 *  Description :  Looks for a TrueType table by name.
 *
 *  Input  :  face       face table to look for
 *            tag        searched tag
 *
 *  Output :  Index of table if found, -1 otherwise.
 *
 ******************************************************************/

  EXPORT_FUNC
  Long  TT_LookUp_Table( PFace  face,
                         ULong  tag  )
  {
    UShort  i;


    PTRACE4(( "TT_LookUp_Table( %08lx, %c%c%c%c )\n",
                  (Long)face,
                  (Char)(tag >> 24),
                  (Char)(tag >> 16),
                  (Char)(tag >> 8),
                  (Char)(tag) ));

    for ( i = 0; i < face->numTables; i++ )
      if ( face->dirTables[i].Tag == tag )
        return i;

    PTRACE4(( "    Could not find table!\n" ));
    return -1;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Collection
 *
 *  Description :  Loads the TTC table directory into face table.
 *
 *  Input  :  face    face record to look for
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  static TT_Error  Load_TrueType_Collection( PFace  face )
  {
    DEFINE_LOCALS;

    ULong  n;


    PTRACE3(( "Load_TrueType_Collection( %08lx )\n", (long)face ));

    if ( FILE_Seek   ( 0L ) ||
         ACCESS_Frame( 12L ) )
      return error;

    face->ttcHeader.Tag      = GET_Tag4();
    face->ttcHeader.version  = GET_Long();
    face->ttcHeader.DirCount = GET_Long();

    FORGET_Frame();

    if ( face->ttcHeader.Tag != TTAG_ttcf )
    {
      face->ttcHeader.Tag      = 0;
      face->ttcHeader.version  = 0;
      face->ttcHeader.DirCount = 0;

      face->ttcHeader.TableDirectory = NULL;

      PTRACE3(("skipped.\n"));

      return TT_Err_File_Is_Not_Collection;
    }

    if ( ALLOC_ARRAY( face->ttcHeader.TableDirectory,
                      face->ttcHeader.DirCount,
                      ULong )                         ||
         ACCESS_Frame( face->ttcHeader.DirCount * 4L ) )
      return error;

    for ( n = 0; n < face->ttcHeader.DirCount; n++ )
      face->ttcHeader.TableDirectory[n] = GET_ULong();

    FORGET_Frame();

    PTRACE3(( "collections directory loaded.\n" ));
    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Directory
 *
 *  Description :  Loads the table directory into face table.
 *
 *  Input  :  face       face record to look for
 *
 *            faceIndex  the index of the TrueType font, when
 *                       we're opening a collection.
 *
 *  Output :  SUCCESS on success.  FAILURE on error.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Directory( PFace  face, ULong  faceIndex )
  {
    DEFINE_LOCALS;

    UShort     n, limit;
    TTableDir  tableDir;

    PTableDirEntry  entry;


    PTRACE2(("Load_TT_Directory( %08lx, %ld )\n", (long)face, faceIndex));

    error = Load_TrueType_Collection( face );

    if ( error )
    {
      if ( error != TT_Err_File_Is_Not_Collection )
        return error;

      /* the file isn't a collection, exit if we're asking */
      /* for a collected font                              */
      if ( faceIndex != 0 )
        return error;

      /* Now skip to the beginning of the file */
      if ( FILE_Seek( 0L ) )
        return error;
    }
    else
    {
      /* The file is a collection. Check the font index */
      if ( faceIndex >= face->ttcHeader.DirCount )
        return TT_Err_Invalid_Argument;

      /* select a TrueType font in the ttc file   */
      if ( FILE_Seek( face->ttcHeader.TableDirectory[faceIndex] ) )
        return error;
    }

    if ( ACCESS_Frame( 12L ) )
      return error;

    tableDir.version   = GET_Long();
    tableDir.numTables = GET_UShort();

    tableDir.searchRange   = GET_UShort();
    tableDir.entrySelector = GET_UShort();
    tableDir.rangeShift    = GET_UShort();

    FORGET_Frame();

    PTRACE2(( "-- Tables count   : %12u\n", tableDir.numTables ));
    PTRACE2(( "-- Format version : %08lx\n", tableDir.version ));

    /* Check that we have a 'sfnt' format there */

    if ( tableDir.version != 0x00010000  &&      /* MS fonts */
         tableDir.version != 0x74727565  &&      /* Mac fonts */
         tableDir.version != 0x00000000  )       /* some Korean fonts */
    {
      PERROR(( "!! invalid file format" ));
      return TT_Err_Invalid_File_Format;
    }

    face->numTables = tableDir.numTables;

    if ( ALLOC_ARRAY( face->dirTables,
                      face->numTables,
                      TTableDirEntry ) )
      return error;

    if ( ACCESS_Frame( face->numTables * 16L ) )
      return error;

    limit = face->numTables;
    entry = face->dirTables;

    for ( n = 0; n < limit; n++ )
    {                      /* loop through the tables and get all entries */
      entry->Tag      = GET_Tag4();
      entry->CheckSum = GET_ULong();
      entry->Offset   = GET_Long();
      entry->Length   = GET_Long();

      PTRACE2(( "  %c%c%c%c  -  %08lx  -  %08lx\n",
                (Char)(entry->Tag >> 24),
                (Char)(entry->Tag >> 16),
                (Char)(entry->Tag >> 8 ),
                (Char)(entry->Tag),
                entry->Offset,
                entry->Length ));
      entry++;
    }

    FORGET_Frame();

    PTRACE2(( "Directory loaded\n\n" ));
    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_MaxProfile
 *
 *  Description :  Loads the maxp table into face table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_MaxProfile( PFace  face )
  {
    DEFINE_LOCALS;

    Long         i;
    PMaxProfile  maxProfile = &face->maxProfile;


    PTRACE2(( "Load_TT_MaxProfile( %08lx )\n", (long)face ));

    if ( ( i = TT_LookUp_Table( face, TTAG_maxp ) ) < 0 )
      return TT_Err_Max_Profile_Missing;

    if ( FILE_Seek( face->dirTables[i].Offset ) )   /* seek to maxprofile */
      return error;

    if ( ACCESS_Frame( 32L ) )  /* read into frame */
      return error;

    /* read frame data into face table */
    maxProfile->version               = GET_ULong();

    maxProfile->numGlyphs             = GET_UShort();

    maxProfile->maxPoints             = GET_UShort();
    maxProfile->maxContours           = GET_UShort();
    maxProfile->maxCompositePoints    = GET_UShort();
    maxProfile->maxCompositeContours  = GET_UShort();

    maxProfile->maxZones              = GET_UShort();
    maxProfile->maxTwilightPoints     = GET_UShort();

    maxProfile->maxStorage            = GET_UShort();
    maxProfile->maxFunctionDefs       = GET_UShort();
    maxProfile->maxInstructionDefs    = GET_UShort();
    maxProfile->maxStackElements      = GET_UShort();
    maxProfile->maxSizeOfInstructions = GET_UShort();
    maxProfile->maxComponentElements  = GET_UShort();
    maxProfile->maxComponentDepth     = GET_UShort();

    FORGET_Frame();

    /* XXX : an adjustement that is necessary to load certain */
    /*       broken fonts like "Keystrokes MT" :-(            */
    /*                                                        */
    /*   We allocate 64 function entries by default when      */
    /*   the maxFunctionDefs field is null.                   */

    if (maxProfile->maxFunctionDefs == 0)
      maxProfile->maxFunctionDefs = 64;

    face->numGlyphs     = maxProfile->numGlyphs;

    face->maxPoints     = MAX( maxProfile->maxCompositePoints,
                               maxProfile->maxPoints );
    face->maxContours   = MAX( maxProfile->maxCompositeContours,
                               maxProfile->maxContours );
    face->maxComponents = maxProfile->maxComponentElements +
                          maxProfile->maxComponentDepth;

    /* XXX: Some fonts have maxComponents set to 0; we will */
    /*      then use 16 of them by default.                 */
    if ( face->maxComponents == 0 )
      face->maxComponents = 16;
     
    /* We also increase maxPoints and maxContours in order to support */
    /* some broken fonts.                                             */
    face->maxPoints   += 8;
    face->maxContours += 4;

    PTRACE2(( "GASP loaded.\n" ));
    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Gasp
 *
 *  Description :  Loads the TrueType Gasp table into the face
 *                 table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Gasp( PFace  face )
  {
    DEFINE_LOCALS;

    Long        i;
    UShort      j;
    TGasp*      gas;
    GaspRange*  gaspranges;


    PTRACE2(( "Load_TT_Gasp( %08lx )\n", (long)face ));

    if ( ( i = TT_LookUp_Table( face, TTAG_gasp ) ) < 0 )
      return TT_Err_Ok; /* gasp table is not required */

    if ( FILE_Seek( face->dirTables[i].Offset ) ||
         ACCESS_Frame( 4L ) )
      return error;

    gas = &face->gasp;

    gas->version   = GET_UShort();
    gas->numRanges = GET_UShort();

    FORGET_Frame();

    PTRACE3(( "number of ranges = %d\n", gas->numRanges ));

    if ( ALLOC_ARRAY( gaspranges, gas->numRanges, GaspRange ) ||
         ACCESS_Frame( gas->numRanges * 4L ) )
      goto Fail;

    face->gasp.gaspRanges = gaspranges;

    for ( j = 0; j < gas->numRanges; j++ )
    {
      gaspranges[j].maxPPEM  = GET_UShort();
      gaspranges[j].gaspFlag = GET_UShort();

      PTRACE3(( " [max:%d flag:%d]",
                gaspranges[j].maxPPEM,
                gaspranges[j].gaspFlag ));
    }
    PTRACE3(("\n"));

    FORGET_Frame();

    PTRACE2(( "GASP loaded\n" ));
    return TT_Err_Ok;

  Fail:
    FREE( gaspranges );
    gas->numRanges = 0;
    return error;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Header
 *
 *  Description :  Loads the TrueType header table into the face
 *                 table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Header( PFace  face )
  {
    DEFINE_LOCALS;

    Long        i;
    TT_Header*  header;


    PTRACE2(( "Load_TT_Header( %08lx )\n", (long)face ));

    if ( ( i = TT_LookUp_Table( face, TTAG_head ) ) < 0 )
    {
      PTRACE0(( "Font Header is missing !!\n" ));
      return TT_Err_Header_Table_Missing;
    }

    if ( FILE_Seek( face->dirTables[i].Offset ) ||
         ACCESS_Frame( 54L ) )
      return error;

    header = &face->fontHeader;

    header->Table_Version = GET_ULong();
    header->Font_Revision = GET_ULong();

    header->CheckSum_Adjust = GET_Long();
    header->Magic_Number    = GET_Long();

    header->Flags        = GET_UShort();
    header->Units_Per_EM = GET_UShort();

    header->Created [0] = GET_Long();
    header->Created [1] = GET_Long();
    header->Modified[0] = GET_Long();
    header->Modified[1] = GET_Long();

    header->xMin = GET_Short();
    header->yMin = GET_Short();
    header->xMax = GET_Short();
    header->yMax = GET_Short();

    header->Mac_Style       = GET_UShort();
    header->Lowest_Rec_PPEM = GET_UShort();

    header->Font_Direction      = GET_Short();
    header->Index_To_Loc_Format = GET_Short();
    header->Glyph_Data_Format   = GET_Short();

    FORGET_Frame();

    PTRACE2(( "    Units per EM : %8u\n", header->Units_Per_EM ));
    PTRACE2(( "    IndexToLoc   : %8d\n", header->Index_To_Loc_Format ));
    PTRACE2(( "Font Header Loaded.\n" ));
    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Metrics
 *
 *  Description :  Loads the horizontal or vertical metrics table
 *                 into face object.
 *
 *  Input  :  face
 *            vertical   set to true when loading the vmtx table,
 *                       or false for hmtx
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  static
  TT_Error  Load_TrueType_Metrics( PFace  face,
                                   Bool   vertical )
  {
    DEFINE_LOCALS;

    Long              n, num_shorts, num_shorts_checked, num_longs;

    PLongMetrics*     longs;
    PShortMetrics*    shorts;

    PLongMetrics      long_metric;


    PTRACE2(( "Load_TT_%s_Metrics( %08lx )\n",
              vertical ? "Vertical" : "Horizontal",
              (long)face ));

    if ( vertical )
    {
      /* The table is optional, quit silently if it wasn't found       */
      /* XXX : Some fonts have a valid vertical header with a non-null */
      /*       "number_of_VMetrics" fields, but no corresponding       */
      /*       'vmtx' table to get the metrics from (e.g. mingliu)     */
      /*                                                               */
      /*       For safety, we set the field to 0 !                     */
      /*                                                               */
      n = TT_LookUp_Table( face, TTAG_vmtx );
      if ( n < 0 )
      {
        /* Set the number_Of_VMetrics to 0! */
        PTRACE2(( "  no vertical header in file.\n" ));
        face->verticalHeader.number_Of_VMetrics = 0;
        return TT_Err_Ok;
      }

      num_longs = face->verticalHeader.number_Of_VMetrics;
      longs     = (PLongMetrics*)&face->verticalHeader.long_metrics;
      shorts    = (PShortMetrics*)&face->verticalHeader.short_metrics;
    }
    else
    {
      if ( ( n = TT_LookUp_Table( face, TTAG_hmtx ) ) < 0 )
      {
        PERROR(( "!! No Horizontal metrics in file !!\n" ));
        return TT_Err_Hmtx_Table_Missing;
      }

      num_longs = face->horizontalHeader.number_Of_HMetrics;
      longs     = (PLongMetrics*)&face->horizontalHeader.long_metrics;
      shorts    = (PShortMetrics*)&face->horizontalHeader.short_metrics;
    }

    /* never trust derived values! */

    num_shorts         = face->maxProfile.numGlyphs - num_longs;
    num_shorts_checked = ( face->dirTables[n].Length - num_longs * 4 ) / 2;

    if ( num_shorts < 0 )            /* sanity check */
    {
      PERROR(( "!! more metrics than glyphs!\n" ));
      if ( vertical )
        return TT_Err_Invalid_Vert_Metrics;
      else
        return TT_Err_Invalid_Horiz_Metrics;
    }

    if ( ALLOC_ARRAY( *longs,  num_longs,  TLongMetrics  ) ||
         ALLOC_ARRAY( *shorts, num_shorts, TShortMetrics ) )
      return error;

    if ( FILE_Seek( face->dirTables[n].Offset )   ||
         ACCESS_Frame( face->dirTables[n].Length ) )
      return error;

    long_metric = *longs;
    for ( n = 0; n < num_longs; n++ )
    {
      long_metric->advance = GET_UShort();
      long_metric->bearing = GET_Short();
      long_metric++;
    }

    /* do we have an inconsistent number of metric values? */

    if ( num_shorts > num_shorts_checked )
    {
      for ( n = 0; n < num_shorts_checked; n++ )
        (*shorts)[n] = GET_Short();

      /* we fill up the missing left side bearings with the    */
      /* last valid value. Since this will occur for buggy CJK */
      /* fonts usually, nothing serious will happen.           */

      for ( n = num_shorts_checked; n < num_shorts; n++ )
        (*shorts)[n] = (*shorts)[num_shorts_checked - 1];
    }
    else
    {
      for ( n = 0; n < num_shorts; n++ )
        (*shorts)[n] = GET_Short();
    }

    FORGET_Frame();

    PTRACE2(( "loaded\n" ));
    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    : Load_TrueType_Metrics_Header
 *
 *  Description : Loads either the "hhea" or "vhea" table in memory
 *
 *  Input  :  face       face table to look for
 *            vertical   a boolean.  When set, queries the optional
 *                       "vhea" table.  Otherwise, load the mandatory
 *                       "hhea" horizontal header.
 *
 *  Output :  Error code.
 *
 *  Note : This function now loads the corresponding metrics table
 *         (either hmtx or vmtx) and attaches it to the header.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Metrics_Header( PFace  face,
                                          Bool   vertical )
  {
    DEFINE_LOCALS;

    Long  i;

    TT_Horizontal_Header*  header;


    PTRACE2(( vertical ? "Vertical header" : "Horizontal header " ));

    if ( vertical )
    {
      face->verticalInfo = 0;

      /* The vertical header table is optional, so return quietly if */
      /* we don't find it..                                          */
      if ( ( i = TT_LookUp_Table( face, TTAG_vhea ) ) < 0 )
        return TT_Err_Ok;

      face->verticalInfo = 1;
      header = (TT_Horizontal_Header*)&face->verticalHeader;
    }
    else
    {
      /* The orizontal header is mandatory, return an error if we */
      /* don't find it.                                           */
      if ( ( i = TT_LookUp_Table( face, TTAG_hhea ) ) < 0 )
        return TT_Err_Horiz_Header_Missing;

      header = &face->horizontalHeader;
    }

    if ( FILE_Seek( face->dirTables[i].Offset ) ||
         ACCESS_Frame( 36L ) )
      return error;

    header->Version   = GET_ULong();
    header->Ascender  = GET_Short();
    header->Descender = GET_Short();
    header->Line_Gap  = GET_Short();

    header->advance_Width_Max = GET_UShort();

    header->min_Left_Side_Bearing  = GET_Short();
    header->min_Right_Side_Bearing = GET_Short();
    header->xMax_Extent            = GET_Short();
    header->caret_Slope_Rise       = GET_Short();
    header->caret_Slope_Run        = GET_Short();

    header->Reserved0 = GET_Short();    /* this is caret_Offset for
                                           vertical headers */
    header->Reserved1 = GET_Short();
    header->Reserved2 = GET_Short();
    header->Reserved3 = GET_Short();
    header->Reserved4 = GET_Short();

    header->metric_Data_Format = GET_Short();
    header->number_Of_HMetrics = GET_UShort();

    FORGET_Frame();

    header->long_metrics  = NULL;
    header->short_metrics = NULL;

    PTRACE2(( "loaded\n" ));

    /* Now try to load the corresponding metrics */

    return Load_TrueType_Metrics( face, vertical );
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Locations
 *
 *  Description :  Loads the location table into face table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  Error code.
 *
 *  NOTE:
 *    The Font Header *must* be loaded in the leading segment
 *    calling this function.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Locations( PFace  face )
  {
    DEFINE_LOCALS;

    Long   n, limit;
    Short  LongOffsets;


    PTRACE2(( "Locations " ));

    LongOffsets = face->fontHeader.Index_To_Loc_Format;

    if ( ( n = TT_LookUp_Table( face, TTAG_loca ) ) < 0 )
      return TT_Err_Locations_Missing;

    if ( FILE_Seek( face->dirTables[n].Offset ) )
      return error;

    if ( LongOffsets != 0 )
    {
      face->numLocations = face->dirTables[n].Length >> 2;

      PTRACE2(( "(32 bit offsets): %12lu ",
                   face->numLocations ));

      if ( ALLOC_ARRAY( face->glyphLocations,
                        face->numLocations,
                        Long ) )
        return error;

      if ( ACCESS_Frame( face->numLocations * 4L ) )
        return error;

      limit = face->numLocations;

      for ( n = 0; n < limit; n++ )
        face->glyphLocations[n] = GET_Long();

      FORGET_Frame();
    }
    else
    {
      face->numLocations = face->dirTables[n].Length >> 1;

      PTRACE2(( "(16 bit offsets): %12lu ",
                   face->numLocations ));

      if ( ALLOC_ARRAY( face->glyphLocations,
                        face->numLocations,
                        Long ) )
        return error;

      if ( ACCESS_Frame( face->numLocations * 2L ) )
        return error;

      limit = face->numLocations;

      for ( n = 0; n < limit; n++ )
        face->glyphLocations[n] =
          (Long)((ULong)GET_UShort() * 2);

      FORGET_Frame();
    }

    PTRACE2(( "loaded\n" ));

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Names
 *
 *  Description :  Loads the name table into face table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Names( PFace  face )
  {
    DEFINE_LOCALS;

    UShort  i, bytes;
    Long    n;
    PByte   storage;

    TName_Table*  names;
    TNameRec*     namerec;


    PTRACE2(( "Names " ));

    if ( ( n = TT_LookUp_Table( face, TTAG_name ) ) < 0 )
    {
      /* The name table is required so indicate failure. */
      PTRACE2(( "is missing!\n" ));

      return TT_Err_Name_Table_Missing;
    }

    /* Seek to the beginning of the table and check the frame access. */
    /* The names table has a 6 byte header.                           */
    if ( FILE_Seek( face->dirTables[n].Offset ) ||
         ACCESS_Frame( 6L ) )
      return error;

    names = &face->nameTable;

    /* Load the initial names data. */
    names->format         = GET_UShort();
    names->numNameRecords = GET_UShort();
    names->storageOffset  = GET_UShort();

    FORGET_Frame();

    /* Allocate the array of name records. */
    if ( ALLOC_ARRAY( names->names,
                      names->numNameRecords,
                      TNameRec )                    ||
         ACCESS_Frame( names->numNameRecords * 12L ) )
    {
      names->numNameRecords = 0;
      goto Fail;
    }

    /* Load the name records and determine how much storage is needed */
    /* to hold the strings themselves.                                */

    for ( i = bytes = 0; i < names->numNameRecords; i++ )
    {
      namerec = names->names + i;
      namerec->platformID   = GET_UShort();
      namerec->encodingID   = GET_UShort();
      namerec->languageID   = GET_UShort();
      namerec->nameID       = GET_UShort();
      namerec->stringLength = GET_UShort();
      namerec->stringOffset = GET_UShort();

#if 0
      /* check the ids */
      if ( namerec->platformID <= 3 )
      {
#endif
        /* this test takes care of 'holes' in the names tables, as */
        /* reported by Erwin                                       */
        if ( (namerec->stringOffset + namerec->stringLength) > bytes )
          bytes = namerec->stringOffset + namerec->stringLength;
#if 0
      }
#endif
    }

    FORGET_Frame();

    /* Allocate storage for the strings if they exist. */

    names->storage = NULL;

    if ( bytes > 0 )
    {
      if ( ALLOC( storage, bytes ) ||
           FILE_Read_At( face->dirTables[n].Offset + names->storageOffset,
                         (void*)storage,
                         bytes ) )
        goto Fail_Storage;

      names->storage = storage;

      /* Go through and assign the string pointers to the name records. */

      for ( i = 0; i < names->numNameRecords; i++ )
      {
        namerec = names->names + i;
        namerec->string = storage + names->names[i].stringOffset;

/* It is possible (but rather unlikely) that a new platform ID will be */
/* added by Apple, so we can't rule out IDs > 3.                       */

#if 0
        if ( namerec->platformID <= 3 )
          namerec->string = storage + names->names[i].stringOffset;
        else
        {
          namerec->string       = NULL;
          namerec->stringLength = 0;
        }
#endif
      }
    }

#ifdef DEBUG_LEVEL_TRACE

    for ( i = 0; i < names->numNameRecords; i++ )
    {
      int  j;


      PTRACE2(( "%d %d %x %d ",
                   names->names[i].platformID,
                   names->names[i].encodingID,
                   names->names[i].languageID,
                   names->names[i].nameID ));

      /* I know that M$ encoded strings are Unicode,            */
      /* but this works reasonable well for debugging purposes. */
      for ( j = 0; j < names->names[i].stringLength; j++ )
      {
        if (names->names[i].string)
        {
          Char  c = *(names->names[i].string + j);


          if ( (Byte)c < 128 )
            PTRACE2(( "%c", c ));
        }
      }

      PTRACE2(( "\n" ));
    }

#endif /* DEBUG_LEVEL_TRACE */

    PTRACE2(( "loaded\n" ));
    return TT_Err_Ok;

  Fail_Storage:
    FREE( storage );

  Fail:
    Free_TrueType_Names( face );
    return error;
  }


/*******************************************************************
 *
 *  Function    :  Free_TrueType_Names
 *
 *  Description :  Frees a name table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  TT_Err_Ok.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Free_TrueType_Names( PFace  face )
  {
    TName_Table*  names = &face->nameTable;


    /* free strings table */
    FREE( names->names );

    /* free strings storage */
    FREE( names->storage );

    names->numNameRecords = 0;
    names->format         = 0;
    names->storageOffset  = 0;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_CVT
 *
 *  Description :  Loads cvt table into resident table.
 *
 *  Input  :  face     face table to look for
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_CVT( PFace  face )
  {
    DEFINE_LOCALS;

    Long  n, limit;


    PTRACE2(( "CVT " ));

    if ( ( n = TT_LookUp_Table( face, TTAG_cvt ) ) < 0 )
    {
      PTRACE2(( "is missing!\n" ));

      face->cvtSize = 0;
      face->cvt     = NULL;
      return TT_Err_Ok;
    }

    face->cvtSize = face->dirTables[n].Length / 2;

    if ( ALLOC_ARRAY( face->cvt,
                      face->cvtSize,
                      Short ) )
      return error;

    if ( FILE_Seek( face->dirTables[n].Offset ) ||
         ACCESS_Frame( face->cvtSize * 2L ) )
      return error;

    limit = face->cvtSize;

    for ( n = 0; n < limit; n++ )
      face->cvt[n] = GET_Short();

    FORGET_Frame();

    PTRACE2(( "loaded\n" ));

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_CMap
 *
 *  Description :  Loads the cmap directory in memory.
 *                 The cmaps themselves are loaded in ttcmap.c .
 *
 *  Input  :  face
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_CMap( PFace  face )
  {
    DEFINE_LOCALS;

    Long  off, table_start;
    Long  n, limit;

    TCMapDir       cmap_dir;
    TCMapDirEntry  entry_;
    PCMapTable     cmap; 

    PTRACE2(( "CMaps " ));

    if ( ( n = TT_LookUp_Table( face, TTAG_cmap ) ) < 0 )
      return TT_Err_CMap_Table_Missing;

    table_start = face->dirTables[n].Offset;

//ShowFont(0, 32,"table_start  ");    
//MakeInt(buf,table_start);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;


    if ( ( FILE_Seek( table_start ) ) ||
         ( ACCESS_Frame( 4L ) ) )           /* 4 bytes cmap header */
      return error;

    cmap_dir.tableVersionNumber = GET_UShort();
    cmap_dir.numCMaps           = GET_UShort();

    FORGET_Frame();

    off = FILE_Pos();  /* save offset to cmapdir[] which follows */

//ShowFont(0, 32,"off    ");    
//MakeInt(buf,off);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;

    /* save space in face table for cmap tables */
    if ( ALLOC_ARRAY( face->cMaps,
                      cmap_dir.numCMaps,
                      TCMapTable ) )
      return error;

    face->numCMaps = cmap_dir.numCMaps;

    limit = face->numCMaps;
    cmap  = face->cMaps;

    for ( n = 0; n < limit; n++ )
    {
      if ( FILE_Seek( off )  ||
           ACCESS_Frame( 8L ) )
        return error;

//ShowFont(0, 32,"n =             ");    
//MakeInt(buf,n);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;

//ShowFont(0, 32,"off =           ");    
//MakeInt(buf,off);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;


      /* extra code using entry_ for platxxx could be cleaned up later */
      cmap->loaded             = FALSE;
      cmap->platformID         = entry_.platformID         = GET_UShort();
      cmap->platformEncodingID = entry_.platformEncodingID = GET_UShort();

      entry_.offset = GET_Long();

//ShowFont(0, 32,"entry_.offset  ");    
//MakeInt(buf,entry_.offset);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;


      FORGET_Frame();

      off = FILE_Pos();

//ShowFont(0, 32,"entry_.offset  ");    
//MakeInt(buf,entry_.offset);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;


      if ( FILE_Seek( table_start + entry_.offset ) ||
           ACCESS_Frame( 6L ) )
        return error;

      cmap->format  = GET_UShort();
      cmap->length  = GET_UShort();
      cmap->version = GET_UShort();

      FORGET_Frame();

      cmap->offset = FILE_Pos();

//ShowFont(0, 32,"platformID      ");    
//MakeInt(buf,cmap->platformID);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;

//ShowFont(0, 32,"EncodingID      ");    
//MakeInt(buf,cmap->platformEncodingID);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;

//ShowFont(0, 32,"length          ");    
//MakeInt(buf,cmap->length);
//ShowFont(0, 48,buf);      
//j=0;while(j<95000000L)j++;

//ShowFont(0, 32,"offset          ");    
//MakeInt(buf,cmap->offset);
//ShowFont(0, 48,buf);    
//j=0;while(j<95000000L)j++;

      cmap++;
    }

    PTRACE2(( "loaded\n" ));

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Programs
 *
 *  Description :  Loads the font (fpgm) and cvt programs into the
 *                 face table.
 *
 *  Input  :  face
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Programs( PFace  face )
  {
    DEFINE_LOCALS_WO_FRAME;

    Long  n;


    PTRACE2(( "Font program " ));

    /* The font program is optional */
    if ( ( n = TT_LookUp_Table( face, TTAG_fpgm ) ) < 0 )
    {
      face->fontProgram = NULL;
      face->fontPgmSize = 0;

      PTRACE2(( "is missing!\n" ));
    }
    else
    {
      face->fontPgmSize = face->dirTables[n].Length;

      if ( ALLOC( face->fontProgram,
                  face->fontPgmSize )              ||
           FILE_Read_At( face->dirTables[n].Offset,
                         (void*)face->fontProgram,
                         face->fontPgmSize )       )
        return error;

      PTRACE2(( "loaded, %12d bytes\n", face->fontPgmSize ));
    }

    PTRACE2(( "Prep program " ));

    if ( ( n = TT_LookUp_Table( face, TTAG_prep ) ) < 0 )
    {
      face->cvtProgram = NULL;
      face->cvtPgmSize = 0;

      PTRACE2(( "is missing!\n" ));
    }
    else
    {
      face->cvtPgmSize = face->dirTables[n].Length;

      if ( ALLOC( face->cvtProgram,
                  face->cvtPgmSize )               ||
           FILE_Read_At( face->dirTables[n].Offset,
                         (void*)face->cvtProgram,
                         face->cvtPgmSize )        )
        return error;

      PTRACE2(( "loaded, %12d bytes\n", face->cvtPgmSize ));
    }

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_OS2
 *
 *  Description :  Loads the OS2 Table.
 *
 *  Input  :  face
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_OS2( PFace  face )
  {
    DEFINE_LOCALS;

    Long     i;
    TT_OS2*  os2;


    PTRACE2(( "OS/2 Table " ));

    /* We now support old Mac fonts where the OS/2 table doesn't  */
    /* exist.  Simply put, we set the `version' field to 0xFFFF   */
    /* and test this value each time we need to access the table. */
    if ( ( i = TT_LookUp_Table( face, TTAG_OS2 ) ) < 0 )
    {
      PTRACE2(( "is missing\n!" ));
      face->os2.version = 0xFFFF;
      error = TT_Err_Ok;
      return TT_Err_Ok;
    }

    if ( FILE_Seek( face->dirTables[i].Offset ) ||
         ACCESS_Frame( 78L ) )
      return error;

    os2 = &face->os2;

    os2->version             = GET_UShort();
    os2->xAvgCharWidth       = GET_Short();
    os2->usWeightClass       = GET_UShort();
    os2->usWidthClass        = GET_UShort();
    os2->fsType              = GET_Short();
    os2->ySubscriptXSize     = GET_Short();
    os2->ySubscriptYSize     = GET_Short();
    os2->ySubscriptXOffset   = GET_Short();
    os2->ySubscriptYOffset   = GET_Short();
    os2->ySuperscriptXSize   = GET_Short();
    os2->ySuperscriptYSize   = GET_Short();
    os2->ySuperscriptXOffset = GET_Short();
    os2->ySuperscriptYOffset = GET_Short();
    os2->yStrikeoutSize      = GET_Short();
    os2->yStrikeoutPosition  = GET_Short();
    os2->sFamilyClass        = GET_Short();

    for ( i = 0; i < 10; i++ )
      os2->panose[i] = GET_Byte();

    os2->ulUnicodeRange1     = GET_ULong();
    os2->ulUnicodeRange2     = GET_ULong();
    os2->ulUnicodeRange3     = GET_ULong();
    os2->ulUnicodeRange4     = GET_ULong();

    for ( i = 0; i < 4; i++ )
      os2->achVendID[i] = GET_Byte();

    os2->fsSelection         = GET_UShort();
    os2->usFirstCharIndex    = GET_UShort();
    os2->usLastCharIndex     = GET_UShort();
    os2->sTypoAscender       = GET_Short();
    os2->sTypoDescender      = GET_Short();
    os2->sTypoLineGap        = GET_Short();
    os2->usWinAscent         = GET_UShort();
    os2->usWinDescent        = GET_UShort();

    FORGET_Frame();

    if ( os2->version >= 0x0001 )
    {
      /* only version 1 tables */

      if ( ACCESS_Frame( 8L ) )  /* read into frame */
        return error;

      os2->ulCodePageRange1 = GET_ULong();
      os2->ulCodePageRange2 = GET_ULong();

      FORGET_Frame();
    }
    else
    {
      os2->ulCodePageRange1 = 0;
      os2->ulCodePageRange2 = 0;
    }

    PTRACE2(( "loaded\n" ));

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_PostScript
 *
 *  Description :  Loads the post table into face table.
 *
 *  Input  :  face         face table to look for
 *
 *  Output :  SUCCESS on success.  FAILURE on error.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_PostScript( PFace  face )
  {
    DEFINE_LOCALS;

    Long  i;

    TT_Postscript*  post = &face->postscript;


    PTRACE2(( "PostScript " ));

    if ( ( i = TT_LookUp_Table( face, TTAG_post ) ) < 0 )
      return TT_Err_Post_Table_Missing;

    if ( FILE_Seek( face->dirTables[i].Offset ) ||
         ACCESS_Frame( 32L ) )
      return error;

    /* read frame data into face table */

    post->FormatType         = GET_ULong();
    post->italicAngle        = GET_ULong();
    post->underlinePosition  = GET_Short();
    post->underlineThickness = GET_Short();
    post->isFixedPitch       = GET_ULong();
    post->minMemType42       = GET_ULong();
    post->maxMemType42       = GET_ULong();
    post->minMemType1        = GET_ULong();
    post->maxMemType1        = GET_ULong();

    FORGET_Frame();

    /* we don't load the glyph names, we do that in a */
    /* library extension (ftxpost).                   */

    PTRACE2(( "loaded\n" ));

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Hdmx
 *
 *  Description :  Loads the horizontal device metrics table.
 *
 *  Input  :  face         face object to look for
 *
 *  Output :  SUCCESS on success.  FAILURE on error.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Hdmx( PFace  face )
  {
    DEFINE_LOCALS;

    TT_Hdmx_Record*  rec;
    TT_Hdmx          hdmx;
    Long             table;
    UShort           n, num_glyphs;
    Long             record_size;


    hdmx.version     = 0;
    hdmx.num_records = 0;
    hdmx.records     = 0;

    face->hdmx = hdmx;

    if ( ( table = TT_LookUp_Table( face, TTAG_hdmx ) ) < 0 )
      return TT_Err_Ok;

    if ( FILE_Seek( face->dirTables[table].Offset )  ||
         ACCESS_Frame( 8L ) )
      return error;

    hdmx.version     = GET_UShort();
    hdmx.num_records = GET_Short();
    record_size      = GET_Long();

    FORGET_Frame();

    /* Only recognize format 0 */

    if ( hdmx.version != 0 )
      return TT_Err_Ok;

    if ( ALLOC( hdmx.records, sizeof ( TT_Hdmx_Record ) * hdmx.num_records ) )
      return error;

    num_glyphs   = face->numGlyphs;
    record_size -= num_glyphs+2;
    rec          = hdmx.records;

    for ( n = 0; n < hdmx.num_records; n++ )
    {
      /* read record */

      if ( ACCESS_Frame( 2L ) )
        goto Fail;

      rec->ppem      = GET_Byte();
      rec->max_width = GET_Byte();

      FORGET_Frame();

      if ( ALLOC( rec->widths, num_glyphs )  ||
           FILE_Read( rec->widths, num_glyphs ) )
        goto Fail;

      /* skip padding bytes */
      if ( record_size > 0 )
        if ( FILE_Skip( record_size ) )
          goto Fail;

      rec++;
    }

    face->hdmx = hdmx;

    return TT_Err_Ok;

  Fail:
    for ( n = 0; n < hdmx.num_records; n++ )
      FREE( hdmx.records[n].widths );

    FREE( hdmx.records );
    return error;
  }


/*******************************************************************
 *
 *  Function    :  Free_TrueType_Hdmx
 *
 *  Description :  Frees the horizontal device metrics table.
 *
 *  Input  :  face         face object to look for
 *
 *  Output :  TT_Err_Ok.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Free_TrueType_Hdmx( PFace  face )
  {
    UShort  n;


    if ( !face )
      return TT_Err_Ok;

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

    FREE( face->hdmx.records );
    face->hdmx.num_records = 0;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Load_TrueType_Any
 *
 *  Description :  Loads any font table into client memory. Used by
 *                 the TT_Get_Font_Data() API function.
 *
 *  Input  :  face     face object to look for
 *
 *            tag      tag of table to load. Use the value 0 if you
 *                     want to access the whole font file, else set
 *                     this parameter to a valid TrueType table tag
 *                     that you can forge with the MAKE_TT_TAG
 *                     macro.
 *
 *            offset   starting offset in the table (or the file
 *                     if tag == 0 )
 *
 *            buffer   address of target buffer
 *
 *            length   address of decision variable :
 *
 *                       if length == NULL :
 *                             load the whole table. returns an
 *                             an error if 'offset' == 0 !!
 *
 *                       if *length == 0 :
 *                             exit immediately, returning the
 *                             length of the given table, or of
 *                             the font file, depending on the
 *                             value of 'tag'
 *
 *                       if *length != 0 :
 *                             load the next 'length' bytes of
 *                             table or font, starting at offset
 *                             'offset' (in table or font too).
 *
 *  Output :  Error condition
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Load_TrueType_Any( PFace  face,
                               ULong  tag,
                               Long   offset,
                               void*  buffer,
                               Long*  length )
  {
    TT_Stream  stream;
    TT_Error   error;
    Long       table;
    ULong      size;


    if ( tag != 0 )
    {
      /* look for tag in font directory */
      table = TT_LookUp_Table( face, tag );
      if ( table < 0 )
        return TT_Err_Table_Missing;

      offset += face->dirTables[table].Offset;
      size    = face->dirTables[table].Length;
    }
    else
      /* tag = 0 -- the use want to access the font file directly */
      size = TT_Stream_Size( face->stream );

    if ( length && *length == 0 )
    {
      *length = size;
      return TT_Err_Ok;
    }

    if ( length )
      size = *length;

    if ( !USE_Stream( face->stream, stream ) )
      (void)FILE_Read_At( offset, buffer, size );
    DONE_Stream( stream );

    return error;
  }


/* END */


TTLOAD.H   、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttload.h                                                    1.1
 *
 *    TrueType Tables Loader.
 *
 *  Copyright 1996-1999 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.
 *
 *
 *  Changes between 1.1 and 1.0 :
 *
 *  - add function Load_TrueType_Any used by TT_Get_Font_Data
 *
 ******************************************************************/

#ifndef TTLOAD_H
#define TTLOAD_H

#include "ttconfig.h"
#include "tttypes.h"
#include "ttobjs.h"

#ifdef __cplusplus
  extern "C" {
#endif

  EXPORT_DEF
  Long  TT_LookUp_Table( PFace  face, ULong  tag  );

  LOCAL_DEF TT_Error  Load_TrueType_Directory        ( PFace  face,
                                                       ULong  faceIndex );

  LOCAL_DEF TT_Error  Load_TrueType_MaxProfile       ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_Gasp             ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_Header           ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_Locations        ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_Names            ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_CVT              ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_CMap             ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_Programs         ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_OS2              ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_PostScript       ( PFace  face );
  LOCAL_DEF TT_Error  Load_TrueType_Hdmx             ( PFace  face );

  LOCAL_DEF TT_Error  Load_TrueType_Metrics_Header( PFace  face,
                                                    Bool   vertical );

  LOCAL_DEF TT_Error  Load_TrueType_Any( PFace  face,
                                         ULong  tag,
                                         Long   offset,
                                         void*  buffer,
                                         Long*  length );

  LOCAL_DEF TT_Error  Free_TrueType_Names( PFace  face );
  LOCAL_DEF TT_Error  Free_TrueType_Hdmx ( PFace  face );


/* The following macros are defined to simplify the writing of */
/* the various table and glyph loaders.                        */

/* For examples see the code in ttload.c, ttgload.c etc.       */

#define USE_Stream( original, duplicate ) \
          ( (error = TT_Use_Stream( original, &duplicate )) != TT_Err_Ok )

#define DONE_Stream( _stream ) \
          TT_Done_Stream( &_stream )

/* Define a file frame -- use it only when needed */
#define DEFINE_A_FRAME   TFileFrame  frame = TT_Null_FileFrame

/* Define a stream -- use it only when needed */
#define DEFINE_A_STREAM  TT_Stream   stream


#ifdef TT_CONFIG_OPTION_THREAD_SAFE  /* re-entrant implementation */

/* The following macros define the necessary local */
/* variables used to access streams and frames.    */

/* Define stream locals with frame */
#define DEFINE_STREAM_LOCALS  \
          TT_Error  error;    \
          DEFINE_A_STREAM;    \
          DEFINE_A_FRAME

/* Define stream locals without frame */
#define DEFINE_STREAM_LOCALS_WO_FRAME  \
          TT_Error  error;             \
          DEFINE_A_STREAM

/* Define locals with a predefined stream in reentrant mode -- see ttload.c */
#define DEFINE_LOAD_LOCALS( STREAM )  \
          TT_Error  error;            \
          DEFINE_A_STREAM = (STREAM); \
          DEFINE_A_FRAME

/* Define locals without frame with a predefined stream - see ttload.c */
#define DEFINE_LOAD_LOCALS_WO_FRAME( STREAM ) \
          TT_Error      error;                \
          DEFINE_A_STREAM = (STREAM)

/* Define all locals necessary to access a font file */
#define DEFINE_ALL_LOCALS  \
          TT_Error  error; \
          DEFINE_A_STREAM; \
          DEFINE_A_FRAME


#define ACCESS_Frame( _size_ ) \
          ( (error = TT_Access_Frame( stream, \
                                      &frame, \
                                      (Long)(_size_) )) != TT_Err_Ok )
#define CHECK_ACCESS_Frame( _size_ ) \
          ( (error = TT_Check_And_Access_Frame( stream, \
                                                &frame, \
                                                (Long)(_size_) )) != TT_Err_Ok )
#define FORGET_Frame() \
          ( (void)TT_Forget_Frame( &frame ) )

#define GET_Byte()    TT_Get_Byte  ( &frame )
#define GET_Char()    TT_Get_Char  ( &frame )
#define GET_UShort()  TT_Get_UShort( &frame )
#define GET_Short()   TT_Get_Short ( &frame )
#define GET_Long()    TT_Get_Long  ( &frame )
#define GET_ULong()   TT_Get_ULong ( &frame )
#define GET_Tag4()    TT_Get_ULong ( &frame )

#define FILE_Pos()    TT_File_Pos ( stream )

#define FILE_Seek( _position_ ) \
          ( (error = TT_Seek_File( stream, \
                                   (Long)(_position_) )) != TT_Err_Ok )
#define FILE_Skip( _distance_ ) \
          ( (error = TT_Skip_File( stream, \
                                   (Long)(_distance_) )) != TT_Err_Ok )
#define FILE_Read( buffer, count ) \
          ( (error = TT_Read_File ( stream, \
                                    buffer, \
                                    (Long)(count) )) != TT_Err_Ok )
#define FILE_Read_At( pos, buffer, count ) \
          ( (error = TT_Read_At_File( stream, \
                                      (Long)(pos), \
                                      buffer, \
                                      (Long)(count) )) != TT_Err_Ok )

#else   /* thread-safe implementation */

/* Define stream locals with frame -- nothing in thread-safe mode */
#define DEFINE_STREAM_LOCALS  \
          TT_Error  error

/* Define stream locals without frame -- nothing in thread-safe mode */
#define DEFINE_STREAM_LOCALS_WO_FRAME \
          TT_Error  error

/* Define locals with a predefined stream in reentrant mode -- see ttload.c */
#define DEFINE_LOAD_LOCALS( STREAM ) \
          TT_Error  error


/* Define locals without frame with a predefined stream - see ttload.c */
#define DEFINE_LOAD_LOCALS_WO_FRAME( STREAM ) \
          TT_Error  error

/* Define all locals necessary to access a font file */
#define DEFINE_ALL_LOCALS  \
          TT_Error  error; \
          DEFINE_A_STREAM


#define ACCESS_Frame( _size_ ) \
          ( (error = TT_Access_Frame( (Long)(_size_) )) != TT_Err_Ok )
#define CHECK_ACCESS_Frame( _size_ ) \
          ( (error = TT_Check_And_Access_Frame( (Long)(_size_) )) != TT_Err_Ok )
#define FORGET_Frame() \
          ( (void)TT_Forget_Frame() )

#define GET_Byte()    TT_Get_Byte  ()
#define GET_Char()    TT_Get_Char  ()
#define GET_UShort()  TT_Get_UShort()
#define GET_Short()   TT_Get_Short ()
#define GET_Long()    TT_Get_Long  ()
#define GET_ULong()   TT_Get_ULong ()
#define GET_Tag4()    TT_Get_ULong ()

#define FILE_Pos()    TT_File_Pos()

#define FILE_Seek( _position_ ) \
          ( (error = TT_Seek_File( (Long)(_position_) )) != TT_Err_Ok )
#define FILE_Skip( _distance_ ) \
          ( (error = TT_Skip_File( (Long)(_distance_) )) != TT_Err_Ok )
#define FILE_Read( buffer, count ) \
          ( (error = TT_Read_File ( buffer, \
                                    (Long)(count) )) != TT_Err_Ok )
#define FILE_Read_At( pos, buffer, count ) \
          ( (error = TT_Read_At_File( (Long)(pos), \
                                      buffer, \
                                      (Long)(count) )) != TT_Err_Ok )

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */

#ifdef __cplusplus
  }
#endif

#endif /* TTLOAD_H */


/* END */




TTMEMORY.C  、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttmemory.c                                               1.2
 *
 *    Memory management component (body).
 *
 *  Copyright 1996-1999 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.
 *
 *
 *  Changes between 1.1 and 1.2:
 *
 *  - the font pool is gone.
 *
 *  - introduced the FREE macro and the Free function for
 *    future use in destructors.
 *
 *  - Init_FontPool() is now a macro to allow the compilation of
 *    'legacy' applications (all four test programs have been updated).
 *
 ******************************************************************/

#include "ttdebug.h"
#include "ttmemory.h"
#include "ttengine.h"

/* required by the tracing mode */
#undef  TT_COMPONENT
#define TT_COMPONENT  trace_memory


#ifdef DEBUG_MEMORY

#include <stdio.h>

#define MAX_TRACKED_BLOCKS  1024

  struct  TMemRec_
  {
    void*  base;
    Long   size;
  };

  typedef struct TMemRec_  TMemRec;

  static TMemRec  pointers[MAX_TRACKED_BLOCKS + 1];

  static Int  num_alloc;
  static Int  num_free;
  static Int  num_realloc; /* counts only `real' reallocations
                              (i.e., an existing buffer will be resized
                              to a value larger than zero */

  static Int  fail_alloc;
  static Int  fail_realloc;
  static Int  fail_free;

#endif /* DEBUG_MEMORY */


#ifndef TT_CONFIG_OPTION_THREAD_SAFE
  Long  TTMemory_Allocated;
  Long  TTMemory_MaxAllocated;
#endif


/*******************************************************************
 *
 *  Function    :  TT_Alloc
 *
 *  Description :  Allocates memory from the heap buffer.
 *
 *  Input  :  Size      size of the memory to be allocated
 *            P         pointer to a buffer pointer
 *
 *  Output :  Error code.
 *
 *  NOTE :  The newly allocated block should _always_ be zeroed
 *          on return.  Many parts of the engine rely on this to
 *          work properly.
 *
 ******************************************************************/

  EXPORT_FUNC
  TT_Error  TT_Alloc( ULong  Size, void**  P )
  {
#ifdef DEBUG_MEMORY
    Int  i;
#endif


    if ( !P )
      return TT_Err_Invalid_Argument;

    if ( Size > (size_t)-1 )
      return TT_Err_Out_Of_Memory;
    if ( Size > 0 )
    {
      //*P = (void*)malloc( Size );
        *P = (void*)dlmalloc( Size );    
      if ( !*P )
        return TT_Err_Out_Of_Memory;

#ifndef TT_CONFIG_OPTION_THREAD_SAFE
      TTMemory_Allocated    += Size;
      TTMemory_MaxAllocated += Size;
#endif

#ifdef DEBUG_MEMORY

      num_alloc++;

      i = 0;
      while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != NULL )
        i++;

      if ( i >= MAX_TRACKED_BLOCKS )
        fail_alloc++;
      else
      {
        pointers[i].base = *P;
        pointers[i].size = Size;
      }

#endif /* DEBUG_MEMORY */

      MEM_Set( *P, 0, Size );
    }
    else
      *P = NULL;

    return TT_Err_Ok;
  }


#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE


/*******************************************************************
 *
 *  Function    :  TT_Realloc
 *
 *  Description :  Reallocates memory from the heap buffer.
 *
 *  Input  :  Size      new size of the memory to be allocated;
 *                      if zero, TT_Free() will be called
 *            P         pointer to a buffer pointer; if *P == NULL,
 *                      TT_Alloc() will be called
 *
 *  Output :  Error code.
 *
 *  NOTES :  It's not necessary to zero the memory in case the 
 *           reallocated buffer is larger than before -- the
 *           application has to take care of this.
 *
 *           If the memory request fails, TT_Free() will be
 *           called on *P, and TT_Err_Out_Of_Memory returned.
 *
 ******************************************************************/

  EXPORT_FUNC
  TT_Error  TT_Realloc( ULong  Size, void**  P )
  {
    void*  Q;

#ifdef DEBUG_MEMORY
    Int  i;
#endif


    if ( !P )
      return TT_Err_Invalid_Argument;

    if ( !*P )
      return TT_Alloc( Size, P );

    if ( Size == 0 )
      return TT_Free( P );

    if ( Size > (size_t)-1 )
    {
      TT_Free( *P );
      return TT_Err_Out_Of_Memory;
    }

    //Q = (void*)realloc( *P, Size );
    Q = (void*)dlrealloc( *P, Size );
    if ( !Q )
    {
      TT_Free( *P );
      return TT_Err_Out_Of_Memory;
    }

#ifdef DEBUG_MEMORY

    num_realloc++;

    i = 0;
    while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
      i++;

    if ( i >= MAX_TRACKED_BLOCKS )
      fail_realloc++;
    else
    {
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
      TTMemory_Allocated += Size - pointers[i].size;
      if ( Size > pointers[i].size )
        TTMemory_MaxAllocated += Size - pointers[i].size;
#endif

      pointers[i].base = Q;
      pointers[i].size = size;
    }
#endif /* DEBUG_MEMORY */

    *P = Q;

    return TT_Err_Ok;
  }


#endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */


/*******************************************************************
 *
 *  Function    :  TT_Free
 *
 *  Description :  Releases a previously allocated block of memory.
 *
 *  Input  :  P    pointer to memory block
 *
 *  Output :  Always SUCCESS.
 *
 *  Note : The pointer must _always_ be set to NULL by this function.
 *
 ******************************************************************/

  EXPORT_FUNC
  TT_Error  TT_Free( void**  P )
  {
#ifdef DEBUG_MEMORY
    Int  i;
#endif /* DEBUG_MEMORY */


    if ( !P || !*P )
      return TT_Err_Ok;

#ifdef DEBUG_MEMORY

    num_free++;

    i = 0;
    while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
      i++;

    if ( i >= MAX_TRACKED_BLOCKS )
      fail_free++;
    else
    {
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
      TTMemory_Allocated -= pointers[i].size;
#endif

      pointers[i].base = NULL;
      pointers[i].size = 0;
    }
#endif /* DEBUG_MEMORY */

    dlfree( *P );

    *P = NULL;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TTMemory_Init
 *
 *  Description :  Initializes the memory.
 *
 *  Output :  Always SUCCESS.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  TTMemory_Init( void )
  {
#ifdef DEBUG_MEMORY
    Int  i;


    for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
    {
      pointers[i].base = NULL;
      pointers[i].size = 0;
    }

    num_alloc   = 0;
    num_realloc = 0;
    num_free    = 0;

    fail_alloc   = 0;
    fail_realloc = 0;
    fail_free    = 0;
#endif


#ifndef TT_CONFIG_OPTION_THREAD_SAFE
    TTMemory_Allocated    = 0;
    TTMemory_MaxAllocated = 0;
#endif

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TTMemory_Done
 *
 *  Description :  Finalizes memory usage.
 *
 *  Output :  Always SUCCESS.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  TTMemory_Done( void )
  {
#ifdef DEBUG_MEMORY
    Int  i, num_leaked, tot_leaked;


    num_leaked = 0;
    tot_leaked = 0;

    for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
    {
      if ( pointers[i].base )
      {
        num_leaked ++;
        tot_leaked += pointers[i].size;
      }
    }

    fprintf( stderr,
             "%d memory allocations, of which %d failed\n",
             num_alloc,
             fail_alloc );

    fprintf( stderr,
             "%d memory reallocations, of which %d failed\n",
             num_realloc,
             fail_realloc );

    fprintf( stderr,
             "%d memory frees, of which %d failed\n",
             num_free,
             fail_free );

    if ( num_leaked > 0 )
    {
      fprintf( stderr,
               "There are %d leaked memory blocks, totalizing %d bytes\n",
               num_leaked, tot_leaked );

      for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
      {
        if ( pointers[i].base )
        {
          fprintf( stderr,
                   "index: %4d (base: $%08lx, size: %08ld)\n",
                   i,
                   (long)pointers[i].base,
                   pointers[i].size );
        }
      }
    }
    else
      fprintf( stderr, "No memory leaks !\n" );

#endif /* DEBUG_MEMORY */

    return TT_Err_Ok;
  }


/* END */


TTMEMORY.H  、、、、、、、、、、、、、、、、、、、、、、、、、、、



/*******************************************************************
 *
 *  ttmemory.h                                               1.2
 *
 *    Memory management component (specification).
 *
 *  Copyright 1996-1999 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.
 *
 *  Changes between 1.2 and 1.1:
 *
 *  - the font pool is gone!  All allocations are now performed
 *    with malloc() and free().
 *
 *  - introduced the FREE() macro and the Free() function for
 *    future use in destructors.
 *
 *  - Init_FontPool() is now a macro to allow the compilation of
 *    'legacy' applications (all four test programs have been updated).
 *
 ******************************************************************/

#ifndef TTMEMORY_H
#define TTMEMORY_H

#include "ttconfig.h"
#include "tttypes.h"
//#include <string.h>


#ifdef __cplusplus
  extern "C" {
#endif

#define MEM_Set( dest, byte, count )  memset( dest, byte, count )

#ifdef HAVE_MEMCPY
#define MEM_Copy( dest, source, count )  memcpy( dest, source, count )
#else
#define MEM_Copy( dest, source, count )  bcopy( source, dest, count )
#endif

#ifdef HAVE_MEMMOVE
#define MEM_Move( dest, source, count )  memmove( dest, source, count )
#else
#define MEM_Move( dest, source, count )  bcopy( source, dest, count )
#endif


#define MEM_Alloc( _pointer_, _size_ ) \
  TT_Alloc( _size_, (void**)&(_pointer_) )

#define MEM_Realloc( _pointer_, _size_ ) \
  TT_Realloc( _size_, (void**)&(_pointer_) )

#define ALLOC( _pointer_, _size_ ) \
  ( ( error = MEM_Alloc( _pointer_, _size_ ) ) != TT_Err_Ok )

#define ALLOC_ARRAY( _pointer_, _count_, _type_ ) \
  ( ( error = MEM_Alloc( _pointer_, \
                         (_count_) * sizeof ( _type_ ) ) ) != TT_Err_Ok )

#define REALLOC( _pointer_, _size_ ) \
  ( ( error = MEM_Realloc( _pointer_, _size_ ) ) != TT_Err_Ok )

#define REALLOC_ARRAY( _pointer_, _count_, _type_ ) \
  ( (error = MEM_Realloc( _pointer_, \
                          (_count_) * sizeof ( _type_ ) ) ) != TT_Err_Ok )

#define FREE( _pointer_ ) \
  TT_Free( (void**)&(_pointer_) )


  /* Allocate a block of memory of 'Size' bytes from the heap, and */
  /* sets the pointer '*P' to its address.  If 'Size' is 0, or in  */
  /* case of error, the pointer is always set to NULL.             */

  EXPORT_DEF
  TT_Error  TT_Alloc( ULong  Size, void**  P );

#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE

  /* Reallocates a block of memory pointed to by '*P' to 'Size'    */
  /* bytes from the heap, possibly changing '*P'.  If 'Size' is 0, */
  /* TT_Free() is called, if '*P' is NULL, TT_Alloc() is called.   */
  /* '*P' is freed (if it's non-NULL) in case of error.            */

  EXPORT_DEF
  TT_Error  TT_Realloc( ULong  Size, void**  P );

#endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */

  /* Releases a block that was previously allocated through Alloc. */
  /* Note that the function returns successfully when P or *P are  */
  /* already NULL.  The pointer '*P' is set to NULL on exit in     */
  /* case of success.                                              */

  EXPORT_DEF
  TT_Error  TT_Free( void**  P );


  /* For "legacy" applications, that should be re-coded.              */
  /* Note that this won't release the previously allocated font pool. */

#define Init_FontPool( x, y )  while( 0 ) { }


  LOCAL_DEF TT_Error  TTMemory_Init( void );
  LOCAL_DEF TT_Error  TTMemory_Done( void );


#ifdef __cplusplus
  }
#endif

#endif /* TTMEMORY_H */


/* END */




TTMUTEX.C  、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、



/*******************************************************************
 *
 *  ttmutex.c                                                1.0
 *
 *    Mutual exclusion object, single-threaded implementation
 *
 *  Copyright 1996-1999 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.
 *
 *  NOTE:  This is a generic non-functional implementation
 *         that you are welcome to refine for your own system.
 *
 *         Please name your system-specific source with a
 *         different name (like ttmutex-os2.c or ttmutex-linux.c)
 *         and change your makefile accordingly.
 *
 ******************************************************************/

#include "ttmutex.h"


/* required by the tracing mode */
#undef  TT_COMPONENT
#define TT_COMPONENT  trace_mutex


/* ANSI C prevents the compilation of empty units.  We thus introduce */
/* a dummy typedef to get rid of compiler warnings/errors.            */
/* Note that gcc's -ansi -pedantic does not report any error here.    */
/* Watcom, VC++ or Borland C++ do however.                            */

  typedef void  _ttmutex_to_satisfy_ANSI_C_;


#ifdef TT_CONFIG_OPTION_THREAD_SAFE

  LOCAL_FUNC
  void  TT_Mutex_Create ( TMutex*  mutex )
  {
    *mutex = (void*)-1;
    /* Replace this line with your own mutex creation code */
  }


  LOCAL_FUNC
  void  TT_Mutex_Delete ( TMutex*  mutex )
  {
    *mutex = (void*)0;
    /* Replace this line with your own mutex destruction code */
  }


  LOCAL_FUNC
  void  TT_Mutex_Lock   ( TMutex*  mutex )
  {
    /* NOTE: It is legal to call this function with a NULL argument */
    /*       in which case an immediate return is appropriate.      */
    if ( !mutex )
      return;

    ; /* Insert your own mutex locking code here */
  }


  LOCAL_FUNC
  void  TT_Mutex_Release( TMutex*  mutex )
  {
    /* NOTE: It is legal to call this function with a NULL argument */
    /*       in which case an immediate return is appropriate       */
    if ( !mutex )
      return;

    ; /* Insert your own mutex release code here */
  }

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */


/* END */


TTMUTEX.H   、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttmutex.h                                                1.0
 *
 *    Mutual exclusion object / dummy generic interface.
 *
 *  Copyright 1996-1999 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.
 *
 *  Note:  This file provides a generic interface.  The implementation
 *         to compile depends on your system and the type of
 *         library you want to build (either singly-threaded,
 *         thread-safe or re-entrant).
 *
 *         Please read the technical documentation for more details.
 *
 ******************************************************************/

#ifndef TTMUTEX_H
#define TTMUTEX_H

#include "ttconfig.h"


  typedef  void*  TMutex;  /* typeless reference to a mutex */

#ifdef TT_CONFIG_OPTION_THREAD_SAFE /* thread-safe and re-entrant builds */

#define MUTEX_Create( mutex )   TT_Mutex_Create ( &(mutex) )
#define MUTEX_Destroy( mutex )  TT_Mutex_Delete ( &(mutex) )
#define MUTEX_Lock( mutex )     TT_Mutex_Lock   ( &(mutex) )
#define MUTEX_Release( mutex )  TT_Mutex_Release( &(mutex) )

  LOCAL_DEF void  TT_Mutex_Create ( TMutex*  mutex ); /* Create a new mutex */
  LOCAL_DEF void  TT_Mutex_Delete ( TMutex*  mutex ); /* Delete a mutex     */
  LOCAL_DEF void  TT_Mutex_Lock   ( TMutex*  mutex ); /* Lock a mutex.      */
  LOCAL_DEF void  TT_Mutex_Release( TMutex*  mutex ); /* Release a mutex    */

#else  /* for the single-thread build */

#define MUTEX_Create( mutex )   /* nothing */
#define MUTEX_Destroy( mutex )  /* nothing */
#define MUTEX_Lock( mutex )     /* nothing */
#define MUTEX_Release( mutex )  /* nothing */

  /* No code will be generated for mutex operations */

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */

#endif /* TTMUTEX_H */


/* END */


TTOBJS.C    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttobjs.c                                                     1.0
 *
 *    Objects manager.
 *
 *  Copyright 1996-1999 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 "ttobjs.h"
#include "ttfile.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttload.h"
#include "ttinterp.h"
#include "ttdebug.h"


/* Add extensions definition */
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
#include "ttextend.h"
#endif

/* Required by tracing mode */
#undef   TT_COMPONENT
#define  TT_COMPONENT  trace_objs

/*******************************************************************
 *
 *  Function    :  New_Context
 *
 *  Description :  Creates a new execution context for a given
 *                 face object.
 *
 ******************************************************************/

  LOCAL_FUNC
  PExecution_Context  New_Context( PFace  face )
  {
    PEngine_Instance    engine;
    PExecution_Context  exec;


    if ( !face )
      return NULL;

    engine = face->engine;
    CACHE_New( engine->objs_exec_cache, exec, face );
    return exec;
  }


/*******************************************************************
 *
 *  Function    :  Done_Context
 *
 *  Description :  Discards an execution context.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Done_Context( PExecution_Context  exec )
  {
    PEngine_Instance  engine;


    if ( !exec )
      return TT_Err_Ok;

    engine = exec->face->engine;
    return CACHE_Done( engine->objs_exec_cache, exec );
  }


#if 0

/*******************************************************************
 *
 *  Function    :  New_Instance
 *
 *  Description :  Creates a new instance for a given face object.
 *
 ******************************************************************/

  LOCAL_FUNC
  PInstance  New_Instance( PFace  face )
  {
    PInstance  ins;


    if ( !face )
      return NULL;

    CACHE_New( &face->instances, ins, face );

    return ins;
  }


/*******************************************************************
 *
 *  Function    :  Done_Instance
 *
 *  Description :  Discards an instance.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Done_Instance( PInstance  instance )
  {
    return CACHE_Done( &instance->owner->instances, instance );
  }

#endif


/*******************************************************************
 *                                                                 *
 *                     GLYPH ZONE FUNCTIONS                        *
 *                                                                 *
 *                                                                 *
 *******************************************************************/

/*******************************************************************
 *
 *  Function    :  New_Glyph_Zone
 *
 *  Description :  Allocates a new glyph zone
 *
 *  Input  :  pts          pointer to the target glyph zone record
 *            maxPoints    capacity of glyph zone in points
 *            maxContours  capacity of glyph zone in contours
 *
 *  Return :  Error code.
 *
 *****************************************************************/

  static
  TT_Error  New_Glyph_Zone( PGlyph_Zone  pts,
                            UShort       maxPoints,
                            UShort       maxContours )
  {
    TT_Error  error;


    if ( ALLOC( pts->org, maxPoints * 2 * sizeof ( TT_F26Dot6 ) ) ||
         ALLOC( pts->cur, maxPoints * 2 * sizeof ( TT_F26Dot6 ) ) ||
         ALLOC( pts->touch, maxPoints * sizeof ( Byte )         ) ||
         ALLOC( pts->contours, maxContours * sizeof ( Short ) ) )
      return error;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Done_Glyph_Zone
 *
 *  Description :  Deallocates a glyph zone
 *
 *  Input  :  pts          pointer to the target glyph zone record
 *
 *  Return :  Error code.
 *
 *****************************************************************/

  static
  TT_Error  Done_Glyph_Zone( PGlyph_Zone  pts )
  {
    FREE( pts->contours );
    FREE( pts->touch );
    FREE( pts->cur );
    FREE( pts->org );

    return TT_Err_Ok;
  }

/*******************************************************************
 *                                                                 *
 *                     CODERANGE FUNCTIONS                         *
 *                                                                 *
 *******************************************************************/

/*******************************************************************
 *
 *  Function    :  Goto_CodeRange
 *
 *  Description :  Switch to a new code range (updates Code and IP).
 *
 *  Input  :  exec    target execution context
 *            range   new execution code range
 *            IP      new IP in new code range
 *
 *  Output :  SUCCESS on success.  FAILURE on error (no code range).
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error  Goto_CodeRange( PExecution_Context  exec,
                            Int                 range,
                            ULong               IP )
  {
    PCodeRange  cr;


    if ( range < 1 || range > 3 )
      return TT_Err_Bad_Argument;

    cr = &exec->codeRangeTable[range - 1];

    if ( cr->Base == NULL )
      return TT_Err_Invalid_CodeRange;

    /* NOTE:  Because the last instruction of a program may be a CALL */
    /*        which will return to the first byte *after* the code    */
    /*        range, we test for IP <= Size, instead of IP < Size.    */

    if ( IP > cr->Size )
      return TT_Err_Code_Overflow;

    exec->code     = cr->Base;
    exec->codeSize = cr->Size;
    exec->IP       = IP;
    exec->curRange = range;

    return TT_Err_Ok;
  }


#if 0

/*******************************************************************
 *
 *  Function    :  Get_CodeRange
 *
 *  Description :  Returns a pointer to a given code range.  Should
 *                 be used only by the debugger.  Returns NULL if
 *                 'range' is out of current bounds.
 *
 *  Input  :  exec    target execution context
 *            range   new execution code range
 *
 *  Output :  Pointer to the code range record.  NULL on failure.
 *
 *****************************************************************/

  LOCAL_FUNC
  PCodeRange  Get_CodeRange( PExecution_Context  exec, Int  range )
  {
    if ( range < 1 || range > 3 )
      return NULL;
    else                /* arrays start with 1 in Pascal, and with 0 in C */
      return &exec->codeRangeTable[range - 1];
  }

#endif


/*******************************************************************
 *
 *  Function    :  Set_CodeRange
 *
 *  Description :  Sets a code range.
 *
 *  Input  :  exec    target execution context
 *            range   code range index
 *            base    new code base
 *            length  range size in bytes
 *
 *  Output :  SUCCESS on success.  FAILURE on error.
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error  Set_CodeRange( PExecution_Context  exec,
                           Int                 range,
                           void*               base,
                           ULong               length )
  {
    if ( range < 1 || range > 3 )
      return TT_Err_Bad_Argument;

    exec->codeRangeTable[range - 1].Base = (Byte*)base;
    exec->codeRangeTable[range - 1].Size = length;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Clear_CodeRange
 *
 *  Description :  Clears a code range.
 *
 *  Input  :  exec    target execution context
 *            range   code range index
 *
 *  Output :  SUCCESS on success.  FAILURE on error.
 *
 *  Note   : Does not set the Error variable.
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error Clear_CodeRange( PExecution_Context  exec, Int  range )
  {
    if ( range < 1 || range > 3 )
      return TT_Err_Bad_Argument;

    exec->codeRangeTable[range - 1].Base = NULL;
    exec->codeRangeTable[range - 1].Size = 0;

    return TT_Err_Ok;
  }

/*******************************************************************
 *                                                                 *
 *                EXECUTION CONTEXT ROUTINES                       *
 *                                                                 *
 *******************************************************************/

/*******************************************************************
 *
 *  Function    :  Context_Destroy
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error  Context_Destroy( void*  _context )
  {
    PExecution_Context  exec = (PExecution_Context)_context;

    if ( !exec )
      return TT_Err_Ok;

    /* free composite load stack */
    FREE( exec->loadStack );
    exec->loadSize = 0;

    /* points zone */
    Done_Glyph_Zone( &exec->pts );
    exec->maxPoints   = 0;
    exec->maxContours = 0;

    /* free stack */
    FREE( exec->stack );
    exec->stackSize = 0;

    /* free call stack */
    FREE( exec->callStack );
    exec->callSize = 0;
    exec->callTop  = 0;

    /* free glyph code range */
    FREE( exec->glyphIns );
    exec->glyphSize = 0;

    exec->instance = NULL;
    exec->face     = NULL;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Context_Create
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error  Context_Create( void*  _context, void*  _face )
  {
    PExecution_Context  exec = (PExecution_Context)_context;

    PFace        face = (PFace)_face;
    TT_Error     error;


    /* XXX : We don't reserve arrays anymore, this is done automatically */
    /*       during a "Context_Load"..                                   */

    exec->callSize  = 32;
    if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TCallRecord ) )
      goto Fail_Memory;

    /* all values in the context are set to 0 already, but this is */
    /* here as a remainder                                         */
    exec->maxPoints   = 0;
    exec->maxContours = 0;

    exec->stackSize = 0;
    exec->loadSize  = 0;
    exec->glyphSize = 0;

    exec->stack     = NULL;
    exec->loadStack = NULL;
    exec->glyphIns  = NULL;

    exec->face     = face;
    exec->instance = NULL;

    return TT_Err_Ok;

  Fail_Memory:
    Context_Destroy( exec );
    return error;
  }


/*******************************************************************
 *
 *  Function    :  Context_Load
 *
 *****************************************************************/

/****************************************************************/
/*                                                              */
/* Update_Max : Reallocate a buffer if it needs to              */
/*                                                              */
/* input:  size        address of buffer's current size         */
/*                     expressed in elements                    */
/*                                                              */
/*         multiplier  size in bytes of each element in the     */
/*                     buffer                                   */
/*                                                              */
/*         buff        address of the buffer base pointer       */
/*                                                              */
/*         new_max     new capacity (size) of the buffer        */

  static
  TT_Error  Update_Max( ULong*  size,
                        ULong   multiplier,
                        void**  buff,
                        ULong   new_max )
  {
    TT_Error  error;

    if ( *size < new_max )
    {
      FREE( *buff );
      if ( ALLOC( *buff, new_max * multiplier ) )
        return error;
      *size = new_max;
    }
    return TT_Err_Ok;
  }


/****************************************************************/
/*                                                              */
/* Update_Zone: Reallocate a zone if it needs to                */
/*                                                              */
/* input:  zone        address of the target zone               */
/*                                                              */
/*         maxPoints   address of the zone's current capacity   */
/*                     in points                                */
/*                                                              */
/*         maxContours address of the zone's current capacity   */
/*                     in contours                              */
/*                                                              */
/*         newPoints   new capacity in points                   */
/*                                                              */
/*         newContours new capacity in contours                 */
/*                                                              */

  static
  TT_Error  Update_Zone( PGlyph_Zone  zone,
                         UShort*      maxPoints,
                         UShort*      maxContours,
                         UShort       newPoints,
                         UShort       newContours )
  {
    if ( *maxPoints < newPoints || *maxContours < newContours )
    {
      TT_Error  error;


      Done_Glyph_Zone( zone );

      error = New_Glyph_Zone( zone, newPoints, newContours );
      if ( error )
        return error;

      *maxPoints   = newPoints;
      *maxContours = newContours;
    }
    return TT_Err_Ok;
  }


  LOCAL_FUNC
  TT_Error Context_Load( PExecution_Context  exec,
                         PFace               face,
                         PInstance           ins )
  {
    Int           i;
    TMaxProfile*  maxp;
    TT_Error      error;

    exec->face     = face;
    maxp           = &face->maxProfile;

    exec->instance = ins;

    if ( ins )
    {
      exec->numFDefs = ins->numFDefs;
      exec->numIDefs = ins->numIDefs;
      exec->maxFDefs = ins->maxFDefs;
      exec->maxIDefs = ins->maxIDefs;
      exec->FDefs    = ins->FDefs;
      exec->IDefs    = ins->IDefs;
      exec->metrics  = ins->metrics;

      exec->maxFunc  = ins->maxFunc;
      exec->maxIns   = ins->maxIns;

      for ( i = 0; i < MAX_CODE_RANGES; i++ )
        exec->codeRangeTable[i] = ins->codeRangeTable[i];

      /* set graphics state */
      exec->GS = ins->GS;

      exec->cvtSize = ins->cvtSize;
      exec->cvt     = ins->cvt;

      exec->storeSize = ins->storeSize;
      exec->storage   = ins->storage;

      exec->twilight  = ins->twilight;
    }

    error = Update_Max( &exec->loadSize,
                        sizeof ( TSubglyph_Record ),
                        (void**)&exec->loadStack,
                        face->maxComponents + 1 );
    if ( error )
      return error;

    error = Update_Max( &exec->stackSize,
                        sizeof ( TT_F26Dot6 ),
                        (void**)&exec->stack,
                        maxp->maxStackElements + 32 );
    /* XXX : We reserve a little more elements on the stack to deal safely */
    /*       with broken fonts like arialbs, courbs, timesbs...            */
    if ( error )
      return error;

    error = Update_Max( &exec->glyphSize,
                        sizeof ( Byte ),
                        (void**)&exec->glyphIns,
                        maxp->maxSizeOfInstructions );
    if ( error )
      return error;

    error = Update_Zone( &exec->pts,
                         &exec->maxPoints,
                         &exec->maxContours,
                         exec->face->maxPoints + 2,
                         exec->face->maxContours );
    /* XXX : We reserve two positions for the phantom points! */
    if ( error )
      return error;

    exec->pts.n_points   = 0;
    exec->pts.n_contours = 0;

    exec->instruction_trap = FALSE;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Context_Save
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error  Context_Save( PExecution_Context  exec,
                          PInstance           ins )
  {
    Int  i;

    /* XXXX : Will probably disappear soon with all the coderange */
    /*        management, which is now rather obsolete.           */

    ins->numFDefs = exec->numFDefs;
    ins->numIDefs = exec->numIDefs;
    ins->maxFunc  = exec->maxFunc;
    ins->maxIns   = exec->maxIns;

    for ( i = 0; i < MAX_CODE_RANGES; i++ )
      ins->codeRangeTable[i] = exec->codeRangeTable[i];

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Context_Run
 *
 *****************************************************************/

  LOCAL_FUNC
  TT_Error  Context_Run( PExecution_Context  exec,
                         Bool                debug )
  {
    TT_Error  error;


    if ( (error = Goto_CodeRange( exec,
                                  TT_CodeRange_Glyph, 0 )) != TT_Err_Ok )
      return error;

    exec->zp0 = exec->pts;
    exec->zp1 = exec->pts;
    exec->zp2 = exec->pts;

    exec->GS.gep0 = 1;
    exec->GS.gep1 = 1;
    exec->GS.gep2 = 1;

    exec->GS.projVector.x = 0x4000;
    exec->GS.projVector.y = 0x0000;

    exec->GS.freeVector = exec->GS.projVector;
    exec->GS.dualVector = exec->GS.projVector;

    exec->GS.round_state = 1;
    exec->GS.loop        = 1;

    /* some glyphs leave something on the stack. so we clean it */
    /* before a new execution.                                  */
    exec->top     = 0;
    exec->callTop = 0;

    if ( !debug )
      return RunIns( exec );
    else
      return TT_Err_Ok;
  }


  LOCAL_FUNC
  const TGraphicsState  Default_GraphicsState =
  {
    0, 0, 0,
    { 0x4000, 0 },
    { 0x4000, 0 },
    { 0x4000, 0 },
    1, 64, 1,
    TRUE, 68, 0, 0, 9, 3,
    0, FALSE, 2, 1, 1, 1
  };

/*******************************************************************
 *                                                                 *
 *                     INSTANCE  FUNCTIONS                         *
 *                                                                 *
 *                                                                 *
 *******************************************************************/

/*******************************************************************
 *
 *  Function    : Instance_Destroy
 *
 *  Description :
 *
 *  Input  :  _instance   the instance object to destroy
 *
 *  Output :  error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Instance_Destroy( void* _instance )
  {
    PInstance  ins = (PInstance)_instance;


    if ( !_instance )
      return TT_Err_Ok;

    if ( ins->debug )
    {
      /* the debug context must be deleted by the debugger itself */
      ins->context = NULL;
      ins->debug   = FALSE;
    }

    FREE( ins->cvt );
    ins->cvtSize = 0;

    /* free storage area */
    FREE( ins->storage );
    ins->storeSize = 0;

    /* twilight zone */
    Done_Glyph_Zone( &ins->twilight );

    FREE( ins->FDefs );
    FREE( ins->IDefs );
    ins->numFDefs = 0;
    ins->numIDefs = 0;
    ins->maxFDefs = 0;
    ins->maxIDefs = 0;
    ins->maxFunc  = -1;
    ins->maxIns   = -1;

    ins->owner = NULL;
    ins->valid = FALSE;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    : Instance_Create
 *
 *  Description :
 *
 *  Input  :  _instance    instance record to initialize
 *            _face        parent face object
 *
 *  Output :  Error code.  All partially built subtables are
 *            released on error.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Instance_Create( void*  _instance,
                             void*  _face )
  {
    PInstance  ins  = (PInstance)_instance;
    PFace      face = (PFace)_face;
    TT_Error   error;
    Int        i;
    UShort     n_twilight;

    PMaxProfile  maxp = &face->maxProfile;


    ins->owner = face;
    ins->valid = FALSE;

    ins->maxFDefs  = maxp->maxFunctionDefs;
    ins->maxIDefs  = maxp->maxInstructionDefs;
    ins->cvtSize   = face->cvtSize;
    ins->storeSize = maxp->maxStorage;

    /* Set default metrics */
    {
      PIns_Metrics   metrics = &ins->metrics;


      metrics->pointSize    = 10 * 64;     /* default pointsize  = 10pts */

      metrics->x_resolution = 96;          /* default resolution = 96dpi */
      metrics->y_resolution = 96;

      metrics->x_ppem = 0;
      metrics->y_ppem = 0;

      metrics->rotated   = FALSE;
      metrics->stretched = FALSE;

      /* set default compensation ( all 0 ) */
      for ( i = 0; i < 4; i++ )
        metrics->compensations[i] = 0;
    }

    /* allocate function defs, instruction defs, cvt and storage area */
    if ( ALLOC_ARRAY( ins->FDefs,   ins->maxFDefs,  TDefRecord )  ||
         ALLOC_ARRAY( ins->IDefs,   ins->maxIDefs,  TDefRecord )  ||
         ALLOC_ARRAY( ins->cvt,     ins->cvtSize,   Long       )  ||
         ALLOC_ARRAY( ins->storage, ins->storeSize, Long       )  )
      goto Fail_Memory;

    /* reserve twilight zone */
    n_twilight = maxp->maxTwilightPoints;
    error = New_Glyph_Zone( &ins->twilight, n_twilight, 0 );
    if (error)
      goto Fail_Memory;

    ins->twilight.n_points = n_twilight;

    return TT_Err_Ok;

  Fail_Memory:
    Instance_Destroy( ins );
    return error;
  }


/*******************************************************************
 *
 *  Function    : Instance_Init
 *
 *  Description : Initialize a fresh new instance.
 *                Executes the font program if any is found.
 *
 *  Input  :  _instance   the instance object to destroy
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Instance_Init( PInstance  ins )
  {
    PExecution_Context  exec;

    TT_Error  error;
    PFace     face = ins->owner;


    if ( ins->debug )
      exec = ins->context;
    else
      exec = New_Context( face );
    /* debugging instances have their own context */

    if ( !exec )
      return TT_Err_Could_Not_Find_Context;

    ins->GS = Default_GraphicsState;

    ins->numFDefs = 0;
    ins->numIDefs = 0;
    ins->maxFunc  = -1;
    ins->maxIns   = -1;

    Context_Load( exec, face, ins );

    exec->callTop   = 0;
    exec->top       = 0;

    exec->period    = 64;
    exec->phase     = 0;
    exec->threshold = 0;

    {
      PIns_Metrics  metrics = &exec->metrics;


      metrics->x_ppem    = 0;
      metrics->y_ppem    = 0;
      metrics->pointSize = 0;
      metrics->x_scale1  = 0;
      metrics->x_scale2  = 1;
      metrics->y_scale1  = 0;
      metrics->y_scale2  = 1;

      metrics->ppem      = 0;
      metrics->scale1    = 0;
      metrics->scale2    = 1;
      metrics->ratio     = 1L << 16;
    }

    exec->instruction_trap = FALSE;

    exec->cvtSize = ins->cvtSize;
    exec->cvt     = ins->cvt;

    exec->F_dot_P = 0x10000;

    /* allow font program execution */
    Set_CodeRange( exec,
                   TT_CodeRange_Font,
                   face->fontProgram,
                   face->fontPgmSize );

    /* disable CVT and glyph programs coderange */
    Clear_CodeRange( exec, TT_CodeRange_Cvt );
    Clear_CodeRange( exec, TT_CodeRange_Glyph );

    if ( face->fontPgmSize > 0 )
    {
      error = Goto_CodeRange( exec, TT_CodeRange_Font, 0 );
      if ( error )
        goto Fin;

      error = RunIns( exec );
    }
    else
      error = TT_Err_Ok;

  Fin:
    Context_Save( exec, ins );

    if ( !ins->debug )
      Done_Context( exec );
    /* debugging instances keep their context */

    ins->valid = FALSE;

    return error;
  }


/*******************************************************************
 *
 *  Function    : Instance_Reset
 *
 *  Description : Resets an instance to a new pointsize/transform.
 *                Executes the cvt program if any is found.
 *
 *  Input  :  _instance   the instance object to destroy
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Instance_Reset( PInstance  ins )
  {
    PExecution_Context  exec;

    TT_Error  error;
    ULong     i;
    UShort    j;
    PFace     face;


    if ( !ins )
      return TT_Err_Invalid_Instance_Handle;

    if ( ins->valid )
      return TT_Err_Ok;

    face = ins->owner;

    if ( ins->metrics.x_ppem < 1 ||
         ins->metrics.y_ppem < 1 )
      return TT_Err_Invalid_PPem;

    /* compute new transformation */
    if ( ins->metrics.x_ppem >= ins->metrics.y_ppem )
    {
      ins->metrics.scale1  = ins->metrics.x_scale1;
      ins->metrics.scale2  = ins->metrics.x_scale2;
      ins->metrics.ppem    = ins->metrics.x_ppem;
      ins->metrics.x_ratio = 1L << 16;
      ins->metrics.y_ratio = TT_MulDiv( ins->metrics.y_ppem,
                                        0x10000,
                                        ins->metrics.x_ppem );
    }
    else
    {
      ins->metrics.scale1  = ins->metrics.y_scale1;
      ins->metrics.scale2  = ins->metrics.y_scale2;
      ins->metrics.ppem    = ins->metrics.y_ppem;
      ins->metrics.x_ratio = TT_MulDiv( ins->metrics.x_ppem,
                                        0x10000,
                                        ins->metrics.y_ppem );
      ins->metrics.y_ratio = 1L << 16;
    }

    /* Scale the cvt values to the new ppem.          */
    /* We use by default the y ppem to scale the CVT. */

    for ( i = 0; i < ins->cvtSize; i++ )
      ins->cvt[i] = TT_MulDiv( face->cvt[i],
                               ins->metrics.scale1,
                               ins->metrics.scale2 );

    /* All twilight points are originally zero */
    for ( j = 0; j < ins->twilight.n_points; j++ )
    {
      ins->twilight.org[j].x = 0;
      ins->twilight.org[j].y = 0;
      ins->twilight.cur[j].x = 0;
      ins->twilight.cur[j].y = 0;
    }

    /* clear storage area */
    for ( i = 0; i < ins->storeSize; i++ )
      ins->storage[i] = 0;

    ins->GS = Default_GraphicsState;

    /* get execution context and run prep program */

    if ( ins->debug )
      exec = ins->context;
    else
      exec = New_Context(face);
    /* debugging instances have their own context */

    if ( !exec )
      return TT_Err_Could_Not_Find_Context;

    Context_Load( exec, face, ins );

    Set_CodeRange( exec,
                   TT_CodeRange_Cvt,
                   face->cvtProgram,
                   face->cvtPgmSize );

    Clear_CodeRange( exec, TT_CodeRange_Glyph );

    exec->instruction_trap = FALSE;

    exec->top     = 0;
    exec->callTop = 0;

    if ( face->cvtPgmSize > 0 )
    {
      error = Goto_CodeRange( exec, TT_CodeRange_Cvt, 0 );
      if ( error )
        goto Fin;

      if ( !ins->debug )
        error = RunIns( exec );
    }
    else
      error = TT_Err_Ok;

    ins->GS = exec->GS;
    /* save default graphics state */

  Fin:
    Context_Save( exec, ins );

    if ( !ins->debug )
      Done_Context( exec );
    /* debugging instances keep their context */

    if ( !error )
      ins->valid = TRUE;

    return error;
  }

/*******************************************************************
 *                                                                 *
 *                         FACE  FUNCTIONS                         *
 *                                                                 *
 *                                                                 *
 *******************************************************************/

/*******************************************************************
 *
 *  Function    :  Face_Destroy
 *
 *  Description :  The face object destructor.
 *
 *  Input  :  _face   typeless pointer to the face object to destroy
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Face_Destroy( void*  _face )
  {
    PFace   face = (PFace)_face;
    UShort  n;


    if ( !face )
      return TT_Err_Ok;

    /* well, we assume that no other thread is using the face */
    /* at this moment, but one is never sure enough.          */
    MUTEX_Lock( face->lock );

    /* first of all, destroys the cached sub-objects */
    Cache_Destroy( &face->instances );
    Cache_Destroy( &face->glyphs );

    /* destroy the extensions */
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
    Extension_Destroy( face );
#endif

    /* freeing the collection table */
    FREE( face->ttcHeader.TableDirectory );
    face->ttcHeader.DirCount = 0;

    /* freeing table directory */
    FREE( face->dirTables );
    face->numTables = 0;

    /* freeing the locations table */
    FREE( face->glyphLocations );
    face->numLocations = 0;

    /* freeing the character mapping tables */
    for ( n = 0; n < face->numCMaps; n++ )
      CharMap_Free( face->cMaps + n );

    FREE( face->cMaps );
    face->numCMaps = 0;

    /* freeing the CVT */
    FREE( face->cvt );
    face->cvtSize = 0;

    /* freeing the horizontal metrics */
    FREE( face->horizontalHeader.long_metrics );
    FREE( face->horizontalHeader.short_metrics );

    /* freeing the vertical ones, if any */
    if (face->verticalInfo)
    {
      FREE( face->verticalHeader.long_metrics  );
      FREE( face->verticalHeader.short_metrics );
      face->verticalInfo = 0;
    }

    /* freeing the programs */
    FREE( face->fontProgram );
    FREE( face->cvtProgram );
    face->fontPgmSize = 0;
    face->cvtPgmSize  = 0;

    /* freeing the gasp table */
    FREE( face->gasp.gaspRanges );
    face->gasp.numRanges = 0;

    /* freeing the name table */
    Free_TrueType_Names( face );

    /* freeing the hdmx table */
    Free_TrueType_Hdmx( face );

    /* TT_Close_Stream( &face->stream ); -- this is performed by the API */

    /* destroy the mutex */
    MUTEX_Destroy(face->lock);

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  Face_Create
 *
 *  Description :  The face object constructor.
 *
 *  Input  :  _face    face record to build
 *            _input   input stream where to load font data
 *
 *  Output :  Error code.
 *
 *  NOTE : The input stream is kept in the face object.  The
 *         caller shouldn't destroy it after calling Face_Create().
 *
 ******************************************************************/

#undef  LOAD_
#define LOAD_( table ) \
          (error = Load_TrueType_##table (face)) != TT_Err_Ok


  LOCAL_FUNC
  TT_Error  Face_Create( void*  _face,
                         void*  _input )
  {
    PEngine_Instance  engine;

    TFont_Input*  input = (TFont_Input*)_input;
    PFace         face  = (PFace)_face;
    TT_Error      error;


    face->stream = input->stream;
    face->engine = input->engine;

    engine = face->engine;

    MUTEX_Create( face->lock );

    Cache_Create( engine,
                  engine->objs_instance_class,
                  &face->instances,
                  &face->lock );

    Cache_Create( engine,
                  engine->objs_glyph_class,
                  &face->glyphs,
                  &face->lock );

    /* Load collection directory if present, then font directory */

    error = Load_TrueType_Directory( face, input->fontIndex );
    if ( error )
      goto Fail;

    /* Load tables */

    if ( LOAD_( Header )        ||
         LOAD_( MaxProfile )    ||
         LOAD_( Locations )     ||

         (error = Load_TrueType_Metrics_Header( face, 0 )) != TT_Err_Ok  ||
         /* load the 'hhea' & 'hmtx' tables at once */

         LOAD_( CMap )          ||
         LOAD_( CVT )           ||
         LOAD_( Programs )      ||
         LOAD_( Gasp )          ||
         LOAD_( Names )         ||
         LOAD_( OS2 )           ||
         LOAD_( PostScript )    ||

         (error = Load_TrueType_Metrics_Header( face, 1 )) != TT_Err_Ok ||
         /* try to load the 'vhea' & 'vmtx' at once if present */

         LOAD_( Hdmx )          )

      goto Fail;

#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
    if ( ( error = Extension_Create( face ) ) != TT_Err_Ok )
      return error;
#endif

    return TT_Err_Ok;

  Fail :
    Face_Destroy( face );
    return error;
  }

#undef LOAD_


/*******************************************************************
 *
 *  Function    :  Glyph_Destroy
 *
 *  Description :  The glyph object destructor.
 *
 *  Input  :  _glyph  typeless pointer to the glyph record to destroy
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Glyph_Destroy( void*  _glyph )
  {
    PGlyph  glyph = (PGlyph)_glyph;


    if ( !glyph )
      return TT_Err_Ok;

    glyph->outline.owner = TRUE;
    return TT_Done_Outline( &glyph->outline );
  }


/*******************************************************************
 *
 *  Function    :  Glyph_Create
 *
 *  Description :  The glyph object constructor.
 *
 *  Input  :  _glyph   glyph record to build.
 *            _face    the glyph's parent face.
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  Glyph_Create( void*  _glyph,
                          void*  _face )
  {
    PFace     face  = (PFace)_face;
    PGlyph    glyph = (PGlyph)_glyph;


    if ( !face )
      return TT_Err_Invalid_Face_Handle;

    if ( !glyph )
      return TT_Err_Invalid_Glyph_Handle;

    glyph->face = face;

    /* XXX: Don't forget the space for the 2 phantom points */
    return TT_New_Outline( glyph->face->maxPoints + 2,
                           glyph->face->maxContours,
                           &glyph->outline );
  }


/*******************************************************************
 *
 *  Function    :  Scale_X
 *
 *  Description :  scale an horizontal distance from font
 *                 units to 26.6 pixels
 *
 *  Input  :  metrics  pointer to metrics
 *            x        value to scale
 *
 *  Output :  scaled value
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Pos  Scale_X( PIns_Metrics  metrics, TT_Pos  x )
  {
    return TT_MulDiv( x, metrics->x_scale1, metrics->x_scale2 );
  }


/*******************************************************************
 *
 *  Function    :  Scale_Y
 *
 *  Description :  scale a vertical distance from font
 *                 units to 26.6 pixels
 *
 *  Input  :  metrics  pointer to metrics
 *            y        value to scale
 *
 *  Output :  scaled value
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Pos  Scale_Y( PIns_Metrics  metrics, TT_Pos  y )
  {
    return TT_MulDiv( y, metrics->y_scale1, metrics->y_scale2 );
  }


/*******************************************************************
 *
 *  Function    :  TTObjs_Init
 *
 *  Description :  The TTObjs component initializer.  Creates the
 *                 object cache classes, as well as the face record
 *                 cache.
 *
 *  Input  :  engine    engine instance
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  static
  const TCache_Class  objs_face_class =
  {
    sizeof ( TFace ),
    -1,
    Face_Create,
    Face_Destroy,
    NULL,
    NULL
  };

  static
  const TCache_Class  objs_instance_class =
  {
    sizeof ( TInstance ),
    -1,
    Instance_Create,
    Instance_Destroy,
    NULL,
    NULL
  };

  /* Note that we use a cache size of 1 for the execution context.  */
  /* This is to avoid re-creating a new context each time we        */
  /* change one instance's attribute (resolution and/or char sizes) */
  /* or when we load a glyph.                                       */

  static
  const TCache_Class  objs_exec_class =
  {
    sizeof ( TExecution_Context ),
    1,
    Context_Create,
    Context_Destroy,
    NULL,
    NULL
  };

  static
  const TCache_Class  objs_glyph_class =
  {
    sizeof ( TGlyph ),
    -1,
    Glyph_Create,
    Glyph_Destroy,
    NULL,
    NULL
  };


  LOCAL_FUNC
  TT_Error  TTObjs_Init( PEngine_Instance  engine )
  {
    PCache        face_cache, exec_cache;
    TT_Error      error;


    face_cache = 0;
    exec_cache = 0;

    if ( ALLOC( face_cache, sizeof ( TCache ) ) ||
         ALLOC( exec_cache, sizeof ( TCache ) ) )
      goto Fail;

      /* create face cache */
    error = Cache_Create( engine, (PCache_Class)&objs_face_class,
                          face_cache, &engine->lock );
    if ( error )
      goto Fail;

    engine->objs_face_cache = face_cache;

    error = Cache_Create( engine, (PCache_Class)&objs_exec_class,
                          exec_cache, &engine->lock );
    if ( error )
      goto Fail;

    engine->objs_exec_cache = exec_cache;

    engine->objs_face_class      = (PCache_Class)&objs_face_class;
    engine->objs_instance_class  = (PCache_Class)&objs_instance_class;
    engine->objs_execution_class = (PCache_Class)&objs_exec_class;
    engine->objs_glyph_class     = (PCache_Class)&objs_glyph_class;

    goto Exit;

  Fail:
    FREE( face_cache );
    FREE( exec_cache );

  Exit:
    return error;
  }


/*******************************************************************
 *
 *  Function    :  TTObjs_Done
 *
 *  Description :  The TTObjs component finalizer.
 *
 *  Input  :  engine    engine instance
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  LOCAL_FUNC
  TT_Error  TTObjs_Done( PEngine_Instance  engine )
  {
    /* destroy all active faces and contexts before releasing the */
    /* caches                                                     */
    Cache_Destroy( (TCache*)engine->objs_exec_cache );
    Cache_Destroy( (TCache*)engine->objs_face_cache );

    /* Now frees caches and cache classes */
    FREE( engine->objs_exec_cache );
    FREE( engine->objs_face_cache );

    return TT_Err_Ok;
  }


/* END */


TTOBJS.H   、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttobjs.h                                                     1.0
 *
 *    Objects definition unit.
 *
 *  Copyright 1996-1999 by
 *  David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 *  This file is part of the FreeType project, and may only be used
 *  modified and distributed under the terms of the FreeType project
 *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
 *  this file you indicate that you have read the license and
 *  understand and accept it fully.
 *
 ******************************************************************/

#ifndef TTOBJS_H
#define TTOBJS_H

#include "ttconfig.h"
#include "ttengine.h"
#include "ttmutex.h"
#include "ttcache.h"
#include "tttables.h"
#include "ttcmap.h"

#ifdef __cplusplus
  extern "C" {
#endif

/*                                                                       */
/*  This file contains the definitions and methods of the four           */
/*  kinds of objects managed by the FreeType engine.  These are:         */
/*                                                                       */
/*                                                                       */
/*   Face objects:                                                       */
/*                                                                       */
/*     There is always one face object per opened TrueType font          */
/*     file, and only one.  The face object contains data that is        */
/*     independent of current transform/scaling/rotation and             */
/*     pointsize, or glyph index.  This data is made of several          */
/*     critical tables that are loaded on face object creation.          */
/*                                                                       */
/*     A face object tracks all active and recycled objects of           */
/*     the instance and execution context classes.  Destroying a face    */
/*     object will automatically destroy all associated instances.       */
/*                                                                       */
/*                                                                       */
/*   Instance objects:                                                   */
/*                                                                       */
/*     An instance object always relates to a given face object,         */
/*     known as its 'parent' or 'owner', and contains only the           */
/*     data that is specific to one given pointsize/transform of         */
/*     the face.  You can only create an instance from a face object.    */
/*                                                                       */
/*     An instance's current transform/pointsize can be changed          */
/*     at any time using a single high-level API call,                   */
/*     TT_Reset_Instance().                                              */
/*                                                                       */
/*   Execution Context objects:                                          */
/*                                                                       */
/*     An execution context (or context in short) relates to a face.     */
/*     It contains the data and tables that are necessary to load        */
/*     and hint (i.e. execute the glyph instructions of) one glyph.      */
/*     A context is a transient object that is queried/created on        */
/*     the fly: client applications never deal with them directly.       */
/*                                                                       */
/*                                                                       */
/*   Glyph objects:                                                      */
/*                                                                       */
/*     A glyph object contains only the minimal glyph information        */
/*     needed to render one glyph correctly.  This means that a glyph    */
/*     object really contains tables that are sized to hold the          */
/*     contents of _any_ glyph of a given face.  A client application    */
/*     can usually create one glyph object for a given face, then use    */
/*     it for all subsequent loads.                                      */
/*                                                                       */
/*   Here is an example of a client application :                        */
/*   (NOTE: No error checking performed here!)                           */
/*                                                                       */
/*                                                                       */
/*     TT_Face       face;         -- face handle                        */
/*     TT_Instance   ins1, ins2;   -- two instance handles               */
/*     TT_Glyph      glyph;        -- glyph handle                       */
/*                                                                       */
/*     TT_Init_FreeType();                                               */
/*                                                                       */
/*     -- Initialize the engine.  This must be done prior to _any_       */
/*        operation.                                                     */
/*                                                                       */
/*     TT_Open_Face( "/some/face/name.ttf", &face );                     */
/*                                                                       */
/*     -- create the face object.  This call opens the font file         */
/*                                                                       */
/*     TT_New_Instance( face, &ins1 );                                   */
/*     TT_New_Instance( face, &ins2 );                                   */
/*                                                                       */
/*     TT_Set_Instance_PointSize( ins1, 8 );                             */
/*     TT_Set_Instance_PointSize( ins2, 12 );                            */
/*                                                                       */
/*     -- create two distinct instances of the same face                 */
/*     -- ins1  is pointsize 8 at resolution 96 dpi                      */
/*     -- ins2  is pointsize 12 at resolution 96 dpi                     */
/*                                                                       */
/*     TT_New_Glyph( face, &glyph );                                     */
/*                                                                       */
/*     -- create a new glyph object which will receive the contents      */
/*        of any glyph of 'face'                                         */
/*                                                                       */
/*     TT_Load_Glyph( ins1, glyph, 64, DEFAULT_GLYPH_LOAD );             */
/*                                                                       */
/*     -- load glyph indexed 64 at pointsize 8 in the 'glyph' object     */
/*     -- NOTE: This call will fail if the instance and the glyph        */
/*              do not relate to the same face object.                   */
/*                                                                       */
/*     TT_Get_Outline( glyph, &outline );                                */
/*                                                                       */
/*     -- extract the glyph outline from the object and copies it        */
/*        to the 'outline' record                                        */
/*                                                                       */
/*     TT_Get_Metrics( glyph, &metrics );                                */
/*                                                                       */
/*     -- extract the glyph metrics and put them into the 'metrics'      */
/*        record                                                         */
/*                                                                       */
/*     TT_Load_Glyph( ins2, glyph, 64, DEFAULT_GLYPH_LOAD );             */
/*                                                                       */
/*     -- load the same glyph at pointsize 12 in the 'glyph' object      */
/*                                                                       */
/*                                                                       */
/*     TT_Close_Face( &face );                                           */
/*                                                                       */
/*     -- destroy the face object.  This will destroy 'ins1' and         */
/*        'ins2'.  However, the glyph object will still be available     */
/*                                                                       */
/*     TT_Done_FreeType();                                               */
/*                                                                       */
/*     -- Finalize the engine.  This will also destroy all pending       */
/*        glyph objects (here 'glyph').                                  */

  struct TFace_;
  struct TInstance_;
  struct TExecution_Context_;
  struct TGlyph_;

  typedef struct TFace_  TFace;
  typedef TFace*         PFace;

  typedef struct TInstance_  TInstance;
  typedef TInstance*         PInstance;

  typedef struct TExecution_Context_  TExecution_Context;
  typedef TExecution_Context*         PExecution_Context;

  typedef struct TGlyph_  TGlyph;
  typedef TGlyph*         PGlyph;


  /*************************************************************/
  /*                                                           */
  /*  ADDITIONAL SUBTABLES                                     */
  /*                                                           */
  /*  These tables are not precisely defined by the specs      */
  /*  but their structures is implied by the TrueType font     */
  /*  file layout.                                             */
  /*                                                           */
  /*************************************************************/

  /* Graphics State                            */
  /*                                           */
  /* The Graphics State (GS) is managed by the */
  /* instruction field, but does not come from */
  /* the font file.  Thus, we can use 'int's   */
  /* where needed.                             */

  struct  TGraphicsState_
  {
    UShort         rp0;
    UShort         rp1;
    UShort         rp2;

    TT_UnitVector  dualVector;
    TT_UnitVector  projVector;
    TT_UnitVector  freeVector;

    Long           loop;
    TT_F26Dot6     minimum_distance;
    Int            round_state;

    Bool           auto_flip;
    TT_F26Dot6     control_value_cutin;
    TT_F26Dot6     single_width_cutin;
    TT_F26Dot6     single_width_value;
    Short          delta_base;
    Short          delta_shift;

    Byte           instruct_control;
    Bool           scan_control;
    Int            scan_type;

    UShort         gep0;
    UShort         gep1;
    UShort         gep2;
  };

  typedef struct TGraphicsState_  TGraphicsState;


  LOCAL_DEF
  const TGraphicsState  Default_GraphicsState;


  /*************************************************************/
  /*                                                           */
  /*  EXECUTION SUBTABLES                                      */
  /*                                                           */
  /*  These sub-tables relate to instruction execution.        */
  /*                                                           */
  /*************************************************************/

#define MAX_CODE_RANGES   3

/* There can only be 3 active code ranges at once:   */
/*   - the Font Program                              */
/*   - the CVT Program                               */
/*   - a glyph's instructions set                    */

#define TT_CodeRange_Font  1
#define TT_CodeRange_Cvt   2
#define TT_CodeRange_Glyph 3


  struct  TCodeRange_
  {
    PByte  Base;
    ULong  Size;
  };

  typedef struct TCodeRange_  TCodeRange;
  typedef TCodeRange*         PCodeRange;


  /* Defintion of a code range                                       */
  /*                                                                 */
  /* Code ranges can be resident to a glyph (i.e. the Font Program)  */
  /* while some others are volatile (Glyph instructions).            */
  /* Tracking the state and presence of code ranges allows function  */
  /* and instruction definitions within a code range to be forgotten */
  /* when the range is discarded.                                    */

  typedef TCodeRange  TCodeRangeTable[MAX_CODE_RANGES];

  /* defines a function/instruction definition record */

  struct  TDefRecord_
  {
    Int    Range;     /* in which code range is it located ? */
    ULong  Start;     /* where does it start ?               */
    Int    Opc;       /* function #, or instruction code     */
    Bool   Active;    /* is it active ?                      */
  };

  typedef struct TDefRecord_  TDefRecord;
  typedef TDefRecord*         PDefRecord;
  typedef TDefRecord*         PDefArray;

  /* defines a call record, used to manage function calls. */

  struct  TCallRecord_
  {
    Int    Caller_Range;
    ULong  Caller_IP;
    Long   Cur_Count;
    ULong  Cur_Restart;
  };

  typedef struct TCallRecord_  TCallRecord;
  typedef TCallRecord*         PCallRecord;
  typedef TCallRecord*         PCallStack;  /* defines a simple call stack */


  /* This type defining a set of glyph points will be used to represent */
  /* each zone (regular and twilight) during instructions decoding.     */
  struct  TGlyph_Zone_
  {
    UShort        n_points;   /* number of points in zone */
    Short         n_contours; /* number of contours       */

    TT_Vector*    org;        /* original points coordinates */
    TT_Vector*    cur;        /* current points coordinates  */

    Byte*         touch;      /* current touch flags         */
    UShort*       contours;   /* contour end points          */
  };

  typedef struct TGlyph_Zone_  TGlyph_Zone;
  typedef TGlyph_Zone*         PGlyph_Zone;

#ifndef TT_STATIC_INTEPRETER  /* indirect implementation */

#define EXEC_OPS   PExecution_Context exc,
#define EXEC_OP    PExecution_Context exc
#define EXEC_ARGS  exc,
#define EXEC_ARG   exc

#else                          /* static implementation */

#define EXEC_OPS   /* void */
#define EXEC_OP    /* void */
#define EXEC_ARGS  /* void */
#define EXEC_ARG   /* void */

#endif

  /* Rounding function, as used by the interpreter */
  typedef TT_F26Dot6  (*TRound_Function)( EXEC_OPS TT_F26Dot6 distance,
                                                   TT_F26Dot6 compensation );

  /* Point displacement along the freedom vector routine, as */
  /* used by the interpreter                                 */
  typedef void  (*TMove_Function)( EXEC_OPS PGlyph_Zone  zone,
                                            UShort       point,
                                            TT_F26Dot6   distance );

  /* Distance projection along one of the proj. vectors, as used */
  /* by the interpreter                                          */
  typedef TT_F26Dot6  (*TProject_Function)( EXEC_OPS TT_Vector*  v1,
                                                     TT_Vector*  v2 );

  /* reading a cvt value. Take care of non-square pixels when needed */
  typedef TT_F26Dot6  (*TGet_CVT_Function)( EXEC_OPS ULong  index );

  /* setting or moving a cvt value.  Take care of non-square pixels  */
  /* when needed                                                     */
  typedef void  (*TSet_CVT_Function)( EXEC_OPS  ULong       index,
                                                TT_F26Dot6  value );

  /* subglyph transformation record */
  struct  TTransform_
  {
    TT_Fixed    xx, xy; /* transformation */
    TT_Fixed    yx, yy; /*     matrix     */
    TT_F26Dot6  ox, oy; /*    offsets     */
  };

  typedef struct TTransform_  TTransform;
  typedef TTransform*         PTransform;

  /* subglyph loading record.  Used to load composite components */
  struct  TSubglyph_Record_
  {
    Long         index;        /* subglyph index; initialized with -1 */
    Bool         is_scaled;    /* is the subglyph scaled?  */
    Bool         is_hinted;    /* should it be hinted?     */
    Bool         preserve_pps; /* preserve phantom points? */

    Long         file_offset;

    TT_Big_Glyph_Metrics  metrics;

    TGlyph_Zone  zone;

    Long         arg1;  /* first argument  */
    Long         arg2;  /* second argument */

    UShort       element_flag;    /* current load element flag */

    TTransform   transform;       /* transform */

    TT_Vector    pp1, pp2;        /* phantom points */

  };

  typedef struct TSubglyph_Record_  TSubglyph_Record;
  typedef TSubglyph_Record*         PSubglyph_Record;
  typedef TSubglyph_Record*         PSubglyph_Stack;

  /* A note regarding non-squared pixels:                                */
  /*                                                                     */
  /* (This text will probably go into some docs at some time, for        */
  /*  now, it is kept there to explain some definitions in the           */
  /*  TIns_Metrics record).                                              */
  /*                                                                     */
  /* The CVT is a one-dimensional array containing values that           */
  /* control certain important characteristics in a font, like           */
  /* the height of all capitals, all lowercase letter, default           */
  /* spacing or stem width/height.                                       */
  /*                                                                     */
  /* These values are found in FUnits in the font file, and must be      */
  /* scaled to pixel coordinates before being used by the CVT and        */
  /* glyph programs.  Unfortunately, when using distinct x and y         */
  /* resolutions (or distinct x and y pointsizes), there are two         */
  /* possible scalings.                                                  */
  /*                                                                     */
  /* A first try was to implement a 'lazy' scheme where all values       */
  /* were scaled when first used.  However, while some values are always */
  /* used in the same direction, and some other are used in many         */
  /* different circumstances and orientations.                           */
  /*                                                                     */
  /* I have found a simpler way to do the same, and it even seems to     */
  /* work in most of the cases:                                          */
  /*                                                                     */
  /* - all CVT values are scaled to the maximum ppem size                */
  /*                                                                     */
  /* - when performing a read or write in the CVT, a ratio factor        */
  /*   is used to perform adequate scaling. Example:                     */
  /*                                                                     */
  /*    x_ppem = 14                                                      */
  /*    y_ppem = 10                                                      */
  /*                                                                     */
  /*   we choose ppem = x_ppem = 14 as the CVT scaling size.  All cvt    */
  /*   entries are scaled to it.                                         */
  /*                                                                     */
  /*    x_ratio = 1.0                                                    */
  /*    y_ratio = y_ppem/ppem (< 1.0)                                    */
  /*                                                                     */
  /*   we compute the current ratio like:                                */
  /*                                                                     */
  /*     - if projVector is horizontal,                                  */
  /*         ratio = x_ratio = 1.0                                       */
  /*     - if projVector is vertical,                                    */
  /*         ratop = y_ratio                                             */
  /*     - else,                                                         */
  /*         ratio = sqrt((proj.x*x_ratio)^2 + (proj.y*y_ratio)^2)       */
  /*                                                                     */
  /*   reading a cvt value returns      ratio * cvt[index]               */
  /*   writing a cvt value in pixels    cvt[index] / ratio               */
  /*                                                                     */
  /*   the current ppem is simply       ratio * ppem                     */
  /*                                                                     */

  /* metrics used by the instance and execution context objects */
  struct  TIns_Metrics_
  {
    TT_F26Dot6  pointSize;      /* point size.  1 point = 1/72 inch. */

    UShort      x_resolution;   /* device horizontal resolution in dpi. */
    UShort      y_resolution;   /* device vertical resolution in dpi.   */

    UShort      x_ppem;         /* horizontal pixels per EM */
    UShort      y_ppem;         /* vertical pixels per EM   */

    Long        x_scale1;
    Long        x_scale2;    /* used to scale FUnits to fractional pixels */

    Long        y_scale1;
    Long        y_scale2;    /* used to scale FUnits to fractional pixels */

    /* for non-square pixels */
    Long        x_ratio;
    Long        y_ratio;

    UShort      ppem;        /* maximum ppem size */
    Long        ratio;       /* current ratio     */
    Long        scale1;
    Long        scale2;      /* scale for ppem */

    TT_F26Dot6  compensations[4];  /* device-specific compensations */

    Bool        rotated;        /* `is the glyph rotated?'-flag   */
    Bool        stretched;      /* `is the glyph stretched?'-flag */
  };

  typedef struct TIns_Metrics_  TIns_Metrics;
  typedef TIns_Metrics*         PIns_Metrics;

  /***********************************************************************/
  /*                                                                     */
  /*                         FreeType Face Type                          */
  /*                                                                     */
  /***********************************************************************/

  struct  TFace_
  {
    /* parent engine instance for the face object */
    PEngine_Instance  engine;

    /* i/o stream */
    TT_Stream  stream;

    /* used only by the threaded builds of the library */
    TMutex  lock;

    /* TrueType collection header, if any was found */
    TTTCHeader  ttcHeader;

    /* maximum profile table, as found in the TrueType file */
    TMaxProfile  maxProfile;

    /* Note:                                          */
    /*  it seems that some maximum values cannot be   */
    /*  taken directly from this table, but rather by */
    /*  combining some of its fields; e.g. the max.   */
    /*  number of points seems to be given by         */
    /*  MAX( maxPoints, maxCompositePoints )          */
    /*                                                */
    /*  For this reason, we define later our own      */
    /*  max values that are used to load and allocate */
    /*  further tables.                               */

    TT_Header             fontHeader;           /* the font header, as   */
                                                /* found in the TTF file */
    TT_Horizontal_Header  horizontalHeader;     /* the horizontal header */

    Bool                  verticalInfo;         /* True when vertical table */
    TT_Vertical_Header    verticalHeader;       /* is present in the font   */

    TT_OS2                os2;                  /* 'OS/2' table */

    TT_Postscript         postscript;           /* 'Post' table */

    TT_Hdmx               hdmx;                 /* 'Hdmx' table */

    TName_Table           nameTable;            /* name table */

    TGasp                 gasp;                 /* the 'gasp' table */

    /* The directory of TrueType tables for this typeface */
    UShort          numTables;
    PTableDirEntry  dirTables;

    /* The directory of character mappings table for */
    /* this typeface                                 */
    UShort      numCMaps;
    PCMapTable  cMaps;

    /* The glyph locations table */
    ULong     numLocations;         /* UShort is not enough */
#ifndef TT_HUGE_PTR
    PStorage  glyphLocations;
#else
    Storage TT_HUGE_PTR * glyphLocations;
#endif

    /* NOTE : The "hmtx" is now part of the horizontal header */

    /* the font program, if any */
    ULong   fontPgmSize;
    PByte   fontProgram;

    /* the cvt program, if any */
    ULong   cvtPgmSize;
    PByte   cvtProgram;

    /* the original, unscaled, control value table */
    ULong   cvtSize;
    PShort  cvt;

    /* The following values _must_ be set by the */
    /* maximum profile loader                    */

    UShort  numGlyphs;     /* the face's total number of glyphs */
    UShort  maxPoints;     /* max glyph points number, simple and composite */
    UShort  maxContours;   /* max glyph contours numb, simple and composite */
    UShort  maxComponents; /* max components in a composite glyph */

    /* the following are object caches to track active */
    /* and recycled instances and execution contexts   */
    /* objects.  See 'ttcache.h'                       */

    TCache  instances;   /* current instances for this face */
    TCache  glyphs;      /* current glyph containers for this face */


    /* A typeless pointer to the face object extensions defined */
    /* in the 'ttextend.*' files.                               */
    void*  extension;
    Int    n_extensions;    /* number of extensions */

    /* Use extensions to provide additional capabilities to the */
    /* engine.  Read the developer's guide in the documentation */
    /* directory to know how to do that.                        */

    /* a generic pointer for client use - see TT_Set/Get_Face_Pointer */
    void*  generic;
  };

  /***********************************************************************/
  /*                                                                     */
  /*                       FreeType Instance Type                        */
  /*                                                                     */
  /***********************************************************************/

  struct  TInstance_
  {
    PFace            owner;     /* face object */

    Bool             valid;

    TIns_Metrics     metrics;

    UShort           numFDefs;  /* number of function definitions */
    UShort           maxFDefs;
    PDefArray        FDefs;     /* table of FDefs entries         */

    UShort           numIDefs;  /* number of instruction definitions */
    UShort           maxIDefs;
    PDefArray        IDefs;     /* table of IDefs entries            */

    Int              maxFunc;   /* maximum function definition id    */
    Int              maxIns;    /* maximum instruction definition id */

    TCodeRangeTable  codeRangeTable;

    TGraphicsState   GS;
    TGraphicsState   default_GS;

    ULong            cvtSize;   /* the scaled control value table */
    PLong            cvt;

    ULong            storeSize; /* The storage area is now part of the */
    PLong            storage;   /* instance                            */

    TGlyph_Zone      twilight;  /* The instance's twilight zone */

    /* debugging variables */

    /* When using the debugger, we must keep the */
    /* execution context tied to the instance    */
    /* object rather than asking it on demand    */

    Bool                debug;
    PExecution_Context  context;

    /* a generic pointer for client use - see TT_Set/Get_Instance_Pointer */
    void*            generic;
  };


  /***********************************************************************/
  /*                                                                     */
  /*                  FreeType Execution Context Type                    */
  /*                                                                     */
  /***********************************************************************/

  struct  TExecution_Context_
  {
    PFace           face;
    PInstance       instance;

    /* instructions state */

    TT_Error        error;     /* last execution error */

    Long            top;        /* top of exec. stack  */

    ULong           stackSize;  /* size of exec. stack */
    PStorage        stack;      /* current exec. stack */

    Long            args;
    ULong           new_top;    /* new top after exec.    */

    TGlyph_Zone     zp0,            /* zone records */
                    zp1,
                    zp2,
                    pts,
                    twilight;

    TIns_Metrics    metrics;       /* instance metrics */

    TGraphicsState  GS;            /* current graphics state */

    Int             curRange;  /* current code range number   */
    PByte           code;      /* current code range          */
    ULong           IP;        /* current instruction pointer */
    ULong           codeSize;  /* size of current range       */

    Byte            opcode;    /* current opcode              */
    Int             length;    /* length of current opcode    */

    Bool            step_ins;  /* true if the interpreter must */
                               /* increment IP after ins. exec */
    ULong           cvtSize;
    PLong           cvt;

    ULong           glyphSize; /* glyph instructions buffer size */
    PByte           glyphIns;  /* glyph instructions buffer */

    UShort          numFDefs;  /* number of function defs         */
    UShort          maxFDefs;  /* maximum number of function defs */
    PDefRecord      FDefs;     /* table of FDefs entries          */

    UShort          numIDefs;  /* number of instruction defs         */
    UShort          maxIDefs;  /* maximum number of instruction defs */
    PDefRecord      IDefs;     /* table of IDefs entries             */

    Int             maxFunc;
    Int             maxIns;

    Int             callTop,    /* top of call stack during execution */
                    callSize;   /* size of call stack */
    PCallStack      callStack;  /* call stack */

    UShort          maxPoints;    /* capacity of this context's "pts" */
    UShort          maxContours;  /* record, expressed in points and  */
                                  /* contours..                       */

    TCodeRangeTable codeRangeTable;  /* table of valid coderanges */
                                     /* useful for the debugger   */

    ULong           storeSize;  /* size of current storage */
    PLong           storage;    /* storage area            */

    TT_F26Dot6      period;     /* values used for the */
    TT_F26Dot6      phase;      /* 'SuperRounding'     */
    TT_F26Dot6      threshold;

    /* this seems to be unused */
#if 0
    Int             cur_ppem;       /* ppem along the current proj vector */
#endif
    Long            scale1;         /* scaling values along the current   */
    Long            scale2;         /* projection vector too..            */
    Bool            cached_metrics; /* the ppem is computed lazily. used  */
                                    /* to trigger computation when needed */

    Bool            instruction_trap;  /* If True, the interpreter will */
                                       /* exit after each instruction   */

    TGraphicsState  default_GS;    /* graphics state resulting from  */
                                   /* the prep program               */
    Bool            is_composite;  /* ture if the glyph is composite */

    Bool            pedantic_hinting;  /* if true, read and write array   */
                                       /* bounds faults halt the hinting  */

    /* latest interpreter additions */

    Long               F_dot_P;    /* dot product of freedom and projection */
                                   /* vectors                               */
    TRound_Function    func_round; /* current rounding function             */

    TProject_Function  func_project,   /* current projection function */
                       func_dualproj,  /* current dual proj. function */
                       func_freeProj;  /* current freedom proj. func  */

    TMove_Function     func_move;      /* current point move function */

    TGet_CVT_Function  func_read_cvt;  /* read a cvt entry              */
    TSet_CVT_Function  func_write_cvt; /* write a cvt entry (in pixels) */
    TSet_CVT_Function  func_move_cvt;  /* incr a cvt entry (in pixels)  */

    ULong              loadSize;
    PSubglyph_Stack    loadStack;      /* loading subglyph stack */

  };


  /***********************************************************************/
  /*                                                                     */
  /*                  FreeType Glyph Object Type                         */
  /*                                                                     */
  /***********************************************************************/

  struct TGlyph_
  {
    PFace                 face;
    TT_Big_Glyph_Metrics  metrics;
    TT_Outline            outline;
  };


  /* The following type is used to load a font from a collection. */
  /* See Face_Create in ttobjs.c                                  */

  struct  TFont_Input_
  {
    TT_Stream         stream;     /* input stream                */
    ULong             fontIndex;  /* index of font in collection */
    PEngine_Instance  engine;     /* parent engine instance      */

  };

  typedef struct TFont_Input_  TFont_Input;


  /********************************************************************/
  /*                                                                  */
  /*   Code Range Functions                                           */
  /*                                                                  */
  /********************************************************************/

  /* Goto a specified coderange */
  LOCAL_DEF
  TT_Error  Goto_CodeRange( PExecution_Context  exec,
                            Int                 range,
                            ULong               IP );

#if 0
  /* Return a pointer to a given coderange record. */
  /* Used only by the debugger.                    */
  LOCAL_DEF
  PCodeRange  Get_CodeRange( PExecution_Context  exec,
                             Int                 range );
#endif

  /* Set a given code range properties */
  LOCAL_DEF
  TT_Error  Set_CodeRange( PExecution_Context  exec,
                           Int                 range,
                           void*               base,
                           ULong               length );

  /* Clear a given coderange */
  LOCAL_DEF
  TT_Error  Clear_CodeRange( PExecution_Context  exec, Int  range );


  LOCAL_DEF
  PExecution_Context  New_Context( PFace  face );

  LOCAL_DEF
  TT_Error  Done_Context( PExecution_Context  exec );


  LOCAL_DEF
  TT_Error  Context_Load( PExecution_Context  exec,
                          PFace               face,
                          PInstance           ins );

  LOCAL_DEF
  TT_Error  Context_Save( PExecution_Context  exec,
                          PInstance           ins );

  LOCAL_DEF
  TT_Error  Context_Run( PExecution_Context  exec,
                         Bool                debug );

  LOCAL_DEF
  TT_Error  Instance_Init( PInstance  ins );

  LOCAL_DEF
  TT_Error  Instance_Reset( PInstance  ins );


  /********************************************************************/
  /*                                                                  */
  /*   Handy scaling functions                                        */
  /*                                                                  */
  /********************************************************************/

  LOCAL_DEF TT_Pos   Scale_X( PIns_Metrics  metrics, TT_Pos  x );
  LOCAL_DEF TT_Pos   Scale_Y( PIns_Metrics  metrics, TT_Pos  y );

  /********************************************************************/
  /*                                                                  */
  /*   Component Initializer/Finalizer                                */
  /*                                                                  */
  /*   Called from 'freetype.c'                                       */
  /*   The component must create and register the face, instance and  */
  /*   execution context cache classes before any object can be       */
  /*   managed.                                                       */
  /*                                                                  */
  /********************************************************************/

  LOCAL_DEF TT_Error  TTObjs_Init( PEngine_Instance  engine );
  LOCAL_DEF TT_Error  TTObjs_Done( PEngine_Instance  engine );

#ifdef __cplusplus
  }
#endif

#endif /* TTOBJS_H */


/* END */


TTRASTER.C    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttraster.c                                                  1.5
 *
 *  The FreeType glyph rasterizer (body).
 *
 *  Copyright 1996-1999 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.
 *
 *  NOTES:
 *
 *  This version supports the following:
 *
 *    - direct grayscaling
 *    - sub-banding
 *    - drop-out modes 4 and 5
 *    - second pass for complete drop-out control (bitmap only)
 *    - variable precision
 *
 *   Changes between 1.5 and 1.4:
 *
 *     Performance tuning.
 *
 *   Changes between 1.4 and 1.3:
 *
 *   Mainly performance tunings:
 *
 *   - Line_Down() and Bezier_Down() now use the functions Line_Up()
 *     and Bezier_Up() to do their work.
 *   - optimized Split_Bezier()
 *   - optimized linked lists used during sweeps
 *
 ******************************************************************/

#include "ttraster.h"
#include "ttdebug.h"
#include "tttypes.h"
#include "ttengine.h"
#include "ttcalc.h"      /* for TT_MulDiv only */

#include "ttmemory.h"    /* only used to allocate memory on engine init */

/* required by the tracing mode */
#undef  TT_COMPONENT
#define TT_COMPONENT      trace_raster


/* The default render pool size */
#define  RASTER_RENDER_POOL   64000

/* The size of the two-lines intermediate bitmap used */
/* for anti-aliasing                                  */
#define  RASTER_GRAY_LINES    2048


#define Raster_Err_None              TT_Err_Ok
#define Raster_Err_Not_Ini           TT_Err_Raster_Not_Initialized
#define Raster_Err_Overflow          TT_Err_Raster_Pool_Overflow
#define Raster_Err_Neg_Height        TT_Err_Raster_Negative_Height
#define Raster_Err_Invalid           TT_Err_Raster_Invalid_Value
#define Raster_Err_Gray_Unsupported  TT_Err_Raster_Gray_Unsupported


/* FMulDiv means "Fast MulDiv", it is uses in case where 'b' is typically */
/* a small value and the result of (a*b) is known to fit in 32 bits.      */
#define FMulDiv( a, b, c )  ( (a) * (b) / (c) )

/* On the other hand, SMulDiv is for "Slow MulDiv", and is used typically */
/* for clipping computations.  It simply uses the TT_MulDiv() function    */
/* defined in "ttcalc.h"                                                  */
/*                                                                        */
/* So, the following definition fits the bill nicely, and we don't need   */
/* to use the one in 'ttcalc' anymore, even for 16-bit systems...         */
#define SMulDiv   TT_MulDiv


/* Define DEBUG_RASTER if you want to generate a debug version of the  */
/* rasterizer.  This will progressively draw the glyphs while all the  */
/* computation are done directly on the graphics screen (the glyphs    */
/* will be inverted).                                                  */

/* Note that DEBUG_RASTER should only be used for debugging with b/w   */
/* rendering, not with gray levels.                                    */

/* The definition of DEBUG_RASTER should appear in the file            */
/* "ttconfig.h".                                                       */

#ifdef DEBUG_RASTER
  extern Char*  Vio;  /* A pointer to VRAM or display buffer */
#endif


/* The rasterizer is a very general purpose component, please leave */
/* the following redefinitions there (you never know your target    */
/* environment).                                                    */

#ifndef TRUE
#define TRUE   1
#endif

#ifndef FALSE
#define FALSE  0
#endif

#ifndef NULL
#define NULL  (void*)0
#endif

#define MaxBezier  32   /* The maximum number of stacked Bezier curves. */
                        /* Setting this constant to more than 32 is a   */
                        /* pure waste of space.                         */

#define Pixel_Bits  6   /* fractional bits of *input* coordinates */

  /* States of each line, arc and profile */
  enum  TStates_
  {
    Unknown,
    Ascending,
    Descending,
    Flat
  };

  typedef enum TStates_  TStates;

  struct  TProfile_;
  typedef struct TProfile_  TProfile;
  typedef TProfile*         PProfile;

  struct  TProfile_
  {
    TT_F26Dot6  X;           /* current coordinate during sweep          */
    PProfile    link;        /* link to next profile - various purpose   */
    PStorage    offset;      /* start of profile's data in render pool   */
    Int         flow;        /* Profile orientation: Asc/Descending      */
    Long        height;      /* profile's height in scanlines            */
    Long        start;       /* profile's starting scanline              */

    UShort      countL;      /* number of lines to step before this      */
                             /* profile becomes drawable                 */

    PProfile    next;        /* next profile in same contour, used       */
                             /* during drop-out control                  */
  };

  typedef PProfile   TProfileList;
  typedef PProfile*  PProfileList;


  /* I use the classic trick of two dummy records for the head and tail  */
  /* of a linked list; this reduces tests in insertion/deletion/sorting. */
  /* NOTE: used during sweeps only.                                      */

  /* Simple record used to implement a stack of bands, required */
  /* by the sub-banding mechanism                               */

  struct  TBand_
  {
    Short  y_min;   /* band's minimum */
    Short  y_max;   /* band's maximum */
  };

  typedef struct TBand_  TBand;


#define AlignProfileSize \
          (( sizeof(TProfile)+sizeof(long)-1 ) / sizeof(long))


  /* Left fill bitmask */
  static const Byte  LMask[8] =
    { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };

  /* Right fill bitmask */
  static const Byte  RMask[8] =
    { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };

  /* prototypes used for sweep function dispatch */
  typedef void  Function_Sweep_Init( RAS_ARGS Short*  min,
                                              Short*  max );

  typedef void  Function_Sweep_Span( RAS_ARGS Short       y,
                                              TT_F26Dot6  x1,
                                              TT_F26Dot6  x2,
                                              PProfile    left,
                                              PProfile    right );

  typedef void  Function_Sweep_Step( RAS_ARG );


/* NOTE: These operations are only valid on 2's complement processors */

#define FLOOR( x )    ( (x) & -ras.precision )
#define CEILING( x )  ( ((x) + ras.precision - 1) & -ras.precision )
#define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
#define FRAC( x )     ( (x) & (ras.precision - 1) )
#define SCALED( x )   ( ((x) << ras.scale_shift) - ras.precision_half )

#ifdef DEBUG_RASTER
#define DEBUG_PSET  Pset()
#else
#define DEBUG_PSET
#endif

  struct  TPoint_
  {
    Long  x, y;
  };

  typedef struct TPoint_  TPoint;


  /* Note that I have moved the location of some fields in the */
  /* structure to ensure that the most used variables are used */
  /* at the top.  Thus, their offset can be coded with less    */
  /* opcodes, and it results in a smaller executable.          */

  struct  TRaster_Instance_
  {
    Int       precision_bits;       /* precision related variables */
    Int       precision;
    Int       precision_half;
    Long      precision_mask;
    Int       precision_shift;
    Int       precision_step;
    Int       precision_jitter;

    Int       scale_shift;        /* == precision_shift   for bitmaps */
                                  /* == precision_shift+1 for pixmaps */

    PStorage  buff;                 /* The profiles buffer          */
    PStorage  sizeBuff;             /* Render pool size             */
    PStorage  maxBuff;              /* Profiles buffer size         */
    PStorage  top;                  /* Current cursor in buffer     */

    TT_Error  error;

    PByte     flags;                /* current flags table    */
    PUShort   outs;                 /* current outlines table */

    UShort    nPoints;              /* number of points in current glyph   */
    Short     nContours;            /* number of contours in current glyph */
    Int       numTurns;             /* number of Y-turns in outline        */

    TPoint*   arc;                  /* current Bezier arc pointer */

    UShort    bWidth;               /* target bitmap width  */
    PByte     bTarget;              /* target bitmap buffer */
    PByte     gTarget;              /* target pixmap buffer */

    Long      lastX, lastY, minY, maxY;

    UShort    num_Profs;            /* current number of profiles */

    Bool      fresh;                /* signals a fresh new profile which */
                                    /* 'start' field must be completed   */
    Bool      joint;                /* signals that the last arc ended   */
                                    /* exactly on a scanline.  Allows    */
                                    /* removal of doublets               */
    PProfile  cProfile;             /* current profile                   */
    PProfile  fProfile;             /* head of linked list of profiles   */
    PProfile  gProfile;             /* contour's first profile in case   */
                                    /* of impact                         */
    TStates   state;                /* rendering state */

    TT_Raster_Map  target;          /* description of target bit/pixmap */

    Long      traceOfs;             /* current offset in target bitmap */
    Long      traceG;               /* current offset in target pixmap */

    Short     traceIncr;            /* sweep's increment in target bitmap */

    Short     gray_min_x;           /* current min x during gray rendering */
    Short     gray_max_x;           /* current max x during gray rendering */

    /* dispatch variables */

    Function_Sweep_Init*  Proc_Sweep_Init;
    Function_Sweep_Span*  Proc_Sweep_Span;
    Function_Sweep_Span*  Proc_Sweep_Drop;
    Function_Sweep_Step*  Proc_Sweep_Step;

    TT_Vector*  coords;

    Byte      dropOutControl;       /* current drop_out control method */

    Byte      grays[5];         /* Palette of gray levels used for render */

    Byte*     gray_lines;       /* Intermediate table used to render the   */
                                /* graylevels pixmaps.                     */
                                /* gray_lines is a buffer holding two      */
                                /* monochrome scanlines                    */
    Short     gray_width;       /* width in bytes of one monochrome        */
                                /* intermediate scanline of gray_lines.    */
                                /* Each gray pixel takes 2 bits long there */

                        /* The gray_lines must hold 2 lines, thus with size */
                        /* in bytes of at least 'gray_width*2'              */

    Bool      second_pass;      /* indicates wether a horizontal pass      */
                                /* should be performed to control drop-out */
                                /* accurately when calling Render_Glyph.   */
                                /* Note that there is no horizontal pass   */
                                /* during gray rendering.                  */
    TPoint    arcs[2 * MaxBezier + 1];      /* The Bezier stack */

    TBand     band_stack[16];       /* band stack used for sub-banding */
    Int       band_top;             /* band stack top                  */

    Int       count_table[256];     /* Look-up table used to quickly count */
                                    /* set bits in a gray 2x2 cell         */
  };


#ifdef TT_CONFIG_OPTION_STATIC_RASTER

  static TRaster_Instance  cur_ras;
#define ras  cur_ras

#else

#define ras  (*raster)

#endif /* TT_STATIC_RASTER */


#ifdef DEBUG_RASTER

  /************************************************/
  /*                                              */
  /* Pset:                                        */
  /*                                              */
  /*  Used for debugging only.  Plots a point     */
  /*  in VRAM during rendering (not afterwards).  */
  /*                                              */
  /* NOTE:  This procedure relies on the value    */
  /*        of cProfile->start, which may not     */
  /*        be set when Pset is called sometimes. */
  /*        This will usually result in a dot     */
  /*        plotted on the first screen scanline  */
  /*        (far away its original position).     */
  /*                                              */
  /*        This "bug" reflects nothing wrong     */
  /*        in the current implementation, and    */
  /*        the bitmap is rendered correctly,     */
  /*        so don't panic if you see 'flying'    */
  /*        dots in debugging mode.               */
  /*                                              */
  /*  - David                                     */
  /*                                              */
  /************************************************/

  static void  Pset( RAS_ARG )
  {
    Long  o;
    Long  x;


    x = ras.top[-1];

    switch ( ras.cProfile->flow )
    {
    case TT_Flow_Up:
      o = Vio_ScanLineWidth *
         ( ras.top-ras.cProfile->offset + ras.cProfile->start ) +
         ( x / (ras.precision*8) );
      break;

    case TT_Flow_Down:
      o = Vio_ScanLineWidth *
         ( ras.cProfile->start-ras.top + ras.cProfile->offset ) +
         ( x / (ras.precision*8) );
      break;
    }

    if ( o > 0 )
      Vio[o] |= (unsigned)0x80 >> ( (x/ras.precision) & 7 );
  }


  static void  Clear_Band( RAS_ARGS Int  y1, Int  y2 )
  {
    MEM_Set( Vio + y1*Vio_ScanLineWidth, (y2-y1+1)*Vio_ScanLineWidth, 0 );
  }

#endif /* DEBUG_RASTER */


/************************************************************************/
/*                                                                      */
/* Function:    Set_High_Precision                                      */
/*                                                                      */
/* Description: Sets precision variables according to param flag.       */
/*                                                                      */
/* Input:       High     set to True for high precision (typically for  */
/*                       ppem < 18), false otherwise.                   */
/*                                                                      */
/************************************************************************/

  static void  Set_High_Precision( RAS_ARGS Bool  High )
  {
    if ( High )
    {
      ras.precision_bits   = 10;
      ras.precision_step   = 128;
      ras.precision_jitter = 24;
    }
    else
    {
      ras.precision_bits   = 6;
      ras.precision_step   = 32;
      ras.precision_jitter = 2;
    }

    PTRACE7(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));

    ras.precision       = 1 << ras.precision_bits;
    ras.precision_half  = ras.precision / 2;
    ras.precision_shift = ras.precision_bits - Pixel_Bits;
    ras.precision_mask  = -ras.precision;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    New_Profile                                                 */
/*                                                                          */
/* Description: Creates a new Profile in the render pool.                   */
/*                                                                          */
/* Input:       aState   state/orientation of the new Profile               */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE in case of overflow or of incoherent Profile.       */
/*                                                                          */
/****************************************************************************/

  static Bool  New_Profile( RAS_ARGS TStates  aState )
  {
    if ( !ras.fProfile )
    {
      ras.cProfile  = (PProfile)ras.top;
      ras.fProfile  = ras.cProfile;
      ras.top      += AlignProfileSize;
    }

    if ( ras.top >= ras.maxBuff )
    {
      ras.error = Raster_Err_Overflow;
      return FAILURE;
    }

    switch ( aState )
    {
    case Ascending:
      ras.cProfile->flow = TT_Flow_Up;
      PTRACE7(( "New ascending profile = %lx\n", (long)ras.cProfile ));
      break;

    case Descending:
      ras.cProfile->flow = TT_Flow_Down;
      PTRACE7(( "New descending profile = %lx\n", (long)ras.cProfile ));
      break;

    default:
      PTRACE0(( "Invalid profile direction in Raster:New_Profile !!\n" ));
      ras.error = Raster_Err_Invalid;
      return FAILURE;
    }

    ras.cProfile->start  = 0;
    ras.cProfile->height = 0;
    ras.cProfile->offset = ras.top;
    ras.cProfile->link   = (PProfile)0;
    ras.cProfile->next   = (PProfile)0;

    if ( !ras.gProfile )
      ras.gProfile = ras.cProfile;

    ras.state = aState;
    ras.fresh = TRUE;
    ras.joint = FALSE;

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    End_Profile                                                 */
/*                                                                          */
/* Description: Finalizes the current Profile.                              */
/*                                                                          */
/* Input:       None                                                        */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE in case of overflow or incoherency.                 */
/*                                                                          */
/****************************************************************************/

  static Bool  End_Profile( RAS_ARG )
  {
    Long      h;
    PProfile  oldProfile;


    h = ras.top - ras.cProfile->offset;

    if ( h < 0 )
    {
      PTRACE0(( "Negative height encountered in End_Profile!\n" ));
      ras.error = Raster_Err_Neg_Height;
      return FAILURE;
    }

    if ( h > 0 )
    {
      PTRACE1(( "Ending profile %lx, start = %ld, height = %ld\n",
                (long)ras.cProfile, ras.cProfile->start, h ));

      oldProfile           = ras.cProfile;
      ras.cProfile->height = h;
      ras.cProfile         = (PProfile)ras.top;

      ras.top             += AlignProfileSize;

      ras.cProfile->height = 0;
      ras.cProfile->offset = ras.top;
      oldProfile->next     = ras.cProfile;
      ras.num_Profs++;
    }

    if ( ras.top >= ras.maxBuff )
    {
      PTRACE1(( "overflow in End_Profile\n" ));
      ras.error = Raster_Err_Overflow;
      return FAILURE;
    }

    ras.joint = FALSE;

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Insert_Y_Turn                                               */
/*                                                                          */
/* Description: Insert a salient into the sorted list placed on top         */
/*              of the render pool                                          */
/*                                                                          */
/* Input:       New y scanline position                                     */
/*                                                                          */
/****************************************************************************/

  static
  Bool Insert_Y_Turn( RAS_ARGS  Int  y )
  {
    PStorage  y_turns;
    Int       y2, n;

    n       = ras.numTurns-1;
    y_turns = ras.sizeBuff - ras.numTurns;

    /* look for first y value that is <= */
    while ( n >= 0 && y < y_turns[n] )
      n--;

    /* if it is <, simply insert it, ignore if == */
    if ( n >= 0 && y > y_turns[n] )
      while ( n >= 0 )
      {
        y2 = y_turns[n];
        y_turns[n] = y;
        y = y2;
        n--;
      }

    if ( n < 0 )
    {
      if (ras.maxBuff <= ras.top)
      {
        ras.error = Raster_Err_Overflow;
        return FAILURE;
      }
      ras.maxBuff--;
      ras.numTurns++;
      ras.sizeBuff[-ras.numTurns] = y;
    }

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Finalize_Profile_Table                                      */
/*                                                                          */
/* Description: Adjusts all links in the Profiles list.                     */
/*                                                                          */
/* Input:       None                                                        */
/*                                                                          */
/* Returns:     None.                                                       */
/*                                                                          */
/****************************************************************************/

  static
  Bool Finalize_Profile_Table( RAS_ARG )
  {
    Int       bottom, top;
    UShort    n;
    PProfile  p;


    n = ras.num_Profs;

    if ( n > 1 )
    {
      p = ras.fProfile;
      while ( n > 0 )
      {
        if ( n > 1 )
          p->link = (PProfile)( p->offset + p->height );
        else
          p->link = NULL;

        switch ( p->flow )
        {
        case TT_Flow_Down:
          bottom     = p->start - p->height+1;
          top        = p->start;
          p->start   = bottom;
          p->offset += p->height-1;
          break;

        case TT_Flow_Up:
        default:
          bottom = p->start;
          top    = p->start + p->height-1;
        }

        if ( Insert_Y_Turn( RAS_VARS  bottom ) ||
             Insert_Y_Turn( RAS_VARS  top+1 )  )
          return FAILURE;

        p = p->link;
        n--;
      }
    }
    else
      ras.fProfile = NULL;

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Split_Bezier                                                */
/*                                                                          */
/* Description: Subdivides one Bezier arc into two joint                    */
/*              sub-arcs in the Bezier stack.                               */
/*                                                                          */
/* Input:       None (subdivided bezier is taken from the top of the        */
/*              stack).                                                     */
/*                                                                          */
/* Returns:     None.                                                       */
/*                                                                          */
/*                                                                          */
/* Note:  This routine is the 'beef' of this component. It is  _the_        */
/*        inner loop that should be optimized to hell to get the            */
/*        best performance.                                                 */
/*                                                                          */
/****************************************************************************/

  static void  Split_Bezier( TPoint*  base )
  {
    Long     a, b;


    base[4].x = base[2].x;
    b = base[1].x;
    a = base[3].x = ( base[2].x + b ) / 2;
    b = base[1].x = ( base[0].x + b ) / 2;
    base[2].x = ( a + b ) / 2;

    base[4].y = base[2].y;
    b = base[1].y;
    a = base[3].y = ( base[2].y + b ) / 2;
    b = base[1].y = ( base[0].y + b ) / 2;
    base[2].y = ( a + b ) / 2;

    /* hand optimized.  gcc doesn't seem too good at common expression */
    /* substitution and instruction scheduling ;-)                     */
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Push_Bezier                                                 */
/*                                                                          */
/* Description: Clears the Bezier stack and pushes a new arc on top of it.  */
/*                                                                          */
/* Input:       x1,y1 x2,y2 x3,y3  new Bezier arc                           */
/*                                                                          */
/* Returns:     None.                                                       */
/*                                                                          */
/****************************************************************************/

  static void  Push_Bezier( RAS_ARGS Long  x1, Long  y1,
                                     Long  x2, Long  y2,
                                     Long  x3, Long  y3 )
  {
    ras.arc      = ras.arcs;
    ras.arc[2].x = x1; ras.arc[2].y = y1;
    ras.arc[1].x = x2; ras.arc[1].y = y2;
    ras.arc[0].x = x3; ras.arc[0].y = y3;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Line_Up                                                     */
/*                                                                          */
/* Description: Computes the x-coordinates of an ascending line segment     */
/*              and stores them in the render pool.                         */
/*                                                                          */
/* Input:       x1,y1,x2,y2  Segment start (x1,y1) and end (x2,y2) points   */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE on Render Pool overflow.                            */
/*                                                                          */
/****************************************************************************/

  static Bool  Line_Up( RAS_ARGS Long  x1, Long  y1,
                                 Long  x2, Long  y2,
                                 Long  miny, Long  maxy )
  {
    Long  Dx, Dy;
    Int   e1, e2, f1, f2, size;     /* XXX: is `Short' sufficient? */
    Long  Ix, Rx, Ax;

    PStorage  top;


    Dx = x2 - x1;
    Dy = y2 - y1;

    if ( Dy <= 0 || y2 < miny || y1 > maxy )
      return SUCCESS_OK;

    if ( y1 < miny )
    {
      /* Take care : miny-y1 can be a very large value, we use     */
      /*             a slow MulDiv function to avoid clipping bugs */
      x1 += SMulDiv( Dx, miny - y1, Dy );
      e1  = TRUNC( miny );
      f1  = 0;
    }
    else
    {
      e1 = TRUNC( y1 );
      f1 = FRAC( y1 );
    }

    if ( y2 > maxy )
    {
      /* x2 += FMulDiv( Dx, maxy - y2, Dy );  UNNECESSARY */
      e2  = TRUNC( maxy );
      f2  = 0;
    }
    else
    {
      e2 = TRUNC( y2 );
      f2 = FRAC( y2 );
    }

    if ( f1 > 0 )
    {
      if ( e1 == e2 ) return SUCCESS_OK;
      else
      {
        x1 += FMulDiv( Dx, ras.precision - f1, Dy );
        e1 += 1;
      }
    }
    else
      if ( ras.joint )
      {
        ras.top--;
        ras.joint = FALSE;
      }

    ras.joint = ( f2 == 0 );

    if ( ras.fresh )
    {
      ras.cProfile->start = e1;
      ras.fresh           = FALSE;
    }

    size = e2 - e1 + 1;
    if ( ras.top + size >= ras.maxBuff )
    {
      ras.error = Raster_Err_Overflow;
      return FAILURE;
    }

    if ( Dx > 0 )
    {
      Ix = (ras.precision*Dx) / Dy;
      Rx = (ras.precision*Dx) % Dy;
      Dx = 1;
    }
    else
    {
      Ix = -( (ras.precision*-Dx) / Dy );
      Rx =    (ras.precision*-Dx) % Dy;
      Dx = -1;
    }

    Ax  = -Dy;
    top = ras.top;

    while ( size > 0 )
    {
      *top++ = x1;

      DEBUG_PSET;

      x1 += Ix;
      Ax += Rx;
      if ( Ax >= 0 )
      {
        Ax -= Dy;
        x1 += Dx;
      }
      size--;
    }

    ras.top = top;
    return SUCCESS_OK;
  }


  static Bool  Line_Down( RAS_ARGS Long  x1, Long  y1,
                                   Long  x2, Long  y2,
                                   Long  miny, Long  maxy )
  {
    Bool result, fresh;


    fresh  = ras.fresh;

    result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );

    if ( fresh && !ras.fresh )
      ras.cProfile->start = -ras.cProfile->start;

    return result;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Bezier_Up                                                   */
/*                                                                          */
/* Description: Computes thes x-coordinates of an ascending bezier arc      */
/*              and stores them in the render pool.                         */
/*                                                                          */
/* Input:       None.  The arc is taken from the top of the Bezier stack.   */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE on Render Pool overflow.                            */
/*                                                                          */
/****************************************************************************/

  static Bool  Bezier_Up( RAS_ARGS Long  miny, Long  maxy )
  {
    Long   y1, y2, e, e2, e0;
    Short  f1;

    TPoint*  arc;
    TPoint*  start_arc;

    PStorage top;


    arc = ras.arc;
    y1  = arc[2].y;
    y2  = arc[0].y;
    top = ras.top;

    if ( y2 < miny || y1 > maxy )
      goto Fin;

    e2 = FLOOR( y2 );

    if ( e2 > maxy )
      e2 = maxy;

    e0 = miny;

    if ( y1 < miny )
      e = miny;
    else
    {
      e  = CEILING( y1 );
      f1 = FRAC( y1 );
      e0 = e;

      if ( f1 == 0 )
      {
        if ( ras.joint )
        {
          top--;
          ras.joint = FALSE;
        }

        *top++ = arc[2].x;

        DEBUG_PSET;

        e += ras.precision;
      }
    }

    if ( ras.fresh )
    {
      ras.cProfile->start = TRUNC( e0 );
      ras.fresh = FALSE;
    }

    if ( e2 < e )
      goto Fin;

    if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
    {
      ras.top   = top;
      ras.error = Raster_Err_Overflow;
      return FAILURE;
    }

    start_arc = arc;

    while ( arc >= start_arc && e <= e2 )
    {
      ras.joint = FALSE;

      y2 = arc[0].y;

      if ( y2 > e )
      {
        y1 = arc[2].y;
        if ( y2 - y1 >= ras.precision_step )
        {
          Split_Bezier( arc );
          arc += 2;
        }
        else
        {
          *top++ = arc[2].x + FMulDiv( arc[0].x - arc[2].x,
                                       e - y1,
                                       y2 - y1 );
          DEBUG_PSET;

          arc -= 2;
          e   += ras.precision;
        }
      }
      else
      {
        if ( y2 == e )
        {
          ras.joint  = TRUE;
          *top++     = arc[0].x;

          DEBUG_PSET;

          e += ras.precision;
        }
        arc -= 2;
      }
    }

  Fin:
    ras.top  = top;
    ras.arc -= 2;
    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Bezier_Down                                                 */
/*                                                                          */
/* Description: Computes the x-coordinates of a descending bezier arc       */
/*              and stores them in the render pool.                         */
/*                                                                          */
/* Input:       None.  Arc is taken from the top of the Bezier stack.       */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE on Render Pool overflow.                            */
/*                                                                          */
/****************************************************************************/

  static Bool  Bezier_Down( RAS_ARGS Long  miny, Long  maxy )
  {
    TPoint*  arc = ras.arc;
    Bool     result, fresh;


    arc[0].y = -arc[0].y;
    arc[1].y = -arc[1].y;
    arc[2].y = -arc[2].y;

    fresh = ras.fresh;

    result = Bezier_Up( RAS_VARS -maxy, -miny );

    if ( fresh && !ras.fresh )
      ras.cProfile->start = -ras.cProfile->start;

    arc[0].y = -arc[0].y;
    return result;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Line_To                                                     */
/*                                                                          */
/* Description: Injects a new line segment and adjusts Profiles list.       */
/*                                                                          */
/* Input:       x, y : segment endpoint (start point in LastX,LastY)        */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE on Render Pool overflow or Incorrect Profile.       */
/*                                                                          */
/****************************************************************************/

  static Bool  Line_To( RAS_ARGS Long  x, Long  y )
  {
    /* First, detect a change of direction */

    switch ( ras.state )
    {
    case Unknown:
      if ( y > ras.lastY )
      {
        if ( New_Profile( RAS_VARS  Ascending ) ) return FAILURE;
      }
      else
      {
        if ( y < ras.lastY )
          if ( New_Profile( RAS_VARS  Descending ) ) return FAILURE;
      }
      break;

    case Ascending:
      if ( y < ras.lastY )
      {
        if ( End_Profile( RAS_VAR ) ||
             New_Profile( RAS_VARS  Descending ) ) return FAILURE;
      }
      break;

    case Descending:
      if ( y > ras.lastY )
      {
        if ( End_Profile( RAS_VAR ) ||
             New_Profile( RAS_VARS  Ascending ) ) return FAILURE;
      }
      break;

    default:
      ;
    }

    /* Then compute the lines */

    switch ( ras.state )
    {
    case Ascending:
      if ( Line_Up ( RAS_VARS  ras.lastX, ras.lastY,
                     x, y, ras.minY, ras.maxY ) )
        return FAILURE;
      break;

    case Descending:
      if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
                      x, y, ras.minY, ras.maxY ) )
        return FAILURE;
      break;

    default:
      ;
    }

    ras.lastX = x;
    ras.lastY = y;

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Bezier_To                                                   */
/*                                                                          */
/* Description: Injects a new bezier arc and adjusts the profile list.      */
/*                                                                          */
/* Input:       x,   y : arc endpoint (start point in LastX, LastY)         */
/*              Cx, Cy : control point                                      */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE on Render Pool overflow or Incorrect Profile.       */
/*                                                                          */
/****************************************************************************/

  static Bool  Bezier_To( RAS_ARGS Long  x,
                                   Long  y,
                                   Long  cx,
                                   Long  cy )
  {
    Long     y1, y2, y3, x3;
    TStates  state_bez;


    Push_Bezier( RAS_VARS ras.lastX, ras.lastY, cx, cy, x, y );

    do
    {
      y1 = ras.arc[2].y;
      y2 = ras.arc[1].y;
      y3 = ras.arc[0].y;
      x3 = ras.arc[0].x;

      /* first, categorize the bezier arc */

      if ( y1 == y2 )
      {
        if ( y2 == y3 )
          state_bez = Flat;
        else if ( y2 > y3 )
          state_bez = Descending;
        else
          state_bez = Ascending;
      }
      else if ( y1 > y2 )
      {
        if ( y2 >= y3 )
          state_bez = Descending;
        else
          state_bez = Unknown;
      }
      else if ( y2 <= y3 )
        state_bez = Ascending;
      else
        state_bez = Unknown;

      /* split non-monotonic arcs, ignore flat ones, or */
      /* computes the up and down ones                  */

      switch ( state_bez )
      {
      case Flat:
        ras.arc -= 2;
        break;

      case Unknown:
        Split_Bezier( ras.arc );
        ras.arc += 2;
        break;

      default:
        /* detect a change of direction */

        if ( ras.state != state_bez )
        {
          if ( ras.state != Unknown )
            if ( End_Profile( RAS_VAR ) ) return FAILURE;

          if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE;
        }

        /* compute */

        switch ( ras.state )
        {
        case Ascending:
          if ( Bezier_Up ( RAS_VARS ras.minY, ras.maxY ) )
            return FAILURE;
          break;

        case Descending:
          if ( Bezier_Down( RAS_VARS ras.minY, ras.maxY ) )
            return FAILURE;
          break;

        default:
          ;
        }
      }
    } while ( ras.arc >= ras.arcs );

    ras.lastX = x3;
    ras.lastY = y3;

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Decompose_Curve                                             */
/*                                                                          */
/* Description: Scans the outline arays in order to emit individual         */
/*              segments and beziers by calling Line_To() and Bezier_To().  */
/*              It handles all weird cases, like when the first point       */
/*              is off the curve, or when there are simply no 'on'          */
/*              points in the contour!                                      */
/*                                                                          */
/* Input:       first, last    : indexes of first and last point in         */
/*                               contour.                                   */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE on error.                                           */
/*                                                                          */
/****************************************************************************/

#undef  SWAP_
#define SWAP_(x,y)  { Long swap = x; x = y; y = swap; }

  static Bool  Decompose_Curve( RAS_ARGS UShort  first,
                                         UShort  last,
                                         Bool    flipped )
  {
    Long   x,  y;   /* current point                */
    Long   cx, cy;  /* current Bezier control point */
    Long   mx, my;  /* current middle point         */

    Long   x_first, y_first;  /* first point's coordinates */
    Long   x_last,  y_last;   /* last point's coordinates  */

    UShort  index;     /* current point's index */
    Bool    on_curve;  /* current point's state */

    x_first = SCALED( ras.coords[first].x );
    y_first = SCALED( ras.coords[first].y );

    if ( flipped ) SWAP_( x_first,y_first );

    x_last  = SCALED( ras.coords[last].x );
    y_last  = SCALED( ras.coords[last].y );

    if ( flipped ) SWAP_( x_last,y_last );

    ras.lastX = cx = x_first;
    ras.lastY = cy = y_first;

    on_curve = (ras.flags[first] & 1);
    index    = first;

    /* check first point to determine origin */
    if ( !on_curve )
    {
      /* first point is off the curve.  Yes, this happens... */
      if ( ras.flags[last] & 1 )
      {
        ras.lastX = x_last;  /* start at last point if it */
        ras.lastY = y_last;  /* is on the curve           */
      }
      else
      {
        /* if both first and last points are off the curve, */
        /* start at their middle and record its position    */
        /* for closure                                      */
        ras.lastX = (ras.lastX + x_last)/2;
        ras.lastY = (ras.lastY + y_last)/2;

        x_last = ras.lastX;
        y_last = ras.lastY;
      }
    }

    /* now process each contour point individually */
    while ( index < last )
    {
      index++;
      x = SCALED( ras.coords[index].x );
      y = SCALED( ras.coords[index].y );

      if ( flipped ) SWAP_( x, y );

      if ( on_curve )
      {
        /* the previous point was on the curve */
        on_curve = ( ras.flags[index] & 1 );
        if ( on_curve )
        {
          /* two successive on points => emit segment */
          if ( Line_To( RAS_VARS  x, y ) ) return FAILURE;
        }
        else
        {
          /* else, keep current control point for next bezier */
          cx = x;
          cy = y;
        }
      }
      else
      {
        /* the previous point was off the curve */
        on_curve = ( ras.flags[index] & 1 );
        if ( on_curve )
        {
          /* reaching an `on' point */
          if ( Bezier_To( RAS_VARS  x, y, cx, cy ) ) return FAILURE;
        }
        else
        {
          /* two successive `off' points => create middle point */
          mx = ( cx + x ) / 2;
          my = ( cy + y ) / 2;

          if ( Bezier_To( RAS_VARS  mx, my, cx, cy ) ) return FAILURE;

          cx = x;
          cy = y;
        }
      }
    }

    /* end of contour, close curve cleanly */
    if ( ras.flags[first] & 1 )
    {
      if ( on_curve )
        return Line_To( RAS_VARS  x_first, y_first );
      else
        return Bezier_To( RAS_VARS  x_first, y_first, cx, cy );
    }
    else
      if ( !on_curve )
        return Bezier_To( RAS_VARS  x_last, y_last, cx, cy );

    return SUCCESS_OK;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Convert_Glyph                                               */
/*                                                                          */
/* Description: Converts a glyph into a series of segments and arcs         */
/*              and makes a Profiles list with them.                        */
/*                                                                          */
/* Input:       _xCoord, _yCoord : coordinates tables.                      */
/*                                                                          */
/*              Uses the 'Flag' table too.                                  */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE if any error was encountered during rendering.      */
/*                                                                          */
/****************************************************************************/

  static Bool  Convert_Glyph( RAS_ARGS int  flipped )
  {
    Short     i;
    UShort    start;

    PProfile  lastProfile;


    ras.fProfile = NULL;
    ras.joint    = FALSE;
    ras.fresh    = FALSE;

    ras.maxBuff  = ras.sizeBuff - AlignProfileSize;

    ras.numTurns = 0;

    ras.cProfile         = (PProfile)ras.top;
    ras.cProfile->offset = ras.top;
    ras.num_Profs        = 0;

    start = 0;

    for ( i = 0; i < ras.nContours; i++ )
    {
      ras.state    = Unknown;
      ras.gProfile = NULL;

      if ( Decompose_Curve( RAS_VARS  start, ras.outs[i], flipped ) )
        return FAILURE;

      start = ras.outs[i] + 1;

      /* We must now see if the extreme arcs join or not */
      if ( ( FRAC( ras.lastY ) == 0 &&
             ras.lastY >= ras.minY      &&
             ras.lastY <= ras.maxY ) )
        if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
          ras.top--;
        /* Note that ras.gProfile can be nil if the contour was too small */
        /* to be drawn.                                                   */

      lastProfile = ras.cProfile;
      if ( End_Profile( RAS_VAR ) ) return FAILURE;

      /* close the 'next profile in contour' linked list */
      if ( ras.gProfile )
        lastProfile->next = ras.gProfile;
    }

    if (Finalize_Profile_Table( RAS_VAR ))
      return FAILURE;

    return (ras.top < ras.maxBuff ? SUCCESS_OK : FAILURE );
  }


/************************************************/
/*                                              */
/*  Init_Linked                                 */
/*                                              */
/*    Inits an empty linked list.               */
/*                                              */
/************************************************/

  static void  Init_Linked( TProfileList*  l )
  {
    *l = NULL;
  }


/************************************************/
/*                                              */
/*  InsNew :                                    */
/*                                              */
/*    Inserts a new Profile in a linked list.   */
/*                                              */
/************************************************/

  static void  InsNew( PProfileList  list,
                       PProfile      profile )
  {
    PProfile  *old, current;
    Long       x;


    old     = list;
    current = *old;
    x       = profile->X;

    while ( current )
    {
      if ( x < current->X )
        break;
      old     = &current->link;
      current = *old;
    }

    profile->link = current;
    *old          = profile;
  }


/*************************************************/
/*                                               */
/*  DelOld :                                     */
/*                                               */
/*    Removes an old Profile from a linked list. */
/*                                               */
/*************************************************/

  static void  DelOld( PProfileList  list,
                       PProfile      profile )
  {
    PProfile  *old, current;


    old     = list;
    current = *old;

    while ( current )
    {
      if ( current == profile )
      {
        *old = current->link;
        return;
      }

      old     = &current->link;
      current = *old;
    }

    /* we should never get there, unless the Profile was not part of */
    /* the list.                                                     */
  }


/************************************************/
/*                                              */
/*  Update :                                    */
/*                                              */
/*    Update all X offsets of a drawing list    */
/*                                              */
/************************************************/

  static void  Update( PProfile  first )
  {
    PProfile  current = first;


    while ( current )
    {
      current->X       = *current->offset;
      current->offset += current->flow;
      current->height--;
      current = current->link;
    }
  }


/************************************************/
/*                                              */
/*  Sort :                                      */
/*                                              */
/*    Sorts a trace list.  In 95%, the list     */
/*    is already sorted.  We need an algorithm  */
/*    which is fast in this case.  Bubble sort  */
/*    is enough and simple.                     */
/*                                              */
/************************************************/

  static void  Sort( PProfileList  list )
  {
    PProfile  *old, current, next;


    /* First, set the new X coordinate of each profile */
    Update( *list );

    /* Then sort them */
    old     = list;
    current = *old;

    if ( !current )
      return;

    next = current->link;

    while ( next )
    {
      if ( current->X <= next->X )
      {
        old     = &current->link;
        current = *old;

        if ( !current )
          return;
      }
      else
      {
        *old          = next;
        current->link = next->link;
        next->link    = current;

        old     = list;
        current = *old;
      }

      next = current->link;
    }
  }


/***********************************************************************/
/*                                                                     */
/*  Vertical Sweep Procedure Set :                                     */
/*                                                                     */
/*  These three routines are used during the vertical black/white      */
/*  sweep phase by the generic Draw_Sweep() function.                  */
/*                                                                     */
/***********************************************************************/

  static void  Vertical_Sweep_Init( RAS_ARGS Short*  min, Short*  max )
  {
    switch ( ras.target.flow )
    {
    case TT_Flow_Up:
      ras.traceOfs  = *min * ras.target.cols;
      ras.traceIncr = ras.target.cols;
      break;

    default:
      ras.traceOfs  = ( ras.target.rows - 1 - *min ) * ras.target.cols;
      ras.traceIncr = -ras.target.cols;
    }

    ras.gray_min_x = 0;
    ras.gray_max_x = 0;
  }


  static void  Vertical_Sweep_Span( RAS_ARGS Short       y,
                                             TT_F26Dot6  x1,
                                             TT_F26Dot6  x2,
                                             PProfile    left,
                                             PProfile    right )
  {
    Long   e1, e2;
    Short  c1, c2;
    Short  f1, f2;
    Byte*  target;


    /* Drop-out control */

    e1 = TRUNC( CEILING( x1 ) );

    if ( x2-x1-ras.precision <= ras.precision_jitter )
      e2 = e1;
    else
      e2 = TRUNC( FLOOR( x2 ) );

    if ( e2 >= 0 && e1 < ras.bWidth )
    {
      if ( e1 < 0 )           e1 = 0;
      if ( e2 >= ras.bWidth ) e2 = ras.bWidth-1;

      c1 = (Short)(e1 >> 3);
      c2 = (Short)(e2 >> 3);

      f1 = e1 & 7;
      f2 = e2 & 7;

      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
      if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2;

      target = ras.bTarget + ras.traceOfs + c1;

      if ( c1 != c2 )
      {
        *target |= LMask[f1];

        if ( c2 > c1 + 1 )
          MEM_Set( target + 1, 0xFF, c2 - c1 - 1 );

        target[c2 - c1] |= RMask[f2];
      }
      else
        *target |= ( LMask[f1] & RMask[f2] );
    }
  }


  static void  Vertical_Sweep_Drop( RAS_ARGS Short       y,
                                             TT_F26Dot6  x1,
                                             TT_F26Dot6  x2,
                                             PProfile    left,
                                             PProfile    right )
  {
    Long   e1, e2;
    Short  c1, f1;


    /* Drop-out control */

    e1 = CEILING( x1 );
    e2 = FLOOR  ( x2 );

    if ( e1 > e2 )
    {
      if ( e1 == e2 + ras.precision )
      {
        switch ( ras.dropOutControl )
        {
        case 1:
          e1 = e2;
          break;

        case 4:
          e1 = CEILING( (x1 + x2 + 1) / 2 );
          break;

        case 2:
        case 5:
          /* Drop-out Control Rule #4 */

          /* The spec is not very clear regarding rule #4.  It      */
          /* presents a method that is way too costly to implement  */
          /* while the general idea seems to get rid of 'stubs'.    */
          /*                                                        */
          /* Here, we only get rid of stubs recognized when:        */
          /*                                                        */
          /*  upper stub:                                           */
          /*                                                        */
          /*   - P_Left and P_Right are in the same contour         */
          /*   - P_Right is the successor of P_Left in that contour */
          /*   - y is the top of P_Left and P_Right                 */
          /*                                                        */
          /*  lower stub:                                           */
          /*                                                        */
          /*   - P_Left and P_Right are in the same contour         */
          /*   - P_Left is the successor of P_Right in that contour */
          /*   - y is the bottom of P_Left                          */
          /*                                                        */

          /* FIXXXME : uncommenting this line solves the disappearing */
          /*           bit problem in the '7' of verdana 10pts, but   */
          /*           makes a new one in the 'C' of arial 14pts      */

          /* if ( x2-x1 < ras.precision_half ) */
          {
            /* upper stub test */

            if ( left->next == right && left->height <= 0 ) return;

            /* lower stub test */

            if ( right->next == left && left->start == y ) return;
          }

          /* check that the rightmost pixel isn't set */

          e1 = TRUNC( e1 );

          c1 = (Short)(e1 >> 3);
          f1 = e1 &  7;

          if ( e1 >= 0 && e1 < ras.bWidth &&
               ras.bTarget[ras.traceOfs + c1] & (0x80 >> f1) )
            return;

          if ( ras.dropOutControl == 2 )
            e1 = e2;
          else
            e1 = CEILING( (x1 + x2 + 1) / 2 );

          break;

        default:
          return;  /* unsupported mode */
        }
      }
      else
        return;
    }

    e1 = TRUNC( e1 );

    if ( e1 >= 0 && e1 < ras.bWidth )
    {
      c1 = (Short)(e1 >> 3);
      f1 = e1 & 7;

      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
      if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;

      ras.bTarget[ras.traceOfs + c1] |= (Char)(0x80 >> f1);
    }
  }


  static void Vertical_Sweep_Step( RAS_ARG )
  {
    ras.traceOfs += ras.traceIncr;
  }


/***********************************************************************/
/*                                                                     */
/*  Horizontal Sweep Procedure Set :                                   */
/*                                                                     */
/*  These three routines are used during the horizontal black/white    */
/*  sweep phase by the generic Draw_Sweep() function.                  */
/*                                                                     */
/***********************************************************************/

  static void  Horizontal_Sweep_Init( RAS_ARGS Short*  min, Short*  max )
  {
    /* nothing, really */
  }


  static void  Horizontal_Sweep_Span( RAS_ARGS Short       y,
                                               TT_F26Dot6  x1,
                                               TT_F26Dot6  x2,
                                               PProfile    left,
                                               PProfile    right )
  {
    Long  e1, e2;
    PByte bits;
    Byte  f1;


    if ( x2-x1 < ras.precision )
    {
      e1 = CEILING( x1 );
      e2 = FLOOR  ( x2 );

      if ( e1 == e2 )
      {
        bits = ras.bTarget + (y >> 3);
        f1   = (Byte)(0x80 >> (y  & 7));

        e1 = TRUNC( e1 );

        if ( e1 >= 0 && e1 < ras.target.rows )
        {
          if ( ras.target.flow == TT_Flow_Down )
            bits[(ras.target.rows-1 - e1) * ras.target.cols] |= f1;
          else
            bits[e1 * ras.target.cols] |= f1;
        }
      }
    }
#if 0
      e2 = TRUNC( e2 );

      if ( e2 >= 0 && e2 < ras.target.rows )
        if ( ras.target.flow == TT_Flow_Down )
          bits[(ras.target.rows-1-e2) * ras.target.cols] |= f1;
        else
          bits[e2 * ras.target.cols] |= f1;
#endif
  }


  static void  Horizontal_Sweep_Drop( RAS_ARGS Short       y,
                                               TT_F26Dot6  x1,
                                               TT_F26Dot6  x2,
                                               PProfile    left,
                                               PProfile    right )
  {
    Long  e1, e2;
    PByte bits;
    Byte  f1;


    /* During the horizontal sweep, we only take care of drop-outs */

    e1 = CEILING( x1 );
    e2 = FLOOR  ( x2 );

    if ( e1 > e2 )
    {
      if ( e1 == e2 + ras.precision )
      {
        switch ( ras.dropOutControl )
        {
        case 1:
          e1 = e2;
          break;

        case 4:
          e1 = CEILING( (x1 + x2 + 1) / 2 );
          break;

        case 2:
        case 5:

          /* Drop-out Control Rule #4 */

          /* The spec is not very clear regarding rule #4.  It      */
          /* presents a method that is way too costly to implement  */
          /* while the general idea seems to get rid of 'stubs'.    */
          /*                                                        */

          /* rightmost stub test */

          if ( left->next == right && left->height <= 0 ) return;

          /* leftmost stub test */

          if ( right->next == left && left->start == y ) return;

          /* check that the rightmost pixel isn't set */

          e1 = TRUNC( e1 );

          bits = ras.bTarget + (y >> 3);
          f1   = (Byte)(0x80 >> (y &  7));

          if ( ras.target.flow == TT_Flow_Down )
            bits += (ras.target.rows-1-e1) * ras.target.cols;
          else
            bits += e1 * ras.target.cols;

          if ( e1 >= 0              &&
               e1 < ras.target.rows &&
               *bits & f1 )
            return;

          if ( ras.dropOutControl == 2 )
            e1 = e2;
          else
            e1 = CEILING( (x1 + x2 + 1) / 2 );

          break;

        default:
          return;  /* unsupported mode */
        }
      }
      else
        return;
    }

    bits = ras.bTarget + (y >> 3);
    f1   = (Byte)(0x80 >> (y  & 7));

    e1 = TRUNC( e1 );

    if ( e1 >= 0 && e1 < ras.target.rows )
    {
      if (ras.target.flow==TT_Flow_Down)
        bits[(ras.target.rows-1-e1) * ras.target.cols] |= f1;
      else
        bits[e1 * ras.target.cols] |= f1;
    }
  }


  static void Horizontal_Sweep_Step( RAS_ARG )
  {
    /* Nothing, really */
  }


#ifdef TT_CONFIG_OPTION_GRAY_SCALING

/***********************************************************************/
/*                                                                     */
/*  Vertical Gray Sweep Procedure Set:                                 */
/*                                                                     */
/*  These two routines are used during the vertical gray-levels        */
/*  sweep phase by the generic Draw_Sweep() function.                  */
/*                                                                     */
/*                                                                     */
/*  NOTES:                                                             */
/*                                                                     */
/*  - The target pixmap's width *must* be a multiple of 4.             */
/*                                                                     */
/*  - you have to use the function Vertical_Sweep_Span() for           */
/*    the gray span call.                                              */
/*                                                                     */
/***********************************************************************/

  static void  Vertical_Gray_Sweep_Init( RAS_ARGS Short*  min, Short*  max )
  {
    *min = *min & -2;
    *max = ( *max + 3 ) & -2;

    ras.traceOfs = 0;

    switch ( ras.target.flow )
    {
    case TT_Flow_Up:
      ras.traceG  = (*min / 2) * ras.target.cols;
      ras.traceIncr = ras.target.cols;
      break;

    default:
      ras.traceG    = (ras.target.rows-1 - *min/2) * ras.target.cols;
      ras.traceIncr = -ras.target.cols;
    }

    ras.gray_min_x =  ras.target.cols;
    ras.gray_max_x = -ras.target.cols;
  }


  static void  Vertical_Gray_Sweep_Step( RAS_ARG )
  {
    Int    c1, c2;
    PByte  pix, bit, bit2;
    Int*   count = ras.count_table;
    Byte*  grays;


    ras.traceOfs += ras.gray_width;

    if ( ras.traceOfs > ras.gray_width )
    {
      pix   = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
      grays = ras.grays;

      if ( ras.gray_max_x >= 0 )
      {
        if ( ras.gray_max_x >= ras.target.width )
          ras.gray_max_x = ras.target.width-1;

        if ( ras.gray_min_x < 0 )
          ras.gray_min_x = 0;

        bit   = ras.bTarget + ras.gray_min_x;
        bit2  = bit + ras.gray_width;

        c1 = ras.gray_max_x - ras.gray_min_x;

        while ( c1 >= 0 )
        {
          c2 = count[*bit] + count[*bit2];

          if ( c2 )
          {
            pix[0] = grays[(c2 & 0xF000) >> 12];
            pix[1] = grays[(c2 & 0x0F00) >>  8];
            pix[2] = grays[(c2 & 0x00F0) >>  4];
            pix[3] = grays[(c2 & 0x000F)      ];

            *bit  = 0;
            *bit2 = 0;
          }

          bit ++;
          bit2++;
          pix += 4;
          c1  --;
        }
      }

      ras.traceOfs = 0;
      ras.traceG  += ras.traceIncr;

      ras.gray_min_x =  ras.target.cols;
      ras.gray_max_x = -ras.target.cols;
    }
  }


  static void  Horizontal_Gray_Sweep_Span( RAS_ARGS Short       y,
                                                    TT_F26Dot6  x1,
                                                    TT_F26Dot6  x2,
                                                    PProfile    left,
                                                    PProfile    right )
  {
    /* nothing, really */
  }

  static void  Horizontal_Gray_Sweep_Drop( RAS_ARGS Short       y,
                                                    TT_F26Dot6  x1,
                                                    TT_F26Dot6  x2,
                                                    PProfile    left,
                                                    PProfile    right )
  {
    Long  e1, e2;
    PByte pixel;
    Byte  color;


    /* During the horizontal sweep, we only take care of drop-outs */
    e1 = CEILING( x1 );
    e2 = FLOOR  ( x2 );

    if ( e1 > e2 )
    {
      if ( e1 == e2 + ras.precision )
      {
        switch ( ras.dropOutControl )
        {
        case 1:
          e1 = e2;
          break;

        case 4:
          e1 = CEILING( (x1 + x2 + 1) / 2 );
          break;

        case 2:
        case 5:

          /* Drop-out Control Rule #4 */

          /* The spec is not very clear regarding rule #4.  It      */
          /* presents a method that is way too costly to implement  */
          /* while the general idea seems to get rid of 'stubs'.    */
          /*                                                        */

          /* rightmost stub test */
          if ( left->next == right && left->height <= 0 ) return;

          /* leftmost stub test */
          if ( right->next == left && left->start == y ) return;

          if ( ras.dropOutControl == 2 )
            e1 = e2;
          else
            e1 = CEILING( (x1 + x2 + 1) / 2 );

          break;

        default:
          return;  /* unsupported mode */
        }
      }
      else
        return;
    }

    if ( e1 >= 0 )
    {
      if ( x2 - x1 >= ras.precision_half )
        color = ras.grays[2];
      else
        color = ras.grays[1];

      e1 = TRUNC( e1 ) / 2;
      if ( e1 < ras.target.rows )
      {
        if ( ras.target.flow == TT_Flow_Down )
          pixel = ras.gTarget +
                  (ras.target.rows - 1 - e1) * ras.target.cols + y / 2;
        else
          pixel = ras.gTarget +
                  e1 * ras.target.cols + y / 2;

        if (pixel[0] == ras.grays[0])
          pixel[0] = color;
      }
    }
  }

#endif /* TT_CONFIG_OPTION_GRAY_SCALING */


/********************************************************************/
/*                                                                  */
/*  Generic Sweep Drawing routine                                   */
/*                                                                  */
/********************************************************************/

  static Bool  Draw_Sweep( RAS_ARG )
  {
    Short  y, y_change, y_height;

    PProfile  P, Q, P_Left, P_Right;

    Short  min_Y, max_Y, top, bottom, dropouts;

    Long  x1, x2, xs, e1, e2;

    TProfileList  wait;
    TProfileList  draw_left, draw_right;


    /* Init empty linked lists */

    Init_Linked( &wait );

    Init_Linked( &draw_left  );
    Init_Linked( &draw_right );

    /* first, compute min and max Y */

    P     = ras.fProfile;
    max_Y = (short)TRUNC( ras.minY );
    min_Y = (short)TRUNC( ras.maxY );

    while ( P )
    {
      Q = P->link;

      bottom = P->start;
      top    = P->start + P->height-1;

      if ( min_Y > bottom ) min_Y = bottom;
      if ( max_Y < top    ) max_Y = top;

      P->X = 0;
      InsNew( &wait, P );

      P = Q;
    }

    /* Check the Y-turns */
    if ( ras.numTurns == 0 )
    {
      ras.error = Raster_Err_Invalid;
      return FAILURE;
    }

    /* Now inits the sweep */

    ras.Proc_Sweep_Init( RAS_VARS  &min_Y, &max_Y );

    /* Then compute the distance of each profile from min_Y */

    P = wait;

    while ( P )
    {
      P->countL = P->start - min_Y;
      P = P->link;
    }

    /* Let's go */

    y        = min_Y;
    y_height = 0;

    if ( ras.numTurns > 0 &&
         ras.sizeBuff[-ras.numTurns] == min_Y )
      ras.numTurns--;

    while ( ras.numTurns > 0 )
    {
      /* look in the wait list for new activations */

      P = wait;

      while ( P )
      {
        Q = P->link;
        P->countL -= y_height;
        if ( P->countL == 0 )
        {
          DelOld( &wait, P );

          switch ( P->flow )
          {
            case TT_Flow_Up:    InsNew( &draw_left,  P ); break;
            case TT_Flow_Down:  InsNew( &draw_right, P ); break;
          }
        }

        P = Q;
      }

      /* Sort the drawing lists */

      Sort( &draw_left );
      Sort( &draw_right );

      y_change = (Short)ras.sizeBuff[-ras.numTurns--];
      y_height = y_change - y;

      while ( y < y_change )
      {

        /* Let's trace */

        dropouts = 0;

        P_Left  = draw_left;
        P_Right = draw_right;

        while ( P_Left )
        {
          x1 = P_Left ->X;
          x2 = P_Right->X;

          if ( x1 > x2 )
          {
            xs = x1;
            x1 = x2;
            x2 = xs;
          }

          if ( x2-x1 <= ras.precision )
          {
            e1 = FLOOR( x1 );
            e2 = CEILING( x2 );

            if ( ras.dropOutControl != 0 &&
                 (e1 > e2 || e2 == e1 + ras.precision) )
            {
              /* a drop out was detected */

              P_Left ->X = x1;
              P_Right->X = x2;

              /* mark profile for drop-out processing */
              P_Left->countL = 1;
              dropouts++;

              goto Skip_To_Next;
            }
          }

          ras.Proc_Sweep_Span( RAS_VARS  y, x1, x2, P_Left, P_Right );

   Skip_To_Next:

          P_Left  = P_Left->link;
          P_Right = P_Right->link;
        }

        /* now perform the dropouts _after_ the span drawing   */
        /* drop-outs processing has been moved out of the loop */
        /* for performance tuning                              */
        if (dropouts > 0)
          goto Scan_DropOuts;

   Next_Line:

        ras.Proc_Sweep_Step( RAS_VAR );

        y++;

        if ( y < y_change )
        {
          Sort( &draw_left  );
          Sort( &draw_right );
        }

      }

      /* Now finalize the profiles that needs it */

      {
        PProfile  Q, P;
        P = draw_left;
        while ( P )
        {
          Q = P->link;
          if ( P->height == 0 )
            DelOld( &draw_left, P );
          P = Q;
        }
      }

      {
        PProfile  Q, P = draw_right;
        while ( P )
        {
          Q = P->link;
          if ( P->height == 0 )
            DelOld( &draw_right, P );
          P = Q;
        }
      }
    }

    /* for gray-scaling, flushes the bitmap scanline cache */
    while ( y <= max_Y )
    {
      ras.Proc_Sweep_Step( RAS_VAR );
      y++;
    }

    return SUCCESS_OK;

Scan_DropOuts :

    P_Left  = draw_left;
    P_Right = draw_right;

    while ( P_Left )
    {
      if ( P_Left->countL )
      {
        P_Left->countL = 0;
        /* dropouts--;    -- this is useful when debugging only */
        ras.Proc_Sweep_Drop( RAS_VARS  y,
                                       P_Left->X,
                                       P_Right->X,
                                       P_Left,
                                       P_Right );
      }

      P_Left  = P_Left->link;
      P_Right = P_Right->link;
    }

    goto Next_Line;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Render_Single_Pass                                          */
/*                                                                          */
/* Description: Performs one sweep with sub-banding.                        */
/*                                                                          */
/* Input:       _XCoord, _YCoord : x and y coordinates arrays               */
/*                                                                          */
/* Returns:     SUCCESS on success                                          */
/*              FAILURE if any error was encountered during render.         */
/*                                                                          */
/****************************************************************************/

  static TT_Error  Render_Single_Pass( RAS_ARGS Bool  flipped )
  {
    Short  i, j, k;


    while ( ras.band_top >= 0 )
    {
      ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
      ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;

      ras.top = ras.buff;

      ras.error = Raster_Err_None;

      if ( Convert_Glyph( RAS_VARS  flipped ) )
      {
        if ( ras.error != Raster_Err_Overflow ) return FAILURE;

        ras.error = Raster_Err_None;

        /* sub-banding */

#ifdef DEBUG_RASTER
        ClearBand( RAS_VARS  TRUNC( ras.minY ), TRUNC( ras.maxY ) );
#endif

        i = ras.band_stack[ras.band_top].y_min;
        j = ras.band_stack[ras.band_top].y_max;

        k = ( i + j ) / 2;

        if ( ras.band_top >= 7 || k < i )
        {
          ras.band_top     = 0;
          ras.error = Raster_Err_Invalid;
          return ras.error;
        }

        ras.band_stack[ras.band_top+1].y_min = k;
        ras.band_stack[ras.band_top+1].y_max = j;

        ras.band_stack[ras.band_top].y_max = k - 1;

        ras.band_top++;
      }
      else
      {
        if ( ras.fProfile )
          if ( Draw_Sweep( RAS_VAR ) ) return ras.error;
        ras.band_top--;
      }
    }

    return TT_Err_Ok;
  }


/****************************************************************************/
/*                                                                          */
/* Function:    Render_Glyph                                                */
/*                                                                          */
/* Description: Renders a glyph in a bitmap.  Sub-banding if needed.        */
/*                                                                          */
/* Input:       AGlyph   Glyph record                                       */
/*                                                                          */
/* Returns:     SUCCESS on success.                                         */
/*              FAILURE if any error was encountered during rendering.      */
/*                                                                          */
/****************************************************************************/

  LOCAL_FUNC
  TT_Error  Render_Glyph( RAS_ARGS TT_Outline*     glyph,
                                   TT_Raster_Map*  target_map )
  {
    TT_Error  error;


    if ( glyph->n_points == 0 || glyph->n_contours <= 0 )
      return TT_Err_Ok;

    if ( !ras.buff )
    {
      ras.error = Raster_Err_Not_Ini;
      return ras.error;
    }

    if ( glyph->n_points < glyph->contours[glyph->n_contours - 1] )
    {
      ras.error = TT_Err_Too_Many_Points;
      return ras.error;
    }

    if ( target_map )
      ras.target = *target_map;

    ras.outs      = glyph->contours;
    ras.flags     = glyph->flags;
    ras.nPoints   = glyph->n_points;
    ras.nContours = glyph->n_contours;
    ras.coords    = glyph->points;

    Set_High_Precision( RAS_VARS glyph->high_precision );
    ras.scale_shift    = ras.precision_shift;
    ras.dropOutControl = glyph->dropout_mode;
    ras.second_pass    = glyph->second_pass;


    /* Vertical Sweep */
    ras.Proc_Sweep_Init = Vertical_Sweep_Init;
    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
    ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
    ras.Proc_Sweep_Step = Vertical_Sweep_Step;

    ras.band_top            = 0;
    ras.band_stack[0].y_min = 0;
    ras.band_stack[0].y_max = ras.target.rows - 1;

    ras.bWidth  = ras.target.width;
    ras.bTarget = (Byte*)ras.target.bitmap;

    if ( (error = Render_Single_Pass( RAS_VARS 0 )) != 0 )
      return error;

    /* Horizontal Sweep */

    if ( ras.second_pass && ras.dropOutControl != 0 )
    {
      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
      ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
      ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;

      ras.band_top            = 0;
      ras.band_stack[0].y_min = 0;
      ras.band_stack[0].y_max = ras.target.width - 1;

      if ( (error = Render_Single_Pass( RAS_VARS  1 )) != 0 )
        return error;
    }

    return TT_Err_Ok;
  }


#ifdef TT_CONFIG_OPTION_GRAY_SCALING

/****************************************************************************/
/*                                                                          */
/* Function:    Render_Gray_Glyph                                           */
/*                                                                          */
/* Description: Renders a glyph with grayscaling. Sub-banding if needed.    */
/*                                                                          */
/* Input:       AGlyph   Glyph record                                       */
/*                                                                          */
/* Returns:     SUCCESS on success                                          */
/*              FAILURE if any error was encountered during rendering.      */
/*                                                                          */
/****************************************************************************/

  LOCAL_FUNC
  TT_Error  Render_Gray_Glyph( RAS_ARGS  TT_Outline*     glyph,
                                         TT_Raster_Map*  target_map,
                                         Byte*           palette )
  {
    Int       i;
    TT_Error  error;

    if ( !ras.buff )
    {
      ras.error = Raster_Err_Not_Ini;
      return ras.error;
    }

    if ( glyph->n_points == 0 || glyph->n_contours <= 0 )
      return TT_Err_Ok;

    if ( glyph->n_points < glyph->contours[glyph->n_contours - 1] )
    {
      ras.error = TT_Err_Too_Many_Points;
      return ras.error;
    }

    if ( palette )
    {
      for ( i = 0; i < 5; i++ )
        ras.grays[i] = palette[i];
    }

    if ( target_map )
      ras.target = *target_map;

    ras.outs      = glyph->contours;
    ras.flags     = glyph->flags;
    ras.nPoints   = glyph->n_points;
    ras.nContours = glyph->n_contours;
    ras.coords    = glyph->points;

    Set_High_Precision( RAS_VARS glyph->high_precision );
    ras.scale_shift    = ras.precision_shift+1;
    ras.dropOutControl = glyph->dropout_mode;
    ras.second_pass    = glyph->second_pass;


    /* Vertical Sweep */

    ras.band_top            = 0;
    ras.band_stack[0].y_min = 0;
    ras.band_stack[0].y_max = 2 * ras.target.rows - 1;

    ras.bWidth  = ras.gray_width;
    if ( ras.bWidth > ras.target.cols/4 )
      ras.bWidth = ras.target.cols/4;

    ras.bWidth  = ras.bWidth * 8;
    ras.bTarget = (Byte*)ras.gray_lines;
    ras.gTarget = (Byte*)ras.target.bitmap;

    ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
    ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
    ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;

    error = Render_Single_Pass( RAS_VARS  0 );
    if (error)
      return error;

    /* Horizontal Sweep */

    if ( ras.second_pass && ras.dropOutControl != 0 )
    {
      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
      ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
      ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;

      ras.band_top            = 0;
      ras.band_stack[0].y_min = 0;
      ras.band_stack[0].y_max = ras.target.width * 2 - 1;

      error = Render_Single_Pass( RAS_VARS  1 );
      if (error)
        return error;
    }

    return TT_Err_Ok;
  }

#endif /* TT_CONFIG_OPTION_GRAY_SCALING */


/************************************************/
/*                                              */
/* InitRasterizer                               */
/*                                              */
/*  Raster Initialization.                      */
/*  Gets the bitmap description and render pool */
/*  addresses.                                  */
/*                                              */
/************************************************/

#undef ras

  LOCAL_FUNC
  TT_Error  TTRaster_Done( PEngine_Instance  engine )
  {
    TRaster_Instance*  ras = (TRaster_Instance*)engine->raster_component;


    if ( !ras )
      return TT_Err_Ok;

    FREE( ras->buff );
    FREE( ras->gray_lines );

#ifndef TT_CONFIG_OPTION_STATIC_RASTER
    FREE( engine->raster_component );
#endif

    return TT_Err_Ok;
  }


  LOCAL_FUNC
  TT_Error  TTRaster_Init( PEngine_Instance  engine )
  {
    TT_Error  error;

    Int  i, l, j, c;

    TRaster_Instance*  ras;


#ifdef TT_CONFIG_OPTION_STATIC_RASTER
    ras = engine->raster_component = &cur_ras;
#else
    if ( ALLOC( engine->raster_component, sizeof ( TRaster_Instance ) ) )
      return error;

    ras = (TRaster_Instance*)engine->raster_component;
#endif

    if ( ALLOC( ras->buff,       RASTER_RENDER_POOL )  ||
         ALLOC( ras->gray_lines, RASTER_GRAY_LINES ) )
       return error;

    ras->sizeBuff   = ras->buff + ( RASTER_RENDER_POOL/sizeof(long) );
    ras->gray_width = RASTER_GRAY_LINES/2;

    /* Initialization of Count_Table */

    for ( i = 0; i < 256; i++ )
    {
      l = 0;
      j = i;

      for ( c = 0; c < 4; c++ )
      {
        l <<= 4;

        if ( j & 0x80 ) l++;
        if ( j & 0x40 ) l++;

        j = ( j << 2 ) & 0xFF;
      }

      ras->count_table[i] = l;
    }

    ras->dropOutControl = 2;
    ras->error          = Raster_Err_None;

    return TT_Err_Ok;
  }


/* END */


TTRASTER.H  、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  ttraster.h                                                 v 1.4
 *
 *  The FreeType glyph rasterizer.
 *
 *  Copyright 1996-1999 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.
 *
 *  NOTES:
 *
 *  This version supports the following:
 *
 *    - direct grayscaling
 *    - sub-banding
 *    - drop-out modes 4 and 5
 *    - second pass for complete drop-out control (bitmap only)
 *    - variable precision
 *
 *
 *   Changes between 1.4 and 1.3:
 *
 *   Mainly performance tunings:
 *
 *   - Line_Down() and Bezier_Down() now use the functions Line_Up()
 *     and Bezier_Up() to do their work.
 *   - optimized Split_Bezier()
 *   - optimized linked lists used during sweeps
 *
 *   Changes between 1.2 and 1.3:
 *
 *     - made the engine optionaly re-entrant.  Saves a lot
 *       of code for a moderate performance hit.
 *
 ******************************************************************/

#ifndef TTRASTER_H
#define TTRASTER_H

#include "ttconfig.h"
#include "freetype.h"  /* for TT_Outline */
#include "ttengine.h"

#ifdef __cplusplus
extern "C" {
#endif

  /* We provide two different builds of the scan-line converter  */
  /* The static build uses global variables and isn't            */
  /* re-entrant.                                                 */
  /* The indirect build is re-entrant but accesses all variables */
  /* indirectly.                                                 */
  /*                                                             */
  /* As a consequence, the indirect build is about 10% slower    */
  /* than the static one on a _Pentium_ (this could get worse    */
  /* on older processors), but the code size is reduced by       */
  /* more than 30% !                                             */
  /*                                                             */
  /* The indirect build is now the default, defined in           */
  /* ttconfig.h.  Be careful if you experiment with this.        */

  /* Note also that, though its code can be re-entrant, the      */
  /* component is always used in thread-safe mode.  This is      */
  /* simply due to the fact that we want to use a single         */
  /* render pool (of 64 Kb), and not to waste memory.            */

#ifdef TT_STATIC_RASTER

#define  RAS_ARGS  /* void */
#define  RAS_ARG   /* void */

#define  RAS_VARS  /* void */
#define  RAS_VAR   /* void */

#else

#define  RAS_ARGS  TRaster_Instance*  raster,
#define  RAS_ARG   TRaster_Instance*  raster

#define  RAS_VARS  raster,
#define  RAS_VAR   raster

#endif


  struct  TRaster_Instance_;
  typedef struct TRaster_Instance_  TRaster_Instance;

  /* Render one glyph in the target bitmap, using drop-out control */
  /* mode 'scan'.                                                  */
  LOCAL_DEF
  TT_Error  Render_Glyph( RAS_ARGS TT_Outline*     glyph,
                                   TT_Raster_Map*  target );

#ifdef TT_CONFIG_OPTION_GRAY_SCALING
  /* Render one gray-level glyph in the target pixmap.              */
  /* Palette points to an array of 5 colors used for the rendering. */
  /* Use NULL to reuse the last palette. Default is VGA graylevels. */
  LOCAL_DEF
  TT_Error  Render_Gray_Glyph( RAS_ARGS TT_Outline*     glyph,
                                        TT_Raster_Map*  target,
                                        Byte*           palette );
#endif

  /* Initialize rasterizer */
  LOCAL_DEF
  TT_Error  TTRaster_Init( PEngine_Instance  engine );

  /* Finalize it */
  LOCAL_DEF
  TT_Error  TTRaster_Done( PEngine_Instance  engine );


#ifdef __cplusplus
}
#endif

#endif /* TTRASTER_H */


/* END */


TTTABLES.H    、、、、、、、、、、、、、、、、       、、、、、、

/*******************************************************************
 *
 *  tttables.h                                                  1.1
 *
 *    TrueType Tables structures and handling (specification).
 *
 *  Copyright 1996-1999 by
 *  David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 *  This file is part of the FreeType project, and may only be used
 *  modified and distributed under the terms of the FreeType project
 *  license, LICENSE.TXT. By continuing to use, modify, or distribute
 *  this file you indicate that you have read the license and
 *  understand and accept it fully.
 *
 ******************************************************************/

#ifndef TTTABLES_H
#define TTTABLES_H

#include "ttconfig.h"
#include "tttypes.h"

#ifdef __cplusplus
  extern "C" {
#endif

  /***********************************************************************/
  /*                                                                     */
  /*                      TrueType Table Types                           */
  /*                                                                     */
  /***********************************************************************/

  /* TrueType Collection Header */

  struct  TTTCHeader_
  {
    ULong     Tag;
    TT_Fixed  version;
    ULong     DirCount;
    PULong    TableDirectory;
  };

  typedef struct TTTCHeader_  TTTCHeader;
  typedef TTTCHeader*         PTTCHeader;


  /* TrueType Table Directory type */

  struct  TTableDir_
  {
    TT_Fixed  version;      /* should be 0x10000 */
    UShort    numTables;    /* number of tables  */

    UShort  searchRange;    /* These parameters are only used  */
    UShort  entrySelector;  /* for a dichotomy search in the   */
    UShort  rangeShift;     /* directory. We ignore them.      */
  };

  typedef struct TTableDir_  TTableDir;
  typedef TTableDir*         PTableDir;


  /* The 'TableDir' is followed by 'numTables' TableDirEntries */

  struct  TTableDirEntry_
  {
    ULong  Tag;        /*        table type */
    ULong  CheckSum;   /*    table checksum */
    ULong  Offset;     /* table file offset */
    ULong  Length;     /*      table length */
  };

  typedef struct TTableDirEntry_  TTableDirEntry;
  typedef TTableDirEntry*         PTableDirEntry;


  /* 'cmap' tables */

  struct  TCMapDir_
  {
    UShort  tableVersionNumber;
    UShort  numCMaps;
  };

  typedef struct TCMapDir_  TCMapDir;
  typedef TCMapDir*         PCMapDir;

  struct  TCMapDirEntry_
  {
    UShort  platformID;
    UShort  platformEncodingID;
    Long    offset;
  };

  typedef struct TCMapDirEntry_  TCMapDirEntry;
  typedef TCMapDirEntry*         PCMapDirEntries;


  /* 'maxp' Maximum Profiles table */

  struct  TMaxProfile_
  {
    TT_Fixed  version;
    UShort    numGlyphs,
              maxPoints,
              maxContours,
              maxCompositePoints,
              maxCompositeContours,
              maxZones,
              maxTwilightPoints,
              maxStorage,
              maxFunctionDefs,
              maxInstructionDefs,
              maxStackElements,
              maxSizeOfInstructions,
              maxComponentElements,
              maxComponentDepth;
  };

  typedef struct TMaxProfile_  TMaxProfile;
  typedef TMaxProfile*         PMaxProfile;


  /* table "gasp" */

#define GASP_GRIDFIT  0x01
#define GASP_DOGRAY   0x02

  struct  GaspRange_
  {
    UShort  maxPPEM;
    UShort  gaspFlag;
  };

  typedef struct GaspRange_  GaspRange;


  struct  TGasp_
  {
    UShort      version;
    UShort      numRanges;
    GaspRange*  gaspRanges;
  };

  typedef struct TGasp_  TGasp;


  /* table "head" - now defined in freetype.h */
  /* table "hhea" - now defined in freetype.h */


  /* tables "HMTX" and "VMTX" */

  struct  TLongMetrics_
  {
    UShort  advance;
    Short   bearing;
  };

  typedef struct TLongMetrics_  TLongMetrics, *PLongMetrics;

  typedef Short  TShortMetrics, *PShortMetrics;

  /* 'loca' location table type */

  struct  TLoca_
  {
    UShort    Size;
    PStorage  Table;
  };

  typedef struct TLoca_  TLoca;


  /* table "name" */

  struct  TNameRec_
  {
    UShort  platformID;
    UShort  encodingID;
    UShort  languageID;
    UShort  nameID;
    UShort  stringLength;
    UShort  stringOffset;

    /* this last field is not defined in the spec */
    /* but used by the FreeType engine            */

    PByte   string;
  };

  typedef struct TNameRec_  TNameRec;


  struct  TName_Table_
  {
    UShort     format;
    UShort     numNameRecords;
    UShort     storageOffset;
    TNameRec*  names;
    PByte      storage;
  };

  typedef struct TName_Table_  TName_Table;


#ifdef __cplusplus
  }
#endif

#endif /* TTTABLES_H */


/* END */


TTTAGS.H   、、、、、、、、、、、、、、、、       、、、、、、、、



/*******************************************************************
 *
 *  tttags.h
 *
 *    tags for TrueType tables (specification only).
 *
 *  Copyright 1996-1999 by
 *  David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 *  This file is part of the FreeType project, and may only be used
 *  modified and distributed under the terms of the FreeType project
 *  license, LICENSE.TXT. By continuing to use, modify, or distribute
 *  this file you indicate that you have read the license and
 *  understand and accept it fully.
 *
 ******************************************************************/

#ifndef TTAGS_H
#define TTAGS_H

#include "ttconfig.h"
#include "freetype.h"   /* for MAKE_TT_TAG() */

#define TTAG_BASE  MAKE_TT_TAG( 'B', 'A', 'S', 'E' )
#define TTAG_bloc  MAKE_TT_TAG( 'b', 'l', 'o', 'c' )
#define TTAG_bdat  MAKE_TT_TAG( 'b', 'd', 'a', 't' )
#define TTAG_cmap  MAKE_TT_TAG( 'c', 'm', 'a', 'p' )
#define TTAG_cvt   MAKE_TT_TAG( 'c', 'v', 't', ' ' )
#define TTAG_EBDT  MAKE_TT_TAG( 'E', 'B', 'D', 'T' )
#define TTAG_EBLC  MAKE_TT_TAG( 'E', 'B', 'L', 'C' )
#define TTAG_EBSC  MAKE_TT_TAG( 'E', 'B', 'S', 'C' )
#define TTAG_fpgm  MAKE_TT_TAG( 'f', 'p', 'g', 'm' )
#define TTAG_gasp  MAKE_TT_TAG( 'g', 'a', 's', 'p' )
#define TTAG_glyf  MAKE_TT_TAG( 'g', 'l', 'y', 'f' )
#define TTAG_GDEF  MAKE_TT_TAG( 'G', 'D', 'E', 'F' )
#define TTAG_GPOS  MAKE_TT_TAG( 'G', 'P', 'O', 'S' )
#define TTAG_GSUB  MAKE_TT_TAG( 'G', 'S', 'U', 'B' )
#define TTAG_hdmx  MAKE_TT_TAG( 'h', 'd', 'm', 'x' )
#define TTAG_head  MAKE_TT_TAG( 'h', 'e', 'a', 'd' )
#define TTAG_hhea  MAKE_TT_TAG( 'h', 'h', 'e', 'a' )
#define TTAG_hmtx  MAKE_TT_TAG( 'h', 'm', 't', 'x' )
#define TTAG_JSTF  MAKE_TT_TAG( 'J', 'S', 'T', 'F' )
#define TTAG_kern  MAKE_TT_TAG( 'k', 'e', 'r', 'n' )
#define TTAG_loca  MAKE_TT_TAG( 'l', 'o', 'c', 'a' )
#define TTAG_LTSH  MAKE_TT_TAG( 'L', 'T', 'S', 'H' )
#define TTAG_maxp  MAKE_TT_TAG( 'm', 'a', 'x', 'p' )
#define TTAG_name  MAKE_TT_TAG( 'n', 'a', 'm', 'e' )
#define TTAG_OS2   MAKE_TT_TAG( 'O', 'S', '/', '2' )
#define TTAG_PCLT  MAKE_TT_TAG( 'P', 'C', 'L', 'T' )
#define TTAG_post  MAKE_TT_TAG( 'p', 'o', 's', 't' )
#define TTAG_prep  MAKE_TT_TAG( 'p', 'r', 'e', 'p' )
#define TTAG_ttc   MAKE_TT_TAG( 't', 't', 'c', ' ' )
#define TTAG_ttcf  MAKE_TT_TAG( 't', 't', 'c', 'f' )
#define TTAG_VDMX  MAKE_TT_TAG( 'V', 'D', 'M', 'X' )
#define TTAG_vhea  MAKE_TT_TAG( 'v', 'h', 'e', 'a' )
#define TTAG_vmtx  MAKE_TT_TAG( 'v', 'm', 't', 'x' )

#endif /* TTAGS_H */


/* END */


TTTYPES.H      、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

/*******************************************************************
 *
 *  tttypes.h
 *
 *    Freetype engine's common types specification
 *    (this spec has no associated body).
 *
 *  Copyright 1996-1999 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.
 *
 *  NOTE:
 *
 *   All these declarations are library internals, and *not* part
 *   of the high-level interface.  See also 'freetype.h'.
 *
 ******************************************************************/

#ifndef TTTYPES_H
#define TTTYPES_H

#include "ttconfig.h"
#include "freetype.h"

#ifdef __MACTYPES__
#error "<MacTypes.h> have been included, and this prevents the proper\
 compilation of this library.  Please remove the precompiled headers."
#endif

  typedef          char   String;
  typedef signed   char   Char;
  typedef unsigned char   Byte;

  typedef unsigned short  UShort;
  typedef signed   short  Short;

  typedef unsigned long   ULong;
  typedef signed   long   Long;

  typedef TT_Int32        Fixed;

  typedef int             Int;

  /* Simple access types: pointers and tables */

  typedef Byte*    PByte;
  typedef UShort*  PUShort;
  typedef Short*   PShort;
  typedef ULong*   PULong;
  typedef Long*    PLong;

  typedef Fixed*   PFixed;

  typedef Int*     PInt;

  typedef void*    Pointer;

  typedef TT_F26Dot6*     PCoordinates;
  typedef unsigned char*  PTouchTable;


#ifndef Bool
  typedef int  Bool;        /* No boolean type in C */
#endif

#ifndef TRUE
#define TRUE  1
#endif

#ifndef FALSE
#define FALSE  0
#endif

#ifndef NULL
#define NULL  (void*)0
#endif

  typedef Long      Storage;
  typedef Storage*  PStorage;


/* Rounding mode constants */

#define TT_Round_Off             5
#define TT_Round_To_Half_Grid    0
#define TT_Round_To_Grid         1
#define TT_Round_To_Double_Grid  2
#define TT_Round_Up_To_Grid      4
#define TT_Round_Down_To_Grid    3
#define TT_Round_Super           6
#define TT_Round_Super_45        7


/* Touch flag masks */

#define TT_Flag_On_Curve      1
#define TT_Flag_Touched_X     2
#define TT_Flag_Touched_Y     4
#define TT_Flag_Touched_Both  6


/* Error management constants :) */

#define SUCCESS_OK  0
#define FAILURE  -1


/* The min and max functions missing in C.  As usual, be careful not to */
/* write things like MIN( a++, b++ ) to avoid side effects.             */

#ifndef MIN
#define MIN( a, b )  ( (a) < (b) ? (a) : (b) )
#endif

#ifndef MAX
#define MAX( a, b )  ( (a) > (b) ? (a) : (b) )
#endif

#ifndef ABS
#define ABS( a )     ( (a) < 0 ? -(a) : (a) )
#endif

/* conversion macros for the handles defined in freetype.h */

#define HANDLE_Val( handle )       ((handle).z)

#define HANDLE_Engine( handle )    ((PEngine_Instance)HANDLE_Val( handle ))

#define HANDLE_Face( handle )      ((PFace)HANDLE_Val( handle ))

#define HANDLE_Instance( handle )  ((PInstance)HANDLE_Val( handle ))

/* HANDLE_Stream( handle ) must be defined in ttfile.c */

#define HANDLE_Glyph( handle )     ((PGlyph)HANDLE_Val( handle ))

#define HANDLE_CharMap( handle )   ((PCMapTable)HANDLE_Val( handle ))

#define HANDLE_Set( handle, val )  ((handle).z = (void*)(val))


#endif /* TTTYPES_H */


/* END */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值