shithub: freetype+ttf2subf

Download patch

ref: 3b2c50eb3b7863131ea18350a3ae5d48fbc567b9
parent: 8728f294bcc5d424337e10b33d40077366c79c36
author: David Turner <[email protected]>
date: Wed Aug 23 17:11:13 EDT 2000

completing the FreeType Cache subsystem files

git/fs: mount .git/fs: mount/attach disallowed
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
 LATEST CHANGES
 
+  - added the cache sub-system. See <freetype/ftcache.h> as well as the
+    sources in "src/cache". Note that it compiles but is still untested
+    for now ..
+
   - updated "docs/docmaker.py", a draft API reference is available at
     http://www.freetype.org/ft2api.html
 
--- /dev/null
+++ b/include/freetype/ftcache.h
@@ -1,0 +1,451 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcache.h                                                              */
+/*                                                                         */
+/*    FreeType Cache subsystem                                             */
+/*                                                                         */
+/*  Copyright 1996-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 FTCACHE_H
+#define FTCACHE_H
+
+#include <freetype/ftglyph.h>
+
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+ /*****                                                                *****/
+ /*****                     BASIC TYPE DEFINITIONS                     *****/
+ /*****                                                                *****/
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+
+ /**************************************************************************
+  *
+  *  <Type>
+  *     FTC_FaceID
+  *
+  *  <Description>
+  *     a generic pointer type that is used to identity face objects.
+  *     the content of such objects is application-dependent
+  *
+  **************************************************************************/
+  
+  typedef FT_Pointer  FTC_FaceID;
+
+
+  
+ /**************************************************************************
+  *
+  *  <FuncType>
+  *     FTC_Face_Requester
+  *
+  *  <Description>
+  *     a callback function provided by client applications. It is used
+  *     to translate a given FTC_FaceID into a new valid FT_Face object
+  *
+  *  <Input>
+  *     face_id :: the face id to resolve
+  *     library :: handle to a FreeType library object
+  *     data    :: application-provided request data
+  *
+  *  <Output>
+  *     aface   :: a new FT_Face handle
+  *
+  *  <Return>
+  *     Error code. 0 means success
+  *
+  **************************************************************************/
+  
+  typedef FT_Error  (*FTC_Face_Requester)( FTC_FaceID  face_id,
+                                           FT_Library  library,
+                                           FT_Pointer  request_data, 
+                                           FT_Face*    aface );
+
+
+ /**************************************************************************
+  *
+  *  <Struct>
+  *     FTC_SizeRec
+  *
+  *  <Description>
+  *     A simple structure used to describe a given "font size" to the
+  *     cache manager
+  *
+  *  <Fields>
+  *     face_id    :: id of face to use
+  *     pix_width  :: character width in integer pixels
+  *     pix_height :: character height in integer pixels
+  *
+  **************************************************************************/
+
+  typedef struct  FTC_SizeRec_
+  {
+    FTC_FaceID  face_id;
+    FT_UShort   pix_width;
+    FT_UShort   pix_height;
+    
+  } FTC_SizeRec;
+
+
+ /**************************************************************************
+  *
+  *  <Type>
+  *     FTC_SizeID
+  *
+  *  <Description>
+  *     A simple handle to a FTC_SizeRec structure
+  *
+  **************************************************************************/
+  
+  typedef FTC_SizeRec*  FTC_SizeID;
+ 
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+ /*****                                                                *****/
+ /*****                       CACHE MANAGER OBJECT                     *****/
+ /*****                                                                *****/
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+
+
+ /**************************************************************************
+  *
+  *  <Type>
+  *     FTC_Manager
+  *
+  *  <Description>
+  *     This object is used to cache one or more FT_Face object, along with
+  *     corresponding FT_Size objects.
+  *    
+  **************************************************************************/
+  
+  typedef struct FTC_ManagerRec_*  FTC_Manager;
+
+
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Manager_New
+  *
+  *  <Description>
+  *     Create a new cache manager.
+  *
+  *  <Input>
+  *     library   :: the parent FreeType library handle to use
+  *
+  *     requester :: an application-provided callback used to translate
+  *                  face IDs into real FT_Face objects
+  *
+  *     req_data  :: a generic pointer that is passed to the requester
+  *                  each time it is called (see FTC_Face_Requester)
+  *
+  *  <Output>
+  *     amanager  :: handle to new manager object. 0 in case of failure
+  *
+  *  <Return>
+  *     Error code. 0 means success
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( FT_Error )  FTC_Manager_New( FT_Library          library,
+                                              FTC_Face_Requester  requester,
+                                              FT_Pointer          req_data,
+                                              FTC_Manager*        amanager );
+
+
+                        
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Manager_Reset
+  *
+  *  <Description>
+  *     Empty a given cache manager. This simply gets rid of all the
+  *     currently cached FT_Face & FT_Size objects within the manager
+  *
+  *  <Input>
+  *     manager :: handle to manager
+  *
+  **************************************************************************/
+
+  FT_EXPORT_DEF( void )      FTC_Manager_Reset( FTC_Manager  manager );
+
+
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Manager_Done
+  *
+  *  <Description>
+  *     destroys a given manager after emptying it..
+  *
+  *  <Input>
+  *     manager :: handle to target cache manager object
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( void )      FTC_Manager_Done( FTC_Manager  manager );
+
+
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Manager_Lookup_Face
+  *
+  *  <Description>
+  *     retrieves the FT_Face that corresponds to a given face ID through
+  *     a cache manager.
+  *
+  *  <Input>
+  *     manager  :: handle to cache manager
+  *     face_id  :: ID of face object
+  *
+  *  <Output>
+  *     aface     :: handle to face object
+  *
+  *  <Return>
+  *     Error code. 0 means success
+  *
+  *  <Note>
+  *     The returned FT_Face object is always owned by the manager, you
+  *     should never try to discard it yourself..
+  *
+  *     The FT_Face object doesn't necessarily have a current size object
+  *     (i.e. face->size can be 0). If you need a specific "font size",
+  *     use FTC_Manager_Lookup_Size instead..
+  *
+  *     Never change the face's transform (i.e. NEVER CALL FT_Set_Transform)
+  *     on a returned face. If you need to transform glyphs, do it yourself
+  *     after glyph loading..
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( FT_Error )  FTC_Manager_Lookup_Face( FTC_Manager  manager,
+                                                      FTC_FaceID   face_id,
+                                                      FT_Face*     aface );
+ 
+
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Manager_Lookup_Size
+  *
+  *  <Description>
+  *     retrieves the FT_Face & FT_Size that correspond to a given
+  *     FTC_SizeID
+  *
+  *  <Input>
+  *     manager  :: handle to cache manager.
+  *     size_id  :: ID of the "font size" to use
+  *
+  *  <InOut>
+  *     aface    :: ptr to handle to face object. Set to 0 if you don't need it
+  *     asize    :: ptr to handle to size object. Set to 0 if you don't need it
+  *
+  *  <Return>
+  *     Error code. 0 means success
+  *
+  *  <Note>
+  *     The returned FT_Face object is always owned by the manager, you
+  *     should never try to discard it yourself..
+  *
+  *     Never change the face's transform (i.e. NEVER CALL FT_Set_Transform)
+  *     on a returned face. If you need to transform glyphs, do it yourself
+  *     after glyph loading..
+  *
+  *     The returned FT_Size object is always owned by the manager, you
+  *     should never try to discard it, NEVER CHANGE ITS SETTINGS THROUGH
+  *     FT_Set_Pixel_Sizes OR FT_Set_Char_Size !!
+  *
+  *     The returned size object is the face's current size, which means
+  *     that you can call FT_Load_Glyph with the face if you need to..
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( FT_Error )  FTC_Manager_Lookup_Size( FTC_Manager  manager,
+                                                      FTC_SizeID   size_id,
+                                                      FT_Face*     aface,
+                                                      FT_Size*     asize );
+
+  
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+ /*****                                                                *****/
+ /*****                        IMAGE CACHE OBJECT                      *****/
+ /*****                                                                *****/
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+ /**************************************************************************
+  *
+  *  <Enum>
+  *     FTC_Image_Type
+  *
+  *  <Description>
+  *     An enumeration used to list the types of glyph images found in a
+  *     glyph image cache.
+  *
+  *  <Fields>
+  *     ftc_image_mono     :: monochrome bitmap glyphs
+  *     ftc_image_grays    :: anti-aliased bitmap glyphs
+  *     ftc_image_outline  :: scaled (and hinted) outline glyphs
+  *     ftc_master_outline :: unscaled original outline glyphs
+  *
+  *  <Note>
+  *     other types may be defined in the future
+  *
+  **************************************************************************/
+
+  typedef enum  FTC_Image_Type_
+  {
+    ftc_image_mono = 0,         /* monochrome bitmap   */
+    ftc_image_grays,            /* anti-aliased bitmap */
+    ftc_image_outline,          /* scaled outline      */
+    ftc_image_master_outline    /* original outline    */
+  
+  } FTC_Image_Type;
+
+ 
+ /**************************************************************************
+  *
+  *  <Struct>
+  *     FTC_Image_Desc
+  *
+  *  <Description>
+  *     A simple structure used to describe a given glyph image category
+  *
+  *  <Fields>
+  *     size       :: a FTC_SizeRec used to describe the glyph's face & size
+  *     image_type :: the glyph image's type
+  *
+  **************************************************************************/
+
+  typedef struct FTC_Image_Desc_
+  {
+    FTC_SizeRec  size;
+    FT_UInt      image_type;
+  
+  } FTC_Image_Desc;
+
+
+
+ /**************************************************************************
+  *
+  *  <Type>
+  *     FTC_Image_Cache
+  *
+  *  <Description>
+  *     A handle to an glyph image cache object.. They are designed to
+  *     hold many distinct glyph images, while not exceeding a certain
+  *     memory threshold..
+  *
+  **************************************************************************/
+
+  typedef struct FTC_Image_CacheRec_*  FTC_Image_Cache; 
+
+
+
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Image_Cache_New
+  *
+  *  <Description>
+  *     Create a new glyph image cache.
+  *
+  *  <Input>
+  *     manager   :: parent manager for the image cache
+  *
+  *     max_bytes :: the maximum amount of memory that will be used to
+  *                  store glyph images
+  *
+  *  <Output>
+  *     acache    :: handle to new glyph image cache object
+  *
+  *  <Return>
+  *     Error code. 0 means success
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_New( FTC_Manager       manager,
+                                                  FT_ULong          max_bytes,
+                                                  FTC_Image_Cache*  acache );
+                                                
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Image_Cache_Done
+  *
+  *  <Description>
+  *     Destroys a given glyph image cache (and all glyphs within it).
+  *
+  *  <Input>
+  *     manager   :: parent manager for the image cache
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( void )      FTC_Image_Cache_Done( FTC_Image_Cache  cache );
+
+
+ /**************************************************************************
+  *
+  *  <Function>
+  *     FTC_Image_Cache_Lookup
+  *
+  *  <Description>
+  *     Retrieve a given glyph image from a glyph image cache.
+  *
+  *  <Input>
+  *     cache   :: handle to source glyph image cache
+  *     desc    :: pointer to a glyph image descriptor
+  *     gindex  :: index of glyph to retrieve
+  *
+  *  <Output>
+  *     aglyph  :: the corresponding FT_Glyph object. 0 in case of failure
+  *
+  *  <Return>
+  *     Error code. 0 means success
+  *
+  *  <Note>
+  *     the returned glyph is owned and manager by the glyph image cache,
+  *     never try to transform or discard it manually. You can however
+  *     create a copy with FT_Glyph_Copy and modify the new one at will.
+  *
+  *     Because the glyph image cache limits the total amount of memory
+  *     taken by the glyphs it holds, the returned glyph might disappear
+  *     on a later invocation of this function !! It's a cache after all ;-)
+  *
+  **************************************************************************/
+  
+  FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_Lookup(
+                               FTC_Image_Cache  cache,
+                               FTC_Image_Desc*  desc,
+                               FT_UInt          gindex,
+                               FT_Glyph*        aglyph );
+
+
+#endif /* FTCACHE_H */
--- /dev/null
+++ b/src/cache/ftcache.c
@@ -1,0 +1,36 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcache.c                                                              */
+/*                                                                         */
+/*    The FreeType Caching sub-system                                      */
+/*                                                                         */
+/*  Copyright 1996-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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#ifdef FT_FLAT_COMPILE
+
+#include "ftlru.c"
+#include "ftcmanag.c"
+#include "ftcimage.c"
+
+#else
+
+#include <cache/ftlru.c>
+#include <cache/ftcmanag.c>
+#include <cache/ftcimage.c>
+
+#endif
+
+
+/* END */
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -17,8 +17,61 @@
 
 
 #include <cache/ftcimage.h>
+#include <freetype/fterrors.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftlist.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/fragmentation       *****/
+ /*****                                                             *****/
+ /***********************************************************************/
+ /***********************************************************************/
+ 
+
   static
+  FT_Error  FTC_ImageNode_New( FTC_Image_Cache   cache,
+                               FTC_ImageNode    *anode )
+  {
+    FT_Error       error;
+    FT_Memory      memory = cache->memory;
+    FTC_ImageNode  node;
+    
+    *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;
+    FREE( node );
+  }                                     
+
+
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /*****                                                             *****/
+ /*****                      GLYPH IMAGE QUEUES                     *****/
+ /*****                                                             *****/
+ /***********************************************************************/
+ /***********************************************************************/
+ 
+
+  static
   void  ftc_done_glyph_image( FTC_Image_Queue  queue,
                               FTC_ImageNode    node )
   {
@@ -43,7 +96,7 @@
     if ( pitch < 0 )
       pitch = -pitch;
       
-    return (FT_ULong)(pitch * glyph->bitmap->rows + sizeof ( *glyph ) );
+    return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) );
   }
 
 
@@ -51,7 +104,6 @@
   FT_ULong  ftc_size_outline_image( FTC_Image_Queue  queue,
                                     FTC_ImageNode    node )
   {
-    FT_Long          pitch;
     FT_OutlineGlyph  glyph;
     FT_Outline*      outline;
     
@@ -68,14 +120,6 @@
   }
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****              MONOCHROME BITMAP CALLBACKS                      *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
   static
   FT_Error  ftc_init_mono_image( FTC_Image_Queue  queue,
                                  FTC_ImageNode    node )
@@ -84,13 +128,12 @@
     FT_Size   size;
     FT_Error  error;
 
-    
     error = FTC_Manager_Lookup_Size( queue->manager,
-                                     &queue->size_rec,
+                                     &queue->descriptor.size,
                                      &face, &size );
     if ( !error )
     {
-      FT_UInt  glyph_index = FTC_IMAGENODE_GINDEX( node );
+      FT_UInt  glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
 
       
       error = FT_Load_Glyph( face, glyph_index,
@@ -97,7 +140,7 @@
                              FT_LOAD_RENDER | FT_LOAD_MONOCHROME );
       if ( !error )
       {
-        if ( face->glyph->format            != ft_image_format_bitmap ||
+        if ( face->glyph->format            != ft_glyph_format_bitmap ||
              face->glyph->bitmap.pixel_mode != ft_pixel_mode_mono     )
         {
           /* there is no monochrome glyph for this font! */
@@ -129,11 +172,11 @@
     
 
     error = FTC_Manager_Lookup_Size( queue->manager,
-                                     &queue->size_rec,
+                                     &queue->descriptor.size,
                                      &face, &size );
     if ( !error )
     {
-      FT_UInt  glyph_index = FTC_IMAGENODE_GINDEX( node );
+      FT_UInt  glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
       
 
       error = FT_Load_Glyph( face, glyph_index,
@@ -140,10 +183,10 @@
                              FT_LOAD_RENDER );
       if ( !error )
       {
-        if ( face->glyph->format            != ft_image_format_bitmap ||
+        if ( face->glyph->format            != ft_glyph_format_bitmap ||
              face->glyph->bitmap.pixel_mode != ft_pixel_mode_grays )
         {
-          /* there is no monochrome glyph for this font! */
+          /* there is no anti-aliased glyph for this font! */
           error = FT_Err_Invalid_Glyph_Index;
         }
         else
@@ -158,6 +201,472 @@
         }
       }
     }
+    return error;
+  }
+
+
+  static
+  FT_Error  ftc_init_outline_image( FTC_Image_Queue  queue,
+                                    FTC_ImageNode    node )
+  {  
+    FT_Face   face;
+    FT_Size   size;
+    FT_Error  error;
+    
+
+    error = FTC_Manager_Lookup_Size( queue->manager,
+                                     &queue->descriptor.size,
+                                     &face, &size );
+    if ( !error )
+    {
+      FT_UInt  glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
+      
+
+      error = FT_Load_Glyph( face, glyph_index,
+                             FT_LOAD_NO_BITMAP );
+      if ( !error )
+      {
+        if ( face->glyph->format != ft_glyph_format_outline )
+        {
+          /* there is no outline glyph for this font! */
+          error = FT_Err_Invalid_Glyph_Index;
+        }
+        else
+        {
+          /* ok, copy it */
+          FT_Glyph  glyph;
+          
+          
+          error = FT_Get_Glyph( face->glyph, &glyph );
+          if ( !error )
+            FTC_IMAGENODE_SET_GLYPH( node, glyph );
+        }
+      }
+    }
+    return error;
+  }
+
+
+
+  static
+  FT_Error  ftc_init_master_outline_image( FTC_Image_Queue  queue,
+                                           FTC_ImageNode    node )
+  {  
+    FT_Face   face;
+    FT_Size   size;
+    FT_Error  error;
+    
+
+    error = FTC_Manager_Lookup_Size( queue->manager,
+                                     &queue->descriptor.size,
+                                     &face, &size );
+    if ( !error )
+    {
+      FT_UInt  glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
+      
+
+      error = FT_Load_Glyph( face, glyph_index,
+                             FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
+      if ( !error )
+      {
+        if ( face->glyph->format != ft_glyph_format_outline )
+        {
+          /* there is no outline glyph for this font! */
+          error = FT_Err_Invalid_Glyph_Index;
+        }
+        else
+        {
+          /* ok, copy it */
+          FT_Glyph  glyph;
+          
+          
+          error = FT_Get_Glyph( face->glyph, &glyph );
+          if ( !error )
+            FTC_IMAGENODE_SET_GLYPH( node, glyph );
+        }
+      }
+    }
+    return error;
+  }
+
+
+  static
+  const FTC_Image_Class   ftc_mono_image_class =
+  {
+    ftc_init_mono_image,
+    ftc_done_glyph_image,
+    ftc_size_bitmap_image
+  };
+  
+  static
+  const FTC_Image_Class   ftc_gray_image_class =
+  {
+    ftc_init_gray_image,
+    ftc_done_glyph_image,
+    ftc_size_bitmap_image
+  };
+  
+  static
+  const FTC_Image_Class   ftc_outline_image_class =
+  {
+    ftc_init_outline_image,
+    ftc_done_glyph_image,
+    ftc_size_outline_image
+  };
+  
+  static
+  const FTC_Image_Class   ftc_master_outline_image_class =
+  {
+    ftc_init_master_outline_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  = 32;
+    
+    if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
+      goto Exit;
+
+    switch (desc->image_type)
+    {
+      case ftc_image_mono:
+        clazz = &ftc_mono_image_class;
+        break;
+        
+      case ftc_image_grays:
+        clazz = &ftc_gray_image_class;
+        break;
+        
+      case ftc_image_outline:
+        clazz = &ftc_outline_image_class;
+        break;
+        
+      case ftc_image_master_outline:
+        clazz = &ftc_master_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 );
+
+    return error;
+  }                                  
+
+
+  static
+  void   FTC_Image_Queue_Done( FTC_Image_Queue  queue )
+  {
+    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;
+    
+    /* for each bucket, free the list of image nodes */
+    for ( ; bucket < bucket_limit; bucket++ )
+    {
+      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);
+        
+        queue->clazz->done_image( queue, inode );
+        FT_List_Remove( glyphs_lru, lrunode );
+        
+        FTC_ImageNode_Done( cache, inode );
+      }
+      
+      bucket->head = bucket->tail = 0;
+    }
+    FREE( queue->buckets );
+    FREE( queue );
+  }
+
+
+  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, next;
+    FT_Error         error;
+    FTC_ImageNode    inode;
+    
+    *anode = 0;
+    for ( node = bucket->head; node; node = next )
+    {
+      inode = (FTC_ImageNode)node;
+      
+      if ( FTC_IMAGENODE_GET_GINDEX(inode) == glyph_index )
+      {
+        /* we found it !! - move glyph to start of the list */
+        FT_List_Up( bucket, node );
+        *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;
+    
+    error = queue->clazz->init_image( queue, inode );
+    if (error)
+    {
+      FTC_ImageNode_Done( queue->cache, inode );
+      goto Exit;
+    }
+    
+    /* set the glyph and queue indices in the image node */
+    FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index );
+    
+    /* 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);
+
+    *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)
+
+  static
+  FT_Error   ftc_image_cache_init_queue( FT_Lru      lru,
+                                         FT_LruNode  node )
+  {
+    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;
+  }
+
+
+  static
+  void       ftc_image_cache_done_queue( FT_Lru      lru,
+                                         FT_LruNode  node )
+  {
+    FTC_Image_Queue  queue = FTC_LRUNODE_QUEUE(node);
+    
+    FT_UNUSED(lru);
+    FTC_Image_Queue_Done(queue);
+  }
+
+
+  static
+  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      );
+  }                                            
+
+
+
+  static
+  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 it needs it.. i.e. discards all old glyph images    */
+ /* until "cache.num_bytes" is under "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 = cache->glyphs_lru.tail;
+      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 is always at the */
+      /* start of the list..)                                      */
+      
+      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 );
+
+      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_Error         error;
+    FT_Memory        memory;
+    FTC_Image_Cache  cache;
+    
+    
+    *acache = 0;
+    memory  = manager->library->memory;
+    
+    if ( ALLOC( cache, sizeof(*cache) ) )
+      goto Exit;
+    
+    cache->manager   = manager;
+    cache->max_bytes = max_bytes;
+
+    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_Memory  memory = cache->memory;
+    
+    
+    /* discard image queues */
+    FT_Lru_Done( cache->queues_lru );
+    
+    /* discard cache */
+    FREE( cache );
+  }
+
+
+
+  FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_Lookup(
+                               FTC_Image_Cache  cache,
+                               FTC_Image_Desc*  desc,
+                               FT_UInt          gindex,
+                               FT_Glyph*        aglyph )
+  {
+    FT_Error         error;
+    FTC_Image_Queue  queue;
+    FTC_ImageNode    inode;
+
+    *aglyph = 0;    
+    error   = FT_Lru_Lookup( cache->queues_lru,
+                             (FT_LruKey)desc,
+                             (FT_Pointer*)&queue );
+    if (error)
+      goto Exit;
+
+    error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode );
+    if (error)
+      goto Exit;
+
+    FTC_Image_Cache_Compress( cache, inode );
+    *aglyph = FTC_IMAGENODE_GET_GLYPH(inode);
+
+  Exit:
     return error;
   }
 
--- a/src/cache/ftcimage.h
+++ b/src/cache/ftcimage.h
@@ -21,40 +21,18 @@
 
 #include <cache/ftcmanag.h>
 #include <freetype/ftglyph.h>
+#include <stddef.h>
 
-
 #ifdef __cplusplus
   extern "C" {
 #endif
 
+#define FTC_MAX_IMAGE_QUEUES  16
 
   typedef struct FTC_Image_QueueRec_*  FTC_Image_Queue;
-  typedef struct FTC_Image_CacheRec_*  FTC_Image_Cache; 
   typedef struct FTC_ImageNodeRec_*    FTC_ImageNode;
   
 
-  /* types of glyph images */
-  typedef enum  FTC_Image_Type_
-  {
-    ftc_image_mono = 0,         /* monochrome bitmap   */
-    ftc_image_grays,            /* anti-aliased bitmap */
-    ftc_image_outline,          /* scaled outline      */
-    ftc_image_master_outline,   /* original outline    */
-  
-  } FTC_Image_Type;
-
- 
-  /* a descriptor used to describe all glyphs in a given queue */
-  typedef struct FTC_Image_Desc_
-  {
-    FTC_FaceID  face_id;
-    FT_UInt     pix_width;
-    FT_UInt     pix_height;
-    FT_UInt     image_type;
-  
-  } FTC_Image_Desc;
-
-
   /* 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 ) ) 
@@ -76,7 +54,9 @@
   /* 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_SET_INDICES( g, q )                 \
+#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 ); \
@@ -83,6 +63,17 @@
           } 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;
@@ -91,9 +82,10 @@
     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_Lru       queues_lru;  /* static queues lru list          */
+    FT_ListRec   glyphs_lru;   /* global lru list of glyph images */
 
-  } FTC_Image_Cache;
+  } FTC_Image_CacheRec;
 
 
   /* a table of functions used to generate/manager glyph images */
@@ -100,13 +92,13 @@
   typedef struct  FTC_Image_Class_
   {
     FT_Error  (*init_image)( FTC_Image_Queue  queue,
-                             FTC_Image_Node   node );
+                             FTC_ImageNode    node );
                                 
     void      (*done_image)( FTC_Image_Queue  queue,
-                             FTC_Image_Node   node );
+                             FTC_ImageNode    node );
                                 
     FT_ULong  (*size_image)( FTC_Image_Queue  queue,
-                             FTC_Image_Node   node );
+                             FTC_ImageNode    node );
 
   } FTC_Image_Class;
 
@@ -120,21 +112,10 @@
     FTC_Image_Desc    descriptor;
     FT_UInt           hash_size;
     FT_List           buckets;
+    FT_UInt           index;     /* index in parent cache  */
 
-  } FTC_Image_SubCacheRec;
+  } FTC_Image_QueueRec;
 
-
-  FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_New( FTC_Manager       manager,
-                                                  FT_ULong          max_bytes,
-                                                  FTC_Image_Cache*  acache );
-                                                
-  FT_EXPORT_DEF( void )  FTC_Image_Cache_Done( FTC_Image_Cache  cache );
-  
-  FT_EXPORT_DEF( FT_Error )  FTC_Image_Cache_Lookup(
-                               FTC_Image_Cache  cache,
-                               FTC_Image_Desc*  desc,
-                               FT_UInt          gindex,
-                               FT_Glyph*        aglyph );
 
 
 #ifdef __cplusplus
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -20,7 +20,7 @@
 #include <freetype/internal/ftobjs.h>
 
 
-#define FTC_LRU_GET_MANAGER( lru )  ((FTC_Manager_Lru)lru)->manager
+#define FTC_LRU_GET_MANAGER( lru )  (FTC_Manager)lru->user_data
 
 
  /**************************************************************************/
@@ -40,6 +40,7 @@
     
 
     error = manager->request_face( (FTC_FaceID)node->key,
+                                   manager->library,
                                    manager->request_data,
                                    (FT_Face*)&node->root.data );
     if ( !error )
@@ -179,7 +180,7 @@
   static
   const FT_Lru_Class  ftc_face_lru_class =
   {
-    sizeof ( FTC_Manager_LruRec ),
+    sizeof ( FT_LruRec ),
     ftc_manager_init_face,
     ftc_manager_done_face,
     0,
@@ -190,7 +191,7 @@
   static
   const FT_Lru_Class  ftc_size_lru_class =
   {
-    sizeof ( FTC_Manager_LruRec ),
+    sizeof ( FT_LruRec ),
     ftc_manager_init_size,
     ftc_manager_done_size,
     ftc_manager_flush_size,
@@ -213,6 +214,7 @@
       
     error = FT_Lru_New( &ftc_face_lru_class,
                         FTC_MAX_FACES,
+                        manager,
                         memory,
                         1, /* pre_alloc = TRUE */
                         (FT_Lru*)&manager->faces_lru );
@@ -221,6 +223,7 @@
       
     error = FT_Lru_New( &ftc_size_lru_class,
                         FTC_MAX_SIZES,
+                        manager,
                         memory,
                         1, /* pre_alloc = TRUE */
                         (FT_Lru*)&manager->sizes_lru );                    
@@ -227,9 +230,6 @@
     if ( error )
       goto Exit;
     
-    ((FTC_Manager_Lru)manager->faces_lru)->manager = manager;
-    ((FTC_Manager_Lru)manager->sizes_lru)->manager = manager;
-
     manager->library      = library;
     manager->request_face = requester;
     manager->request_data = req_data;
@@ -275,6 +275,7 @@
   }
  
  
+ 
   FT_EXPORT_DEF( FT_Error )  FTC_Manager_Lookup_Size( FTC_Manager  manager,
                                                       FTC_SizeID   size_id,
                                                       FT_Face*     aface,
@@ -285,12 +286,17 @@
     FT_Face          face;
     
 
-    *aface = 0;
-    *asize = 0;
+    if (aface)
+      *aface = 0;
+      
+    if (asize)
+      *asize = 0;
 
     error  = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face ); 
     if ( !error )
     {
+      FT_Size  size;
+      
       req.face   = face;
       req.width  = size_id->pix_width;
       req.height = size_id->pix_height;
@@ -297,12 +303,17 @@
       
       error = FT_Lru_Lookup( manager->sizes_lru,
                              (FT_LruKey)&req,
-                             (FT_Pointer*)asize );
+                             (FT_Pointer*)&size );
       if ( !error )
       {
         /* select the size as the current one for this face */
         face->size = *asize;
-        *aface = face;
+        
+        if (asize)
+          *asize = size;
+          
+        if (aface)
+          *aface = face;
       }
     }
 
--- a/src/cache/ftcmanag.h
+++ b/src/cache/ftcmanag.h
@@ -19,6 +19,7 @@
 #ifndef FTCMANAG_H
 #define FTCMANAG_H
 
+#include <freetype/ftcache.h>
 #include <cache/ftlru.h>
 
 
@@ -31,32 +32,6 @@
 #define  FTC_MAX_SIZES  8
 
 
-  typedef FT_Pointer  FTC_FaceID;
-  
-  typedef struct  FTC_SizeRec_
-  {
-    FTC_FaceID  face_id;
-    FT_UShort   pix_width;
-    FT_UShort   pix_height;
-    
-  } FTC_SizeRec, *FTC_SizeID;
-
- 
-  typedef FT_Error  (*FTC_Face_Requester)( FTC_FaceID  face_id,
-                                           FT_Pointer  data, 
-                                           FT_Face*    aface );
-
-
-  typedef struct FTC_ManagerRec_*  FTC_Manager;
-
-  typedef struct  FTC_Manager_LruRec_
-  {
-    FT_LruRec    root;
-    FTC_Manager  manager;
-  
-  } FTC_Manager_LruRec, *FTC_Manager_Lru;
-
-
   typedef struct  FTC_ManagerRec_
   {
     FT_Library          library;
@@ -68,24 +43,6 @@
     
   } FTC_ManagerRec;
 
-
-  FT_EXPORT_DEF( FT_Error )  FTC_Manager_New( FT_Library          library,
-                                              FTC_Face_Requester  requester,
-                                              FT_Pointer          req_data,
-                                              FTC_Manager*        amanager );
-                        
-  FT_EXPORT_DEF( void )  FTC_Manager_Done( FTC_Manager  manager );
-
-  FT_EXPORT_DEF( void )  FTC_Manager_Reset( FTC_Manager  manager );
-
-  FT_EXPORT_DEF( FT_Error )  FTC_Manager_Lookup_Face( FTC_Manager  manager,
-                                                      FTC_FaceID   face_id,
-                                                      FT_Face*     aface );
- 
-  FT_EXPORT_DEF( FT_Error )  FTC_Manager_Lookup_Size( FTC_Manager  manager,
-                                                      FTC_SizeID   size_id,
-                                                      FT_Face*     aface,
-                                                      FT_Size*     asize );
 
 
 #ifdef __cplusplus
--- a/src/cache/ftlru.c
+++ b/src/cache/ftlru.c
@@ -38,6 +38,7 @@
 
   FT_EXPORT_FUNC( FT_Error )  FT_Lru_New( const FT_Lru_Class*  clazz,
                                           FT_UInt              max_elements,
+                                          FT_Pointer           user_data,
                                           FT_Memory            memory,
                                           FT_Bool              pre_alloc,
                                           FT_Lru*              alru )
@@ -66,6 +67,7 @@
       lru->clazz        = (FT_Lru_Class*)clazz;
       lru->max_elements = max_elements;
       lru->memory       = memory;
+      lru->user_data    = user_data;
 
       *alru = lru;
     }
--- a/src/cache/ftlru.h
+++ b/src/cache/ftlru.h
@@ -40,6 +40,8 @@
 
   typedef struct FT_LruRec_*  FT_Lru;
 
+
+
   typedef struct  FT_Lru_Class_
   {
     FT_UInt   lru_size;      /* object size in bytes */
@@ -60,6 +62,7 @@
   } FT_Lru_Class;
 
 
+
   typedef FT_Bool  (*FT_Lru_Selector)( FT_Lru      lru,
                                        FT_LruNode  node,
                                        FT_Pointer  data );
@@ -72,6 +75,7 @@
     FT_UInt         num_elements;
     FT_ListRec      elements;
     FT_Memory       memory;
+    FT_Pointer      user_data;
     
     /* the following fields are only meaningful for static lru containers */
     FT_ListRec      free_nodes;
@@ -82,6 +86,7 @@
 
   FT_EXPORT_DEF( FT_Error )  FT_Lru_New( const FT_Lru_Class*  clazz,
                                          FT_UInt              max_elements,
+                                         FT_Pointer           user_data,
                                          FT_Memory            memory,
                                          FT_Bool              pre_alloc,
                                          FT_Lru*              alru );
--- /dev/null
+++ b/src/cache/rules.mk
@@ -1,0 +1,70 @@
+#
+# FreeType 2 Cache configuration rules
+#
+
+
+# Copyright 1996-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.
+
+
+# Cache driver directory
+#
+Cache_DIR  := $(SRC_)cache
+Cache_DIR_ := $(Cache_DIR)$(SEP)
+
+
+# compilation flags for the driver
+#
+Cache_COMPILE := $(FT_COMPILE)
+
+
+# Cache driver sources (i.e., C files)
+#
+Cache_DRV_SRC := $(Cache_DIR_)ftlru.c   \
+                 $(Cache_DIR_)ftcmanag.c \
+                 $(Cache_DIR_)ftcimage.c
+
+# Cache driver headers
+#
+Cache_DRV_H := $(Cache_DRV_SRC:%c=%h)
+
+
+# Cache driver object(s)
+#
+#   Cache_DRV_OBJ_M is used during `multi' builds.
+#   Cache_DRV_OBJ_S is used during `single' builds.
+#
+Cache_DRV_OBJ_M := $(Cache_DRV_SRC:$(Cache_DIR_)%.c=$(OBJ_)%.$O)
+Cache_DRV_OBJ_S := $(OBJ_)ftcache.$O
+
+# Cache driver source file for single build
+#
+Cache_DRV_SRC_S := $(Cache_DIR_)ftcache.c
+
+
+# Cache driver - single object
+#
+$(Cache_DRV_OBJ_S): $(Cache_DRV_SRC_S) $(Cache_DRV_SRC) \
+                   $(FREETYPE_H) $(Cache_DRV_H)
+	$(Cache_COMPILE) $T$@ $(Cache_DRV_SRC_S)
+
+
+# Cache driver - multiple objects
+#
+$(OBJ_)%.$O: $(Cache_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H)
+	$(Cache_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(Cache_DRV_OBJ_S)
+DRV_OBJS_M += $(Cache_DRV_OBJ_M)
+
+
+# EOF