code:
/***************************************************************************/
/*                                                                         */
/*  ftcmanag.c                                                             */
/*                                                                         */
/*    FreeType Cache Manager (body).                                       */
/*                                                                         */
/*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 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_CACHE_H
#include "ftcmanag.h"
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include FT_SIZES_H

#include "ftccback.h"
#include "ftcerror.h"

#ifdef FT_CONFIG_OPTION_PIC
#error "cache system does not support PIC yet"
#endif

#undef  FT_COMPONENT
#define FT_COMPONENT  trace_cache

#define FTC_LRU_GET_MANAGER( lru )  ( (FTC_Manager)(lru)->user_data )

  static FT_Error
  ftc_scaler_lookup_size( FTC_Manager  manager,
                          FTC_Scaler   scaler,
                          FT_Size     *asize )
  {
    FT_Face   face;
    FT_Size   size = NULL;
    FT_Error  error;

    error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
    if ( error )
      goto Exit;

    error = FT_New_Size( face, &size );
    if ( error )
      goto Exit;

    FT_Activate_Size( size );

    if ( scaler->pixel )
      error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
    else
      error = FT_Set_Char_Size( face, scaler->width, scaler->height,
                                scaler->x_res, scaler->y_res );
    if ( error )
    {
      FT_Done_Size( size );
      size = NULL;
    }

  Exit:
    *asize = size;
    return error;
  }

  typedef struct  FTC_SizeNodeRec_
  {
    FTC_MruNodeRec  node;
    FT_Size         size;
    FTC_ScalerRec   scaler;

  } FTC_SizeNodeRec, *FTC_SizeNode;

#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )

  FT_CALLBACK_DEF( void )
  ftc_size_node_done( FTC_MruNode  ftcnode,
                      FT_Pointer   data )
  {
    FTC_SizeNode  node = (FTC_SizeNode)ftcnode;
    FT_Size       size = node->size;
    FT_UNUSED( data );

    if ( size )
      FT_Done_Size( size );
  }

  FT_CALLBACK_DEF( FT_Bool )
  ftc_size_node_compare( FTC_MruNode  ftcnode,
                         FT_Pointer   ftcscaler )
  {
    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
    FTC_Scaler    scaler0 = &node->scaler;

    if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
    {
      FT_Activate_Size( node->size );
      return 1;
    }
    return 0;
  }

  FT_CALLBACK_DEF( FT_Error )
  ftc_size_node_init( FTC_MruNode  ftcnode,
                      FT_Pointer   ftcscaler,
                      FT_Pointer   ftcmanager )
  {
    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
    FTC_Manager   manager = (FTC_Manager)ftcmanager;

    node->scaler = scaler[0];

    return ftc_scaler_lookup_size( manager, scaler, &node->size );
  }

  FT_CALLBACK_DEF( FT_Error )
  ftc_size_node_reset( FTC_MruNode  ftcnode,
                       FT_Pointer   ftcscaler,
                       FT_Pointer   ftcmanager )
  {
    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
    FTC_Manager   manager = (FTC_Manager)ftcmanager;

    FT_Done_Size( node->size );

    node->scaler = scaler[0];

    return ftc_scaler_lookup_size( manager, scaler, &node->size );
  }

  FT_CALLBACK_TABLE_DEF
  const FTC_MruListClassRec  ftc_size_list_class =
  {
    sizeof ( FTC_SizeNodeRec ),
    ftc_size_node_compare,
    ftc_size_node_init,
    ftc_size_node_reset,
    ftc_size_node_done
  };

  /* helper function used by ftc_face_node_done */
  static FT_Bool
  ftc_size_node_compare_faceid( FTC_MruNode  ftcnode,
                                FT_Pointer   ftcface_id )
  {
    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;

    return FT_BOOL( node->scaler.face_id == face_id );
  }

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( FT_Error )
  FTC_Manager_LookupSize( FTC_Manager  manager,
                          FTC_Scaler   scaler,
                          FT_Size     *asize )
  {
    FT_Error     error;
    FTC_MruNode  mrunode;

    if ( asize == NULL )
      return FTC_Err_Invalid_Argument;

    *asize = NULL;

    if ( !manager )
      return FTC_Err_Invalid_Cache_Handle;

#ifdef FTC_INLINE

    FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
                            mrunode, error );

#else
    error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
#endif

    if ( !error )
      *asize = FTC_SIZE_NODE( mrunode )->size;

    return error;
  }

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                    FACE MRU IMPLEMENTATION                    *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  typedef struct  FTC_FaceNodeRec_
  {
    FTC_MruNodeRec  node;
    FTC_FaceID      face_id;
    FT_Face         face;

  } FTC_FaceNodeRec, *FTC_FaceNode;

#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )

  FT_CALLBACK_DEF( FT_Error )
  ftc_face_node_init( FTC_MruNode  ftcnode,
                      FT_Pointer   ftcface_id,
                      FT_Pointer   ftcmanager )
  {
    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
    FTC_Manager   manager = (FTC_Manager)ftcmanager;
    FT_Error      error;

    node->face_id = face_id;

    error = manager->request_face( face_id,
                                   manager->library,
                                   manager->request_data,
                                   &node->face );
    if ( !error )
    {
      /* destroy initial size object; it will be re-created later */
      if ( node->face->size )
        FT_Done_Size( node->face->size );
    }

    return error;
  }

  FT_CALLBACK_DEF( void )
  ftc_face_node_done( FTC_MruNode  ftcnode,
                      FT_Pointer   ftcmanager )
  {
    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
    FTC_Manager   manager = (FTC_Manager)ftcmanager;

    /* we must begin by removing all scalers for the target face */
    /* from the manager's list                                   */
    FTC_MruList_RemoveSelection( &manager->sizes,
                                 ftc_size_node_compare_faceid,
                                 node->face_id );

    /* all right, we can discard the face now */
    FT_Done_Face( node->face );
    node->face    = NULL;
    node->face_id = NULL;
  }

  FT_CALLBACK_DEF( FT_Bool )
  ftc_face_node_compare( FTC_MruNode  ftcnode,
                         FT_Pointer   ftcface_id )
  {
    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;

    return FT_BOOL( node->face_id == face_id );
  }

  FT_CALLBACK_TABLE_DEF
  const FTC_MruListClassRec  ftc_face_list_class =
  {
    sizeof ( FTC_FaceNodeRec),

    ftc_face_node_compare,
    ftc_face_node_init,
    0,                          /* FTC_MruNode_ResetFunc */
    ftc_face_node_done
  };

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( FT_Error )
  FTC_Manager_LookupFace( FTC_Manager  manager,
                          FTC_FaceID   face_id,
                          FT_Face     *aface )
  {
    FT_Error     error;
    FTC_MruNode  mrunode;

    if ( aface == NULL )
      return FTC_Err_Invalid_Argument;

    *aface = NULL;

    if ( !manager )
      return FTC_Err_Invalid_Cache_Handle;

    /* we break encapsulation for the sake of speed */
#ifdef FTC_INLINE

    FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
                            mrunode, error );

#else
    error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
#endif

    if ( !error )
      *aface = FTC_FACE_NODE( mrunode )->face;

    return error;
  }

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                    CACHE MANAGER ROUTINES                     *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( FT_Error )
  FTC_Manager_New( FT_Library          library,
                   FT_UInt             max_faces,
                   FT_UInt             max_sizes,
                   FT_ULong            max_bytes,
                   FTC_Face_Requester  requester,
                   FT_Pointer          req_data,
                   FTC_Manager        *amanager )
  {
    FT_Error     error;
    FT_Memory    memory;
    FTC_Manager  manager = 0;

    if ( !library )
      return FTC_Err_Invalid_Library_Handle;

    memory = library->memory;

    if ( FT_NEW( manager ) )
      goto Exit;

    if ( max_faces == 0 )
      max_faces = FTC_MAX_FACES_DEFAULT;

    if ( max_sizes == 0 )
      max_sizes = FTC_MAX_SIZES_DEFAULT;

    if ( max_bytes == 0 )
      max_bytes = FTC_MAX_BYTES_DEFAULT;

    manager->library      = library;
    manager->memory       = memory;
    manager->max_weight   = max_bytes;

    manager->request_face = requester;
    manager->request_data = req_data;

    FTC_MruList_Init( &manager->faces,
                      &ftc_face_list_class,
                      max_faces,
                      manager,
                      memory );

    FTC_MruList_Init( &manager->sizes,
                      &ftc_size_list_class,
                      max_sizes,
                      manager,
                      memory );

    *amanager = manager;

  Exit:
    return error;
  }

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( void )
  FTC_Manager_Done( FTC_Manager  manager )
  {
    FT_Memory  memory;
    FT_UInt    idx;

    if ( !manager || !manager->library )
      return;

    memory = manager->memory;

    /* now discard all caches */
    for (idx = manager->num_caches; idx-- > 0; )
    {
      FTC_Cache  cache = manager->caches[idx];

      if ( cache )
      {
        cache->clazz.cache_done( cache );
        FT_FREE( cache );
        manager->caches[idx] = NULL;
      }
    }
    manager->num_caches = 0;

    /* discard faces and sizes */
    FTC_MruList_Done( &manager->sizes );
    FTC_MruList_Done( &manager->faces );

    manager->library = NULL;
    manager->memory  = NULL;

    FT_FREE( manager );
  }

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( void )
  FTC_Manager_Reset( FTC_Manager  manager )
  {
    if ( manager )
    {
      FTC_MruList_Reset( &manager->sizes );
      FTC_MruList_Reset( &manager->faces );
    }
    /* XXX: FIXME: flush the caches? */
  }

#ifdef FT_DEBUG_ERROR

  static void
  FTC_Manager_Check( FTC_Manager  manager )
  {
    FTC_Node  node, first;

    first = manager->nodes_list;

    /* check node weights */
    if ( first )
    {
      FT_ULong  weight = 0;

      node = first;

      do
      {
        FTC_Cache  cache = manager->caches[node->cache_index];

        if ( (FT_UInt)node->cache_index >= manager->num_caches )
          FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
                      node->cache_index ));
        else
          weight += cache->clazz.node_weight( node, cache );

        node = FTC_NODE__NEXT( node );

      } while ( node != first );

      if ( weight != manager->cur_weight )
        FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
                    manager->cur_weight, weight ));
    }

    /* check circular list */
    if ( first )
    {
      FT_UFast  count = 0;

      node = first;
      do
      {
        count++;
        node = FTC_NODE__NEXT( node );

      } while ( node != first );

      if ( count != manager->num_nodes )
        FT_TRACE0(( "FTC_Manager_Check:"
                    " invalid cache node count %d instead of %d\n",
                    manager->num_nodes, count ));
    }
  }

#endif /* FT_DEBUG_ERROR */

  /* `Compress' the manager's data, i.e., get rid of old cache nodes */
  /* that are not referenced anymore in order to limit the total     */
  /* memory used by the cache.                                       */

  /* documentation is in ftcmanag.h */

  FT_LOCAL_DEF( void )
  FTC_Manager_Compress( FTC_Manager  manager )
  {
    FTC_Node   node, first;

    if ( !manager )
      return;

    first = manager->nodes_list;

#ifdef FT_DEBUG_ERROR
    FTC_Manager_Check( manager );

    FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
                manager->cur_weight, manager->max_weight,
                manager->num_nodes ));
#endif

    if ( manager->cur_weight < manager->max_weight || first == NULL )
      return;

    /* go to last node -- it's a circular list */
    node = FTC_NODE__PREV( first );
    do
    {
      FTC_Node  prev;

      prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );

      if ( node->ref_count <= 0 )
        ftc_node_destroy( node, manager );

      node = prev;

    } while ( node && manager->cur_weight > manager->max_weight );
  }

  /* documentation is in ftcmanag.h */

  FT_LOCAL_DEF( FT_Error )
  FTC_Manager_RegisterCache( FTC_Manager      manager,
                             FTC_CacheClass   clazz,
                             FTC_Cache       *acache )
  {
    FT_Error   error = FTC_Err_Invalid_Argument;
    FTC_Cache  cache = NULL;

    if ( manager && clazz && acache )
    {
      FT_Memory  memory = manager->memory;

      if ( manager->num_caches >= FTC_MAX_CACHES )
      {
        error = FTC_Err_Too_Many_Caches;
        FT_ERROR(( "FTC_Manager_RegisterCache:"
                   " too many registered caches\n" ));
        goto Exit;
      }

      if ( !FT_ALLOC( cache, clazz->cache_size ) )
      {
        cache->manager   = manager;
        cache->memory    = memory;
        cache->clazz     = clazz[0];
        cache->org_class = clazz;

        /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
        /* IF IT IS NOT SET CORRECTLY                          */
        cache->index = manager->num_caches;

        error = clazz->cache_init( cache );
        if ( error )
        {
          clazz->cache_done( cache );
          FT_FREE( cache );
          goto Exit;
        }

        manager->caches[manager->num_caches++] = cache;
      }
    }

  Exit:
    if ( acache )
      *acache = cache;
    return error;
  }

  FT_LOCAL_DEF( FT_UInt )
  FTC_Manager_FlushN( FTC_Manager  manager,
                      FT_UInt      count )
  {
    FTC_Node  first = manager->nodes_list;
    FTC_Node  node;
    FT_UInt   result;

    /* try to remove `count' nodes from the list */
    if ( first == NULL )  /* empty list! */
      return 0;

    /* go to last node - it's a circular list */
    node = FTC_NODE__PREV(first);
    for ( result = 0; result < count; )
    {
      FTC_Node  prev = FTC_NODE__PREV( node );

      /* don't touch locked nodes */
      if ( node->ref_count <= 0 )
      {
        ftc_node_destroy( node, manager );
        result++;
      }

      if ( node == first )
        break;

      node = prev;
    }
    return  result;
  }

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( void )
  FTC_Manager_RemoveFaceID( FTC_Manager  manager,
                            FTC_FaceID   face_id )
  {
    FT_UInt  nn;

    /* this will remove all FTC_SizeNode that correspond to
     * the face_id as well
     */
    FTC_MruList_RemoveSelection( &manager->faces,
                                 ftc_face_node_compare,
                                 face_id );

    for ( nn = 0; nn < manager->num_caches; nn++ )
      FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
  }

  /* documentation is in ftcache.h */

  FT_EXPORT_DEF( void )
  FTC_Node_Unref( FTC_Node     node,
                  FTC_Manager  manager )
  {
    if ( node && (FT_UInt)node->cache_index < manager->num_caches )
      node->ref_count--;
  }

#ifdef FT_CONFIG_OPTION_OLD_INTERNALS

  FT_EXPORT_DEF( FT_Error )
  FTC_Manager_Lookup_Face( FTC_Manager  manager,
                           FTC_FaceID   face_id,
                           FT_Face     *aface )
  {
    return FTC_Manager_LookupFace( manager, face_id, aface );
  }

  FT_EXPORT( FT_Error )
  FTC_Manager_Lookup_Size( FTC_Manager  manager,
                           FTC_Font     font,
                           FT_Face     *aface,
                           FT_Size     *asize )
  {
    FTC_ScalerRec  scaler;
    FT_Error       error;
    FT_Size        size;
    FT_Face        face;

    scaler.face_id = font->face_id;
    scaler.width   = font->pix_width;
    scaler.height  = font->pix_height;
    scaler.pixel   = TRUE;
    scaler.x_res   = 0;
    scaler.y_res   = 0;

    error = FTC_Manager_LookupSize( manager, &scaler, &size );
    if ( error )
    {
      face = NULL;
      size = NULL;
    }
    else
      face = size->face;

    if ( aface )
      *aface = face;

    if ( asize )
      *asize = size;

    return error;
  }

#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftcmanag.h                                                             */
/*                                                                         */
/*    FreeType Cache Manager (specification).                              */
/*                                                                         */
/*  Copyright 2000-2001, 2003, 2004, 2006 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.                                        */
/*                                                                         */
/***************************************************************************/

  /*************************************************************************/
  /*                                                                       */
  /* A cache manager is in charge of the following:                        */
  /*                                                                       */
  /*  - Maintain a mapping between generic FTC_FaceIDs and live FT_Face    */
  /*    objects.  The mapping itself is performed through a user-provided  */
  /*    callback.  However, the manager maintains a small cache of FT_Face */
  /*    and FT_Size objects in order to speed up things considerably.      */
  /*                                                                       */
  /*  - Manage one or more cache objects.  Each cache is in charge of      */
  /*    holding a varying number of `cache nodes'.  Each cache node        */
  /*    represents a minimal amount of individually accessible cached      */
  /*    data.  For example, a cache node can be an FT_Glyph image          */
  /*    containing a vector outline, or some glyph metrics, or anything    */
  /*    else.                                                              */
  /*                                                                       */
  /*    Each cache node has a certain size in bytes that is added to the   */
  /*    total amount of `cache memory' within the manager.                 */
  /*                                                                       */
  /*    All cache nodes are located in a global LRU list, where the oldest */
  /*    node is at the tail of the list.                                   */
  /*                                                                       */
  /*    Each node belongs to a single cache, and includes a reference      */
  /*    count to avoid destroying it (due to caching).                     */
  /*                                                                       */
  /*************************************************************************/

  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /*********                                                       *********/
  /*********             WARNING, THIS IS BETA CODE.               *********/
  /*********                                                       *********/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/

#ifndef __FTCMANAG_H__
#define __FTCMANAG_H__

#include <ft2build.h>
#include FT_CACHE_H
#include "ftcmru.h"
#include "ftccache.h"

FT_BEGIN_HEADER

  /*************************************************************************/
  /*                                                                       */
  /* <Section>                                                             */
  /*    cache_subsystem                                                    */
  /*                                                                       */
  /*************************************************************************/

#define FTC_MAX_FACES_DEFAULT  2
#define FTC_MAX_SIZES_DEFAULT  4
#define FTC_MAX_BYTES_DEFAULT  200000L  /* ~200kByte by default */

  /* maximum number of caches registered in a single manager */
#define FTC_MAX_CACHES         16

  typedef struct  FTC_ManagerRec_
  {
    FT_Library          library;
    FT_Memory           memory;

    FTC_Node            nodes_list;
    FT_ULong            max_weight;
    FT_ULong            cur_weight;
    FT_UInt             num_nodes;

    FTC_Cache           caches[FTC_MAX_CACHES];
    FT_UInt             num_caches;

    FTC_MruListRec      faces;
    FTC_MruListRec      sizes;

    FT_Pointer          request_data;
    FTC_Face_Requester  request_face;

  } FTC_ManagerRec;

  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FTC_Manager_Compress                                               */
  /*                                                                       */
  /* <Description>                                                         */
  /*    This function is used to check the state of the cache manager if   */
  /*    its `num_bytes' field is greater than its `max_bytes' field.  It   */
  /*    will flush as many old cache nodes as possible (ignoring cache     */
  /*    nodes with a non-zero reference count).                            */
  /*                                                                       */
  /* <InOut>                                                               */
  /*    manager :: A handle to the cache manager.                          */
  /*                                                                       */
  /* <Note>                                                                */
  /*    Client applications should not call this function directly.  It is */
  /*    normally invoked by specific cache implementations.                */
  /*                                                                       */
  /*    The reason this function is exported is to allow client-specific   */
  /*    cache classes.                                                     */
  /*                                                                       */
  FT_LOCAL( void )
  FTC_Manager_Compress( FTC_Manager  manager );

  /* try to flush `count' old nodes from the cache; return the number
   * of really flushed nodes
   */
  FT_LOCAL( FT_UInt )
  FTC_Manager_FlushN( FTC_Manager  manager,
                      FT_UInt      count );

  /* this must be used internally for the moment */
  FT_LOCAL( FT_Error )
  FTC_Manager_RegisterCache( FTC_Manager      manager,
                             FTC_CacheClass   clazz,
                             FTC_Cache       *acache );

 /* */

#define FTC_SCALER_COMPARE( a, b )                \
    ( (a)->face_id      == (b)->face_id      &&   \
      (a)->width        == (b)->width        &&   \
      (a)->height       == (b)->height       &&   \
      ((a)->pixel != 0) == ((b)->pixel != 0) &&   \
      ( (a)->pixel ||                             \
        ( (a)->x_res == (b)->x_res &&             \
          (a)->y_res == (b)->y_res ) ) )

#define FTC_SCALER_HASH( q )                                 \
    ( _FTC_FACE_ID_HASH( (q)->face_id ) +                     \
      (q)->width + (q)->height*7 +                           \
      ( (q)->pixel ? 0 : ( (q)->x_res*33 ^ (q)->y_res*61 ) ) )

 /* */

FT_END_HEADER

#endif /* __FTCMANAG_H__ */

/* END */

license: mit


code:
/***************************************************************************/
/*                                                                         */
/*  ftcmru.c                                                               */
/*                                                                         */
/*    FreeType MRU support (body).                                         */
/*                                                                         */
/*  Copyright 2003, 2004, 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_CACHE_H
#include "ftcmru.h"
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H

#include "ftcerror.h"

  FT_LOCAL_DEF( void )
  FTC_MruNode_Prepend( FTC_MruNode  *plist,
                       FTC_MruNode   node )
  {
    FTC_MruNode  first = *plist;

    if ( first )
    {
      FTC_MruNode  last = first->prev;

#ifdef FT_DEBUG_ERROR
      {
        FTC_MruNode  cnode = first;

        do
        {
          if ( cnode == node )
          {
            fprintf( stderr, "FTC_MruNode_Prepend: invalid action\n" );
            exit( 2 );
          }
          cnode = cnode->next;

        } while ( cnode != first );
      }
#endif

      first->prev = node;
      last->next  = node;
      node->next  = first;
      node->prev  = last;
    }
    else
    {
      node->next = node;
      node->prev = node;
    }
    *plist = node;
  }

  FT_LOCAL_DEF( void )
  FTC_MruNode_Up( FTC_MruNode  *plist,
                  FTC_MruNode   node )
  {
    FTC_MruNode  first = *plist;

    FT_ASSERT( first != NULL );

    if ( first != node )
    {
      FTC_MruNode  prev, next, last;

#ifdef FT_DEBUG_ERROR
      {
        FTC_MruNode  cnode = first;
        do
        {
          if ( cnode == node )
            goto Ok;
          cnode = cnode->next;

        } while ( cnode != first );

        fprintf( stderr, "FTC_MruNode_Up: invalid action\n" );
        exit( 2 );
      Ok:
      }
#endif
      prev = node->prev;
      next = node->next;

      prev->next = next;
      next->prev = prev;

      last = first->prev;

      last->next  = node;
      first->prev = node;

      node->next = first;
      node->prev = last;

      *plist = node;
    }
  }

  FT_LOCAL_DEF( void )
  FTC_MruNode_Remove( FTC_MruNode  *plist,
                      FTC_MruNode   node )
  {
    FTC_MruNode  first = *plist;
    FTC_MruNode  prev, next;

    FT_ASSERT( first != NULL );

#ifdef FT_DEBUG_ERROR
      {
        FTC_MruNode  cnode = first;

        do
        {
          if ( cnode == node )
            goto Ok;
          cnode = cnode->next;

        } while ( cnode != first );

        fprintf( stderr, "FTC_MruNode_Remove: invalid action\n" );
        exit( 2 );
      Ok:
      }
#endif

    prev = node->prev;
    next = node->next;

    prev->next = next;
    next->prev = prev;

    if ( node == next )
    {
      FT_ASSERT( first == node );
      FT_ASSERT( prev  == node );

      *plist = NULL;
    }
    else if ( node == first )
        *plist = next;
  }

  FT_LOCAL_DEF( void )
  FTC_MruList_Init( FTC_MruList       list,
                    FTC_MruListClass  clazz,
                    FT_UInt           max_nodes,
                    FT_Pointer        data,
                    FT_Memory         memory )
  {
    list->num_nodes = 0;
    list->max_nodes = max_nodes;
    list->nodes     = NULL;
    list->clazz     = *clazz;
    list->data      = data;
    list->memory    = memory;
  }

  FT_LOCAL_DEF( void )
  FTC_MruList_Reset( FTC_MruList  list )
  {
    while ( list->nodes )
      FTC_MruList_Remove( list, list->nodes );

    FT_ASSERT( list->num_nodes == 0 );
  }

  FT_LOCAL_DEF( void )
  FTC_MruList_Done( FTC_MruList  list )
  {
    FTC_MruList_Reset( list );
  }

#ifndef FTC_INLINE
  FT_LOCAL_DEF( FTC_MruNode )
  FTC_MruList_Find( FTC_MruList  list,
                    FT_Pointer   key )
  {
    FTC_MruNode_CompareFunc  compare = list->clazz.node_compare;
    FTC_MruNode              first, node;

    first = list->nodes;
    node  = NULL;

    if ( first )
    {
      node = first;
      do
      {
        if ( compare( node, key ) )
        {
          if ( node != first )
            FTC_MruNode_Up( &list->nodes, node );

          return node;
        }

        node = node->next;

      } while ( node != first);
    }

    return NULL;
  }
#endif

  FT_LOCAL_DEF( FT_Error )
  FTC_MruList_New( FTC_MruList   list,
                   FT_Pointer    key,
                   FTC_MruNode  *anode )
  {
    FT_Error     error;
    FTC_MruNode  node;
    FT_Memory    memory = list->memory;

    if ( list->num_nodes >= list->max_nodes && list->max_nodes > 0 )
    {
      node = list->nodes->prev;

      FT_ASSERT( node );

      if ( list->clazz.node_reset )
      {
        FTC_MruNode_Up( &list->nodes, node );

        error = list->clazz.node_reset( node, key, list->data );
        if ( !error )
          goto Exit;
      }

      FTC_MruNode_Remove( &list->nodes, node );
      list->num_nodes--;

      if ( list->clazz.node_done )
        list->clazz.node_done( node, list->data );
    }
    else if ( FT_ALLOC( node, list->clazz.node_size ) )
        goto Exit;

    error = list->clazz.node_init( node, key, list->data );
    if ( error )
      goto Fail;

      FTC_MruNode_Prepend( &list->nodes, node );
      list->num_nodes++;

  Exit:
    *anode = node;
    return error;

  Fail:
    if ( list->clazz.node_done )
      list->clazz.node_done( node, list->data );

    FT_FREE( node );
    goto Exit;
  }

#ifndef FTC_INLINE
  FT_LOCAL_DEF( FT_Error )
  FTC_MruList_Lookup( FTC_MruList   list,
                      FT_Pointer    key,
                      FTC_MruNode  *anode )
  {
    FTC_MruNode  node;

    node = FTC_MruList_Find( list, key );
    if ( node == NULL )
      return FTC_MruList_New( list, key, anode );

    *anode = node;
    return 0;
  }
#endif /* FTC_INLINE */

  FT_LOCAL_DEF( void )
  FTC_MruList_Remove( FTC_MruList  list,
                      FTC_MruNode  node )
  {
    FTC_MruNode_Remove( &list->nodes, node );
    list->num_nodes--;

    {
      FT_Memory  memory = list->memory;

      if ( list->clazz.node_done )
       list->clazz.node_done( node, list->data );

      FT_FREE( node );
    }
  }

  FT_LOCAL_DEF( void )
  FTC_MruList_RemoveSelection( FTC_MruList              list,
                               FTC_MruNode_CompareFunc  selection,
                               FT_Pointer               key )
  {
    FTC_MruNode  first, node, next;

    first = list->nodes;
    while ( first && ( selection == NULL || selection( first, key ) ) )
    {
      FTC_MruList_Remove( list, first );
      first = list->nodes;
    }

    if ( first )
    {
      node = first->next;
      while ( node != first )
      {
        next = node->next;

        if ( selection( node, key ) )
          FTC_MruList_Remove( list, node );

        node = next;
      }
    }
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftcmru.h                                                               */
/*                                                                         */
/*    Simple MRU list-cache (specification).                               */
/*                                                                         */
/*  Copyright 2000-2001, 2003, 2004, 2005, 2006, 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.                                        */
/*                                                                         */
/***************************************************************************/

  /*************************************************************************/
  /*                                                                       */
  /* An MRU is a list that cannot hold more than a certain number of       */
  /* elements (`max_elements').  All elements in the list are sorted in    */
  /* least-recently-used order, i.e., the `oldest' element is at the tail  */
  /* of the list.                                                          */
  /*                                                                       */
  /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'),   */
  /* the list is searched for an element with the corresponding key.  If   */
  /* it is found, the element is moved to the head of the list and is      */
  /* returned.                                                             */
  /*                                                                       */
  /* If no corresponding element is found, the lookup routine will try to  */
  /* obtain a new element with the relevant key.  If the list is already   */
  /* full, the oldest element from the list is discarded and replaced by a */
  /* new one; a new element is added to the list otherwise.                */
  /*                                                                       */
  /* Note that it is possible to pre-allocate the element list nodes.      */
  /* This is handy if `max_elements' is sufficiently small, as it saves    */
  /* allocations/releases during the lookup process.                       */
  /*                                                                       */
  /*************************************************************************/

#ifndef __FTCMRU_H__
#define __FTCMRU_H__

#include <ft2build.h>
#include FT_FREETYPE_H

#ifdef FREETYPE_H
#error "freetype.h of FreeType 1 has been loaded!"
#error "Please fix the directory search order for header files"
#error "so that freetype.h of FreeType 2 is found first."
#endif

#define  xxFT_DEBUG_ERROR
#define  FTC_INLINE

FT_BEGIN_HEADER

  typedef struct FTC_MruNodeRec_*  FTC_MruNode;

  typedef struct  FTC_MruNodeRec_
  {
    FTC_MruNode  next;
    FTC_MruNode  prev;

  } FTC_MruNodeRec;

  FT_LOCAL( void )
  FTC_MruNode_Prepend( FTC_MruNode  *plist,
                       FTC_MruNode   node );

  FT_LOCAL( void )
  FTC_MruNode_Up( FTC_MruNode  *plist,
                  FTC_MruNode   node );

  FT_LOCAL( void )
  FTC_MruNode_Remove( FTC_MruNode  *plist,
                      FTC_MruNode   node );

  typedef struct FTC_MruListRec_*              FTC_MruList;

  typedef struct FTC_MruListClassRec_ const *  FTC_MruListClass;

  typedef FT_Bool
  (*FTC_MruNode_CompareFunc)( FTC_MruNode  node,
                              FT_Pointer   key );

  typedef FT_Error
  (*FTC_MruNode_InitFunc)( FTC_MruNode  node,
                           FT_Pointer   key,
                           FT_Pointer   data );

  typedef FT_Error
  (*FTC_MruNode_ResetFunc)( FTC_MruNode  node,
                            FT_Pointer   key,
                            FT_Pointer   data );

  typedef void
  (*FTC_MruNode_DoneFunc)( FTC_MruNode  node,
                           FT_Pointer   data );

  typedef struct  FTC_MruListClassRec_
  {
    FT_Offset                node_size;
    FTC_MruNode_CompareFunc  node_compare;
    FTC_MruNode_InitFunc     node_init;
    FTC_MruNode_ResetFunc    node_reset;
    FTC_MruNode_DoneFunc     node_done;

  } FTC_MruListClassRec;

  typedef struct  FTC_MruListRec_
  {
    FT_UInt              num_nodes;
    FT_UInt              max_nodes;
    FTC_MruNode          nodes;
    FT_Pointer           data;
    FTC_MruListClassRec  clazz;
    FT_Memory            memory;

  } FTC_MruListRec;

  FT_LOCAL( void )
  FTC_MruList_Init( FTC_MruList       list,
                    FTC_MruListClass  clazz,
                    FT_UInt           max_nodes,
                    FT_Pointer        data,
                    FT_Memory         memory );

  FT_LOCAL( void )
  FTC_MruList_Reset( FTC_MruList  list );

  FT_LOCAL( void )
  FTC_MruList_Done( FTC_MruList  list );

  FT_LOCAL( FT_Error )
  FTC_MruList_New( FTC_MruList   list,
                   FT_Pointer    key,
                   FTC_MruNode  *anode );

  FT_LOCAL( void )
  FTC_MruList_Remove( FTC_MruList  list,
                      FTC_MruNode  node );

  FT_LOCAL( void )
  FTC_MruList_RemoveSelection( FTC_MruList              list,
                               FTC_MruNode_CompareFunc  selection,
                               FT_Pointer               key );

#ifdef FTC_INLINE

#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error )           \
  FT_BEGIN_STMNT                                                            \
    FTC_MruNode*             _pfirst  = &(list)->nodes;                     \
    FTC_MruNode_CompareFunc  _compare = (FTC_MruNode_CompareFunc)(compare); \
    FTC_MruNode              _first, _node;                                 \
                                                                            \
                                                                            \
    error  = FTC_Err_Ok;                                                    \
    _first = *(_pfirst);                                                    \
    _node  = NULL;                                                          \
                                                                            \
    if ( _first )                                                           \
    {                                                                       \
      _node = _first;                                                       \
      do                                                                    \
      {                                                                     \
        if ( _compare( _node, (key) ) )                                     \
        {                                                                   \
          if ( _node != _first )                                            \
            FTC_MruNode_Up( _pfirst, _node );                               \
                                                                            \
          node = _node;                                                     \
          goto _MruOk;                                                      \
        }                                                                   \
        _node = _node->next;                                                \
                                                                            \
      } while ( _node != _first) ;                                          \
    }                                                                       \
                                                                            \
    error = FTC_MruList_New( (list), (key), (FTC_MruNode*)(void*)&(node) ); \
  _MruOk:                                                                   \
    ;                                                                       \
  FT_END_STMNT

#define FTC_MRULIST_LOOKUP( list, key, node, error ) \
  FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error )

#else  /* !FTC_INLINE */

  FT_LOCAL( FTC_MruNode )
  FTC_MruList_Find( FTC_MruList  list,
                    FT_Pointer   key );

  FT_LOCAL( FT_Error )
  FTC_MruList_Lookup( FTC_MruList   list,
                      FT_Pointer    key,
                      FTC_MruNode  *pnode );

#define FTC_MRULIST_LOOKUP( list, key, node, error ) \
  error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) )

#endif /* !FTC_INLINE */

#define FTC_MRULIST_LOOP( list, node )        \
  FT_BEGIN_STMNT                              \
    FTC_MruNode  _first = (list)->nodes;      \
                                              \
                                              \
    if ( _first )                             \
    {                                         \
      FTC_MruNode  _node = _first;            \
                                              \
                                              \
      do                                      \
      {                                       \
        *(FTC_MruNode*)&(node) = _node;

#define FTC_MRULIST_LOOP_END()               \
        _node = _node->next;                 \
                                             \
      } while ( _node != _first );           \
    }                                        \
  FT_END_STMNT

 /* */

FT_END_HEADER

#endif /* __FTCMRU_H__ */

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  ftcsbits.h                                                             */
/*                                                                         */
/*    A small-bitmap cache (specification).                                */
/*                                                                         */
/*  Copyright 2000-2001, 2002, 2003, 2006 by                               */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#ifndef __FTCSBITS_H__
#define __FTCSBITS_H__

#include <ft2build.h>
#include FT_CACHE_H
#include "ftcglyph.h"

FT_BEGIN_HEADER

#define FTC_SBIT_ITEMS_PER_NODE  16

  typedef struct  FTC_SNodeRec_
  {
    FTC_GNodeRec  gnode;
    FT_UInt       count;
    FTC_SBitRec   sbits[FTC_SBIT_ITEMS_PER_NODE];

  } FTC_SNodeRec, *FTC_SNode;

#define FTC_SNODE( x )         ( (FTC_SNode)( x ) )
#define FTC_SNODE_GINDEX( x )  FTC_GNODE( x )->gindex
#define FTC_SNODE_FAMILY( x )  FTC_GNODE( x )->family

  typedef FT_UInt
  (*FTC_SFamily_GetCountFunc)( FTC_Family   family,
                               FTC_Manager  manager );

  typedef FT_Error
  (*FTC_SFamily_LoadGlyphFunc)( FTC_Family   family,
                                FT_UInt      gindex,
                                FTC_Manager  manager,
                                FT_Face     *aface );

  typedef struct  FTC_SFamilyClassRec_
  {
    FTC_MruListClassRec        clazz;
    FTC_SFamily_GetCountFunc   family_get_count;
    FTC_SFamily_LoadGlyphFunc  family_load_glyph;

  } FTC_SFamilyClassRec;

  typedef const FTC_SFamilyClassRec*  FTC_SFamilyClass;

#define FTC_SFAMILY_CLASS( x )  ((FTC_SFamilyClass)(x))

#define FTC_CACHE__SFAMILY_CLASS( x )  \
          FTC_SFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS( x )->family_class )

  FT_LOCAL( void )
  FTC_SNode_Free( FTC_SNode  snode,
                  FTC_Cache  cache );

  FT_LOCAL( FT_Error )
  FTC_SNode_New( FTC_SNode   *psnode,
                 FTC_GQuery   gquery,
                 FTC_Cache    cache );

#if 0
  FT_LOCAL( FT_ULong )
  FTC_SNode_Weight( FTC_SNode  inode );
#endif

  FT_LOCAL( FT_Bool )
  FTC_SNode_Compare( FTC_SNode   snode,
                     FTC_GQuery  gquery,
                     FTC_Cache   cache );

  /* */

FT_END_HEADER

#endif /* __FTCSBITS_H__ */

/* END */


code:
#
# FreeType 2 Cache configuration rules
#

# Copyright 2000, 2001, 2003, 2004, 2006, 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.

# Cache driver directory
#
CACHE_DIR   := $(SRC_DIR)/cache

# compilation flags for the driver
#
CACHE_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(CACHE_DIR))

# Cache driver sources (i.e., C files)
#
CACHE_DRV_SRC := $(CACHE_DIR)/ftcbasic.c \
                 $(CACHE_DIR)/ftccache.c \
                 $(CACHE_DIR)/ftccmap.c  \
                 $(CACHE_DIR)/ftcglyph.c \
                 $(CACHE_DIR)/ftcimage.c \
                 $(CACHE_DIR)/ftcmanag.c \
                 $(CACHE_DIR)/ftcmru.c   \
                 $(CACHE_DIR)/ftcsbits.c

# Cache driver headers
#
CACHE_DRV_H := $(CACHE_DIR)/ftccache.h \
               $(CACHE_DIR)/ftccback.h \
               $(CACHE_DIR)/ftcerror.h \
               $(CACHE_DIR)/ftcglyph.h \
               $(CACHE_DIR)/ftcimage.h \
               $(CACHE_DIR)/ftcmanag.h \
               $(CACHE_DIR)/ftcmru.h   \
               $(CACHE_DIR)/ftcsbits.h

# Cache driver object(s)
#
#   CACHE_DRV_OBJ_M is used during `multi' builds.
#   CACHE_DRV_OBJ_S is used during `single' builds.
#
CACHE_DRV_OBJ_M := $(CACHE_DRV_SRC:$(CACHE_DIR)/%.c=$(OBJ_DIR)/%.$O)
CACHE_DRV_OBJ_S := $(OBJ_DIR)/ftcache.$O

# Cache driver source file for single build
#
CACHE_DRV_SRC_S := $(CACHE_DIR)/ftcache.c

# Cache driver - single object
#
$(CACHE_DRV_OBJ_S): $(CACHE_DRV_SRC_S) $(CACHE_DRV_SRC) \
                   $(FREETYPE_H) $(CACHE_DRV_H)
	$(CACHE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(CACHE_DRV_SRC_S))

# Cache driver - multiple objects
#
$(OBJ_DIR)/%.$O: $(CACHE_DIR)/%.c $(FREETYPE_H) $(CACHE_DRV_H)
	$(CACHE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)

# update main driver object lists
#
DRV_OBJS_S += $(CACHE_DRV_OBJ_S)
DRV_OBJS_M += $(CACHE_DRV_OBJ_M)

# EOF


code:
# FreeType 2 src/cff Jamfile
#
# Copyright 2001, 2002 by
# David Turner, Robert Wilhelm, and Werner Lemberg.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.

SubDir  FT2_TOP $(FT2_SRC_DIR) cff ;

{
  local  _sources ;

  if $(FT2_MULTI)
  {
    _sources = cffdrivr cffgload cffload cffobjs cffparse cffcmap cffpic ;
  }
  else
  {
    _sources = cff ;
  }

  Library  $(FT2_LIB) : $(_sources).c ;
}

# end of src/cff Jamfile


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

#define FT_MAKE_OPTION_SINGLE_OBJECT

#include <ft2build.h>
#include "cffpic.c"
#include "cffdrivr.c"
#include "cffparse.c"
#include "cffload.c"
#include "cffobjs.c"
#include "cffgload.c"
#include "cffcmap.c"

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  cffdrivr.c                                                             */
/*                                                                         */
/*    OpenType font driver implementation (body).                          */
/*                                                                         */
/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 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_FREETYPE_H
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_SFNT_H
#include FT_SERVICE_CID_H
#include FT_SERVICE_POSTSCRIPT_INFO_H
#include FT_SERVICE_POSTSCRIPT_NAME_H
#include FT_SERVICE_TT_CMAP_H

#include "cffdrivr.h"
#include "cffgload.h"
#include "cffload.h"
#include "cffcmap.h"
#include "cffparse.h"

#include "cfferrs.h"
#include "cffpic.h"

#include FT_SERVICE_XFREE86_NAME_H
#include FT_SERVICE_GLYPH_DICT_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_cffdriver

  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****                                                                 ****/
  /****                          F A C E S                              ****/
  /****                                                                 ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/

#undef  PAIR_TAG
#define PAIR_TAG( left, right )  ( ( (FT_ULong)left << 16 ) | \
                                     (FT_ULong)right        )

  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    cff_get_kerning                                                    */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to return the kerning vector between two      */
  /*    glyphs of the same face.                                           */
  /*                                                                       */
  /* <Input>                                                               */
  /*    face        :: A handle to the source face object.                 */
  /*                                                                       */
  /*    left_glyph  :: The index of the left glyph in the kern pair.       */
  /*                                                                       */
  /*    right_glyph :: The index of the right glyph in the kern pair.      */
  /*                                                                       */
  /* <Output>                                                              */
  /*    kerning     :: The kerning vector.  This is in font units for      */
  /*                   scalable formats, and in pixels for fixed-sizes     */
  /*                   formats.                                            */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    Only horizontal layouts (left-to-right & right-to-left) are        */
  /*    supported by this function.  Other layouts, or more sophisticated  */
  /*    kernings, are out of scope of this method (the basic driver        */
  /*    interface is meant to be simple).                                  */
  /*                                                                       */
  /*    They can be implemented by format-specific interfaces.             */
  /*                                                                       */
  FT_CALLBACK_DEF( FT_Error )
  cff_get_kerning( FT_Face     ttface,          /* TT_Face */
                   FT_UInt     left_glyph,
                   FT_UInt     right_glyph,
                   FT_Vector*  kerning )
  {
    TT_Face       face = (TT_Face)ttface;
    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;

    kerning->x = 0;
    kerning->y = 0;

    if ( sfnt )
      kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );

    return CFF_Err_Ok;
  }

#undef PAIR_TAG

  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Load_Glyph                                                         */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to load a glyph within a given glyph slot.    */
  /*                                                                       */
  /* <Input>                                                               */
  /*    slot        :: A handle to the target slot object where the glyph  */
  /*                   will be loaded.                                     */
  /*                                                                       */
  /*    size        :: A handle to the source face size at which the glyph */
  /*                   must be scaled, loaded, etc.                        */
  /*                                                                       */
  /*    glyph_index :: The index of the glyph in the font file.            */
  /*                                                                       */
  /*    load_flags  :: A flag indicating what to load for this glyph.  The */
  /*                   FT_LOAD_??? constants can be used to control the    */
  /*                   glyph loading process (e.g., whether the outline    */
  /*                   should be scaled, whether to load bitmaps or not,   */
  /*                   whether to hint the outline, etc).                  */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  FT_CALLBACK_DEF( FT_Error )
  Load_Glyph( FT_GlyphSlot  cffslot,        /* CFF_GlyphSlot */
              FT_Size       cffsize,        /* CFF_Size      */
              FT_UInt       glyph_index,
              FT_Int32      load_flags )
  {
    FT_Error       error;
    CFF_GlyphSlot  slot = (CFF_GlyphSlot)cffslot;
    CFF_Size       size = (CFF_Size)cffsize;

    if ( !slot )
      return CFF_Err_Invalid_Slot_Handle;

    /* check whether we want a scaled outline or bitmap */
    if ( !size )
      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;

    /* reset the size object if necessary */
    if ( load_flags & FT_LOAD_NO_SCALE )
      size = NULL;

    if ( size )
    {
      /* these two objects must have the same parent */
      if ( cffsize->face != cffslot->face )
        return CFF_Err_Invalid_Face_Handle;
    }

    /* now load the glyph outline if necessary */
    error = cff_slot_load( slot, size, glyph_index, load_flags );

    /* force drop-out mode to 2 - irrelevant now */
    /* slot->outline.dropout_mode = 2; */

    return error;
  }

  FT_CALLBACK_DEF( FT_Error )
  cff_get_advances( FT_Face    face,
                    FT_UInt    start,
                    FT_UInt    count,
                    FT_Int32   flags,
                    FT_Fixed*  advances )
  {
    FT_UInt       nn;
    FT_Error      error = CFF_Err_Ok;
    FT_GlyphSlot  slot  = face->glyph;

    flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;

    for ( nn = 0; nn < count; nn++ )
    {
      error = Load_Glyph( slot, face->size, start + nn, flags );
      if ( error )
        break;

      advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
                     ? slot->linearVertAdvance
                     : slot->linearHoriAdvance;
    }

    return error;
  }

  /*
   *  GLYPH DICT SERVICE
   *
   */

  static FT_Error
  cff_get_glyph_name( CFF_Face    face,
                      FT_UInt     glyph_index,
                      FT_Pointer  buffer,
                      FT_UInt     buffer_max )
  {
    CFF_Font    font   = (CFF_Font)face->extra.data;
    FT_String*  gname;
    FT_UShort   sid;
    FT_Error    error;

    if ( !font->psnames )
    {
      FT_ERROR(( "cff_get_glyph_name:"
                 " cannot get glyph name from CFF & CEF fonts\n"
                 "                   "
                 " without the `PSNames' module\n" ));
      error = CFF_Err_Unknown_File_Format;
      goto Exit;
    }

    /* first, locate the sid in the charset table */
    sid = font->charset.sids[glyph_index];

    /* now, lookup the name itself */
    gname = cff_index_get_sid_string( font, sid );

    if ( gname )
      FT_STRCPYN( buffer, gname, buffer_max );

    error = CFF_Err_Ok;

  Exit:
    return error;
  }

  static FT_UInt
  cff_get_name_index( CFF_Face    face,
                      FT_String*  glyph_name )
  {
    CFF_Font            cff;
    CFF_Charset         charset;
    FT_Service_PsCMaps  psnames;
    FT_String*          name;
    FT_UShort           sid;
    FT_UInt             i;

    cff     = (CFF_FontRec *)face->extra.data;
    charset = &cff->charset;

    FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
    if ( !psnames )
      return 0;

    for ( i = 0; i < cff->num_glyphs; i++ )
    {
      sid = charset->sids[i];

      if ( sid > 390 )
        name = cff_index_get_string( cff, sid - 391 );
      else
        name = (FT_String *)psnames->adobe_std_strings( sid );

      if ( !name )
        continue;

      if ( !ft_strcmp( glyph_name, name ) )
        return i;
    }

    return 0;
  }

  FT_DEFINE_SERVICE_GLYPHDICTREC(cff_service_glyph_dict,
    (FT_GlyphDict_GetNameFunc)  cff_get_glyph_name,
    (FT_GlyphDict_NameIndexFunc)cff_get_name_index
  )

  /*
   *  POSTSCRIPT INFO SERVICE
   *
   */

  static FT_Int
  cff_ps_has_glyph_names( FT_Face  face )
  {
    return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0;
  }

  static FT_Error
  cff_ps_get_font_info( CFF_Face         face,
                        PS_FontInfoRec*  afont_info )
  {
    CFF_Font  cff   = (CFF_Font)face->extra.data;
    FT_Error  error = CFF_Err_Ok;

    if ( cff && cff->font_info == NULL )
    {
      CFF_FontRecDict  dict   = &cff->top_font.font_dict;
      PS_FontInfoRec  *font_info;
      FT_Memory        memory = face->root.memory;

      if ( FT_ALLOC( font_info, sizeof ( *font_info ) ) )
        goto Fail;

      font_info->version     = cff_index_get_sid_string( cff,
                                                         dict->version );
      font_info->notice      = cff_index_get_sid_string( cff,
                                                         dict->notice );
      font_info->full_name   = cff_index_get_sid_string( cff,
                                                         dict->full_name );
      font_info->family_name = cff_index_get_sid_string( cff,
                                                         dict->family_name );
      font_info->weight      = cff_index_get_sid_string( cff,
                                                         dict->weight );
      font_info->italic_angle        = dict->italic_angle;
      font_info->is_fixed_pitch      = dict->is_fixed_pitch;
      font_info->underline_position  = (FT_Short)dict->underline_position;
      font_info->underline_thickness = (FT_Short)dict->underline_thickness;

      cff->font_info = font_info;
    }

    if ( cff )
      *afont_info = *cff->font_info;

  Fail:
    return error;
  }

  FT_DEFINE_SERVICE_PSINFOREC(cff_service_ps_info,
    (PS_GetFontInfoFunc)   cff_ps_get_font_info,
    (PS_GetFontExtraFunc)  NULL,
    (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names,
    (PS_GetFontPrivateFunc)NULL         /* unsupported with CFF fonts */
  )

  /*
   *  POSTSCRIPT NAME SERVICE
   *
   */

  static const char*
  cff_get_ps_name( CFF_Face  face )
  {
    CFF_Font  cff = (CFF_Font)face->extra.data;

    return (const char*)cff->font_name;
  }

  FT_DEFINE_SERVICE_PSFONTNAMEREC(cff_service_ps_name,
    (FT_PsName_GetFunc)cff_get_ps_name
  )

  /*
   * TT CMAP INFO
   *
   * If the charmap is a synthetic Unicode encoding cmap or
   * a Type 1 standard (or expert) encoding cmap, hide TT CMAP INFO
   * service defined in SFNT module.
   *
   * Otherwise call the service function in the sfnt module.
   *
   */
  static FT_Error
  cff_get_cmap_info( FT_CharMap    charmap,
                     TT_CMapInfo  *cmap_info )
  {
    FT_CMap   cmap  = FT_CMAP( charmap );
    FT_Error  error = CFF_Err_Ok;
    FT_Face    face    = FT_CMAP_FACE( cmap );
    FT_Library library = FT_FACE_LIBRARY( face );

    cmap_info->language = 0;
    cmap_info->format   = 0;

    if ( cmap->clazz != &FT_CFF_CMAP_ENCODING_CLASS_REC_GET &&
         cmap->clazz != &FT_CFF_CMAP_UNICODE_CLASS_REC_GET  )
    {
      FT_Module           sfnt    = FT_Get_Module( library, "sfnt" );
      FT_Service_TTCMaps  service =
        (FT_Service_TTCMaps)ft_module_get_service( sfnt,
                                                   FT_SERVICE_ID_TT_CMAP );

      if ( service && service->get_cmap_info )
        error = service->get_cmap_info( charmap, cmap_info );
    }

    return error;
  }

  FT_DEFINE_SERVICE_TTCMAPSREC(cff_service_get_cmap_info,
    (TT_CMap_Info_GetFunc)cff_get_cmap_info
  )

  /*
   *  CID INFO SERVICE
   *
   */
  static FT_Error
  cff_get_ros( CFF_Face      face,
               const char*  *registry,
               const char*  *ordering,
               FT_Int       *supplement )
  {
    FT_Error  error = CFF_Err_Ok;
    CFF_Font  cff   = (CFF_Font)face->extra.data;

    if ( cff )
    {
      CFF_FontRecDict  dict = &cff->top_font.font_dict;

      if ( dict->cid_registry == 0xFFFFU )
      {
        error = CFF_Err_Invalid_Argument;
        goto Fail;
      }

      if ( registry )
      {
        if ( cff->registry == NULL )
          cff->registry = cff_index_get_sid_string( cff,
                                                    dict->cid_registry );
        *registry = cff->registry;
      }

      if ( ordering )
      {
        if ( cff->ordering == NULL )
          cff->ordering = cff_index_get_sid_string( cff,
                                                    dict->cid_ordering );
        *ordering = cff->ordering;
      }

      /*
       * XXX: According to Adobe TechNote #5176, the supplement in CFF
       *      can be a real number. We truncate it to fit public API
       *      since freetype-2.3.6.
       */
      if ( supplement )
      {
        if ( dict->cid_supplement < FT_INT_MIN ||
             dict->cid_supplement > FT_INT_MAX )
          FT_TRACE1(( "cff_get_ros: too large supplement %d is truncated\n",
                      dict->cid_supplement ));
        *supplement = (FT_Int)dict->cid_supplement;
      }
    }

  Fail:
    return error;
  }

  static FT_Error
  cff_get_is_cid( CFF_Face  face,
                  FT_Bool  *is_cid )
  {
    FT_Error  error = CFF_Err_Ok;
    CFF_Font  cff   = (CFF_Font)face->extra.data;

    *is_cid = 0;

    if ( cff )
    {
      CFF_FontRecDict  dict = &cff->top_font.font_dict;

      if ( dict->cid_registry != 0xFFFFU )
        *is_cid = 1;
    }

    return error;
  }

  static FT_Error
  cff_get_cid_from_glyph_index( CFF_Face  face,
                                FT_UInt   glyph_index,
                                FT_UInt  *cid )
  {
    FT_Error  error = CFF_Err_Ok;
    CFF_Font  cff;

    cff = (CFF_Font)face->extra.data;

    if ( cff )
    {
      FT_UInt          c;
      CFF_FontRecDict  dict = &cff->top_font.font_dict;

      if ( dict->cid_registry == 0xFFFFU )
      {
        error = CFF_Err_Invalid_Argument;
        goto Fail;
      }

      if ( glyph_index > cff->num_glyphs )
      {
        error = CFF_Err_Invalid_Argument;
        goto Fail;
      }

      c = cff->charset.sids[glyph_index];

      if ( cid )
        *cid = c;
    }

  Fail:
    return error;
  }

  FT_DEFINE_SERVICE_CIDREC(cff_service_cid_info,
    (FT_CID_GetRegistryOrderingSupplementFunc)cff_get_ros,
    (FT_CID_GetIsInternallyCIDKeyedFunc)      cff_get_is_cid,
    (FT_CID_GetCIDFromGlyphIndexFunc)         cff_get_cid_from_glyph_index
  )

  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****                                                                 ****/
  /****                D R I V E R  I N T E R F A C E                   ****/
  /****                                                                 ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
  FT_DEFINE_SERVICEDESCREC6(cff_services,
    FT_SERVICE_ID_XF86_NAME,            FT_XF86_FORMAT_CFF,
    FT_SERVICE_ID_POSTSCRIPT_INFO,      &FT_CFF_SERVICE_PS_INFO_GET,
    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &FT_CFF_SERVICE_PS_NAME_GET,
    FT_SERVICE_ID_GLYPH_DICT,           &FT_CFF_SERVICE_GLYPH_DICT_GET,
    FT_SERVICE_ID_TT_CMAP,              &FT_CFF_SERVICE_GET_CMAP_INFO_GET,
    FT_SERVICE_ID_CID,                  &FT_CFF_SERVICE_CID_INFO_GET
  )
#else
  FT_DEFINE_SERVICEDESCREC5(cff_services,
    FT_SERVICE_ID_XF86_NAME,            FT_XF86_FORMAT_CFF,
    FT_SERVICE_ID_POSTSCRIPT_INFO,      &FT_CFF_SERVICE_PS_INFO_GET,
    FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &FT_CFF_SERVICE_PS_NAME_GET,
    FT_SERVICE_ID_TT_CMAP,              &FT_CFF_SERVICE_GET_CMAP_INFO_GET,
    FT_SERVICE_ID_CID,                  &FT_CFF_SERVICE_CID_INFO_GET
  )
#endif

  FT_CALLBACK_DEF( FT_Module_Interface )
  cff_get_interface( FT_Module    driver,       /* CFF_Driver */
                     const char*  module_interface )
  {
    FT_Module            sfnt;
    FT_Module_Interface  result;

    result = ft_service_list_lookup( FT_CFF_SERVICES_GET, module_interface );
    if ( result != NULL )
      return  result;

    if ( !driver )
      return NULL;

    /* we pass our request to the `sfnt' module */
    sfnt = FT_Get_Module( driver->library, "sfnt" );

    return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0;
  }

  /* The FT_DriverInterface structure is defined in ftdriver.h. */

#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
#define CFF_SIZE_SELECT cff_size_select
#else
#define CFF_SIZE_SELECT 0
#endif

  FT_DEFINE_DRIVER(cff_driver_class,
      FT_MODULE_FONT_DRIVER       |
      FT_MODULE_DRIVER_SCALABLE   |
      FT_MODULE_DRIVER_HAS_HINTER,

      sizeof( CFF_DriverRec ),
      "cff",
      0x10000L,
      0x20000L,

      0,   /* module-specific interface */

      cff_driver_init,
      cff_driver_done,
      cff_get_interface,

    /* now the specific driver fields */
    sizeof( TT_FaceRec ),
    sizeof( CFF_SizeRec ),
    sizeof( CFF_GlyphSlotRec ),

    cff_face_init,
    cff_face_done,
    cff_size_init,
    cff_size_done,
    cff_slot_init,
    cff_slot_done,

    ft_stub_set_char_sizes, /* FT_CONFIG_OPTION_OLD_INTERNALS */
    ft_stub_set_pixel_sizes, /* FT_CONFIG_OPTION_OLD_INTERNALS */

    Load_Glyph,

    cff_get_kerning,
    0,                      /* FT_Face_AttachFunc      */
    cff_get_advances,       /* FT_Face_GetAdvancesFunc */

    cff_size_request,

    CFF_SIZE_SELECT
  )

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  cffdrivr.h                                                             */
/*                                                                         */
/*    High-level OpenType driver interface (specification).                */
/*                                                                         */
/*  Copyright 1996-2001, 2002 by                                           */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/

#ifndef __CFFDRIVER_H__
#define __CFFDRIVER_H__

#include <ft2build.h>
#include FT_INTERNAL_DRIVER_H

FT_BEGIN_HEADER

  FT_DECLARE_DRIVER( cff_driver_class )

FT_END_HEADER

#endif /* __CFFDRIVER_H__ */

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  cfferrs.h                                                              */
/*                                                                         */
/*    CFF error codes (specification only).                                */
/*                                                                         */
/*  Copyright 2001 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 is used to define the CFF error enumeration constants.      */
  /*                                                                       */
  /*************************************************************************/

#ifndef __CFFERRS_H__
#define __CFFERRS_H__

#include FT_MODULE_ERRORS_H

#undef __FTERRORS_H__

#define FT_ERR_PREFIX  CFF_Err_
#define FT_ERR_BASE    FT_Mod_Err_CFF

#include FT_ERRORS_H

#endif /* __CFFERRS_H__ */

/* END */