shithub: freetype+ttf2subf

Download patch

ref: ebdce8344a089963635473c73cb7cbc967bc6a7e
parent: 58e932157b02295427db073e19a36cbae33213e6
author: David Turner <[email protected]>
date: Mon Sep 18 21:11:11 EDT 2000

updated the cache sub-system. Major internal rewrite
please be aware that major bug persist..

git/fs: mount .git/fs: mount/attach disallowed
--- a/src/cache/ftcache.c
+++ b/src/cache/ftcache.c
@@ -22,6 +22,7 @@
 
 #include "ftlru.c"
 #include "ftcmanag.c"
+#include "ftcglyph.c"
 #include "ftcimage.c"
 
 #else
@@ -28,6 +29,7 @@
 
 #include <cache/ftlru.c>
 #include <cache/ftcmanag.c>
+#include <cache/ftcglyph.c>
 #include <cache/ftcimage.c>
 
 #endif
--- /dev/null
+++ b/src/cache/ftcglyph.c
@@ -1,0 +1,386 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcglyph.c                                                             */
+/*                                                                         */
+/*    FreeType Glyph Image (FT_Glyph) cache..                              */
+/*                                                                         */
+/*  Copyright 2000 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.                                        */
+/*                                                                         */
+/*                                                                         */
+/*  Note: the implementation of glyph queues is rather generic in this     */
+/*        code. This will allow other glyph node/cache types to be         */
+/*        easily included in the future.. For now, we only cache           */
+/*        glyph images..                                                   */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <freetype/cache/ftcglyph.h>
+#include <freetype/fterrors.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftlist.h>
+#include <freetype/fterrors.h>
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      GLYPH NODES                              *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ 
+/* in the future, we might provide a better scheme for managing       */
+/* glyph node element. For the moment, we simply use FT_Alloc/FT_Free */
+
+ /* creates a new glyph node, setting its cache index and ref count */
+  FT_EXPORT_FUNC(void)   FTC_GlyphNode_Init( FTC_GlyphNode    node,
+                                             FTC_Glyph_Queue  queue,
+                                             FT_UInt          gindex )
+  {
+    FTC_Glyph_Cache      cache = queue->cache;
+    FTC_CacheNode_Data*  data  = FTC_CACHENODE_TO_DATA_P( &node->root );
+      
+    data->cache_index = (FT_UShort) cache->root.cache_index;
+    data->ref_count   = (FT_Short)  0;
+    node->queue_index = (FT_UShort) queue->queue_index;
+    node->glyph_index = (FT_UShort) gindex;
+  }
+
+
+
+
+  /* Important: this function is called from the cache manager to */
+  /* destroy a given cache node during "cache compression". The   */
+  /* second argument is always "cache.user_data". You thus be     */
+  /* certain that the function FTC_Image_Cache_New does indeed    */
+  /* set its "user_data" field correctly, otherwise bad things    */
+  /* will happen !!                                               */
+  
+  FT_EXPORT_FUNC(void)  FTC_GlyphNode_Destroy( FTC_GlyphNode    node,
+                                               FTC_Glyph_Cache  cache )
+  {
+    FT_LruNode       queue_lru = cache->queues_lru->nodes+node->queue_index;
+    FTC_Glyph_Queue  queue     = (FTC_Glyph_Queue)queue_lru->root.data;
+    FT_UInt          hash      = node->glyph_index % queue->hash_size;
+    FT_List          bucket    = queue->buckets + hash;
+    
+    /* remove node from its queue's bucket list */
+    FT_List_Remove( bucket, FTC_GLYPHNODE_TO_LISTNODE(node) );
+    
+    /* destroy the node */
+    queue->clazz->destroy_node( node, queue );
+  }
+
+  
+  /* Important: this function is called from the cache manager to */
+  /* size a given cache node during "cache compression". The      */
+  /* second argument is always "cache.user_data". You thus be     */
+  /* certain that the function FTC_Image_Cache_New does indeed    */
+  /* set its "user_data" field correctly, otherwise bad things    */
+  /* will happen !!                                               */
+  
+  FT_EXPORT_FUNC(FT_ULong)  FTC_GlyphNode_Size( FTC_GlyphNode    node,
+                                                FTC_Glyph_Cache  cache )
+  {
+    FT_LruNode       queue_lru = cache->queues_lru->nodes+node->queue_index;
+    FTC_Glyph_Queue  queue     = (FTC_Glyph_Queue)queue_lru->root.data;
+    
+    return queue->clazz->size_node( node, queue );
+  }
+
+
+  FT_CPLUSPLUS(const FTC_CacheNode_Class)   ftc_glyph_cache_node_class =
+  {
+    (FTC_CacheNode_SizeFunc)     FTC_GlyphNode_Size,
+    (FTC_CacheNode_DestroyFunc)  FTC_GlyphNode_Destroy
+  };
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      GLYPH QUEUES                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_EXPORT_FUNC(FT_Error)  FTC_Glyph_Queue_New(
+                                 FTC_Glyph_Cache   cache,
+                                 FT_Pointer        type,
+                                 FTC_Glyph_Queue*  aqueue )
+  {
+    FT_Error         error;
+    FT_Memory        memory  = cache->root.memory;
+    FTC_Manager      manager = cache->root.manager;
+    FTC_Glyph_Queue  queue   = 0;
+    
+    FTC_Glyph_Cache_Class* gcache_class;
+    FTC_Glyph_Queue_Class* clazz;
+    
+    gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
+    clazz        = gcache_class->queue_class;
+    
+    *aqueue = 0;
+    
+    if ( ALLOC( queue, clazz->queue_byte_size ) )
+      goto Exit;
+    
+    queue->cache     = cache;
+    queue->manager   = manager;
+    queue->memory    = memory;
+    queue->hash_size = FTC_QUEUE_HASH_SIZE_DEFAULT;
+    queue->clazz     = clazz;
+
+    /* allocate buckets table */
+    if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
+    if (error)
+      goto Exit;
+
+    /* initialize queue by type - if needed */
+    if (clazz->init)
+    {
+      error = clazz->init( queue, type );
+      if (error)
+        goto Exit;
+    }
+
+    *aqueue = queue;
+
+  Exit:
+    if ( error && queue )
+    {
+      FREE( queue->buckets );
+      FREE( queue );
+    }
+
+    return error;
+  }                                  
+
+
+
+  FT_EXPORT_FUNC(void)  FTC_Glyph_Queue_Done( FTC_Glyph_Queue  queue )
+  {
+    FTC_Glyph_Cache  cache        = queue->cache;
+    FTC_Manager      manager      = cache->root.manager;
+    FT_List          glyphs_lru   = &manager->global_lru;
+    FT_List          bucket       = queue->buckets;
+    FT_List          bucket_limit = bucket + queue->hash_size;
+    FT_Memory        memory       = cache->root.memory;
+    
+    FTC_Glyph_Queue_Class*  clazz = queue->clazz;
+
+    /* for each bucket, free the list of Glyph nodes */
+    for ( ; bucket < bucket_limit; bucket++ )
+    {
+      FT_ListNode    node = bucket->head;
+      FT_ListNode    next = 0;
+      FT_ListNode    lrunode;
+      FTC_GlyphNode  inode;
+      
+
+      for ( ; node; node = next )
+      {
+        next    = node->next;
+        inode   = FTC_LISTNODE_TO_GLYPHNODE(node);
+        lrunode = FTC_GLYPHNODE_TO_LRUNODE( inode );
+        
+        manager->num_bytes -= clazz->size_node( inode, queue );
+        
+        FT_List_Remove( glyphs_lru, lrunode );
+
+        clazz->destroy_node( inode, queue );
+      }
+      
+      bucket->head = bucket->tail = 0;
+    }
+
+    if (clazz->done)
+      clazz->done(queue);
+
+    FREE( queue->buckets );
+    FREE( queue );
+  }
+
+
+  FT_EXPORT_FUNC(FT_Error)  FTC_Glyph_Queue_Lookup_Node(
+                                         FTC_Glyph_Queue  queue,
+                                         FT_UInt          glyph_index,
+                                         FTC_GlyphNode*   anode )
+  {
+    FTC_Glyph_Cache       cache      = queue->cache;
+    FTC_Manager           manager    = cache->root.manager;
+    FT_UInt               hash_index = glyph_index % queue->hash_size;
+    FT_List               bucket     = queue->buckets + hash_index;
+    FT_ListNode           node;
+    FT_Error              error;
+    FTC_GlyphNode         inode;
+    
+    FTC_Glyph_Queue_Class*  clazz = queue->clazz;
+
+    *anode = 0;
+    for ( node = bucket->head; node; node = node->next )
+    {
+      FT_UInt  gindex;
+      
+      inode  = FTC_LISTNODE_TO_GLYPHNODE(node);
+      gindex = inode->glyph_index;
+      
+      if ( gindex == glyph_index )
+      {
+        /* we found it! -- move glyph to start of the lists */
+        FT_List_Up( bucket, node );
+        FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( inode ) );
+        *anode = inode;
+        return 0;
+      }
+    }
+
+    /* we didn't found the glyph image, we will now create a new one */
+    error = clazz->new_node( queue, glyph_index, &inode );
+    if ( error )
+      goto Exit;
+
+    /* insert the node at the start of our bucket list */
+    FT_List_Insert( bucket, FTC_GLYPHNODE_TO_LISTNODE(inode) );
+    
+    /* insert the node at the start the global LRU glyph list */
+    FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE(inode) );
+    
+    manager->num_bytes += clazz->size_node( inode, queue );
+
+    if (manager->num_bytes > manager->max_bytes)
+      FTC_Manager_Compress( manager );
+      
+    *anode = inode;
+
+  Exit:
+    return error;
+  }
+
+  
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                   GLYPH QUEUES LRU CALLBACKS                  *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+ 
+
+#define FTC_QUEUE_LRU_GET_CACHE( lru )   \
+          ( (FTC_Glyph_Cache)(lru)->user_data )
+          
+#define FTC_QUEUE_LRU_GET_MANAGER( lru ) \
+          FTC_QUEUE_LRU_GET_CACHE( lru )->manager
+          
+#define FTC_LRUNODE_QUEUE( node )        \
+          ( (FTC_Glyph_Queue)(node)->root.data )
+
+
+  LOCAL_FUNC_X
+  FT_Error  ftc_glyph_queue_lru_init( FT_Lru      lru,
+                                      FT_LruNode  node )
+  {
+    FTC_Glyph_Cache  cache = FTC_QUEUE_LRU_GET_CACHE( lru );
+    FT_Error         error;
+    FTC_Glyph_Queue  queue;
+
+    error = FTC_Glyph_Queue_New( cache,
+                                 (FT_Pointer)node->key,
+                                 &queue );
+    if ( !error )
+    {
+      /* good, now set the queue index within the queue object */
+      queue->queue_index = node - lru->nodes;
+      node->root.data    = queue;
+    }
+    
+    return error;
+  }
+
+
+
+  LOCAL_FUNC_X
+  void  ftc_glyph_queue_lru_done( FT_Lru      lru,
+                                  FT_LruNode  node )
+  {
+    FTC_Glyph_Queue  queue = FTC_LRUNODE_QUEUE( node );
+    
+    FT_UNUSED( lru );
+
+
+    FTC_Glyph_Queue_Done( queue );
+  }
+
+
+
+  LOCAL_FUNC_X
+  FT_Bool  ftc_glyph_queue_lru_compare( FT_LruNode  node,
+                                        FT_LruKey   key )
+  {
+    FTC_Glyph_Queue  queue = FTC_LRUNODE_QUEUE( node );
+    return queue->clazz->compare( queue, (FT_Pointer)key );
+  }                                            
+
+
+
+  FT_CPLUSPLUS( const FT_Lru_Class )  ftc_glyph_queue_lru_class =
+  {
+    sizeof( FT_LruRec ),
+    ftc_glyph_queue_lru_init,
+    ftc_glyph_queue_lru_done,
+    0,  /* no flush */
+    ftc_glyph_queue_lru_compare
+  };
+
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                GLYPH IMAGE CACHE OBJECTS                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+ 
+
+  FT_EXPORT_FUNC(FT_Error)   FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache )
+  {
+    FT_Memory               memory = cache->root.memory;
+    FT_Error                error;
+
+    /* set up root node_class to be used by manager */
+    cache->root.node_clazz = (FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
+    
+    /* The following is extremely important for ftc_destroy_glyph_image */
+    /* to work properly, as the second parameter that is sent to it     */
+    /* through the cache manager is "user_data" and must be set to      */
+    /* "cache" here..                                                   */
+    /*                                                                  */
+    cache->root.cache_user = cache;
+
+    error = FT_Lru_New( &ftc_glyph_queue_lru_class,
+                        FTC_MAX_GLYPH_QUEUES,
+                        cache,
+                        memory,
+                        1, /* pre_alloc == TRUE */
+                        &cache->queues_lru );
+    return error;
+  }
+
+
+  FT_EXPORT_FUNC(void)    FTC_Glyph_Cache_Done( FTC_Glyph_Cache  cache )
+  {
+    /* discard Glyph queues */
+    FT_Lru_Done( cache->queues_lru );
+  }
+
+
+
+/* END */
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -1,146 +1,58 @@
-/***************************************************************************/
-/*                                                                         */
-/*  ftcimage.c                                                             */
-/*                                                                         */
-/*    FreeType Image Cache (body).                                         */
-/*                                                                         */
-/*  Copyright 2000 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.                                        */
-/*                                                                         */
-/***************************************************************************/
+#ifdef FT_FLAT_COMPILE
+#  include "ftcimage.h"
+#else
+#  include <cache/ftcimage.h>
+#endif
 
-
-#include <cache/ftcimage.h>
-#include <freetype/fterrors.h>
-#include <freetype/internal/ftobjs.h>
-#include <freetype/internal/ftlist.h>
-#include <freetype/fterrors.h>
-
-
- /**************************************************************************/
- /**************************************************************************/
- /*****                                                                *****/
- /*****                      IMAGE NODE MANAGEMENT                     *****/
- /*****                                                                *****/
- /*****  For now, we simply ALLOC/FREE the FTC_ImageNode.  However, it *****/
- /*****  certainly is a good idea to use a chunk manager in the future *****/
- /*****  in order to reduce memory waste resp. fragmentation.          *****/
- /*****                                                                *****/
- /**************************************************************************/
- /**************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                    GLYPH IMAGE NODES                          *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
  
-
-  static
-  FT_Error  FTC_ImageNode_New( FTC_Image_Cache  cache,
-                               FTC_ImageNode*   anode )
+  /* this is a simple glyph image destructor, which is called exclusively */
+  /* from the CacheQueue object                                           */
+  LOCAL_FUNC_X
+  void  ftc_glyph_image_node_destroy( FTC_GlyphNode    node,
+                                      FTC_Glyph_Queue  queue )
   {
-    FT_Error       error;
-    FT_Memory      memory = cache->memory;
-    FTC_ImageNode  node;
+    FT_Memory  memory = queue->memory;
     
-
-    *anode = 0;
-    if ( !ALLOC( node, sizeof ( *node ) ) )
-      *anode = node;
-      
-    return error;
-  }                                      
-
-
-  static
-  void  FTC_ImageNode_Done( FTC_Image_Cache  cache,
-                            FTC_ImageNode    node )
-  {
-    /* for now, we simply discard the node;  we may later add a chunk */
-    /* manager to the image cache.                                    */
-    FT_Memory  memory = cache->memory;
-
-
+    FT_Done_Glyph( FTC_GLYPHNODE_GET_GLYPH( node ) );
     FREE( node );
-  }                                     
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                      GLYPH IMAGE QUEUES                       *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
- 
-
-  LOCAL_FUNC_X
-  void  ftc_done_glyph_image( FTC_Image_Queue  queue,
-                              FTC_ImageNode    node )
-  {
-    FT_UNUSED( queue );
-
-    FT_Done_Glyph( FTC_IMAGENODE_GET_GLYPH( node ) );
   }
 
 
   LOCAL_FUNC_X
-  FT_ULong  ftc_size_bitmap_image( FTC_Image_Queue  queue,
-                                   FTC_ImageNode    node )
-  {
-    FT_Long         pitch;
-    FT_BitmapGlyph  glyph;
-    
-    FT_UNUSED( queue );
-
-
-    glyph = (FT_BitmapGlyph)FTC_IMAGENODE_GET_GLYPH(node);
-    pitch = glyph->bitmap.pitch;
-    if ( pitch < 0 )
-      pitch = -pitch;
-      
-    return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) );
-  }
-
-
-  LOCAL_FUNC_X
-  FT_ULong  ftc_size_outline_image( FTC_Image_Queue  queue,
-                                    FTC_ImageNode    node )
-  {
-    FT_OutlineGlyph  glyph;
-    FT_Outline*      outline;
-    
-    FT_UNUSED( queue );
-
-
-    glyph   = (FT_OutlineGlyph)FTC_IMAGENODE_GET_GLYPH( node );
-    outline = &glyph->outline;
-    
-    return (FT_ULong)( 
-      outline->n_points *  ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
-      outline->n_contours * sizeof ( FT_Short )                          +
-      sizeof( *glyph ) );
-  }
-
-
-  LOCAL_FUNC_X
-  FT_Error  ftc_init_glyph_image( FTC_Image_Queue  queue,
-                                  FTC_ImageNode    node )
+  FT_Error  ftc_glyph_image_node_new( FTC_Glyph_Queue  queue,
+                                      FT_UInt          glyph_index,
+                                      FTC_GlyphNode   *anode )
   {  
-    FT_Face   face;
-    FT_Size   size;
-    FT_Error  error;
+    FT_Memory        memory   = queue->memory;
+    FTC_Image_Queue  imageq = (FTC_Image_Queue)queue;
+    FT_Error         error;
+    FTC_GlyphNode    node = 0;
+    FT_Face          face;
+    FT_Size          size;
 
+    /* allocate node */
+    if ( ALLOC( node, sizeof(*node) ) )
+      goto Exit;
 
+    /* init its inner fields */
+    FTC_GlyphNode_Init( node, queue, glyph_index );
+
+    /* we will now load the glyph image */
     error = FTC_Manager_Lookup_Size( queue->manager,
-                                     &queue->descriptor.size,
+                                     &imageq->description.font,
                                      &face, &size );
     if ( !error )
     {
-      FT_UInt  glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
+      FT_UInt  glyph_index = node->glyph_index;
       FT_UInt  load_flags  = FT_LOAD_DEFAULT;
-      FT_UInt  image_type  = queue->descriptor.image_type;
+      FT_UInt  image_type  = imageq->description.image_type;
       
       if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
       {           
@@ -179,373 +91,134 @@
           
           error = FT_Get_Glyph( face->glyph, &glyph );
           if ( !error )
-            FTC_IMAGENODE_SET_GLYPH( node, glyph );
+            FTC_GLYPHNODE_SET_GLYPH( node, glyph );
         }
         else
           error = FT_Err_Invalid_Argument;
       }
     }
-    return error;
-  }
-
-
-  FT_CPLUSPLUS( const FTC_Image_Class )  ftc_bitmap_image_class =
-  {
-    ftc_init_glyph_image,
-    ftc_done_glyph_image,
-    ftc_size_bitmap_image
-  };
-  
-  FT_CPLUSPLUS( const FTC_Image_Class )  ftc_outline_image_class =
-  {
-    ftc_init_glyph_image,
-    ftc_done_glyph_image,
-    ftc_size_outline_image
-  };
-  
-
-  static
-  FT_Error  FTC_Image_Queue_New( FTC_Image_Cache   cache,
-                                 FTC_Image_Desc*   desc,
-                                 FTC_Image_Queue*  aqueue )
-  {
-    FT_Error         error;
-    FT_Memory        memory  = cache->memory;
-    FTC_Manager      manager = cache->manager;
-    FTC_Image_Queue  queue   = 0;
-    
-    const FTC_Image_Class*  clazz;
-    
-
-    *aqueue = 0;
-    if ( ALLOC( queue, sizeof ( *queue ) ) )
-      goto Exit;
-    
-    queue->cache      = cache;
-    queue->manager    = manager;
-    queue->memory     = memory;
-    queue->descriptor = *desc;
-    queue->hash_size  = 64;
-    
-    if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
-      goto Exit;
-
-    switch ( FTC_IMAGE_FORMAT( desc->image_type ) )
-    {
-    case ftc_image_format_bitmap:
-      clazz = &ftc_bitmap_image_class;
-      break;
-        
-    case ftc_image_format_outline:
-      clazz = &ftc_outline_image_class;
-      break;
-        
-    default:
-      /* invalid image type! */
-      error = FT_Err_Invalid_Argument;
-      goto Exit;
-    }
-
-    queue->clazz = (FTC_Image_Class*)clazz;
-    *aqueue = queue;
-
   Exit:
-    if ( error )
-      FREE( queue );
+    if (error && node)
+      FREE(node);
 
+    *anode = node;
     return error;
-  }                                  
+  }
 
 
-  static
-  void  FTC_Image_Queue_Done( FTC_Image_Queue  queue )
+ /* this function is important, because it is both part of */
+ /* a FTC_Glyph_Queue_Class and a FTC_CacheNode_Class      */
+ /*                                                        */
+  LOCAL_FUNC_X
+  FT_ULong  ftc_glyph_image_node_size( FTC_GlyphNode    node )
   {
-    FTC_Image_Cache  cache        = queue->cache;
-    FT_List          glyphs_lru   = &cache->glyphs_lru;
-    FT_List          bucket       = queue->buckets;
-    FT_List          bucket_limit = bucket + queue->hash_size;
-    FT_Memory        memory       = cache->memory;
+    FT_ULong        size  = 0;
+    FT_Glyph        glyph = FTC_GLYPHNODE_GET_GLYPH(node);
     
-
-    /* for each bucket, free the list of image nodes */
-    for ( ; bucket < bucket_limit; bucket++ )
+    switch (glyph->format)
     {
-      FT_ListNode    node = bucket->head;
-      FT_ListNode    next = 0;
-      FT_ListNode    lrunode;
-      FTC_ImageNode  inode;
-      
-
-      for ( ; node; node = next )
-      {
-        next    = node->next;
-        inode   = (FTC_ImageNode)node;
-        lrunode = FTC_IMAGENODE_TO_LISTNODE( inode );
+      case ft_glyph_format_bitmap:
+        {
+          FT_BitmapGlyph  bitg;
+          
+          bitg = (FT_BitmapGlyph)glyph;
+          size = bitg->bitmap.rows * labs(bitg->bitmap.pitch) +
+                 sizeof(*bitg);
+        }
+        break;
         
-        cache->num_bytes -= queue->clazz->size_image( queue, inode ) +
-                            sizeof( FTC_ImageNodeRec );
+      case ft_glyph_format_outline:
+        {
+          FT_OutlineGlyph  outg;
+          
+          outg = (FT_OutlineGlyph)glyph;
+          size = outg->outline.n_points * 
+                   ( sizeof( FT_Vector ) + sizeof( FT_Byte ) ) +
+                 outg->outline.n_contours *
+                     sizeof( FT_Short ) +
+                 sizeof(*outg);
+        }
+        break;
         
-        queue->clazz->done_image( queue, inode );
-        FT_List_Remove( glyphs_lru, lrunode );
-        
-        FTC_ImageNode_Done( cache, inode );
-      }
-      
-      bucket->head = bucket->tail = 0;
+      default:
+        ;
     }
-
-    FREE( queue->buckets );
-    FREE( queue );
+    size += sizeof(*node);
+    return size;
   }
 
 
-  static
-  FT_Error  FTC_Image_Queue_Lookup_Node( FTC_Image_Queue  queue,
-                                         FT_UInt          glyph_index,
-                                         FTC_ImageNode*   anode )
-  {
-    FTC_Image_Cache  cache      = queue->cache;
-    FT_UInt          hash_index = glyph_index % queue->hash_size;
-    FT_List          bucket     = queue->buckets + hash_index;
-    FT_ListNode      node;
-    FT_Error         error;
-    FTC_ImageNode    inode;
-    
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                    GLYPH IMAGE QUEUES                         *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
 
-    *anode = 0;
-    for ( node = bucket->head; node; node = node->next )
-    {
-      FT_UInt  gindex;
-      
-      inode  = (FTC_ImageNode)node;
-      gindex = FTC_IMAGENODE_GET_GINDEX( inode );
-      
-      if ( gindex == glyph_index )
-      {
-        /* we found it! -- move glyph to start of the list */
-        FT_List_Up( bucket, node );
-        FT_List_Up( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) );
-        *anode = inode;
-        return 0;
-      }
-    }
 
-    /* we didn't found the glyph image, we will now create a new one */
-    error = FTC_ImageNode_New( queue->cache, &inode );
-    if ( error )
-      goto Exit;
-
-    /* set the glyph and queue indices in the image node */
-    FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index );
-    
-    error = queue->clazz->init_image( queue, inode );
-    if ( error )
-    {
-      FTC_ImageNode_Done( queue->cache, inode );
-      goto Exit;
-    }
-    
-    /* insert the node at the start of our bucket list */
-    FT_List_Insert( bucket, (FT_ListNode)inode );
-    
-    /* insert the node at the start the global LRU glyph list */
-    FT_List_Insert( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) );
-    
-    cache->num_bytes += queue->clazz->size_image( queue, inode ) +
-                        sizeof( FTC_ImageNodeRec );
-
-    *anode = inode;
-
-  Exit:
-    return error;
-  }
-
-  
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                    IMAGE CACHE CALLBACKS                      *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
- 
-
-#define FTC_QUEUE_LRU_GET_CACHE( lru )   \
-          ( (FTC_Image_Cache)(lru)->user_data )
-#define FTC_QUEUE_LRU_GET_MANAGER( lru ) \
-          FTC_QUEUE_LRU_GET_CACHE( lru )->manager
-#define FTC_LRUNODE_QUEUE( node )        \
-          ( (FTC_Image_Queue)(node)->root.data )
-
-
   LOCAL_FUNC_X
-  FT_Error  ftc_image_cache_init_queue( FT_Lru      lru,
-                                        FT_LruNode  node )
+  FT_Error  ftc_image_queue_init( FTC_Image_Queue  queue,
+                                  FTC_Image_Desc*  type )
   {
-    FTC_Image_Cache  cache = FTC_QUEUE_LRU_GET_CACHE( lru );
-    FTC_Image_Desc*  desc  = (FTC_Image_Desc*)node->key;
-    FT_Error         error;
-    FTC_Image_Queue  queue;
-
-    
-    error = FTC_Image_Queue_New( cache, desc, &queue );
-    if ( !error )
-    {
-      /* good, now set the queue index within the queue object */
-      queue->index    = node - lru->nodes;
-      node->root.data = queue;
-    }
-    
-    return error;
+    queue->description = *type;
+    return 0;
   }
 
 
   LOCAL_FUNC_X
-  void  ftc_image_cache_done_queue( FT_Lru      lru,
-                                    FT_LruNode  node )
+  FT_Bool   ftc_image_queue_compare( FTC_Image_Queue   queue,
+                                     FTC_Image_Desc*   type )
   {
-    FTC_Image_Queue  queue = FTC_LRUNODE_QUEUE( node );
-    
-    FT_UNUSED( lru );
-
-
-    FTC_Image_Queue_Done( queue );
+    return !memcmp( &queue->description, type, sizeof(*type) );
   }
-
-
-  LOCAL_FUNC_X
-  FT_Bool  ftc_image_cache_compare_queue( FT_LruNode  node,
-                                          FT_LruKey   key )
-  {
-    FTC_Image_Queue  queue = FTC_LRUNODE_QUEUE( node );
-    FTC_Image_Desc*  desc2 = (FTC_Image_Desc*)key;
-    FTC_Image_Desc*  desc1 = &queue->descriptor;
-    
-
-    return ( desc1->size.face_id    == desc2->size.face_id    &&
-             desc1->size.pix_width  == desc2->size.pix_width  &&
-             desc1->size.pix_height == desc2->size.pix_height &&
-             desc1->image_type      == desc2->image_type      );
-  }                                            
-
-
-  FT_CPLUSPLUS( const FT_Lru_Class )  ftc_image_queue_lru_class =
-  {
-    sizeof( FT_LruRec ),
-    ftc_image_cache_init_queue,
-    ftc_image_cache_done_queue,
-    0,  /* no flush */
-    ftc_image_cache_compare_queue
-  };
-
-
-  /* compress image cache if necessary, i.e., discard all old glyph images */
-  /* until `cache.num_bytes' is less than `cache.max_bytes'.  Note that    */
-  /* this function will avoid to remove `new_node'.                        */
-  static
-  void  FTC_Image_Cache_Compress( FTC_Image_Cache  cache,
-                                  FTC_ImageNode    new_node )
-  {
-    while ( cache->num_bytes > cache->max_bytes )
-    {
-      FT_ListNode      cur;
-      FTC_Image_Queue  queue;
-      FT_UInt          glyph_index;
-      FT_UInt          hash_index;
-      FT_UInt          queue_index;
-      FT_ULong         size;
-      FTC_ImageNode    inode;
-      
+                                      
 
-      /* exit our loop if there isn't any glyph image left, or if       */
-      /* we reached the newly created node (which happens always at the */
-      /* start of the list)                                             */
-      
-      cur   = cache->glyphs_lru.tail;
-      inode = FTC_LISTNODE_TO_IMAGENODE( cur );
-      if ( !cur || inode == new_node )
-        break;
-        
-      glyph_index = FTC_IMAGENODE_GET_GINDEX( inode );
-      queue_index = FTC_IMAGENODE_GET_QINDEX( inode );
-      queue       = (FTC_Image_Queue)cache->queues_lru->
-                      nodes[queue_index].root.data;
-      hash_index  = glyph_index % queue->hash_size;
-      size        = queue->clazz->size_image( queue, inode ) +
-                    sizeof(FTC_ImageNodeRec);
-
-      FT_List_Remove( &cache->glyphs_lru, cur );
-      FT_List_Remove( queue->buckets + hash_index, (FT_ListNode)inode );
-      queue->clazz->done_image( queue, inode );
-      FTC_ImageNode_Done( cache, inode );
-      
-      cache->num_bytes -= size;
-    }
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_New( FTC_Manager       manager,
-                                                  FT_ULong          max_bytes,
-                                                  FTC_Image_Cache*  acache )
+  FT_CPLUSPLUS(const FTC_Glyph_Queue_Class)  ftc_glyph_image_queue_class =
   {
-    FT_Error         error;
-    FT_Memory        memory;
-    FTC_Image_Cache  cache;
+    sizeof( FTC_Image_QueueRec ),
     
+    (FTC_Glyph_Queue_InitFunc)     ftc_image_queue_init,
+    (FTC_Glyph_Queue_DoneFunc)     0,
+    (FTC_Glyph_Queue_CompareFunc)  ftc_image_queue_compare,
     
-    if ( !manager )
-      return FT_Err_Invalid_Cache_Handle;
+    (FTC_Glyph_Queue_NewNodeFunc)      ftc_glyph_image_node_new,
+    (FTC_Glyph_Queue_SizeNodeFunc)     ftc_glyph_image_node_size,
+    (FTC_Glyph_Queue_DestroyNodeFunc)  ftc_glyph_image_node_destroy
+  };
 
-    if ( !acache || !manager->library )
-      return FT_Err_Invalid_Argument;
 
-    *acache = 0;
-    memory  = manager->library->memory;
-    
-    if ( ALLOC( cache, sizeof ( *cache ) ) )
-      goto Exit;
-    
-    cache->manager   = manager;
-    cache->memory    = manager->library->memory;
-    cache->max_bytes = max_bytes;
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                    GLYPH IMAGE CACHE                          *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
 
-    error = FT_Lru_New( &ftc_image_queue_lru_class,
-                        FTC_MAX_IMAGE_QUEUES,
-                        cache,
-                        memory,
-                        1, /* pre_alloc == TRUE */
-                        &cache->queues_lru );
-    if ( error )
-      goto Exit;                        
-    
-    *acache = cache;
 
-  Exit:
-    if ( error )
-      FREE( cache );
-      
-    return error;
-  }                                                  
 
-
-  FT_EXPORT_DEF( void )  FTC_Image_Cache_Done( FTC_Image_Cache  cache )
+  FT_CPLUSPLUS(const FTC_Glyph_Cache_Class)  ftc_glyph_image_cache_class =
   {
-    FT_Memory  memory;
-    
+    {
+      sizeof( FTC_Glyph_CacheRec ),
+      (FTC_Cache_InitFunc)  FTC_Glyph_Cache_Init,
+      (FTC_Cache_DoneFunc)  FTC_Glyph_Cache_Done
+    },
+    (FTC_Glyph_Queue_Class*)  &ftc_glyph_image_queue_class
+  };
 
-    if ( !cache )
-      return;
 
-    memory = cache->memory;
-    
-    /* discard image queues */
-    FT_Lru_Done( cache->queues_lru );
-    
-    /* discard cache */
-    FREE( cache );
+  FT_EXPORT_FUNC( FT_Error )  FTC_Image_Cache_New( FTC_Manager       manager,
+                                                   FTC_Image_Cache*  acache )
+  {
+    return FTC_Manager_Register_Cache(
+              manager,
+              (FTC_Cache_Class*)&ftc_glyph_image_cache_class,
+              (FTC_Cache*)acache );
   }
+                                        
 
-
   FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_Lookup(
                                FTC_Image_Cache  cache,
                                FTC_Image_Desc*  desc,
@@ -553,9 +226,11 @@
                                FT_Glyph*        aglyph )
   {
     FT_Error         error;
-    FTC_Image_Queue  queue;
-    FTC_ImageNode    inode;
+    FTC_Glyph_Queue  queue;
+    FTC_GlyphNode    inode;
+    FTC_Manager      manager;
 
+    FTC_Image_Queue  img_queue;
 
     /* check for valid `desc' delayed to FT_Lru_Lookup() */
 
@@ -562,30 +237,33 @@
     if ( !cache || !aglyph )
       return FT_Err_Invalid_Argument;
 
-    *aglyph = 0;    
-    queue   = cache->last_queue;
-    if ( !queue                                                      ||
-          queue->descriptor.size.face_id    != desc->size.face_id    ||
-          queue->descriptor.size.pix_width  != desc->size.pix_width  ||
-          queue->descriptor.size.pix_height != desc->size.pix_height ||
-          queue->descriptor.image_type      != desc->image_type      )
+    *aglyph   = 0;    
+    queue     = cache->root.last_queue;
+    img_queue = (FTC_Image_Queue)queue;
+    if ( !queue || memcmp( &img_queue->description, desc, sizeof(*desc) ) )
     {
-      error = FT_Lru_Lookup( cache->queues_lru,
+      error = FT_Lru_Lookup( cache->root.queues_lru,
                              (FT_LruKey)desc,
                              (FT_Pointer*)&queue );
-      cache->last_queue = queue;
+      cache->root.last_queue = queue;
       if ( error )
         goto Exit;
     }
 
-    error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode );
+    error = FTC_Glyph_Queue_Lookup_Node( queue, gindex, &inode );
     if ( error )
       goto Exit;
 
-    if (cache->num_bytes > cache->max_bytes)
-      FTC_Image_Cache_Compress( cache, inode );
+    /* now compress the manager's cache pool if needed */
+    manager = cache->root.root.manager;
+    if (manager->num_bytes > manager->max_bytes)
+    {
+      FTC_GlyphNode_Ref(inode);
+      FTC_Manager_Compress( manager );
+      FTC_GlyphNode_Unref(inode);
+    }
 
-    *aglyph = FTC_IMAGENODE_GET_GLYPH( inode );
+    *aglyph = FTC_GLYPHNODE_GET_GLYPH( inode );
 
   Exit:
     return error;
@@ -592,4 +270,3 @@
   }
 
 
-/* END */
--- a/src/cache/ftcimage.h
+++ b/src/cache/ftcimage.h
@@ -1,137 +1,21 @@
-/***************************************************************************/
-/*                                                                         */
-/*  ftcimage.h                                                             */
-/*                                                                         */
-/*    FreeType Image Cache (specification).                                */
-/*                                                                         */
-/*  Copyright 2000 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 FTCIMAGE_H
 #define FTCIMAGE_H
 
-#include <cache/ftcmanag.h>
-#include <freetype/ftglyph.h>
-#include <stddef.h>
+#include <freetype/cache/ftcglyph.h>
 
-#ifdef __cplusplus
-  extern "C" {
-#endif
-
-#define FTC_MAX_IMAGE_QUEUES  16
-
-  typedef struct FTC_Image_QueueRec_*  FTC_Image_Queue;
-  typedef struct FTC_ImageNodeRec_*    FTC_ImageNode;
+ /* the glyph image queue type */
+  typedef struct FTC_Image_QueueRec_
+  {
+    FTC_Glyph_QueueRec  root;
+    FTC_Image_Desc      description;
   
+  } FTC_Image_QueueRec, *FTC_Image_Queue;
 
-  /* macros used to pack a glyph index and a queue index in a single ptr */  
-#define FTC_PTR_TO_GINDEX( p )  ( (FT_UInt)( (FT_ULong)(p) >> 16 ) )
-#define FTC_PTR_TO_QINDEX( p )  ( (FT_UInt)( (FT_ULong)(p) & 0xFFFF ) ) 
-#define FTC_INDICES_TO_PTR( g, q )                      \
-          ( (FT_Pointer)( ( (FT_ULong)(g) << 16 )   |   \
-                          ( (FT_ULong)(q) & 0xFFFF) ) )
-    
-  typedef struct  FTC_ImageNodeRec_
+  typedef struct FTC_Image_CacheRec_
   {
-    /* root1.data contains an FT_Glyph handle          */
-    FT_ListNodeRec  root1;
-
-    /* root2.data contains a glyph index + queue index */
-    FT_ListNodeRec  root2;
- 
-  } FTC_ImageNodeRec;
-
-
-  /* macros to read/set the glyph & queue index in a FTC_ImageNode */
-#define FTC_IMAGENODE_GET_GINDEX( n )  FTC_PTR_TO_GINDEX( (n)->root2.data )
-#define FTC_IMAGENODE_GET_QINDEX( n )  FTC_PTR_TO_QINDEX( (n)->root2.data )
-#define FTC_IMAGENODE_GET_GLYPH( n )   ( (FT_Glyph)(n)->root1.data )
-#define FTC_IMAGENODE_SET_GLYPH( n, g ) \
-          do                            \
-          {                             \
-            (n)->root1.data = g;        \
-          } while ( 0 )
-          
-#define FTC_IMAGENODE_SET_INDICES( n, g, q )              \
-          do                                              \
-          {                                               \
-            (n)->root2.data = FTC_INDICES_TO_PTR( g, q ); \
-          } while ( 0 )
-
-
-  /* this macro is used to extract a handle to the global LRU list node */
-  /* corresponding to a given image node                                */
-#define FTC_IMAGENODE_TO_LISTNODE( n ) \
-          ( (FT_ListNode)&(n)->root2 )
-
-  /* this macro is used to extract a handle to a given image node from */
-  /* the corresponding LRU glyph list node. That's a bit hackish..     */
-#define FTC_LISTNODE_TO_IMAGENODE( p )                              \
-          ( (FTC_ImageNode)( (char*)(p) -                           \
-                             offsetof( FTC_ImageNodeRec,root2 ) ) )
-
-
-  typedef struct  FTC_Image_CacheRec_
-  {
-    FTC_Manager      manager;
-    FT_Memory        memory;
+    FTC_Glyph_CacheRec  root;
     
-    FT_ULong         max_bytes;   /* maximum size of cache in bytes */
-    FT_ULong         num_bytes;   /* current size of cache in bytes */
-    
-    FT_Lru           queues_lru;  /* static queues lru list          */
-    FT_ListRec       glyphs_lru;  /* global lru list of glyph images */
-    
-    FTC_Image_Queue  last_queue;  /* small cache */
-
   } FTC_Image_CacheRec;
 
-
-  /* a table of functions used to generate/manager glyph images */
-  typedef struct  FTC_Image_Class_
-  {
-    FT_Error  (*init_image)( FTC_Image_Queue  queue,
-                             FTC_ImageNode    node );
-                                
-    void      (*done_image)( FTC_Image_Queue  queue,
-                             FTC_ImageNode    node );
-                                
-    FT_ULong  (*size_image)( FTC_Image_Queue  queue,
-                             FTC_ImageNode    node );
-
-  } FTC_Image_Class;
-
-
-  typedef struct  FTC_Image_QueueRec_
-  {
-    FTC_Image_Cache   cache;
-    FTC_Manager       manager;
-    FT_Memory         memory;
-    FTC_Image_Class*  clazz;
-    FTC_Image_Desc    descriptor;
-    FT_UInt           hash_size;
-    FT_List           buckets;
-    FT_UInt           index;     /* index in parent cache  */
-
-  } FTC_Image_QueueRec;
-
-
-
-#ifdef __cplusplus
-  }
-#endif
-
-
 #endif /* FTCIMAGE_H */
 
-
-/* END */
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -16,9 +16,13 @@
 /***************************************************************************/
 
 
-#include <cache/ftcmanag.h>
+#include <freetype/cache/ftcmanag.h>
 #include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/ftlist.h>
 
+#undef   FT_COMPONENT
+#define  FT_COMPONENT  trace_cache
 
 #define FTC_LRU_GET_MANAGER( lru )  (FTC_Manager)lru->user_data
 
@@ -38,6 +42,7 @@
   {
     FTC_Manager  manager = FTC_LRU_GET_MANAGER( lru );
     FT_Error     error;
+    FT_Face      face;
     
 
     error = manager->request_face( (FTC_FaceID)node->key,
@@ -47,9 +52,7 @@
     if ( !error )
     {
       /* destroy initial size object; it will be re-created later */
-      FT_Face  face = (FT_Face)node->root.data;
-
-
+      face = (FT_Face)node->root.data;
       FT_Done_Size( face->size );
     }
 
@@ -89,13 +92,13 @@
   }
 
 
-  typedef struct  FTC_SizeRequest_
+  typedef struct  FTC_FontRequest_
   {
     FT_Face    face;
     FT_UShort  width;
     FT_UShort  height;
     
-  } FTC_SizeRequest;
+  } FTC_FontRequest;
 
 
   LOCAL_FUNC_X
@@ -102,10 +105,10 @@
   FT_Error  ftc_manager_init_size( FT_Lru      lru,
                                    FT_LruNode  node )
   {
-    FTC_SizeRequest*  size_req = (FTC_SizeRequest*)node->key;
+    FTC_FontRequest*  font_req = (FTC_FontRequest*)node->key;
     FT_Size           size;
     FT_Error          error;
-    FT_Face           face = size_req->face;
+    FT_Face           face = font_req->face;
     
     FT_UNUSED( lru );
 
@@ -116,8 +119,8 @@
     {
       face->size = size;
       error = FT_Set_Pixel_Sizes( face,
-                                  size_req->width,
-                                  size_req->height );
+                                  font_req->width,
+                                  font_req->height );
       if ( error )
         FT_Done_Size( size );
       else
@@ -142,7 +145,7 @@
                                     FT_LruNode  node,
                                     FT_LruKey   key )
   {
-    FTC_SizeRequest*  req  = (FTC_SizeRequest*)key;
+    FTC_FontRequest*  req  = (FTC_FontRequest*)key;
     FT_Size           size = (FT_Size)node->root.data;
     FT_Error          error;
     
@@ -168,7 +171,7 @@
   FT_Bool  ftc_manager_compare_size( FT_LruNode  node,
                                      FT_LruKey   key )
   {
-    FTC_SizeRequest*  req  = (FTC_SizeRequest*)key;
+    FTC_FontRequest*  req  = (FTC_FontRequest*)key;
     FT_Size           size = (FT_Size)node->root.data;
     
     FT_UNUSED( node );
@@ -203,6 +206,7 @@
   FT_EXPORT_FUNC( FT_Error )  FTC_Manager_New( FT_Library          library,
                                                FT_UInt             max_faces,
                                                FT_UInt             max_sizes,
+                                               FT_ULong            max_bytes,
                                                FTC_Face_Requester  requester,
                                                FT_Pointer          req_data,
                                                FTC_Manager*        amanager )
@@ -221,11 +225,14 @@
       goto Exit;
     
     if ( max_faces == 0 )
-      max_faces = FTC_MAX_FACES;
+      max_faces = FTC_MAX_FACES_DEFAULT;
       
     if ( max_sizes == 0 )
-      max_sizes = FTC_MAX_SIZES;
+      max_sizes = FTC_MAX_SIZES_DEFAULT;
       
+    if ( max_bytes == 0 )
+      max_bytes = FTC_MAX_BYTES_DEFAULT;
+      
     error = FT_Lru_New( &ftc_face_lru_class,
                         max_faces,
                         manager,
@@ -245,6 +252,7 @@
       goto Exit;
     
     manager->library      = library;
+    manager->max_bytes    = max_bytes;
     manager->request_face = requester;
     manager->request_data = req_data;
     *amanager = manager;
@@ -264,6 +272,7 @@
   FT_EXPORT_DEF( void )  FTC_Manager_Done( FTC_Manager  manager )
   {
     FT_Memory  memory;
+    FT_UInt    index;
     
 
     if ( !manager || !manager->library )
@@ -271,8 +280,24 @@
 
     memory = manager->library->memory;
 
+    /* now discard all caches */
+    for (index = 0; index < FTC_MAX_CACHES; index++ )
+    {
+      FTC_Cache  cache = manager->caches[index];
+      
+      
+      if (cache)
+      {
+        cache->clazz->done_cache( cache );
+        FREE(cache);
+        manager->caches[index] = 0;
+      }
+    }
+    
+    /* discard faces and sizes */
     FT_Lru_Done( manager->sizes_lru );
     FT_Lru_Done( manager->faces_lru );
+    
     FREE( manager );
   }
 
@@ -279,11 +304,11 @@
 
   FT_EXPORT_DEF( void )  FTC_Manager_Reset( FTC_Manager  manager )
   {
-    if ( !manager )
-      return;
-
-    FT_Lru_Reset( manager->sizes_lru );
-    FT_Lru_Reset( manager->faces_lru );
+    if (manager )
+    {
+      FT_Lru_Reset( manager->sizes_lru );
+      FT_Lru_Reset( manager->faces_lru );
+    }
   }
 
 
@@ -298,14 +323,14 @@
                            (FT_LruKey)face_id, 
                            (FT_Pointer*)aface );
   }
- 
- 
+
+
   FT_EXPORT_DEF( FT_Error )  FTC_Manager_Lookup_Size( FTC_Manager  manager,
-                                                      FTC_SizeID   size_id,
+                                                      FTC_Font     font,
                                                       FT_Face*     aface,
                                                       FT_Size*     asize )
   {
-    FTC_SizeRequest  req;
+    FTC_FontRequest  req;
     FT_Error         error;
     FT_Face          face;
     
@@ -318,7 +343,7 @@
     if ( asize )
       *asize = 0;
 
-    error = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face ); 
+    error = FTC_Manager_Lookup_Face( manager, font->face_id, &face ); 
     if ( !error )
     {
       FT_Size  size;
@@ -325,8 +350,8 @@
       
 
       req.face   = face;
-      req.width  = size_id->pix_width;
-      req.height = size_id->pix_height;
+      req.width  = font->pix_width;
+      req.height = font->pix_height;
       
       error = FT_Lru_Lookup( manager->sizes_lru,
                              (FT_LruKey)&req,
@@ -347,5 +372,99 @@
     return error;
   }
 
+
+  /* "compress" the manager's data, i.e. get rids of old cache nodes */
+  /* that are not referenced anymore in order to limit the total     */
+  /* memory used by the cache..                                      */
+  FT_EXPORT_FUNC(void)  FTC_Manager_Compress( FTC_Manager  manager )
+  {
+    FT_ListNode  node;
+    
+    node = manager->global_lru.tail;
+    while (manager->num_bytes > manager->max_bytes && node)
+    {
+      FTC_CacheNode        cache_node = FTC_LIST_TO_CACHENODE(node);
+      FTC_CacheNode_Data*  data       = FTC_CACHENODE_TO_DATA_P(cache_node);
+      FTC_Cache            cache;
+      FT_ListNode          prev       = node->prev;
+      
+      if (data->ref_count <= 0)
+      {
+        /* ok, we're going to remove this node */
+        FT_List_Remove( &manager->global_lru, node );
+      
+        /* finalize cache node */
+        cache = manager->caches[data->cache_index];
+        if (cache)
+        {
+          FTC_CacheNode_Class*  clazz = cache->node_clazz;
+          
+          manager->num_bytes -= clazz->size_node( cache_node,
+                                                  cache->cache_user );
+                                                  
+          clazz->destroy_node( cache_node, cache->cache_user );
+        }
+        else
+        {
+          /* this should never happen !! */
+          FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted !!\n" ));
+        }
+      }
+      node = prev;
+    }
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )  FTC_Manager_Register_Cache(
+                                   FTC_Manager       manager,
+                                   FTC_Cache_Class*  clazz,
+                                   FTC_Cache        *acache )
+  {
+    FT_Error   error  = FT_Err_Invalid_Argument;
+    
+    
+    if ( manager && clazz && acache )
+    {
+      FT_Memory  memory = manager->library->memory;
+      FTC_Cache  cache;
+      FT_UInt    index = 0;
+
+      /* by default, return 0 */
+      *acache = 0;
+
+      /* check for an empty cache slot in the manager's table */
+      for ( index = 0; index < FTC_MAX_CACHES; index++ )
+      {
+        if ( manager->caches[index] == 0 )
+          break;
+      }
+      
+      /* return an error if there are too many registered caches */
+      if (index >= FTC_MAX_CACHES)
+      {
+        error = FT_Err_Too_Many_Caches;
+        FT_ERROR(( "FTC_Manager_Register_Cache:" ));
+        FT_ERROR(( " too many registered caches..\n" ));
+        goto Exit;
+      }
+      
+      if ( !ALLOC( cache, clazz->cache_byte_size ) )
+      {
+        cache->manager = manager;
+        cache->memory  = memory;
+        cache->clazz   = clazz;
+
+        if (clazz->init_cache)
+          error = clazz->init_cache( cache );
+        
+        if (error)
+          FREE(cache);
+        else
+          manager->caches[index] = *acache = cache;        
+      }
+    }
+  Exit:
+    return error;
+  }
 
 /* END */
--- a/src/cache/ftlru.c
+++ b/src/cache/ftlru.c
@@ -16,7 +16,7 @@
 /***************************************************************************/
 
 
-#include <cache/ftlru.h>
+#include <freetype/cache/ftlru.h>
 #include <freetype/internal/ftobjs.h>
 #include <freetype/internal/ftlist.h>
 
--- a/src/cache/rules.mk
+++ b/src/cache/rules.mk
@@ -15,9 +15,11 @@
 
 # Cache driver directory
 #
-Cache_DIR  := $(SRC_)cache
-Cache_DIR_ := $(Cache_DIR)$(SEP)
+CACHE_DIR  := $(SRC_)cache
+CACHE_DIR_ := $(CACHE_DIR)$(SEP)
 
+CACHE_H_DIR  := $(PUBLIC_)cache
+CACHE_H_DIR_ := $(CACHE_H_DIR)$(SEP)
 
 # compilation flags for the driver
 #
@@ -26,13 +28,17 @@
 
 # Cache driver sources (i.e., C files)
 #
-Cache_DRV_SRC := $(Cache_DIR_)ftlru.c    \
-                 $(Cache_DIR_)ftcmanag.c \
-                 $(Cache_DIR_)ftcimage.c
+Cache_DRV_SRC := $(CACHE_DIR_)ftlru.c    \
+                 $(CACHE_DIR_)ftcmanag.c \
+                 $(CACHE_DIR_)ftcglyph.c \
+                 $(CACHE_DIR_)ftcimage.c
 
 # Cache driver headers
 #
-Cache_DRV_H := $(Cache_DRV_SRC:%c=%h)
+Cache_DRV_H := $(CACHE_H_DIR_)ftlru.h    \
+               $(CACHE_H_DIR_)ftcmanag.h \
+               $(CACHE_H_DIR_)ftcglyph.h \
+               $(CACHE_DIR_)ftcimage.h
 
 
 # Cache driver object(s)
@@ -40,12 +46,12 @@
 #   Cache_DRV_OBJ_M is used during `multi' builds.
 #   Cache_DRV_OBJ_S is used during `single' builds.
 #
-Cache_DRV_OBJ_M := $(Cache_DRV_SRC:$(Cache_DIR_)%.c=$(OBJ_)%.$O)
+Cache_DRV_OBJ_M := $(Cache_DRV_SRC:$(CACHE_DIR_)%.c=$(OBJ_)%.$O)
 Cache_DRV_OBJ_S := $(OBJ_)ftcache.$O
 
 # Cache driver source file for single build
 #
-Cache_DRV_SRC_S := $(Cache_DIR_)ftcache.c
+Cache_DRV_SRC_S := $(CACHE_DIR_)ftcache.c
 
 
 # Cache driver - single object
@@ -57,7 +63,7 @@
 
 # Cache driver - multiple objects
 #
-$(OBJ_)%.$O: $(Cache_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H)
+$(OBJ_)%.$O: $(CACHE_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H)
 	$(Cache_COMPILE) $T$@ $<