shithub: freetype+ttf2subf

Download patch

ref: 57ecae22a7b837d486bb03eda944736780ce0868
parent: 9e185f32ce3e99c31d66c24e75d5033a3a3ac244
author: David Turner <[email protected]>
date: Fri Dec 19 16:23:58 EST 2003

new version of the cache sub-system - still under debugging

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/cache/ftccache.h
+++ b/include/freetype/cache/ftccache.h
@@ -20,10 +20,7 @@
 #define __FTCCACHE_H__
 
 
-/* define to allow cache lookup inlining */
-#define  FTC_CACHE_USE_INLINE
 
-
 FT_BEGIN_HEADER
 
   /* handle to cache object */
@@ -30,15 +27,8 @@
   typedef struct FTC_CacheRec_*  FTC_Cache;
 
   /* handle to cache class */
-  typedef const struct FTC_Cache_ClassRec_*  FTC_Cache_Class;
+  typedef const struct FTC_CacheClassRec_*  FTC_CacheClass;
 
-  /* handle to cache node family */
-  typedef struct FTC_FamilyRec_*  FTC_Family;
-
-  /* handle to cache root query */
-  typedef struct FTC_QueryRec_*  FTC_Query;
-
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -66,7 +56,7 @@
     FTC_Node   mru_prev;     /* circular mru list pointer           */
     FTC_Node   link;         /* used for hashing                    */
     FT_UInt32  hash;         /* used for hashing too                */
-    FT_UShort  fam_index;    /* index of family the node belongs to */
+    FT_UShort  cache_index;  /* index of cache the node belongs to  */
     FT_Short   ref_count;    /* reference count for this node       */
 
   } FTC_NodeRec;
@@ -83,11 +73,6 @@
   /* cache sub-system internals.                                           */
   /*                                                                       */
 
-  /* can be used as a FTC_Node_DoneFunc */
-  FT_EXPORT( void )
-  ftc_node_done( FTC_Node   node,
-                 FTC_Cache  cache );
-
   /* reserved for manager's use */
   FT_EXPORT( void )
   ftc_node_destroy( FTC_Node     node,
@@ -94,98 +79,67 @@
                     FTC_Manager  manager );
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                   CACHE QUERY DEFINITIONS                     *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
 
-  /* A structure modelling a cache node query.  The following fields must  */
-  /* all be set by the @FTC_Family_CompareFunc method of a cache's family  */
-  /* list.                                                                 */
-  /*                                                                       */
-  typedef struct  FTC_QueryRec_
-  {
-    FTC_Family  family;
-    FT_UFast    hash;
-
-  } FTC_QueryRec;
-
-
-#define FTC_QUERY( x )    ( (FTC_Query)(x) )
-#define FTC_QUERY_P( x )  ( (FTC_Query*)(x) )
-
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
-  /*****                   CACHE FAMILY DEFINITIONS                    *****/
+  /*****                       CACHE DEFINITIONS                       *****/
   /*****                                                               *****/
   /*************************************************************************/
   /*************************************************************************/
 
-  typedef struct  FTC_FamilyRec_
-  {
-    FT_LruNodeRec  lru;
-    FTC_Cache      cache;
-    FT_UInt        num_nodes;
-    FT_UInt        fam_index;
+  /* initialize a new cache node */
+  typedef FT_Error    (*FTC_Node_NewFunc)( FTC_Node    *pnode,
+                                           FT_Pointer   query,
+                                           FTC_Cache    cache );
 
-  } FTC_FamilyRec;
+  typedef FT_ULong    (*FTC_Node_WeightFunc)( FTC_Node   node,
+                                              FTC_Cache  cache );
 
+  /* compare a node to a given key pair */
+  typedef FT_Bool     (*FTC_Node_CompareFunc)( FTC_Node    node,
+                                               FT_Pointer  key,
+                                               FTC_Cache   cache );
 
-#define FTC_FAMILY( x )    ( (FTC_Family)(x) )
-#define FTC_FAMILY_P( x )  ( (FTC_Family*)(x) )
 
+  typedef void        (*FTC_Node_FreeFunc)( FTC_Node   node,
+                                            FTC_Cache  cache );
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* These functions are exported so that they can be called from          */
-  /* user-provided cache classes; otherwise, they are really part of the   */
-  /* cache sub-system internals.                                           */
-  /*                                                                       */
+  typedef FT_Error    (*FTC_Cache_InitFunc)( FTC_Cache   cache );
 
-  /* must be called by any FTC_Node_InitFunc routine */
-  FT_EXPORT( FT_Error )
-  ftc_family_init( FTC_Family  family,
-                   FTC_Query   query,
-                   FTC_Cache   cache );
+  typedef void        (*FTC_Cache_DoneFunc)( FTC_Cache   cache );
 
 
-  /* can be used as a FTC_Family_DoneFunc; otherwise, must be called */
-  /* by any family finalizer function                                */
-  FT_EXPORT( void )
-  ftc_family_done( FTC_Family  family );
+  typedef struct FTC_CacheClassRec_
+  {
+    FTC_Node_NewFunc        node_new;
+    FTC_Node_WeightFunc     node_weight;
+    FTC_Node_CompareFunc    node_compare;
+    FTC_Node_CompareFunc    node_remove_faceid;
+    FTC_Node_FreeFunc       node_free;
 
+    FT_UInt                 cache_size;
+    FTC_Cache_InitFunc      cache_init;
+    FTC_Cache_DoneFunc      cache_done;
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                       CACHE DEFINITIONS                       *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
+  } FTC_CacheClassRec;
 
   /* each cache really implements a dynamic hash table to manage its nodes */
   typedef struct  FTC_CacheRec_
   {
-    FTC_Manager          manager;
-    FT_Memory            memory;
-    FTC_Cache_Class      clazz;
-
-    FT_UInt              cache_index;  /* in manager's table         */
-    FT_Pointer           cache_data;   /* used by cache node methods */
-
     FT_UFast             p;
     FT_UFast             mask;
     FT_Long              slack;
     FTC_Node*            buckets;
 
-    FT_LruList_ClassRec  family_class;
-    FT_LruList           families;
+    FTC_CacheClassRec    clazz;      /* local copy, for speed */
 
+    FTC_Manager          manager;
+    FT_Memory            memory;
+    FT_UInt              index;  /* in manager's table         */
+
+    FTC_CacheClass       org_class;  /* original class pointer */
+
   } FTC_CacheRec;
 
 
@@ -193,105 +147,38 @@
 #define FTC_CACHE_P( x )  ( (FTC_Cache*)(x) )
 
 
-  /* initialize a given cache */
-  typedef FT_Error
-  (*FTC_Cache_InitFunc)( FTC_Cache  cache );
+ /* default cache initialize */
+  FT_EXPORT( FT_Error )
+  FTC_Cache_Init( FTC_Cache       cache );
 
-  /* clear a cache */
-  typedef void
-  (*FTC_Cache_ClearFunc)( FTC_Cache  cache );
-
-  /* finalize a given cache */
-  typedef void
-  (*FTC_Cache_DoneFunc)( FTC_Cache  cache );
-
-
-  typedef FT_Error
-  (*FTC_Family_InitFunc)( FTC_Family  family,
-                          FTC_Query   query,
-                          FTC_Cache   cache );
-
-  typedef FT_Int
-  (*FTC_Family_CompareFunc)( FTC_Family  family,
-                             FTC_Query   query );
-
-  typedef void
-  (*FTC_Family_DoneFunc)( FTC_Family  family,
-                          FTC_Cache   cache );
-
-  /* initialize a new cache node */
-  typedef FT_Error
-  (*FTC_Node_InitFunc)( FTC_Node    node,
-                        FT_Pointer  type,
-                        FTC_Cache   cache );
-
-  /* compute the weight of a given cache node */
-  typedef FT_ULong
-  (*FTC_Node_WeightFunc)( FTC_Node   node,
-                          FTC_Cache  cache );
-
-  /* compare a node to a given key pair */
-  typedef FT_Bool
-  (*FTC_Node_CompareFunc)( FTC_Node    node,
-                           FT_Pointer  key,
-                           FTC_Cache   cache );
-
-  /* finalize a given cache node */
-  typedef void
-  (*FTC_Node_DoneFunc)( FTC_Node   node,
-                        FTC_Cache  cache );
-
-
-  typedef struct  FTC_Cache_ClassRec_
-  {
-    FT_UInt                 cache_size;
-    FTC_Cache_InitFunc      cache_init;
-    FTC_Cache_ClearFunc     cache_clear;
-    FTC_Cache_DoneFunc      cache_done;
-
-    FT_UInt                 family_size;
-    FTC_Family_InitFunc     family_init;
-    FTC_Family_CompareFunc  family_compare;
-    FTC_Family_DoneFunc     family_done;
-
-    FT_UInt                 node_size;
-    FTC_Node_InitFunc       node_init;
-    FTC_Node_WeightFunc     node_weight;
-    FTC_Node_CompareFunc    node_compare;
-    FTC_Node_DoneFunc       node_done;
-
-  } FTC_Cache_ClassRec;
-
-
-  /* */
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* These functions are exported so that they can be called from          */
-  /* user-provided cache classes; otherwise, they are really part of the   */
-  /* cache sub-system internals.                                           */
-  /*                                                                       */
-
-  /* can be used directly as FTC_Cache_DoneFunc(), or called by custom */
-  /* cache finalizers                                                  */
+ /* default cache finalizer */
   FT_EXPORT( void )
-  ftc_cache_done( FTC_Cache  cache );
+  FTC_Cache_Done( FTC_Cache  cache );
 
-  /* can be used directly as FTC_Cache_ClearFunc(), or called by custom */
-  /* cache clear routines                                               */
-  FT_EXPORT( void )
-  ftc_cache_clear( FTC_Cache  cache );
-
-  /* initalize the hash table within the cache */
+ /* call this function to lookup the cache. if no corresponding
+  * node is found, a new one is automatically created. This function
+  * is capable of flushing the cache adequately to make room for the
+  * new cache object.
+  */
   FT_EXPORT( FT_Error )
-  ftc_cache_init( FTC_Cache  cache );
+  FTC_Cache_Lookup( FTC_Cache   cache,
+                    FT_UInt32   hash,
+                    FT_Pointer  query,
+                    FTC_Node   *anode );
 
-  /* can be called when the key's hash value has been computed */
-  FT_EXPORT( FT_Error )
-  ftc_cache_lookup( FTC_Cache  cache,
-                    FTC_Query  query,
-                    FTC_Node  *anode );
+ /* remove all nodes that relate to a given face_id. This is useful
+  * when un-installing fonts. Note that if a cache node relates to
+  * the face_id, but is locked (i.e. has 'ref_count > 0'), the node
+  * will _not_ be destroyed, but its internal face_id reference will
+  * be modified.
+  *
+  * the end result will be that the node will never come back
+  * in further lookup requests, and will be flushed on demand from
+  * the cache normally when its reference count reaches 0
+  */
+  FT_EXPORT( void )
+  FTC_Cache_RemoveFaceID( FTC_Cache    cache,
+                          FTC_FaceID   face_id );
 
  /* */
 
--- a/include/freetype/cache/ftcglyph.h
+++ b/include/freetype/cache/ftcglyph.h
@@ -16,13 +16,84 @@
 /***************************************************************************/
 
 
+  /*
+   *
+   *  FTC_GCache is an _abstract_ cache object optimized to store glyph
+   *  data. It works as follows:
+   *
+   *   - it manages FTC_GNode objects. Each one of them can hold one or more
+   *     glyph "items". Item types are not specified in the FTC_GCache but in
+   *     classes that extend it
+   *
+   *   - glyph attributes, like face_id, character size, render mode, etc..
+   *     can be grouped in abstract "glyph families". This avoids storing
+   *     the attributes within the FTC_GCache, since it is likely that many
+   *     FTC_GNodes will belong to the same family in typical uses
+   *
+   *   - each FTC_GNode is thus a FTC_Node with two additionnal fields:
+   *
+   *       * gindex :: a glyph index, or the first index in a glyph range
+   *       * family :: a pointer to a glyph "family"
+   *
+   *   - Family types are not fully specific in the FTC_Family type, but
+   *     by classes that extend it.
+   *
+   *  Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. They
+   *  share an FTC_Family sub-class called FTC_BasicFamily which is used to
+   *  store the following data:  face_id, pixel/point sizes, load flags.
+   *  for more details, see the file "src/cache/ftcbasic.c"
+   *
+   *  Client applications can extend FTC_GNode with their own FTC_GNode
+   *  and FTC_Family sub-classes to implement more complex caches (e.g.
+   *  handling automatic synthetis, like obliquing & emboldening, colored
+   *  glyphs, etc...)
+   *
+   *  See also the FTC_ICache & FTC_SCache classes in "ftcimage.h" and
+   *  "ftcsbits.h", which both extend FTC_GCache with additionnal
+   *  optimizations.
+   *
+   *
+   *  a typical FTC_GCache implementation must provide at least the following:
+   *  
+   *  - FTC_GNode sub-class, e.g. MyNode, with relevant methods, i.e:
+   *        my_node_new            ( must call FTC_GNode_Init )
+   *        my_node_free           ( must call FTC_GNode_Done )
+   *        my_node_compare        ( must call FTC_GNode_Compare )
+   *        my_node_remove_faceid  ( must call ftc_gnode_unselect in case 
+   *                                 of match )
+   *
+   *
+   *  - FTC_Family sub-class, e.g. MyFamily, with relevant methods, e.g.:
+   *        my_family_compare
+   *        my_family_init
+   *        my_family_reset (optional)
+   *        my_family_done
+   *
+   *  - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query
+   *    data.
+   *
+   *  - provide constant structures for a FTC_GNodeClass
+   *
+   *  - MyCacheNew() can be implemented easily as a call to the convenience
+   *    function FTC_GCache_New
+   *
+   *  - implement MyCacheLookup with a call to FTC_GCache_Lookup. This
+   *    function will automatically:
+   *
+   *      - search for the corresponding family in the cache, or create
+   *        a new one if necessary. put it in FTC_GQUERY(myquery).family
+   *
+   *      - call FTC_Cache_Lookup
+   *
+   *    if it returns NULL, you should create a new node, then call
+   *    ftc_cache_add as usual.
+   */
+
   /*************************************************************************/
   /*                                                                       */
   /* Important: The functions defined in this file are only used to        */
   /*            implement an abstract glyph cache class.  You need to      */
   /*            provide additional logic to implement a complete cache.    */
-  /*            For example, see `ftcimage.h' and `ftcimage.c' which       */
-  /*            implement a FT_Glyph cache based on this code.             */
   /*                                                                       */
   /*************************************************************************/
 
@@ -47,99 +118,64 @@
 
 
 #include <ft2build.h>
-#include FT_CACHE_H
-#include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_MANAGER_H
 
 
 FT_BEGIN_HEADER
 
 
-  /* each glyph set is characterized by a "glyph set type" which must be */
-  /* defined by sub-classes                                              */
-  typedef struct FTC_GlyphFamilyRec_*  FTC_GlyphFamily;
-
-  /* handle to a glyph cache node */
-  typedef struct FTC_GlyphNodeRec_*  FTC_GlyphNode;
-
-
-  /* size should be 24 + chunk size on 32-bit machines;                 */
-  /* note that the node's hash is ((gfam->hash << 16) | glyph_index) -- */
-  /* this _must_ be set properly by the glyph node initializer          */
-  /*                                                                    */
-  typedef struct  FTC_GlyphNodeRec_
+ /*
+  *  we can group glyph in "families". Each family correspond to a
+  *  given face id, character size, transform, etc...
+  *
+  *  families are implemented as MRU list nodes. They are reference-counted
+  */
+  
+  typedef struct  FTC_FamilyRec_
   {
-    FTC_NodeRec   node;
-    FT_UShort     item_count;
-    FT_UShort     item_start;
+    FTC_MruNode       mrunode;
+    FT_UInt           num_nodes;   /* current number of nodes in this family */
+    FTC_MruListClass  clazz;
+  
+  } FTC_FamilyRec, *FTC_Family;
 
-  } FTC_GlyphNodeRec;
+#define  FTC_FAMILY(x)    ( (FTC_Family)(x) )
+#define  FTC_FAMILY_P(x)  ( (FTC_Family*)(x) )
 
 
-#define FTC_GLYPH_NODE( x )    ( (FTC_GlyphNode)(x) )
-#define FTC_GLYPH_NODE_P( x )  ( (FTC_GlyphNode*)(x) )
-
-
-  typedef struct  FTC_GlyphQueryRec_
+  typedef struct  FTC_GNodeRec_
   {
-    FTC_QueryRec  query;
-    FT_UInt       gindex;
+    FTC_NodeRec      node;
+    FTC_Family       family;
+    FT_UInt          gindex;
 
-  } FTC_GlyphQueryRec, *FTC_GlyphQuery;
+  } FTC_GNodeRec, *FTC_GNode;
 
+#define FTC_GNODE( x )    ( (FTC_GNode)(x) )
+#define FTC_GNODE_P( x )  ( (FTC_GNode*)(x) )
 
-#define FTC_GLYPH_QUERY( x )  ( (FTC_GlyphQuery)(x) )
 
-
-  /* a glyph set is used to categorize glyphs of a given type */
-  typedef struct  FTC_GlyphFamilyRec_
+  typedef struct  FTC_GQueryRec_
   {
-    FTC_FamilyRec  family;
-    FT_UInt32      hash;
-    FT_UInt        item_total;   /* total number of glyphs in family */
-    FT_UInt        item_count;   /* number of glyph items per node   */
+    FT_UInt      gindex;
+    FTC_Family   family;
 
-  } FTC_GlyphFamilyRec;
+  } FTC_GQueryRec, *FTC_GQuery;
 
+#define FTC_GQUERY( x )  ( (FTC_GQuery)(x) )
 
-#define FTC_GLYPH_FAMILY( x )         ( (FTC_GlyphFamily)(x) )
-#define FTC_GLYPH_FAMILY_P( x )       ( (FTC_GlyphFamily*)(x) )
 
-#define FTC_GLYPH_FAMILY_MEMORY( x )  FTC_FAMILY(x)->cache->memory
 
-
   /* each glyph node contains a 'chunk' of glyph items; */
   /* translate a glyph index into a chunk index         */
-#define FTC_GLYPH_FAMILY_CHUNK( gfam, gindex )                  \
-          ( ( gindex ) / FTC_GLYPH_FAMILY( gfam )->item_count )
+#define FTC_FAMILY_CHUNK( gfam, gindex )                  \
+          ( ( gindex ) / FTC_FAMILY( gfam )->item_count )
 
   /* find a glyph index's chunk, and return its start index */
-#define FTC_GLYPH_FAMILY_START( gfam, gindex )       \
-          ( FTC_GLYPH_FAMILY_CHUNK( gfam, gindex ) * \
-            FTC_GLYPH_FAMILY( gfam )->item_count )
+#define FTC_FAMILY_START( gfam, gindex )       \
+          ( FTC_FAMILY_CHUNK( gfam, gindex ) * \
+            FTC_FAMILY( gfam )->item_count )
 
-  /* compute a glyph request's hash value */
-#define FTC_GLYPH_FAMILY_HASH( gfam, gindex )                          \
-          ( (FT_UFast)(                                                \
-              ( FTC_GLYPH_FAMILY( gfam )->hash << 16 ) |               \
-              ( FTC_GLYPH_FAMILY_CHUNK( gfam, gindex ) & 0xFFFFU ) ) )
-
-  /* must be called in an FTC_Family_CompareFunc to update the query */
-  /* whenever a glyph set is matched in the lookup, or when it       */
-  /* is created                                                      */
-#define FTC_GLYPH_FAMILY_FOUND( gfam, gquery )                            \
-          do                                                              \
-          {                                                               \
-            FTC_QUERY( gquery )->family = FTC_FAMILY( gfam );             \
-            FTC_QUERY( gquery )->hash =                                   \
-              FTC_GLYPH_FAMILY_HASH( gfam,                                \
-                                     FTC_GLYPH_QUERY( gquery )->gindex ); \
-          } while ( 0 )
-
-  /* retrieve glyph index of glyph node */
-#define FTC_GLYPH_NODE_GINDEX( x )                                  \
-          ( (FT_UInt)( FTC_GLYPH_NODE( x )->node.hash & 0xFFFFU ) )
-
-
   /*************************************************************************/
   /*                                                                       */
   /* These functions are exported so that they can be called from          */
@@ -149,36 +185,78 @@
 
   /* must be called by derived FTC_Node_InitFunc routines */
   FT_EXPORT( void )
-  ftc_glyph_node_init( FTC_GlyphNode    node,
-                       FT_UInt          gindex,  /* glyph index for node */
-                       FTC_GlyphFamily  gfam );
+  FTC_GNode_Init( FTC_GNode    node,
+                  FT_UInt      gindex,  /* glyph index for node */
+                  FTC_Family   family );
 
   /* returns TRUE iff the query's glyph index correspond to the node;  */
   /* this assumes that the "family" and "hash" fields of the query are */
   /* already correctly set                                             */
   FT_EXPORT( FT_Bool )
-  ftc_glyph_node_compare( FTC_GlyphNode   gnode,
-                          FTC_GlyphQuery  gquery );
+  FTC_GNode_Compare( FTC_GNode   gnode,
+                     FTC_GQuery  gquery );
 
+ /* call this function to clear a node's family. this is necessary
+  * to implement the "node_remove_faceid" cache method correctly
+  */
+  FT_EXPORT( void )
+  FTC_GNode_UnselectFamily( FTC_GNode   gnode,
+                            FTC_Cache   cache );
+
   /* must be called by derived FTC_Node_DoneFunc routines */
   FT_EXPORT( void )
-  ftc_glyph_node_done( FTC_GlyphNode  node,
-                       FTC_Cache      cache );
+  FTC_GNode_Done( FTC_GNode  node,
+                  FTC_Cache      cache );
 
 
-  /* must be called by derived FTC_Family_InitFunc; */
-  /* calls "ftc_family_init"                        */
+  typedef struct FTC_GCacheRec_
+  {
+    FTC_CacheRec       cache;
+    FTC_MruListRec     families;
+
+  } FTC_GCacheRec, *FTC_GCache;
+
+
+#define FTC_GCACHE(x)  ((FTC_GCache)(x))
+
+
+ /* can be used as @FTC_Cache_InitFunc */
   FT_EXPORT( FT_Error )
-  ftc_glyph_family_init( FTC_GlyphFamily  gfam,
-                         FT_UInt32        hash,
-                         FT_UInt          item_count,
-                         FT_UInt          item_total,
-                         FTC_GlyphQuery   gquery,
-                         FTC_Cache        cache );
+  FTC_GCache_Init( FTC_GCache     cache );
 
+
+ /* can be used as @FTC_Cache_DoneFunc */
   FT_EXPORT( void )
-  ftc_glyph_family_done( FTC_GlyphFamily  gfam );
+  FTC_GCache_Done( FTC_GCache  cache );
 
+
+ /* the glyph cache class adds fields for the family implementation */
+  typedef struct FTC_GCacheClassRec_
+  {
+    FTC_CacheClassRec  clazz;
+    FTC_MruListClass   family_class;
+
+  } FTC_GCacheClassRec;
+
+  typedef const FTC_GCacheClassRec*   FTC_GCacheClass;
+
+#define  FTC_GCACHE_CLASS(x)  ((FTC_GCacheClass)(x))
+
+#define  FTC_CACHE__GCACHE_CLASS(x)  FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class )
+
+
+ /* convenience function. use instead of FTC_Manager_Register_Cache */
+  FT_EXPORT( FT_Error )
+  FTC_GCache_New( FTC_Manager       manager,
+                  FTC_GCacheClass   clazz,
+                  FTC_GCache       *acache );
+
+  FT_EXPORT( FT_Error )
+  FTC_GCache_Lookup( FTC_GCache   cache,
+                     FT_UInt32    hash,
+                     FT_UInt      gindex,
+                     FTC_GQuery   query,
+                     FTC_Node    *anode );
 
   /* */
  
--- a/include/freetype/cache/ftcimage.h
+++ b/include/freetype/cache/ftcimage.h
@@ -2,7 +2,7 @@
 /*                                                                         */
 /*  ftcimage.h                                                             */
 /*                                                                         */
-/*    FreeType Image cache (specification).                                */
+/*    FreeType Generic Image cache (specification)                         */
 /*                                                                         */
 /*  Copyright 2000-2001, 2002, 2003 by                                     */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
@@ -16,6 +16,15 @@
 /***************************************************************************/
 
 
+ /*
+  *  FTC_ICache is an _abstract_ cache used to store a single FT_Glyph
+  *  image per cache node.
+  *
+  *  FTC_ICache extends FTC_GCache. For an implementation example,
+  *  see FTC_ImageCache in "src/cache/ftbasic.c"
+  *
+  */
+  
   /*************************************************************************/
   /*                                                                       */
   /* Each image cache really manages FT_Glyph objects.                     */
@@ -29,283 +38,63 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
 
-
 FT_BEGIN_HEADER
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Section>                                                             */
-  /*    cache_subsystem                                                    */
-  /*                                                                       */
-  /*************************************************************************/
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                       IMAGE CACHE OBJECT                      *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
- /**************************************************************************
-  *
-  * @struct:
-  *   FTC_ImageTypeRec
-  *
-  * @description:
-  *   A simple structure used to describe the type of glyph image to be
-  *   loaded into the cache.
-  *
-  * @fields:
-  *   font  :: An @FTC_FontRec used to describe the glyph's face and size.
-  *
-  *   flags :: The load flags to be applied when loading the glyph; see
-  *            the @FT_LOAD_XXX constants for details.
-  *
-  * @note:
-  *   This type completely replaces the @FTC_Image_Desc structure which is
-  *   now obsolete.
-  */
-  typedef struct  FTC_ImageTypeRec_
+  /* the FT_Glyph image node type - we store only 1 glyph per node */
+  typedef struct  FTC_INodeRec_
   {
-    FTC_FontRec  font;
-    FT_Int32     flags;
+    FTC_GNodeRec  gnode;
+    FT_Glyph      glyph;
 
-  } FTC_ImageTypeRec;
+  } FTC_INodeRec, *FTC_INode;
 
-  typedef struct FTC_ImageTypeRec_*   FTC_ImageType;
+#define FTC_INODE( x )         ( (FTC_INode)( x ) )
+#define FTC_INODE_GINDEX( x )  FTC_GNODE(x)->gindex
+#define FTC_INODE_FAMILY( x )  FTC_GNODE(x)->family
 
- /* */
+  typedef FT_Error  (*FTC_IFamily_LoadGlyphFunc)( FTC_Family   family,
+                                                  FT_UInt      gindex,
+                                                  FTC_Cache    cache,
+                                                  FT_Glyph    *aglyph );
 
-#define FTC_IMAGE_TYPE_COMPARE( d1, d2 )                    \
-          ( FTC_FONT_COMPARE( &(d1)->font, &(d2)->font ) && \
-            (d1)->flags == (d2)->flags                   )
-
-#define FTC_IMAGE_TYPE_HASH( d )                    \
-          (FT_UFast)( FTC_FONT_HASH( &(d)->font ) ^ \
-                      ( (d)->flags << 4 )         )
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Type>                                                                */
-  /*    FTC_ImageCache                                                     */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A handle to an glyph image cache object.  They are designed to     */
-  /*    hold many distinct glyph images while not exceeding a certain      */
-  /*    memory threshold.                                                  */
-  /*                                                                       */
-  typedef struct FTC_ImageCacheRec_*  FTC_ImageCache;
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_ImageCache_New                                                 */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Creates a new glyph image cache.                                   */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    manager :: The parent manager for the image cache.                 */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    acache  :: A handle to the new glyph image cache object.           */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  FT_EXPORT( FT_Error )
-  FTC_ImageCache_New( FTC_Manager      manager,
-                      FTC_ImageCache  *acache );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_ImageCache_Lookup                                              */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Retrieves a given glyph image from a glyph image cache.            */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    cache  :: A handle to the source glyph image cache.                */
-  /*                                                                       */
-  /*    type   :: A pointer to a glyph image type descriptor.              */
-  /*                                                                       */
-  /*    gindex :: The glyph index to retrieve.                             */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    aglyph :: The corresponding @FT_Glyph object.  0 in case of        */
-  /*              failure.                                                 */
-  /*                                                                       */
-  /*    anode  :: Used to return the address of of the corresponding cache */
-  /*              node after incrementing its reference count (see note    */
-  /*              below).                                                  */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    The returned glyph is owned and managed by the glyph image cache.  */
-  /*    Never try to transform or discard it manually!  You can however    */
-  /*    create a copy with @FT_Glyph_Copy and modify the new one.          */
-  /*                                                                       */
-  /*    If "anode" is _not_ NULL, it receives the address of the cache     */
-  /*    node containing the glyph image, after increasing its reference    */
-  /*    count.  This ensures that the node (as well as the FT_Glyph) will  */
-  /*    always be kept in the cache until you call @FTC_Node_Unref to      */
-  /*    "release" it.                                                      */
-  /*                                                                       */
-  /*    If "anode" is NULL, the cache node is left unchanged, which means  */
-  /*    that the FT_Glyph could be flushed out of the cache on the next    */
-  /*    call to one of the caching sub-system APIs.  Don't assume that it  */
-  /*    is persistent!                                                     */
-  /*                                                                       */
-  FT_EXPORT( FT_Error )
-  FTC_ImageCache_Lookup( FTC_ImageCache  cache,
-                         FTC_ImageType   type,
-                         FT_UInt         gindex,
-                         FT_Glyph       *aglyph,
-                         FTC_Node       *anode );
-
-  /* */
-
-#define ftc_image_format( x )  ( (x) & 7 )
-
-
-#define ftc_image_format_bitmap    0x0000
-#define ftc_image_format_outline   0x0001
-
-#define ftc_image_format_mask      0x000F
-
-#define ftc_image_flag_monochrome  0x0010
-#define ftc_image_flag_unhinted    0x0020
-#define ftc_image_flag_autohinted  0x0040
-#define ftc_image_flag_unscaled    0x0080
-#define ftc_image_flag_no_sbits    0x0100
-
-  /* monochrome bitmap */
-#define ftc_image_mono             ftc_image_format_bitmap | \
-                                   ftc_image_flag_monochrome
-
-  /* anti-aliased bitmap */
-#define ftc_image_grays            ftc_image_format_bitmap
-
-  /* scaled outline */
-#define ftc_image_outline          ftc_image_format_outline
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Struct>                                                              */
-  /*    FTC_Image_Desc                                                     */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    THIS TYPE IS DEPRECATED.  Use @FTC_ImageTypeRec instead.           */
-  /*                                                                       */
-  /*    A simple structure used to describe a given glyph image category.  */
-  /*                                                                       */
-  /* <Fields>                                                              */
-  /*    font       :: An @FTC_FontRec used to describe the glyph's face    */
-  /*                  and size.                                            */
-  /*                                                                       */
-  /*    image_type :: The glyph image's type.                              */
-  /*                                                                       */
-  typedef struct  FTC_Image_Desc_
+  typedef struct FTC_IFamilyClassRec_
   {
-    FTC_FontRec  font;
-    FT_UInt      image_type;
+    FTC_MruListClassRec        clazz;
+    FTC_IFamily_LoadGlyphFunc  family_load_glyph;
 
-  } FTC_Image_Desc;
+  } FTC_IFamilyClassRec;
 
+  typedef const FTC_IFamilyClassRec*  FTC_IFamilyClass;
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Type>                                                                */
-  /*    FTC_Image_Cache                                                    */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    THIS TYPE IS DEPRECATED.  Use @FTC_ImageCache instead.             */
-  /*                                                                       */
-  typedef FTC_ImageCache  FTC_Image_Cache;
+#define  FTC_IFAMILY_CLASS(x) ((FTC_IFamilyClass)(x))
 
+#define  FTC_CACHE__IFAMILY_CLASS(x)  \
+            FTC_IFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class )
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_Image_Cache_New                                                */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    THIS FUNCTION IS DEPRECATED.  Use @FTC_ImageCache_New instead.     */
-  /*                                                                       */
-  /*    Creates a new glyph image cache.                                   */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    manager :: The parent manager for the image cache.                 */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    acache  :: A handle to the new glyph image cache object.           */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  FT_EXPORT( FT_Error )
-  FTC_Image_Cache_New( FTC_Manager       manager,
-                       FTC_Image_Cache  *acache );
+ /* can be used as a @FTC_Node_FreeFunc */
+  FT_EXPORT( void )
+  FTC_INode_Free( FTC_INode  inode,
+                  FTC_Cache  cache );
 
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_Image_Cache_Lookup                                             */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    THIS FUNCTION IS DEPRECATED.  Use @FTC_ImageCache_Lookup instead.  */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    cache  :: A handle to the source glyph image cache.                */
-  /*                                                                       */
-  /*    desc   :: A pointer to a glyph image descriptor.                   */
-  /*                                                                       */
-  /*    gindex :: The glyph index to retrieve.                             */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    aglyph :: The corresponding @FT_Glyph object.  0 in case of        */
-  /*              failure.                                                 */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    The returned glyph is owned and managed by the glyph image cache.  */
-  /*    Never try to transform or discard it manually!  You can however    */
-  /*    create a copy with @FT_Glyph_Copy and modify the new one.          */
-  /*                                                                       */
-  /*    Because the glyph image cache limits the total amount of memory    */
-  /*    taken by the glyphs it holds, the returned glyph might disappear   */
-  /*    on a later invocation of this function!  It is a cache after       */
-  /*    all...                                                             */
-  /*                                                                       */
-  /*    Use this function to "lock" the glyph as long as it is needed.     */
-  /*                                                                       */
+ /* can be used as @FTC_Node_NewFunc. "gquery.index" & "gquery.family" must
+  * be set correctly. this function will call the 'family_load_glyph' method
+  * to load the FT_Glyph into the cache node
+  */
   FT_EXPORT( FT_Error )
-  FTC_Image_Cache_Lookup( FTC_Image_Cache  cache,
-                          FTC_Image_Desc*  desc,
-                          FT_UInt          gindex,
-                          FT_Glyph        *aglyph );
+  FTC_INode_New( FTC_INode   *pinode,
+                 FTC_GQuery   gquery,
+                 FTC_Cache    cache );
 
+ /* can be used as @FTC_Node_WeightFunc */
+  FT_EXPORT( FT_ULong )
+  FTC_INode_Weight( FTC_INode  inode );
+
  /* */
 
 FT_END_HEADER
-
 
 #endif /* __FTCIMAGE_H__ */
 
--- a/include/freetype/cache/ftcmanag.h
+++ b/include/freetype/cache/ftcmanag.h
@@ -65,7 +65,7 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_INTERNAL_LRU_H
+#include FT_CACHE_INTERNAL_MRU_H
 #include FT_CACHE_INTERNAL_CACHE_H
 
 
@@ -80,99 +80,32 @@
   /*************************************************************************/
 
 
-#define FTC_MAX_FACES_DEFAULT  2
-#define FTC_MAX_SIZES_DEFAULT  4
-#define FTC_MAX_BYTES_DEFAULT  200000L  /* ~200kByte by default */
+#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_FamilyEntryRec_
-  {
-    FTC_Family  family;
-    FTC_Cache   cache;
-    FT_UInt     index;
-    FT_UInt     link;
-
-  } FTC_FamilyEntryRec, *FTC_FamilyEntry;
-
-
-#define FTC_FAMILY_ENTRY_NONE  ( (FT_UInt)-1 )
-
-
-  typedef struct  FTC_FamilyTableRec_
-  {
-    FT_UInt          count;
-    FT_UInt          size;
-    FTC_FamilyEntry  entries;
-    FT_UInt          free;
-  
-  } FTC_FamilyTableRec, *FTC_FamilyTable;
-
-
-  FT_EXPORT( FT_Error )
-  ftc_family_table_alloc( FTC_FamilyTable   table,
-                          FT_Memory         memory,
-                          FTC_FamilyEntry  *aentry );
-
-  FT_EXPORT( void )
-  ftc_family_table_free( FTC_FamilyTable  table,
-                         FT_UInt          idx );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Struct>                                                              */
-  /*    FTC_ManagerRec                                                     */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    The cache manager structure.                                       */
-  /*                                                                       */
-  /* <Fields>                                                              */
-  /*    library      :: A handle to a FreeType library instance.           */
-  /*                                                                       */
-  /*    faces_list   :: The lru list of @FT_Face objects in the cache.     */
-  /*                                                                       */
-  /*    sizes_list   :: The lru list of @FT_Size objects in the cache.     */
-  /*                                                                       */
-  /*    max_weight   :: The maximum cache pool weight.                     */
-  /*                                                                       */
-  /*    cur_weight   :: The current cache pool weight.                     */
-  /*                                                                       */
-  /*    num_nodes    :: The current number of nodes in the manager.        */
-  /*                                                                       */
-  /*    nodes_list   :: The global lru list of all cache nodes.            */
-  /*                                                                       */
-  /*    caches       :: A table of installed/registered cache objects.     */
-  /*                                                                       */
-  /*    request_data :: User-provided data passed to the requester.        */
-  /*                                                                       */
-  /*    request_face :: User-provided function used to implement a mapping */
-  /*                    between abstract @FTC_FaceID values and real       */
-  /*                    @FT_Face objects.                                  */
-  /*                                                                       */
-  /*    families     :: Global table of families.                          */
-  /*                                                                       */
   typedef struct  FTC_ManagerRec_
   {
     FT_Library          library;
-    FT_LruList          faces_list;
-    FT_LruList          sizes_list;
+    FT_Memory           memory;
 
+    FTC_Node            nodes_list;
     FT_ULong            max_weight;
     FT_ULong            cur_weight;
-    
     FT_UInt             num_nodes;
-    FTC_Node            nodes_list;
     
-    FTC_Cache           caches[FTC_MAX_CACHES];
+    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_FamilyTableRec  families;
-
   } FTC_ManagerRec;
 
 
@@ -201,42 +134,57 @@
   FTC_Manager_Compress( FTC_Manager  manager );
 
 
+ /* try to flush "count" old nodes from the cache. return the number
+  * of really flushed nodes
+  */
+  FT_EXPORT( FT_UInt )
+  FTC_Manager_FlushN( FTC_Manager  manager,
+                       FT_UInt      count );
+
+
   /* this must be used internally for the moment */
   FT_EXPORT( FT_Error )
-  FTC_Manager_Register_Cache( FTC_Manager      manager,
-                              FTC_Cache_Class  clazz,
-                              FTC_Cache       *acache );
+  FTC_Manager_RegisterCache( FTC_Manager      manager,
+                             FTC_CacheClass   clazz,
+                             FTC_Cache       *acache );
 
+ /* */
 
-  /* can be called to increment a node's reference count */
-  FT_EXPORT( void )
-  FTC_Node_Ref( FTC_Node     node,
-                FTC_Manager  manager );
+  typedef struct FTC_ScalerRec_
+  {
+    FTC_FaceID   face_id;
+    FT_UInt      width;
+    FT_UInt      height;
+    FT_Int       pixel;
+    FT_UInt      x_res;
+    FT_UInt      y_res;
+  
+  } FTC_ScalerRec, *FTC_Scaler;
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_Node_Unref                                                     */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Decrement a cache node's internal reference count.  When the count */
-  /*    reaches 0, it is not destroyed but becomes eligible for subsequent */
-  /*    cache flushes.                                                     */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    node    :: The cache node handle.                                  */
-  /*                                                                       */
-  /*    manager :: The cache manager handle.                               */
-  /*                                                                       */
-  FT_EXPORT( void )
-  FTC_Node_Unref( FTC_Node     node,
-                  FTC_Manager  manager );
+#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 ? ( (q)->x_res*33 ^ (q)->y_res*61 ) : 0 )
+
+
+  FT_EXPORT( FT_Error )
+  FTC_Manager_LookupSize( FTC_Manager    manager,
+                           FTC_Scaler     scaler,
+                           FT_Size       *asize );
+
  /* */
 
 FT_END_HEADER
-
 
 #endif /* __FTCMANAG_H__ */
 
--- /dev/null
+++ b/include/freetype/cache/ftcmru.h
@@ -1,0 +1,143 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcmru.h                                                               */
+/*                                                                         */
+/*    Simple MRU list-cache (specification).                               */
+/*                                                                         */
+/*  Copyright 2000-2001, 2003 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
+
+
+FT_BEGIN_HEADER
+
+  typedef struct FTC_MruListRec_*              FTC_MruList;
+
+  typedef struct FTC_MruNodeRec_*              FTC_MruNode;
+
+  typedef struct FTC_MruListClassRec_ const *  FTC_MruListClass;
+
+  typedef struct FTC_MruNodeRec_
+  {
+    FTC_MruNode   next;
+
+  } FTC_MruNodeRec;
+
+  typedef FT_Int       (*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_UInt                   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_EXPORT( void )
+  FTC_MruList_Init( FTC_MruList       list,
+                    FTC_MruListClass  clazz,
+                    FT_UInt           max_nodes,
+                    FT_Pointer        data,
+                    FT_Memory         memory );
+
+  FT_EXPORT( void )
+  FTC_MruList_Reset( FTC_MruList  list );
+
+
+  FT_EXPORT( void )
+  FTC_MruList_Done( FTC_MruList  list );
+
+
+  FT_EXPORT( FT_Error )
+  FTC_MruList_Lookup( FTC_MruList   list,
+                      FT_Pointer    key,
+                      FTC_MruNode  *pnode );
+
+  FT_EXPORT( void )
+  FTC_MruList_Remove( FTC_MruList   list,
+                      FTC_MruNode   node );
+
+  FT_EXPORT( void )
+  FTC_MruList_RemoveSelection( FTC_MruList              list,
+                               FTC_MruNode_CompareFunc  select,
+                               FT_Pointer               key );
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __FTCMRU_H__ */
+
+
+/* END */
--- a/include/freetype/cache/ftcsbits.h
+++ b/include/freetype/cache/ftcsbits.h
@@ -22,250 +22,68 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_IMAGE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
 
 
 FT_BEGIN_HEADER
 
+#define FTC_SBIT_ITEMS_PER_NODE  16
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Section>                                                             */
-  /*    cache_subsystem                                                    */
-  /*                                                                       */
-  /*************************************************************************/
+  typedef struct  FTC_SNodeRec_
+  {
+    FTC_GNodeRec  gnode;
+    FT_UInt       count;
+    FTC_SBitRec   sbits[ FTC_SBIT_ITEMS_PER_NODE ];
 
+  } FTC_SNodeRec, *FTC_SNode;
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Type>                                                                */
-  /*    FTC_SBit                                                           */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A handle to a small bitmap descriptor.  See the @FTC_SBitRec       */
-  /*    structure for details.                                             */
-  /*                                                                       */
-  typedef struct FTC_SBitRec_*  FTC_SBit;
 
+#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
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Struct>                                                              */
-  /*    FTC_SBitRec                                                        */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A very compact structure used to describe a small glyph bitmap.    */
-  /*                                                                       */
-  /* <Fields>                                                              */
-  /*    width     :: The bitmap width in pixels.                           */
-  /*                                                                       */
-  /*    height    :: The bitmap height in pixels.                          */
-  /*                                                                       */
-  /*    left      :: The horizontal distance from the pen position to the  */
-  /*                 left bitmap border (a.k.a. `left side bearing', or    */
-  /*                 `lsb').                                               */
-  /*                                                                       */
-  /*    top       :: The vertical distance from the pen position (on the   */
-  /*                 baseline) to the upper bitmap border (a.k.a. `top     */
-  /*                 side bearing').  The distance is positive for upwards */
-  /*                 Y coordinates.                                        */
-  /*                                                                       */
-  /*    format    :: The format of the glyph bitmap (monochrome or gray).  */
-  /*                                                                       */
-  /*    max_grays :: Maximum gray level value (in the range 1 to 255).     */
-  /*                                                                       */
-  /*    pitch     :: The number of bytes per bitmap line.  May be positive */
-  /*                 or negative.                                          */
-  /*                                                                       */
-  /*    xadvance  :: The horizontal advance width in pixels.               */
-  /*                                                                       */
-  /*    yadvance  :: The vertical advance height in pixels.                */
-  /*                                                                       */
-  /*    buffer   :: A pointer to the bitmap pixels.                        */
-  /*                                                                       */
-  typedef struct  FTC_SBitRec_
-  {
-    FT_Byte   width;
-    FT_Byte   height;
-    FT_Char   left;
-    FT_Char   top;
+  typedef FT_UInt   (*FTC_SFamily_GetCountFunc)( FTC_Family   family,
+                                                 FTC_Manager  manager );
 
-    FT_Byte   format;
-    FT_Byte   max_grays;
-    FT_Short  pitch;
-    FT_Char   xadvance;
-    FT_Char   yadvance;
+  typedef FT_Error  (*FTC_SFamily_LoadGlyphFunc)( FTC_Family   family,
+                                                  FT_UInt      gindex,
+                                                  FTC_Manager  manager,
+                                                  FT_Face     *aface );
 
-    FT_Byte*  buffer;
+  typedef struct FTC_SFamilyClassRec_
+  {
+    FTC_MruListClassRec        clazz;
+    FTC_SFamily_GetCountFunc   family_get_count;
+    FTC_SFamily_LoadGlyphFunc  family_load_glyph;
 
-  } FTC_SBitRec;
+  } FTC_SFamilyClassRec;
 
+  typedef const FTC_SFamilyClassRec*  FTC_SFamilyClass;
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Type>                                                                */
-  /*    FTC_SBitCache                                                      */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A handle to a small bitmap cache.  These are special cache objects */
-  /*    used to store small glyph bitmaps (and anti-aliased pixmaps) in a  */
-  /*    much more efficient way than the traditional glyph image cache     */
-  /*    implemented by @FTC_ImageCache.                                    */
-  /*                                                                       */
-  typedef struct FTC_SBitCacheRec_*  FTC_SBitCache;
+#define  FTC_SFAMILY_CLASS(x)  ((FTC_SFamilyClass)(x))
 
+#define  FTC_CACHE__SFAMILY_CLASS(x)  \
+             FTC_SFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class )
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Type>                                                                */
-  /*    FTC_SBit_Cache                                                     */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    DEPRECATED.  Use @FTC_SBitCache instead.                           */
-  /*                                                                       */
-  typedef FTC_SBitCache  FTC_SBit_Cache;
+  FT_EXPORT( void )
+  FTC_SNode_Free( FTC_SNode  snode,
+                  FTC_Cache  cache );
 
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_SBitCache_New                                                  */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Creates a new cache to store small glyph bitmaps.                  */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    manager :: A handle to the source cache manager.                   */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    acache  :: A handle to the new sbit cache.  NULL in case of error. */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
   FT_EXPORT( FT_Error )
-  FTC_SBitCache_New( FTC_Manager     manager,
-                     FTC_SBitCache  *acache );
+  FTC_SNode_New( FTC_SNode   *psnode,
+                 FTC_GQuery   gquery,
+                 FTC_Cache    cache );
 
+  FT_EXPORT( FT_ULong )
+  FTC_SNode_Weight( FTC_SNode  inode );
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_SBitCache_Lookup                                               */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Looks up a given small glyph bitmap in a given sbit cache and      */
-  /*    "lock" it to prevent its flushing from the cache until needed      */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    cache  :: A handle to the source sbit cache.                       */
-  /*                                                                       */
-  /*    type   :: A pointer to the glyph image type descriptor.            */
-  /*                                                                       */
-  /*    gindex :: The glyph index.                                         */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    sbit   :: A handle to a small bitmap descriptor.                   */
-  /*                                                                       */
-  /*    anode  :: Used to return the address of of the corresponding cache */
-  /*              node after incrementing its reference count (see note    */
-  /*              below).                                                  */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    The small bitmap descriptor and its bit buffer are owned by the    */
-  /*    cache and should never be freed by the application.  They might    */
-  /*    as well disappear from memory on the next cache lookup, so don't   */
-  /*    treat them as persistent data.                                     */
-  /*                                                                       */
-  /*    The descriptor's `buffer' field is set to 0 to indicate a missing  */
-  /*    glyph bitmap.                                                      */
-  /*                                                                       */
-  /*    If "anode" is _not_ NULL, it receives the address of the cache     */
-  /*    node containing the bitmap, after increasing its reference count.  */
-  /*    This ensures that the node (as well as the image) will always be   */
-  /*    kept in the cache until you call @FTC_Node_Unref to "release" it.  */
-  /*                                                                       */
-  /*    If "anode" is NULL, the cache node is left unchanged, which means  */
-  /*    that the bitmap could be flushed out of the cache on the next      */
-  /*    call to one of the caching sub-system APIs.  Don't assume that it  */
-  /*    is persistent!                                                     */
-  /*                                                                       */
-  FT_EXPORT( FT_Error )
-  FTC_SBitCache_Lookup( FTC_SBitCache    cache,
-                        FTC_ImageType    type,
-                        FT_UInt          gindex,
-                        FTC_SBit        *sbit,
-                        FTC_Node        *anode );
 
+  FT_EXPORT( FT_Bool )
+  FTC_SNode_Compare( FTC_SNode   snode,
+                     FTC_GQuery  gquery,
+                     FTC_Cache   cache );
 
   /* */
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_SBit_Cache_New                                                 */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    DEPRECATED.  Use @FTC_SBitCache_New instead.                       */
-  /*                                                                       */
-  /*    Creates a new cache to store small glyph bitmaps.                  */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    manager :: A handle to the source cache manager.                   */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    acache  :: A handle to the new sbit cache.  NULL in case of error. */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  FT_EXPORT( FT_Error )
-  FTC_SBit_Cache_New( FTC_Manager      manager,
-                      FTC_SBit_Cache  *acache );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    FTC_SBit_Cache_Lookup                                              */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    DEPRECATED.  Use @FTC_SBitCache_Lookup instead.                    */
-  /*                                                                       */
-  /*    Looks up a given small glyph bitmap in a given sbit cache.         */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    cache  :: A handle to the source sbit cache.                       */
-  /*                                                                       */
-  /*    desc   :: A pointer to the glyph image descriptor.                 */
-  /*                                                                       */
-  /*    gindex :: The glyph index.                                         */
-  /*                                                                       */
-  /* <Output>                                                              */
-  /*    sbit   :: A handle to a small bitmap descriptor.                   */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    The small bitmap descriptor and its bit buffer are owned by the    */
-  /*    cache and should never be freed by the application.  They might    */
-  /*    as well disappear from memory on the next cache lookup, so don't   */
-  /*    treat them as persistent data.                                     */
-  /*                                                                       */
-  /*    The descriptor's `buffer' field is set to 0 to indicate a missing  */
-  /*    glyph bitmap.                                                      */
-  /*                                                                       */
-  FT_EXPORT( FT_Error )
-  FTC_SBit_Cache_Lookup( FTC_SBit_Cache   cache,
-                         FTC_Image_Desc*  desc,
-                         FT_UInt          gindex,
-                         FTC_SBit        *sbit );
-
 
 FT_END_HEADER
 
--- a/include/freetype/cache/ftlru.h
+++ /dev/null
@@ -1,208 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  ftlru.h                                                                */
-/*                                                                         */
-/*    Simple LRU list-cache (specification).                               */
-/*                                                                         */
-/*  Copyright 2000-2001, 2003 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 LRU 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.                       */
-  /*                                                                       */
-  /*************************************************************************/
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*********                                                       *********/
-  /*********             WARNING, THIS IS BETA CODE.               *********/
-  /*********                                                       *********/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-#ifndef __FTLRU_H__
-#define __FTLRU_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
-
-
-FT_BEGIN_HEADER
-
-
-  /* generic list key type */
-  typedef FT_Pointer  FT_LruKey;
-
-  /* a list list handle */
-  typedef struct FT_LruListRec_*  FT_LruList;
-
-  /* a list class handle */
-  typedef const struct FT_LruList_ClassRec_*  FT_LruList_Class;
-
-  /* a list node handle */
-  typedef struct FT_LruNodeRec_*  FT_LruNode;
-
-  /* the list node structure */
-  typedef struct  FT_LruNodeRec_
-  {
-    FT_LruNode  next;
-    FT_LruKey   key;
-
-  } FT_LruNodeRec;
-
-
-  /* the list structure */
-  typedef struct  FT_LruListRec_
-  {
-    FT_Memory         memory;
-    FT_LruList_Class  clazz;
-    FT_LruNode        nodes;
-    FT_UInt           max_nodes;
-    FT_UInt           num_nodes;
-    FT_Pointer        data;
-
-  } FT_LruListRec;
-
-
-  /* initialize a list list */
-  typedef FT_Error
-  (*FT_LruList_InitFunc)( FT_LruList  list );
-
-  /* finalize a list list */
-  typedef void
-  (*FT_LruList_DoneFunc)( FT_LruList  list );
-
-  /* this method is used to initialize a new list element node */
-  typedef FT_Error
-  (*FT_LruNode_InitFunc)( FT_LruNode  node,
-                          FT_LruKey   key,
-                          FT_Pointer  data );
-
-  /* this method is used to finalize a given list element node */
-  typedef void
-  (*FT_LruNode_DoneFunc)( FT_LruNode  node,
-                          FT_Pointer  data );
-
-  /* If defined, this method is called when the list if full        */
-  /* during the lookup process -- it is used to change the contents */
-  /* of a list element node instead of calling `done_element()',    */
-  /* then `init_element()'.  Set it to 0 for default behaviour.     */
-  typedef FT_Error
-  (*FT_LruNode_FlushFunc)( FT_LruNode  node,
-                           FT_LruKey   new_key,
-                           FT_Pointer  data );
-
-  /* If defined, this method is used to compare a list element node */
-  /* with a given key during a lookup.  If set to 0, the `key'      */
-  /* fields will be directly compared instead.                      */
-  typedef FT_Bool
-  (*FT_LruNode_CompareFunc)( FT_LruNode  node,
-                             FT_LruKey   key,
-                             FT_Pointer  data );
-
-  /* A selector is used to indicate whether a given list element node */
-  /* is part of a selection for FT_LruList_Remove_Selection().  The   */
-  /* functrion must return true (i.e., non-null) to indicate that the */
-  /* node is part of it.                                              */
-  typedef FT_Bool
-  (*FT_LruNode_SelectFunc)( FT_LruNode  node,
-                            FT_Pointer  data,
-                            FT_Pointer  list_data );
-
-  /* LRU class */
-  typedef struct  FT_LruList_ClassRec_
-  {
-    FT_UInt                 list_size;
-    FT_LruList_InitFunc     list_init;      /* optional */
-    FT_LruList_DoneFunc     list_done;      /* optional */
-
-    FT_UInt                 node_size;
-    FT_LruNode_InitFunc     node_init;     /* MANDATORY */
-    FT_LruNode_DoneFunc     node_done;     /* optional  */
-    FT_LruNode_FlushFunc    node_flush;    /* optional  */
-    FT_LruNode_CompareFunc  node_compare;  /* optional  */
-
-  } FT_LruList_ClassRec;
-
-
-  /* The following functions must be exported in the case where */
-  /* applications would want to write their own cache classes.  */
-
-  FT_EXPORT( FT_Error )
-  FT_LruList_New( FT_LruList_Class  clazz,
-                  FT_UInt           max_elements,
-                  FT_Pointer        user_data,
-                  FT_Memory         memory,
-                  FT_LruList       *alist );
-
-  FT_EXPORT( void )
-  FT_LruList_Reset( FT_LruList  list );
-
-  FT_EXPORT( void )
-  FT_LruList_Destroy ( FT_LruList  list );
-
-  FT_EXPORT( FT_Error )
-  FT_LruList_Lookup( FT_LruList  list,
-                     FT_LruKey   key,
-                     FT_LruNode *anode );
-
-  FT_EXPORT( void )
-  FT_LruList_Remove( FT_LruList  list,
-                     FT_LruNode  node );
-
-  FT_EXPORT( void )
-  FT_LruList_Remove_Selection( FT_LruList             list,
-                               FT_LruNode_SelectFunc  select_func,
-                               FT_Pointer             select_data );
-
- /* */
-
-FT_END_HEADER
-
-
-#endif /* __FTLRU_H__ */
-
-
-/* END */
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -433,7 +433,10 @@
   /*    see the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need  */
   /*    to store small glyph bitmaps, as it will use less memory.          */
   /*                                                                       */
-#define FT_CACHE_IMAGE_H  <freetype/cache/ftcimage.h>
+  /*    this macro is *DEPRECATED*, simply include @FT_CACHE_H and you'll  */
+  /*    have all glyph image-related cache declarations                    */
+  /*                                                                       */
+#define FT_CACHE_IMAGE_H    FT_CACHE_H
 
 
   /*************************************************************************/
@@ -450,7 +453,10 @@
   /*    in @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images,  */
   /*    including scalable outlines.                                       */
   /*                                                                       */
-#define FT_CACHE_SMALL_BITMAPS_H  <freetype/cache/ftcsbits.h>
+  /*    this macro is *DEPRECATED*, simply include @FT_CACHE_H and you'll  */
+  /*    have all small bitmaps-related cache declarations                  */
+  /*                                                                       */
+#define FT_CACHE_SMALL_BITMAPS_H  FT_CACHE_H
 
 
   /*************************************************************************/
@@ -462,7 +468,10 @@
   /*    A macro used in #include statements to name the file containing    */
   /*    the `charmap' API of the FreeType 2 cache sub-system.              */
   /*                                                                       */
-#define FT_CACHE_CHARMAP_H  <freetype/cache/ftccmap.h>
+  /*    this macro is *DEPRECATED*, simply include @FT_CACHE_H and you'll  */
+  /*    have all charmap-based cache declarations                          */
+  /*                                                                       */
+#define FT_CACHE_CHARMAP_H     FT_CACHE_H
 
 
   /*************************************************************************/
@@ -515,9 +524,13 @@
 
 #define FT_CACHE_MANAGER_H         <freetype/cache/ftcmanag.h>
 
-#define FT_CACHE_INTERNAL_LRU_H    <freetype/cache/ftlru.h>
-#define FT_CACHE_INTERNAL_GLYPH_H  <freetype/cache/ftcglyph.h>
+#define FT_CACHE_INTERNAL_MRU_H      <freetype/cache/ftcmru.h>
+#define FT_CACHE_INTERNAL_MANAGER_H  <freetype/cache/ftcmanag.h>
 #define FT_CACHE_INTERNAL_CACHE_H  <freetype/cache/ftccache.h>
+#define FT_CACHE_INTERNAL_GLYPH_H    <freetype/cache/ftcglyph.h>
+#define FT_CACHE_INTERNAL_IMAGE_H    <freetype/cache/ftcimage.h>
+#define FT_CACHE_INTERNAL_SBITS_H    <freetype/cache/ftcsbits.h>
+
 
 #define FT_XFREE86_H               <freetype/ftxf86.h>
 
--- a/include/freetype/config/ftoption.h
+++ b/include/freetype/config/ftoption.h
@@ -277,8 +277,8 @@
   /*   Do not #undef these macros here since the build system might define */
   /*   them for certain configurations only.                               */
   /*                                                                       */
-/* #define FT_DEBUG_LEVEL_ERROR */
-/* #define FT_DEBUG_LEVEL_TRACE */
+#define FT_DEBUG_LEVEL_ERROR
+#define FT_DEBUG_LEVEL_TRACE
 
 
   /*************************************************************************/
@@ -296,7 +296,7 @@
   /*   Do not #undef this macro here since the build system might define   */
   /*   it for certain configurations only.                                 */
   /*                                                                       */
-/* #define FT_DEBUG_MEMORY */
+#define FT_DEBUG_MEMORY
 
 
   /*************************************************************************/
--- a/include/freetype/ftcache.h
+++ b/include/freetype/ftcache.h
@@ -63,7 +63,7 @@
   /*   FTC_Face_Requester                                                  */
   /*                                                                       */
   /*   FTC_Manager_New                                                     */
-  /*   FTC_Manager_Lookup_Face                                             */
+  /*   FTC_Manager_LookupFace                                             */
   /*   FTC_Manager_Lookup_Size                                             */
   /*                                                                       */
   /*   FTC_Node                                                            */
@@ -257,29 +257,17 @@
   /*    Creates a new cache manager.                                       */
   /*                                                                       */
   /* <Input>                                                               */
-  /*    library   :: The parent FreeType library handle to use.            */
+  /*    library     :: The parent FreeType library handle to use.          */
   /*                                                                       */
-  /*    max_faces :: Maximum number of faces to keep alive in manager.     */
-  /*                 Use 0 for defaults (currently 2; see the value of     */
-  /*                 FTC_MAX_FACES_DEFAULT in                              */
-  /*                 `include/freetype/cache/ftcmanag.h').                 */
+  /*    max_bytes   :: Maximum number of bytes to use for cached data.     */
+  /*                   Use 0 for defaults.                                 */
   /*                                                                       */
-  /*    max_sizes :: Maximum number of sizes to keep alive in manager.     */
-  /*                 Use 0 for defaults (currently 4; see the value of     */
-  /*                 FTC_MAX_SIZES_DEFAULT in                              */
-  /*                 `include/freetype/cache/ftcmanag.h').                 */
+  /*    requester   :: An application-provided callback used to translate  */
+  /*                   face IDs into real @FT_Face objects.                */
   /*                                                                       */
-  /*    max_bytes :: Maximum number of bytes to use for cached data.       */
-  /*                 Use 0 for defaults (currently 200000; see the value   */
-  /*                 of FTC_MAX_BYTES_DEFAULT in                           */
-  /*                 `include/freetype/cache/ftcmanag.h').                 */
+  /*    req_data    :: A generic pointer that is passed to the requester   */
+  /*                   each time it is called (see @FTC_Face_Requester).   */
   /*                                                                       */
-  /*    requester :: An application-provided callback used to translate    */
-  /*                 face IDs into real @FT_Face objects.                  */
-  /*                                                                       */
-  /*    req_data  :: A generic pointer that is passed to the requester     */
-  /*                 each time it is called (see @FTC_Face_Requester).     */
-  /*                                                                       */
   /* <Output>                                                              */
   /*    amanager  :: A handle to a new manager object.  0 in case of       */
   /*                 failure.                                              */
@@ -331,7 +319,7 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
-  /*    FTC_Manager_Lookup_Face                                            */
+  /*    FTC_Manager_LookupFace                                            */
   /*                                                                       */
   /* <Description>                                                         */
   /*    Retrieves the @FT_Face object that corresponds to a given face ID  */
@@ -361,7 +349,7 @@
   /*    to transform glyphs, do it yourself after glyph loading.           */
   /*                                                                       */
   FT_EXPORT( FT_Error )
-  FTC_Manager_Lookup_Face( FTC_Manager  manager,
+  FTC_Manager_LookupFace( FTC_Manager  manager,
                            FTC_FaceID   face_id,
                            FT_Face     *aface );
 
@@ -369,48 +357,411 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
-  /*    FTC_Manager_Lookup_Size                                            */
+  /*    FTC_Node_Unref                                                     */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    Retrieves the @FT_Face and @FT_Size objects that correspond to a   */
-  /*    given font.                                                        */
+  /*    Decrement a cache node's internal reference count.  When the count */
+  /*    reaches 0, it is not destroyed but becomes eligible for subsequent */
+  /*    cache flushes.                                                     */
   /*                                                                       */
   /* <Input>                                                               */
+  /*    node    :: The cache node handle.                                  */
+  /*                                                                       */
+  /*    manager :: The cache manager handle.                               */
+  /*                                                                       */
+  FT_EXPORT( void )
+  FTC_Node_Unref( FTC_Node     node,
+                  FTC_Manager  manager );
+
+
+ /* remove all nodes belonging to a given face_id */
+  FT_EXPORT( void )
+  FTC_Manager_RemoveFaceID( FTC_Manager  manager,
+                             FTC_FaceID   face_id );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Section>                                                             */
+  /*    cache_subsystem                                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /************************************************************************
+   *
+   * @type:
+   *    FTC_CMapCache
+   *
+   * @description:
+   *    An opaque handle used to manager a charmap cache.  This cache is
+   *    to hold character codes -> glyph indices mappings.
+   */
+  typedef struct FTC_CMapCacheRec_*  FTC_CMapCache;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @type:                                                                */
+  /*    FTC_CMapDesc                                                       */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    A handle to an @FTC_CMapDescRec structure used to describe a given */
+  /*    charmap in a charmap cache.                                        */
+  /*                                                                       */
+  /*    Each @FTC_CMapDesc describes which charmap (of which @FTC_FaceID)  */
+  /*    we want to use in @FTC_CMapCache_Lookup.                           */
+  /*                                                                       */
+  typedef struct FTC_CMapDescRec_*  FTC_CMapDesc;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @function:                                                            */
+  /*    FTC_CMapCache_New                                                  */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    Creates a new charmap cache.                                       */
+  /*                                                                       */
+  /* @input:                                                               */
   /*    manager :: A handle to the cache manager.                          */
   /*                                                                       */
-  /*    font    :: The font to use.                                        */
+  /* @output:                                                              */
+  /*    acache  :: A new cache handle.  NULL in case of error.             */
   /*                                                                       */
+  /* @return:                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* @note:                                                                */
+  /*    Like all other caches, this one will be destroyed with the cache   */
+  /*    manager.                                                           */
+  /*                                                                       */
+  FT_EXPORT( FT_Error )
+  FTC_CMapCache_New( FTC_Manager     manager,
+                     FTC_CMapCache  *acache );
+
+
+ /* retrieve the index of a given charmap
+  */
+  FT_EXPORT( FT_UInt )
+  FT_Get_CharMap_Index( FT_CharMap  charmap );
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @function:                                                            */
+  /*    FTC_CMapCache_Lookup                                               */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    Translates a character code into a glyph index, using the charmap  */
+  /*    cache.                                                             */
+  /*                                                                       */
+  /* @input:                                                               */
+  /*    cache     :: A charmap cache handle.                               */
+  /*                                                                       */
+  /*    cmap_desc :: A charmap descriptor handle.                          */
+  /*                                                                       */
+  /*    char_code :: The character code (in the corresponding charmap).    */
+  /*                                                                       */
+  /* @return:                                                              */
+  /*    Glyph index.  0 means "no glyph".                                  */
+  /*                                                                       */
+  /* @note:                                                                */
+  /*    This function doesn't return @FTC_Node handles, since there is no  */
+  /*    real use for them with typical uses of charmaps.                   */
+  /*                                                                       */
+  FT_EXPORT( FT_UInt )
+  FTC_CMapCache_Lookup( FTC_CMapCache  cache,
+                        FTC_FaceID     face_id,
+                        FT_UInt        cmap_index,
+                        FT_UInt32      char_code );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Section>                                                             */
+  /*    cache_subsystem                                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       IMAGE CACHE OBJECT                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct  FTC_ImageTypeRec_
+  {
+    FTC_FaceID   face_id;
+    FT_Int       width;
+    FT_Int       height;
+    FT_Int32     flags;
+
+  } FTC_ImageTypeRec;
+
+  typedef struct FTC_ImageTypeRec_*   FTC_ImageType;
+
+ /* */
+
+#define FTC_IMAGE_TYPE_COMPARE( d1, d2 )                    \
+          ( FTC_FONT_COMPARE( &(d1)->font, &(d2)->font ) && \
+            (d1)->flags == (d2)->flags                   )
+
+#define FTC_IMAGE_TYPE_HASH( d )                    \
+          (FT_UFast)( FTC_FONT_HASH( &(d)->font ) ^ \
+                      ( (d)->flags << 4 )         )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    FTC_ImageCache                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to an glyph image cache object.  They are designed to     */
+  /*    hold many distinct glyph images while not exceeding a certain      */
+  /*    memory threshold.                                                  */
+  /*                                                                       */
+  typedef struct FTC_ImageCacheRec_*  FTC_ImageCache;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FTC_ImageCache_New                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Creates a new glyph image cache.                                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    manager :: The parent manager for the image cache.                 */
+  /*                                                                       */
   /* <Output>                                                              */
-  /*    aface   :: A pointer to the handle of the face object.  Set it to  */
-  /*               zero if you don't need it.                              */
+  /*    acache  :: A handle to the new glyph image cache object.           */
   /*                                                                       */
-  /*    asize   :: A pointer to the handle of the size object.  Set it to  */
-  /*               zero if you don't need it.                              */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
+  FT_EXPORT( FT_Error )
+  FTC_ImageCache_New( FTC_Manager      manager,
+                      FTC_ImageCache  *acache );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FTC_ImageCache_Lookup                                              */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Retrieves a given glyph image from a glyph image cache.            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    cache  :: A handle to the source glyph image cache.                */
+  /*                                                                       */
+  /*    type   :: A pointer to a glyph image type descriptor.              */
+  /*                                                                       */
+  /*    gindex :: The glyph index to retrieve.                             */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    aglyph :: The corresponding @FT_Glyph object.  0 in case of        */
+  /*              failure.                                                 */
+  /*                                                                       */
+  /*    anode  :: Used to return the address of of the corresponding cache */
+  /*              node after incrementing its reference count (see note    */
+  /*              below).                                                  */
+  /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   /* <Note>                                                                */
-  /*    The returned @FT_Face object is always owned by the manager.  You  */
-  /*    should never try to discard it yourself.                           */
+  /*    The returned glyph is owned and managed by the glyph image cache.  */
+  /*    Never try to transform or discard it manually!  You can however    */
+  /*    create a copy with @FT_Glyph_Copy and modify the new one.          */
   /*                                                                       */
-  /*    Never change the face's transformation matrix (i.e., never call    */
-  /*    the @FT_Set_Transform function) on a returned face!  If you need   */
-  /*    to transform glyphs, do it yourself after glyph loading.           */
+  /*    If "anode" is _not_ NULL, it receives the address of the cache     */
+  /*    node containing the glyph image, after increasing its reference    */
+  /*    count.  This ensures that the node (as well as the FT_Glyph) will  */
+  /*    always be kept in the cache until you call @FTC_Node_Unref to      */
+  /*    "release" it.                                                      */
   /*                                                                       */
-  /*    Similarly, the returned @FT_Size object is always owned by the     */
-  /*    manager.  You should never try to discard it, and never change its */
-  /*    settings with @FT_Set_Pixel_Sizes or @FT_Set_Char_Size!            */
+  /*    If "anode" is NULL, the cache node is left unchanged, which means  */
+  /*    that the FT_Glyph could be flushed out of the cache on the next    */
+  /*    call to one of the caching sub-system APIs.  Don't assume that it  */
+  /*    is persistent!                                                     */
   /*                                                                       */
-  /*    The returned size object is the face's current size, which means   */
-  /*    that you can call @FT_Load_Glyph with the face if you need to.     */
+  FT_EXPORT( FT_Error )
+  FTC_ImageCache_Lookup( FTC_ImageCache  cache,
+                         FTC_ImageType   type,
+                         FT_UInt         gindex,
+                         FT_Glyph       *aglyph,
+                         FTC_Node       *anode );
+
+  /*************************************************************************/
   /*                                                                       */
+  /* <Section>                                                             */
+  /*    cache_subsystem                                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    FTC_SBit                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a small bitmap descriptor.  See the @FTC_SBitRec       */
+  /*    structure for details.                                             */
+  /*                                                                       */
+  typedef struct FTC_SBitRec_*  FTC_SBit;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    FTC_SBitRec                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A very compact structure used to describe a small glyph bitmap.    */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    width     :: The bitmap width in pixels.                           */
+  /*                                                                       */
+  /*    height    :: The bitmap height in pixels.                          */
+  /*                                                                       */
+  /*    left      :: The horizontal distance from the pen position to the  */
+  /*                 left bitmap border (a.k.a. `left side bearing', or    */
+  /*                 `lsb').                                               */
+  /*                                                                       */
+  /*    top       :: The vertical distance from the pen position (on the   */
+  /*                 baseline) to the upper bitmap border (a.k.a. `top     */
+  /*                 side bearing').  The distance is positive for upwards */
+  /*                 Y coordinates.                                        */
+  /*                                                                       */
+  /*    format    :: The format of the glyph bitmap (monochrome or gray).  */
+  /*                                                                       */
+  /*    max_grays :: Maximum gray level value (in the range 1 to 255).     */
+  /*                                                                       */
+  /*    pitch     :: The number of bytes per bitmap line.  May be positive */
+  /*                 or negative.                                          */
+  /*                                                                       */
+  /*    xadvance  :: The horizontal advance width in pixels.               */
+  /*                                                                       */
+  /*    yadvance  :: The vertical advance height in pixels.                */
+  /*                                                                       */
+  /*    buffer   :: A pointer to the bitmap pixels.                        */
+  /*                                                                       */
+  typedef struct  FTC_SBitRec_
+  {
+    FT_Byte   width;
+    FT_Byte   height;
+    FT_Char   left;
+    FT_Char   top;
+
+    FT_Byte   format;
+    FT_Byte   max_grays;
+    FT_Short  pitch;
+    FT_Char   xadvance;
+    FT_Char   yadvance;
+
+    FT_Byte*  buffer;
+
+  } FTC_SBitRec;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    FTC_SBitCache                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a small bitmap cache.  These are special cache objects */
+  /*    used to store small glyph bitmaps (and anti-aliased pixmaps) in a  */
+  /*    much more efficient way than the traditional glyph image cache     */
+  /*    implemented by @FTC_ImageCache.                                    */
+  /*                                                                       */
+  typedef struct FTC_SBitCacheRec_*  FTC_SBitCache;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FTC_SBitCache_New                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Creates a new cache to store small glyph bitmaps.                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    manager :: A handle to the source cache manager.                   */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    acache  :: A handle to the new sbit cache.  NULL in case of error. */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
   FT_EXPORT( FT_Error )
-  FTC_Manager_Lookup_Size( FTC_Manager  manager,
-                           FTC_Font     font,
-                           FT_Face     *aface,
-                           FT_Size     *asize );
+  FTC_SBitCache_New( FTC_Manager     manager,
+                     FTC_SBitCache  *acache );
 
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FTC_SBitCache_Lookup                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Looks up a given small glyph bitmap in a given sbit cache and      */
+  /*    "lock" it to prevent its flushing from the cache until needed      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    cache  :: A handle to the source sbit cache.                       */
+  /*                                                                       */
+  /*    type   :: A pointer to the glyph image type descriptor.            */
+  /*                                                                       */
+  /*    gindex :: The glyph index.                                         */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    sbit   :: A handle to a small bitmap descriptor.                   */
+  /*                                                                       */
+  /*    anode  :: Used to return the address of of the corresponding cache */
+  /*              node after incrementing its reference count (see note    */
+  /*              below).                                                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The small bitmap descriptor and its bit buffer are owned by the    */
+  /*    cache and should never be freed by the application.  They might    */
+  /*    as well disappear from memory on the next cache lookup, so don't   */
+  /*    treat them as persistent data.                                     */
+  /*                                                                       */
+  /*    The descriptor's `buffer' field is set to 0 to indicate a missing  */
+  /*    glyph bitmap.                                                      */
+  /*                                                                       */
+  /*    If "anode" is _not_ NULL, it receives the address of the cache     */
+  /*    node containing the bitmap, after increasing its reference count.  */
+  /*    This ensures that the node (as well as the image) will always be   */
+  /*    kept in the cache until you call @FTC_Node_Unref to "release" it.  */
+  /*                                                                       */
+  /*    If "anode" is NULL, the cache node is left unchanged, which means  */
+  /*    that the bitmap could be flushed out of the cache on the next      */
+  /*    call to one of the caching sub-system APIs.  Don't assume that it  */
+  /*    is persistent!                                                     */
+  /*                                                                       */
+  FT_EXPORT( FT_Error )
+  FTC_SBitCache_Lookup( FTC_SBitCache    cache,
+                        FTC_ImageType    type,
+                        FT_UInt          gindex,
+                        FTC_SBit        *sbit,
+                        FTC_Node        *anode );
+
+
+ /* */
 
 FT_END_HEADER
 
--- a/include/freetype/ftstroke.h
+++ b/include/freetype/ftstroke.h
@@ -95,12 +95,113 @@
 
   } FT_Stroker_LineCap;
 
- /* */
 
+/**************************************************************
+ *
+ * @enum: FT_StrokerBorder
+ *
+ * @description:
+ *    theses values are used to select a given stroke border
+ *    in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder
+ *
+ * @values:
+ *    FT_STROKER_BORDER_LEFT ::
+ *      select the left border, relative to the drawing direction
+ *
+ *    FT_STROKER_BORDER_RIGHT ::
+ *      select the right border, relative to the drawing direction
+ *
+ * @note:
+ *   applications are generally interested in the "inside" and "outside"
+ *   borders. However, there is no direct mapping between these and
+ *   the "left" / "right" ones, since this really depends on the glyph's
+ *   drawing orientation, which varies between font formats
+ *
+ *   you can however use @FT_Outline_GetInsideBorder and
+ *   @FT_Outline_GetOutsideBorder to get these.
+ */
+  typedef enum
+  {
+    FT_STROKER_BORDER_LEFT = 0,
+    FT_STROKER_BORDER_RIGHT
+  
+  } FT_StrokerBorder;
+
+
+/**************************************************************
+ *
+ * @function: FT_Outline_GetInsideBorder
+ *
+ * @description:
+ *    retrieve the @FT_StrokerBorder value corresponding to the
+ *    "inside" borders of a given outline
+ *
+ * @input:
+ *    outline :: source outline handle
+ *
+ * @return:
+ *    border index. @FT_STROKER_BORDER_LEFT for empty or invalid outlines
+ */
+  FT_EXPORT( FT_StrokerBorder )
+  FT_Outline_GetInsideBorder( FT_Outline*  outline );
+
+
+/**************************************************************
+ *
+ * @function: FT_Outline_GetOutsideBorder
+ *
+ * @description:
+ *    retrieve the @FT_StrokerBorder value corresponding to the
+ *    "outside" borders of a given outline
+ *
+ * @input:
+ *    outline :: source outline handle
+ *
+ * @return:
+ *    border index. @FT_STROKER_BORDER_LEFT for empty or invalid outlines
+ */
+  FT_EXPORT( FT_StrokerBorder )
+  FT_Outline_GetOutsideBorder( FT_Outline*  outline );
+
+ 
+/**************************************************************
+ *
+ * @function: FT_Stroker_New
+ *
+ * @description:
+ *    create a new stroker object
+ *
+ * @input:
+ *    memory :: memory manager handle
+ *
+ * @output:
+ *    new stroker object handle, NULL in case of error
+ *
+ * @return:
+ *    error code. 0 means success
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_New( FT_Memory    memory,
                   FT_Stroker  *astroker );
 
+
+/**************************************************************
+ *
+ * @function: FT_Stroker_Set
+ *
+ * @description:
+ *    reset a stroker object's attributes
+ *
+ * @input:
+ *    stroker     :: target stroker handle
+ *    radius      :: border radius
+ *    line_cap    :: line cap style
+ *    line_join   :: line join style
+ *    miter_limit :: miter limit for the FT_STROKER_LINEJOIN_MITER style,
+ *                   expressed as 16.16 fixed point value.
+ * @note:
+ *   the radius is expressed in the same units that the outline coordinates.
+ */
   FT_EXPORT( void )
   FT_Stroker_Set( FT_Stroker           stroker,
                   FT_Fixed             radius,
@@ -109,29 +210,152 @@
                   FT_Fixed             miter_limit );
 
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_ParseOutline
+ *
+ * @description:
+ *    a convenient function used to parse a whole outline with
+ *    the stroker. The resulting outline(s) can be retrieved
+ *    later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export
+ *
+ * @input:
+ *    stroker     :: target stroker handle
+ *    outline     :: source outline
+ *    opened      :: boolean. if TRUE, the outline is treated as an open path,
+ *                   instead of a closed one
+ *
+ * @return:*
+ *   error code. 0 means success
+ *
+ * @note:
+ *   if 'opened' is 0 (the default), the outline is treated as a closed path,
+ *   and the stroker will generate two distinct "border" outlines
+ *
+ *   if 'opened' is 1, the outline is processed as an open path, and the
+ *   stroker will generate a single "stroke" outline
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_ParseOutline( FT_Stroker   stroker,
                            FT_Outline*  outline,
                            FT_Bool      opened );
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_BeginSubPath
+ *
+ * @description:
+ *    start a new sub-path in the stroker
+ *    
+ * @input:
+ *    stroker     :: target stroker handle
+ *    to          :: pointer to start vector
+ *    open        :: boolean. if TRUE, the sub-path is treated as an open
+ *                   one
+ *
+ * @return:*
+ *   error code. 0 means success
+ *
+ * @note:
+ *   this function is useful when you need to stroke a path that is
+ *   not stored as a @FT_Outline object
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_BeginSubPath( FT_Stroker  stroker,
                            FT_Vector*  to,
                            FT_Bool     open );
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_EndSubPath
+ *
+ * @description:
+ *    close the current sub-path in the stroker
+ *    
+ * @input:
+ *    stroker     :: target stroker handle
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   you should call this function after @FT_Stroker_BeginSubPath.
+ *   if the subpath was not "opened", this function will "draw" a
+ *   single line segment to the start position when needed.
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_EndSubPath( FT_Stroker  stroker );
 
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_LineTo
+ *
+ * @description:
+ *    "draw" a single line segment in the stroker's current sub-path,
+ *    from the last position
+ *    
+ * @input:
+ *    stroker     :: target stroker handle
+ *    to          :: pointer to destination point
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   you should call this function between @FT_Stroker_BeginSubPath and
+ *   @FT_Stroker_EndSubPath
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_LineTo( FT_Stroker  stroker,
                      FT_Vector*  to );
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_ConicTo
+ *
+ * @description:
+ *    "draw" a single quadratic bezier in the stroker's current sub-path,
+ *    from the last position
+ *    
+ * @input:
+ *    stroker     :: target stroker handle
+ *    control     :: pointer to bezier control point
+ *    to          :: pointer to destination point
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   you should call this function between @FT_Stroker_BeginSubPath and
+ *   @FT_Stroker_EndSubPath
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_ConicTo( FT_Stroker  stroker,
                       FT_Vector*  control,
                       FT_Vector*  to );
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_CubicTo
+ *
+ * @description:
+ *    "draw" a single cubic bezier in the stroker's current sub-path,
+ *    from the last position
+ *    
+ * @input:
+ *    stroker     :: target stroker handle
+ *    control1    :: pointer to first bezier control point
+ *    control2    :: pointer to second bezier control point
+ *    to          :: pointer to destination point
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   you should call this function between @FT_Stroker_BeginSubPath and
+ *   @FT_Stroker_EndSubPath
+ */
   FT_EXPORT( FT_Error )
   FT_Stroker_CubicTo( FT_Stroker  stroker,
                       FT_Vector*  control1,
@@ -139,18 +363,166 @@
                       FT_Vector*  to );
 
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_GetBorderCounts
+ *
+ * @description:
+ *    call this function once you finished parsing your paths
+ *    with the stroker. It will return the number of points and
+ *    contours necessary to export one of the "border" or "stroke"
+ *    outlines generated by the stroker.
+ *    
+ * @input:
+ *    stroker  :: target stroker handle
+ *    border   :: border index
+ *
+ * @output:
+ *    anum_points   :: number of points
+ *    anum_contours :: number of contours
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   when an outline, or a sub-path, is "closed", the stroker generates
+ *   two independent 'border' outlines, named 'left' and 'right'
+ *   
+ *   when the outline, or a sub-path, is "opened", the stroker merges
+ *   the 'border' outlines with caps. The 'left' border receives all
+ *   points, while the 'right' border becomes empty.
+ *
+ *   use the function @FT_Stroker_GetCounts instead if you want to
+ *   retrieve the counts associated to both borders.
+ */
   FT_EXPORT( FT_Error )
+  FT_Stroker_GetBorderCounts( FT_Stroker        stroker,
+                              FT_StrokerBorder  border,
+                              FT_UInt          *anum_points,
+                              FT_UInt          *anum_contours );
+
+/**************************************************************
+ *
+ * @function: FT_Stroker_ExportBorder
+ *
+ * @description:
+ *    call this function after @FT_Stroker_GetBorderCounts to
+ *    export the corresponding border to your own @FT_Outline
+ *    structure.
+ *    
+ *    note that this function will append the border points and
+ *    contours to your outline, but will not try to resize its
+ *    arrays.
+ *
+ * @input:
+ *    stroker  :: target stroker handle
+ *    border   :: border index
+ *    outline  :: target outline handle
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   always call this function after @FT_Stroker_GetBorderCounts to
+ *   get sure that there is enough room in your @FT_Outline object to
+ *   receive all new data.
+ *
+ *   when an outline, or a sub-path, is "closed", the stroker generates
+ *   two independent 'border' outlines, named 'left' and 'right'
+ *   
+ *   when the outline, or a sub-path, is "opened", the stroker merges
+ *   the 'border' outlines with caps. The 'left' border receives all
+ *   points, while the 'right' border becomes empty.
+ *
+ *   use the function @FT_Stroker_Export instead if you want to
+ *   retrieve all borders at once
+ */
+  FT_EXPORT( void )
+  FT_Stroker_ExportBorder( FT_Stroker        stroker,
+                           FT_StrokerBorder  border,
+                           FT_Outline*       outline );
+
+/**************************************************************
+ *
+ * @function: FT_Stroker_GetCounts
+ *
+ * @description:
+ *    call this function once you finished parsing your paths
+ *    with the stroker. It will return the number of points and
+ *    contours necessary to export all points/borders from the stroked
+ *    outline/path.
+ *    
+ * @input:
+ *    stroker  :: target stroker handle
+ *
+ * @output:
+ *    anum_points   :: number of points
+ *    anum_contours :: number of contours
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ */
+  FT_EXPORT( FT_Error )
   FT_Stroker_GetCounts( FT_Stroker  stroker,
                         FT_UInt    *anum_points,
                         FT_UInt    *anum_contours );
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_ExportBorder
+ *
+ * @description:
+ *    call this function after @FT_Stroker_GetBorderCounts to
+ *    export the corresponding border to your own @FT_Outline
+ *    structure.
+ *    
+ *    note that this function will append the border points and
+ *    contours to your outline, but will not try to resize its
+ *    arrays.
+ *
+ * @input:
+ *    stroker  :: target stroker handle
+ *    border   :: border index
+ *    outline  :: target outline handle
+ *
+ * @return:
+ *   error code. 0 means success
+ *
+ * @note:
+ *   always call this function after @FT_Stroker_GetBorderCounts to
+ *   get sure that there is enough room in your @FT_Outline object to
+ *   receive all new data.
+ *
+ *   when an outline, or a sub-path, is "closed", the stroker generates
+ *   two independent 'border' outlines, named 'left' and 'right'
+ *   
+ *   when the outline, or a sub-path, is "opened", the stroker merges
+ *   the 'border' outlines with caps. The 'left' border receives all
+ *   points, while the 'right' border becomes empty.
+ *
+ *   use the function @FT_Stroker_Export instead if you want to
+ *   retrieve all borders at once
+ */
   FT_EXPORT( void )
   FT_Stroker_Export( FT_Stroker   stroker,
                      FT_Outline*  outline );
 
+/**************************************************************
+ *
+ * @function: FT_Stroker_Done
+ *
+ * @description:
+ *    destroy a stroker object
+ *
+ * @input:
+ *    stroker :: stroker handle. can be NULL
+ */
   FT_EXPORT( void )
   FT_Stroker_Done( FT_Stroker  stroker );
 
+ /* */
 
 FT_END_HEADER
 
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -399,6 +399,8 @@
 
     hints->x_scale = x_scale;
     hints->y_scale = y_scale;
+    hints->x_delta = x_delta;
+    hints->y_delta = y_delta;
 
     points = hints->points;
     if ( hints->num_points == 0 )
@@ -405,8 +407,6 @@
       goto Exit;
 
     {
-      /* do one thing at a time -- it is easier to understand, and */
-      /* the code is clearer                                       */
       AF_Point  point;
       AF_Point  point_limit = points + hints->num_points;
 
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -163,7 +163,11 @@
     FT_Memory     memory;
 
     FT_Fixed      x_scale;
+    FT_Pos        x_delta;
+
     FT_Fixed      y_scale;
+    FT_Pos        y_delta;
+
     FT_Pos        edge_distance_threshold;
 
     FT_Int        max_points;
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -20,10 +20,7 @@
     metrics->axis[ AF_DIMENSION_HORZ ].width_count = 0;
     metrics->axis[ AF_DIMENSION_VERT ].width_count = 0;
 
-    /* For now, compute the standard width and height from the `o'       */
-    /* character.  I started computing the stem width of the `i' and the */
-    /* stem height of the "-", but it wasn't too good.  Moreover, we now */
-    /* have a single character that gives us standard width and height.  */
+    /* For now, compute the standard width and height from the `o' */
     {
       FT_UInt       glyph_index;
       AF_Dimension  dim;
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -40,14 +40,14 @@
     FT_Pos  org;  /* original position/width in font units              */
     FT_Pos  cur;  /* current/scaled position/width in device sub-pixels */
     FT_Pos  fit;  /* current/fitted position/width in device sub-pixels */
-  
+
   } AF_WidthRec, *AF_Width;
-  
 
+
   AF_LOCAL( void )
   af_sort_pos( FT_UInt   count,
                FT_Pos*   table );
- 
+
  /**************************************************************************/
  /**************************************************************************/
  /*****                                                                *****/
@@ -55,11 +55,11 @@
  /*****                                                                *****/
  /**************************************************************************/
  /**************************************************************************/
- 
+
  /*
   *  Angle type. The auto-fitter doesn't need a very high angular accuracy,
   *  and this allows us to speed up some computations considerably with a
-  *  light Cordic algorithm (see afangle.c)
+  *  light Cordic algorithm (see afangles.c)
   *
   */
 
@@ -111,10 +111,10 @@
     FT_Face          face;
     FT_OutlineRec    outline;
     FT_UInt          outline_resolution;
-    
+
     FT_Int           advance;
     FT_UInt          metrics_resolution;
-    
+
     AF_GlyphHints    hints;
 
   } AF_OutlineRec;
@@ -133,7 +133,7 @@
   *  auto-hinted glyph image
   *
   */
-  
+
   typedef enum
   {
     AF_SCALER_FLAG_NO_HORIZONTAL = 1,  /* disable horizontal hinting */
@@ -152,7 +152,7 @@
     FT_Pos          y_delta;      /* in 1/64th device pixels                 */
     FT_Render_Mode  render_mode;  /* monochrome, anti-aliased, LCD, etc..    */
     FT_UInt32       flags;        /* additionnal control flags, see above    */
-  
+
   } AF_ScalerRec, *AF_Scaler;
 
 
@@ -169,7 +169,7 @@
   *  the list of know scripts. Each different script correspond to the
   *  following information:
   *
-  *   - a set of Unicode ranges to test wether the face supports the
+  *   - a set of Unicode ranges to test weither the face supports the
   *     script
   *
   *   - a specific global analyzer that will compute global metrics
@@ -189,9 +189,9 @@
   {
     AF_SCRIPT_LATIN = 0,
     /* add new scripts here. don't forget to update the list in "afglobal.c" */
-    
+
     AF_SCRIPT_MAX   /* do not remove */
-  
+
   } AF_Script;
 
 
@@ -207,7 +207,7 @@
 
  /* this function parses a FT_Face to compute global metrics for
   * a specific script
-  */ 
+  */
   typedef FT_Error  (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics   metrics,
                                                   FT_Face            face );
 
@@ -230,9 +230,9 @@
   {
     FT_UInt32    first;
     FT_UInt32    last;
-  
+
   } AF_Script_UniRangeRec, *AF_Script_UniRange;
- 
+
 
   typedef struct AF_ScriptClassRec_
   {
--- a/src/base/ftstroke.c
+++ b/src/base/ftstroke.c
@@ -19,10 +19,31 @@
 #include <ft2build.h>
 #include FT_STROKER_H
 #include FT_TRIGONOMETRY_H
+#include FT_OUTLINE_H
 #include FT_INTERNAL_MEMORY_H
 #include FT_INTERNAL_DEBUG_H
 
 
+  FT_EXPORT_DEF( FT_StrokerBorder )
+  FT_Outline_GetInsideBorder( FT_Outline*  outline )
+  {
+    FT_Orientation  or = FT_Outline_Get_Orientation( outline );
+
+    return ( or == FT_ORIENTATION_TRUETYPE ) ? FT_STROKER_BORDER_RIGHT
+                                             : FT_STROKER_BORDER_LEFT ;
+  }
+
+
+  FT_EXPORT_DEF( FT_StrokerBorder )
+  FT_Outline_GetOutsideBorder( FT_Outline*  outline )
+  {
+    FT_Orientation  or = FT_Outline_Get_Orientation( outline );
+
+    return ( or == FT_ORIENTATION_TRUETYPE ) ? FT_STROKER_BORDER_RIGHT
+                                             : FT_STROKER_BORDER_LEFT ;
+  }
+
+
  /***************************************************************************/
  /***************************************************************************/
  /*****                                                                 *****/
@@ -221,6 +242,7 @@
     FT_Bool     movable;
     FT_Int      start;    /* index of current sub-path start point */
     FT_Memory   memory;
+    FT_Bool     valid;
 
   } FT_StrokeBorderRec, *FT_StrokeBorder;
 
@@ -468,6 +490,7 @@
     border->num_points = 0;
     border->max_points = 0;
     border->start      = -1;
+    border->valid      = 0;
   }
 
 
@@ -476,6 +499,7 @@
   {
     border->num_points = 0;
     border->start      = -1;
+    border->valid      = 0;
   }
 
 
@@ -491,6 +515,7 @@
     border->num_points = 0;
     border->max_points = 0;
     border->start      = -1;
+    border->valid      = 0;
   }
 
 
@@ -520,7 +545,7 @@
       }
       else if ( in_contour == 0 )
         goto Fail;
- 
+
       if ( tags[0] & FT_STROKE_TAG_END )
       {
         if ( in_contour == 0 )
@@ -534,6 +559,8 @@
     if ( in_contour != 0 )
       goto Fail;
 
+    border->valid = 1;
+
   Exit:
     *anum_points   = num_points;
     *anum_contours = num_contours;
@@ -661,8 +688,6 @@
     stroker->line_join   = line_join;
     stroker->miter_limit = miter_limit;
 
-    stroker->valid = 0;
-
     ft_stroke_border_reset( &stroker->borders[0] );
     ft_stroke_border_reset( &stroker->borders[1] );
   }
@@ -1424,6 +1449,34 @@
 
 
   FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_GetBorderCounts( FT_Stroker        stroker,
+                              FT_StrokerBorder  border,
+                              FT_UInt          *anum_points,
+                              FT_UInt          *anum_contours )
+  {
+    FT_UInt   num_points = 0, num_contours = 0;
+    FT_Error  error;
+
+    if ( !stroker || border > 1 )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    error = ft_stroke_border_get_counts( stroker->borders + border,
+                                         &num_points, &num_contours );
+  Exit:
+    if ( anum_points )
+      *anum_points = num_points;
+
+    if ( anum_contours )
+      *anum_contours = num_contours;
+
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
   FT_Stroker_GetCounts( FT_Stroker  stroker,
                         FT_UInt    *anum_points,
                         FT_UInt    *anum_contours )
@@ -1446,8 +1499,6 @@
     num_points   = count1 + count3;
     num_contours = count2 + count4;
 
-    stroker->valid = 1;
-
   Exit:
     *anum_points   = num_points;
     *anum_contours = num_contours;
@@ -1456,15 +1507,30 @@
 
 
   FT_EXPORT_DEF( void )
-  FT_Stroker_Export( FT_Stroker   stroker,
+  FT_Stroker_ExportBorder( FT_Stroker        stroker,
+                           FT_StrokerBorder  border,
                      FT_Outline*  outline )
   {
-    if ( stroker->valid )
+    if ( border == FT_STROKER_BORDER_LEFT  ||
+         border == FT_STROKER_BORDER_RIGHT )
     {
-      ft_stroke_border_export( stroker->borders + 0, outline );
-      ft_stroke_border_export( stroker->borders + 1, outline );
+      FT_StrokeBorder  sborder = & stroker->borders[border];
+
+      if ( sborder->valid )
+        ft_stroke_border_export( sborder, outline );
     }
   }
+
+
+  FT_EXPORT_DEF( void )
+  FT_Stroker_Export( FT_Stroker   stroker,
+                     FT_Outline*  outline )
+  {
+    FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline );
+    FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline );
+  }
+
+
 
 
   /*
--- a/src/cache/Jamfile
+++ b/src/cache/Jamfile
@@ -14,7 +14,15 @@
 
   if $(FT2_MULTI)
   {
-    _sources = ftlru ftcmanag ftccache ftcglyph ftcsbits ftcimage ftccmap ;
+    _sources = ftmru 
+               ftcmanag 
+               ftccache 
+               ftcglyph 
+               ftcsbits 
+               ftcimage
+               ftcbasic 
+               ftccmap 
+               ;
   }
   else
   {
--- a/src/cache/ftcache.c
+++ b/src/cache/ftcache.c
@@ -19,13 +19,13 @@
 #define FT_MAKE_OPTION_SINGLE_OBJECT
 
 #include <ft2build.h>
-#include "ftlru.c"
+#include "ftcmru.c"
 #include "ftcmanag.c"
 #include "ftccache.c"
+#include "ftccmap.c"
 #include "ftcglyph.c"
 #include "ftcimage.c"
 #include "ftcsbits.c"
-#include "ftccmap.c"
-
+#include "ftcbasic.c"
 
 /* END */
--- /dev/null
+++ b/src/cache/ftcbasic.c
@@ -1,0 +1,380 @@
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_CACHE_INTERNAL_IMAGE_H
+#include FT_CACHE_INTERNAL_SBITS_H
+#include FT_INTERNAL_MEMORY_H
+
+#include "ftcerror.h"
+
+
+ /*
+  *  Basic Families
+  *
+  *
+  */
+  typedef struct FTC_BasicAttrRec_
+  {
+    FTC_ScalerRec  scaler;
+    FT_UInt        load_flags;
+
+  } FTC_BasicAttrRec, *FTC_BasicAttrs;
+
+#define  FTC_BASIC_ATTR_COMPARE(a,b)                           \
+       ( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) &&   \
+         (a)->load_flags == (b)->load_flags                )
+
+#define  FTC_BASIC_ATTR_HASH(a)   \
+       ( FTC_SCALER_HASH(&(a)->scaler) + 31*(a)->load_flags )
+
+
+  typedef struct FTC_BasicQueryRec_
+  {
+    FTC_GQueryRec      gquery;
+    FTC_BasicAttrRec   attrs;
+
+  } FTC_BasicQueryRec, *FTC_BasicQuery;
+
+
+
+  typedef struct FTC_BasicFamilyRec_
+  {
+    FTC_FamilyRec      family;
+    FTC_BasicAttrRec   attrs;
+
+  } FTC_BasicFamilyRec, *FTC_BasicFamily;
+
+
+  static FT_Bool
+  ftc_basic_family_compare( FTC_BasicFamily   family,
+                            FTC_BasicQuery    query )
+  {
+    return FT_BOOL( FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ) );
+  }
+
+  static FT_Error
+  ftc_basic_family_init( FTC_BasicFamily   family,
+                         FTC_BasicQuery    query,
+                         FTC_Cache         cache )
+  {
+    ftc_family_init( FTC_FAMILY( family ), cache );
+    family->attrs = query->attrs;
+    return 0;
+  }
+
+  static FT_Error
+  ftc_basic_family_reset( FTC_BasicFamily  family,
+                          FTC_BasicQuery   query )
+  {
+    family->attrs = query->attrs;
+    return 0;
+  }
+
+
+  static FT_Bool
+  ftc_basic_gnode_compare_faceid( FTC_GNode   gnode,
+                                  FTC_FaceID  face_id,
+                                  FTC_Cache   cache )
+  {
+    FTC_BasicFamily  family = (FTC_BasicFamily) gnode->family;
+    FT_Bool          result;
+
+    result = FT_BOOL( family->attrs.scaler.face_id == face_id );
+    if ( result )
+    {
+     /* we must call this function to avoid this node from appearing
+      * in later lookups with the same face_id !!
+      */
+      FTC_GNode_UnselectFamily( gnode, cache );
+    }
+    return result;
+  }
+
+
+  static FT_UInt
+  ftc_basic_family_get_count( FTC_BasicFamily  family,
+                              FTC_Manager      manager )
+  {
+    FT_Error  error;
+    FT_Face   face;
+    FT_UInt   result = 0;
+
+    error = FTC_Manager_LookupFace( manager, &family->attrs.scaler.face_id,
+                                    &face );
+    if ( !error )
+      result = face->num_glyphs;
+
+    return result;
+  }
+
+
+  static FT_Error
+  ftc_basic_family_load_bitmap( FTC_BasicFamily  family,
+                                FT_UInt          gindex,
+                                FTC_Manager      manager,
+                                FT_Face         *aface )
+  {
+    FT_Error  error;
+    FT_Size   size;
+
+    error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
+    if ( !error )
+    {
+      FT_Face   face = size->face;
+
+      error = FT_Load_Glyph( face, gindex, family->attrs.load_flags |
+                                           FT_LOAD_RENDER );
+      if ( !error )
+        *aface = face;
+    }
+    return error;
+  }
+
+
+  static FT_Error
+  ftc_basic_family_load_glyph( FTC_BasicFamily  family,
+                               FT_UInt          gindex,
+                               FTC_Cache        cache,
+                               FT_Glyph        *aglyph )
+  {
+    FT_Error       error;
+    FTC_Scaler     scaler = &family->attrs.scaler;
+    FT_Face        face;
+    FT_Size        size;
+
+    /* we will now load the glyph image */
+    error = FTC_Manager_LookupSize( cache->manager,
+                                    scaler,
+                                    &size );
+    if ( !error )
+    {
+      face = size->face;
+
+      error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
+      if ( !error )
+      {
+        if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
+             face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
+        {
+          /* ok, copy it */
+          FT_Glyph  glyph;
+
+
+          error = FT_Get_Glyph( face->glyph, &glyph );
+          if ( !error )
+          {
+            *aglyph = glyph;
+            goto Exit;
+          }
+        }
+        else
+          error = FTC_Err_Invalid_Argument;
+      }
+    }
+  Exit:
+    return error;
+  }
+
+
+ /*
+  *
+  * basic image cache
+  *
+  */
+
+  static const FTC_IFamilyClassRec  ftc_basic_image_family_class =
+  {
+    {
+      sizeof( FTC_BasicFamilyRec ),
+      (FTC_MruNode_CompareFunc)  ftc_basic_family_compare,
+      (FTC_MruNode_InitFunc)     ftc_basic_family_init,
+      (FTC_MruNode_ResetFunc)    ftc_basic_family_reset,
+      (FTC_MruNode_DoneFunc)     NULL
+    },
+    (FTC_IFamily_LoadGlyphFunc)  ftc_basic_family_load_glyph
+  };
+
+
+
+  static const FTC_GCacheClassRec  ftc_basic_image_cache_class =
+  {
+    {
+      (FTC_Node_NewFunc)      FTC_INode_New,
+      (FTC_Node_WeightFunc)   FTC_INode_Weight,
+      (FTC_Node_CompareFunc)  FTC_GNode_Compare,
+      (FTC_Node_CompareFunc)  ftc_basic_gnode_compare_faceid,
+      (FTC_Node_FreeFunc)     FTC_INode_Free,
+
+      sizeof( FTC_GCacheRec ),
+      (FTC_Cache_InitFunc)    FTC_GCache_Init,
+      (FTC_Cache_DoneFunc)    FTC_GCache_Done
+    },
+    (FTC_MruListClass) & ftc_basic_image_family_class
+  };
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_ImageCache_New( FTC_Manager      manager,
+                      FTC_ImageCache  *acache )
+  {
+    return FTC_GCache_New( manager, & ftc_basic_image_cache_class,
+                           (FTC_GCache*) acache );
+  }
+
+
+  /* documentation is in ftcimage.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_ImageCache_Lookup( FTC_ImageCache  cache,
+                         FTC_ImageType   type,
+                         FT_UInt         gindex,
+                         FT_Glyph       *aglyph,
+                         FTC_Node       *anode )
+  {
+    FTC_BasicQueryRec  query;
+    FTC_INode          node;
+    FT_Error           error;
+    FT_UInt32          hash;
+
+
+    /* some argument checks are delayed to FTC_Cache_Lookup */
+    if ( !aglyph )
+    {
+      error = FTC_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    *aglyph = NULL;
+    if ( anode )
+      *anode  = NULL;
+
+    query.attrs.scaler.face_id = type->face_id;
+    query.attrs.scaler.width   = type->width;
+    query.attrs.scaler.height  = type->height;
+    query.attrs.scaler.pixel   = 1;
+    query.attrs.load_flags     = type->flags;
+
+    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) ^ (gindex << 8);
+
+    error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
+                               hash, gindex,
+                               FTC_GQUERY( &query ),
+                               (FTC_Node*) &node );
+    if ( !error )
+    {
+      *aglyph = FTC_INODE(node)->glyph;
+
+      if ( anode )
+      {
+        *anode = FTC_NODE(node);
+        FTC_NODE(node)->ref_count++;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+
+ /*
+  *
+  * basic small bitmap cache
+  *
+  */
+
+
+  static const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
+  {
+    {
+      sizeof( FTC_BasicFamilyRec ),
+      (FTC_MruNode_CompareFunc)  ftc_basic_family_compare,
+      (FTC_MruNode_InitFunc)     ftc_basic_family_init,
+      (FTC_MruNode_ResetFunc)    ftc_basic_family_reset,
+      (FTC_MruNode_DoneFunc)     NULL
+    },
+    (FTC_SFamily_GetCountFunc)   ftc_basic_family_get_count,
+    (FTC_SFamily_LoadGlyphFunc)  ftc_basic_family_load_bitmap
+  };
+
+
+  static const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
+  {
+    {
+      (FTC_Node_NewFunc)      FTC_SNode_New,
+      (FTC_Node_WeightFunc)   FTC_SNode_Weight,
+      (FTC_Node_CompareFunc)  FTC_SNode_Compare,
+      (FTC_Node_CompareFunc)  ftc_basic_gnode_compare_faceid,
+      (FTC_Node_FreeFunc)     FTC_SNode_Free,
+
+      sizeof( FTC_GCacheRec ),
+      (FTC_Cache_InitFunc)    FTC_GCache_Init,
+      (FTC_Cache_DoneFunc)    FTC_GCache_Done
+    },
+    (FTC_MruListClass) & ftc_basic_sbit_family_class
+  };
+
+
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SBitCache_New( FTC_Manager     manager,
+                     FTC_SBitCache  *acache )
+  {
+    return FTC_GCache_New( manager, & ftc_basic_sbit_cache_class,
+                           (FTC_GCache*) acache );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SBitCache_Lookup( FTC_SBitCache   cache,
+                        FTC_ImageType   type,
+                        FT_UInt         gindex,
+                        FTC_SBit       *ansbit,
+                        FTC_Node       *anode )
+  {
+    FT_Error           error;
+    FTC_BasicQueryRec  query;
+    FTC_SNode          node;
+    FT_UInt32          hash;
+
+    if ( anode )
+      *anode = NULL;
+
+    /* other argument checks delayed to FTC_Cache_Lookup */
+    if ( !ansbit )
+      return FTC_Err_Invalid_Argument;
+
+    *ansbit = NULL;
+
+    query.attrs.scaler.face_id = type->face_id;
+    query.attrs.scaler.width   = type->width;
+    query.attrs.scaler.height  = type->height;
+    query.attrs.scaler.pixel   = 1;
+    query.attrs.load_flags     = type->flags;
+
+   /* beware, the hash must be the same for all glyph ranges !!
+    */
+    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) ^
+           (gindex/FTC_SBIT_ITEMS_PER_NODE);
+
+    error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
+                               hash,
+                               gindex,
+                               FTC_GQUERY( &query ),
+                               (FTC_Node*) &node );
+    if ( error )
+      goto Exit;
+
+    *ansbit = node->sbits + ( gindex - FTC_GNODE(node)->gindex );
+
+    if ( anode )
+    {
+      *anode = FTC_NODE( node );
+      FTC_NODE( node )->ref_count++;
+    }
+
+  Exit:
+    return error;
+  }
+
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -17,7 +17,7 @@
 
 
 #include <ft2build.h>
-#include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_MANAGER_H
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 
@@ -40,23 +40,6 @@
   /*************************************************************************/
   /*************************************************************************/
 
-  FT_EXPORT_DEF( void )
-  ftc_node_done( FTC_Node   node,
-                 FTC_Cache  cache )
-  {
-    FTC_Family       family;
-    FTC_FamilyEntry  entry;
-
-
-    entry  = cache->manager->families.entries + node->fam_index;
-    family = entry->family;
-
-    /* remove from parent set table - eventually destroy the set */
-    if ( --family->num_nodes == 0 )
-      FT_LruList_Remove( cache->families, (FT_LruNode) family );
-  }
-
-
   /* add a new node to the head of the manager's circular MRU list */
   static void
   ftc_node_mru_link( FTC_Node     node,
@@ -152,159 +135,171 @@
   }
 
 
-  /* remove a node from its cache's hash table */
-  static FT_Error
-  ftc_node_hash_unlink( FTC_Node   node,
-                        FTC_Cache  cache )
+ /* note that this function cannot fail. If we cannot re-size the
+  * buckets array appropriately, we simply degrade the hash table's
+  * performance !!
+  */
+  static void
+  ftc_cache_resize( FTC_Cache  cache )
   {
-    FT_Error   error = 0;
-    FTC_Node  *pnode;
-    FT_UInt    idx, num_buckets;
-
-
-    idx = (FT_UInt)( node->hash & cache->mask );
-    if ( idx < cache->p )
-      idx = (FT_UInt)( node->hash & ( 2 * cache->mask + 1 ) );
-
-    pnode = cache->buckets + idx;
-
     for (;;)
     {
-      if ( *pnode == NULL )
-      {
-        FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" ));
-        return FTC_Err_Ok;
-      }
+      FTC_Node   node, *pnode;
+      FT_UInt    p      = cache->p;
+      FT_UInt    mask   = cache->mask;
+      FT_UInt    count  = mask + p + 1;    /* number of buckets */
 
-      if ( *pnode == node )
+     /* do we need to shrink the buckets array ?
+      */
+      if ( cache->slack < 0 )
       {
-        *pnode     = node->link;
-        node->link = NULL;
-        break;
-      }
+        FTC_Node   new_list = NULL;
 
-      pnode = &(*pnode)->link;
-    }
+        /* try to expand the buckets array _before_ splitting
+         * the bucket lists
+         */
+         if ( p >= mask )
+         {
+           FT_Memory  memory = cache->memory;
 
-    num_buckets = ( cache->p + cache->mask + 1 );
+          /* if we can't expand the array, leave immediately */
+           if ( FT_MEM_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) )
+             break;
+         }
 
-    if ( ++cache->slack > (FT_Long)num_buckets * FTC_HASH_SUB_LOAD )
-    {
-      FT_UInt    p         = cache->p;
-      FT_UInt    mask      = cache->mask;
-      FT_UInt    old_index = p + mask;
-      FTC_Node*  pold;
+        /* split a single bucket */
+         pnode = cache->buckets + p;
 
+         for (;;)
+         {
+           node = *pnode;
+           if ( node == NULL )
+             break;
 
-      if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
-        goto Exit;
+           if ( node->hash & ( mask + 1 ) )
+           {
+             *pnode     = node->link;
+             node->link = new_list;
+             new_list   = node;
+           }
+           else
+             pnode = &node->link;
+         }
 
-      if ( p == 0 )
-      {
-        FT_Memory  memory = cache->memory;
+         cache->buckets[p + mask + 1] = new_list;
 
+         cache->slack += FTC_HASH_MAX_LOAD;
 
-        cache->mask >>= 1;
-        p             = cache->mask;
-
-        if ( FT_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) )
+        if ( p >= mask )
         {
-          FT_ERROR(( "ftc_node_hash_unlink: couldn't shunk buckets!\n" ));
-          goto Exit;
+          cache->mask = 2 * mask + 1;
+          cache->p    = 0;
         }
+        else
+          cache->p = p + 1;
       }
-      else
-        p--;
+     /* do we need to expand the buckets array ?
+      */
+      else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD )
+      {
+        FT_UInt    old_index = p + mask;
+        FTC_Node*  pold;
 
-      pnode = cache->buckets + p;
-      while ( *pnode )
-        pnode = &(*pnode)->link;
+        if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
+          break;
 
-      pold   = cache->buckets + old_index;
-      *pnode = *pold;
-      *pold  = NULL;
+        if ( p == 0 )
+        {
+          FT_Memory  memory = cache->memory;
 
-      cache->slack -= FTC_HASH_MAX_LOAD;
-      cache->p      = p;
-    }
+         /* if we can't shrink the array, leave immediately */
+          if ( FT_MEM_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) )
+            break;
 
-  Exit:
-    return error;
+          cache->mask >>= 1;
+          p             = cache->mask;
+        }
+        else
+          p--;
+
+        pnode = cache->buckets + p;
+        while ( *pnode )
+          pnode = &(*pnode)->link;
+
+        pold   = cache->buckets + old_index;
+        *pnode = *pold;
+        *pold  = NULL;
+
+        cache->slack -= FTC_HASH_MAX_LOAD;
+        cache->p      = p;
+      }
+      else /* the hash table is balanced */
+        break;
+    }
   }
 
 
 
-  /* add a node to the "top" of its cache's hash table */
-  static FT_Error
-  ftc_node_hash_link( FTC_Node   node,
-                      FTC_Cache  cache )
+  /* remove a node from its cache's hash table */
+  static void
+  ftc_node_hash_unlink( FTC_Node   node0,
+                        FTC_Cache  cache )
   {
     FTC_Node  *pnode;
     FT_UInt    idx;
-    FT_Error   error = 0;
 
 
-    idx = (FT_UInt)( node->hash & cache->mask );
+    idx = (FT_UInt)( node0->hash & cache->mask );
     if ( idx < cache->p )
-      idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) );
+      idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) );
 
     pnode = cache->buckets + idx;
 
-    node->link = *pnode;
-    *pnode     = node;
-
-    if ( --cache->slack < 0 )
+    for (;;)
     {
-      FT_UInt    p     = cache->p;
-      FT_UInt    mask  = cache->mask;
-      FTC_Node   new_list;
+      FTC_Node  node = *pnode;
 
+      if ( node == NULL )
+      {
+        FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" ));
+        return;
+      }
 
-      /* split a single bucket */
-      new_list = NULL;
-      pnode    = cache->buckets + p;
+      if ( node == node0 )
+        break;
 
-      for (;;)
-      {
-        node = *pnode;
-        if ( node == NULL )
-          break;
+      pnode = &(*pnode)->link;
+    }
 
-        if ( node->hash & ( mask + 1 ) )
-        {
-          *pnode     = node->link;
-          node->link = new_list;
-          new_list   = node;
-        }
-        else
-          pnode = &node->link;
-      }
+    *pnode      = node0->link;
+    node0->link = NULL;
 
-      cache->buckets[p + mask + 1] = new_list;
+    cache->slack++;
+    ftc_cache_resize( cache );
+  }
 
-      cache->slack += FTC_HASH_MAX_LOAD;
 
-      if ( p >= mask )
-      {
-        FT_Memory  memory = cache->memory;
 
+  /* add a node to the "top" of its cache's hash table */
+  static void
+  ftc_node_hash_link( FTC_Node   node,
+                      FTC_Cache  cache )
+  {
+    FTC_Node  *pnode;
+    FT_UInt    idx;
 
-        if ( FT_RENEW_ARRAY( cache->buckets,
-                             ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) )
-        {
-          FT_ERROR(( "ftc_node_hash_link: couldn't expand buckets!\n" ));
-          goto Exit;
-        }
 
-        cache->mask = 2 * mask + 1;
-        cache->p    = 0;
-      }
-      else
-        cache->p = p + 1;
-    }
+    idx = (FT_UInt)( node->hash & cache->mask );
+    if ( idx < cache->p )
+      idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) );
 
-  Exit:
-    return error;
+    pnode = cache->buckets + idx;
+
+    node->link = *pnode;
+    *pnode     = node;
+
+    cache->slack--;
+    ftc_cache_resize( cache );
   }
 
 
@@ -315,15 +310,12 @@
   ftc_node_destroy( FTC_Node     node,
                     FTC_Manager  manager )
   {
-    FT_Memory        memory  = manager->library->memory;
-    FTC_Cache        cache;
-    FTC_FamilyEntry  entry;
-    FTC_Cache_Class  clazz;
+    FTC_Cache  cache;
 
 
 #ifdef FT_DEBUG_ERROR
     /* find node's cache */
-    if ( node->fam_index >= manager->families.count )
+    if ( node->cache_index >= manager->num_caches )
     {
       FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
       return;
@@ -330,8 +322,7 @@
     }
 #endif
 
-    entry = manager->families.entries + node->fam_index;
-    cache = entry->cache;
+    cache = manager->caches[ node->cache_index ];
 
 #ifdef FT_DEBUG_ERROR
     if ( cache == NULL )
@@ -341,10 +332,8 @@
     }
 #endif
 
-    clazz = cache->clazz;
+    manager->cur_weight -= cache->clazz.node_weight( node, cache );
 
-    manager->cur_weight -= clazz->node_weight( node, cache );
-
     /* remove node from mru list */
     ftc_node_mru_unlink( node, manager );
 
@@ -352,11 +341,8 @@
     ftc_node_hash_unlink( node, cache );
 
     /* now finalize it */
-    if ( clazz->node_done )
-      clazz->node_done( node, cache );
+    cache->clazz.node_free( node, cache );
 
-    FT_FREE( node );
-
 #if 0
     /* check, just in case of general corruption :-) */
     if ( manager->num_nodes == 0 )
@@ -369,58 +355,6 @@
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
-  /*****                   CACHE FAMILY DEFINITIONS                    *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_EXPORT_DEF( FT_Error )
-  ftc_family_init( FTC_Family  family,
-                   FTC_Query   query,
-                   FTC_Cache   cache )
-  {
-    FT_Error         error;
-    FTC_Manager      manager = cache->manager;
-    FT_Memory        memory  = manager->library->memory;
-    FTC_FamilyEntry  entry;
-
-
-    family->cache     = cache;
-    family->num_nodes = 0;
-
-    /* now add to manager's family table */
-    error = ftc_family_table_alloc( &manager->families, memory, &entry );
-    if ( !error )
-    {
-      entry->cache      = cache;
-      entry->family     = family;
-      family->fam_index = entry->index;
-
-      query->family = family;   /* save family in query */
-    }
-
-    return error;
-  }
-
-
-  FT_EXPORT_DEF( void )
-  ftc_family_done( FTC_Family  family )
-  {
-    if ( family && family->cache )
-    {
-      FTC_Manager  manager = family->cache->manager;
-
-
-      /* remove from manager's family table */
-      ftc_family_table_free( &manager->families, family->fam_index );
-    }
-  }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
   /*****                    ABSTRACT CACHE CLASS                       *****/
   /*****                                                               *****/
   /*************************************************************************/
@@ -427,62 +361,28 @@
   /*************************************************************************/
 
 
-
-  FT_EXPORT_DEF( FT_Error )
-  ftc_cache_init( FTC_Cache  cache )
+  FT_EXPORT( FT_Error )
+  FTC_Cache_Init( FTC_Cache       cache )
   {
-    FT_Memory        memory = cache->memory;
-    FTC_Cache_Class  clazz  = cache->clazz;
-    FT_Error         error;
+    FT_Memory  memory = cache->memory;
 
+    cache->p       = 0;
+    cache->mask    = FTC_HASH_INITIAL_SIZE - 1;
+    cache->slack   = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
 
-    cache->p     = 0;
-    cache->mask  = FTC_HASH_INITIAL_SIZE - 1;
-    cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
-
-    if ( FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) )
-      goto Exit;
-
-    /* now, initialize the lru list of families for this cache */
-    if ( clazz->family_size > 0 )
-    {
-      FT_LruList_ClassRec*  lru_class = &cache->family_class;
-
-
-      lru_class->list_size = sizeof( FT_LruListRec );
-      lru_class->list_init = NULL;
-      lru_class->list_done = NULL;
-
-      lru_class->node_size    = clazz->family_size;
-      lru_class->node_init    = (FT_LruNode_InitFunc)   clazz->family_init;
-      lru_class->node_done    = (FT_LruNode_DoneFunc)   clazz->family_done;
-      lru_class->node_flush   = (FT_LruNode_FlushFunc)  NULL;
-      lru_class->node_compare = (FT_LruNode_CompareFunc)clazz->family_compare;
-
-      error = FT_LruList_New( (FT_LruList_Class) lru_class,
-                              0,    /* max items == 0 => unbounded list */
-                              cache,
-                              memory,
-                              &cache->families );
-      if ( error )
-        FT_FREE( cache->buckets );
-    }
-
-  Exit:
-    return error;
+    return ( FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) );
   }
 
 
+
   FT_EXPORT_DEF( void )
-  ftc_cache_clear( FTC_Cache  cache )
+  FTC_Cache_Clear( FTC_Cache  cache )
   {
     if ( cache )
     {
-      FT_Memory        memory  = cache->memory;
-      FTC_Cache_Class  clazz   = cache->clazz;
-      FTC_Manager      manager = cache->manager;
-      FT_UFast         i;
-      FT_UInt          count;
+      FTC_Manager  manager = cache->manager;
+      FT_UFast     i;
+      FT_UInt      count;
 
       count = cache->p + cache->mask + 1;
 
@@ -500,310 +400,228 @@
           ftc_node_mru_unlink( node, manager );
 
           /* now finalize it */
-          manager->cur_weight -= clazz->node_weight( node, cache );
+          manager->cur_weight -= cache->clazz.node_weight( node, cache );
 
-          if ( clazz->node_done )
-            clazz->node_done( node, cache );
-
-          FT_FREE( node );
+          cache->clazz.node_free( node, cache );
           node = next;
         }
         cache->buckets[i] = NULL;
       }
-
-      cache->p = 0;
-
-      /* destroy the families */
-      if ( cache->families )
-        FT_LruList_Reset( cache->families );
+      ftc_cache_resize( cache );
     }
   }
 
 
-  FT_EXPORT_DEF( void )
-  ftc_cache_done( FTC_Cache  cache )
+  FT_EXPORT( void )
+  FTC_Cache_Done( FTC_Cache  cache )
   {
-    if ( cache )
+    if ( cache->memory )
     {
       FT_Memory  memory = cache->memory;
 
+      FTC_Cache_Clear( cache );
 
-      ftc_cache_clear( cache );
-
       FT_FREE( cache->buckets );
       cache->mask  = 0;
+      cache->p     = 0;
       cache->slack = 0;
 
-      if ( cache->families )
-      {
-        FT_LruList_Destroy( cache->families );
-        cache->families = NULL;
-      }
+      cache->memory = NULL;
     }
   }
 
 
-  /* Look up a node in "top" of its cache's hash table. */
-  /* If not found, create a new node.                   */
-  /*                                                    */
-  FT_EXPORT_DEF( FT_Error )
-  ftc_cache_lookup( FTC_Cache   cache,
-                    FTC_Query   query,
-                    FTC_Node   *anode )
+
+  static void
+  ftc_cache_add( FTC_Cache    cache,
+                 FT_UInt32    hash,
+                 FTC_Node     node )
   {
-    FT_Error     error = FTC_Err_Ok;
-    FTC_Manager  manager;
-    FT_LruNode   lru;
-    FT_UInt      free_count = 0;
+    node->hash = hash;
 
+    ftc_node_hash_link( node, cache );
+    ftc_node_mru_link( node, cache->manager );
 
-    if ( !cache || !query || !anode )
-      return FTC_Err_Invalid_Argument;
+    {
+      FTC_Manager  manager = cache->manager;
 
-    *anode = NULL;
+      manager->cur_weight += cache->clazz.node_weight( node, cache );
 
-    query->hash   = 0;
-    query->family = NULL;
-
-    manager = cache->manager;
-
-   /*  here's a small note explaining what's happening in the code below.
-    *
-    *  We need to deal intelligently with out-of-memory (OOM) conditions
-    *  when trying to create a new family or cache node during the lookup.
-    *
-    *  When an OOM is detected, we try to free one or more "old" nodes
-    *  from the cache, then try again.  It may be necessary to do that
-    *  several times, so a loop is needed.
-    *
-    *  The local variable "free_count" holds the number of "old" nodes to
-    *  discard on each attempt.  It starts at 1 and doubles on each
-    *  iteration.  The loop stops when:
-    *
-    *   - a non-OOM error is detected
-    *   - a succesful lookup is performed
-    *   - there are no more unused nodes in the cache
-    *
-    *  For the record, remember that all used nodes appear _before_
-    *  unused ones in the manager's MRU node list.
-    */
-
-    for (;;)
-    {
+      if ( manager->cur_weight >= manager->max_weight )
       {
-        /* first of all, find the relevant family */
-        FT_LruList              list    = cache->families;
-        FT_LruNode              fam, *pfam;
-        FT_LruNode_CompareFunc  compare = list->clazz->node_compare;
+        node->ref_count++;
+        FTC_Manager_Compress( manager );
+        node->ref_count--;
+      }
+    }
+  }
 
-        pfam = &list->nodes;
-        for (;;)
-        {
-          fam = *pfam;
-          if ( fam == NULL )
-          {
-            error = FT_LruList_Lookup( list, query, &lru );
-            if ( error )
-              goto Fail;
 
-            goto Skip;
-          }
+  FT_EXPORT( FT_Error )
+  FTC_Cache_Lookup( FTC_Cache   cache,
+                    FT_UInt32   hash,
+                    FT_Pointer  query,
+                    FTC_Node   *anode )
+  {
+    FT_UFast   idx;
+    FTC_Node*  bucket;
+    FTC_Node*  pnode;
+    FTC_Node   node;
+    FT_Error   error = 0;
 
-          if ( compare( fam, query, list->data ) )
-            break;
+    FTC_Node_CompareFunc  compare = cache->clazz.node_compare;
 
-          pfam = &fam->next;
-        }
 
-        FT_ASSERT( fam != NULL );
+    if ( cache == NULL || anode == NULL )
+      return FT_Err_Invalid_Argument;
 
-        /* move to top of list when needed */
-        if ( fam != list->nodes )
-        {
-          *pfam       = fam->next;
-          fam->next   = list->nodes;
-          list->nodes = fam;
-        }
+    idx = hash & cache->mask;
+    if ( idx < cache->p )
+      idx = hash & ( cache->mask * 2 + 1 );
 
-        lru = fam;
+    bucket = cache->buckets + idx;
+    pnode  = bucket;
+    for (;;)
+    {
+      node = *pnode;
+      if ( node == NULL )
+        goto NewNode;
 
-      Skip:
-        ;
-      }
+      if ( node->hash == hash && compare( node, query, cache ) )
+        break;
 
-      {
-        FTC_Family   family  = (FTC_Family) lru;
-        FT_UFast     hash    = query->hash;
-        FTC_Node*    bucket;
-        FT_UInt      idx;
+      pnode = &node->link;
+    }
 
+    if ( node != *bucket )
+    {
+      *pnode     = node->link;
+      node->link = *bucket;
+      *bucket    = node;
+    }
 
-        idx = hash & cache->mask;
-        if ( idx < cache->p )
-          idx = hash & ( cache->mask * 2 + 1 );
+    /* move to head of MRU list */
+    {
+      FTC_Manager  manager = cache->manager;
 
-        bucket  = cache->buckets + idx;
+      if ( node != manager->nodes_list )
+        ftc_node_mru_up( node, manager );
+    }
+    goto Exit;
 
+  NewNode:
 
-        if ( query->family     != family                 ||
-             family->fam_index >= manager->families.size )
-        {
-          FT_ERROR((
-            "ftc_cache_lookup: invalid query (bad 'family' field)\n" ));
-          error = FTC_Err_Invalid_Argument;
-          goto Exit;
-        }
+   /*
+    *  try to allocate a new cache node. Note that in case of
+    *  out-of-memory error (OOM), we'll flush the cache a bit,
+    *  then try again.
+    *
+    *  on each try, the "tries" variable gives the number
+    *  of old nodes we want to flush from the manager's global list
+    *  before the next allocation attempt. it barely doubles on
+    *  each iteration
+    *
+    */
+    error = cache->clazz.node_new( &node, query, cache );
+    if ( !error )
+      goto AddNode;
 
-        if ( *bucket )
-        {
-          FTC_Node*             pnode   = bucket;
-          FTC_Node_CompareFunc  compare = cache->clazz->node_compare;
+    node = NULL;
+    if ( error != FT_Err_Out_Of_Memory )
+      goto Exit;
 
+    {
+      FTC_Manager  manager = cache->manager;
+      FT_UInt      count, tries = 1;
 
-          for ( ;; )
-          {
-            FTC_Node  node;
+      for (;;)
+      {
+        error = cache->clazz.node_new( &node, query, cache );
+        if ( !error )
+          break;
 
+        node = NULL;
+        if ( error != FT_Err_Out_Of_Memory )
+          goto Exit;
 
-            node = *pnode;
-            if ( node == NULL )
-              break;
+        count = FTC_Manager_FlushN( manager, tries );
+        if ( count == 0 )
+          goto Exit;
 
-            if ( node->hash == hash                            &&
-                 (FT_UInt)node->fam_index == family->fam_index &&
-                 compare( node, query, cache ) )
-            {
-              /* move to head of bucket list */
-              if ( pnode != bucket )
-              {
-                *pnode     = node->link;
-                node->link = *bucket;
-                *bucket    = node;
-              }
-
-              /* move to head of MRU list */
-              if ( node != manager->nodes_list )
-                ftc_node_mru_up( node, manager );
-
-              *anode = node;
-              goto Exit;
-            }
-
-            pnode = &node->link;
-          }
+        if ( count == tries )
+        {
+          count = tries*2;
+          if ( count < tries || count > manager->num_nodes )
+            count = manager->num_nodes;
         }
+        tries = count;
+      }
+    }
 
-        /* didn't find a node, create a new one */
-        {
-          FTC_Cache_Class  clazz   = cache->clazz;
-          FT_Memory        memory  = cache->memory;
-          FTC_Node         node;
+  AddNode:
+   /* don't assume that the cache has the same number of buckets, since
+    * our allocation request might have triggered global cache flushing
+    */
+    ftc_cache_add( cache, hash, node );
 
+  Exit:
+    *anode = node;
+    return error;
+  }
 
-          if ( FT_ALLOC( node, clazz->node_size ) )
-            goto Fail;
 
-          node->fam_index = (FT_UShort) family->fam_index;
-          node->hash      = query->hash;
-          node->ref_count = 0;
 
-          error = clazz->node_init( node, query, cache );
-          if ( error )
-          {
-            FT_FREE( node );
-            goto Fail;
-          }
 
-          error = ftc_node_hash_link( node, cache );
-          if ( error )
-          {
-            clazz->node_done( node, cache );
-            FT_FREE( node );
-            goto Fail;
-          }
+  FT_EXPORT( void )
+  FTC_Cache_RemoveFaceID( FTC_Cache    cache,
+                           FTC_FaceID   face_id )
+  {
+    FT_UFast     i, count;
+    FTC_Manager  manager = cache->manager;
+    FTC_Node     free    = NULL;
 
-          ftc_node_mru_link( node, cache->manager );
+    count = cache->p + cache->mask;
+    for ( i = 0; i < count; i++ )
+    {
+      FTC_Node*  bucket = cache->buckets + i;
+      FTC_Node*  pnode  = bucket;
 
-          cache->manager->cur_weight += clazz->node_weight( node, cache );
+      for ( ;; )
+      {
+        FTC_Node  node = *pnode;
 
-          /* now try to compress the node pool when necessary */
-          if ( manager->cur_weight >= manager->max_weight )
-          {
-            node->ref_count++;
-            FTC_Manager_Compress( manager );
-            node->ref_count--;
-          }
+        if ( node == NULL )
+          break;
 
-          *anode = node;
+        if ( cache->clazz.node_remove_faceid( node, face_id, cache ) )
+        {
+          *pnode = node->link;
+          node->link = free;
+          free       = node;
         }
-
-       /* all is well, exit now
-        */
-        goto Exit;
+        else
+          pnode = &node->link;
       }
+    }
 
-    Fail:
-      if ( error != FTC_Err_Out_Of_Memory )
-        goto Exit;
+   /* remove all nodes in the free list
+    */
+    while ( free )
+    {
+      FTC_Node  node;
 
-     /* There is not enough memory; try to release some unused nodes
-      * from the cache to make room for a new one.
-      */
-      {
-        FT_UInt  new_count;
+      node = free;
+      free = node->link;
 
+      manager->cur_weight -= cache->clazz.node_weight( node, cache );
+      ftc_node_mru_unlink( node, manager );
 
-        new_count = 1 + free_count * 2;
+      cache->clazz.node_free( node, cache );
 
-        /* check overflow and bounds */
-        if ( new_count < free_count || free_count > manager->num_nodes )
-          goto Exit;
-
-        free_count = new_count;
-
-        /* try to remove "new_count" nodes from the list */
-        {
-          FTC_Node  first = manager->nodes_list;
-          FTC_Node  node;
-
-
-          if ( first == NULL )  /* empty list! */
-            goto Exit;
-
-          /* go to last node - it's a circular list */
-          node = first->mru_prev;
-          for ( ; node && new_count > 0; new_count-- )
-          {
-            FTC_Node  prev = node->mru_prev;
-
-
-            /* Used nodes always appear before unused one in the MRU
-             * list.  If we find one here, we'd better stop right now
-             * our iteration.
-             */
-            if ( node->ref_count > 0 )
-            {
-              /* if there are no unused nodes in the list, we'd better exit */
-              if ( new_count == free_count )
-                goto Exit;
-
-              break;
-            }
-
-            ftc_node_destroy( node, manager );
-
-            if ( node == first )
-              break;
-
-            node = prev;
-          }
-        }
-      }
+      cache->slack ++;
     }
 
-  Exit:
-    return error;
+    ftc_cache_resize( cache );
   }
-
 
 /* END */
--- a/src/cache/ftccmap.c
+++ b/src/cache/ftccmap.c
@@ -19,8 +19,7 @@
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_CACHE_H
-#include FT_CACHE_CHARMAP_H
-#include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_MANAGER_H
 #include FT_INTERNAL_MEMORY_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_TRUETYPE_IDS_H
@@ -47,56 +46,41 @@
   /* number of glyph indices / character code per node */
 #define FTC_CMAP_INDICES_MAX  128
 
+  /* compute a query/node hash */
+#define  FTC_CMAP_HASH( faceid, index, charcode )    \
+   ( FTC_FACE_ID_HASH( faceid ) + 211*( index ) + ((char_code) / FTC_CMAP_INDICES_MAX) )
 
+  /* the charmap query */
+  typedef struct  FTC_CMapQueryRec_
+  {
+    FTC_FaceID    face_id;
+    FT_UInt       cmap_index;
+    FT_UInt32     char_code;
+
+  } FTC_CMapQueryRec, *FTC_CMapQuery;
+
+#define  FTC_CMAP_QUERY(x)  ((FTC_CMapQuery)(x))
+#define  FTC_CMAP_QUERY_HASH(x)  FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code )
+
+ /* the cmap cache node */
   typedef struct  FTC_CMapNodeRec_
   {
     FTC_NodeRec  node;
+    FTC_FaceID   face_id;
+    FT_UInt      cmap_index;
     FT_UInt32    first;                         /* first character in node */
     FT_UInt16    indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices  */
 
   } FTC_CMapNodeRec, *FTC_CMapNode;
 
-
 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
+#define FTC_CMAP_NODE_HASH(x)  FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first )
 
-
-  /* compute node hash value from cmap family and "requested" glyph index */
-#define FTC_CMAP_HASH( cfam, cquery )                                       \
-          ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) )
-
   /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
   /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet   */
 #define FTC_CMAP_UNKNOWN  ( (FT_UInt16)-1 )
 
 
-  /* the charmap query */
-  typedef struct  FTC_CMapQueryRec_
-  {
-    FTC_QueryRec  query;
-    FTC_CMapDesc  desc;
-    FT_UInt32     char_code;
-
-  } FTC_CMapQueryRec, *FTC_CMapQuery;
-
-
-#define FTC_CMAP_QUERY( x )  ( (FTC_CMapQuery)( x ) )
-
-
-  /* the charmap family */
-  typedef struct FTC_CMapFamilyRec_
-  {
-    FTC_FamilyRec    family;
-    FT_UInt32        hash;
-    FTC_CMapDescRec  desc;
-    FT_UInt          index;
-
-  } FTC_CMapFamilyRec, *FTC_CMapFamily;
-
-
-#define FTC_CMAP_FAMILY( x )         ( (FTC_CMapFamily)( x ) )
-#define FTC_CMAP_FAMILY_MEMORY( x )  FTC_FAMILY( x )->memory
-
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -108,25 +92,40 @@
 
   /* no need for specific finalizer; we use "ftc_node_done" directly */
 
-  /* initialize a new cmap node */
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_cmap_node_init( FTC_CMapNode   cnode,
-                      FTC_CMapQuery  cquery,
+  FT_CALLBACK_DEF( void )
+  ftc_cmap_node_free( FTC_CMapNode   node,
                       FTC_Cache      cache )
   {
-    FT_UInt32  first;
-    FT_UInt    n;
-    FT_UNUSED( cache );
+    FT_Memory  memory = cache->memory;
 
+    FT_FREE( node );
+  }
 
-    first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) *
-            FTC_CMAP_INDICES_MAX;
 
-    cnode->first = first;
-    for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
-      cnode->indices[n] = FTC_CMAP_UNKNOWN;
+  /* initialize a new cmap node */
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_cmap_node_new( FTC_CMapNode  *anode,
+                     FTC_CMapQuery  query,
+                     FTC_Cache      cache )
+  {
+    FT_Error      error;
+    FT_Memory     memory  = cache->memory;
+    FTC_CMapNode  node;
+    FT_UInt       nn;
 
-    return 0;
+    if ( !FT_NEW( node ) )
+    {
+      node->face_id    = query->face_id;
+      node->cmap_index = query->cmap_index;
+      node->first      = (query->char_code / FTC_CMAP_INDICES_MAX) *
+                         FTC_CMAP_INDICES_MAX;
+
+      for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
+        node->indices[nn] = FTC_CMAP_UNKNOWN;
+    }
+
+    *anode = node;
+    return error;
   }
 
 
@@ -142,188 +141,27 @@
 
   /* compare a cmap node to a given query */
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_cmap_node_compare( FTC_CMapNode   cnode,
-                         FTC_CMapQuery  cquery )
+  ftc_cmap_node_compare( FTC_CMapNode   node,
+                         FTC_CMapQuery  query )
   {
-    FT_UInt32  offset = (FT_UInt32)( cquery->char_code - cnode->first );
-
-
-    return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
-  }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    CHARMAP FAMILY                             *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_cmap_family_init( FTC_CMapFamily  cfam,
-                        FTC_CMapQuery   cquery,
-                        FTC_Cache       cache )
-  {
-    FTC_Manager   manager = cache->manager;
-    FTC_CMapDesc  desc = cquery->desc;
-    FT_UInt32     hash = 0;
-    FT_Error      error;
-    FT_Face       face;
-
-
-    /* setup charmap descriptor */
-    cfam->desc = *desc;
-
-    /* let's see whether the rest is correct too */
-    error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
-    if ( !error )
+    if ( node->face_id    == query->face_id    &&
+         node->cmap_index == query->cmap_index )
     {
-      FT_UInt      count = face->num_charmaps;
-      FT_UInt      idx   = count;
-      FT_CharMap*  cur   = face->charmaps;
+      FT_UInt32  offset = (FT_UInt32)( query->char_code - node->first );
 
-
-      switch ( desc->type )
-      {
-      case FTC_CMAP_BY_INDEX:
-        idx  = desc->u.index;
-        hash = idx * 33;
-        break;
-
-      case FTC_CMAP_BY_ENCODING:
-        if ( desc->u.encoding == FT_ENCODING_UNICODE )
-        {
-          /* Since the `interesting' table, pid/eid (3,10), is normally the
-           * last one, we loop backwards.  This looses with type1 fonts with
-           * non-BMP characters (<.0001%), this wins with .ttf with non-BMP
-           * chars (.01% ?), and this is the same about 99.99% of the time!
-           */
-
-          FT_UInt  unicmap_idx = count;  /* some UCS-2 map, if we found it */
-
-
-          cur += count - 1;
-
-          for ( idx = 0; idx < count; idx++, cur-- )
-          {
-            if ( cur[0]->encoding == FT_ENCODING_UNICODE )
-            {
-              unicmap_idx = idx;  /* record we found a Unicode charmap */
-
-              /* XXX If some new encodings to represent UCS-4 are added,
-               *     they should be added here.
-               */
-              if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
-                     cur[0]->encoding_id == TT_MS_ID_UCS_4        )      ||
-                   ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
-                     cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32    )  )
-
-              /* Hurray! We found a UCS-4 charmap.  We can stop the scan! */
-              {
-                idx = count - 1 - idx;
-                goto Found_idx_for_FTC_CMAP_BY_ENCODING;
-              }
-            }
-          }
-
-          /* We do not have any UCS-4 charmap. Sigh.
-           * Let's see if we have some other kind of Unicode charmap, though.
-           */
-          if ( unicmap_idx < count )
-            idx = count - 1 - unicmap_idx;
-        }
-        else
-        {
-          for ( idx = 0; idx < count; idx++, cur++ )
-            if ( cur[0]->encoding == desc->u.encoding )
-              break;
-        }
-
-      Found_idx_for_FTC_CMAP_BY_ENCODING:
-        hash = idx * 67;
-        break;
-
-      case FTC_CMAP_BY_ID:
-        for ( idx = 0; idx < count; idx++, cur++ )
-        {
-          if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform &&
-               (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding )
-          {
-            hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7;
-            break;
-          }
-        }
-        break;
-
-      default:
-        ;
-      }
-
-      if ( idx >= count )
-        goto Bad_Descriptor;
-
-      /* compute hash value, both in family and query */
-      cfam->index               = idx;
-      cfam->hash                = hash ^ FTC_FACE_ID_HASH( desc->face_id );
-      FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
-
-      error = ftc_family_init( FTC_FAMILY( cfam ),
-                               FTC_QUERY( cquery ), cache );
+      return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
     }
-
-    return error;
-
-  Bad_Descriptor:
-    FT_TRACE1(( "ftp_cmap_family_init: invalid charmap descriptor\n" ));
-    return FTC_Err_Invalid_Argument;
+    return 0;
   }
 
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_cmap_family_compare( FTC_CMapFamily  cfam,
-                           FTC_CMapQuery   cquery )
+  ftc_cmap_node_remove_faceid( FTC_CMapNode  node,
+                               FTC_FaceID    face_id )
   {
-    FT_Int  result = 0;
-
-
-    /* first, compare face id and type */
-    if ( cfam->desc.face_id != cquery->desc->face_id ||
-         cfam->desc.type    != cquery->desc->type    )
-      goto Exit;
-
-    switch ( cfam->desc.type )
-    {
-    case FTC_CMAP_BY_INDEX:
-      result = ( cfam->desc.u.index == cquery->desc->u.index );
-      break;
-
-    case FTC_CMAP_BY_ENCODING:
-      result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
-      break;
-
-    case FTC_CMAP_BY_ID:
-      result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
-                 cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
-      break;
-
-    default:
-      ;
-    }
-
-    if ( result )
-    {
-      /* when found, update the 'family' and 'hash' field of the query */
-      FTC_QUERY( cquery )->family = FTC_FAMILY( cfam );
-      FTC_QUERY( cquery )->hash   = FTC_CMAP_HASH( cfam, cquery );
-    }
-
-  Exit:
-    return FT_BOOL( result );
+    return FT_BOOL( node->face_id == face_id );
   }
 
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -334,26 +172,19 @@
 
 
   FT_CALLBACK_TABLE_DEF
-  const FTC_Cache_ClassRec  ftc_cmap_cache_class =
+  const FTC_CacheClassRec  ftc_cmap_cache_class =
   {
-    sizeof ( FTC_CacheRec ),
-    (FTC_Cache_InitFunc) ftc_cache_init,
-    (FTC_Cache_ClearFunc)ftc_cache_clear,
-    (FTC_Cache_DoneFunc) ftc_cache_done,
+    (FTC_Node_NewFunc)      ftc_cmap_node_new,
+    (FTC_Node_WeightFunc)   ftc_cmap_node_weight,
+    (FTC_Node_CompareFunc)  ftc_cmap_node_compare,
+    (FTC_Node_CompareFunc)  ftc_cmap_node_remove_faceid,
+    (FTC_Node_FreeFunc)     ftc_cmap_node_free,
 
-    sizeof ( FTC_CMapFamilyRec ),
-    (FTC_Family_InitFunc)   ftc_cmap_family_init,
-    (FTC_Family_CompareFunc)ftc_cmap_family_compare,
-    (FTC_Family_DoneFunc)   ftc_family_done,
-
-    sizeof ( FTC_CMapNodeRec ),
-    (FTC_Node_InitFunc)   ftc_cmap_node_init,
-    (FTC_Node_WeightFunc) ftc_cmap_node_weight,
-    (FTC_Node_CompareFunc)ftc_cmap_node_compare,
-    (FTC_Node_DoneFunc)   ftc_node_done
+    sizeof ( FTC_CacheRec ),
+    (FTC_Cache_InitFunc) FTC_Cache_Init,
+    (FTC_Cache_DoneFunc) FTC_Cache_Done,
   };
 
-
   /* documentation is in ftccmap.h */
 
   FT_EXPORT_DEF( FT_Error )
@@ -360,101 +191,76 @@
   FTC_CMapCache_New( FTC_Manager     manager,
                      FTC_CMapCache  *acache )
   {
-    return FTC_Manager_Register_Cache(
-             manager,
-             (FTC_Cache_Class)&ftc_cmap_cache_class,
-             FTC_CACHE_P( acache ) );
+    return FTC_Manager_RegisterCache( manager,
+                                      & ftc_cmap_cache_class,
+                                      FTC_CACHE_P( acache ) );
   }
-
-
-#ifdef FTC_CACHE_USE_INLINE
-
-#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
-          ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) )
-
-#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
-          ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) )
-
-#define GEN_CACHE_LOOKUP  ftc_cmap_cache_lookup
-
-#include "ftccache.i"
-
-#else  /* !FTC_CACHE_USE_INLINE */
-
-#define ftc_cmap_cache_lookup  ftc_cache_lookup
-
-#endif /* !FTC_CACHE_USE_INLINE */
-
-
   /* documentation is in ftccmap.h */
 
   FT_EXPORT_DEF( FT_UInt )
-  FTC_CMapCache_Lookup( FTC_CMapCache  cache,
-                        FTC_CMapDesc   desc,
+  FTC_CMapCache_Lookup( FTC_CMapCache  cmap_cache,
+                        FTC_FaceID     face_id,
+                        FT_UInt        cmap_index,
                         FT_UInt32      char_code )
   {
-    FTC_CMapQueryRec  cquery;
+    FTC_Cache         cache = FTC_CACHE( cmap_cache );
+    FTC_CMapQueryRec  query;
     FTC_CMapNode      node;
     FT_Error          error;
     FT_UInt           gindex = 0;
+    FT_UInt32         hash;
 
 
-    if ( !cache || !desc )
+    if ( !cache )
     {
       FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
       return 0;
     }
 
-    cquery.desc      = desc;
-    cquery.char_code = char_code;
+    query.face_id    = face_id;
+    query.cmap_index = cmap_index;
+    query.char_code  = char_code;
 
-    error = ftc_cmap_cache_lookup( FTC_CACHE( cache ),
-                                   FTC_QUERY( &cquery ),
-                                   (FTC_Node*)&node );
-    if ( !error )
-    {
-      FT_UInt  offset = (FT_UInt)( char_code - node->first );
+    hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
 
+    error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node );
+    if ( error )
+      goto Exit;
 
-      FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
+    FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX );
 
-      gindex = node->indices[offset];
-      if ( gindex == FTC_CMAP_UNKNOWN )
-      {
-        FT_Face  face;
+    gindex = node->indices[ char_code - node->first ];
+    if ( gindex == FTC_CMAP_UNKNOWN )
+    {
+      FT_Face     face;
 
+      gindex = 0;
 
-        /* we need to use FT_Get_Char_Index */
-        gindex = 0;
+      error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face );
+      if ( error )
+        goto Exit;
 
-        error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
-                                         desc->face_id,
-                                         &face );
-        if ( !error )
-        {
-          FT_CharMap  old, cmap  = NULL;
-          FT_UInt     cmap_index;
+      if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
+      {
+        FT_CharMap  old, cmap  = NULL;
 
+        old  = face->charmap;
+        cmap = face->charmaps[ cmap_index ];
 
-          /* save old charmap, select new one */
-          old        = face->charmap;
-          cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
-          cmap       = face->charmaps[cmap_index];
-
+        if (old != cmap)
           FT_Set_Charmap( face, cmap );
 
-          /* perform lookup */
-          gindex                = FT_Get_Char_Index( face, char_code );
-          node->indices[offset] = (FT_UInt16)gindex;
+        gindex = FT_Get_Char_Index( face, char_code );
 
-          /* restore old charmap */
+        if (old != cmap)
           FT_Set_Charmap( face, old );
-        }
       }
+
+      node->indices[ char_code - node->first ] = gindex;
     }
 
+  Exit:
     return gindex;
   }
-
 
 /* END */
--- a/src/cache/ftcglyph.c
+++ b/src/cache/ftcglyph.c
@@ -20,7 +20,6 @@
 #include FT_CACHE_H
 #include FT_CACHE_INTERNAL_GLYPH_H
 #include FT_ERRORS_H
-#include FT_LIST_H
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 
@@ -29,45 +28,45 @@
 
   /* create a new chunk node, setting its cache index and ref count */
   FT_EXPORT_DEF( void )
-  ftc_glyph_node_init( FTC_GlyphNode     gnode,
-                       FT_UInt           gindex,
-                       FTC_GlyphFamily   gfam )
+  FTC_GNode_Init( FTC_GNode   gnode,
+                  FT_UInt     gindex,
+                  FTC_Family  family )
   {
-    FT_UInt  len;
-    FT_UInt  start = FTC_GLYPH_FAMILY_START( gfam, gindex );
+    gnode->family = family;
+    gnode->gindex = gindex;
+    family->num_nodes++;
+  }
 
 
-    gnode->item_start = (FT_UShort)start;
+  FT_EXPORT_DEF( void )
+  FTC_GNode_UnselectFamily( FTC_GNode   gnode,
+                            FTC_Cache   cache )
+  {
+    FTC_Family  family = gnode->family;
 
-    len = gfam->item_total - start;
-    if ( len > gfam->item_count )
-      len = gfam->item_count;
-
-    gnode->item_count = (FT_UShort)len;
-    gfam->family.num_nodes++;
+    gnode->family = NULL;
+    if ( family && --family->num_nodes <= 0 )
+      FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family );
   }
 
 
   FT_EXPORT_DEF( void )
-  ftc_glyph_node_done( FTC_GlyphNode  gnode,
-                       FTC_Cache      cache )
+  FTC_GNode_Done( FTC_GNode  gnode,
+                  FTC_Cache  cache )
   {
     /* finalize the node */
-    gnode->item_count = 0;
-    gnode->item_start = 0;
+    gnode->gindex = 0;
 
-    ftc_node_done( FTC_NODE( gnode ), cache );
+    FTC_GNode_UnselectFamily( gnode, cache );
   }
 
 
   FT_EXPORT_DEF( FT_Bool )
-  ftc_glyph_node_compare( FTC_GlyphNode   gnode,
-                          FTC_GlyphQuery  gquery )
+  FTC_GNode_Compare( FTC_GNode   gnode,
+                     FTC_GQuery  gquery )
   {
-    FT_UInt  start = (FT_UInt)gnode->item_start;
-    FT_UInt  count = (FT_UInt)gnode->item_count;
-
-    return FT_BOOL( (FT_UInt)( gquery->gindex - start ) < count );
+    return FT_BOOL(  gnode->family == gquery->family &&
+                     gnode->gindex == gquery->gindex );
   }
 
 
@@ -79,36 +78,72 @@
   /*************************************************************************/
   /*************************************************************************/
 
+  FT_EXPORT_DEF( void )
+  ftc_family_init( FTC_Family  family,
+                   FTC_Cache   cache )
+  {
+    FTC_GCacheClass  clazz = FTC_CACHE__GCACHE_CLASS(cache);
 
+    family->clazz     = clazz->family_class;
+    family->num_nodes = 0;
+  }
+
+
   FT_EXPORT_DEF( FT_Error )
-  ftc_glyph_family_init( FTC_GlyphFamily  gfam,
-                         FT_UInt32        hash,
-                         FT_UInt          item_count,
-                         FT_UInt          item_total,
-                         FTC_GlyphQuery   gquery,
-                         FTC_Cache        cache )
+  FTC_GCache_Init( FTC_GCache  cache )
   {
-    FT_Error  error;
+    FT_Error error;
 
-
-    error = ftc_family_init( FTC_FAMILY( gfam ), FTC_QUERY( gquery ), cache );
+    error = FTC_Cache_Init( FTC_CACHE(cache) );
     if ( !error )
     {
-      gfam->hash       = hash;
-      gfam->item_total = item_total;
-      gfam->item_count = item_count;
-      
-      FTC_GLYPH_FAMILY_FOUND( gfam, gquery );
-    }
+      FTC_GCacheClass   clazz = (FTC_GCacheClass) FTC_CACHE(cache)->org_class;
 
+      FTC_MruList_Init( &cache->families,
+                        clazz->family_class,
+                        0,  /* no maximum here !! */
+                        cache,
+                        FTC_CACHE(cache)->memory );
+    }
     return error;
   }
 
 
   FT_EXPORT_DEF( void )
-  ftc_glyph_family_done( FTC_GlyphFamily  gfam )
+  FTC_GCache_Done( FTC_GCache  cache )
   {
-    ftc_family_done( FTC_FAMILY( gfam ) );
+    FTC_Cache_Done( (FTC_Cache)cache );
+    FTC_MruList_Done( &cache->families );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_GCache_New( FTC_Manager       manager,
+                  FTC_GCacheClass   clazz,
+                  FTC_GCache       *acache )
+  {
+    return FTC_Manager_RegisterCache( manager, (FTC_CacheClass) clazz,
+                                      (FTC_Cache*) acache );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_GCache_Lookup( FTC_GCache   cache,
+                     FT_UInt32    hash,
+                     FT_UInt      gindex,
+                     FTC_GQuery   query,
+                     FTC_Node    *anode )
+  {
+    FT_Error  error;
+
+    query->gindex = gindex;
+
+    error = FTC_MruList_Lookup( &cache->families, query,
+                                (FTC_MruNode*) &query->family );
+    if ( !error )
+      error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, anode );
+
+    return error;
   }
 
 
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -18,65 +18,19 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_IMAGE_H
-#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_CACHE_INTERNAL_IMAGE_H
 #include FT_INTERNAL_MEMORY_H
 
 #include "ftcerror.h"
 
 
-  /* the FT_Glyph image node type */
-  typedef struct  FTC_ImageNodeRec_
-  {
-    FTC_GlyphNodeRec  gnode;
-    FT_Glyph          glyph;
-
-  } FTC_ImageNodeRec, *FTC_ImageNode;
-
-
-#define FTC_IMAGE_NODE( x )         ( (FTC_ImageNode)( x ) )
-#define FTC_IMAGE_NODE_GINDEX( x )  FTC_GLYPH_NODE_GINDEX( x )
-
-
-  /* the glyph image query */
-  typedef struct  FTC_ImageQueryRec_
-  {
-    FTC_GlyphQueryRec  gquery;
-    FTC_ImageTypeRec   type;
-
-  } FTC_ImageQueryRec, *FTC_ImageQuery;
-
-
-#define FTC_IMAGE_QUERY( x )  ( (FTC_ImageQuery)( x ) )
-
-
-  /* the glyph image set type */
-  typedef struct  FTC_ImageFamilyRec_
-  {
-    FTC_GlyphFamilyRec  gfam;
-    FTC_ImageTypeRec    type;
-
-  } FTC_ImageFamilyRec, *FTC_ImageFamily;
-
-
-#define FTC_IMAGE_FAMILY( x )         ( (FTC_ImageFamily)( x ) )
-#define FTC_IMAGE_FAMILY_MEMORY( x )  FTC_GLYPH_FAMILY_MEMORY( &(x)->gfam )
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    GLYPH IMAGE NODES                          *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
   /* finalize a given glyph image node */
-  FT_CALLBACK_DEF( void )
-  ftc_image_node_done( FTC_ImageNode  inode,
-                       FTC_Cache      cache )
+  FT_EXPORT_DEF( void )
+  FTC_INode_Free( FTC_INode  inode,
+                  FTC_Cache  cache )
   {
+    FT_Memory  memory = cache->memory;
+
     if ( inode->glyph )
     {
       FT_Done_Glyph( inode->glyph );
@@ -83,68 +37,41 @@
       inode->glyph = NULL;
     }
 
-    ftc_glyph_node_done( FTC_GLYPH_NODE( inode ), cache );
+    FTC_GNode_Done( FTC_GNODE( inode ), cache );
+    FT_FREE( inode );
   }
 
 
   /* initialize a new glyph image node */
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_image_node_init( FTC_ImageNode   inode,
-                       FTC_GlyphQuery  gquery,
-                       FTC_Cache       cache )
+  FT_EXPORT_DEF( FT_Error )
+  FTC_INode_New( FTC_INode   *pinode,
+                 FTC_GQuery   gquery,
+                 FTC_Cache    cache )
   {
-    FTC_ImageFamily  ifam = FTC_IMAGE_FAMILY( gquery->query.family );
-    FT_Error         error;
-    FT_Face          face;
-    FT_Size          size;
+    FT_Memory  memory = cache->memory;
+    FT_Error   error;
+    FTC_INode  inode;
 
-
-    /* initialize its inner fields */
-    ftc_glyph_node_init( FTC_GLYPH_NODE( inode ),
-                         gquery->gindex,
-                         FTC_GLYPH_FAMILY( ifam ) );
-
-    /* we will now load the glyph image */
-    error = FTC_Manager_Lookup_Size( FTC_FAMILY( ifam )->cache->manager,
-                                     &ifam->type.font,
-                                     &face, &size );
-    if ( !error )
+    if ( !FT_NEW( inode ) )
     {
-      FT_UInt  gindex = FTC_GLYPH_NODE_GINDEX( inode );
+      FTC_GNode         gnode  = FTC_GNODE( inode );
+      FTC_Family        family = gquery->family;
+      FT_UInt           gindex = gquery->gindex;
+      FTC_IFamilyClass  clazz  = FTC_CACHE__IFAMILY_CLASS( cache );
 
+      /* initialize its inner fields */
+      FTC_GNode_Init( gnode, gindex, family );
 
-      error = FT_Load_Glyph( face, gindex, ifam->type.flags );
-      if ( !error )
-      {
-        if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
-             face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
-        {
-          /* ok, copy it */
-          FT_Glyph  glyph;
-
-
-          error = FT_Get_Glyph( face->glyph, &glyph );
-          if ( !error )
-          {
-            inode->glyph = glyph;
-            goto Exit;
-          }
-        }
-        else
-          error = FTC_Err_Invalid_Argument;
-      }
+      /* we will now load the glyph image */
+      error = clazz->family_load_glyph( family, gindex, cache, &inode->glyph );
     }
-
-    /* in case of error */
-    ftc_glyph_node_done( FTC_GLYPH_NODE(inode), cache );
-
-  Exit:
+    *pinode = inode;
     return error;
   }
 
 
-  FT_CALLBACK_DEF( FT_ULong )
-  ftc_image_node_weight( FTC_ImageNode  inode )
+  FT_EXPORT_DEF( FT_ULong )
+  FTC_INode_Weight( FTC_INode  inode )
   {
     FT_ULong  size  = 0;
     FT_Glyph  glyph = inode->glyph;
@@ -182,217 +109,6 @@
 
     size += sizeof ( *inode );
     return size;
-  }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    GLYPH IMAGE SETS                           *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_image_family_init( FTC_ImageFamily  ifam,
-                         FTC_ImageQuery   iquery,
-                         FTC_Cache        cache )
-  {
-    FTC_Manager  manager = cache->manager;
-    FT_Error     error;
-    FT_Face      face;
-
-
-    ifam->type = iquery->type;
-
-    /* we need to compute "iquery.item_total" now */
-    error = FTC_Manager_Lookup_Face( manager,
-                                     iquery->type.font.face_id,
-                                     &face );
-    if ( !error )
-    {
-      error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( ifam ),
-                                     FTC_IMAGE_TYPE_HASH( &ifam->type ),
-                                     1,
-                                     face->num_glyphs,
-                                     FTC_GLYPH_QUERY( iquery ),
-                                     cache );
-    }
-
-    return error;
-  }
-
-
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_image_family_compare( FTC_ImageFamily  ifam,
-                            FTC_ImageQuery   iquery )
-  {
-    FT_Bool  result;
-
-
-    result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &ifam->type, &iquery->type ) );
-    if ( result )
-      FTC_GLYPH_FAMILY_FOUND( ifam, iquery );
-
-    return result;
-  }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    GLYPH IMAGE CACHE                          *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FTC_Cache_ClassRec  ftc_image_cache_class =
-  {
-    sizeof ( FTC_CacheRec ),
-    (FTC_Cache_InitFunc) ftc_cache_init,
-    (FTC_Cache_ClearFunc)ftc_cache_clear,
-    (FTC_Cache_DoneFunc) ftc_cache_done,
-
-    sizeof ( FTC_ImageFamilyRec ),
-    (FTC_Family_InitFunc)   ftc_image_family_init,
-    (FTC_Family_CompareFunc)ftc_image_family_compare,
-    (FTC_Family_DoneFunc)   ftc_glyph_family_done,
-
-    sizeof ( FTC_ImageNodeRec ),
-    (FTC_Node_InitFunc)   ftc_image_node_init,
-    (FTC_Node_WeightFunc) ftc_image_node_weight,
-    (FTC_Node_CompareFunc)ftc_glyph_node_compare,
-    (FTC_Node_DoneFunc)   ftc_image_node_done
-  };
-
-
-  /* documentation is in ftcimage.h */
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_ImageCache_New( FTC_Manager      manager,
-                      FTC_ImageCache  *acache )
-  {
-    return FTC_Manager_Register_Cache(
-             manager,
-             (FTC_Cache_Class)&ftc_image_cache_class,
-             FTC_CACHE_P( acache ) );
-  }
-
-
-  /* documentation is in ftcimage.h */
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_ImageCache_Lookup( FTC_ImageCache  cache,
-                         FTC_ImageType   type,
-                         FT_UInt         gindex,
-                         FT_Glyph       *aglyph,
-                         FTC_Node       *anode )
-  {
-    FTC_ImageQueryRec  iquery;
-    FTC_ImageNode      node;
-    FT_Error           error;
-
-
-    /* some argument checks are delayed to ftc_cache_lookup */
-    if ( !aglyph )
-      return FTC_Err_Invalid_Argument;
-
-    if ( anode )
-      *anode  = NULL;
-
-    iquery.gquery.gindex = gindex;
-    iquery.type          = *type;
-
-    error = ftc_cache_lookup( FTC_CACHE( cache ),
-                              FTC_QUERY( &iquery ),
-                              (FTC_Node*)&node );
-    if ( !error )
-    {
-      *aglyph = node->glyph;
-
-      if ( anode )
-      {
-        *anode = (FTC_Node)node;
-        FTC_NODE( node )->ref_count++;
-      }
-    }
-
-    return error;
-  }
-
-
-  /* backwards-compatibility functions */
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_Image_Cache_New( FTC_Manager       manager,
-                       FTC_Image_Cache  *acache )
-  {
-    return FTC_ImageCache_New( manager, (FTC_ImageCache*)acache );
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_Image_Cache_Lookup( FTC_Image_Cache  icache,
-                          FTC_Image_Desc*  desc,
-                          FT_UInt          gindex,
-                          FT_Glyph        *aglyph )
-  {
-    FTC_ImageTypeRec  type0;
-
-
-    if ( !desc )
-      return FTC_Err_Invalid_Argument;
-
-    type0.font = desc->font;
-
-    /* convert image type flags to load flags */
-    {
-      FT_UInt  load_flags = FT_LOAD_DEFAULT;
-      FT_UInt  type       = desc->image_type;
-
-
-      /* determine load flags, depending on the font description's */
-      /* image type                                                */
-
-      if ( ftc_image_format( type ) == ftc_image_format_bitmap )
-      {
-        if ( type & ftc_image_flag_monochrome )
-          load_flags |= FT_LOAD_MONOCHROME;
-
-        /* disable embedded bitmaps loading if necessary */
-        if ( type & ftc_image_flag_no_sbits )
-          load_flags |= FT_LOAD_NO_BITMAP;
-      }
-      else
-      {
-        /* we want an outline, don't load embedded bitmaps */
-        load_flags |= FT_LOAD_NO_BITMAP;
-
-        if ( type & ftc_image_flag_unscaled )
-          load_flags |= FT_LOAD_NO_SCALE;
-      }
-
-      /* always render glyphs to bitmaps */
-      load_flags |= FT_LOAD_RENDER;
-
-      if ( type & ftc_image_flag_unhinted )
-        load_flags |= FT_LOAD_NO_HINTING;
-
-      if ( type & ftc_image_flag_autohinted )
-        load_flags |= FT_LOAD_FORCE_AUTOHINT;
-
-      type0.flags = load_flags;
-    }
-
-    return FTC_ImageCache_Lookup( (FTC_ImageCache)icache,
-                                   &type0,
-                                   gindex,
-                                   aglyph,
-                                   NULL );
   }
 
 
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -18,8 +18,7 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_MANAGER_H
-#include FT_CACHE_INTERNAL_LRU_H
+#include FT_CACHE_INTERNAL_MANAGER_H
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_SIZES_H
@@ -33,124 +32,135 @@
 #define FTC_LRU_GET_MANAGER( lru )  ( (FTC_Manager)(lru)->user_data )
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    FACE LRU IMPLEMENTATION                    *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
+  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;
 
-  typedef struct FTC_FaceNodeRec_*  FTC_FaceNode;
-  typedef struct FTC_SizeNodeRec_*  FTC_SizeNode;
+    error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
+    if ( error ) goto Exit;
 
+    error = FT_New_Size( face, &size );
+    if ( error ) goto Exit;
 
-  typedef struct  FTC_FaceNodeRec_
-  {
-    FT_LruNodeRec  lru;
-    FT_Face        face;
+    FT_Activate_Size( size );
 
-  } FTC_FaceNodeRec;
+    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_
+
+  typedef struct FTC_SizeNodeRec_
   {
-    FT_LruNodeRec  lru;
-    FT_Size        size;
+    FTC_MruNodeRec    node;
+    FT_Size           size;
+    FTC_ScalerRec     scaler;
 
-  } FTC_SizeNodeRec;
+  } FTC_SizeNodeRec, *FTC_SizeNode;
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_face_node_init( FTC_FaceNode  node,
-                      FTC_FaceID    face_id,
-                      FTC_Manager   manager )
+  FT_CALLBACK_DEF( void )
+  ftc_size_node_done( FTC_SizeNode  node )
   {
-    FT_Error  error;
+    FT_Size  size = node->size;
 
-
-    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;
+    if ( size )
+      FT_Done_Size( size );
   }
 
 
-  /* helper function for ftc_face_node_done() */
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_size_node_select( FTC_SizeNode  node,
-                        FT_Face       face )
+  ftc_size_node_compare( FTC_SizeNode  node,
+                         FTC_Scaler    scaler )
   {
-    return FT_BOOL( node->size->face == face );
+    FTC_Scaler  scaler0 = &node->scaler;
+
+    return FTC_SCALER_COMPARE( scaler0, scaler );
   }
 
 
-  FT_CALLBACK_DEF( void )
-  ftc_face_node_done( FTC_FaceNode  node,
-                      FTC_Manager   manager )
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_size_node_init( FTC_SizeNode   node,
+                      FTC_Scaler     scaler,
+                      FTC_Manager    manager )
   {
-    FT_Face  face    = node->face;
+    node->scaler = scaler[0];
 
+    return ftc_scaler_lookup_size( manager, scaler, &node->size );
+  }
 
-    /* we must begin by removing all sizes for the target face */
-    /* from the manager's list                                 */
-    FT_LruList_Remove_Selection( manager->sizes_list,
-                                 (FT_LruNode_SelectFunc)ftc_size_node_select,
-                                 face );
 
-    /* all right, we can discard the face now */
-    FT_Done_Face( face );
-    node->face = NULL;
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_size_node_reset( FTC_SizeNode       node,
+                       FTC_Scaler         scaler,
+                       FTC_Manager        manager )
+  {
+    FT_Done_Size( node->size );
+
+    node->scaler = scaler[0];
+
+    return ftc_scaler_lookup_size( manager, scaler, &node->size );
   }
 
 
-  FT_CALLBACK_TABLE_DEF
-  const FT_LruList_ClassRec  ftc_face_list_class =
+  static const FTC_MruListClassRec  ftc_size_list_class =
   {
-    sizeof ( FT_LruListRec ),
-    (FT_LruList_InitFunc)0,
-    (FT_LruList_DoneFunc)0,
-
-    sizeof ( FTC_FaceNodeRec ),
-    (FT_LruNode_InitFunc)   ftc_face_node_init,
-    (FT_LruNode_DoneFunc)   ftc_face_node_done,
-    (FT_LruNode_FlushFunc)  0,  /* no flushing needed                      */
-    (FT_LruNode_CompareFunc)0,  /* direct comparison of FTC_FaceID handles */
+    sizeof( FTC_SizeNodeRec ),
+    (FTC_MruNode_CompareFunc)  ftc_size_node_compare,
+    (FTC_MruNode_InitFunc)     ftc_size_node_init,
+    (FTC_MruNode_ResetFunc)    ftc_size_node_reset,
+    (FTC_MruNode_DoneFunc)     ftc_size_node_done
   };
 
 
-  /* documentation is in ftcache.h */
+ /* helper function used by ftc_face_node_done */
+  static FT_Bool
+  ftc_size_node_compare_faceid( FTC_SizeNode  node,
+                                FTC_FaceID    face_id )
+  {
+    return FT_BOOL( node->scaler.face_id == face_id );
+  }
 
+
   FT_EXPORT_DEF( FT_Error )
-  FTC_Manager_Lookup_Face( FTC_Manager  manager,
-                           FTC_FaceID   face_id,
-                           FT_Face     *aface )
+  FTC_Manager_LookupSize( FTC_Manager    manager,
+                          FTC_Scaler     scaler,
+                          FT_Size       *asize )
   {
     FT_Error      error;
-    FTC_FaceNode  node;
+    FTC_SizeNode  node;
 
 
-    if ( aface == NULL )
+    if ( asize == NULL )
       return FTC_Err_Bad_Argument;
 
-    *aface = NULL;
+    *asize = NULL;
 
     if ( !manager )
       return FTC_Err_Invalid_Cache_Handle;
 
-    error = FT_LruList_Lookup( manager->faces_list,
-                               (FT_LruKey)face_id,
-                               (FT_LruNode*)&node );
+    error = FTC_MruList_Lookup( &manager->sizes,
+                                scaler,
+                                (FTC_MruNode*) &node );
     if ( !error )
-      *aface = node->face;
+      *asize = node->size;
 
     return error;
   }
@@ -159,42 +169,39 @@
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
-  /*****                      SIZES LRU IMPLEMENTATION                 *****/
+  /*****                    FACE MRU IMPLEMENTATION                    *****/
   /*****                                                               *****/
   /*************************************************************************/
   /*************************************************************************/
 
-
-  typedef struct  FTC_SizeQueryRec_
+  typedef struct  FTC_FaceNodeRec_
   {
-    FT_Face  face;
-    FT_UInt  width;
-    FT_UInt  height;
+    FTC_MruNodeRec  node;
+    FTC_FaceID      face_id;
+    FT_Face         face;
 
-  } FTC_SizeQueryRec, *FTC_SizeQuery;
+  } FTC_FaceNodeRec, *FTC_FaceNode;
 
 
+
   FT_CALLBACK_DEF( FT_Error )
-  ftc_size_node_init( FTC_SizeNode   node,
-                      FTC_SizeQuery  query )
+  ftc_face_node_init( FTC_FaceNode  node,
+                      FTC_FaceID    face_id,
+                      FTC_Manager   manager )
   {
-    FT_Face   face = query->face;
-    FT_Size   size;
-    FT_Error  error;
+    FT_Error      error;
 
+    node->face_id = face_id;
 
-    node->size = NULL;
-    error = FT_New_Size( face, &size );
+    error = manager->request_face( face_id,
+                                   manager->library,
+                                   manager->request_data,
+                                   &node->face );
     if ( !error )
     {
-      FT_Activate_Size( size );
-      error = FT_Set_Pixel_Sizes( query->face,
-                                  query->width,
-                                  query->height );
-      if ( error )
-        FT_Done_Size( size );
-      else
-        node->size = size;
+      /* destroy initial size object; it will be re-created later */
+      if ( node->face->size )
+        FT_Done_Size( node->face->size );
     }
     return error;
   }
@@ -201,238 +208,79 @@
 
 
   FT_CALLBACK_DEF( void )
-  ftc_size_node_done( FTC_SizeNode  node )
+  ftc_face_node_done( FTC_FaceNode  node,
+                      FTC_Manager   manager )
   {
-    if ( node->size )
-    {
-      FT_Done_Size( node->size );
-      node->size = NULL;
-    }
-  }
+    FT_Memory  memory = manager->memory;
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_size_node_flush( FTC_SizeNode   node,
-                       FTC_SizeQuery  query )
-  {
-    FT_Size   size = node->size;
-    FT_Error  error;
+    /* we must begin by removing all scalers for the target face */
+    /* from the manager's list                                   */
+    FTC_MruList_RemoveSelection(
+          & manager->sizes,
+          (FTC_MruNode_CompareFunc) 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;
 
-    if ( size->face == query->face )
-    {
-      FT_Activate_Size( size );
-      error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
-      if ( error )
-      {
-        FT_Done_Size( size );
-        node->size = NULL;
-      }
-    }
-    else
-    {
-      FT_Done_Size( size );
-      node->size = NULL;
-
-      error = ftc_size_node_init( node, query );
-    }
-    return error;
+    FT_FREE( node );
   }
 
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_size_node_compare( FTC_SizeNode   node,
-                         FTC_SizeQuery  query )
+  ftc_face_node_compare( FTC_FaceNode  node,
+                         FTC_FaceID    face_id )
   {
-    FT_Size  size = node->size;
-
-
-    return FT_BOOL( size->face                    == query->face   &&
-                    (FT_UInt)size->metrics.x_ppem == query->width  &&
-                    (FT_UInt)size->metrics.y_ppem == query->height );
+    return FT_BOOL( node->face_id == face_id );
   }
 
 
-  FT_CALLBACK_TABLE_DEF
-  const FT_LruList_ClassRec  ftc_size_list_class =
+  static const FTC_MruListClassRec  ftc_face_list_class =
   {
-    sizeof ( FT_LruListRec ),
-    (FT_LruList_InitFunc)0,
-    (FT_LruList_DoneFunc)0,
+    sizeof( FTC_FaceNodeRec),
 
-    sizeof ( FTC_SizeNodeRec ),
-    (FT_LruNode_InitFunc)   ftc_size_node_init,
-    (FT_LruNode_DoneFunc)   ftc_size_node_done,
-    (FT_LruNode_FlushFunc)  ftc_size_node_flush,
-    (FT_LruNode_CompareFunc)ftc_size_node_compare
+    (FTC_MruNode_CompareFunc) ftc_face_node_compare,
+    (FTC_MruNode_InitFunc)    ftc_face_node_init,
+    (FTC_MruNode_ResetFunc)   NULL,
+    (FTC_MruNode_DoneFunc)    ftc_face_node_done
   };
 
 
+
   /* documentation is in ftcache.h */
 
   FT_EXPORT_DEF( FT_Error )
-  FTC_Manager_Lookup_Size( FTC_Manager  manager,
-                           FTC_Font     font,
-                           FT_Face     *aface,
-                           FT_Size     *asize )
+  FTC_Manager_LookupFace( FTC_Manager  manager,
+                          FTC_FaceID   face_id,
+                          FT_Face     *aface )
   {
-    FT_Error  error;
+    FT_Error      error;
+    FTC_FaceNode  node;
 
 
-    /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
-    if ( aface )
-      *aface = 0;
+    if ( aface == NULL )
+      return FTC_Err_Bad_Argument;
 
-    if ( asize )
-      *asize = 0;
+    *aface = NULL;
 
-    error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
+    if ( !manager )
+      return FTC_Err_Invalid_Cache_Handle;
+
+    error = FTC_MruList_Lookup( &manager->faces,
+                                face_id,
+                                (FTC_MruNode*) &node );
     if ( !error )
-    {
-      FTC_SizeQueryRec  query;
-      FTC_SizeNode      node;
+      *aface = node->face;
 
-
-      query.face   = *aface;
-      query.width  = font->pix_width;
-      query.height = font->pix_height;
-
-      error = FT_LruList_Lookup( manager->sizes_list,
-                                 (FT_LruKey)&query,
-                                 (FT_LruNode*)&node );
-      if ( !error )
-      {
-        /* select the size as the current one for this face */
-        FT_Activate_Size( node->size );
-
-        if ( asize )
-          *asize = node->size;
-      }
-    }
-
     return error;
   }
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    SET TABLE MANAGEMENT                       *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
 
-  static void
-  ftc_family_table_init( FTC_FamilyTable  table )
-  {
-    table->count   = 0;
-    table->size    = 0;
-    table->entries = NULL;
-    table->free    = FTC_FAMILY_ENTRY_NONE;
-  }
 
-
-  static void
-  ftc_family_table_done( FTC_FamilyTable  table,
-                         FT_Memory        memory )
-  {
-    FT_FREE( table->entries );
-    table->free  = 0;
-    table->count = 0;
-    table->size  = 0;
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )
-  ftc_family_table_alloc( FTC_FamilyTable   table,
-                          FT_Memory         memory,
-                          FTC_FamilyEntry  *aentry )
-  {
-    FTC_FamilyEntry  entry;
-    FT_Error         error = 0;
-
-
-    /* re-allocate table size when needed */
-    if ( table->free == FTC_FAMILY_ENTRY_NONE && table->count >= table->size )
-    {
-      FT_UInt  old_size = table->size;
-      FT_UInt  new_size, idx;
-
-
-      if ( old_size == 0 )
-        new_size = 8;
-      else
-      {
-        new_size = old_size * 2;
-
-        /* check for (unlikely) overflow */
-        if ( new_size < old_size )
-          new_size = 65534;
-      }
-
-      if ( FT_RENEW_ARRAY( table->entries, old_size, new_size ) )
-        return error;
-
-      table->size = new_size;
-
-      entry       = table->entries + old_size;
-      table->free = old_size;
-
-      for ( idx = old_size; idx + 1 < new_size; idx++, entry++ )
-      {
-        entry->link  = idx + 1;
-        entry->index = idx;
-      }
-
-      entry->link  = FTC_FAMILY_ENTRY_NONE;
-      entry->index = idx;
-    }
-
-    if ( table->free != FTC_FAMILY_ENTRY_NONE )
-    {
-      entry       = table->entries + table->free;
-      table->free = entry->link;
-    }
-    else if ( table->count < table->size )
-    {
-      entry = table->entries + table->count++;
-    }
-    else
-    {
-      FT_ERROR(( "ftc_family_table_alloc: internal bug!" ));
-      return FTC_Err_Invalid_Argument;
-    }
-
-    entry->link = FTC_FAMILY_ENTRY_NONE;
-    table->count++;
-
-    *aentry = entry;
-    return error;
-  }
-
-
-  FT_EXPORT_DEF( void )
-  ftc_family_table_free( FTC_FamilyTable  table,
-                         FT_UInt          idx )
-  {
-    /* simply add it to the linked list of free entries */
-    if ( idx < table->count )
-    {
-      FTC_FamilyEntry  entry = table->entries + idx;
-
-
-      if ( entry->link != FTC_FAMILY_ENTRY_NONE )
-        FT_ERROR(( "ftc_family_table_free: internal bug!\n" ));
-      else
-      {
-        entry->link = table->free;
-        table->free = entry->index;
-        table->count--;
-      }
-    }
-  }
-
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -475,41 +323,28 @@
     if ( max_bytes == 0 )
       max_bytes = FTC_MAX_BYTES_DEFAULT;
 
-    error = FT_LruList_New( &ftc_face_list_class,
-                            max_faces,
-                            manager,
-                            memory,
-                            &manager->faces_list );
-    if ( error )
-      goto Exit;
-
-    error = FT_LruList_New( &ftc_size_list_class,
-                            max_sizes,
-                            manager,
-                            memory,
-                            &manager->sizes_list );
-    if ( error )
-      goto Exit;
-
     manager->library      = library;
+    manager->memory       = memory;
     manager->max_weight   = max_bytes;
-    manager->cur_weight   = 0;
 
     manager->request_face = requester;
     manager->request_data = req_data;
 
-    ftc_family_table_init( &manager->families );
+    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:
-    if ( error && manager )
-    {
-      FT_LruList_Destroy( manager->faces_list );
-      FT_LruList_Destroy( manager->sizes_list );
-      FT_FREE( manager );
-    }
-
     return error;
   }
 
@@ -526,31 +361,28 @@
     if ( !manager || !manager->library )
       return;
 
-    memory = manager->library->memory;
+    memory = manager->memory;
 
     /* now discard all caches */
-    for (idx = 0; idx < FTC_MAX_CACHES; idx++ )
+    for (idx = manager->num_caches; idx-- > 0; )
     {
       FTC_Cache  cache = manager->caches[idx];
 
-
       if ( cache )
       {
-        cache->clazz->cache_done( cache );
+        cache->clazz.cache_done( cache );
         FT_FREE( cache );
-        manager->caches[idx] = 0;
+        manager->caches[idx] = NULL;
       }
     }
+    manager->num_caches = 0;
 
-    /* discard families table */
-    ftc_family_table_done( &manager->families, memory );
-
     /* discard faces and sizes */
-    FT_LruList_Destroy( manager->faces_list );
-    manager->faces_list = 0;
+    FTC_MruList_Done( &manager->sizes );
+    FTC_MruList_Done( &manager->faces );
 
-    FT_LruList_Destroy( manager->sizes_list );
-    manager->sizes_list = 0;
+    manager->library = NULL;
+    manager->memory  = NULL;
 
     FT_FREE( manager );
   }
@@ -563,8 +395,8 @@
   {
     if ( manager )
     {
-      FT_LruList_Reset( manager->sizes_list );
-      FT_LruList_Reset( manager->faces_list );
+      FTC_MruList_Reset( &manager->sizes );
+      FTC_MruList_Reset( &manager->faces );
     }
     /* XXX: FIXME: flush the caches? */
   }
@@ -576,8 +408,8 @@
   FTC_Manager_Check( FTC_Manager  manager )
   {
     FTC_Node  node, first;
-    
 
+
     first = manager->nodes_list;
 
     /* check node weights */
@@ -584,23 +416,20 @@
     if ( first )
     {
       FT_ULong  weight = 0;
-      
 
+
       node = first;
 
       do
       {
-        FTC_FamilyEntry  entry = manager->families.entries + node->fam_index;
-        FTC_Cache     cache;
+        FTC_Cache     cache = manager->caches + node->cache_index;
 
-        if ( (FT_UInt)node->fam_index >= manager->families.count ||
-             entry->link              != FTC_FAMILY_ENTRY_NONE  )
-          FT_ERROR(( "FTC_Manager_Check: invalid node (family index = %ld\n",
-                     node->fam_index ));
+        if ( (FT_UInt)node->cache_index >= manager->num_caches )
+          FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
+                     node->cache_index ));
         else
         {
-          cache   = entry->cache;
-          weight += cache->clazz->node_weight( node, cache );
+          weight += cache->clazz.node_weight( node, cache );
         }
 
         node = node->mru_next;
@@ -685,8 +514,8 @@
   /* documentation is in ftcmanag.h */
 
   FT_EXPORT_DEF( FT_Error )
-  FTC_Manager_Register_Cache( FTC_Manager      manager,
-                              FTC_Cache_Class  clazz,
+  FTC_Manager_RegisterCache( FTC_Manager      manager,
+                              FTC_CacheClass   clazz,
                               FTC_Cache       *acache )
   {
     FT_Error   error = FTC_Err_Invalid_Argument;
@@ -695,50 +524,36 @@
 
     if ( manager && clazz && acache )
     {
-      FT_Memory  memory = manager->library->memory;
-      FT_UInt    idx  = 0;
+      FT_Memory  memory = manager->memory;
 
-
-      /* check for an empty cache slot in the manager's table */
-      for ( idx = 0; idx < FTC_MAX_CACHES; idx++ )
+      if ( manager->num_caches >= FTC_MAX_CACHES )
       {
-        if ( manager->caches[idx] == 0 )
-          break;
-      }
-
-      /* return an error if there are too many registered caches */
-      if ( idx >= FTC_MAX_CACHES )
-      {
         error = FTC_Err_Too_Many_Caches;
-        FT_ERROR(( "FTC_Manager_Register_Cache:" ));
-        FT_ERROR(( " too many registered caches\n" ));
+        FT_ERROR(( "%s: too many registered caches\n",
+                   "FTC_Manager_Register_Cache" ));
         goto Exit;
       }
 
       if ( !FT_ALLOC( cache, clazz->cache_size ) )
       {
-        cache->manager = manager;
-        cache->memory  = memory;
-        cache->clazz   = clazz;
+        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->cache_index = idx;
+        cache->index = manager->num_caches;
 
-        if ( clazz->cache_init )
+        error = clazz->cache_init( cache );
+        if ( error )
         {
-          error = clazz->cache_init( cache );
-          if ( error )
-          {
-            if ( clazz->cache_done )
-              clazz->cache_done( cache );
-
-            FT_FREE( cache );
-            goto Exit;
-          }
+          clazz->cache_done( cache );
+          FT_FREE( cache );
+          goto Exit;
         }
 
-        manager->caches[idx] = cache;
+        manager->caches[ manager->num_caches++ ] = cache;
       }
     }
 
@@ -748,6 +563,57 @@
   }
 
 
+  FT_EXPORT_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 = first->mru_prev;
+    for ( result = 0; result < count; )
+    {
+      FTC_Node  prev = node->mru_prev;
+
+
+     /* don't touch locked nodes */
+      if ( node->ref_count <= 0 )
+      {
+        ftc_node_destroy( node, manager );
+        result++;
+      }
+
+      if ( prev == manager->nodes_list )
+        break;
+
+      node = prev;
+    }
+    return  result;
+  }
+
+
+  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, NULL, face_id );
+
+    for ( nn = 0; nn < manager->num_caches; nn++ )
+      FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
+  }
+
+
   /* documentation is in ftcmanag.h */
 
   FT_EXPORT_DEF( void )
@@ -754,11 +620,8 @@
   FTC_Node_Unref( FTC_Node     node,
                   FTC_Manager  manager )
   {
-    if ( node && (FT_UInt)node->fam_index < manager->families.count &&
-         manager->families.entries[node->fam_index].cache )
-    {
+    if ( node && (FT_UInt)node->cache_index < manager->num_caches )
       node->ref_count--;
-    }
   }
 
 
--- /dev/null
+++ b/src/cache/ftcmru.c
@@ -1,0 +1,204 @@
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_MRU_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+  FT_EXPORT_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;
+  }
+
+
+  static void
+  ftc_mrulist_free_nodes( FTC_MruList  list,
+                          FTC_MruNode *plist )
+  {
+    FT_Memory  memory = list->memory;
+
+    while ( *plist )
+    {
+      FTC_MruNode  node = *plist;
+
+      *plist = node->next;
+
+      if ( list->clazz.node_done )
+        list->clazz.node_done( node, list->data );
+
+      FT_FREE( node );
+    }
+  }
+
+
+  FT_EXPORT( void )
+  FTC_MruList_Reset( FTC_MruList  list )
+  {
+    ftc_mrulist_free_nodes( list, &list->nodes );
+    list->num_nodes = 0;
+  }
+
+
+  FT_EXPORT( void )
+  FTC_MruList_Done( FTC_MruList  list )
+  {
+    FTC_MruList_Reset( list );
+  }
+
+
+  FT_EXPORT( FT_Error )
+  FTC_MruList_Lookup( FTC_MruList   list,
+                      FT_Pointer    key,
+                      FTC_MruNode  *anode )
+  {
+    FT_Memory                memory = list->memory;
+    FTC_MruNode_CompareFunc  compare = list->clazz.node_compare;
+    FTC_MruNode              *plast, *pnode, *pfirst;
+    FTC_MruNode              node;
+    FT_Error                 error = 0;
+
+    pfirst = &list->nodes;
+    plast  = pnode = pfirst;
+
+    for (;;)
+    {
+      node = *pnode;
+      if ( node == NULL )
+        goto NewNode;
+      if ( compare( node, key ) )
+        break;
+      plast = pnode;
+      pnode = &node->next;
+    }
+
+    if ( node != *pfirst )
+    {
+      *pnode     = node->next;
+      node->next = *pfirst;
+      *pfirst    = node;
+    }
+    goto Exit;
+
+  NewNode:
+    if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
+    {
+      node = *plast;
+
+      if ( node )
+      {
+        *plast = NULL;
+        list->num_nodes--;
+
+        if ( list->clazz.node_reset )
+        {
+          error = list->clazz.node_reset( node, key, list->data );
+          if ( !error ) goto AddNode;
+        }
+
+        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 )
+    {
+      if ( list->clazz.node_done )
+        list->clazz.node_done( node, list->data );
+
+      FT_FREE( node );
+      goto Exit;
+    }
+
+  AddNode:
+    node->next  = list->nodes;
+    list->nodes = node;
+    list->num_nodes++;
+
+  Exit:
+    *anode = node;
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FTC_MruList_Remove( FTC_MruList   list,
+                      FTC_MruNode   node )
+  {
+    FTC_MruNode  *pnode = &list->nodes;
+
+    for ( ;; )
+    {
+      if ( *pnode == NULL )  /* should not happen !! */
+      {
+        FT_ERROR(( "%s: trying to remove unknown node !!\n",
+                   "FTC_MruList_Remove" ));
+        return;
+      }
+
+      if ( *pnode == node )
+        break;
+
+      pnode = &node->next;
+    }
+
+    *pnode     = node->next;
+    node->next = NULL;
+    list->num_nodes--;
+
+    {
+      FT_Memory  memory = list->memory;
+
+      if ( list->clazz.node_done )
+        list->clazz.node_done( node, list->data );
+
+      FT_FREE( node );
+    }
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FTC_MruList_RemoveSelection( FTC_MruList              list,
+                               FTC_MruNode_CompareFunc  select,
+                               FT_Pointer               key )
+  {
+    FTC_MruNode  *pnode = &list->nodes;
+    FTC_MruNode   node, free = NULL;;
+
+    if ( select )
+    {
+      for (;;)
+      {
+        FTC_MruNode  node = *pnode;
+
+        if ( node == NULL )
+          break;
+
+        if ( select( node, key ) )
+        {
+          *pnode     = node->next;
+          node->next = free;
+          free       = node;
+        }
+        else
+          pnode = &node->next;
+      }
+    }
+
+    ftc_mrulist_free_nodes( list, &free );
+  }
+
+/* END */
+
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -18,8 +18,7 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_SMALL_BITMAPS_H
-#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_CACHE_INTERNAL_SBITS_H
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_ERRORS_H
@@ -27,48 +26,7 @@
 #include "ftcerror.h"
 
 
-#define FTC_SBIT_ITEMS_PER_NODE  16
 
-
-  typedef struct FTC_SBitNodeRec_*  FTC_SBitNode;
-
-  typedef struct  FTC_SBitNodeRec_
-  {
-    FTC_GlyphNodeRec  gnode;
-    FTC_SBitRec       sbits[FTC_SBIT_ITEMS_PER_NODE];
-
-  } FTC_SBitNodeRec;
-
-
-#define FTC_SBIT_NODE( x )  ( (FTC_SBitNode)( x ) )
-
-
-  typedef struct  FTC_SBitQueryRec_
-  {
-    FTC_GlyphQueryRec  gquery;
-    FTC_ImageTypeRec   type;
-
-  } FTC_SBitQueryRec, *FTC_SBitQuery;
-
-
-#define FTC_SBIT_QUERY( x ) ( (FTC_SBitQuery)( x ) )
-
-
-  typedef struct FTC_SBitFamilyRec_*  FTC_SBitFamily;
-
-  /* sbit family structure */
-  typedef struct  FTC_SBitFamilyRec_
-  {
-    FTC_GlyphFamilyRec  gfam;
-    FTC_ImageTypeRec    type;
-
-  } FTC_SBitFamilyRec;
-
-
-#define FTC_SBIT_FAMILY( x )         ( (FTC_SBitFamily)( x ) )
-#define FTC_SBIT_FAMILY_MEMORY( x )  FTC_GLYPH_FAMILY_MEMORY( &( x )->cset )
-
-
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -100,12 +58,12 @@
   }
 
 
-  FT_CALLBACK_DEF( void )
-  ftc_sbit_node_done( FTC_SBitNode  snode,
-                      FTC_Cache     cache )
+  FT_EXPORT_DEF( void )
+  FTC_SNode_Free( FTC_SNode  snode,
+                  FTC_Cache  cache )
   {
     FTC_SBit   sbit   = snode->sbits;
-    FT_UInt    count  = FTC_GLYPH_NODE( snode )->item_count;
+    FT_UInt    count  = snode->count;
     FT_Memory  memory = cache->memory;
 
 
@@ -112,116 +70,105 @@
     for ( ; count > 0; sbit++, count-- )
       FT_FREE( sbit->buffer );
 
-    ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
+    FTC_GNode_Done( FTC_GNODE( snode ), cache );
+
+    FT_FREE( snode );
   }
 
 
   static FT_Error
-  ftc_sbit_node_load( FTC_SBitNode    snode,
-                      FTC_Manager     manager,
-                      FTC_SBitFamily  sfam,
-                      FT_UInt         gindex,
-                      FT_ULong       *asize )
+  ftc_snode_load( FTC_SNode       snode,
+                  FTC_Manager     manager,
+                  FT_UInt         gindex,
+                  FT_ULong       *asize )
   {
-    FT_Error       error;
-    FTC_GlyphNode  gnode = FTC_GLYPH_NODE( snode );
-    FT_Memory      memory;
-    FT_Face        face;
-    FT_Size        size;
-    FTC_SBit       sbit;
+    FT_Error           error;
+    FTC_GNode          gnode  = FTC_GNODE( snode );
+    FTC_Family         family = gnode->family;
+    FT_Memory          memory = manager->memory;
+    FT_Face            face;
+    FTC_SBit           sbit;
+    FTC_SFamilyClass   clazz;
 
 
-    if ( gindex <  (FT_UInt)gnode->item_start                     ||
-         gindex >= (FT_UInt)gnode->item_start + gnode->item_count )
+    if ( (FT_UInt)gindex >= gnode->gindex + snode->count )
     {
-      FT_ERROR(( "ftc_sbit_node_load: invalid glyph index" ));
+      FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
       return FTC_Err_Invalid_Argument;
     }
 
-    memory = manager->library->memory;
+    sbit   = snode->sbits + ( gindex - gnode->gindex );
+    clazz  = (FTC_SFamilyClass) family->clazz;
 
-    sbit = snode->sbits + ( gindex - gnode->item_start );
+    sbit->buffer = 0;
 
-    error = FTC_Manager_Lookup_Size( manager, &sfam->type.font,
-                                     &face, &size );
-    if ( !error )
+    error = clazz->family_load_glyph( family, gindex, manager, &face );
+    if ( error )
+      goto BadGlyph;
+
     {
-      /* by default, indicates a `missing' glyph */
-      sbit->buffer = 0;
+      FT_Int        temp;
+      FT_GlyphSlot  slot   = face->glyph;
+      FT_Bitmap*    bitmap = &slot->bitmap;
+      FT_Int        xadvance, yadvance;
 
-      error = FT_Load_Glyph( face, gindex, sfam->type.flags | FT_LOAD_RENDER );
-      if ( !error )
+      if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
       {
-        FT_Int        temp;
-        FT_GlyphSlot  slot   = face->glyph;
-        FT_Bitmap*    bitmap = &slot->bitmap;
-        FT_Int        xadvance, yadvance;
+        FT_ERROR(( "%s: glyph loaded didn't returned a bitmap !!\n",
+                   "ftc_snode_load" ));
+        goto BadGlyph;
+      }
 
+      /* check that our values fit into 8-bit containers!       */
+      /* If this is not the case, our bitmap is too large       */
+      /* and we will leave it as `missing' with sbit.buffer = 0 */
 
-        /* check that our values fit into 8-bit containers!       */
-        /* If this is not the case, our bitmap is too large       */
-        /* and we will leave it as `missing' with sbit.buffer = 0 */
-
 #define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
 #define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
 
-        /* XXX: FIXME: add support for vertical layouts maybe */
+      /* horizontal advance in pixels */
+      xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
+      yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
 
-        /* horizontal advance in pixels */
-        xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
-        yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
+      if ( !CHECK_BYTE( bitmap->rows  )     ||
+           !CHECK_BYTE( bitmap->width )     ||
+           !CHECK_CHAR( bitmap->pitch )     ||
+           !CHECK_CHAR( slot->bitmap_left ) ||
+           !CHECK_CHAR( slot->bitmap_top  ) ||
+           !CHECK_CHAR( xadvance )          ||
+           !CHECK_CHAR( yadvance )          )
+        goto BadGlyph;
 
-        if ( CHECK_BYTE( bitmap->rows  )     &&
-             CHECK_BYTE( bitmap->width )     &&
-             CHECK_CHAR( bitmap->pitch )     &&
-             CHECK_CHAR( slot->bitmap_left ) &&
-             CHECK_CHAR( slot->bitmap_top  ) &&
-             CHECK_CHAR( xadvance )          &&
-             CHECK_CHAR( yadvance )          )
-        {
-          sbit->width     = (FT_Byte)bitmap->width;
-          sbit->height    = (FT_Byte)bitmap->rows;
-          sbit->pitch     = (FT_Char)bitmap->pitch;
-          sbit->left      = (FT_Char)slot->bitmap_left;
-          sbit->top       = (FT_Char)slot->bitmap_top;
-          sbit->xadvance  = (FT_Char)xadvance;
-          sbit->yadvance  = (FT_Char)yadvance;
-          sbit->format    = (FT_Byte)bitmap->pixel_mode;
-          sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
+      sbit->width     = (FT_Byte)bitmap->width;
+      sbit->height    = (FT_Byte)bitmap->rows;
+      sbit->pitch     = (FT_Char)bitmap->pitch;
+      sbit->left      = (FT_Char)slot->bitmap_left;
+      sbit->top       = (FT_Char)slot->bitmap_top;
+      sbit->xadvance  = (FT_Char)xadvance;
+      sbit->yadvance  = (FT_Char)yadvance;
+      sbit->format    = (FT_Byte)bitmap->pixel_mode;
+      sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
 
-#if 0 /* this doesn't work well with embedded bitmaps */
+      /* copy the bitmap into a new buffer -- ignore error */
+      error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
 
-          /* grab the bitmap when possible - this is a hack! */
-          if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
-          {
-            slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
-            sbit->buffer           = bitmap->buffer;
-          }
-          else
-#endif
-          {
-            /* copy the bitmap into a new buffer -- ignore error */
-            error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
-          }
+      /* now, compute size */
+      if ( asize )
+        *asize = ABS( sbit->pitch ) * sbit->height;
 
-          /* now, compute size */
-          if ( asize )
-            *asize = ABS( sbit->pitch ) * sbit->height;
+    } /* glyph loading successful */
 
-        }  /* glyph dimensions ok */
-
-      } /* glyph loading successful */
-
-      /* ignore the errors that might have occurred --   */
-      /* we mark unloaded glyphs with `sbit.buffer == 0' */
-      /* and 'width == 255', 'height == 0'               */
-      /*                                                 */
-      if ( error && error != FTC_Err_Out_Of_Memory )
-      {
-        sbit->width = 255;
-        error       = 0;
-        /* sbit->buffer == NULL too! */
-      }
+    /* ignore the errors that might have occurred --   */
+    /* we mark unloaded glyphs with `sbit.buffer == 0' */
+    /* and 'width == 255', 'height == 0'               */
+    /*                                                 */
+    if ( error && error != FTC_Err_Out_Of_Memory )
+    {
+    BadGlyph:
+      sbit->width  = 255;
+      sbit->height = 0;
+      sbit->buffer = NULL;
+      error        = 0;
     }
 
     return error;
@@ -228,38 +175,64 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_sbit_node_init( FTC_SBitNode    snode,
-                      FTC_GlyphQuery  gquery,
-                      FTC_Cache       cache )
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SNode_New( FTC_SNode  *psnode,
+                 FTC_GQuery  gquery,
+                 FTC_Cache   cache )
   {
-    FT_Error  error;
+    FT_Memory   memory = cache->memory;
+    FT_Error    error;
+    FTC_SNode   snode  = NULL;
+    FT_UInt     gindex = gquery->gindex;
+    FTC_Family  family = gquery->family;
 
+    FTC_SFamilyClass  clazz = FTC_CACHE__SFAMILY_CLASS( cache );
+    FT_UInt           total;
 
-    ftc_glyph_node_init( FTC_GLYPH_NODE( snode ),
-                         gquery->gindex,
-                         FTC_GLYPH_FAMILY( gquery->query.family ) );
+    total = clazz->family_get_count( family, cache->manager );
+    if ( total == 0 || gindex >= total )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
 
-    error = ftc_sbit_node_load( snode,
-                                cache->manager,
-                                FTC_SBIT_FAMILY( FTC_QUERY( gquery )->family ),
-                                gquery->gindex,
-                                NULL );
-    if ( error )
-      ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
+    if ( !FT_NEW( snode ) )
+    {
+      FT_UInt   count, start;
 
+      start = gindex - (gindex % FTC_SBIT_ITEMS_PER_NODE);
+      count = total - start;
+      if ( count > FTC_SBIT_ITEMS_PER_NODE )
+        count = FTC_SBIT_ITEMS_PER_NODE;
+
+      FTC_GNode_Init( FTC_GNODE( snode ), start, family );
+
+      snode->count = count;
+
+      error = ftc_snode_load( snode,
+                              cache->manager,
+                              gindex,
+                              NULL );
+      if ( error )
+      {
+        FTC_SNode_Free( snode, cache );
+        snode = NULL;
+      }
+    }
+
+  Exit:
+    *psnode = snode;
     return error;
   }
 
 
-  FT_CALLBACK_DEF( FT_ULong )
-  ftc_sbit_node_weight( FTC_SBitNode  snode )
+  FT_EXPORT_DEF( FT_ULong )
+  FTC_SNode_Weight( FTC_SNode  snode )
   {
-    FTC_GlyphNode  gnode = FTC_GLYPH_NODE( snode );
-    FT_UInt        count = gnode->item_count;
-    FTC_SBit       sbit  = snode->sbits;
-    FT_Int         pitch;
-    FT_ULong       size;
+    FT_UInt    count = snode->count;
+    FTC_SBit   sbit  = snode->sbits;
+    FT_Int     pitch;
+    FT_ULong   size;
 
 
     /* the node itself */
@@ -266,7 +239,7 @@
     size = sizeof ( *snode );
 
     /* the sbit records */
-    size += FTC_GLYPH_NODE( snode )->item_count * sizeof ( FTC_SBitRec );
+    size += count * sizeof( FTC_SBitRec );
 
     for ( ; count > 0; count--, sbit++ )
     {
@@ -285,22 +258,20 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_sbit_node_compare( FTC_SBitNode   snode,
-                         FTC_SBitQuery  squery,
-                         FTC_Cache      cache )
+  FT_EXPORT_DEF( FT_Bool )
+  FTC_SNode_Compare( FTC_SNode   snode,
+                     FTC_GQuery  gquery,
+                     FTC_Cache   cache )
   {
-    FTC_GlyphQuery  gquery = FTC_GLYPH_QUERY( squery );
-    FTC_GlyphNode   gnode  = FTC_GLYPH_NODE( snode );
-    FT_Bool         result;
+    FTC_GNode   gnode  = FTC_GNODE( snode );
+    FT_UInt     gindex = gquery->gindex;
+    FT_Bool     result;
 
-
-    result = ftc_glyph_node_compare( gnode, gquery );
+    result = FT_BOOL( (FT_UInt)(gindex - gnode->gindex) < snode->count );
     if ( result )
     {
       /* check if we need to load the glyph bitmap now */
-      FT_UInt   gindex = gquery->gindex;
-      FTC_SBit  sbit   = snode->sbits + ( gindex - gnode->item_start );
+      FTC_SBit  sbit = snode->sbits + ( gindex - gnode->gindex );
 
 
       if ( sbit->buffer == NULL && sbit->width != 255 )
@@ -308,247 +279,15 @@
         FT_ULong  size;
 
 
-        if ( !ftc_sbit_node_load(
-                snode, cache->manager,
-                FTC_SBIT_FAMILY( FTC_QUERY( squery )->family ),
-                gindex, &size ) )
+        if ( !ftc_snode_load( snode, cache->manager,
+                              gindex, &size ) )
+        {
           cache->manager->cur_weight += size;
+        }
       }
     }
 
     return result;
   }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                     SBITS FAMILIES                            *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_sbit_family_init( FTC_SBitFamily  sfam,
-                        FTC_SBitQuery   squery,
-                        FTC_Cache       cache )
-  {
-    FTC_Manager  manager = cache->manager;
-    FT_Error     error;
-    FT_Face      face;
-
-
-    sfam->type = squery->type;
-
-    /* we need to compute "cquery.item_total" now */
-    error = FTC_Manager_Lookup_Face( manager,
-                                     squery->type.font.face_id,
-                                     &face );
-    if ( !error )
-    {
-      error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( sfam ),
-                                     FTC_IMAGE_TYPE_HASH( &sfam->type ),
-                                     FTC_SBIT_ITEMS_PER_NODE,
-                                     face->num_glyphs,
-                                     FTC_GLYPH_QUERY( squery ),
-                                     cache );
-    }
-
-    return error;
-  }
-
-
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_sbit_family_compare( FTC_SBitFamily  sfam,
-                           FTC_SBitQuery   squery )
-  {
-    FT_Bool  result;
-
-
-    /* we need to set the "cquery.cset" field or our query for */
-    /* faster glyph comparisons in ftc_sbit_node_compare       */
-    /*                                                         */
-    result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &sfam->type, &squery->type ) );
-    if ( result )
-      FTC_GLYPH_FAMILY_FOUND( sfam, squery );
-
-    return result;
-  }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                     SBITS CACHE                               *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FTC_Cache_ClassRec  ftc_sbit_cache_class =
-  {
-    sizeof ( FTC_CacheRec ),
-    (FTC_Cache_InitFunc) ftc_cache_init,
-    (FTC_Cache_ClearFunc)ftc_cache_clear,
-    (FTC_Cache_DoneFunc) ftc_cache_done,
-
-    sizeof ( FTC_SBitFamilyRec ),
-    (FTC_Family_InitFunc)   ftc_sbit_family_init,
-    (FTC_Family_CompareFunc)ftc_sbit_family_compare,
-    (FTC_Family_DoneFunc)   ftc_glyph_family_done,
-
-    sizeof ( FTC_SBitNodeRec ),
-    (FTC_Node_InitFunc)   ftc_sbit_node_init,
-    (FTC_Node_WeightFunc) ftc_sbit_node_weight,
-    (FTC_Node_CompareFunc)ftc_sbit_node_compare,
-    (FTC_Node_DoneFunc)   ftc_sbit_node_done
-  };
-
-
-  /* documentation is in ftcsbits.h */
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_SBitCache_New( FTC_Manager     manager,
-                     FTC_SBitCache  *acache )
-  {
-    return FTC_Manager_Register_Cache( manager,
-                                       &ftc_sbit_cache_class,
-                                       (FTC_Cache*)acache );
-  }
-
-
-  /* documentation is in ftcsbits.h */
-
-#ifdef FTC_CACHE_USE_INLINE
-
-#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
-          ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) )
-
-#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
-          ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c )
-
-#define GEN_CACHE_LOOKUP  ftc_sbit_cache_lookup
-#include "ftccache.i"
-
-#else  /* !FTC_CACHE_USE_INLINE */
-
-#define ftc_sbit_cache_lookup  ftc_cache_lookup
-
-#endif /* !FTC_CACHE_USE_INLINE */
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_SBitCache_Lookup( FTC_SBitCache   cache,
-                        FTC_ImageType   type,
-                        FT_UInt         gindex,
-                        FTC_SBit       *ansbit,
-                        FTC_Node       *anode )
-  {
-    FT_Error          error;
-    FTC_SBitQueryRec  squery;
-    FTC_SBitNode      node;
-
-
-    /* other argument checks delayed to ftc_cache_lookup */
-    if ( !ansbit )
-      return FTC_Err_Invalid_Argument;
-
-    *ansbit = NULL;
-
-    if ( anode )
-      *anode = NULL;
-
-    squery.gquery.gindex = gindex;
-    squery.type          = *type;
-
-    error = ftc_sbit_cache_lookup( FTC_CACHE( cache ),
-                                   FTC_QUERY( &squery ),
-                                   (FTC_Node*)&node );
-    if ( !error )
-    {
-      *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start );
-
-      if ( anode )
-      {
-        *anode = FTC_NODE( node );
-        FTC_NODE( node )->ref_count++;
-      }
-    }
-    return error;
-  }
-
-
-  /* backwards-compatibility functions */
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_SBit_Cache_New( FTC_Manager      manager,
-                      FTC_SBit_Cache  *acache )
-  {
-    return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache );
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_SBit_Cache_Lookup( FTC_SBit_Cache   cache,
-                         FTC_Image_Desc*  desc,
-                         FT_UInt          gindex,
-                         FTC_SBit        *ansbit )
-  {
-    FTC_ImageTypeRec  type0;
-
-
-    if ( !desc )
-      return FTC_Err_Invalid_Argument;
-
-    type0.font  = desc->font;
-    type0.flags = 0;
-
-    /* convert image type flags to load flags */
-    {
-      FT_UInt  load_flags = FT_LOAD_DEFAULT;
-      FT_UInt  type       = desc->image_type;
-
-
-      /* determine load flags, depending on the font description's */
-      /* image type                                                */
-
-      if ( ftc_image_format( type ) == ftc_image_format_bitmap )
-      {
-        if ( type & ftc_image_flag_monochrome )
-          load_flags |= FT_LOAD_MONOCHROME;
-
-        /* disable embedded bitmaps loading if necessary */
-        if ( type & ftc_image_flag_no_sbits )
-          load_flags |= FT_LOAD_NO_BITMAP;
-      }
-      else
-      {
-        /* we want an outline, don't load embedded bitmaps */
-        load_flags |= FT_LOAD_NO_BITMAP;
-
-        if ( type & ftc_image_flag_unscaled )
-          load_flags |= FT_LOAD_NO_SCALE;
-      }
-
-      /* always render glyphs to bitmaps */
-      load_flags |= FT_LOAD_RENDER;
-
-      if ( type & ftc_image_flag_unhinted )
-        load_flags |= FT_LOAD_NO_HINTING;
-
-      if ( type & ftc_image_flag_autohinted )
-        load_flags |= FT_LOAD_FORCE_AUTOHINT;
-
-      type0.flags = load_flags;
-    }
-
-    return FTC_SBitCache_Lookup( (FTC_SBitCache)cache,
-                                  &type0,
-                                  gindex,
-                                  ansbit,
-                                  NULL );
-  }
-
 
 /* END */
--- a/src/cache/ftlru.c
+++ /dev/null
@@ -1,390 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  ftlru.c                                                                */
-/*                                                                         */
-/*    Simple LRU list-cache (body).                                        */
-/*                                                                         */
-/*  Copyright 2000-2001, 2002, 2003 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 FT_CACHE_INTERNAL_LRU_H
-#include FT_LIST_H
-#include FT_INTERNAL_OBJECTS_H
-#include FT_INTERNAL_DEBUG_H
-
-#include "ftcerror.h"
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FT_LruList_New( FT_LruList_Class  clazz,
-                  FT_UInt           max_nodes,
-                  FT_Pointer        user_data,
-                  FT_Memory         memory,
-                  FT_LruList       *alist )
-  {
-    FT_Error    error;
-    FT_LruList  list;
-
-
-    if ( !alist || !clazz )
-      return FTC_Err_Invalid_Argument;
-
-    *alist = NULL;
-    if ( !FT_ALLOC( list, clazz->list_size ) )
-    {
-      /* initialize common fields */
-      list->clazz      = clazz;
-      list->memory     = memory;
-      list->max_nodes  = max_nodes;
-      list->data       = user_data;
-
-      if ( clazz->list_init )
-      {
-        error = clazz->list_init( list );
-        if ( error )
-        {
-          if ( clazz->list_done )
-            clazz->list_done( list );
-
-          FT_FREE( list );
-        }
-      }
-
-      *alist = list;
-    }
-
-    return error;
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FT_LruList_Destroy( FT_LruList  list )
-  {
-    FT_Memory         memory;
-    FT_LruList_Class  clazz;
-
-
-    if ( !list )
-      return;
-
-    memory = list->memory;
-    clazz  = list->clazz;
-
-    FT_LruList_Reset( list );
-
-    if ( clazz->list_done )
-      clazz->list_done( list );
-
-    FT_FREE( list );
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FT_LruList_Reset( FT_LruList  list )
-  {
-    FT_LruNode        node;
-    FT_LruList_Class  clazz;
-    FT_Memory         memory;
-
-
-    if ( !list )
-      return;
-
-    node   = list->nodes;
-    clazz  = list->clazz;
-    memory = list->memory;
-
-    while ( node )
-    {
-      FT_LruNode  next = node->next;
-
-
-      if ( clazz->node_done )
-        clazz->node_done( node, list->data );
-
-      FT_FREE( node );
-      node = next;
-    }
-
-    list->nodes     = NULL;
-    list->num_nodes = 0;
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FT_LruList_Lookup( FT_LruList   list,
-                     FT_LruKey    key,
-                     FT_LruNode  *anode )
-  {
-    FT_Error          error = 0;
-    FT_LruNode        node, *pnode;
-    FT_LruList_Class  clazz;
-    FT_LruNode        result = NULL;
-    FT_Memory         memory;
-
-
-    if ( !list || !key || !anode )
-      return FTC_Err_Invalid_Argument;
-
-    pnode  = &list->nodes;
-    node   = NULL;
-    clazz  = list->clazz;
-    memory = list->memory;
-
-    if ( clazz->node_compare )
-    {
-      for (;;)
-      {
-        node = *pnode;
-        if ( node == NULL )
-          break;
-
-        if ( clazz->node_compare( node, key, list->data ) )
-          break;
-
-        pnode = &(*pnode)->next;
-      }
-    }
-    else
-    {
-      for (;;)
-      {
-        node = *pnode;
-        if ( node == NULL )
-          break;
-
-        if ( node->key == key )
-          break;
-
-        pnode = &(*pnode)->next;
-      }
-    }
-
-    if ( node )
-    {
-      /* move element to top of list */
-      if ( list->nodes != node )
-      {
-        *pnode      = node->next;
-        node->next  = list->nodes;
-        list->nodes = node;
-      }
-      result = node;
-      goto Exit;
-    }
-
-   /* Since we haven't found the relevant element in our LRU list,
-    * we're going to "create" a new one.
-    *
-    * The following code is a bit special, because it tries to handle
-    * out-of-memory conditions (OOM) in an intelligent way.
-    *
-    * More precisely, if not enough memory is available to create a
-    * new node or "flush" an old one, we need to remove the oldest
-    * elements from our list, and try again.  Since several tries may
-    * be necessary, a loop is needed.
-    *
-    * This loop will only exit when:
-    *
-    *   - a new node was successfully created, or an old node flushed
-    *   - an error other than FTC_Err_Out_Of_Memory is detected
-    *   - the list of nodes is empty, and it isn't possible to create
-    *     new nodes
-    *
-    * On each unsuccessful attempt, one node will be removed from the list.
-    *
-    */
-    
-    {
-      FT_Int  drop_last = ( list->max_nodes > 0 && 
-                            list->num_nodes >= list->max_nodes );
-
-      for (;;)
-      {
-        node = NULL;
-
-        /* If "drop_last" is true, we should free the last node in
-         * the list to make room for a new one.  Note that we reuse
-         * its memory block to save allocation calls.
-         */
-        if ( drop_last )
-        {
-         /* find the last node in the list
-          */
-          pnode = &list->nodes;
-          node  = *pnode;
-  
-          if ( node == NULL )
-          {
-            FT_ASSERT( list->num_nodes == 0 );
-            error = FTC_Err_Out_Of_Memory;
-            goto Exit;
-          }
-
-          FT_ASSERT( list->num_nodes > 0 );
-
-          while ( node->next )
-          {
-            pnode = &node->next;
-            node  = *pnode;
-          }
-  
-          /* Remove it from the list, and try to "flush" it.  Doing this will
-           * save a significant number of dynamic allocations compared to
-           * a classic destroy/create cycle.
-           */
-          *pnode = NULL;
-          list->num_nodes--;
-  
-          if ( clazz->node_flush )
-          {
-            error = clazz->node_flush( node, key, list->data );
-            if ( !error )
-              goto Success;
-
-           /* Note that if an error occured during the flush, we need to
-            * finalize it since it is potentially in incomplete state.
-            */
-          }
-
-          /* We finalize, but do not destroy the last node, we
-           * simply reuse its memory block!
-           */
-          if ( clazz->node_done )
-            clazz->node_done( node, list->data );
-            
-          FT_MEM_ZERO( node, clazz->node_size );
-        }
-        else
-        {
-         /* Try to allocate a new node when "drop_last" is not TRUE.
-          * This usually happens on the first pass, when the LRU list
-          * is not already full.
-          */
-          if ( FT_ALLOC( node, clazz->node_size ) )
-            goto Fail;
-        }
-  
-        FT_ASSERT( node != NULL );
-
-        node->key = key;
-        error = clazz->node_init( node, key, list->data );
-        if ( error )
-        {
-          if ( clazz->node_done )
-            clazz->node_done( node, list->data );
-
-          FT_FREE( node );
-          goto Fail;
-        }
-
-      Success:
-        result = node;
-
-        node->next  = list->nodes;
-        list->nodes = node;
-        list->num_nodes++;
-        goto Exit;
-  
-      Fail:
-        if ( error != FTC_Err_Out_Of_Memory )
-          goto Exit;
-        
-        drop_last = 1;
-        continue;
-      }
-    }
-
-  Exit:
-    *anode = result;
-    return error;
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FT_LruList_Remove( FT_LruList  list,
-                     FT_LruNode  node )
-  {
-    FT_LruNode  *pnode;
-
-
-    if ( !list || !node )
-      return;
-
-    pnode = &list->nodes;
-    for (;;)
-    {
-      if ( *pnode == node )
-      {
-        FT_Memory         memory = list->memory;
-        FT_LruList_Class  clazz  = list->clazz;
-
-
-        *pnode     = node->next;
-        node->next = NULL;
-
-        if ( clazz->node_done )
-          clazz->node_done( node, list->data );
-
-        FT_FREE( node );
-        list->num_nodes--;
-        break;
-      }
-
-      pnode = &(*pnode)->next;
-    }
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FT_LruList_Remove_Selection( FT_LruList             list,
-                               FT_LruNode_SelectFunc  select_func,
-                               FT_Pointer             select_data )
-  {
-    FT_LruNode       *pnode, node;
-    FT_LruList_Class  clazz;
-    FT_Memory         memory;
-
-
-    if ( !list || !select_func )
-      return;
-
-    memory = list->memory;
-    clazz  = list->clazz;
-    pnode  = &list->nodes;
-
-    for (;;)
-    {
-      node = *pnode;
-      if ( node == NULL )
-        break;
-
-      if ( select_func( node, select_data, list->data ) )
-      {
-        *pnode     = node->next;
-        node->next = NULL;
-
-        if ( clazz->node_done )
-          clazz->node_done( node, list );
-
-        FT_FREE( node );
-        list->num_nodes--;
-      }
-      else
-        pnode = &(*pnode)->next;
-    }
-  }
-
-
-/* END */
--- a/src/cache/rules.mk
+++ b/src/cache/rules.mk
@@ -25,8 +25,9 @@
 
 # Cache driver sources (i.e., C files)
 #
-CACHE_DRV_SRC := $(CACHE_DIR)/ftlru.c    \
+CACHE_DRV_SRC := $(CACHE_DIR)/ftcmru.c   \
                  $(CACHE_DIR)/ftcmanag.c \
+                 $(CACHE_DIR)/ftcbasic.c \
                  $(CACHE_DIR)/ftccache.c \
                  $(CACHE_DIR)/ftcglyph.c \
                  $(CACHE_DIR)/ftcsbits.c \
@@ -35,10 +36,11 @@
 
 # Cache driver headers
 #
-CACHE_DRV_H := $(CACHE_H_DIR)/ftlru.h    \
+CACHE_DRV_H := $(CACHE_H_DIR)/ftcmru.h   \
                $(CACHE_H_DIR)/ftcmanag.h \
                $(CACHE_H_DIR)/ftcglyph.h \
                $(CACHE_H_DIR)/ftcimage.h \
+               $(CACHE_H_DIR)/ftccmap.h  \
                $(CACHE_DIR)/ftcerror.h