/*******************************************************************
 *
 *  ttapi.c    
 *
 *    High-level interface implementation
 *
 *  Copyright 1996, 1997 by
 *  David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 *  This file is part of the FreeType project, and may only be used,
 *  modified, and distributed under the terms of the FreeType project
 *  license, LICENSE.TXT.  By continuing to use, modify, or distribute 
 *  this file you indicate that you have read the license and
 *  understand and accept it fully.
 *
 *  Notes:
 *
 *    This file implements most of the features of the high-level
 *    interface.  Note, however, that the character mapping tables
 *    functions, TT_Get_CharMap() and TT_Char_Index(), are all located
 *    in the 'ttindex.c' source file.
 *
 ******************************************************************/

#include "freetype.h"
#include "ttcommon.h"
#include "ttengine.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttcache.h"
#include "ttfile.h"
#include "ttobjs.h"
#include "ttload.h"
#include "ttgload.h"
#include "ttraster.h"
#include "ttextend.h"


#ifdef TT_STATIC_RASTER
#define  RAS_OPS   /* void */
#define  RAS_OP    /* void */
#else
#define  RAS_OPS   ((TRaster_Instance*)_engine->raster_component),
#define  RAS_OP    ((TRaster_Instance*)_engine->raster_component)
#endif /* TT_STATIC_RASTER */
  

#define RENDER_Glyph( glyph, target ) \
          Render_Glyph( RAS_OPS  glyph, target )

#define RENDER_Gray_Glyph( glyph, target, palette ) \
          Render_Gray_Glyph( RAS_OPS  glyph, target, palette )


  const TT_Instance   TT_Null_Instance = { (void*)0 };

/*******************************************************************
 *
 *  Function    : TT_Init_FreeType
 *
 *  Description : The library's engine initializer.  This function
 *                must be called prior to any call.
 *
 *  Input  :  None
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Init_FreeType( TT_Engine*  engine )
  {
    PEngine_Instance  _engine;

    TT_Error  error;
    int       n;

    /* first of all, allocate engine instance */
    if ( ALLOC( _engine, sizeof ( TEngine_Instance ) ) )
      return error;

    /* Initalize components */
    if ( ( error = TTMemory_Init( _engine ) )  ||
         ( error = TTFile_Init  ( _engine ) )  ||
         ( error = TTLists_Init ( _engine ) )  ||
#ifdef TT_EXTEND_ENGINE
         ( error = TTExtend_Init( _engine ) )  ||
#endif
         ( error = TTObjs_Init  ( _engine ) )  ||
         ( error = TTRaster_Init( _engine ) )  )
      goto Fail;

    /* set the gray palette defaults: 0 to 4 */
    for ( n = 0; n < 5; n++ )
       _engine->raster_palette[n] = n;

    /* create the engine lock */
    MUTEX_Create( _engine.lock );

    HANDLE_Set( *engine, _engine );

    return TT_Err_Ok;

  Fail:
    TT_Done_FreeType( *engine );
    HANDLE_Set( *engine, NULL );
    return error;
  }


/*******************************************************************
 *
 *  Function    : TT_Done_FreeType
 *
 *  Description : The library's engine finalizer.  This function
 *                will discard all active face and glyph objects
 *                from the heap.
 *
 *  Input  :  None
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Done_FreeType( TT_Engine  engine )
  {
    PEngine_Instance  _engine = HANDLE_Engine( engine );

    if ( !_engine )
      return TT_Err_Ok;

    MUTEX_Destroy( engine.lock );

    TTRaster_Done( _engine );
    TTObjs_Done  ( _engine );
#ifdef TT_EXTEND_ENGINE
    TTExtend_Done( _engine );
#endif
    TTLists_Done ( _engine );
    TTFile_Done  ( _engine );
    TTMemory_Done( _engine );

    FREE( _engine );
    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Set_Raster_Gray_Palette
 *
 *  Description :  Sets the gray-levels palette used for font
 *                 smoothing.
 *
 *  Input  :  palette       address of palette (a 5 byte array)
 *
 *  Output :  invalid argument if 'palette' is NULL.
 *
 ******************************************************************/

  TT_Error  TT_Set_Raster_Gray_Palette( TT_Engine  engine, char*  palette )
  {  
    int  i;


    if ( !palette )
      return TT_Err_Invalid_Argument;

    for ( i = 0; i < 5; i++ )
      HANDLE_Engine( engine )->raster_palette[i] = palette[i];

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Open_Face
 *
 *  Description :  Creates a new face object from a given font file.
 *
 *  Input  :  fontpathname    the font file's pathname
 *            face            adress of returned face handle
 *
 *  Output :  Error code.
 *
 *  Note : the face handle is set to NULL in case of failure.
 *
 ******************************************************************/

  TT_Error  TT_Open_Face( TT_Engine    engine,
                          const char*  fontpathname,
                          TT_Face*     face )
  {
    PEngine_Instance  _engine = HANDLE_Engine( engine );

    TFont_Input  input;
    TT_Error     error;
    TT_Stream    stream;
    PFace        _face;

    if ( !_engine )
      return TT_Err_Invalid_Engine;

    /* open the file */
    error = TT_Open_Stream( fontpathname, &stream );
    if ( error )
      return error;

    input.stream    = stream;
    input.fontIndex = 0;
    input.engine    = _engine;

    /* Create and load the new face object */
    error = CACHE_New( _engine->objs_face_cache,
                       _face,
                       &input );

    /* Set the handle */
    HANDLE_Set( *face, _face );

    if ( error )
      goto Fail;

    return TT_Err_Ok;

  Fail:
    TT_Close_Stream( &stream );
    return error;
  }


/*******************************************************************
 *
 *  Function    :  TT_Open_Collection
 *
 *  Description :  Creates a new face object from a given font file.
 *
 *  Input  :  fontpathname    the font file's pathname
 *            face            adress of returned face handle
 *
 *  Output :  Error code.
 *
 *  Note : the face handle is set to NULL in case of failure.
 *
 ******************************************************************/

  TT_Error  TT_Open_Collection( TT_Engine    engine,
                                const char*  collectionpathname,
                                int          fontIndex,
                                TT_Face*     face )
  {
    PEngine_Instance  _engine = HANDLE_Engine( engine );

    TFont_Input  input;
    TT_Error     error;
    TT_Stream    stream;
    PFace        _face;


    if ( !_engine )
      return TT_Err_Invalid_Engine;

    /* open the file */
    error = TT_Open_Stream( collectionpathname, &stream );
    if ( error )
      return error;

    input.stream    = stream;
    input.fontIndex = fontIndex;
    input.engine    = _engine;

    /* Create and load the new face object */
    error = CACHE_New( _engine->objs_face_cache,
                       _face,
                       &input );

    /* Set the handle */
    HANDLE_Set( *face, _face );

    if ( error )
      goto Fail;

    return TT_Err_Ok;

  Fail:
    TT_Close_Stream( &stream );

    return error;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Face_Properties
 *
 *  Description :  Returns face properties.
 *
 *  Input  :  face        the face handle
 *            properties  address of target properties record
 *
 *  Output :  Error code.
 *
 *  Note : Currently, max_Faces is always set to 0.
 *
 ******************************************************************/

  TT_Error  TT_Get_Face_Properties( TT_Face              face,
                                    TT_Face_Properties*  properties )
  {
    PFace _face = HANDLE_Face( face );


    if ( !_face )
      return TT_Err_Invalid_Face_Handle;

    properties->num_Glyphs   = _face->numGlyphs;
    properties->max_Points   = _face->maxPoints;
    properties->max_Contours = _face->maxContours;

    properties->num_Faces    = _face->ttcHeader.DirCount;

    properties->header     = &_face->fontHeader;
    properties->horizontal = &_face->horizontalHeader;
    properties->os2        = &_face->os2;
    properties->postscript = &_face->postscript;
    properties->hdmx       = &_face->hdmx;

    return TT_Err_Ok;
  }

/*******************************************************************
 *
 *  Function    :  TT_Set_Face_Pointer
 *
 *  Description :  Each face object has one pointer, which use is
 *                 reserved to client applications. The TrueType       
 *                 engine never access or use this field.
 *
 *                 This function is used to set the pointer
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Set_Face_Pointer( TT_Face  face,
                                 void*    data )
  {
    PFace  faze = HANDLE_Face(face);
    if (!faze)
      return TT_Err_Invalid_Face_Handle;
    else
      faze->generic = data;
    return TT_Err_Ok;
  }

/*******************************************************************
 *
 *  Function    :  TT_Get_Face_Pointer
 *
 *  Description :  Each face object has one pointer, which use is
 *                 reserved to client applications. The TrueType       
 *                 engine never access or use this field.
 *
 *                 This function is used to read the pointer
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  void*     TT_Get_Face_Pointer( TT_Face  face )
  {
    PFace  faze = HANDLE_Face(face);
    if (!faze)
      return NULL;
    else
      return faze->generic;
  }


/*******************************************************************
 *
 *  Function    :  TT_Flush_Face
 *
 *  Description :  This function is used to close an active face's
 *                 file handle or descriptor. This is useful to save
 *                 system resources, if your application uses tons
 *                 of fonts.
 *
 *  Input  :  face    the given face handle
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Flush_Face( TT_Face  face )
  {
    PFace  faze = HANDLE_Face(face);
    if (!faze)
      return TT_Err_Invalid_Face_Handle;
    else
      return TT_Flush_Stream( &faze->stream );
  }

/*******************************************************************
 *
 *  Function    :  TT_Close_Face
 *
 *  Description :  Closes an opened face object.  This function
 *                 will destroy all objects associated to the
 *                 face, except the glyphs.
 *
 *  Input  :  face    the given face handle
 *
 *  Output :  Error code.
 *
 *  NOTE   :  the handle is set to NULL on exit.
 *
 ******************************************************************/

  TT_Error  TT_Close_Face( TT_Face  face )
  {
    PFace  _face = HANDLE_Face( face );


    if ( !_face )
      return TT_Err_Invalid_Face_Handle;

    TT_Close_Stream( &_face->stream );

    return CACHE_Done( _face->engine->objs_face_cache, _face );
  }


/*******************************************************************
 *
 *  Function    :  TT_New_Instance
 *
 *  Description :  Creates a new instance from a given face.
 *
 *  Input  :  face        parent face handle
 *            instance    address of resimt instance handle
 *            resolution  device resolution in dpi
 *            pointsize   point size
 *
 *  Output :  Error code.
 *
 *  Note   :  The handle is set to NULL in case of failure.
 *
 ******************************************************************/

  TT_Error  TT_New_Instance( TT_Face       face,
                             TT_Instance*  instance )
  {
    TT_Error   error;
    PFace      _face = HANDLE_Face( face );
    PInstance  _ins;


    if ( !_face )
      return TT_Err_Invalid_Face_Handle;

    /* get a new instance from the face's cache */
    error = CACHE_New( &_face->instances, _ins, _face );

    HANDLE_Set( *instance, _ins );

    if ( !error )
    {
      error = Instance_Init( _ins );
      if ( error )
      {
        HANDLE_Set( *instance, NULL );
        CACHE_Done( &_face->instances, _ins );
      }
    }

    return error;
  }


/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_Resolutions
 *
 *  Description :  Resets an instance to a new device resolution.
 *
 *  Input  :  instance      the instance handle
 *            x_resolution  new horizontal device resolution in dpi
 *            y_resolution  new vertical device resolution in dpi
 *
 *  Output :  Error code.
 *
 *  NOTE : y_resolution is currently ignored.
 *
 ******************************************************************/

  TT_Error  TT_Set_Instance_Resolutions( TT_Instance  instance,
                                         int          x_resolution,
                                         int          y_resolution )
  {
    PInstance  ins = HANDLE_Instance( instance );

    if ( !ins )
      return TT_Err_Invalid_Instance_Handle;

    ins->metrics.x_resolution = x_resolution;
    ins->metrics.y_resolution = y_resolution;
    ins->valid                = FALSE;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_CharSize
 *
 *  Description :  Resets an instance to new point size.
 *
 *  Input  :  instance      the instance handle
 *            pointsize     new point size in 26.6 format
 *
 *  Output :  Error code.
 *
 *  NOTE : y_resolution is currently ignored.
 *
 ******************************************************************/

  TT_Error  TT_Set_Instance_CharSizes( TT_Instance  instance,
                                       TT_F26Dot6   charWidth,
                                       TT_F26Dot6   charHeight )
  {
    PInstance  ins = HANDLE_Instance( instance );

    if ( !ins )
      return TT_Err_Invalid_Instance_Handle;

    if ( charWidth < 1*64 )
      charWidth = 1*64;

    if ( charHeight < 1*64 )
      charHeight = 1*64;

    ins->metrics.x_ppem = MulDiv_Round( charWidth,
                                        ins->metrics.x_resolution,
                                        64*72 );

    ins->metrics.y_ppem = MulDiv_Round( charHeight,
                                        ins->metrics.y_resolution,
                                        64*72 );

    if ( charWidth > charHeight )
      ins->metrics.pointSize = charWidth;
    else
      ins->metrics.pointSize = charHeight;

    ins->valid  = FALSE;

    return Instance_Reset( ins, FALSE );
  }


  TT_Error  TT_Set_Instance_CharSize( TT_Instance  instance,
                                      TT_F26Dot6   charSize )
  {
    return TT_Set_Instance_CharSizes( instance, charSize, charSize );
  }

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_PixelSizes
 *
 *  Description :  Resets an instance to new pixel sizes
 *
 *  Input  :  instance      the instance handle
 *            pixelWidth    
 *            pixelHeight
 *
 *  Output :  Error code.
 *
 *  NOTE : y_resolution is currently ignored.
 *
 ******************************************************************/

  TT_Error  TT_Set_Instance_PixelSizes( TT_Instance  instance,
                                        int          pixelWidth,
                                        int          pixelHeight,
                                        TT_F26Dot6   pointSize )
  {
    PInstance  ins = HANDLE_Instance( instance );

    if ( !ins )
      return TT_Err_Invalid_Instance_Handle;

    if ( pixelWidth  < 1 ) pixelWidth = 1;
    if ( pixelHeight < 1 ) pixelHeight = 1;

    ins->metrics.x_ppem    = pixelWidth;
    ins->metrics.y_ppem    = pixelHeight;
    ins->metrics.pointSize = pointSize;

    return Instance_Reset( ins, FALSE );
  }

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_Transform_Flags
 *
 *  Description :  Informs the interpreter about the transformations
 *                 that will be applied to the rendered glyphs.
 *
 *  Input  :  instance      the instance handle
 *            rotated       set to TRUE if the glyph are rotated
 *            stretched     set to TRUE if the glyph are stretched
 *
 *  Output :  Error code.
 *
 *  NOTE : y_resolution is currently ignored.
 *
 ******************************************************************/

  TT_Error  TT_Set_Instance_Transform_Flags( TT_Instance  instance,
                                             int          rotated,
                                             int          stretched )
  {
    PInstance  ins = HANDLE_Instance( instance );


    if ( !ins )
      return TT_Err_Invalid_Instance_Handle;

    ins->metrics.rotated   = rotated;
    ins->metrics.stretched = stretched;
    ins->valid             = FALSE;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Instance_Metrics
 *
 *  Description :  Returns instance metrics.
 *
 *  Input  :  instance   the instance handle
 *            metrics    address of target instance metrics record
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Get_Instance_Metrics( TT_Instance           instance,
                                     TT_Instance_Metrics*  metrics )
  {
    PInstance  ins = HANDLE_Instance( instance );


    if ( !ins )
     return TT_Err_Invalid_Instance_Handle;

    if ( !ins->valid )
      Instance_Reset( ins, FALSE );

    metrics->pointSize    = ins->metrics.pointSize;
    metrics->x_resolution = ins->metrics.x_resolution;
    metrics->y_resolution = ins->metrics.y_resolution;
    metrics->x_ppem       = ins->metrics.x_ppem;
    metrics->y_ppem       = ins->metrics.y_ppem;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_Pointer
 *
 *  Description :  Each instance has one pointer, which use is
 *                 reserved to client applications. The TrueType       
 *                 engine never access or use this field.
 *
 *                 This function is used to set the pointer
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Set_Instance_Pointer( TT_Instance  instance,
                                     void*        data )
  {
    PInstance  ins = HANDLE_Instance(instance);
    if (!ins)
      return TT_Err_Invalid_Instance_Handle;
    else
      ins->generic = data;
    return TT_Err_Ok;
  }

/*******************************************************************
 *
 *  Function    :  TT_Get_Instance_Pointer
 *
 *  Description :  Each instance has one pointer, which use is
 *                 reserved to client applications. The TrueType       
 *                 engine never access or use this field.
 *
 *                 This function is used to read the pointer
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  void*  TT_Get_Instance_Pointer( TT_Instance  instance )
  {
    PInstance  ins = HANDLE_Instance(instance);
    if (!ins)
      return NULL;
    else
      return ins->generic;
  }


/*******************************************************************
 *
 *  Function    :  TT_Done_Instance
 *
 *  Description :  Closes a given instance.
 *
 *  Input  :  instance   address of instance handle
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Done_Instance( TT_Instance  instance )
  {
    PInstance  ins = HANDLE_Instance( instance );


    if ( !ins )
      return TT_Err_Invalid_Instance_Handle;

    return CACHE_Done( &ins->owner->instances, ins );
  }


/*******************************************************************
 *
 *  Function    :  TT_New_Glyph
 *
 *  Description :  Creates a new glyph object related to a given
 *                 face.
 *
 *  Input  :  face       the face handle
 *            glyph      address of target glyph handle
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_New_Glyph( TT_Face    face,
                          TT_Glyph*  glyph )
  {
    TT_Error  error;
    PFace     _face = HANDLE_Face( face );
    PGlyph    _glyph;


    if ( !_face )
      return TT_Err_Invalid_Face_Handle;

    /* get a new glyph from the face's cache */
    error = CACHE_New( &_face->glyphs, _glyph, _face );

    HANDLE_Set( *glyph, _glyph );

    return error;
  }


/*******************************************************************
 *
 *  Function    :  TT_Done_Glyph
 *
 *  Description :  Destroys a given glyph object.
 *
 *  Input  :  glyph  the glyph handle
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Done_Glyph( TT_Glyph  glyph )
  {
    PGlyph  _glyph = HANDLE_Glyph( glyph );


    if ( !_glyph )
      return TT_Err_Invalid_Glyph_Handle;

    return CACHE_Done( &_glyph->face->glyphs, _glyph );
  }


/*******************************************************************
 *
 *  Function    :  TT_Load_Glyph
 *
 *  Description :  Loads a glyph.
 *
 *  Input  :  None
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Load_Glyph( TT_Instance  instance,
                           TT_Glyph     glyph,
                           int          glyph_index,
                           int          load_flags   )
  {
    PInstance  _ins;
    PGlyph     _glyph;
    TT_Error   error;

    _ins = HANDLE_Instance( instance );

    if ( !_ins )
      load_flags &= ~(TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);

    if ( (load_flags & TTLOAD_SCALE_GLYPH) == 0 )
      _ins = 0;

    _glyph = HANDLE_Glyph( glyph );
    if ( !_glyph )
      return TT_Err_Invalid_Glyph_Handle;

    if ( _ins )
    {
      if ( _ins->owner != _glyph->face )
        return TT_Err_Invalid_Face_Handle;
  
      if ( !_ins->valid )
      {
        error = Instance_Reset( _ins, FALSE );
        if ( error )
          return error;
      }
    }

    return Load_TrueType_Glyph( _ins, _glyph, glyph_index, load_flags );
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Outline
 *
 *  Description :  Returns the glyph's outline data.
 *
 *  Input  :  None
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  static void  Glyph2Outline( PGlyph  glyph, TT_Outline*  outline )
  {
    outline->points   = glyph->num_points;
    outline->contours = glyph->num_contours;

    outline->xCoord   = glyph->x_coord;
    outline->yCoord   = glyph->y_coord;
    outline->flag     = glyph->touch;
    outline->conEnds  = glyph->endContours;

    outline->owner = FALSE;
    outline->high_precision = glyph->high_precision;
    outline->second_pass    = (glyph->scan_type != 0);
    outline->dropout_mode   = glyph->scan_type;
  }

  TT_Error  TT_Get_Glyph_Outline( TT_Glyph     glyph,
                                  TT_Outline*  outline )
  {
    PGlyph  _glyph = HANDLE_Glyph( glyph );

    if ( !_glyph )
      return TT_Err_Invalid_Glyph_Handle;

    Glyph2Outline( _glyph, outline );

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Metrics
 *
 *  Description :  Extracts the glyph's metrics information.
 *
 *  Input  :  None
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Get_Glyph_Metrics( TT_Glyph           glyph,
                                  TT_Glyph_Metrics*  metrics )
  {
    PGlyph  _glyph = HANDLE_Glyph( glyph );


    if ( !_glyph )
      return TT_Err_Invalid_Glyph_Handle;

    metrics->bbox.xMin = _glyph->xMin;
    metrics->bbox.xMax = _glyph->xMax;
    metrics->bbox.yMin = _glyph->yMin;
    metrics->bbox.yMax = _glyph->yMax;

    metrics->advance   = _glyph->advanceWidth;
    metrics->bearingX  = _glyph->leftSideBearing;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Bitmap
 *
 *  Description :  Produces a bitmap from a glyph outline.
 *
 *  Input  :  glyph      the glyph container's handle
 *            map        target pixmap description block
 *            x_offset   x_offset in fractional pixels (26.6 format)
 *            y_offset   y_offset in fractional pixels (26.6 format)
 *
 *  Output :  Error code.
 *
 *  Note : Only use integer pixel offsets if you want to preserve
 *         the fine hints applied to the outline.  This means that
 *         x_offset and y_offset must be multiples of 64!
 *
 ******************************************************************/

  TT_Error  TT_Get_Glyph_Bitmap( TT_Glyph        glyph,
                                 TT_Raster_Map*  map,
                                 TT_F26Dot6      x_offset,
                                 TT_F26Dot6      y_offset )
  {
    PEngine_Instance  _engine;
    TT_Engine         engine;
    TT_Error  error;
    PGlyph    _glyph = HANDLE_Glyph( glyph );

    TT_Outline  outline;

    if ( !_glyph )
      return TT_Err_Invalid_Glyph_Handle;

    _engine = _glyph->face->engine;
    HANDLE_Set(engine,_engine);

    Glyph2Outline( _glyph, &outline );

    /* outline.dropout_mode = _glyph->scan_type; */
    outline.dropout_mode = 2;

    TT_Translate_Outline( &outline, x_offset, y_offset );
    error = TT_Get_Outline_Bitmap( engine, &outline, map );
    TT_Translate_Outline( &outline, -x_offset, -y_offset );

    return error;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Pixmap
 *
 *  Description :  Produces a grayscaled pixmap from a glyph
 *                 outline.
 *
 *  Input  :  glyph      the glyph container's handle
 *            map        target pixmap description block
 *            x_offset   x_offset in fractional pixels (26.6 format)
 *            y_offset   y_offset in fractional pixels (26.6 format)
 *
 *  Output :  Error code.
 *
 *  Note : Only use integer pixel offsets to preserve the fine
 *         hinting of the glyph and the 'correct' anti-aliasing
 *         (where vertical and horizontal stems aren't grayed).
 *         This means that x_offset and y_offset must be multiples
 *         of 64!
 *
 *         You can experiment with offsets of +32 to get 'blurred'
 *         versions of the glyphs (a nice effect at large sizes that
 *         some graphists may appreciate :)
 *
 ******************************************************************/

  TT_Error  TT_Get_Glyph_Pixmap( TT_Glyph        glyph,
                                 TT_Raster_Map*  map,
                                 TT_F26Dot6      x_offset,
                                 TT_F26Dot6      y_offset )
  {
    PEngine_Instance  _engine;
    TT_Engine         engine;
    TT_Error  error;
    PGlyph    _glyph = HANDLE_Glyph( glyph );

    TT_Outline  outline;

    if ( !_glyph )
      return TT_Err_Invalid_Glyph_Handle;

    _engine = _glyph->face->engine;
    HANDLE_Set(engine,_engine);

    Glyph2Outline( _glyph, &outline );

    /* outline.dropout_mode = _glyph->scan_type; */
    outline.dropout_mode = 2;

    TT_Translate_Outline( &outline, x_offset, y_offset );
    error = TT_Get_Outline_Pixmap( engine, &outline, map );
    TT_Translate_Outline( &outline, -x_offset, -y_offset );

    return error;
  }

  static const TT_Outline   empty_outline
      = { 0, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0 };


/*******************************************************************
 *
 *  Function    :  TT_New_Outline
 *
 *  Description :  Creates a new TrueType outline, reservinf
 *                 array space for a given number of points and
 *                 contours
 *
 *  Input  :  num_points     number of points
 *            num_contours   number of contours
 *            outline        address of target outline structure
 *
 *  Output :  Error code
 *
 ******************************************************************/

  TT_Error  TT_New_Outline( int          num_points,
                            int          num_contours,
                            TT_Outline*  outline )
  {
    TT_Error  error;
    long      l;

    if ( num_points < 0 || num_contours < 0 || !outline )
      return TT_Err_Invalid_Argument;

    *outline = empty_outline;

    l = num_points*sizeof(TT_F26Dot6);

    if ( ALLOC( outline->xCoord,  num_points*sizeof(TT_F26Dot6) ) ||
         ALLOC( outline->yCoord,  num_points*sizeof(TT_F26Dot6) ) ||
         ALLOC( outline->flag,    num_points*sizeof(Byte)       ) ||
         ALLOC( outline->conEnds, num_contours*sizeof(UShort) ) )
      goto Fail;

    outline->points   = num_points;
    outline->contours = num_contours;
    outline->owner    = TRUE;
    return TT_Err_Ok;

  Fail:
    outline->owner = TRUE;
    TT_Done_Outline( outline );
    return error;
  }

/*******************************************************************
 *
 *  Function    :  TT_Done_Outline
 *
 *  Description :  Deletes an outline created through TT_New_Outline
 *                 calling this function for the outlines returned
 *                 by TT_Get_Glyph_Outline is an error
 *
 *  Input  :  outline        address of outline
 *
 *  Output :  Error code
 *
 ******************************************************************/

  TT_Error  TT_Done_Outline( TT_Outline*  outline )
  {
    if (outline)
    {
      if (outline->owner)
      {
        FREE( outline->xCoord );
        FREE( outline->yCoord );
        FREE( outline->flag );
        FREE( outline->conEnds );
      }
      *outline = empty_outline;
      return TT_Err_Ok;
    }
    else
      return TT_Err_Invalid_Argument;
  }

/*******************************************************************
 *
 *  Function    :  TT_Get_Outline_Bitmap
 *
 *  Description :  Render a TrueType outline into a bitmap.         
 *                 Note that the bitmap must be created by the caller
 *
 *  Input  :  outline        the outline to render     
 *            raster_map     the target bitmap         
 *
 *  Output :  Error code
 *
 ******************************************************************/

  TT_Error  TT_Get_Outline_Bitmap( TT_Engine       engine,
                                   TT_Outline*     outline,
                                   TT_Raster_Map*  raster_map )
  {
    PEngine_Instance  _engine = HANDLE_Engine(engine);

    if ( !_engine )
      return TT_Err_Invalid_Engine;

    if ( !outline || !raster_map )
      return TT_Err_Invalid_Argument;

    return RENDER_Glyph( outline, raster_map );
  }

/*******************************************************************
 *
 *  Function    :  TT_Get_Outline_Pixmap
 *
 *  Description :  Render a TrueType outline into a pixmap.         
 *                 Note that the pixmap must be created by the caller
 *
 *  Input  :  outline        the outline to render     
 *            raster_map     the target bitmap         
 *
 *  Output :  Error code
 *
 ******************************************************************/

  TT_Error  TT_Get_Outline_Pixmap( TT_Engine       engine,
                                   TT_Outline*     outline,
                                   TT_Raster_Map*  raster_map )
  {
    PEngine_Instance  _engine = HANDLE_Engine(engine);

    if ( !_engine )
      return TT_Err_Invalid_Engine;

    if ( !outline || !raster_map )
      return TT_Err_Invalid_Argument;

    return RENDER_Gray_Glyph( outline, raster_map, _engine->raster_palette );
  }

/*******************************************************************
 *
 *  Function    :  TT_Copy_Outline
 *
 *  Description :  Copy an outline into another. The source and     
 *                 target outlines must have the same points and   
 *                 contours numbers.                    
 *
 *  Input  :  source         address of source outline
 *            target         address of target outline
 *
 *  Output :  Error code
 *
 *  Note : this function doesn't touch the target outline's "owner"
 *         field.
 *
 ******************************************************************/

  TT_Error  TT_Copy_Outline( TT_Outline*  source,
                             TT_Outline*  target )
  {
    if ( !source || !target || 
         source->points != target->points ||
         source->contours != target->contours )
      return TT_Err_Invalid_Argument;

    MEM_Copy( target->xCoord, source->xCoord, 
              source->points*sizeof(TT_F26Dot6) );

    MEM_Copy( target->yCoord, source->yCoord, 
              source->points*sizeof(TT_F26Dot6) );
    
    MEM_Copy( target->flag, source->flag, source->points*sizeof(Byte));

    MEM_Copy( target->conEnds, source->conEnds,
              source->contours*sizeof(UShort) );

    target->high_precision = source->high_precision;
    target->second_pass    = target->second_pass;
    target->dropout_mode   = source->dropout_mode;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Transform_Outline
 *
 *  Description :  Applies a simple transformation to an outline.
 *
 *  Input  :  outline     the glyph's outline. Can be extracted
 *                        from a glyph container through
 *                        TT_Get_Glyph_Outline
 *
 *            matrix      simple matrix with 16.16 fixed floats
 *
 *  Output :  Error code (always TT_Err_Ok).
 *
 ******************************************************************/

  void  TT_Transform_Outline( TT_Outline*  outline,
                              TT_Matrix*   matrix )
  {	
  	Int         n;
    TT_F26Dot6  x, y;

    for ( n = 0; n < outline->points; n++ )
    {
      x = MulDiv_Round( outline->xCoord[n], matrix->xx, 0x10000 ) +
          MulDiv_Round( outline->yCoord[n], matrix->xy, 0x10000 );

      y = MulDiv_Round( outline->xCoord[n], matrix->yx, 0x10000 ) +
          MulDiv_Round( outline->yCoord[n], matrix->yy, 0x10000 );

      outline->xCoord[n] = x;
      outline->yCoord[n] = y;
    }
  }  


/*******************************************************************
 *
 *  Function    :  TT_Transform_Vector
 *
 *  Description :  Apply a simple transform to a vector
 *
 *  Input  :  x, y        the vector.
 *
 *            matrix      simple matrix with 16.16 fixed floats
 *
 *  Output :  Error code. (always TT_Err_Ok)
 *
 ******************************************************************/

  void  TT_Transform_Vector( TT_F26Dot6*  x,
                             TT_F26Dot6*  y,
                             TT_Matrix*   matrix )
  {
    TT_F26Dot6  xz, yz;

    xz = MulDiv_Round( *x, matrix->xx, 0x10000 ) +
         MulDiv_Round( *y, matrix->xy, 0x10000 );

    yz = MulDiv_Round( *x, matrix->yx, 0x10000 ) +
         MulDiv_Round( *y, matrix->yy, 0x10000 );

    *x = xz;
    *y = yz;
  }


/*******************************************************************
 *
 *  Function    :  TT_Translate_Outline
 *
 *  Description :  Applies a simple translation.
 *
 *  Input  :  outline   no comment :)
 *            x_offset
 *            y_offset
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  void      TT_Translate_Outline( TT_Outline*  outline,
                                  TT_F26Dot6   x_offset,
                                  TT_F26Dot6   y_offset )
  {
    Int  n;

    for ( n = 0; n < outline->points; n++ )
    {
      outline->xCoord[n] += x_offset;
      outline->yCoord[n] += y_offset;
    }
  }

/*******************************************************************
 *
 *  Function    :  TT_Get_Outline_BBox
 *
 *  Description :  returns an outline's bounding box
 *
 *  Input  :  outline   no comment :)
 *            bbox      guess what //
 *
 *  Output :  Error code.
 *
 ******************************************************************/

  TT_Error  TT_Get_Outline_BBox( TT_Outline*  outline,
                                 TT_BBox*     bbox )
  {
    TT_F26Dot6  x, y;
    int         k;

    if (outline && bbox)
    {
      if ( outline->points <= 0 )
      {
        bbox->xMin = 0;
        bbox->yMin = 0;
        bbox->xMax = 0;
        bbox->yMax = 0;
      }
      else
      {
        bbox->xMin = bbox->xMax = outline->xCoord[0];
        bbox->yMin = bbox->yMax = outline->yCoord[0];

        for ( k = 1; k < outline->points; k++ )
        {
          x = outline->xCoord[k];
          if ( x < bbox->xMin ) bbox->xMin = x;
          if ( x > bbox->xMax ) bbox->xMax = x;
          y = outline->yCoord[k];
          if ( y < bbox->yMin ) bbox->yMin = y;
          if ( y > bbox->yMax ) bbox->yMax = y;
        }
      }
      return TT_Err_Ok;
    }    
    else
      return TT_Err_Invalid_Argument;
  }



  /* ----------------- character mappings support ------------- */

/*******************************************************************
 *
 *  Function    :  TT_Get_CharMap_Count
 *
 *  Description :  Returns the number of charmaps in a given face.
 *
 *  Input  :  face   face object handle
 *
 *  Output :  Number of tables. -1 in case of error (bad handle).
 *
 ******************************************************************/

  int  TT_Get_CharMap_Count( TT_Face  face )
  {
    PFace  faze = HANDLE_Face( face );

    if ( !faze )
      return -1;

    return faze->numCMaps;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_CharMap_ID
 *
 *  Description :  Returns the ID of a given charmap.
 *
 *  Input  :  face             face object handle
 *            charmapIndex     index of charmap in directory
 *            platformID       address of returned platform ID
 *            encodingID       address of returned encoding ID
 *
 *  Output :  error code
 *
 ******************************************************************/

  TT_Error  TT_Get_CharMap_ID( TT_Face  face,
                               int      charmapIndex,
                               short*   platformID,
                               short*   encodingID )
  {
    PCMapTable  cmap;
    PFace       faze = HANDLE_Face( face );


    if ( !faze )
      return TT_Err_Invalid_Face_Handle;

    if ( charmapIndex < 0 || charmapIndex >= faze->numCMaps )
      return TT_Err_Bad_Argument;

    cmap = faze->cMaps + charmapIndex;

    *platformID = cmap->platformID;
    *encodingID = cmap->platformEncodingID;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_CharMap
 *
 *  Description :  Looks up a charmap.
 *
 *  Input  :  face          face object handle
 *            charmapIndex  index of charmap in directory
 *            charMap       address of returned charmap handle
 *
 *  Output :  error code.
 *
 ******************************************************************/

  TT_Error  TT_Get_CharMap( TT_Face      face,
                            int          charmapIndex,
                            TT_CharMap*  charMap )
  {
    TT_Error    error;
    TT_Stream   stream;
    PCMapTable  cmap;
    PFace       faze = HANDLE_Face( face );


    if ( !faze )
      return TT_Err_Invalid_Face_Handle;

    if ( charmapIndex < 0 || charmapIndex >= faze->numCMaps )
      return TT_Err_Bad_Argument;

    cmap = faze->cMaps + charmapIndex;

    /* Load table if needed */

    error = TT_Err_Ok;

    if ( !cmap->loaded )
    {
      USE_Stream( faze->stream, stream );
      if ( !error )
      {
        error = CharMap_Load( cmap, stream );
        TT_Done_Stream( &stream );
      }

      if ( error )
        cmap = NULL;
      else
        cmap->loaded = TRUE;
    }

    HANDLE_Set( *charMap, cmap );

    return error;
  }


/*******************************************************************
 *
 *  Function    :  TT_Char_Index
 *
 *  Description :  Returns the glyph index corresponding to
 *                 a given charcode defined for the 'charmap'.
 *
 *  Input  :  charMap    charmap handle
 *            charcode   character code in locale
 *
 *  Output :  glyph index.
 *
 *  Notes  :  Char code 0 is the unknown glyph, which should never
 *            be displayed.
 *
 ******************************************************************/

  int  TT_Char_Index( TT_CharMap      charMap,
                      unsigned short  charCode )
  {
    PCMapTable  cmap = HANDLE_CharMap( charMap );

    if (!cmap)
      return 0;  /* we return 0 in case of invalid char map */

    return CharMap_Index( cmap, charCode );
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Name_Count
 *
 *  Description :  Returns the number of strings found in the
 *                 name table.
 *
 *  Input  :  face   face handle
 *
 *  Output :  number of strings.
 *
 *  Notes  :  Returns -1 on error (invalid handle).
 *
 ******************************************************************/

  int  TT_Get_Name_Count( TT_Face  face )
  {
    PFace  faze = HANDLE_Face( face );


    if ( !faze )
      return TT_Err_Invalid_Face_Handle;

    return faze->nameTable.numNameRecords;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Name_ID
 *
 *  Description :  Returns the IDs of the string number 'nameIndex'
 *                 in the name table of a given face.
 *
 *  Input  :  face        face handle
 *            nameIndex   index of string. First is 0
 *            platformID  addresses of returned IDs
 *            encodingID
 *            languageID
 *            nameID
 *
 *  Output :  Error code.
 *
 *  Notes  :  Some files have a corrupt name table, some of their
 *            entries having a platformID > 3.  These should be
 *            ignored by a client application.
 *
 ******************************************************************/

  TT_Error  TT_Get_Name_ID( TT_Face  face,
                            int      nameIndex,
                            short*   platformID,
                            short*   encodingID,
                            short*   languageID,
                            short*   nameID )
  {
    TNameRec*  namerec;
    PFace      faze = HANDLE_Face( face );


    if ( !faze )
      return TT_Err_Invalid_Face_Handle;

    if ( nameIndex < 0 || nameIndex >= faze->nameTable.numNameRecords )
      return TT_Err_Bad_Argument;

    namerec = faze->nameTable.names + nameIndex;

    *platformID = namerec->platformID;
    *encodingID = namerec->encodingID;
    *languageID = namerec->languageID;
    *nameID     = namerec->nameID;

    return TT_Err_Ok;
  }


/*******************************************************************
 *
 *  Function    :  TT_Get_Name_String
 *
 *  Description :  Returns the address and length of a given
 *                 string found in the name table.
 *
 *  Input  :  face        face handle
 *            nameIndex   string index
 *            stringPtr   address of returned pointer to string
 *            length      address of returned string length
 *
 *  Output :  Error code.
 *
 *  Notes  :  If the string's platformID is > 3 (which denotes
 *            an invalid entry in the name table), the returned
 *            pointer is NULL, and the length is 0.
 *
 ******************************************************************/

  TT_Error  TT_Get_Name_String( TT_Face  face,
                                int      nameIndex,
                                char**   stringPtr,
                                int*     length )
  {
    TNameRec*  namerec;
    PFace      faze = HANDLE_Face( face );


    if ( !faze )
      return TT_Err_Invalid_Face_Handle;

    if ( nameIndex < 0 || nameIndex >= faze->nameTable.numNameRecords )
      return TT_Err_Bad_Argument;

    namerec = faze->nameTable.names + nameIndex;

    *stringPtr = (char*)namerec->string;
    *length    = namerec->stringLength;

    return TT_Err_Ok;
  }

/*******************************************************************
 *
 *  Function    :  TT_Get_Font_Data
 *
 *  Description :  Loads any font table in client memory. Used by
 *                 the TT_Get_Font_Data API
 *
 *  Input  :  face     face object to look for
 *            tag      tag of table to load, the whole font file if 0 
 *            offset   starting offset in the table
 *            buffer   address of target buffer
 *
 *            length   on input  : number of bytes to read
 *                     on output : if input is 0, returns the
 *                                 table or file's size in bytes
 *  Output :  Error condition
 *
 ******************************************************************/

  TT_Error  TT_Get_Font_Data( TT_Face  face,
                              long     tag,
                              long     offset,
                              void*    buffer,
                              long*    length )
  {
    PFace faze = HANDLE_Face( face );

    if (!faze)
      return TT_Err_Invalid_Face_Handle;

    return Load_TrueType_Any( faze, tag, offset, buffer, length );
  }

  /************************ callback definition ******************/

  /* Register a new callback to the TrueType engine - this should */
  /* only be used by higher-level libraries, not typical clients  */

  TT_Error  TT_Register_Callback( TT_Engine  engine,
                                  int        callback_id,
                                  void*      callback_ptr )
  {
    PEngine_Instance  eng = HANDLE_Engine(engine);
    if (!eng)
      return TT_Err_Invalid_Argument;

    /* currently, we only support one callback */
    if (callback_id != TT_Callback_Glyph_Outline_Load)
      return TT_Err_Invalid_Argument;

    eng->glCallback = (TT_Glyph_Loader_Callback)callback_ptr;
    return TT_Err_Ok;
  }

/* END */
