code:
/***************************************************************************/
/*                                                                         */
/*  ftbitmap.c                                                             */
/*                                                                         */
/*    FreeType utility functions for bitmaps (body).                       */
/*                                                                         */
/*  Copyright 2004, 2005, 2006, 2007, 2008, 2009 by                        */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_BITMAP_H
#include FT_IMAGE_H
#include FT_INTERNAL_OBJECTS_H

  static
  const FT_Bitmap  null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 };

  /* documentation is in ftbitmap.h */

  FT_EXPORT_DEF( void )
  FT_Bitmap_New( FT_Bitmap  *abitmap )
  {
    *abitmap = null_bitmap;
  }

  /* documentation is in ftbitmap.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Bitmap_Copy( FT_Library        library,
                  const FT_Bitmap  *source,
                  FT_Bitmap        *target)
  {
    FT_Memory  memory = library->memory;
    FT_Error   error  = FT_Err_Ok;
    FT_Int     pitch  = source->pitch;
    FT_ULong   size;

    if ( source == target )
      return FT_Err_Ok;

    if ( source->buffer == NULL )
    {
      *target = *source;

      return FT_Err_Ok;
    }

    if ( pitch < 0 )
      pitch = -pitch;
    size = (FT_ULong)( pitch * source->rows );

    if ( target->buffer )
    {
      FT_Int    target_pitch = target->pitch;
      FT_ULong  target_size;

      if ( target_pitch < 0  )
        target_pitch = -target_pitch;
      target_size = (FT_ULong)( target_pitch * target->rows );

      if ( target_size != size )
        (void)FT_QREALLOC( target->buffer, target_size, size );
    }
    else
      (void)FT_QALLOC( target->buffer, size );

    if ( !error )
    {
      unsigned char *p;

      p = target->buffer;
      *target = *source;
      target->buffer = p;

      FT_MEM_COPY( target->buffer, source->buffer, size );
    }

    return error;
  }

  static FT_Error
  ft_bitmap_assure_buffer( FT_Memory   memory,
                           FT_Bitmap*  bitmap,
                           FT_UInt     xpixels,
                           FT_UInt     ypixels )
  {
    FT_Error        error;
    int             pitch;
    int             new_pitch;
    FT_UInt         bpp;
    FT_Int          i, width, height;
    unsigned char*  buffer;

    width  = bitmap->width;
    height = bitmap->rows;
    pitch  = bitmap->pitch;
    if ( pitch < 0 )
      pitch = -pitch;

    switch ( bitmap->pixel_mode )
    {
    case FT_PIXEL_MODE_MONO:
      bpp       = 1;
      new_pitch = ( width + xpixels + 7 ) >> 3;
      break;
    case FT_PIXEL_MODE_GRAY2:
      bpp       = 2;
      new_pitch = ( width + xpixels + 3 ) >> 2;
      break;
    case FT_PIXEL_MODE_GRAY4:
      bpp       = 4;
      new_pitch = ( width + xpixels + 1 ) >> 1;
      break;
    case FT_PIXEL_MODE_GRAY:
    case FT_PIXEL_MODE_LCD:
    case FT_PIXEL_MODE_LCD_V:
      bpp       = 8;
      new_pitch = ( width + xpixels );
      break;
    default:
      return FT_Err_Invalid_Glyph_Format;
    }

    /* if no need to allocate memory */
    if ( ypixels == 0 && new_pitch <= pitch )
    {
      /* zero the padding */
      FT_Int  bit_width = pitch * 8;
      FT_Int  bit_last  = ( width + xpixels ) * bpp;

      if ( bit_last < bit_width )
      {
        FT_Byte*  line  = bitmap->buffer + ( bit_last >> 3 );
        FT_Byte*  end   = bitmap->buffer + pitch;
        FT_Int    shift = bit_last & 7;
        FT_UInt   mask  = 0xFF00U >> shift;
        FT_Int    count = height;

        for ( ; count > 0; count--, line += pitch, end += pitch )
        {
          FT_Byte*  write = line;

          if ( shift > 0 )
          {
            write[0] = (FT_Byte)( write[0] & mask );
            write++;
          }
          if ( write < end )
            FT_MEM_ZERO( write, end-write );
        }
      }

      return FT_Err_Ok;
    }

    if ( FT_QALLOC_MULT( buffer, new_pitch, bitmap->rows + ypixels ) )
      return error;

    if ( bitmap->pitch > 0 )
    {
      FT_Int  len = ( width * bpp + 7 ) >> 3;

      for ( i = 0; i < bitmap->rows; i++ )
        FT_MEM_COPY( buffer + new_pitch * ( ypixels + i ),
                     bitmap->buffer + pitch * i, len );
    }
    else
    {
      FT_Int  len = ( width * bpp + 7 ) >> 3;

      for ( i = 0; i < bitmap->rows; i++ )
        FT_MEM_COPY( buffer + new_pitch * i,
                     bitmap->buffer + pitch * i, len );
    }

    FT_FREE( bitmap->buffer );
    bitmap->buffer = buffer;

    if ( bitmap->pitch < 0 )
      new_pitch = -new_pitch;

    /* set pitch only, width and height are left untouched */
    bitmap->pitch = new_pitch;

    return FT_Err_Ok;
  }

  /* documentation is in ftbitmap.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Bitmap_Embolden( FT_Library  library,
                      FT_Bitmap*  bitmap,
                      FT_Pos      xStrength,
                      FT_Pos      yStrength )
  {
    FT_Error        error;
    unsigned char*  p;
    FT_Int          i, x, y, pitch;
    FT_Int          xstr, ystr;

    if ( !library )
      return FT_Err_Invalid_Library_Handle;

    if ( !bitmap || !bitmap->buffer )
      return FT_Err_Invalid_Argument;

    if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) ||
         ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) )
      return FT_Err_Invalid_Argument;

    xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6;
    ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6;

    if ( xstr == 0 && ystr == 0 )
      return FT_Err_Ok;
    else if ( xstr < 0 || ystr < 0 )
      return FT_Err_Invalid_Argument;

    switch ( bitmap->pixel_mode )
    {
    case FT_PIXEL_MODE_GRAY2:
    case FT_PIXEL_MODE_GRAY4:
      {
        FT_Bitmap  tmp;
        FT_Int     align;

        if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY2 )
          align = ( bitmap->width + xstr + 3 ) / 4;
        else
          align = ( bitmap->width + xstr + 1 ) / 2;

        FT_Bitmap_New( &tmp );

        error = FT_Bitmap_Convert( library, bitmap, &tmp, align );
        if ( error )
          return error;

        FT_Bitmap_Done( library, bitmap );
        *bitmap = tmp;
      }
      break;

    case FT_PIXEL_MODE_MONO:
      if ( xstr > 8 )
        xstr = 8;
      break;

    case FT_PIXEL_MODE_LCD:
      xstr *= 3;
      break;

    case FT_PIXEL_MODE_LCD_V:
      ystr *= 3;
      break;
    }

    error = ft_bitmap_assure_buffer( library->memory, bitmap, xstr, ystr );
    if ( error )
      return error;

    pitch = bitmap->pitch;
    if ( pitch > 0 )
      p = bitmap->buffer + pitch * ystr;
    else
    {
      pitch = -pitch;
      p = bitmap->buffer + pitch * ( bitmap->rows - 1 );
    }

    /* for each row */
    for ( y = 0; y < bitmap->rows ; y++ )
    {
      /*
       * Horizontally:
       *
       * From the last pixel on, make each pixel or'ed with the
       * `xstr' pixels before it.
       */
      for ( x = pitch - 1; x >= 0; x-- )
      {
        unsigned char tmp;

        tmp = p[x];
        for ( i = 1; i <= xstr; i++ )
        {
          if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO )
          {
            p[x] |= tmp >> i;

            /* the maximum value of 8 for `xstr' comes from here */
            if ( x > 0 )
              p[x] |= p[x - 1] << ( 8 - i );

#if 0
            if ( p[x] == 0xff )
              break;
#endif
          }
          else
          {
            if ( x - i >= 0 )
            {
              if ( p[x] + p[x - i] > bitmap->num_grays - 1 )
              {
                p[x] = (unsigned char)(bitmap->num_grays - 1);
                break;
              }
              else
              {
                p[x] = (unsigned char)(p[x] + p[x-i]);
                if ( p[x] == bitmap->num_grays - 1 )
                  break;
              }
            }
            else
              break;
          }
        }
      }

      /*
       * Vertically:
       *
       * Make the above `ystr' rows or'ed with it.
       */
      for ( x = 1; x <= ystr; x++ )
      {
        unsigned char*  q;

        q = p - bitmap->pitch * x;
        for ( i = 0; i < pitch; i++ )
          q[i] |= p[i];
      }

      p += bitmap->pitch;
    }

    bitmap->width += xstr;
    bitmap->rows += ystr;

    return FT_Err_Ok;
  }

  /* documentation is in ftbitmap.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Bitmap_Convert( FT_Library        library,
                     const FT_Bitmap  *source,
                     FT_Bitmap        *target,
                     FT_Int            alignment )
  {
    FT_Error   error = FT_Err_Ok;
    FT_Memory  memory;

    if ( !library )
      return FT_Err_Invalid_Library_Handle;

    memory = library->memory;

    switch ( source->pixel_mode )
    {
    case FT_PIXEL_MODE_MONO:
    case FT_PIXEL_MODE_GRAY:
    case FT_PIXEL_MODE_GRAY2:
    case FT_PIXEL_MODE_GRAY4:
    case FT_PIXEL_MODE_LCD:
    case FT_PIXEL_MODE_LCD_V:
      {
        FT_Int   pad;
        FT_Long  old_size;

        old_size = target->rows * target->pitch;
        if ( old_size < 0 )
          old_size = -old_size;

        target->pixel_mode = FT_PIXEL_MODE_GRAY;
        target->rows       = source->rows;
        target->width      = source->width;

        pad = 0;
        if ( alignment > 0 )
        {
          pad = source->width % alignment;
          if ( pad != 0 )
            pad = alignment - pad;
        }

        target->pitch = source->width + pad;

        if ( target->rows * target->pitch > old_size             &&
             FT_QREALLOC( target->buffer,
                          old_size, target->rows * target->pitch ) )
          return error;
      }
      break;

    default:
      error = FT_Err_Invalid_Argument;
    }

    switch ( source->pixel_mode )
    {
    case FT_PIXEL_MODE_MONO:
      {
        FT_Byte*  s = source->buffer;
        FT_Byte*  t = target->buffer;
        FT_Int    i;

        target->num_grays = 2;

        for ( i = source->rows; i > 0; i-- )
        {
          FT_Byte*  ss = s;
          FT_Byte*  tt = t;
          FT_Int    j;

          /* get the full bytes */
          for ( j = source->width >> 3; j > 0; j-- )
          {
            FT_Int  val = ss[0]; /* avoid a byte->int cast on each line */

            tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 );
            tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 );
            tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 );
            tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 );
            tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 );
            tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 );
            tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 );
            tt[7] = (FT_Byte)(   val & 0x01 );

            tt += 8;
            ss += 1;
          }

          /* get remaining pixels (if any) */
          j = source->width & 7;
          if ( j > 0 )
          {
            FT_Int  val = *ss;

            for ( ; j > 0; j-- )
            {
              tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7);
              val <<= 1;
              tt   += 1;
            }
          }

          s += source->pitch;
          t += target->pitch;
        }
      }
      break;

    case FT_PIXEL_MODE_GRAY:
    case FT_PIXEL_MODE_LCD:
    case FT_PIXEL_MODE_LCD_V:
      {
        FT_Int    width   = source->width;
        FT_Byte*  s       = source->buffer;
        FT_Byte*  t       = target->buffer;
        FT_Int    s_pitch = source->pitch;
        FT_Int    t_pitch = target->pitch;
        FT_Int    i;

        target->num_grays = 256;

        for ( i = source->rows; i > 0; i-- )
        {
          FT_ARRAY_COPY( t, s, width );

          s += s_pitch;
          t += t_pitch;
        }
      }
      break;

    case FT_PIXEL_MODE_GRAY2:
      {
        FT_Byte*  s = source->buffer;
        FT_Byte*  t = target->buffer;
        FT_Int    i;

        target->num_grays = 4;

        for ( i = source->rows; i > 0; i-- )
        {
          FT_Byte*  ss = s;
          FT_Byte*  tt = t;
          FT_Int    j;

          /* get the full bytes */
          for ( j = source->width >> 2; j > 0; j-- )
          {
            FT_Int  val = ss[0];

            tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
            tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 );
            tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 );
            tt[3] = (FT_Byte)( ( val & 0x03 ) );

            ss += 1;
            tt += 4;
          }

          j = source->width & 3;
          if ( j > 0 )
          {
            FT_Int  val = ss[0];

            for ( ; j > 0; j-- )
            {
              tt[0]  = (FT_Byte)( ( val & 0xC0 ) >> 6 );
              val  <<= 2;
              tt    += 1;
            }
          }

          s += source->pitch;
          t += target->pitch;
        }
      }
      break;

    case FT_PIXEL_MODE_GRAY4:
      {
        FT_Byte*  s = source->buffer;
        FT_Byte*  t = target->buffer;
        FT_Int    i;

        target->num_grays = 16;

        for ( i = source->rows; i > 0; i-- )
        {
          FT_Byte*  ss = s;
          FT_Byte*  tt = t;
          FT_Int    j;

          /* get the full bytes */
          for ( j = source->width >> 1; j > 0; j-- )
          {
            FT_Int  val = ss[0];

            tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 );
            tt[1] = (FT_Byte)( ( val & 0x0F ) );

            ss += 1;
            tt += 2;
          }

          if ( source->width & 1 )
            tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 );

          s += source->pitch;
          t += target->pitch;
        }
      }
      break;

    default:
      ;
    }

    return error;
  }

  /* documentation is in ftbitmap.h */

  FT_EXPORT_DEF( FT_Error )
  FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot  slot )
  {
    if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP   &&
         !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
    {
      FT_Bitmap  bitmap;
      FT_Error   error;

      FT_Bitmap_New( &bitmap );
      error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap );
      if ( error )
        return error;

      slot->bitmap = bitmap;
      slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    }

    return FT_Err_Ok;
  }

  /* documentation is in ftbitmap.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Bitmap_Done( FT_Library  library,
                  FT_Bitmap  *bitmap )
  {
    FT_Memory  memory;

    if ( !library )
      return FT_Err_Invalid_Library_Handle;

    if ( !bitmap )
      return FT_Err_Invalid_Argument;

    memory = library->memory;

    FT_FREE( bitmap->buffer );
    *bitmap = null_bitmap;

    return FT_Err_Ok;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftcid.c                                                                */
/*                                                                         */
/*    FreeType API for accessing CID font information.                     */
/*                                                                         */
/*  Copyright 2007, 2009 by Derek Clegg, Michael Toftdal.                  */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_CID_H
#include FT_INTERNAL_OBJECTS_H
#include FT_SERVICE_CID_H

  /* documentation is in ftcid.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Get_CID_Registry_Ordering_Supplement( FT_Face       face,
                                           const char*  *registry,
                                           const char*  *ordering,
                                           FT_Int       *supplement)
  {
    FT_Error     error;
    const char*  r = NULL;
    const char*  o = NULL;
    FT_Int       s = 0;

    error = FT_Err_Invalid_Argument;

    if ( face )
    {
      FT_Service_CID  service;

      FT_FACE_FIND_SERVICE( face, service, CID );

      if ( service && service->get_ros )
        error = service->get_ros( face, &r, &o, &s );
    }

    if ( registry )
      *registry = r;

    if ( ordering )
      *ordering = o;

    if ( supplement )
      *supplement = s;

    return error;
  }

  FT_EXPORT_DEF( FT_Error )
  FT_Get_CID_Is_Internally_CID_Keyed( FT_Face   face,
                                      FT_Bool  *is_cid )
  {
    FT_Error  error = FT_Err_Invalid_Argument;
    FT_Bool   ic = 0;

    if ( face )
    {
      FT_Service_CID  service;

      FT_FACE_FIND_SERVICE( face, service, CID );

      if ( service && service->get_is_cid )
        error = service->get_is_cid( face, &ic);
    }

    if ( is_cid )
      *is_cid = ic;

    return error;
  }

  FT_EXPORT_DEF( FT_Error )
  FT_Get_CID_From_Glyph_Index( FT_Face   face,
                               FT_UInt   glyph_index,
                               FT_UInt  *cid )
  {
    FT_Error  error = FT_Err_Invalid_Argument;
    FT_UInt   c = 0;

    if ( face )
    {
      FT_Service_CID  service;

      FT_FACE_FIND_SERVICE( face, service, CID );

      if ( service && service->get_cid_from_glyph_index )
        error = service->get_cid_from_glyph_index( face, glyph_index, &c);
    }

    if ( cid )
      *cid = c;

    return error;
  }

/* END */

license: mit


code:
/***************************************************************************/
/*                                                                         */
/*  ftdbgmem.c                                                             */
/*                                                                         */
/*    Memory debugger (body).                                              */
/*                                                                         */
/*  Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2009 by                  */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_MEMORY_H
#include FT_SYSTEM_H
#include FT_ERRORS_H
#include FT_TYPES_H

#ifdef FT_DEBUG_MEMORY

#define  KEEPALIVE /* `Keep alive' means that freed blocks aren't released
                    * to the heap.  This is useful to detect double-frees
                    * or weird heap corruption, but it uses large amounts of
                    * memory, however.
                    */

#include FT_CONFIG_STANDARD_LIBRARY_H

  FT_BASE_DEF( const char* )  _ft_debug_file   = 0;
  FT_BASE_DEF( long )         _ft_debug_lineno = 0;

  extern void
  FT_DumpMemory( FT_Memory  memory );

  typedef struct FT_MemSourceRec_*  FT_MemSource;
  typedef struct FT_MemNodeRec_*    FT_MemNode;
  typedef struct FT_MemTableRec_*   FT_MemTable;

#define FT_MEM_VAL( addr )  ((FT_PtrDist)(FT_Pointer)( addr ))

  /*
   *  This structure holds statistics for a single allocation/release
   *  site.  This is useful to know where memory operations happen the
   *  most.
   */
  typedef struct  FT_MemSourceRec_
  {
    const char*   file_name;
    long          line_no;

    FT_Long       cur_blocks;   /* current number of allocated blocks */
    FT_Long       max_blocks;   /* max. number of allocated blocks    */
    FT_Long       all_blocks;   /* total number of blocks allocated   */

    FT_Long       cur_size;     /* current cumulative allocated size */
    FT_Long       max_size;     /* maximum cumulative allocated size */
    FT_Long       all_size;     /* total cumulative allocated size   */

    FT_Long       cur_max;      /* current maximum allocated size */

    FT_UInt32     hash;
    FT_MemSource  link;

  } FT_MemSourceRec;

  /*
   *  We don't need a resizable array for the memory sources, because
   *  their number is pretty limited within FreeType.
   */
#define FT_MEM_SOURCE_BUCKETS  128

  /*
   *  This structure holds information related to a single allocated
   *  memory block.  If KEEPALIVE is defined, blocks that are freed by
   *  FreeType are never released to the system.  Instead, their `size'
   *  field is set to -size.  This is mainly useful to detect double frees,
   *  at the price of large memory footprint during execution.
   */
  typedef struct  FT_MemNodeRec_
  {
    FT_Byte*      address;
    FT_Long       size;     /* < 0 if the block was freed */

    FT_MemSource  source;

#ifdef KEEPALIVE
    const char*   free_file_name;
    FT_Long       free_line_no;
#endif

    FT_MemNode    link;

  } FT_MemNodeRec;

  /*
   *  The global structure, containing compound statistics and all hash
   *  tables.
   */
  typedef struct  FT_MemTableRec_
  {
    FT_ULong         size;
    FT_ULong         nodes;
    FT_MemNode*      buckets;

    FT_ULong         alloc_total;
    FT_ULong         alloc_current;
    FT_ULong         alloc_max;
    FT_ULong         alloc_count;

    FT_Bool          bound_total;
    FT_ULong         alloc_total_max;

    FT_Bool          bound_count;
    FT_ULong         alloc_count_max;

    FT_MemSource     sources[FT_MEM_SOURCE_BUCKETS];

    FT_Bool          keep_alive;

    FT_Memory        memory;
    FT_Pointer       memory_user;
    FT_Alloc_Func    alloc;
    FT_Free_Func     free;
    FT_Realloc_Func  realloc;

  } FT_MemTableRec;

#define FT_MEM_SIZE_MIN  7
#define FT_MEM_SIZE_MAX  13845163

#define FT_FILENAME( x )  ((x) ? (x) : "unknown file")

  /*
   *  Prime numbers are ugly to handle.  It would be better to implement
   *  L-Hashing, which is 10% faster and doesn't require divisions.
   */
  static const FT_UInt  ft_mem_primes[] =
  {
    7,
    11,
    19,
    37,
    73,
    109,
    163,
    251,
    367,
    557,
    823,
    1237,
    1861,
    2777,
    4177,
    6247,
    9371,
    14057,
    21089,
    31627,
    47431,
    71143,
    106721,
    160073,
    240101,
    360163,
    540217,
    810343,
    1215497,
    1823231,
    2734867,
    4102283,
    6153409,
    9230113,
    13845163,
  };

  static FT_ULong
  ft_mem_closest_prime( FT_ULong  num )
  {
    FT_UInt  i;

    for ( i = 0;
          i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
      if ( ft_mem_primes[i] > num )
        return ft_mem_primes[i];

    return FT_MEM_SIZE_MAX;
  }

  extern void
  ft_mem_debug_panic( const char*  fmt,
                      ... )
  {
    va_list  ap;

    printf( "FreeType.Debug: " );

    va_start( ap, fmt );
    vprintf( fmt, ap );
    va_end( ap );

    printf( "\n" );
    exit( EXIT_FAILURE );
  }

  static FT_Pointer
  ft_mem_table_alloc( FT_MemTable  table,
                      FT_Long      size )
  {
    FT_Memory   memory = table->memory;
    FT_Pointer  block;

    memory->user = table->memory_user;
    block = table->alloc( memory, size );
    memory->user = table;

    return block;
  }

  static void
  ft_mem_table_free( FT_MemTable  table,
                     FT_Pointer   block )
  {
    FT_Memory  memory = table->memory;

    memory->user = table->memory_user;
    table->free( memory, block );
    memory->user = table;
  }

  static void
  ft_mem_table_resize( FT_MemTable  table )
  {
    FT_ULong  new_size;

    new_size = ft_mem_closest_prime( table->nodes );
    if ( new_size != table->size )
    {
      FT_MemNode*  new_buckets;
      FT_ULong     i;

      new_buckets = (FT_MemNode *)
                      ft_mem_table_alloc( table,
                                          new_size * sizeof ( FT_MemNode ) );
      if ( new_buckets == NULL )
        return;

      FT_ARRAY_ZERO( new_buckets, new_size );

      for ( i = 0; i < table->size; i++ )
      {
        FT_MemNode  node, next, *pnode;
        FT_PtrDist  hash;

        node = table->buckets[i];
        while ( node )
        {
          next  = node->link;
          hash  = FT_MEM_VAL( node->address ) % new_size;
          pnode = new_buckets + hash;

          node->link = pnode[0];
          pnode[0]   = node;

          node = next;
        }
      }

      if ( table->buckets )
        ft_mem_table_free( table, table->buckets );

      table->buckets = new_buckets;
      table->size    = new_size;
    }
  }

  static FT_MemTable
  ft_mem_table_new( FT_Memory  memory )
  {
    FT_MemTable  table;

    table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
    if ( table == NULL )
      goto Exit;

    FT_ZERO( table );

    table->size  = FT_MEM_SIZE_MIN;
    table->nodes = 0;

    table->memory = memory;

    table->memory_user = memory->user;

    table->alloc   = memory->alloc;
    table->realloc = memory->realloc;
    table->free    = memory->free;

    table->buckets = (FT_MemNode *)
                       memory->alloc( memory,
                                      table->size * sizeof ( FT_MemNode ) );
    if ( table->buckets )
      FT_ARRAY_ZERO( table->buckets, table->size );
    else
    {
      memory->free( memory, table );
      table = NULL;
    }

  Exit:
    return table;
  }

  static void
  ft_mem_table_destroy( FT_MemTable  table )
  {
    FT_ULong  i;

    FT_DumpMemory( table->memory );

    if ( table )
    {
      FT_Long   leak_count = 0;
      FT_ULong  leaks      = 0;

      /* remove all blocks from the table, revealing leaked ones */
      for ( i = 0; i < table->size; i++ )
      {
        FT_MemNode  *pnode = table->buckets + i, next, node = *pnode;

        while ( node )
        {
          next       = node->link;
          node->link = 0;

          if ( node->size > 0 )
          {
            printf(
              "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
              node->address, node->size,
              FT_FILENAME( node->source->file_name ),
              node->source->line_no );

            leak_count++;
            leaks += node->size;

            ft_mem_table_free( table, node->address );
          }

          node->address = NULL;
          node->size    = 0;

          ft_mem_table_free( table, node );
          node = next;
        }
        table->buckets[i] = 0;
      }

      ft_mem_table_free( table, table->buckets );
      table->buckets = NULL;

      table->size  = 0;
      table->nodes = 0;

      /* remove all sources */
      for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
      {
        FT_MemSource  source, next;

        for ( source = table->sources[i]; source != NULL; source = next )
        {
          next = source->link;
          ft_mem_table_free( table, source );
        }

        table->sources[i] = NULL;
      }

      printf(
        "FreeType: total memory allocations = %ld\n", table->alloc_total );
      printf(
        "FreeType: maximum memory footprint = %ld\n", table->alloc_max );

      ft_mem_table_free( table, table );

      if ( leak_count > 0 )
        ft_mem_debug_panic(
          "FreeType: %ld bytes of memory leaked in %ld blocks\n",
          leaks, leak_count );

      printf( "FreeType: no memory leaks detected\n" );
    }
  }

  static FT_MemNode*
  ft_mem_table_get_nodep( FT_MemTable  table,
                          FT_Byte*     address )
  {
    FT_PtrDist   hash;
    FT_MemNode  *pnode, node;

    hash  = FT_MEM_VAL( address );
    pnode = table->buckets + ( hash % table->size );

    for (;;)
    {
      node = pnode[0];
      if ( !node )
        break;

      if ( node->address == address )
        break;

      pnode = &node->link;
    }
    return pnode;
  }

  static FT_MemSource
  ft_mem_table_get_source( FT_MemTable  table )
  {
    FT_UInt32     hash;
    FT_MemSource  node, *pnode;

    /* cast to FT_PtrDist first since void* can be larger */
    /* than FT_UInt32 and GCC 4.1.1 emits a warning       */
    hash  = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file +
              (FT_UInt32)( 5 * _ft_debug_lineno );
    pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];

    for ( ;; )
    {
      node = *pnode;
      if ( node == NULL )
        break;

      if ( node->file_name == _ft_debug_file &&
           node->line_no   == _ft_debug_lineno   )
        goto Exit;

      pnode = &node->link;
    }

    node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
    if ( node == NULL )
      ft_mem_debug_panic(
        "not enough memory to perform memory debugging\n" );

    node->file_name = _ft_debug_file;
    node->line_no   = _ft_debug_lineno;

    node->cur_blocks = 0;
    node->max_blocks = 0;
    node->all_blocks = 0;

    node->cur_size   = 0;
    node->max_size   = 0;
    node->all_size   = 0;

    node->cur_max    = 0;

    node->link = NULL;
    node->hash = hash;
    *pnode     = node;

  Exit:
    return node;
  }

  static void
  ft_mem_table_set( FT_MemTable  table,
                    FT_Byte*     address,
                    FT_ULong     size,
                    FT_Long      delta )
  {
    FT_MemNode  *pnode, node;

    if ( table )
    {
      FT_MemSource  source;

      pnode = ft_mem_table_get_nodep( table, address );
      node  = *pnode;
      if ( node )
      {
        if ( node->size < 0 )
        {
          /* This block was already freed.  Our memory is now completely */
          /* corrupted!                                                  */
          /* This can only happen in keep-alive mode.                    */
          ft_mem_debug_panic(
            "memory heap corrupted (allocating freed block)" );
        }
        else
        {
          /* This block was already allocated.  This means that our memory */
          /* is also corrupted!                                            */
          ft_mem_debug_panic(
            "memory heap corrupted (re-allocating allocated block at"
            " %p, of size %ld)\n"
            "org=%s:%d new=%s:%d\n",
            node->address, node->size,
            FT_FILENAME( node->source->file_name ), node->source->line_no,
            FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
        }
      }

      /* we need to create a new node in this table */
      node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
      if ( node == NULL )
        ft_mem_debug_panic( "not enough memory to run memory tests" );

      node->address = address;
      node->size    = size;
      node->source  = source = ft_mem_table_get_source( table );

      if ( delta == 0 )
      {
        /* this is an allocation */
        source->all_blocks++;
        source->cur_blocks++;
        if ( source->cur_blocks > source->max_blocks )
          source->max_blocks = source->cur_blocks;
      }

      if ( size > (FT_ULong)source->cur_max )
        source->cur_max = size;

      if ( delta != 0 )
      {
        /* we are growing or shrinking a reallocated block */
        source->cur_size     += delta;
        table->alloc_current += delta;
      }
      else
      {
        /* we are allocating a new block */
        source->cur_size     += size;
        table->alloc_current += size;
      }

      source->all_size += size;

      if ( source->cur_size > source->max_size )
        source->max_size = source->cur_size;

      node->free_file_name = NULL;
      node->free_line_no   = 0;

      node->link = pnode[0];

      pnode[0] = node;
      table->nodes++;

      table->alloc_total += size;

      if ( table->alloc_current > table->alloc_max )
        table->alloc_max = table->alloc_current;

      if ( table->nodes * 3 < table->size  ||
           table->size  * 3 < table->nodes )
        ft_mem_table_resize( table );
    }
  }

  static void
  ft_mem_table_remove( FT_MemTable  table,
                       FT_Byte*     address,
                       FT_Long      delta )
  {
    if ( table )
    {
      FT_MemNode  *pnode, node;

      pnode = ft_mem_table_get_nodep( table, address );
      node  = *pnode;
      if ( node )
      {
        FT_MemSource  source;

        if ( node->size < 0 )
          ft_mem_debug_panic(
            "freeing memory block at %p more than once at (%s:%ld)\n"
            "block allocated at (%s:%ld) and released at (%s:%ld)",
            address,
            FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
            FT_FILENAME( node->source->file_name ), node->source->line_no,
            FT_FILENAME( node->free_file_name ), node->free_line_no );

        /* scramble the node's content for additional safety */
        FT_MEM_SET( address, 0xF3, node->size );

        if ( delta == 0 )
        {
          source = node->source;

          source->cur_blocks--;
          source->cur_size -= node->size;

          table->alloc_current -= node->size;
        }

        if ( table->keep_alive )
        {
          /* we simply invert the node's size to indicate that the node */
          /* was freed.                                                 */
          node->size           = -node->size;
          node->free_file_name = _ft_debug_file;
          node->free_line_no   = _ft_debug_lineno;
        }
        else
        {
          table->nodes--;

          *pnode = node->link;

          node->size   = 0;
          node->source = NULL;

          ft_mem_table_free( table, node );

          if ( table->nodes * 3 < table->size  ||
               table->size  * 3 < table->nodes )
            ft_mem_table_resize( table );
        }
      }
      else
        ft_mem_debug_panic(
          "trying to free unknown block at %p in (%s:%ld)\n",
          address,
          FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
    }
  }

  extern FT_Pointer
  ft_mem_debug_alloc( FT_Memory  memory,
                      FT_Long    size )
  {
    FT_MemTable  table = (FT_MemTable)memory->user;
    FT_Byte*     block;

    if ( size <= 0 )
      ft_mem_debug_panic( "negative block size allocation (%ld)", size );

    /* return NULL if the maximum number of allocations was reached */
    if ( table->bound_count                           &&
         table->alloc_count >= table->alloc_count_max )
      return NULL;

    /* return NULL if this allocation would overflow the maximum heap size */
    if ( table->bound_total                                             &&
         table->alloc_total_max - table->alloc_current > (FT_ULong)size )
      return NULL;

    block = (FT_Byte *)ft_mem_table_alloc( table, size );
    if ( block )
    {
      ft_mem_table_set( table, block, (FT_ULong)size, 0 );

      table->alloc_count++;
    }

    _ft_debug_file   = "<unknown>";
    _ft_debug_lineno = 0;

    return (FT_Pointer)block;
  }

  extern void
  ft_mem_debug_free( FT_Memory   memory,
                     FT_Pointer  block )
  {
    FT_MemTable  table = (FT_MemTable)memory->user;

    if ( block == NULL )
      ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
                          FT_FILENAME( _ft_debug_file ),
                          _ft_debug_lineno );

    ft_mem_table_remove( table, (FT_Byte*)block, 0 );

    if ( !table->keep_alive )
      ft_mem_table_free( table, block );

    table->alloc_count--;

    _ft_debug_file   = "<unknown>";
    _ft_debug_lineno = 0;
  }

  extern FT_Pointer
  ft_mem_debug_realloc( FT_Memory   memory,
                        FT_Long     cur_size,
                        FT_Long     new_size,
                        FT_Pointer  block )
  {
    FT_MemTable  table = (FT_MemTable)memory->user;
    FT_MemNode   node, *pnode;
    FT_Pointer   new_block;
    FT_Long      delta;

    const char*  file_name = FT_FILENAME( _ft_debug_file );
    FT_Long      line_no   = _ft_debug_lineno;

    /* unlikely, but possible */
    if ( new_size == cur_size )
      return block;

    /* the following is valid according to ANSI C */
#if 0
    if ( block == NULL || cur_size == 0 )
      ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
                          file_name, line_no );
#endif

    /* while the following is allowed in ANSI C also, we abort since */
    /* such case should be handled by FreeType.                      */
    if ( new_size <= 0 )
      ft_mem_debug_panic(
        "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
        block, cur_size, file_name, line_no );

    /* check `cur_size' value */
    pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
    node  = *pnode;
    if ( !node )
      ft_mem_debug_panic(
        "trying to reallocate unknown block at %p in (%s:%ld)",
        block, file_name, line_no );

    if ( node->size <= 0 )
      ft_mem_debug_panic(
        "trying to reallocate freed block at %p in (%s:%ld)",
        block, file_name, line_no );

    if ( node->size != cur_size )
      ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
                          "%ld instead of %ld in (%s:%ld)",
                          block, cur_size, node->size, file_name, line_no );

    /* return NULL if the maximum number of allocations was reached */
    if ( table->bound_count                           &&
         table->alloc_count >= table->alloc_count_max )
      return NULL;

    delta = (FT_Long)( new_size - cur_size );

    /* return NULL if this allocation would overflow the maximum heap size */
    if ( delta > 0                                                       &&
         table->bound_total                                              &&
         table->alloc_current + (FT_ULong)delta > table->alloc_total_max )
      return NULL;

    new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size );
    if ( new_block == NULL )
      return NULL;

    ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );

    ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );

    ft_mem_table_remove( table, (FT_Byte*)block, delta );

    _ft_debug_file   = "<unknown>";
    _ft_debug_lineno = 0;

    if ( !table->keep_alive )
      ft_mem_table_free( table, block );

    return new_block;
  }

  extern FT_Int
  ft_mem_debug_init( FT_Memory  memory )
  {
    FT_MemTable  table;
    FT_Int       result = 0;

    if ( getenv( "FT2_DEBUG_MEMORY" ) )
    {
      table = ft_mem_table_new( memory );
      if ( table )
      {
        const char*  p;

        memory->user    = table;
        memory->alloc   = ft_mem_debug_alloc;
        memory->realloc = ft_mem_debug_realloc;
        memory->free    = ft_mem_debug_free;

        p = getenv( "FT2_ALLOC_TOTAL_MAX" );
        if ( p != NULL )
        {
          FT_Long   total_max = ft_atol( p );

          if ( total_max > 0 )
          {
            table->bound_total     = 1;
            table->alloc_total_max = (FT_ULong)total_max;
          }
        }

        p = getenv( "FT2_ALLOC_COUNT_MAX" );
        if ( p != NULL )
        {
          FT_Long  total_count = ft_atol( p );

          if ( total_count > 0 )
          {
            table->bound_count     = 1;
            table->alloc_count_max = (FT_ULong)total_count;
          }
        }

        p = getenv( "FT2_KEEP_ALIVE" );
        if ( p != NULL )
        {
          FT_Long  keep_alive = ft_atol( p );

          if ( keep_alive > 0 )
            table->keep_alive = 1;
        }

        result = 1;
      }
    }
    return result;
  }

  extern void
  ft_mem_debug_done( FT_Memory  memory )
  {
    FT_MemTable  table = (FT_MemTable)memory->user;

    if ( table )
    {
      memory->free    = table->free;
      memory->realloc = table->realloc;
      memory->alloc   = table->alloc;

      ft_mem_table_destroy( table );
      memory->user = NULL;
    }
  }

  static int
  ft_mem_source_compare( const void*  p1,
                         const void*  p2 )
  {
    FT_MemSource  s1 = *(FT_MemSource*)p1;
    FT_MemSource  s2 = *(FT_MemSource*)p2;

    if ( s2->max_size > s1->max_size )
      return 1;
    else if ( s2->max_size < s1->max_size )
      return -1;
    else
      return 0;
  }

  extern void
  FT_DumpMemory( FT_Memory  memory )
  {
    FT_MemTable  table = (FT_MemTable)memory->user;

    if ( table )
    {
      FT_MemSource*  bucket = table->sources;
      FT_MemSource*  limit  = bucket + FT_MEM_SOURCE_BUCKETS;
      FT_MemSource*  sources;
      FT_UInt        nn, count;
      const char*    fmt;

      count = 0;
      for ( ; bucket < limit; bucket++ )
      {
        FT_MemSource  source = *bucket;

        for ( ; source; source = source->link )
          count++;
      }

      sources = (FT_MemSource*)ft_mem_table_alloc(
                                 table, sizeof ( *sources ) * count );

      count = 0;
      for ( bucket = table->sources; bucket < limit; bucket++ )
      {
        FT_MemSource  source = *bucket;

        for ( ; source; source = source->link )
          sources[count++] = source;
      }

      ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );

      printf( "FreeType Memory Dump: "
              "current=%ld max=%ld total=%ld count=%ld\n",
              table->alloc_current, table->alloc_max,
              table->alloc_total, table->alloc_count );
      printf( " block  block    sizes    sizes    sizes   source\n" );
      printf( " count   high      sum  highsum      max   location\n" );
      printf( "-------------------------------------------------\n" );

      fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";

      for ( nn = 0; nn < count; nn++ )
      {
        FT_MemSource  source = sources[nn];

        printf( fmt,
                source->cur_blocks, source->max_blocks,
                source->cur_size, source->max_size, source->cur_max,
                FT_FILENAME( source->file_name ),
                source->line_no );
      }
      printf( "------------------------------------------------\n" );

      ft_mem_table_free( table, sources );
    }
  }

#else  /* !FT_DEBUG_MEMORY */

  /* ANSI C doesn't like empty source files */
  typedef int  _debug_mem_dummy;

#endif /* !FT_DEBUG_MEMORY */

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftdebug.c                                                              */
/*                                                                         */
/*    Debugging and logging component (body).                              */
/*                                                                         */
/*  Copyright 1996-2001, 2002, 2004, 2008 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.                                        */
/*                                                                         */
/***************************************************************************/

  /*************************************************************************/
  /*                                                                       */
  /* This component contains various macros and functions used to ease the */
  /* debugging of the FreeType engine.  Its main purpose is in assertion   */
  /* checking, tracing, and error detection.                               */
  /*                                                                       */
  /* There are now three debugging modes:                                  */
  /*                                                                       */
  /* - trace mode                                                          */
  /*                                                                       */
  /*   Error and trace messages are sent to the log file (which can be the */
  /*   standard error output).                                             */
  /*                                                                       */
  /* - error mode                                                          */
  /*                                                                       */
  /*   Only error messages are generated.                                  */
  /*                                                                       */
  /* - release mode:                                                       */
  /*                                                                       */
  /*   No error message is sent or generated.  The code is free from any   */
  /*   debugging parts.                                                    */
  /*                                                                       */
  /*************************************************************************/

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_INTERNAL_DEBUG_H

#ifdef FT_DEBUG_LEVEL_ERROR

  /* documentation is in ftdebug.h */

  FT_BASE_DEF( void )
  FT_Message( const char*  fmt, ... )
  {
    va_list  ap;

    va_start( ap, fmt );
    vfprintf( stderr, fmt, ap );
    va_end( ap );
  }

  /* documentation is in ftdebug.h */

  FT_BASE_DEF( void )
  FT_Panic( const char*  fmt, ... )
  {
    va_list  ap;

    va_start( ap, fmt );
    vfprintf( stderr, fmt, ap );
    va_end( ap );

    exit( EXIT_FAILURE );
  }

#endif /* FT_DEBUG_LEVEL_ERROR */

#ifdef FT_DEBUG_LEVEL_TRACE

  /* array of trace levels, initialized to 0 */
  int  ft_trace_levels[trace_count];

  /* define array of trace toggle names */
#define FT_TRACE_DEF( x )  #x ,

  static const char*  ft_trace_toggles[trace_count + 1] =
  {
#include FT_INTERNAL_TRACE_H
    NULL
  };

#undef FT_TRACE_DEF

  /* documentation is in ftdebug.h */

  FT_BASE_DEF( FT_Int )
  FT_Trace_Get_Count( void )
  {
    return trace_count;
  }

  /* documentation is in ftdebug.h */

  FT_BASE_DEF( const char * )
  FT_Trace_Get_Name( FT_Int  idx )
  {
    int  max = FT_Trace_Get_Count();

    if ( idx < max )
      return ft_trace_toggles[idx];
    else
      return NULL;
  }

  /*************************************************************************/
  /*                                                                       */
  /* Initialize the tracing sub-system.  This is done by retrieving the    */
  /* value of the `FT2_DEBUG' environment variable.  It must be a list of  */
  /* toggles, separated by spaces, `;', or `,'.  Example:                  */
  /*                                                                       */
  /*    export FT2_DEBUG="any:3 memory:7 stream:5"                         */
  /*                                                                       */
  /* This requests that all levels be set to 3, except the trace level for */
  /* the memory and stream components which are set to 7 and 5,            */
  /* respectively.                                                         */
  /*                                                                       */
  /* See the file <include/freetype/internal/fttrace.h> for details of the */
  /* available toggle names.                                               */
  /*                                                                       */
  /* The level must be between 0 and 7; 0 means quiet (except for serious  */
  /* runtime errors), and 7 means _very_ verbose.                          */
  /*                                                                       */
  FT_BASE_DEF( void )
  ft_debug_init( void )
  {
    const char*  ft2_debug = getenv( "FT2_DEBUG" );

    if ( ft2_debug )
    {
      const char*  p = ft2_debug;
      const char*  q;

      for ( ; *p; p++ )
      {
        /* skip leading whitespace and separators */
        if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
          continue;

        /* read toggle name, followed by ':' */
        q = p;
        while ( *p && *p != ':' )
          p++;

        if ( *p == ':' && p > q )
        {
          FT_Int  n, i, len = (FT_Int)( p - q );
          FT_Int  level = -1, found = -1;

          for ( n = 0; n < trace_count; n++ )
          {
            const char*  toggle = ft_trace_toggles[n];

            for ( i = 0; i < len; i++ )
            {
              if ( toggle[i] != q[i] )
                break;
            }

            if ( i == len && toggle[i] == 0 )
            {
              found = n;
              break;
            }
          }

          /* read level */
          p++;
          if ( *p )
          {
            level = *p++ - '0';
            if ( level < 0 || level > 7 )
              level = -1;
          }

          if ( found >= 0 && level >= 0 )
          {
            if ( found == trace_any )
            {
              /* special case for `any' */
              for ( n = 0; n < trace_count; n++ )
                ft_trace_levels[n] = level;
            }
            else
              ft_trace_levels[found] = level;
          }
        }
      }
    }
  }

#else  /* !FT_DEBUG_LEVEL_TRACE */

  FT_BASE_DEF( void )
  ft_debug_init( void )
  {
    /* nothing */
  }

  FT_BASE_DEF( FT_Int )
  FT_Trace_Get_Count( void )
  {
    return 0;
  }

  FT_BASE_DEF( const char * )
  FT_Trace_Get_Name( FT_Int  idx )
  {
    FT_UNUSED( idx );

    return NULL;
  }

#endif /* !FT_DEBUG_LEVEL_TRACE */

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftfstype.c                                                             */
/*                                                                         */
/*    FreeType utility file to access FSType data (body).                  */
/*                                                                         */
/*  Copyright 2008, 2009 by                                                */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_TYPE1_TABLES_H
#include FT_TRUETYPE_TABLES_H
#include FT_INTERNAL_SERVICE_H
#include FT_SERVICE_POSTSCRIPT_INFO_H

  /* documentation is in freetype.h */

  FT_EXPORT_DEF( FT_UShort )
  FT_Get_FSType_Flags( FT_Face  face )
  {
    TT_OS2*  os2;

    /* first, try to get the fs_type directly from the font */
    if ( face )
    {
      FT_Service_PsInfo  service = NULL;

      FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO );

      if ( service && service->ps_get_font_extra )
      {
        PS_FontExtraRec  extra;

        if ( !service->ps_get_font_extra( face, &extra ) &&
             extra.fs_type != 0                          )
          return extra.fs_type;
      }
    }

    /* look at FSType before fsType for Type42 */

    if ( ( os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, ft_sfnt_os2 ) ) != NULL &&
         os2->version != 0xFFFFU                                           )
      return os2->fsType;

    return 0;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftgasp.c                                                               */
/*                                                                         */
/*    Access of TrueType's `gasp' table (body).                            */
/*                                                                         */
/*  Copyright 2007 by                                                      */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_GASP_H
#include FT_INTERNAL_TRUETYPE_TYPES_H

  FT_EXPORT_DEF( FT_Int )
  FT_Get_Gasp( FT_Face  face,
               FT_UInt  ppem )
  {
    FT_Int  result = FT_GASP_NO_TABLE;

    if ( face && FT_IS_SFNT( face ) )
    {
      TT_Face  ttface = (TT_Face)face;

      if ( ttface->gasp.numRanges > 0 )
      {
        TT_GaspRange  range     = ttface->gasp.gaspRanges;
        TT_GaspRange  range_end = range + ttface->gasp.numRanges;

        while ( ppem > range->maxPPEM )
        {
          range++;
          if ( range >= range_end )
            goto Exit;
        }

        result = range->gaspFlag;

        /* ensure that we don't have spurious bits */
        if ( ttface->gasp.version == 0 )
          result &= 3;
      }
    }
  Exit:
    return result;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftglyph.c                                                              */
/*                                                                         */
/*    FreeType convenience functions to handle glyphs (body).              */
/*                                                                         */
/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2007, 2008, 2010 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.                                        */
/*                                                                         */
/***************************************************************************/

  /*************************************************************************/
  /*                                                                       */
  /*  This file contains the definition of several convenience functions   */
  /*  that can be used by client applications to easily retrieve glyph     */
  /*  bitmaps and outlines from a given face.                              */
  /*                                                                       */
  /*  These functions should be optional if you are writing a font server  */
  /*  or text layout engine on top of FreeType.  However, they are pretty  */
  /*  handy for many other simple uses of the library.                     */
  /*                                                                       */
  /*************************************************************************/

#include <ft2build.h>
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BITMAP_H
#include FT_INTERNAL_OBJECTS_H

#include "basepic.h"

  /*************************************************************************/
  /*                                                                       */
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_glyph

  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****   FT_BitmapGlyph support                                        ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/

  FT_CALLBACK_DEF( FT_Error )
  ft_bitmap_glyph_init( FT_Glyph      bitmap_glyph,
                        FT_GlyphSlot  slot )
  {
    FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
    FT_Error        error   = FT_Err_Ok;
    FT_Library      library = FT_GLYPH( glyph )->library;

    if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
    {
      error = FT_Err_Invalid_Glyph_Format;
      goto Exit;
    }

    glyph->left = slot->bitmap_left;
    glyph->top  = slot->bitmap_top;

    /* do lazy copying whenever possible */
    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    {
      glyph->bitmap = slot->bitmap;
      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    }
    else
    {
      FT_Bitmap_New( &glyph->bitmap );
      error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
    }

  Exit:
    return error;
  }

  FT_CALLBACK_DEF( FT_Error )
  ft_bitmap_glyph_copy( FT_Glyph  bitmap_source,
                        FT_Glyph  bitmap_target )
  {
    FT_Library      library = bitmap_source->library;
    FT_BitmapGlyph  source  = (FT_BitmapGlyph)bitmap_source;
    FT_BitmapGlyph  target  = (FT_BitmapGlyph)bitmap_target;

    target->left = source->left;
    target->top  = source->top;

    return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap );
  }

  FT_CALLBACK_DEF( void )
  ft_bitmap_glyph_done( FT_Glyph  bitmap_glyph )
  {
    FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
    FT_Library      library = FT_GLYPH( glyph )->library;

    FT_Bitmap_Done( library, &glyph->bitmap );
  }

  FT_CALLBACK_DEF( void )
  ft_bitmap_glyph_bbox( FT_Glyph  bitmap_glyph,
                        FT_BBox*  cbox )
  {
    FT_BitmapGlyph  glyph = (FT_BitmapGlyph)bitmap_glyph;

    cbox->xMin = glyph->left << 6;
    cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );
    cbox->yMax = glyph->top << 6;
    cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 );
  }

  FT_DEFINE_GLYPH(ft_bitmap_glyph_class,
    sizeof ( FT_BitmapGlyphRec ),
    FT_GLYPH_FORMAT_BITMAP,

    ft_bitmap_glyph_init,
    ft_bitmap_glyph_done,
    ft_bitmap_glyph_copy,
    0,                          /* FT_Glyph_TransformFunc */
    ft_bitmap_glyph_bbox,
    0                           /* FT_Glyph_PrepareFunc   */
  )

  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****   FT_OutlineGlyph support                                       ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/

  FT_CALLBACK_DEF( FT_Error )
  ft_outline_glyph_init( FT_Glyph      outline_glyph,
                         FT_GlyphSlot  slot )
  {
    FT_OutlineGlyph  glyph   = (FT_OutlineGlyph)outline_glyph;
    FT_Error         error   = FT_Err_Ok;
    FT_Library       library = FT_GLYPH( glyph )->library;
    FT_Outline*      source  = &slot->outline;
    FT_Outline*      target  = &glyph->outline;

    /* check format in glyph slot */
    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
    {
      error = FT_Err_Invalid_Glyph_Format;
      goto Exit;
    }

    /* allocate new outline */
    error = FT_Outline_New( library, source->n_points, source->n_contours,
                            &glyph->outline );
    if ( error )
      goto Exit;

    FT_Outline_Copy( source, target );

  Exit:
    return error;
  }

  FT_CALLBACK_DEF( void )
  ft_outline_glyph_done( FT_Glyph  outline_glyph )
  {
    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;

    FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
  }

  FT_CALLBACK_DEF( FT_Error )
  ft_outline_glyph_copy( FT_Glyph  outline_source,
                         FT_Glyph  outline_target )
  {
    FT_OutlineGlyph  source  = (FT_OutlineGlyph)outline_source;
    FT_OutlineGlyph  target  = (FT_OutlineGlyph)outline_target;
    FT_Error         error;
    FT_Library       library = FT_GLYPH( source )->library;

    error = FT_Outline_New( library, source->outline.n_points,
                            source->outline.n_contours, &target->outline );
    if ( !error )
      FT_Outline_Copy( &source->outline, &target->outline );

    return error;
  }

  FT_CALLBACK_DEF( void )
  ft_outline_glyph_transform( FT_Glyph          outline_glyph,
                              const FT_Matrix*  matrix,
                              const FT_Vector*  delta )
  {
    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;

    if ( matrix )
      FT_Outline_Transform( &glyph->outline, matrix );

    if ( delta )
      FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
  }

  FT_CALLBACK_DEF( void )
  ft_outline_glyph_bbox( FT_Glyph  outline_glyph,
                         FT_BBox*  bbox )
  {
    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;

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

  FT_CALLBACK_DEF( FT_Error )
  ft_outline_glyph_prepare( FT_Glyph      outline_glyph,
                            FT_GlyphSlot  slot )
  {
    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;

    slot->format         = FT_GLYPH_FORMAT_OUTLINE;
    slot->outline        = glyph->outline;
    slot->outline.flags &= ~FT_OUTLINE_OWNER;

    return FT_Err_Ok;
  }

  FT_DEFINE_GLYPH( ft_outline_glyph_class,
    sizeof ( FT_OutlineGlyphRec ),
    FT_GLYPH_FORMAT_OUTLINE,

    ft_outline_glyph_init,
    ft_outline_glyph_done,
    ft_outline_glyph_copy,
    ft_outline_glyph_transform,
    ft_outline_glyph_bbox,
    ft_outline_glyph_prepare
  )

  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****   FT_Glyph class and API                                        ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/

   static FT_Error
   ft_new_glyph( FT_Library             library,
                 const FT_Glyph_Class*  clazz,
                 FT_Glyph*              aglyph )
   {
     FT_Memory  memory = library->memory;
     FT_Error   error;
     FT_Glyph   glyph  = NULL;

     *aglyph = 0;

     if ( !FT_ALLOC( glyph, clazz->glyph_size ) )
     {
       glyph->library = library;
       glyph->clazz   = clazz;
       glyph->format  = clazz->glyph_format;

       *aglyph = glyph;
     }

     return error;
   }

  /* documentation is in ftglyph.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Glyph_Copy( FT_Glyph   source,
                 FT_Glyph  *target )
  {
    FT_Glyph               copy;
    FT_Error               error;
    const FT_Glyph_Class*  clazz;

    /* check arguments */
    if ( !target )
    {
      error = FT_Err_Invalid_Argument;
      goto Exit;
    }

    *target = 0;

    if ( !source || !source->clazz )
    {
      error = FT_Err_Invalid_Argument;
      goto Exit;
    }

    clazz = source->clazz;
    error = ft_new_glyph( source->library, clazz, &copy );
    if ( error )
      goto Exit;

    copy->advance = source->advance;
    copy->format  = source->format;

    if ( clazz->glyph_copy )
      error = clazz->glyph_copy( source, copy );

    if ( error )
      FT_Done_Glyph( copy );
    else
      *target = copy;

  Exit:
    return error;
  }

  /* documentation is in ftglyph.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Get_Glyph( FT_GlyphSlot  slot,
                FT_Glyph     *aglyph )
  {
    FT_Library  library;
    FT_Error    error;
    FT_Glyph    glyph;

    const FT_Glyph_Class*  clazz = 0;

    if ( !slot )
      return FT_Err_Invalid_Slot_Handle;

    library = slot->library;

    if ( !aglyph )
      return FT_Err_Invalid_Argument;

    /* if it is a bitmap, that's easy :-) */
    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
      clazz = FT_BITMAP_GLYPH_CLASS_GET;

    /* if it is an outline */
    else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
      clazz = FT_OUTLINE_GLYPH_CLASS_GET;

    else
    {
      /* try to find a renderer that supports the glyph image format */
      FT_Renderer  render = FT_Lookup_Renderer( library, slot->format, 0 );

      if ( render )
        clazz = &render->glyph_class;
    }

    if ( !clazz )
    {
      error = FT_Err_Invalid_Glyph_Format;
      goto Exit;
    }

    /* create FT_Glyph object */
    error = ft_new_glyph( library, clazz, &glyph );
    if ( error )
      goto Exit;

    /* copy advance while converting it to 16.16 format */
    glyph->advance.x = slot->advance.x << 10;
    glyph->advance.y = slot->advance.y << 10;

    /* now import the image from the glyph slot */
    error = clazz->glyph_init( glyph, slot );

    /* if an error occurred, destroy the glyph */
    if ( error )
      FT_Done_Glyph( glyph );
    else
      *aglyph = glyph;

  Exit:
    return error;
  }

  /* documentation is in ftglyph.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Glyph_Transform( FT_Glyph    glyph,
                      FT_Matrix*  matrix,
                      FT_Vector*  delta )
  {
    const FT_Glyph_Class*  clazz;
    FT_Error               error = FT_Err_Ok;

    if ( !glyph || !glyph->clazz )
      error = FT_Err_Invalid_Argument;
    else
    {
      clazz = glyph->clazz;
      if ( clazz->glyph_transform )
      {
        /* transform glyph image */
        clazz->glyph_transform( glyph, matrix, delta );

        /* transform advance vector */
        if ( matrix )
          FT_Vector_Transform( &glyph->advance, matrix );
      }
      else
        error = FT_Err_Invalid_Glyph_Format;
    }
    return error;
  }

  /* documentation is in ftglyph.h */

  FT_EXPORT_DEF( void )
  FT_Glyph_Get_CBox( FT_Glyph  glyph,
                     FT_UInt   bbox_mode,
                     FT_BBox  *acbox )
  {
    const FT_Glyph_Class*  clazz;

    if ( !acbox )
      return;

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

    if ( !glyph || !glyph->clazz )
      return;
    else
    {
      clazz = glyph->clazz;
      if ( !clazz->glyph_bbox )
        return;
      else
      {
        /* retrieve bbox in 26.6 coordinates */
        clazz->glyph_bbox( glyph, acbox );

        /* perform grid fitting if needed */
        if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||
             bbox_mode == FT_GLYPH_BBOX_PIXELS  )
        {
          acbox->xMin = FT_PIX_FLOOR( acbox->xMin );
          acbox->yMin = FT_PIX_FLOOR( acbox->yMin );
          acbox->xMax = FT_PIX_CEIL( acbox->xMax );
          acbox->yMax = FT_PIX_CEIL( acbox->yMax );
        }

        /* convert to integer pixels if needed */
        if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||
             bbox_mode == FT_GLYPH_BBOX_PIXELS   )
        {
          acbox->xMin >>= 6;
          acbox->yMin >>= 6;
          acbox->xMax >>= 6;
          acbox->yMax >>= 6;
        }
      }
    }
    return;
  }

  /* documentation is in ftglyph.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Glyph_To_Bitmap( FT_Glyph*       the_glyph,
                      FT_Render_Mode  render_mode,
                      FT_Vector*      origin,
                      FT_Bool         destroy )
  {
    FT_GlyphSlotRec           dummy;
    FT_GlyphSlot_InternalRec  dummy_internal;
    FT_Error                  error = FT_Err_Ok;
    FT_Glyph                  glyph;
    FT_BitmapGlyph            bitmap = NULL;

    const FT_Glyph_Class*     clazz;

#ifdef FT_CONFIG_OPTION_PIC
    FT_Library                library = FT_GLYPH( glyph )->library;
#endif

    /* check argument */
    if ( !the_glyph )
      goto Bad;

    /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
    /* then calling FT_Render_Glyph_Internal()                            */

    glyph = *the_glyph;
    if ( !glyph )
      goto Bad;

    clazz = glyph->clazz;

    /* when called with a bitmap glyph, do nothing and return successfully */
    if ( clazz == FT_BITMAP_GLYPH_CLASS_GET )
      goto Exit;

    if ( !clazz || !clazz->glyph_prepare )
      goto Bad;

    FT_MEM_ZERO( &dummy, sizeof ( dummy ) );
    FT_MEM_ZERO( &dummy_internal, sizeof ( dummy_internal ) );
    dummy.internal = &dummy_internal;
    dummy.library  = glyph->library;
    dummy.format   = clazz->glyph_format;

    /* create result bitmap glyph */
    error = ft_new_glyph( glyph->library, FT_BITMAP_GLYPH_CLASS_GET,
                          (FT_Glyph*)(void*)&bitmap );
    if ( error )
      goto Exit;

#if 1
    /* if `origin' is set, translate the glyph image */
    if ( origin )
      FT_Glyph_Transform( glyph, 0, origin );
#else
    FT_UNUSED( origin );
#endif

    /* prepare dummy slot for rendering */
    error = clazz->glyph_prepare( glyph, &dummy );
    if ( !error )
      error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );

#if 1
    if ( !destroy && origin )
    {
      FT_Vector  v;

      v.x = -origin->x;
      v.y = -origin->y;
      FT_Glyph_Transform( glyph, 0, &v );
    }
#endif

    if ( error )
      goto Exit;

    /* in case of success, copy the bitmap to the glyph bitmap */
    error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy );
    if ( error )
      goto Exit;

    /* copy advance */
    bitmap->root.advance = glyph->advance;

    if ( destroy )
      FT_Done_Glyph( glyph );

    *the_glyph = FT_GLYPH( bitmap );

  Exit:
    if ( error && bitmap )
      FT_Done_Glyph( FT_GLYPH( bitmap ) );

    return error;

  Bad:
    error = FT_Err_Invalid_Argument;
    goto Exit;
  }

  /* documentation is in ftglyph.h */

  FT_EXPORT_DEF( void )
  FT_Done_Glyph( FT_Glyph  glyph )
  {
    if ( glyph )
    {
      FT_Memory              memory = glyph->library->memory;
      const FT_Glyph_Class*  clazz  = glyph->clazz;

      if ( clazz->glyph_done )
        clazz->glyph_done( glyph );

      FT_FREE( glyph );
    }
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftgxval.c                                                              */
/*                                                                         */
/*    FreeType API for validating TrueTyepGX/AAT tables (body).            */
/*                                                                         */
/*  Copyright 2004, 2005, 2006, 2010 by                                    */
/*  Masatake YAMATO, Redhat K.K,                                           */
/*  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.                                        */
/*                                                                         */
/***************************************************************************/

/***************************************************************************/
/*                                                                         */
/* gxvalid is derived from both gxlayout module and otvalid module.        */
/* Development of gxlayout is supported by the Information-technology      */
/* Promotion Agency(IPA), Japan.                                           */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include FT_SERVICE_GX_VALIDATE_H

  /* documentation is in ftgxval.h */

  FT_EXPORT_DEF( FT_Error )
  FT_TrueTypeGX_Validate( FT_Face   face,
                          FT_UInt   validation_flags,
                          FT_Bytes  tables[FT_VALIDATE_GX_LENGTH],
                          FT_UInt   table_length )
  {
    FT_Service_GXvalidate  service;
    FT_Error               error;

    if ( !face )
    {
      error = FT_Err_Invalid_Face_Handle;
      goto Exit;
    }

    if ( tables == NULL )
    {
      error = FT_Err_Invalid_Argument;
      goto Exit;
    }

    FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE );

    if ( service )
      error = service->validate( face,
                                 validation_flags,
                                 tables,
                                 table_length );
    else
      error = FT_Err_Unimplemented_Feature;

  Exit:
    return error;
  }

  FT_EXPORT_DEF( void )
  FT_TrueTypeGX_Free( FT_Face   face,
                      FT_Bytes  table )
  {
    FT_Memory  memory;

    if ( !face )
      return;

    memory = FT_FACE_MEMORY( face );

    FT_FREE( table );
  }

  FT_EXPORT_DEF( FT_Error )
  FT_ClassicKern_Validate( FT_Face    face,
                           FT_UInt    validation_flags,
                           FT_Bytes  *ckern_table )
  {
    FT_Service_CKERNvalidate  service;
    FT_Error                  error;

    if ( !face )
    {
      error = FT_Err_Invalid_Face_Handle;
      goto Exit;
    }

    if ( ckern_table == NULL )
    {
      error = FT_Err_Invalid_Argument;
      goto Exit;
    }

    FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE );

    if ( service )
      error = service->validate( face,
                                 validation_flags,
                                 ckern_table );
    else
      error = FT_Err_Unimplemented_Feature;

  Exit:
    return error;
  }

  FT_EXPORT_DEF( void )
  FT_ClassicKern_Free( FT_Face   face,
                       FT_Bytes  table )
  {
    FT_Memory  memory;

    if ( !face )
      return;

    memory = FT_FACE_MEMORY( face );

    FT_FREE( table );
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftinit.c                                                               */
/*                                                                         */
/*    FreeType initialization layer (body).                                */
/*                                                                         */
/*  Copyright 1996-2001, 2002, 2005, 2007, 2009 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.                                        */
/*                                                                         */
/***************************************************************************/

  /*************************************************************************/
  /*                                                                       */
  /*  The purpose of this file is to implement the following two           */
  /*  functions:                                                           */
  /*                                                                       */
  /*  FT_Add_Default_Modules():                                            */
  /*     This function is used to add the set of default modules to a      */
  /*     fresh new library object.  The set is taken from the header file  */
  /*     `freetype/config/ftmodule.h'.  See the document `FreeType 2.0     */
  /*     Build System' for more information.                               */
  /*                                                                       */
  /*  FT_Init_FreeType():                                                  */
  /*     This function creates a system object for the current platform,   */
  /*     builds a library out of it, then calls FT_Default_Drivers().      */
  /*                                                                       */
  /*  Note that even if FT_Init_FreeType() uses the implementation of the  */
  /*  system object defined at build time, client applications are still   */
  /*  able to provide their own `ftsystem.c'.                              */
  /*                                                                       */
  /*************************************************************************/

#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include FT_MODULE_H
#include "basepic.h"

  /*************************************************************************/
  /*                                                                       */
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_init

#ifndef FT_CONFIG_OPTION_PIC

#undef  FT_USE_MODULE
#ifdef __cplusplus
#define FT_USE_MODULE( type, x )  extern "C" const type  x;
#else
#define FT_USE_MODULE( type, x )  extern const type  x;
#endif

#include FT_CONFIG_MODULES_H

#undef  FT_USE_MODULE
#define FT_USE_MODULE( type, x )  (const FT_Module_Class*)&(x),

  static
  const FT_Module_Class*  const ft_default_modules[] =
  {
#include FT_CONFIG_MODULES_H
    0
  };

#else /* FT_CONFIG_OPTION_PIC */

#ifdef __cplusplus
#define FT_EXTERNC  extern "C"
#else
#define FT_EXTERNC  extern
#endif

  /* declare the module's class creation/destruction functions */
#undef  FT_USE_MODULE
#define FT_USE_MODULE( type, x )  \
  FT_EXTERNC FT_Error FT_Create_Class_##x( FT_Library library, FT_Module_Class** output_class ); \
  FT_EXTERNC void     FT_Destroy_Class_##x( FT_Library library, FT_Module_Class*  clazz );

#include FT_CONFIG_MODULES_H

  /* count all module classes */
#undef  FT_USE_MODULE
#define FT_USE_MODULE( type, x )  MODULE_CLASS_##x,

  enum
  {
#include FT_CONFIG_MODULES_H
    FT_NUM_MODULE_CLASSES
  };

  /* destroy all module classes */
#undef  FT_USE_MODULE
#define FT_USE_MODULE( type, x )  \
  if ( classes[i] ) { FT_Destroy_Class_##x(library, classes[i]); } \
  i++;                                                             \

  FT_BASE_DEF( void )
  ft_destroy_default_module_classes( FT_Library  library )
  {
    FT_Module_Class** classes;
    FT_Memory         memory;
    FT_UInt           i;
    BasePIC*          pic_container = (BasePIC*)library->pic_container.base;

    if ( !pic_container->default_module_classes )
      return;

    memory = library->memory;
    classes = pic_container->default_module_classes;
    i = 0;

#include FT_CONFIG_MODULES_H

    FT_FREE( classes );
    pic_container->default_module_classes = 0;
  }

  /* initialize all module classes and the pointer table */
#undef  FT_USE_MODULE
#define FT_USE_MODULE( type, x )                \
  error = FT_Create_Class_##x(library, &clazz); \
  if (error) goto Exit;                         \
  classes[i++] = clazz;

  FT_BASE_DEF( FT_Error )
  ft_create_default_module_classes( FT_Library  library )
  {
    FT_Error          error;
    FT_Memory         memory;
    FT_Module_Class** classes;
    FT_Module_Class*  clazz;
    FT_UInt           i;
    BasePIC*          pic_container = (BasePIC*)library->pic_container.base;

    memory = library->memory;
    pic_container->default_module_classes = 0;

    if ( FT_ALLOC(classes, sizeof(FT_Module_Class*) * (FT_NUM_MODULE_CLASSES + 1) ) )
      return error;
    /* initialize all pointers to 0, especially the last one */
    for (i = 0; i < FT_NUM_MODULE_CLASSES; i++)
      classes[i] = 0;
    classes[FT_NUM_MODULE_CLASSES] = 0;

    i = 0;

#include FT_CONFIG_MODULES_H

Exit:
    if (error) ft_destroy_default_module_classes( library );
    else pic_container->default_module_classes = classes;

    return error;
  }

#endif /* FT_CONFIG_OPTION_PIC */

  /* documentation is in ftmodapi.h */

  FT_EXPORT_DEF( void )
  FT_Add_Default_Modules( FT_Library  library )
  {
    FT_Error                       error;
    const FT_Module_Class* const*  cur;

    /* test for valid `library' delayed to FT_Add_Module() */

    cur = FT_DEFAULT_MODULES_GET;
    while ( *cur )
    {
      error = FT_Add_Module( library, *cur );
      /* notify errors, but don't stop */
      if ( error )
        FT_TRACE0(( "FT_Add_Default_Module:"
                    " Cannot install `%s', error = 0x%x\n",
                    (*cur)->module_name, error ));
      cur++;
    }
  }

  /* documentation is in freetype.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Init_FreeType( FT_Library  *alibrary )
  {
    FT_Error   error;
    FT_Memory  memory;

    /* First of all, allocate a new system object -- this function is part */
    /* of the system-specific component, i.e. `ftsystem.c'.                */

    memory = FT_New_Memory();
    if ( !memory )
    {
      FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" ));
      return FT_Err_Unimplemented_Feature;
    }

    /* build a library out of it, then fill it with the set of */
    /* default drivers.                                        */

    error = FT_New_Library( memory, alibrary );
    if ( error )
      FT_Done_Memory( memory );
    else
      FT_Add_Default_Modules( *alibrary );

    return error;
  }

  /* documentation is in freetype.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Done_FreeType( FT_Library  library )
  {
    if ( library )
    {
      FT_Memory  memory = library->memory;

      /* Discard the library object */
      FT_Done_Library( library );

      /* discard memory manager */
      FT_Done_Memory( memory );
    }

    return FT_Err_Ok;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftlcdfil.c                                                             */
/*                                                                         */
/*    FreeType API for color filtering of subpixel bitmap glyphs (body).   */
/*                                                                         */
/*  Copyright 2006, 2008, 2009, 2010 by                                    */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_LCD_FILTER_H
#include FT_IMAGE_H
#include FT_INTERNAL_OBJECTS_H

#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING

/* define USE_LEGACY to implement the legacy filter */
#define  USE_LEGACY

  /* FIR filter used by the default and light filters */
  static void
  _ft_lcd_filter_fir( FT_Bitmap*      bitmap,
                      FT_Render_Mode  mode,
                      FT_Library      library )
  {
    FT_Byte*  weights = library->lcd_weights;
    FT_UInt   width   = (FT_UInt)bitmap->width;
    FT_UInt   height  = (FT_UInt)bitmap->rows;

    /* horizontal in-place FIR filter */
    if ( mode == FT_RENDER_MODE_LCD && width >= 4 )
    {
      FT_Byte*  line = bitmap->buffer;

      for ( ; height > 0; height--, line += bitmap->pitch )
      {
        FT_UInt  fir[5];
        FT_UInt  val1, xx;

        val1   = line[0];
        fir[0] = weights[2] * val1;
        fir[1] = weights[3] * val1;
        fir[2] = weights[4] * val1;
        fir[3] = 0;
        fir[4] = 0;

        val1    = line[1];
        fir[0] += weights[1] * val1;
        fir[1] += weights[2] * val1;
        fir[2] += weights[3] * val1;
        fir[3] += weights[4] * val1;

        for ( xx = 2; xx < width; xx++ )
        {
          FT_UInt  val, pix;

          val    = line[xx];
          pix    = fir[0] + weights[0] * val;
          fir[0] = fir[1] + weights[1] * val;
          fir[1] = fir[2] + weights[2] * val;
          fir[2] = fir[3] + weights[3] * val;
          fir[3] =          weights[4] * val;

          pix        >>= 8;
          pix         |= -( pix >> 8 );
          line[xx - 2] = (FT_Byte)pix;
        }

        {
          FT_UInt  pix;

          pix          = fir[0] >> 8;
          pix         |= -( pix >> 8 );
          line[xx - 2] = (FT_Byte)pix;

          pix          = fir[1] >> 8;
          pix         |= -( pix >> 8 );
          line[xx - 1] = (FT_Byte)pix;
        }
      }
    }

    /* vertical in-place FIR filter */
    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 )
    {
      FT_Byte*  column = bitmap->buffer;
      FT_Int    pitch  = bitmap->pitch;

      for ( ; width > 0; width--, column++ )
      {
        FT_Byte*  col = column;
        FT_UInt   fir[5];
        FT_UInt   val1, yy;

        val1   = col[0];
        fir[0] = weights[2] * val1;
        fir[1] = weights[3] * val1;
        fir[2] = weights[4] * val1;
        fir[3] = 0;
        fir[4] = 0;
        col   += pitch;

        val1    = col[0];
        fir[0] += weights[1] * val1;
        fir[1] += weights[2] * val1;
        fir[2] += weights[3] * val1;
        fir[3] += weights[4] * val1;
        col    += pitch;

        for ( yy = 2; yy < height; yy++ )
        {
          FT_UInt  val, pix;

          val    = col[0];
          pix    = fir[0] + weights[0] * val;
          fir[0] = fir[1] + weights[1] * val;
          fir[1] = fir[2] + weights[2] * val;
          fir[2] = fir[3] + weights[3] * val;
          fir[3] =          weights[4] * val;

          pix           >>= 8;
          pix            |= -( pix >> 8 );
          col[-2 * pitch] = (FT_Byte)pix;
          col            += pitch;
        }

        {
          FT_UInt  pix;

          pix             = fir[0] >> 8;
          pix            |= -( pix >> 8 );
          col[-2 * pitch] = (FT_Byte)pix;

          pix         = fir[1] >> 8;
          pix        |= -( pix >> 8 );
          col[-pitch] = (FT_Byte)pix;
        }
      }
    }
  }

#ifdef USE_LEGACY

  /* intra-pixel filter used by the legacy filter */
  static void
  _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
                         FT_Render_Mode  mode,
                         FT_Library      library )
  {
    FT_UInt  width  = (FT_UInt)bitmap->width;
    FT_UInt  height = (FT_UInt)bitmap->rows;
    FT_Int   pitch  = bitmap->pitch;

    static const int  filters[3][3] =
    {
      { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
      { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
      { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
    };

    FT_UNUSED( library );

    /* horizontal in-place intra-pixel filter */
    if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
    {
      FT_Byte*  line = bitmap->buffer;

      for ( ; height > 0; height--, line += pitch )
      {
        FT_UInt  xx;

        for ( xx = 0; xx < width; xx += 3 )
        {
          FT_UInt  r = 0;
          FT_UInt  g = 0;
          FT_UInt  b = 0;
          FT_UInt  p;

          p  = line[xx];
          r += filters[0][0] * p;
          g += filters[0][1] * p;
          b += filters[0][2] * p;

          p  = line[xx + 1];
          r += filters[1][0] * p;
          g += filters[1][1] * p;
          b += filters[1][2] * p;

          p  = line[xx + 2];
          r += filters[2][0] * p;
          g += filters[2][1] * p;
          b += filters[2][2] * p;

          line[xx]     = (FT_Byte)( r / 65536 );
          line[xx + 1] = (FT_Byte)( g / 65536 );
          line[xx + 2] = (FT_Byte)( b / 65536 );
        }
      }
    }
    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
    {
      FT_Byte*  column = bitmap->buffer;

      for ( ; width > 0; width--, column++ )
      {
        FT_Byte*  col     = column;
        FT_Byte*  col_end = col + height * pitch;

        for ( ; col < col_end; col += 3 * pitch )
        {
          FT_UInt  r = 0;
          FT_UInt  g = 0;
          FT_UInt  b = 0;
          FT_UInt  p;

          p  = col[0];
          r += filters[0][0] * p;
          g += filters[0][1] * p;
          b += filters[0][2] * p;

          p  = col[pitch];
          r += filters[1][0] * p;
          g += filters[1][1] * p;
          b += filters[1][2] * p;

          p  = col[pitch * 2];
          r += filters[2][0] * p;
          g += filters[2][1] * p;
          b += filters[2][2] * p;

          col[0]         = (FT_Byte)( r / 65536 );
          col[pitch]     = (FT_Byte)( g / 65536 );
          col[2 * pitch] = (FT_Byte)( b / 65536 );
        }
      }
    }
  }

#endif /* USE_LEGACY */

  FT_EXPORT_DEF( FT_Error )
  FT_Library_SetLcdFilterWeights( FT_Library      library,
                                  unsigned char  *weights )
  {
    if ( !library || !weights )
      return FT_Err_Invalid_Argument;

    ft_memcpy( library->lcd_weights, weights, 5 );

    return FT_Err_Ok;
  }

  FT_EXPORT_DEF( FT_Error )
  FT_Library_SetLcdFilter( FT_Library    library,
                           FT_LcdFilter  filter )
  {
    static const FT_Byte  light_filter[5] =
                            { 0x00, 0x55, 0x56, 0x55, 0x00 };
    /* the values here sum up to a value larger than 256, */
    /* providing a cheap gamma correction                 */
    static const FT_Byte  default_filter[5] =
                            { 0x10, 0x40, 0x70, 0x40, 0x10 };

    if ( !library )
      return FT_Err_Invalid_Argument;

    switch ( filter )
    {
    case FT_LCD_FILTER_NONE:
      library->lcd_filter_func = NULL;
      library->lcd_extra       = 0;
      break;

    case FT_LCD_FILTER_DEFAULT:
#if defined( FT_FORCE_LEGACY_LCD_FILTER )

      library->lcd_filter_func = _ft_lcd_filter_legacy;
      library->lcd_extra       = 0;

#elif defined( FT_FORCE_LIGHT_LCD_FILTER )

      ft_memcpy( library->lcd_weights, light_filter, 5 );
      library->lcd_filter_func = _ft_lcd_filter_fir;
      library->lcd_extra       = 2;

#else

      ft_memcpy( library->lcd_weights, default_filter, 5 );
      library->lcd_filter_func = _ft_lcd_filter_fir;
      library->lcd_extra       = 2;

#endif

      break;

    case FT_LCD_FILTER_LIGHT:
      ft_memcpy( library->lcd_weights, light_filter, 5 );
      library->lcd_filter_func = _ft_lcd_filter_fir;
      library->lcd_extra       = 2;
      break;

#ifdef USE_LEGACY

    case FT_LCD_FILTER_LEGACY:
      library->lcd_filter_func = _ft_lcd_filter_legacy;
      library->lcd_extra       = 0;
      break;

#endif

    default:
      return FT_Err_Invalid_Argument;
    }

    library->lcd_filter = filter;

    return FT_Err_Ok;
  }

#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */

  FT_EXPORT_DEF( FT_Error )
  FT_Library_SetLcdFilterWeights( FT_Library      library,
                                  unsigned char  *weights )
  {
    FT_UNUSED( library );
    FT_UNUSED( weights );

    return FT_Err_Unimplemented_Feature;
  }

  FT_EXPORT_DEF( FT_Error )
  FT_Library_SetLcdFilter( FT_Library    library,
                           FT_LcdFilter  filter )
  {
    FT_UNUSED( library );
    FT_UNUSED( filter );

    return FT_Err_Unimplemented_Feature;
  }

#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */

/* END */