* massive redesign of the cache sub-system internals.
        in order to simplify the code and even slightly improve
        performance (ftbench shows a 3% improvements in the SBit
        and Image caches)
diff --git a/ChangeLog b/ChangeLog
index 95d619a..6fdcc8f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2005-09-21  David Turner  <david@freetype.org>
+
+        * massive redesign of the cache sub-system internals.
+        in order to simplify the code and even slightly improve
+        performance (ftbench shows a 3% improvements in the SBit
+        and Image caches)
+
 2005-09-19  David Somers  <dsomers@omz13.com>
 
 	* freetype2/src/sfnt/ttload.c (sfnt_dir_check): Modified to allow a
diff --git a/include/freetype/cache/ftccache.h b/include/freetype/cache/ftccache.h
index f2e1028..2e1c216 100644
--- a/include/freetype/cache/ftccache.h
+++ b/include/freetype/cache/ftccache.h
@@ -66,6 +66,8 @@
 #define FTC_NODE( x )    ( (FTC_Node)(x) )
 #define FTC_NODE_P( x )  ( (FTC_Node*)(x) )
 
+#define FTC_NODE_REF(n)   ( FTC_NODE(n)->ref_count += 1, (n) )
+
 #define FTC_NODE__NEXT(x)  FTC_NODE( (x)->mru.next )
 #define FTC_NODE__PREV(x)  FTC_NODE( (x)->mru.prev )
 
@@ -103,9 +105,9 @@
 
   /* compare a node to a given key pair */
   typedef FT_Bool
-  (*FTC_Node_CompareFunc)( FTC_Node    node,
-                           FT_Pointer  key,
-                           FTC_Cache   cache );
+  (*FTC_Node_EqualFunc)( FTC_Node    node,
+                         FT_Pointer  key,
+                         FTC_Cache   cache );
 
 
   typedef void
@@ -123,8 +125,8 @@
   {
     FTC_Node_NewFunc      node_new;
     FTC_Node_WeightFunc   node_weight;
-    FTC_Node_CompareFunc  node_compare;
-    FTC_Node_CompareFunc  node_remove_faceid;
+    FTC_Node_EqualFunc    node_equal;
+    FTC_Node_EqualFunc    node_remove_faceid;
     FTC_Node_FreeFunc     node_free;
 
     FT_UInt               cache_size;
@@ -134,21 +136,36 @@
   } FTC_CacheClassRec;
 
 
+#define  FTC_DEFINE_CACHE_CLASS(_n_new,_n_weight,_n_equal,_n_equal_faceid,_n_free,_c_type,_c_init,_c_done ) \
+  {                                           \
+    (FTC_Node_NewFunc)    (_n_new),           \
+    (FTC_Node_WeightFunc) (_n_weight),        \
+    (FTC_Node_EqualFunc)  (_n_equal),         \
+    (FTC_Node_EqualFunc)  (_n_equal_faceid),  \
+    (FTC_Node_FreeFunc)   (_n_free),          \
+                                              \
+    sizeof( _c_type ),                        \
+    (FTC_Cache_InitFunc) (_c_init),           \
+    (FTC_Cache_DoneFunc) (_c_done)            \
+  }
+
+
   /* each cache really implements a dynamic hash table to manage its nodes */
   typedef struct  FTC_CacheRec_
   {
-    FT_UFast           p;
-    FT_UFast           mask;
-    FT_Long            slack;
-    FTC_Node*          buckets;
+    FT_UFast            p;
+    FT_UFast            mask;
+    FT_Long             slack;
+    FTC_Node*           buckets;
 
-    FTC_CacheClassRec  clazz;       /* local copy, for speed  */
+    FTC_Node_EqualFunc  node_equal;  /* local copy of clazz->node_equal */
+    FTC_Node_WeightFunc node_weight; /* local copy of clazz->node_weight */
 
-    FTC_Manager        manager;
-    FT_Memory          memory;
-    FT_UInt            index;       /* in manager's table     */
+    FTC_Manager         manager;
+    FT_Memory           memory;
+    FT_UInt             index;       /* in manager's table     */
 
-    FTC_CacheClass     org_class;   /* original class pointer */
+    FTC_CacheClass      clazz;       /* class pointer */
 
   } FTC_CacheRec;
 
@@ -156,6 +173,9 @@
 #define FTC_CACHE( x )    ( (FTC_Cache)(x) )
 #define FTC_CACHE_P( x )  ( (FTC_Cache*)(x) )
 
+#define FTC_CACHE__CLASS(c)    (FTC_CACHE(c)->clazz)
+#define FTC_CACHE__MEMORY(c)   (FTC_CACHE(c)->memory)
+#define FTC_CACHE__MANAGER(c)  (FTC_CACHE(c)->manager)
 
   /* default cache initialize */
   FT_EXPORT( FT_Error )
@@ -201,11 +221,10 @@
 
 #define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \
   FT_BEGIN_STMNT                                                         \
-    FTC_Node             *_bucket, *_pnode, _node;                       \
-    FTC_Cache             _cache   = FTC_CACHE(cache);                   \
-    FT_UInt32             _hash    = (FT_UInt32)(hash);                  \
-    FTC_Node_CompareFunc  _nodcomp = (FTC_Node_CompareFunc)(nodecmp);    \
-    FT_UInt               _idx;                                          \
+    FTC_Node           *_bucket, *_pnode, _node;                         \
+    FTC_Cache           _cache   = FTC_CACHE(cache);                     \
+    FT_UInt32           _hash    = (FT_UInt32)(hash);                    \
+    FT_UInt             _idx;                                            \
                                                                          \
                                                                          \
     error = 0;                                                           \
@@ -221,7 +240,7 @@
       if ( _node == NULL )                                               \
         goto _NewNode;                                                   \
                                                                          \
-      if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) )    \
+      if ( _node->hash == _hash && nodecmp( _node, query, _cache ) )     \
         break;                                                           \
                                                                          \
       _pnode = &_node->link;                                             \
@@ -248,7 +267,7 @@
     error = FTC_Cache_NewNode( _cache, _hash, query, &_node );           \
                                                                          \
   _Ok:                                                                   \
-    _pnode = (FTC_Node*)(void*)&(node);                                  \
+    _pnode  = (FTC_Node*)(void*)&(node);                                 \
     *_pnode = _node;                                                     \
   FT_END_STMNT
 
@@ -269,7 +288,7 @@
    *
    * It is used when creating a new cache node, or within a lookup
    * that needs to allocate data (e.g., the sbit cache lookup).
-   * 
+   *
    * Example:
    *
    *   {
diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h
index 3f8301a..ecb357a 100644
--- a/include/freetype/cache/ftcglyph.h
+++ b/include/freetype/cache/ftcglyph.h
@@ -58,7 +58,7 @@
    *  - FTC_GNode sub-class, e.g. MyNode, with relevant methods:
    *        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_equal          (must call FTC_GNode_Compare)
    *        my_node_remove_faceid  (must call ftc_gnode_unselect in case
    *                                of match)
    *
@@ -68,9 +68,6 @@
    *        my_family_reset (optional)
    *        my_family_done
    *
-   *  - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query
-   *    data.
-   *
    *  - Constant structures for a FTC_GNodeClass.
    *
    *  - MyCacheNew() can be implemented easily as a call to the convenience
@@ -116,7 +113,6 @@
 #ifndef __FTCGLYPH_H__
 #define __FTCGLYPH_H__
 
-
 #include <ft2build.h>
 #include FT_CACHE_INTERNAL_MANAGER_H
 
@@ -124,6 +120,9 @@
 FT_BEGIN_HEADER
 
 
+  typedef struct FTC_GCacheRec_*   FTC_GCache;
+
+
  /*
   *  We can group glyphs into `families'.  Each family correspond to a
   *  given face ID, character size, transform, etc.
@@ -132,18 +131,72 @@
   *  reference-counted.
   */
 
+  typedef const struct FTC_FamilyClassRec_*   FTC_FamilyClass;
+
   typedef struct  FTC_FamilyRec_
   {
-    FTC_MruNodeRec    mrunode;
-    FT_UInt           num_nodes; /* current number of nodes in this family */
-    FTC_Cache         cache;
-    FTC_MruListClass  clazz;
+    FTC_Family       link;      /* used for hashing too                   */
+    FT_UInt32        hash;      /* hash value for this family             */
+    FT_Int           num_nodes; /* current number of nodes in this family */
+    FTC_GCache       cache;     /* cache the family belongs to            */
 
-  } FTC_FamilyRec, *FTC_Family;
+  } FTC_FamilyRec;
 
 #define  FTC_FAMILY(x)    ( (FTC_Family)(x) )
 #define  FTC_FAMILY_P(x)  ( (FTC_Family*)(x) )
 
+#define  FTC_FAMILY__CACHE(f)  (FTC_FAMILY(f)->cache)
+#define  FTC_FAMILY__CLASS(f)  FTC_GCACHE__FAMILY_CLASS(FTC_FAMILY__CACHE(f))
+
+ /* note that the content of 'key' has already been copied to 'family'
+  * when this method is called. This callback is only necessary when you
+  * need to perform non-trivial initialization (e.g. duplicating
+  * heap-allocated memory, like strings, owned by the family)
+  *
+  * if this method returns an error, the corresponding FTC_Family_DoneFunc,
+  * will be called, if is not defined to NULL
+  */
+  typedef FT_Error  (*FTC_Family_InitFunc)( FTC_Family  family,
+                                            FTC_Family  key );
+
+ /* finalize the content of a given family object
+  */
+  typedef void      (*FTC_Family_DoneFunc)( FTC_Family  family );
+
+ /* test wether a family matches a given key. Note that this method
+  * is only called when (family.hash == key.hash), so there is no
+  * need to test it again
+  */
+  typedef FT_Bool   (*FTC_Family_EqualFunc)( FTC_Family  family,
+                                             FTC_Family  key );
+
+ /* test wether a family matches a given FTC_FaceID
+  */
+  typedef FT_Bool   (*FTC_Family_EqualFaceIDFunc)( FTC_Family  family,
+                                                   FTC_FaceID  face_id );
+
+  typedef struct FTC_FamilyClassRec_
+  {
+    FT_UInt                     fam_size;
+    FTC_Family_InitFunc         fam_init;
+    FTC_Family_DoneFunc         fam_done;
+    FTC_Family_EqualFunc        fam_equal;
+    FTC_Family_EqualFaceIDFunc  fam_equal_faceid;
+
+  } FTC_FamilyClassRec;
+
+
+#define  FTC_FAMILY_CLASS(x)  ((FTC_FamilyClass)(x))
+
+#define  FTC_DEFINE_FAMILY_CLASS(_type,_init,_done,_equal,_equal_faceid) \
+  {                                              \
+    sizeof(_type),                               \
+    (FTC_Family_InitFunc)       (_init),         \
+    (FTC_Family_DoneFunc)       (_done),         \
+    (FTC_Family_EqualFunc)      (_equal),        \
+    (FTC_Family_EqualFaceIDFunc)(_equal_faceid)  \
+  }
+
 
   typedef struct  FTC_GNodeRec_
   {
@@ -156,17 +209,6 @@
 #define FTC_GNODE( x )    ( (FTC_GNode)(x) )
 #define FTC_GNODE_P( x )  ( (FTC_GNode*)(x) )
 
-
-  typedef struct  FTC_GQueryRec_
-  {
-    FT_UInt      gindex;
-    FTC_Family   family;
-
-  } FTC_GQueryRec, *FTC_GQuery;
-
-#define FTC_GQUERY( x )  ( (FTC_GQuery)(x) )
-
-
   /*************************************************************************/
   /*                                                                       */
   /* These functions are exported so that they can be called from          */
@@ -180,35 +222,46 @@
                   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                                             */
+  /* this macro can be used to test wether a glyph node matches a given
+   * glyph query
+   */
+#define  FTC_GNODE_EQUAL(node,key,cache)                             \
+             ( FTC_GNODE(node)->family == FTC_GNODE(key)->family &&  \
+               FTC_GNODE(node)->gindex == FTC_GNODE(key)->gindex )
+
+
+  /* same as FTC_GNODE_EQUAL, but can be used as a callback */
   FT_EXPORT( FT_Bool )
-  FTC_GNode_Compare( FTC_GNode   gnode,
-                     FTC_GQuery  gquery );
+  FTC_GNode_Equal( FTC_GNode   gnode,
+                   FTC_GNode   gquery,
+                   FTC_GCache  cache );
 
   /* 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 );
+  FT_EXPORT( FT_Bool )
+  FTC_GNode_EqualFaceID( FTC_GNode   gnode,
+                         FTC_FaceID  face_id,
+                         FTC_GCache  cache );
 
   /* must be called by derived FTC_Node_DoneFunc routines */
   FT_EXPORT( void )
-  FTC_GNode_Done( FTC_GNode  node,
-                  FTC_Cache  cache );
+  FTC_GNode_Done( FTC_GNode   node );
 
 
   FT_EXPORT( void )
   FTC_Family_Init( FTC_Family  family,
-                   FTC_Cache   cache );
+                   FT_UInt32   hash,
+                   FTC_GCache  cache );
+
 
   typedef struct FTC_GCacheRec_
   {
-    FTC_CacheRec    cache;
-    FTC_MruListRec  families;
+    FTC_CacheRec                cache;
+    FTC_Family_EqualFunc        fam_equal;
+    FTC_Family_EqualFaceIDFunc  fam_equal_faceid;
+    FTC_Family                  families;
 
-  } FTC_GCacheRec, *FTC_GCache;
+  } FTC_GCacheRec;
 
 #define FTC_GCACHE( x )  ((FTC_GCache)(x))
 
@@ -226,80 +279,112 @@
   /* the glyph cache class adds fields for the family implementation */
   typedef struct  FTC_GCacheClassRec_
   {
-    FTC_CacheClassRec  clazz;
-    FTC_MruListClass   family_class;
+    FTC_CacheClassRec   clazz;
+    FTC_FamilyClassRec  family_class;
 
   } FTC_GCacheClassRec;
 
   typedef const FTC_GCacheClassRec*   FTC_GCacheClass;
 
+
+#define  FTC_DEFINE_GCACHE_CLASS(_cache_class,_family_class)  \
+  {                                                           \
+    _cache_class,                                             \
+    _family_class                                             \
+  }
+
+
 #define FTC_GCACHE_CLASS( x )  ((FTC_GCacheClass)(x))
 
-#define FTC_CACHE__GCACHE_CLASS( x ) \
-          FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class )
-#define FTC_CACHE__FAMILY_CLASS( x ) \
-          ( (FTC_MruListClass)FTC_CACHE__GCACHE_CLASS( x )->family_class )
+#define FTC_GCACHE__CLASS( x ) \
+          FTC_GCACHE_CLASS( FTC_CACHE__CLASS(x) )
+
+#define FTC_GCACHE__FAMILY_CLASS(c) \
+          (&FTC_GCACHE__CLASS(c)->family_class)
 
 
-  /* convenience function; use it 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 );
 
+  /* used by FTC_GCACHE_GET_FAMILY, don't call directly */
+  FT_EXPORT( FT_Error )
+  FTC_GCache_NewFamily( FTC_GCache   cache,
+                        FT_UInt32    hash,
+                        FTC_Family   query,
+                        FTC_Family  *afamily );
+
+  FT_EXPORT( void )
+  FTC_GCache_FreeFamily( FTC_GCache  cache,
+                         FTC_Family  family );
+
+#define  FTC_FAMILY_FREE(f)  FTC_GCache_FreeFamily( (f)->cache, (f) )
+
+  /* query.hash must be set correctly !! */
+  FT_EXPORT( FT_Error )
+  FTC_GCache_GetFamily( FTC_GCache   cache,
+                        FT_UInt32    hash,
+                        FTC_Family   query,
+                        FTC_Family  *afamily );
+
+ /* query.family and query.gindex must be set correctly !!
+  */
+  FT_EXPORT( FT_Error )
+  FTC_GCache_GetNode( FTC_GCache  cache,
+                      FT_UInt32   hash,
+                      FTC_GNode   query,
+                      FTC_Node   *anode );
 
   /* */
 
 
-#define FTC_FAMILY_FREE( family, cache )                      \
-          FTC_MruList_Remove( &FTC_GCACHE((cache))->families, \
-                              (FTC_MruNode)(family) )
-
-
 #ifdef FTC_INLINE
 
-#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash,                \
-                               gindex, query, node, error )                 \
-  FT_BEGIN_STMNT                                                            \
-    FTC_GCache               _gcache   = FTC_GCACHE( cache );               \
-    FTC_GQuery               _gquery   = (FTC_GQuery)( query );             \
-    FTC_MruNode_CompareFunc  _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \
-                                                                            \
-                                                                            \
-    _gquery->gindex = (gindex);                                             \
-                                                                            \
-    FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare,         \
-                            _gquery->family, error );                       \
-    if ( !error )                                                           \
-    {                                                                       \
-      FTC_Family  _gqfamily = _gquery->family;                              \
-                                                                            \
-                                                                            \
-      _gqfamily->num_nodes++;                                               \
-                                                                            \
-      FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error );     \
-                                                                            \
-      if ( --_gqfamily->num_nodes == 0 )                                    \
-        FTC_FAMILY_FREE( _gqfamily, _gcache );                              \
-    }                                                                       \
+#define  FTC_GCACHE_GET_FAMILY( cache, famcmp, hash, key, family, error )  \
+  FT_BEGIN_STMNT                                                       \
+    FTC_GCache             _gcache = FTC_GCACHE( cache );              \
+    FTC_Family             _key    = FTC_FAMILY( key );                \
+    FTC_Family_EqualFunc   _fequal = (FTC_Family_EqualFunc)(famcmp);   \
+    FTC_Family*            _pfamily = &_gcache->families;              \
+    FTC_Family             _family;                                    \
+                                                                       \
+    error = 0;                                                         \
+                                                                       \
+    for (;;)                                                           \
+    {                                                                  \
+      _family = *_pfamily;                                             \
+      if ( _family == NULL )                                           \
+        goto _NewFamily;                                               \
+                                                                       \
+      if ( _family->hash == (hash) && _fequal( _family, _key ) )       \
+        break;                                                         \
+                                                                       \
+      _pfamily = &_family->link;                                       \
+    }                                                                  \
+                                                                       \
+    if ( _family != _gcache->families )                                \
+    {                                                                  \
+      *_pfamily         = _family->link;                               \
+      _family->link     = _gcache->families;                           \
+      _gcache->families = _family;                                     \
+    }                                                                  \
+    goto _FoundIt;                                                     \
+                                                                       \
+  _NewFamily:                                                          \
+    error = FTC_GCache_NewFamily( _gcache, hash, _key, &_family );     \
+  _FoundIt:                                                            \
+    if ( !error )                                                      \
+      _family->num_nodes++;                                            \
+                                                                       \
+    *(FTC_Family*)(void*)(family) = _family;                           \
   FT_END_STMNT
-  /* */
 
 #else /* !FTC_INLINE */
 
-#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash,               \
-                               gindex, query, node, error )                \
-   FT_BEGIN_STMNT                                                          \
-     error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex,         \
-                                FTC_GQUERY( query ), (FTC_Node*)&(node) ); \
-   FT_END_STMNT
+#define FTC_GCACHE_GET_FAMILY( cache, famcmp, key, family, error )  \
+  error = FTC_GCache_GetFamily( (cache), (key), &(family) )
 
 #endif /* !FTC_INLINE */
 
diff --git a/include/freetype/cache/ftcimage.h b/include/freetype/cache/ftcimage.h
index 1bf12db..d5046c6 100644
--- a/include/freetype/cache/ftcimage.h
+++ b/include/freetype/cache/ftcimage.h
@@ -23,7 +23,7 @@
   *  FTC_ICache extends FTC_GCache.  For an implementation example,
   *  see FTC_ImageCache in `src/cache/ftbasic.c'.
   */
-  
+
 
   /*************************************************************************/
   /*                                                                       */
@@ -51,35 +51,41 @@
 
   } FTC_INodeRec, *FTC_INode;
 
-#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
+#define FTC_INODE( x )          ( (FTC_INode)( x ) )
+#define FTC_INODE__GLYPH(x)     ( FTC_INODE(x)->glyph )
+
 
   typedef FT_Error
-  (*FTC_IFamily_LoadGlyphFunc)( FTC_Family  family,
-                                FT_UInt     gindex,
-                                FTC_Cache   cache,
-                                FT_Glyph   *aglyph );
+  (*FTC_IFamily_LoadGlyphFunc)( FTC_Family   family,
+                                FT_UInt      gindex,
+                                FTC_Manager  manager,
+                                FT_Glyph    *aglyph );
 
-  typedef struct  FTC_IFamilyClassRec_
+  typedef struct
   {
-    FTC_MruListClassRec        clazz;
-    FTC_IFamily_LoadGlyphFunc  family_load_glyph;
+    FTC_GCacheClassRec          clazz;
+    FTC_IFamily_LoadGlyphFunc   fam_load_glyph;
 
-  } FTC_IFamilyClassRec;
+  } FTC_ICacheClassRec;
 
-  typedef const FTC_IFamilyClassRec*  FTC_IFamilyClass;
+  typedef const FTC_ICacheClassRec*   FTC_ICacheClass;
 
-#define FTC_IFAMILY_CLASS( x )  ((FTC_IFamilyClass)(x))
+#define  FTC_ICACHE_CLASS(x)  ((FTC_ICacheClass)(x))
 
-#define FTC_CACHE__IFAMILY_CLASS( x ) \
-          FTC_IFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class )
+#define  FTC_ICACHE__CLASS(x)       FTC_ICACHE_CLASS(FTC_GCACHE__CLASS(x))
+#define  FTC_ICACHE__LOAD_GLYPH(x)  (FTC_ICACHE__CLASS(x)->fam_load_glyph)
+
+#define  FTC_DEFINE_ICACHE_CLASS(_gcache_class,_family_load_glyph) \
+  {                                                  \
+    _gcache_class,                                   \
+    (FTC_IFamily_LoadGlyphFunc) _family_load_glyph   \
+  }
 
 
   /* can be used as a @FTC_Node_FreeFunc */
   FT_EXPORT( void )
-  FTC_INode_Free( FTC_INode  inode,
-                  FTC_Cache  cache );
+  FTC_INode_Free( FTC_INode   inode,
+                  FTC_GCache  cache );
 
   /* Can be used as @FTC_Node_NewFunc.  `gquery.index' and `gquery.family'
    * must be set correctly.  This function will call the `family_load_glyph'
@@ -87,8 +93,8 @@
    */
   FT_EXPORT( FT_Error )
   FTC_INode_New( FTC_INode   *pinode,
-                 FTC_GQuery   gquery,
-                 FTC_Cache    cache );
+                 FTC_GNode    gquery,
+                 FTC_GCache   cache );
 
   /* can be used as @FTC_Node_WeightFunc */
   FT_EXPORT( FT_ULong )
diff --git a/include/freetype/cache/ftcmru.h b/include/freetype/cache/ftcmru.h
index ac1a1a9..5638a72 100644
--- a/include/freetype/cache/ftcmru.h
+++ b/include/freetype/cache/ftcmru.h
@@ -67,6 +67,8 @@
 
   } FTC_MruNodeRec;
 
+#define  FTC_MRUNODE(x)  ((FTC_MruNode)(x))
+
 
   FT_EXPORT( void )
   FTC_MruNode_Prepend( FTC_MruNode  *plist,
@@ -87,8 +89,8 @@
 
 
   typedef FT_Bool
-  (*FTC_MruNode_CompareFunc)( FTC_MruNode  node,
-                              FT_Pointer   key );
+  (*FTC_MruNode_EqualFunc)( FTC_MruNode  node,
+                            FT_Pointer   key );
 
   typedef FT_Error
   (*FTC_MruNode_InitFunc)( FTC_MruNode  node,
@@ -108,13 +110,22 @@
   typedef struct  FTC_MruListClassRec_
   {
     FT_UInt                  node_size;
-    FTC_MruNode_CompareFunc  node_compare;
+    FTC_MruNode_EqualFunc    node_equal;
     FTC_MruNode_InitFunc     node_init;
     FTC_MruNode_ResetFunc    node_reset;
     FTC_MruNode_DoneFunc     node_done;
 
   } FTC_MruListClassRec;
 
+#define  FTC_DEFINE_MRULIST_CLASS(_type,_equal,_init,_reset,_done)  \
+  {                                                                 \
+    sizeof (_type),                                                 \
+    (FTC_MruNode_EqualFunc) (_equal),                               \
+    (FTC_MruNode_InitFunc)  (_init),                                \
+    (FTC_MruNode_ResetFunc) (_reset),                               \
+    (FTC_MruNode_DoneFunc)  (_done)                                 \
+  }
+
   typedef struct  FTC_MruListRec_
   {
     FT_UInt              num_nodes;
@@ -162,7 +173,7 @@
 
   FT_EXPORT( void )
   FTC_MruList_RemoveSelection( FTC_MruList              list,
-                               FTC_MruNode_CompareFunc  selection,
+                               FTC_MruNode_EqualFunc  selection,
                                FT_Pointer               key );
 
 
@@ -170,9 +181,9 @@
 
 #define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error )           \
   FT_BEGIN_STMNT                                                            \
-    FTC_MruNode*             _pfirst  = &(list)->nodes;                     \
-    FTC_MruNode_CompareFunc  _compare = (FTC_MruNode_CompareFunc)(compare); \
-    FTC_MruNode              _first, _node, *_pnode;                        \
+    FTC_MruNode*           _pfirst  = &(list)->nodes;                       \
+    FTC_MruNode_EqualFunc  _compare = (FTC_MruNode_EqualFunc)(compare);     \
+    FTC_MruNode            _first, _node, *_pnode;                          \
                                                                             \
                                                                             \
     error  = 0;                                                             \
@@ -204,7 +215,7 @@
   FT_END_STMNT
 
 #define FTC_MRULIST_LOOKUP( list, key, node, error ) \
-  FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error )
+  FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_equal, node, error )
 
 #else  /* !FTC_INLINE */
 
@@ -213,29 +224,6 @@
 
 #endif /* !FTC_INLINE */
 
-
-#define FTC_MRULIST_LOOP( list, node )        \
-  FT_BEGIN_STMNT                              \
-    FTC_MruNode  _first = (list)->nodes;      \
-                                              \
-                                              \
-    if ( _first )                             \
-    {                                         \
-      FTC_MruNode  _node = _first;            \
-                                              \
-                                              \
-      do                                      \
-      {                                       \
-        *(FTC_MruNode*)&(node) = _node;
-
-
-#define FTC_MRULIST_LOOP_END()               \
-        _node = _node->next;                 \
-                                             \
-      } while ( _node != _first );           \
-    }                                        \
-  FT_END_STMNT
-
  /* */
 
 FT_END_HEADER
diff --git a/include/freetype/cache/ftcsbits.h b/include/freetype/cache/ftcsbits.h
index b2ef0f1..e07d508 100644
--- a/include/freetype/cache/ftcsbits.h
+++ b/include/freetype/cache/ftcsbits.h
@@ -39,8 +39,8 @@
 
 
 #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
+#define FTC_SNODE__COUNT(x)    ( FTC_SNODE(x)->count )
+
 
   typedef FT_UInt
   (*FTC_SFamily_GetCountFunc)( FTC_Family   family,
@@ -52,40 +52,54 @@
                                 FTC_Manager  manager,
                                 FT_Face     *aface );
 
-  typedef struct  FTC_SFamilyClassRec_
+  typedef struct
   {
-    FTC_MruListClassRec        clazz;
-    FTC_SFamily_GetCountFunc   family_get_count;
-    FTC_SFamily_LoadGlyphFunc  family_load_glyph;
+    FTC_GCacheClassRec         clazz;
+    FTC_SFamily_GetCountFunc   fam_get_count;
+    FTC_SFamily_LoadGlyphFunc  fam_load_glyph;
 
-  } FTC_SFamilyClassRec;
+  } FTC_SCacheClassRec;
 
-  typedef const FTC_SFamilyClassRec*  FTC_SFamilyClass;
+  typedef const FTC_SCacheClassRec*   FTC_SCacheClass;
 
-#define FTC_SFAMILY_CLASS( x )  ((FTC_SFamilyClass)(x))
+#define  FTC_SCACHE_CLASS(x)   ((FTC_SCacheClass)(x))
+#define  FTC_SCACHE__CLASS(c)  FTC_SCACHE_CLASS(FTC_CACHE__CLASS(c))
+
+#define  FTC_DEFINE_SCACHE_CLASS(_gcache_class,_get_count,_get_glyph) \
+  {                                               \
+    _gcache_class,                                \
+    (FTC_SFamily_GetCountFunc) (_get_count),      \
+    (FTC_SFamily_LoadGlyphFunc)(_get_glyph)       \
+  }
+
+#define  FTC_SFAMILY__CLASS(f)  FTC_SCACHE__CLASS(FTC_FAMILY__CACHE(f))
+
 
 #define FTC_CACHE__SFAMILY_CLASS( x )  \
           FTC_SFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS( x )->family_class )
 
 
   FT_EXPORT( void )
-  FTC_SNode_Free( FTC_SNode  snode,
-                  FTC_Cache  cache );
+  FTC_SNode_Free( FTC_SNode   snode,
+                  FTC_GCache  cache );
 
   FT_EXPORT( FT_Error )
   FTC_SNode_New( FTC_SNode   *psnode,
-                 FTC_GQuery   gquery,
-                 FTC_Cache    cache );
+                 FTC_GNode    gquery,
+                 FTC_GCache   cache );
+
+#define  FTC_SNODE_EQUAL(node,query,cache)  \
+  FTC_SNode_Equal( FTC_SNODE(node), FTC_GNODE(query), FTC_CACHE(cache) )
+
+  FT_EXPORT( FT_Bool )
+  FTC_SNode_Equal( FTC_SNode  snode,
+                   FTC_GNode  gquery,
+                   FTC_Cache  cache );
 
   FT_EXPORT( FT_ULong )
   FTC_SNode_Weight( FTC_SNode  inode );
 
 
-  FT_EXPORT( FT_Bool )
-  FTC_SNode_Compare( FTC_SNode   snode,
-                     FTC_GQuery  gquery,
-                     FTC_Cache   cache );
-
   /* */
 
 FT_END_HEADER
diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h
index 985641c..20e9a1e 100644
--- a/include/freetype/ftcache.h
+++ b/include/freetype/ftcache.h
@@ -248,6 +248,21 @@
 
   /*************************************************************************/
   /*                                                                       */
+  /* <Type>                                                                */
+  /*    FTC_Family                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    An opaque handle to a cache family object. A family is used to     */
+  /*    group the attributes of several similar cache nodes.               */
+  /*                                                                       */
+  /*    Each family is reference-counted. When its count reaches 0, it     */
+  /*    is immediately destroyed.                                          */
+  /*                                                                       */
+  typedef struct FTC_FamilyRec_*   FTC_Family;
+
+
+  /*************************************************************************/
+  /*                                                                       */
   /* <Function>                                                            */
   /*    FTC_Manager_New                                                    */
   /*                                                                       */
@@ -449,12 +464,75 @@
                   FTC_Manager  manager );
 
 
+  /**
+   * @func: FTC_Family_Unref
+   *
+   * @description:
+   *    decrement a cache family's internal reference count. When its reaches
+   *    the value 0, it is destroyed immediately. You should always destroy
+   *    family objects as soon as possible.
+   */
+  FT_EXPORT( void )
+  FTC_Family_Unref( FTC_Family   family );
+
+
   /* remove all nodes belonging to a given face_id */
   FT_EXPORT( void )
   FTC_Manager_RemoveFaceID( FTC_Manager  manager,
                             FTC_FaceID   face_id );
 
 
+ /**
+  * @type: FTC_ImgMode
+  *
+  * @description:
+  *   this simple 32-bit unsigned integer type is used to store
+  *   styling and pixel rendering options
+  *
+  *   see @FTC_IMGMODE_MAKE, @FTC_IMGMODE_GET_RENDER, @FTC_IMGMODE_GET_EMBOLDEN
+  *   and @FTC_IMGMODE_GET_OBLIQUE
+  */
+typedef FT_UInt32    FTC_ImgMode;
+
+ /**
+  * @macro: FTC_IMGMODE_MAKE
+  *
+  * @description:
+  *   a convenient macro used to build a @FTC_ImgMode value that describes
+  *   pixel rendering mode, emboldening flag, and obliquing flag
+  *
+  * @param:
+  *   render :: pixel rendering mode, see @FT_Render_Mode
+  *   bold   :: boolean, true if emboldening is wanted
+  *   ital   :: boolean, true if obliquing is wanted
+  */
+#define  FTC_IMGMODE_MAKE(render,bold,ital)  \
+    ((FTC_ImgMode)(((render) << 2) | (((bold) != 0) << 1) | ((ital) != 0) )
+
+ /**
+  * @macro: FTC_IMGMODE_GET_RENDER (mode)
+  *
+  * @description:
+  *   retrieve the render mode of a given @FTC_ImgMode value
+  */
+#define  FTC_IMGMODE_GET_RENDER(m)    ((FT_Render_Mode)((m) >> 2))
+
+ /**
+  * @macro: FTC_IMGMODE_GET_EMBOLDEN (mode)
+  *
+  * @description:
+  *   retrieve the emboldening flags from a @FTC_ImgMode value
+  */
+#define  FTC_IMGMODE_GET_EMBOLDEN(m)  (((m) & 0x2) != 0)
+
+ /**
+  * @macro: FTC_IMGMODE_GET_OBLIQUE (mode)
+  *
+  * @description:
+  *   retrive the obliquing flag from a @FTC_ImgMode value
+  */
+#define  FTC_IMGMODE_GET_OBLIQUE(m)   (((m) & 0x1) != 0)
+
   /*************************************************************************/
   /*                                                                       */
   /* <Section>                                                             */
@@ -653,6 +731,29 @@
                          FTC_Node       *anode );
 
 
+  FT_EXPORT( FT_Error )
+  FTC_ImageCache_GetFamily( FTC_ImageCache  cache,
+                            FTC_Scaler      scaler,
+                            FT_UInt32       load_flags,
+                            FTC_ImgMode     img_mode,
+                            FTC_Family     *afamily );
+
+  FT_EXPORT( FT_Error )
+  FTC_ImageCache_GetGlyph( FTC_ImageCache  cache,
+                           FTC_Family      family,
+                           FT_UInt         gindex,
+                           FT_Glyph       *aglyph,
+                           FTC_Node       *anode );
+
+  FT_EXPORT( FT_Error )
+  FTC_ImageCache_FindGlyph( FTC_ImageCache  cache,
+                            FTC_Scaler      scaler,
+                            FT_UInt32       load_flags,
+                            FTC_ImgMode     img_mode,
+                            FT_UInt         gindex,
+                            FT_Glyph       *aglyph,
+                            FTC_Node       *anode );
+
   /*************************************************************************/
   /*                                                                       */
   /* <Type>                                                                */
@@ -806,6 +907,96 @@
                         FTC_SBit        *sbit,
                         FTC_Node        *anode );
 
+ /**
+  * @func: FTC_SBitCache_GetFamily
+  *
+  * @description:
+  *   retrieve the @FTC_Family from a @FTC_SBitCache that corresponds
+  *   to a given set of scaling mode, load flags and image modes.
+  *
+  * @input:
+  *   cache       :: handle to source SBit cache
+  *   scaler      :: handle to @FTC_ScalerRec structure describing scaling parameters
+  *   load_flags  :: load flags
+  *   image_modes :: corresponds to rendering pixel mode, emboldening and obliquing
+  *
+  * @output:
+  *   afamily :: handle to family. NULL in case of error
+  *
+  * @return:
+  *   error code
+  *
+  * @note:
+  *   you should free the family handle with @FTC_Family_Unref
+  */
+  FT_EXPORT( FT_Error )
+  FTC_SBitCache_GetFamily( FTC_SBitCache  cache,
+                           FTC_Scaler     scaler,
+                           FT_UInt32      load_flags,
+                           FTC_ImgMode    img_mode,
+                           FTC_Family    *afamily );
+
+ /**
+  * @func: FTC_SBitCache_GetBitmap
+  *
+  * @description:
+  *    retrieve a bitmap from a SBit cache using a @FTC_Family previously
+  *    found with @TC_SBitCache_GetFamily. The same family can be used in
+  *    subsequent calls
+  *
+  * @input:
+  *    cache  :: handle to source SBit cache
+  *    family :: family handle
+  *    gindex :: glyph index
+  *
+  * @output:
+  *    asbit  :: handle to small bitmap descriptor
+  *
+  * @inout:
+  *    anode  :: address where the handle to the corresponding cache node
+  *              will be written. set to NULL if you don't need it.
+  *
+  * @note:
+  *   the small bitmap descriptor whose address is managed by the cache
+  *
+  *   if 'anode' is not NULL on input, you must call @FTC_Node_Unref(*anode)
+  *   when you don't need to cache node.
+  */
+  FT_EXPORT( FT_Error )
+  FTC_SBitCache_GetBitmap( FTC_SBitCache  cache,
+                           FTC_Family     family,
+                           FT_UInt        gindex,
+                           FTC_SBit      *asbit,
+                           FTC_Node      *anode );
+
+ /**
+  * @func: FTC_SBitCache_FindBitmap
+  *
+  * @description:
+  *   a convenience function equivalent to the following sequence:
+  *
+  * {
+  *   FTC_Family  family;
+  *
+  *   error = FTC_SBitCache_GetFamily( cache, scaler, load_flags, img_mode,
+  *                                    &family );
+  *   if ( !error )
+  *   {
+  *     error = FTC_SBitCache_GetBitmap( cache, family, gindex, asbit, anode );
+  *
+  *     FTC_Family_Unref( family );
+  *   }
+  * }
+  *
+  */
+  FT_EXPORT( FT_Error )
+  FTC_SBitCache_FindBitmap( FTC_SBitCache  cache,
+                            FTC_Scaler     scaler,
+                            FT_UInt32      load_flags,
+                            FTC_ImgMode    img_mode,
+                            FT_UInt        gindex,
+                            FTC_SBit      *asbit,
+                            FTC_Node      *anode );
 
  /* */
 
diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c
index 689cdc6..4e7209a 100644
--- a/src/cache/ftcbasic.c
+++ b/src/cache/ftcbasic.c
@@ -23,7 +23,6 @@
 #include FT_CACHE_INTERNAL_SBITS_H
 #include FT_INTERNAL_MEMORY_H
 
-#include "ftccback.h"
 #include "ftcerror.h"
 
 
@@ -31,77 +30,46 @@
    *  Basic Families
    *
    */
-  typedef struct  FTC_BasicAttrRec_
-  {
-    FTC_ScalerRec  scaler;
-    FT_UInt        load_flags;
-
-  } FTC_BasicAttrRec, *FTC_BasicAttrs;
-
-#define FTC_BASIC_ATTR_COMPARE( a, b )                                 \
-          FT_BOOL( 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_FamilyRec   family;
+    FTC_ScalerRec   scaler;
+    FT_UInt         load_flags;
 
   } FTC_BasicFamilyRec, *FTC_BasicFamily;
 
 
+#define  FTC_BASIC_FAMILY_HASH(f)  \
+     ( FTC_SCALER_HASH( &(f)->scaler ) + 31*(f)->load_flags )
+
+
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_basic_family_compare( FTC_MruNode  ftcfamily,
-                            FT_Pointer   ftcquery )
+  ftc_basic_family_equal( FTC_BasicFamily  family,
+                          FTC_BasicFamily  query )
   {
-    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
-    FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
-
-
-    return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs );
+    return ( FTC_SCALER_COMPARE( &(family)->scaler, &(query)->scaler ) &&
+             family->load_flags == query->load_flags                   );
   }
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_basic_family_init( FTC_MruNode  ftcfamily,
-                         FT_Pointer   ftcquery,
-                         FT_Pointer   ftccache )
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_basic_family_equal_faceid( FTC_BasicFamily  family,
+                                 FTC_FaceID       face_id )
   {
-    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
-    FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
-    FTC_Cache        cache  = (FTC_Cache)ftccache;
-
-
-    FTC_Family_Init( FTC_FAMILY( family ), cache );
-    family->attrs = query->attrs;
-    return 0;
+    return FT_BOOL( family->scaler.face_id == face_id );
   }
 
 
   FT_CALLBACK_DEF( FT_UInt )
-  ftc_basic_family_get_count( FTC_Family   ftcfamily,
-                              FTC_Manager  manager )
+  ftc_basic_family_get_count( FTC_BasicFamily  family,
+                              FTC_Manager      manager )
   {
-    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
-    FT_Error         error;
-    FT_Face          face;
-    FT_UInt          result = 0;
+    FT_Error  error;
+    FT_Face   face;
+    FT_UInt   result = 0;
 
 
-    error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
-                                    &face );
+    error = FTC_Manager_LookupFace( manager, family->scaler.face_id, &face );
     if ( !error )
       result = face->num_glyphs;
 
@@ -110,24 +78,23 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
-                                FT_UInt      gindex,
-                                FTC_Manager  manager,
-                                FT_Face     *aface )
+  ftc_basic_family_load_bitmap( FTC_BasicFamily  family,
+                                FT_UInt          gindex,
+                                FTC_Manager      manager,
+                                FT_Face         *aface )
   {
-    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
     FT_Error         error;
     FT_Size          size;
 
 
-    error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
+    error = FTC_Manager_LookupSize( manager, &family->scaler, &size );
     if ( !error )
     {
       FT_Face  face = size->face;
 
 
       error = FT_Load_Glyph( face, gindex,
-                             family->attrs.load_flags | FT_LOAD_RENDER );
+                             family->load_flags | FT_LOAD_RENDER );
       if ( !error )
         *aface = face;
     }
@@ -137,27 +104,24 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
-                               FT_UInt     gindex,
-                               FTC_Cache   cache,
-                               FT_Glyph   *aglyph )
+  ftc_basic_family_load_glyph( FTC_BasicFamily  family,
+                               FT_UInt          gindex,
+                               FTC_Manager      manager,
+                               FT_Glyph        *aglyph )
   {
-    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
-    FT_Error         error;
-    FTC_Scaler       scaler = &family->attrs.scaler;
-    FT_Face          face;
-    FT_Size          size;
+    FT_Error    error;
+    FTC_Scaler  scaler = &family->scaler;
+    FT_Face     face;
+    FT_Size     size;
 
 
     /* we will now load the glyph image */
-    error = FTC_Manager_LookupSize( cache->manager,
-                                    scaler,
-                                    &size );
+    error = FTC_Manager_LookupSize( manager, scaler, &size );
     if ( !error )
     {
       face = size->face;
 
-      error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
+      error = FT_Load_Glyph( face, gindex, family->load_flags );
       if ( !error )
       {
         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
@@ -184,29 +148,6 @@
   }
 
 
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
-                                  FT_Pointer  ftcface_id,
-                                  FTC_Cache   cache )
-  {
-    FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
-    FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
-    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;
-  }
-
-
  /*
   *
   * basic image cache
@@ -214,36 +155,29 @@
   */
 
   FT_CALLBACK_TABLE_DEF
-  const FTC_IFamilyClassRec  ftc_basic_image_family_class =
-  {
-    {
-      sizeof ( FTC_BasicFamilyRec ),
-      ftc_basic_family_compare,
-      ftc_basic_family_init,
-      0,                        /* FTC_MruNode_ResetFunc */
-      0                         /* FTC_MruNode_DoneFunc  */
-    },
-    ftc_basic_family_load_glyph
-  };
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FTC_GCacheClassRec  ftc_basic_image_cache_class =
-  {
-    {
-      ftc_inode_new,
-      ftc_inode_weight,
-      ftc_gnode_compare,
-      ftc_basic_gnode_compare_faceid,
-      ftc_inode_free,
-
-      sizeof ( FTC_GCacheRec ),
-      ftc_gcache_init,
-      ftc_gcache_done
-    },
-    (FTC_MruListClass)&ftc_basic_image_family_class
-  };
-
+  const FTC_ICacheClassRec  ftc_basic_image_cache_class =
+  FTC_DEFINE_ICACHE_CLASS(
+      FTC_DEFINE_GCACHE_CLASS(
+          FTC_DEFINE_CACHE_CLASS(
+              FTC_INode_New,
+              FTC_INode_Weight,
+              FTC_GNode_Equal,
+              FTC_GNode_EqualFaceID,
+              FTC_INode_Free,
+              FTC_GCacheRec,
+              FTC_GCache_Init,
+              FTC_GCache_Done 
+           ),
+           FTC_DEFINE_FAMILY_CLASS(
+              FTC_BasicFamilyRec,
+              0 /* init */,
+              0 /* done */,
+              ftc_basic_family_equal,
+              ftc_basic_family_equal_faceid
+           )
+      ),
+      ftc_basic_family_load_glyph
+  );
 
   /* documentation is in ftcache.h */
 
@@ -251,8 +185,9 @@
   FTC_ImageCache_New( FTC_Manager      manager,
                       FTC_ImageCache  *acache )
   {
-    return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
-                           (FTC_GCache*)acache );
+    return FTC_Manager_RegisterCache( manager,
+                          (FTC_CacheClass) &ftc_basic_image_cache_class,
+                          (FTC_Cache*)acache );
   }
 
 
@@ -265,10 +200,11 @@
                          FT_Glyph       *aglyph,
                          FTC_Node       *anode )
   {
-    FTC_BasicQueryRec  query;
-    FTC_INode          node = 0;  /* make compiler happy */
-    FT_Error           error;
-    FT_UInt32          hash;
+    FTC_BasicFamilyRec  key_family;
+    FTC_GNodeRec        key;
+    FTC_Node            node = 0;  /* make compiler happy */
+    FT_Error            error;
+    FT_UInt32           hash;
 
 
     /* some argument checks are delayed to FTC_Cache_Lookup */
@@ -282,40 +218,34 @@
     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;
+    key_family.scaler.face_id = type->face_id;
+    key_family.scaler.width   = type->width;
+    key_family.scaler.height  = type->height;
+    key_family.scaler.pixel   = 1;
+    key_family.scaler.x_res   = 0;  /* make compilers happy */
+    key_family.scaler.y_res   = 0;
+    key_family.load_flags     = type->flags;
 
-    query.attrs.scaler.x_res   = 0;  /* make compilers happy */
-    query.attrs.scaler.y_res   = 0;
+    hash = FTC_BASIC_FAMILY_HASH( &key_family );
 
-    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
-
-#if 1  /* inlining is about 50% faster! */
-    FTC_GCACHE_LOOKUP_CMP( cache,
-                           ftc_basic_family_compare,
-                           FTC_GNode_Compare,
-                           hash, gindex,
-                           &query,
-                           node,
-                           error );
-#else
-    error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
-                               hash, gindex,
-                               FTC_GQUERY( &query ),
-                               (FTC_Node*) &node );
-#endif
+    FTC_GCACHE_GET_FAMILY( cache, ftc_basic_family_equal,
+                           hash, &key_family, &key.family, error );
     if ( !error )
     {
-      *aglyph = FTC_INODE( node )->glyph;
+      hash      += gindex;
+      key.gindex = gindex;
 
-      if ( anode )
+      FTC_CACHE_LOOKUP_CMP( cache, FTC_GNODE_EQUAL, hash,
+                            &key, node, error );
+      if ( !error )
       {
-        *anode = FTC_NODE( node );
-        FTC_NODE( node )->ref_count++;
+        *aglyph = FTC_INODE( node )->glyph;
+
+        if ( anode )
+          *anode = FTC_NODE_REF( node );
       }
+
+      FTC_Family_Unref( FTC_FAMILY(key.family) );
     }
 
   Exit:
@@ -328,40 +258,31 @@
   * basic small bitmap cache
   *
   */
-
-
   FT_CALLBACK_TABLE_DEF
-  const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
-  {
-    {
-      sizeof( FTC_BasicFamilyRec ),
-      ftc_basic_family_compare,
-      ftc_basic_family_init,
-      0,                            /* FTC_MruNode_ResetFunc */
-      0                             /* FTC_MruNode_DoneFunc  */
-    },
-    ftc_basic_family_get_count,
-    ftc_basic_family_load_bitmap
-  };
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
-  {
-    {
-      ftc_snode_new,
-      ftc_snode_weight,
-      ftc_snode_compare,
-      ftc_basic_gnode_compare_faceid,
-      ftc_snode_free,
-
-      sizeof ( FTC_GCacheRec ),
-      ftc_gcache_init,
-      ftc_gcache_done
-    },
-    (FTC_MruListClass)&ftc_basic_sbit_family_class
-  };
-
+  const FTC_SCacheClassRec  ftc_basic_sbit_cache_class =
+  FTC_DEFINE_SCACHE_CLASS(
+      FTC_DEFINE_GCACHE_CLASS(
+          FTC_DEFINE_CACHE_CLASS(
+              FTC_SNode_New,
+              FTC_SNode_Weight,
+              FTC_SNode_Equal,
+              FTC_GNode_EqualFaceID,
+              FTC_SNode_Free,
+              FTC_GCacheRec,
+              FTC_GCache_Init,
+              FTC_GCache_Done
+          ),
+          FTC_DEFINE_FAMILY_CLASS(
+              FTC_BasicFamilyRec,
+              0 /* init */,
+              0 /* done */,
+              ftc_basic_family_equal,
+              ftc_basic_family_equal_faceid
+          )
+      ),
+      ftc_basic_family_get_count,
+      ftc_basic_family_load_bitmap
+  );
 
   /* documentation is in ftcache.h */
 
@@ -369,8 +290,9 @@
   FTC_SBitCache_New( FTC_Manager     manager,
                      FTC_SBitCache  *acache )
   {
-    return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
-                           (FTC_GCache*)acache );
+    return FTC_Manager_RegisterCache( manager,
+                          (FTC_CacheClass) &ftc_basic_sbit_cache_class,
+                          (FTC_Cache*)acache );
   }
 
 
@@ -383,10 +305,11 @@
                         FTC_SBit      *ansbit,
                         FTC_Node      *anode )
   {
-    FT_Error           error;
-    FTC_BasicQueryRec  query;
-    FTC_SNode          node = 0; /* make compiler happy */
-    FT_UInt32          hash;
+    FTC_BasicFamilyRec  key_family;
+    FTC_GNodeRec        key;
+    FT_Error            error;
+    FTC_Node            node = 0; /* make compiler happy */
+    FT_UInt32           hash;
 
 
     if ( anode )
@@ -398,48 +321,39 @@
 
     *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;
+    key_family.scaler.face_id = type->face_id;
+    key_family.scaler.width   = type->width;
+    key_family.scaler.height  = type->height;
+    key_family.scaler.pixel   = 1;
+    key_family.scaler.x_res   = 0;  /* make compilers happy */
+    key_family.scaler.y_res   = 0;
+    key_family.load_flags     = type->flags;
 
-    query.attrs.scaler.x_res   = 0;  /* make compilers happy */
-    query.attrs.scaler.y_res   = 0;
+    hash = FTC_BASIC_FAMILY_HASH( &key_family );
 
-    /* beware, the hash must be the same for all glyph ranges! */
-    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
-           gindex / FTC_SBIT_ITEMS_PER_NODE;
-
-#if 1  /* inlining is about 50% faster! */
-    FTC_GCACHE_LOOKUP_CMP( cache,
-                           ftc_basic_family_compare,
-                           FTC_SNode_Compare,
-                           hash, gindex,
-                           &query,
-                           node,
-                           error );
-#else
-    error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
-                               hash,
-                               gindex,
-                               FTC_GQUERY( &query ),
-                               (FTC_Node*)&node );
-#endif
-    if ( error )
-      goto Exit;
-
-    *ansbit = node->sbits + ( gindex - FTC_GNODE( node )->gindex );
-
-    if ( anode )
+    FTC_GCACHE_GET_FAMILY( cache, ftc_basic_family_equal,
+                           hash, &key_family, &key.family, error );
+    if ( !error )
     {
-      *anode = FTC_NODE( node );
-      FTC_NODE( node )->ref_count++;
+      /* beware, the hash must be the same for all glyph ranges */
+      hash += gindex/FTC_SBIT_ITEMS_PER_NODE;
+
+      key.gindex = gindex;
+
+      FTC_CACHE_LOOKUP_CMP( cache, FTC_SNODE_EQUAL, hash,
+                            &key, node, error );
+      if ( !error )
+      {
+        *ansbit = FTC_SNODE(node)->sbits + ( gindex - FTC_GNODE(node)->gindex );
+
+        if ( anode )
+          *anode = FTC_NODE_REF(node);
+      }
+
+      FTC_Family_Unref( FTC_FAMILY(key.family) );
     }
 
-  Exit:
     return error;
   }
 
-
 /* END */
diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c
index ad03680..aaf3bd8 100644
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -21,7 +21,6 @@
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 
-#include "ftccback.h"
 #include "ftcerror.h"
 
 
@@ -272,7 +271,7 @@
     }
 #endif
 
-    manager->cur_weight -= cache->clazz.node_weight( node, cache );
+    manager->cur_weight -= cache->node_weight( node, cache );
 
     /* remove node from mru list */
     ftc_node_mru_unlink( node, manager );
@@ -281,7 +280,7 @@
     ftc_node_hash_unlink( node, cache );
 
     /* now finalize it */
-    cache->clazz.node_free( node, cache );
+    cache->clazz->node_free( node, cache );
 
 #if 0
     /* check, just in case of general corruption :-) */
@@ -304,13 +303,6 @@
   FT_EXPORT_DEF( FT_Error )
   FTC_Cache_Init( FTC_Cache  cache )
   {
-    return ftc_cache_init( cache );
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  ftc_cache_init( FTC_Cache  cache )
-  {
     FT_Memory  memory = cache->memory;
 
 
@@ -322,6 +314,7 @@
   }
 
 
+
   FT_EXPORT_DEF( void )
   FTC_Cache_Clear( FTC_Cache  cache )
   {
@@ -348,9 +341,9 @@
           ftc_node_mru_unlink( node, manager );
 
           /* now finalize it */
-          manager->cur_weight -= cache->clazz.node_weight( node, cache );
+          manager->cur_weight -= cache->node_weight( node, cache );
 
-          cache->clazz.node_free( node, cache );
+          cache->clazz->node_free( node, cache );
           node = next;
         }
         cache->buckets[i] = NULL;
@@ -360,8 +353,8 @@
   }
 
 
-  FT_LOCAL_DEF( void )
-  ftc_cache_done( FTC_Cache  cache )
+  FT_EXPORT_DEF( void )
+  FTC_Cache_Done( FTC_Cache  cache )
   {
     if ( cache->memory )
     {
@@ -380,13 +373,6 @@
   }
 
 
-  FT_EXPORT_DEF( void )
-  FTC_Cache_Done( FTC_Cache  cache )
-  {
-    ftc_cache_done( cache );
-  }
-
-
   static void
   ftc_cache_add( FTC_Cache  cache,
                  FT_UInt32  hash,
@@ -403,7 +389,7 @@
       FTC_Manager  manager = cache->manager;
 
 
-      manager->cur_weight += cache->clazz.node_weight( node, cache );
+      manager->cur_weight += cache->node_weight( node, cache );
 
       if ( manager->cur_weight >= manager->max_weight )
       {
@@ -433,7 +419,7 @@
 
     FTC_CACHE_TRYLOOP( cache )
     {
-      error = cache->clazz.node_new( &node, query, cache );
+      error = cache->clazz->node_new( &node, query, cache );
     }
     FTC_CACHE_TRYLOOP_END();
 
@@ -464,7 +450,7 @@
     FTC_Node   node;
     FT_Error   error = 0;
 
-    FTC_Node_CompareFunc  compare = cache->clazz.node_compare;
+    FTC_Node_EqualFunc  compare = cache->node_equal;
 
 
     if ( cache == NULL || anode == NULL )
@@ -535,7 +521,7 @@
         if ( node == NULL )
           break;
 
-        if ( cache->clazz.node_remove_faceid( node, face_id, cache ) )
+        if ( cache->clazz->node_remove_faceid( node, face_id, cache ) )
         {
           *pnode     = node->link;
           node->link = frees;
@@ -555,10 +541,10 @@
       node  = frees;
       frees = node->link;
 
-      manager->cur_weight -= cache->clazz.node_weight( node, cache );
+      manager->cur_weight -= cache->node_weight( node, cache );
       ftc_node_mru_unlink( node, manager );
 
-      cache->clazz.node_free( node, cache );
+      cache->clazz->node_free( node, cache );
 
       cache->slack++;
     }
diff --git a/src/cache/ftccback.h b/src/cache/ftccback.h
deleted file mode 100644
index 6b47e09..0000000
--- a/src/cache/ftccback.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  ftccback.h                                                             */
-/*                                                                         */
-/*    Callback functions of the caching sub-system (specification only).   */
-/*                                                                         */
-/*  Copyright 2004 by                                                      */
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
-/*                                                                         */
-/*  This file is part of the FreeType project, and may only be used,       */
-/*  modified, and distributed under the terms of the FreeType project      */
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
-/*  this file you indicate that you have read the license and              */
-/*  understand and accept it fully.                                        */
-/*                                                                         */
-/***************************************************************************/
-
-#ifndef __FTCCBACK_H__
-#define __FTCCBACK_H__
-
-#include <ft2build.h>
-#include FT_CACHE_H
-#include FT_CACHE_INTERNAL_MRU_H
-#include FT_CACHE_INTERNAL_IMAGE_H
-#include FT_CACHE_INTERNAL_MANAGER_H
-#include FT_CACHE_INTERNAL_GLYPH_H
-#include FT_CACHE_INTERNAL_SBITS_H
-
-
-  FT_LOCAL( void )
-  ftc_inode_free( FTC_Node   inode,
-                  FTC_Cache  cache );
-
-  FT_LOCAL( FT_Error )
-  ftc_inode_new( FTC_Node   *pinode,
-                 FT_Pointer  gquery,
-                 FTC_Cache   cache );
-
-  FT_LOCAL( FT_ULong )
-  ftc_inode_weight( FTC_Node   inode,
-                    FTC_Cache  cache );
-
-
-  FT_LOCAL( void )
-  ftc_snode_free( FTC_Node   snode,
-                  FTC_Cache  cache );
-
-  FT_LOCAL( FT_Error )
-  ftc_snode_new( FTC_Node   *psnode,
-                 FT_Pointer  gquery,
-                 FTC_Cache   cache );
-
-  FT_LOCAL( FT_ULong )
-  ftc_snode_weight( FTC_Node   snode,
-                    FTC_Cache  cache );
-
-  FT_LOCAL( FT_Bool )
-  ftc_snode_compare( FTC_Node    snode,
-                     FT_Pointer  gquery,
-                     FTC_Cache   cache );
-
-
-  FT_LOCAL( FT_Bool )
-  ftc_gnode_compare( FTC_Node    gnode,
-                     FT_Pointer  gquery,
-                     FTC_Cache   cache );
-
-
-  FT_LOCAL( FT_Error )
-  ftc_gcache_init( FTC_Cache  cache );
-
-  FT_LOCAL( void )
-  ftc_gcache_done( FTC_Cache  cache );
-
-
-  FT_LOCAL( FT_Error )
-  ftc_cache_init( FTC_Cache  cache );
-
-  FT_LOCAL( void )
-  ftc_cache_done( FTC_Cache  cache );
-
-
-#endif /* __FTCCBACK_H__ */
-
-/* END */
diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c
index 02b8148..d0b0b21 100644
--- a/src/cache/ftccmap.c
+++ b/src/cache/ftccmap.c
@@ -24,7 +24,6 @@
 #include FT_INTERNAL_DEBUG_H
 #include FT_TRUETYPE_IDS_H
 
-#include "ftccback.h"
 #include "ftcerror.h"
 
 #undef  FT_COMPONENT
@@ -153,9 +152,9 @@
 
   /* compare a cmap node to a given query */
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_cmap_node_compare( FTC_Node    ftcnode,
-                         FT_Pointer  ftcquery,
-                         FTC_Cache   cache )
+  ftc_cmap_node_equal( FTC_Node    ftcnode,
+                       FT_Pointer  ftcquery,
+                       FTC_Cache   cache )
   {
     FTC_CMapNode   node  = (FTC_CMapNode)ftcnode;
     FTC_CMapQuery  query = (FTC_CMapQuery)ftcquery;
@@ -202,13 +201,13 @@
   {
     ftc_cmap_node_new,
     ftc_cmap_node_weight,
-    ftc_cmap_node_compare,
+    ftc_cmap_node_equal,
     ftc_cmap_node_remove_faceid,
     ftc_cmap_node_free,
 
     sizeof ( FTC_CacheRec ),
-    ftc_cache_init,
-    ftc_cache_done,
+    FTC_Cache_Init,
+    FTC_Cache_Done
   };
 
 
@@ -253,7 +252,7 @@
     hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
 
 #if 1
-    FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
+    FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_equal, hash, &query,
                           node, error );
 #else
     error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node );
diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c
index 46d5965..2b8fa66 100644
--- a/src/cache/ftcglyph.c
+++ b/src/cache/ftcglyph.c
@@ -23,10 +23,17 @@
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 
-#include "ftccback.h"
 #include "ftcerror.h"
 
 
+  FT_EXPORT_DEF( void )
+  FTC_Family_Unref( FTC_Family  family )
+  {
+    if ( family && --family->num_nodes <= 0 )
+      FTC_GCache_FreeFamily( family->cache, family );
+  }
+
+
   /* create a new chunk node, setting its cache index and ref count */
   FT_EXPORT_DEF( void )
   FTC_GNode_Init( FTC_GNode   gnode,
@@ -40,52 +47,50 @@
 
 
   FT_EXPORT_DEF( void )
-  FTC_GNode_UnselectFamily( FTC_GNode  gnode,
-                            FTC_Cache  cache )
+  FTC_GNode_Done( FTC_GNode   gnode )
   {
     FTC_Family  family = gnode->family;
 
-
-    gnode->family = NULL;
-    if ( family && --family->num_nodes == 0 )
-      FTC_FAMILY_FREE( family, cache );
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FTC_GNode_Done( FTC_GNode  gnode,
-                  FTC_Cache  cache )
-  {
     /* finalize the node */
     gnode->gindex = 0;
-
-    FTC_GNode_UnselectFamily( gnode, cache );
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  ftc_gnode_compare( FTC_Node    ftcgnode,
-                     FT_Pointer  ftcgquery,
-                     FTC_Cache   cache )
-  {
-    FTC_GNode   gnode  = (FTC_GNode)ftcgnode;
-    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
-    FT_UNUSED( cache );
-
-
-    return FT_BOOL(  gnode->family == gquery->family &&
-                     gnode->gindex == gquery->gindex );
+    gnode->family = 0;
+    if ( family && --family->num_nodes == 0 )
+      FTC_GCache_FreeFamily( family->cache, family );
   }
 
 
   FT_EXPORT_DEF( FT_Bool )
-  FTC_GNode_Compare( FTC_GNode   gnode,
-                     FTC_GQuery  gquery )
+  FTC_GNode_Equal( FTC_GNode   gnode,
+                   FTC_GNode   query,
+                   FTC_GCache  cache )
   {
-    return ftc_gnode_compare( FTC_NODE( gnode ), gquery, NULL );
+    FT_UNUSED(cache);
+
+    return FTC_GNODE_EQUAL(gnode,query,cache);
   }
 
 
+  FT_EXPORT( FT_Bool )
+  FTC_GNode_EqualFaceID( FTC_GNode   gnode,
+                         FTC_FaceID  face_id,
+                         FTC_GCache  cache )
+  {
+    FTC_Family  family = gnode->family;
+    FT_Bool     result;
+
+    result = cache->fam_equal_faceid( family, face_id );
+    if ( result )
+    {
+      gnode->family = NULL;
+      if ( family && --family->num_nodes == 0 )
+        FTC_GCache_FreeFamily( cache, family );
+    }
+    return  result;
+  }
+
+
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -94,64 +99,54 @@
   /*************************************************************************/
   /*************************************************************************/
 
-  FT_EXPORT_DEF( void )
-  FTC_Family_Init( FTC_Family  family,
-                   FTC_Cache   cache )
+  FT_EXPORT_DEF( FT_Error )
+  FTC_GCache_Init( FTC_GCache  cache )
   {
-    FTC_GCacheClass  clazz = FTC_CACHE__GCACHE_CLASS( cache );
-
-
-    family->clazz     = clazz->family_class;
-    family->num_nodes = 0;
-    family->cache     = cache;
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  ftc_gcache_init( FTC_Cache  ftccache )
-  {
-    FTC_GCache  cache = (FTC_GCache)ftccache;
     FT_Error    error;
 
 
     error = FTC_Cache_Init( FTC_CACHE( cache ) );
     if ( !error )
     {
-      FTC_GCacheClass   clazz = (FTC_GCacheClass)FTC_CACHE( cache )->org_class;
+      FTC_FamilyClass  clazz = FTC_GCACHE__FAMILY_CLASS(cache);
 
-      FTC_MruList_Init( &cache->families,
-                        clazz->family_class,
-                        0,  /* no maximum here! */
-                        cache,
-                        FTC_CACHE( cache )->memory );
+      cache->families         = NULL;
+
+      /* create local copies for better performance */
+      cache->fam_equal        = clazz->fam_equal;
+      cache->fam_equal_faceid = clazz->fam_equal_faceid;
     }
 
     return error;
   }
 
 
-  FT_EXPORT_DEF( FT_Error )
-  FTC_GCache_Init( FTC_GCache  cache )
-  {
-    return ftc_gcache_init( FTC_CACHE( cache ) );
-  }
-
-
-  FT_LOCAL_DEF( void )
-  ftc_gcache_done( FTC_Cache  ftccache )
-  {
-    FTC_GCache  cache = (FTC_GCache)ftccache;
-
-
-    FTC_Cache_Done( (FTC_Cache)cache );
-    FTC_MruList_Done( &cache->families );
-  }
-
-
   FT_EXPORT_DEF( void )
   FTC_GCache_Done( FTC_GCache  cache )
   {
-    ftc_gcache_done( FTC_CACHE( cache ) );
+    FT_Memory  memory = FTC_CACHE__MEMORY(cache);
+
+    FTC_Cache_Done( (FTC_Cache)cache );
+
+   /* destroy any families that the clients didn't
+    * release properly !!
+    */
+    if ( cache->families )
+    {
+      FTC_Family           family, next;
+      FTC_FamilyClass      clazz       = FTC_GCACHE__FAMILY_CLASS(cache);
+      FTC_Family_DoneFunc  family_done = clazz->fam_done;
+
+      for ( family = cache->families; family; family = next )
+      {
+        next = family->link;
+
+        if ( family_done )
+          family_done( family );
+
+        FT_FREE( family );
+      }
+    }
   }
 
 
@@ -160,16 +155,146 @@
                   FTC_GCacheClass   clazz,
                   FTC_GCache       *acache )
   {
-    return FTC_Manager_RegisterCache( manager, (FTC_CacheClass)clazz,
+    return FTC_Manager_RegisterCache( manager,
+                                      (FTC_CacheClass)clazz,
                                       (FTC_Cache*)acache );
   }
 
 
+  FT_EXPORT_DEF( void )
+  FTC_GCache_FreeFamily( FTC_GCache  cache,
+                         FTC_Family  family )
+  {
+    FTC_Family*      pfamily = &cache->families;
+    FTC_FamilyClass  clazz   = FTC_GCACHE__FAMILY_CLASS(cache);
+    FT_Memory        memory  = FTC_CACHE__MEMORY(cache);
+
+    for (;;)
+    {
+      if ( *pfamily == NULL )
+        return;
+
+      if ( *pfamily == family )
+      {
+        *pfamily = family->link;
+        break;
+      }
+    }
+
+    if ( clazz->fam_done )
+      clazz->fam_done( family );
+
+    FT_FREE( family );
+  }
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_GCache_NewFamily( FTC_GCache   cache,
+                        FT_UInt32    hash,
+                        FTC_Family   query,
+                        FTC_Family  *afamily )
+  {
+    FT_Memory        memory = FTC_CACHE__MEMORY(cache);
+    FT_Error         error;
+    FTC_Family       family;
+    FTC_FamilyClass  clazz = FTC_GCACHE__FAMILY_CLASS(cache);
+
+    if ( !FT_QALLOC( family, clazz->fam_size ) )
+    {
+      FT_MEM_COPY( family, query, clazz->fam_size );
+
+      family->cache     = cache;
+      family->link      = NULL;
+      family->num_nodes = 0;
+      family->hash      = hash;
+
+      if ( clazz->fam_init )
+      {
+        error = clazz->fam_init( family, query );
+        if ( error )
+        {
+          if ( clazz->fam_done )
+            clazz->fam_done( family );
+
+          FT_FREE( family );
+          goto Exit;
+        }
+      }
+      
+      family->link    = cache->families;
+      cache->families = family;
+    }
+
+  Exit:
+    *afamily = family;
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_GCache_GetFamily( FTC_GCache   cache,
+                        FT_UInt32    hash,
+                        FTC_Family   query,
+                        FTC_Family  *afamily )
+  {
+    FTC_Family*           pfamily = &cache->families;
+    FTC_Family            family;
+    FTC_Family_EqualFunc  fequal  = cache->fam_equal;
+    FT_Error              error   = 0;
+
+    for (;;)
+    {
+      family = *pfamily;
+      if ( family == NULL )
+        break;
+
+      if ( family->hash == hash && fequal( family, query ) )
+      {
+        if ( family != cache->families )
+        {
+          *pfamily        = family->link;
+          family->link    = cache->families;
+          cache->families = family;
+        }
+        goto FoundIt;
+      }
+
+      pfamily = &family->link;
+    }
+
+    /* we didn't found it */
+    error = FTC_GCache_NewFamily( cache, hash, query, &family );
+
+  FoundIt:
+    if ( !error )
+      family->num_nodes++;
+
+    *afamily = family;
+    return error;
+  }
+
+
+  FT_EXPORT( FT_Error )
+  FTC_GCache_GetNode( FTC_GCache  cache,
+                      FT_UInt     hash,
+                      FTC_GNode   query,
+                      FTC_Node   *anode )
+  {
+    FTC_Node  node  = NULL;
+    FT_Error  error = 0;
+
+    FTC_CACHE_LOOKUP_CMP( cache, FTC_CACHE(cache)->node_equal, hash,
+                          query, node, error );
+
+    *anode = node;
+    return error;
+  }
+
+#if 0
   FT_EXPORT_DEF( FT_Error )
   FTC_GCache_Lookup( FTC_GCache   cache,
                      FT_UInt32    hash,
                      FT_UInt      gindex,
-                     FTC_GQuery   query,
+                     FTC_GNode    query,
                      FTC_Node    *anode )
   {
     FT_Error  error;
@@ -177,12 +302,14 @@
 
     query->gindex = gindex;
 
-    FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error );
+    FTC_MRULIST_LOOKUP( &cache->families,
+                        query->family,
+                        query->family,
+                        error );
     if ( !error )
     {
       FTC_Family  family = query->family;
 
-
       /* prevent the family from being destroyed too early when an        */
       /* out-of-memory condition occurs during glyph node initialization. */
       family->num_nodes++;
@@ -194,6 +321,7 @@
     }
     return error;
   }
+#endif
 
 
 /* END */
diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c
index 02020ba..b7d6cdf 100644
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -21,17 +21,15 @@
 #include FT_CACHE_INTERNAL_IMAGE_H
 #include FT_INTERNAL_MEMORY_H
 
-#include "ftccback.h"
 #include "ftcerror.h"
 
 
   /* finalize a given glyph image node */
-  FT_LOCAL_DEF( void )
-  ftc_inode_free( FTC_Node   ftcinode,
-                  FTC_Cache  cache )
+  FT_EXPORT_DEF( void )
+  FTC_INode_Free( FTC_INode   inode,
+                  FTC_GCache  cache )
   {
-    FTC_INode  inode = (FTC_INode)ftcinode;
-    FT_Memory  memory = cache->memory;
+    FT_Memory  memory = FTC_CACHE__MEMORY(cache);
 
 
     if ( inode->glyph )
@@ -40,26 +38,18 @@
       inode->glyph = NULL;
     }
 
-    FTC_GNode_Done( FTC_GNODE( inode ), cache );
+    FTC_GNode_Done( FTC_GNODE( inode ) );
     FT_FREE( inode );
   }
 
 
-  FT_EXPORT_DEF( void )
-  FTC_INode_Free( FTC_INode  inode,
-                  FTC_Cache  cache )
-  {
-    ftc_inode_free( FTC_NODE( inode ), cache );
-  }
-
-
   /* initialize a new glyph image node */
   FT_EXPORT_DEF( FT_Error )
   FTC_INode_New( FTC_INode   *pinode,
-                 FTC_GQuery   gquery,
-                 FTC_Cache    cache )
+                 FTC_GNode    gquery,
+                 FTC_GCache   cache )
   {
-    FT_Memory  memory = cache->memory;
+    FT_Memory  memory = FTC_CACHE__MEMORY(cache);
     FT_Error   error;
     FTC_INode  inode;
 
@@ -69,15 +59,16 @@
       FTC_GNode         gnode  = FTC_GNODE( inode );
       FTC_Family        family = gquery->family;
       FT_UInt           gindex = gquery->gindex;
-      FTC_IFamilyClass  clazz  = FTC_CACHE__IFAMILY_CLASS( cache );
+      FTC_ICacheClass   clazz  = FTC_ICACHE__CLASS( cache );
 
 
       /* initialize its inner fields */
       FTC_GNode_Init( gnode, gindex, family );
 
       /* we will now load the glyph image */
-      error = clazz->family_load_glyph( family, gindex, cache,
-                                        &inode->glyph );
+      error = clazz->fam_load_glyph( family, gindex,
+                                     FTC_CACHE__MANAGER(cache), 
+                                     &inode->glyph );
       if ( error )
       {
         FTC_INode_Free( inode, cache );
@@ -90,29 +81,13 @@
   }
 
 
-  FT_LOCAL_DEF( FT_Error )
-  ftc_inode_new( FTC_Node   *ftcpinode,
-                 FT_Pointer  ftcgquery,
-                 FTC_Cache   cache )
+
+  FT_EXPORT_DEF( FT_ULong )
+  FTC_INode_Weight( FTC_INode  inode )
   {
-    FTC_INode  *pinode = (FTC_INode*)ftcpinode;
-    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
-
-
-    return FTC_INode_New( pinode, gquery, cache );
-  }
-
-
-  FT_LOCAL_DEF( FT_ULong )
-  ftc_inode_weight( FTC_Node   ftcinode,
-                    FTC_Cache  ftccache )
-  {
-    FTC_INode  inode = (FTC_INode)ftcinode;
     FT_ULong   size  = 0;
     FT_Glyph   glyph = inode->glyph;
 
-    FT_UNUSED( ftccache );
-
 
     switch ( glyph->format )
     {
@@ -149,11 +124,4 @@
   }
 
 
-  FT_EXPORT_DEF( FT_ULong )
-  FTC_INode_Weight( FTC_INode  inode )
-  {
-    return ftc_inode_weight( FTC_NODE( inode ), NULL );
-  }
-
-
 /* END */
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c
index 337bea5..356e427 100644
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -93,7 +93,7 @@
 
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_size_node_compare( FTC_MruNode  ftcnode,
+  ftc_size_node_equal( FTC_MruNode  ftcnode,
                          FT_Pointer   ftcscaler )
   {
     FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
@@ -148,7 +148,7 @@
   const FTC_MruListClassRec  ftc_size_list_class =
   {
     sizeof ( FTC_SizeNodeRec ),
-    ftc_size_node_compare,
+    ftc_size_node_equal,
     ftc_size_node_init,
     ftc_size_node_reset,
     ftc_size_node_done
@@ -157,7 +157,7 @@
 
   /* helper function used by ftc_face_node_done */
   static FT_Bool
-  ftc_size_node_compare_faceid( FTC_MruNode  ftcnode,
+  ftc_size_node_equal_faceid( FTC_MruNode  ftcnode,
                                 FT_Pointer   ftcface_id )
   {
     FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
@@ -189,7 +189,7 @@
 
 #ifdef FTC_INLINE
 
-    FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
+    FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_equal,
                             node, error );
 
 #else
@@ -259,7 +259,7 @@
     /* we must begin by removing all scalers for the target face */
     /* from the manager's list                                   */
     FTC_MruList_RemoveSelection( &manager->sizes,
-                                 ftc_size_node_compare_faceid,
+                                 ftc_size_node_equal_faceid,
                                  node->face_id );
 
     /* all right, we can discard the face now */
@@ -270,7 +270,7 @@
 
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_face_node_compare( FTC_MruNode  ftcnode,
+  ftc_face_node_equal( FTC_MruNode  ftcnode,
                          FT_Pointer   ftcface_id )
   {
     FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
@@ -286,7 +286,7 @@
   {
     sizeof ( FTC_FaceNodeRec),
 
-    ftc_face_node_compare,
+    ftc_face_node_equal,
     ftc_face_node_init,
     0,                          /* FTC_MruNode_ResetFunc */
     ftc_face_node_done
@@ -315,7 +315,7 @@
     /* we break encapsulation for the sake of speed */
 #ifdef FTC_INLINE
 
-    FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
+    FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_equal,
                             node, error );
 
 #else
@@ -419,7 +419,7 @@
 
       if ( cache )
       {
-        cache->clazz.cache_done( cache );
+        cache->clazz->cache_done( cache );
         FT_FREE( cache );
         manager->caches[idx] = NULL;
       }
@@ -478,7 +478,7 @@
           FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
                      node->cache_index ));
         else
-          weight += cache->clazz.node_weight( node, cache );
+          weight += cache->node_weight( node, cache );
 
         node = FTC_NODE__NEXT( node );
 
@@ -585,10 +585,11 @@
 
       if ( !FT_ALLOC( cache, clazz->cache_size ) )
       {
-        cache->manager   = manager;
-        cache->memory    = memory;
-        cache->clazz     = clazz[0];
-        cache->org_class = clazz;
+        cache->manager     = manager;
+        cache->memory      = memory;
+        cache->node_equal  = clazz->node_equal;
+        cache->node_weight = clazz->node_weight;
+        cache->clazz       = clazz;
 
         /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
         /* IF IT IS NOT SET CORRECTLY                          */
diff --git a/src/cache/ftcmru.c b/src/cache/ftcmru.c
index d4f733a..a455848 100644
--- a/src/cache/ftcmru.c
+++ b/src/cache/ftcmru.c
@@ -202,7 +202,7 @@
   FTC_MruList_Find( FTC_MruList  list,
                     FT_Pointer   key )
   {
-    FTC_MruNode_CompareFunc  compare = list->clazz.node_compare;
+    FTC_MruNode_EqualFunc  compare = list->clazz.node_equal;
     FTC_MruNode              first, node;
 
 
@@ -323,7 +323,7 @@
 
   FT_EXPORT_DEF( void )
   FTC_MruList_RemoveSelection( FTC_MruList              list,
-                               FTC_MruNode_CompareFunc  selection,
+                               FTC_MruNode_EqualFunc  selection,
                                FT_Pointer               key )
   {
     FTC_MruNode  first, node, next;
diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c
index 891c7ab..4e8922a 100644
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -23,7 +23,6 @@
 #include FT_INTERNAL_DEBUG_H
 #include FT_ERRORS_H
 
-#include "ftccback.h"
 #include "ftcerror.h"
 
 
@@ -58,33 +57,24 @@
   }
 
 
-  FT_LOCAL_DEF( void )
-  ftc_snode_free( FTC_Node   ftcsnode,
-                  FTC_Cache  cache )
+  FT_EXPORT_DEF( void )
+  FTC_SNode_Free( FTC_SNode   snode,
+                  FTC_GCache  cache )
   {
-    FTC_SNode  snode  = (FTC_SNode)ftcsnode;
     FTC_SBit   sbit   = snode->sbits;
     FT_UInt    count  = snode->count;
-    FT_Memory  memory = cache->memory;
+    FT_Memory  memory = FTC_CACHE__MEMORY(cache);
 
 
     for ( ; count > 0; sbit++, count-- )
       FT_FREE( sbit->buffer );
 
-    FTC_GNode_Done( FTC_GNODE( snode ), cache );
+    FTC_GNode_Done( FTC_GNODE( snode ) );
 
     FT_FREE( snode );
   }
 
 
-  FT_EXPORT_DEF( void )
-  FTC_SNode_Free( FTC_SNode  snode,
-                  FTC_Cache  cache )
-  {
-    ftc_snode_free( FTC_NODE( snode ), cache );
-  }
-
-
   /*
    *  This function tries to load a small bitmap within a given FTC_SNode.
    *  Note that it returns a non-zero error code _only_ in the case of
@@ -92,7 +82,7 @@
    *  to a bad font file), this function will mark the sbit as `unavailable'
    *  and return a value of 0.
    *
-   *  You should also read the comment within the @ftc_snode_compare
+   *  You should also read the comment within the @ftc_snode_equal
    *  function below to see how out-of-memory is handled during a lookup.
    */
   static FT_Error
@@ -107,7 +97,7 @@
     FT_Memory         memory = manager->memory;
     FT_Face           face;
     FTC_SBit          sbit;
-    FTC_SFamilyClass  clazz;
+    FTC_SCacheClass   clazz;
 
 
     if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
@@ -117,11 +107,11 @@
     }
 
     sbit  = snode->sbits + ( gindex - gnode->gindex );
-    clazz = (FTC_SFamilyClass)family->clazz;
+    clazz = FTC_SCACHE__CLASS(FTC_FAMILY__CACHE(family));
 
     sbit->buffer = 0;
 
-    error = clazz->family_load_glyph( family, gindex, manager, &face );
+    error = clazz->fam_load_glyph( family, gindex, manager, &face );
     if ( error )
       goto BadGlyph;
 
@@ -199,20 +189,20 @@
 
   FT_EXPORT_DEF( FT_Error )
   FTC_SNode_New( FTC_SNode  *psnode,
-                 FTC_GQuery  gquery,
-                 FTC_Cache   cache )
+                 FTC_GNode   gquery,
+                 FTC_GCache  cache )
   {
-    FT_Memory   memory = cache->memory;
+    FT_Memory   memory = FTC_CACHE__MEMORY(cache);
     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 );
+    FTC_SCacheClass   clazz = FTC_SCACHE__CLASS(cache);
     FT_UInt           total;
 
 
-    total = clazz->family_get_count( family, cache->manager );
+    total = clazz->fam_get_count( family, FTC_CACHE__MANAGER(cache) );
     if ( total == 0 || gindex >= total )
     {
       error = FT_Err_Invalid_Argument;
@@ -234,7 +224,7 @@
       snode->count = count;
 
       error = ftc_snode_load( snode,
-                              cache->manager,
+                              FTC_CACHE__MANAGER(cache),
                               gindex,
                               NULL );
       if ( error )
@@ -250,32 +240,16 @@
   }
 
 
-  FT_LOCAL_DEF( FT_Error )
-  ftc_snode_new( FTC_Node   *ftcpsnode,
-                 FT_Pointer  ftcgquery,
-                 FTC_Cache   cache )
+
+
+  FT_EXPORT_DEF( FT_ULong )
+  FTC_SNode_Weight( FTC_SNode  snode )
   {
-    FTC_SNode  *psnode = (FTC_SNode*)ftcpsnode;
-    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
-
-
-    return FTC_SNode_New( psnode, gquery, cache );
-  }
-
-
-  FT_LOCAL_DEF( FT_ULong )
-  ftc_snode_weight( FTC_Node   ftcsnode,
-                    FTC_Cache  cache )
-  {
-    FTC_SNode  snode = (FTC_SNode)ftcsnode;
     FT_UInt    count = snode->count;
     FTC_SBit   sbit  = snode->sbits;
     FT_Int     pitch;
     FT_ULong   size;
 
-    FT_UNUSED( cache );
-
-
     FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
 
     /* the node itself */
@@ -298,20 +272,11 @@
   }
 
 
-  FT_EXPORT_DEF( FT_ULong )
-  FTC_SNode_Weight( FTC_SNode  snode )
+  FT_EXPORT_DEF( FT_Bool )
+  FTC_SNode_Equal( FTC_SNode   snode,
+                   FTC_GNode   gquery,
+                   FTC_Cache   cache )
   {
-    return ftc_snode_weight( FTC_NODE( snode ), NULL );
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  ftc_snode_compare( FTC_Node    ftcsnode,
-                     FT_Pointer  ftcgquery,
-                     FTC_Cache   cache )
-  {
-    FTC_SNode   snode  = (FTC_SNode)ftcsnode;
-    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
     FTC_GNode   gnode  = FTC_GNODE( snode );
     FT_UInt     gindex = gquery->gindex;
     FT_Bool     result;
@@ -341,7 +306,7 @@
        *  However, we need to `lock' the node before this operation to
        *  prevent it from being flushed within the loop.
        *
-       *  When we exit the loop, we unlock the node, then check the `error' 
+       *  When we exit the loop, we unlock the node, then check the `error'
        *  variable.  If it is non-zero, this means that the cache was
        *  completely flushed and that no usable memory was found to load
        *  the bitmap.
@@ -363,8 +328,8 @@
         FT_Error  error;
 
 
-        ftcsnode->ref_count++;  /* lock node to prevent flushing */
-                                /* in retry loop                 */
+        FTC_NODE_REF(snode);  /* lock node to prevent flushing */
+                              /* in retry loop                 */
 
         FTC_CACHE_TRYLOOP( cache )
         {
@@ -372,7 +337,7 @@
         }
         FTC_CACHE_TRYLOOP_END();
 
-        ftcsnode->ref_count--;  /* unlock the node */
+        FTC_NODE(snode)->ref_count--;  /* unlock the node */
 
         if ( error )
           result = 0;
@@ -385,13 +350,6 @@
   }
 
 
-  FT_EXPORT_DEF( FT_Bool )
-  FTC_SNode_Compare( FTC_SNode   snode,
-                     FTC_GQuery  gquery,
-                     FTC_Cache   cache )
-  {
-    return ftc_snode_compare( FTC_NODE( snode ), gquery, cache );
-  }
 
 
 /* END */