shithub: freetype+ttf2subf

Download patch

ref: 145f94cb261afc5bdbd924b130cd5d856c42e4b9
parent: 6b2e4d4e13a35ee4073042f7bae638e3fac7d846
author: David Turner <[email protected]>
date: Fri Dec 7 09:43:45 EST 2001

added new charmap cache. see include/freetype/cache/ftccmap.h

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2001-12-07  David Turner  <[email protected]>
+
+    * include/freetype/cache/ftccmap.h, src/cache/ftccmap.c: added new
+    charmap cache
+
+
 2001-12-06  Leonard Rosenthol  <[email protected]>
 
 	* src/base/ftmac.c: Added support for reading .dfont files on 
@@ -7,21 +13,35 @@
 	
 	* include/freetype/ftmac.h: Exported FT_GetFile_From_Mac_Name()
 
+
 2001-12-06  Werner Lemberg  <[email protected]>
 
 	* INSTALL: Small update.
 
+
 2001-12-05  David Turner  <[email protected]>
 
-	* src/base/ftglyph.c (FT_Glyph_To_Bitmap): Re-ordered code for
-	debugging purposes.
+    * src/base/ftglyph.c (FT_Glyph_To_Bitmap): re-ordered code for debugging
+    purposes..
 
-	* src/smooth/ftsmooth.c (ft_smooth_render): Fixed a nasty hidden bug
-	where outline shifting wasn't correctly undone after bitmap
-	rasterization.  This created problems with certain glyphs (like '"'
-	of certain fonts) and the cache system.
+    * src/smooth/ftsmooth.c (ft_smooth_render): fixed a nasty hidden bug where
+    outline shifting wasn't correctly undone after bitmap rasterization. this
+    created problems with certain glyphs (like '"' of certain fonts..) and
+    the cache system..
 
+
 2001-12-05  David Turner  <[email protected]>
+
+    First of all, a big thanks to Werner and Antoine for their latest work !!
+    
+    * src/pshinter/pshalgo2.c (psh2_hint_table_init),
+      src/pshinter/pshalgo1.c (psh1_hint_table_init): removed compiler
+      warnings
+
+    * include/freetype/cache/*, src/cache/*: yet another massive rewrite of
+    the caching sub-system, in order to both increase performance and allow
+    simpler cache sub-classing. As an example, the code for the image and
+    sbit caches is now much simpler
 
 	* src/pshinter/pshalgo2.c (psh2_hint_table_init),
 	src/pshinter/pshalgo1.c (psh1_hint_table_init): Removed compiler
--- /dev/null
+++ b/include/freetype/cache/ftccmap.h
@@ -1,0 +1,195 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftccmap.h                                                              */
+/*                                                                         */
+/*    FreeType charmap cache                                               */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#ifndef __FT_CACHE_CHARMAP_H__
+#define __FT_CACHE_CHARMAP_H__
+
+#include <ft2build.h>
+#include FT_CACHE_H
+
+FT_BEGIN_HEADER
+
+ /************************************************************************
+  *
+  * @type: FTC_CmapCache
+  *
+  * @description:
+  *   opaque handle used to manager a charmap cache. This cache is used
+  *   to hold character codes -> glyph indices mappings
+  */
+  typedef struct FTC_CMapCacheRec_*    FTC_CMapCache;
+
+
+ /************************************************************************
+  *
+  * @type: FTC_CMapDesc
+  *
+  * @description:
+  *   handle to a @FTC_CMapDescRec structure used to describe a given charmap
+  *   in a charmap cache.
+  *
+  *   each @FTC_CMapDesc describes which charmap, of which @FTC_Face we
+  *   want to use in @FTC_CMapCache_Lookup
+  */
+  typedef struct FTC_CMapDescRec_*         FTC_CMapDesc;
+
+
+ /************************************************************************
+  *
+  * @enum: FTC_CMapType
+  *
+  * @description:
+  *   the list of valid @FTC_CMap types, they indicate how we want to
+  *   address a charmap within a @FTC_FaceID
+  *
+  * @values:
+  *   FTC_CMAP_BY_INDEX ::
+  *     used to indicate that we want to address a charmap by its index in
+  *     the corresponding @FT_Face
+  *
+  *   FTC_CMAP_BY_ENCODING ::
+  *     used to indicate that we want to use a @FT_Face charmap that
+  *     corresponds to a given encoding
+  *
+  *   FTC_CMAP_BY_ID ::
+  *     used to indicate that we want to use a @FT_Face charmap that
+  *     corresponds to a given (platform,encoding) id. see @FTC_CMapIdRec
+  */
+  typedef enum
+  {
+    FTC_CMAP_BY_INDEX    = 0,
+    FTC_CMAP_BY_ENCODING = 1,
+    FTC_CMAP_BY_ID       = 2
+  
+  } FTC_CMapType;
+
+
+ /************************************************************************
+  *
+  * @struct: FTC_CMapIdRec
+  *
+  * @description:
+  *   a short structure used to identify a charmap by a (platform,encoding)
+  *   pair of values
+  *
+  * @fields:
+  *   platform :: platform ID
+  *   encoding :: encoding ID
+  */
+  typedef struct FTC_CMapIdRec_
+  {
+    FT_UInt  platform;
+    FT_UInt  encoding;
+  
+  } FTC_CMapIdRec;
+
+
+ /************************************************************************
+  *
+  * @struct: FTC_CMapDescRec
+  *
+  * @description:
+  *   a structure used to describe a given charmap to the @FTC_CMapCache
+  *
+  * @fields:
+  *   face_id :: @FTC_FaceID of the face this charmap belongs to
+  *   type    :: type of charmap, see @FTC_CMapType
+  *
+  *   u.index    :: for @FTC_CMAP_BY_INDEX types, this is the charmap index
+  *                 (within a @FT_Face) we want to use.
+  *
+  *   u.encoding :: for @FTC_CMAP_BY_ENCODING types, this is the charmap
+  *                 encoding we want to use. see @FT_Encoding
+  *
+  *   u.id       :: for @FTC_CMAP_BY_ID types, this is the (platform,encoding)
+  *                 pair we want to use. see @FTC_CMapIdRec and
+  *                 @FT_CharMapRec
+  */
+  typedef struct FTC_CMapDescRec_
+  {
+    FTC_FaceID    face_id;
+    FTC_CMapType  type;
+
+    union
+    {
+      FT_UInt        index;
+      FT_Encoding    encoding;
+      FTC_CMapIdRec  id;
+      
+    } u;
+     
+  } FTC_CMapDescRec;
+
+
+
+ /************************************************************************
+  *
+  * @function: FTC_CMapCache_New
+  *
+  * @description:
+  *   create a new charmap cache
+  *
+  * @input:
+  *   manager :: handle to cache manager
+  *
+  * @output:
+  *   acache  :: new cache handle. NULL in case of error
+  *
+  * @return:
+  *   FreeType error code. 0 means success
+  *
+  * @note:
+  *   like all other caches, this one will be destroyed with the
+  *   cache manager
+  */
+  FT_EXPORT( FT_Error )
+  FTC_CMapCache_New( FTC_Manager     manager,
+                     FTC_CMapCache  *acache );
+
+
+
+ /************************************************************************
+  *
+  * @function: FTC_CMapCache_Lookup
+  *
+  * @description:
+  *   translate a character code into a glyph index, using the charmap
+  *   cache.
+  *
+  * @input:
+  *   cache     :: charmap cache handle
+  *   cmap_desc :: charmap descriptor handle
+  *   char_code :: character code (in the corresponding charmap)
+  *
+  * @return:
+  *   glyph index. 0 means "no glyph" !!
+  *
+  * @note:
+  *   this function doesn't return @FTC_Node handles, since there is
+  *   no real use for them with typical uses of charmaps
+  */
+  FT_EXPORT( FT_UInt )
+  FTC_CMapCache_Lookup( FTC_CMapCache  cache,
+                        FTC_CMapDesc   cmap_desc,
+                        FT_UInt32      char_code );
+
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __FT_CACHE_CHARMAP_H__ */
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -420,6 +420,18 @@
   /*************************************************************************/
   /*                                                                       */
   /* @macro:                                                               */
+  /*    FT_CACHE_CHARMAP_H                                                 */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    A macro used in #include statements to name the file containing    */
+  /*    the `charmap'API of the FreeType 2 cache sub-system.               */
+  /*                                                                       */
+#define FT_CACHE_CHARMAP_H        <freetype/cache/ftccmap.h>
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @macro:                                                               */
   /*    FT_MAC_H                                                           */
   /*                                                                       */
   /* @description:                                                         */
--- a/src/cache/Jamfile
+++ b/src/cache/Jamfile
@@ -16,7 +16,7 @@
 
   if $(FT2_MULTI)
   {
-    _sources = ftlru ftcmanag ftccache ftcglyph ftcsbits ftcimage ;
+    _sources = ftlru ftcmanag ftccache ftcglyph ftcsbits ftcimage ftccmap ;
   }
   else
   {
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -559,8 +559,8 @@
         if ( ALLOC( node, clazz->node_size ) )
           goto Exit;
 
-        /* node initializer must set 'hash' field */
         node->fam_index = (FT_UShort) family->fam_index;
+        node->hash      = query->hash;
         node->ref_count = 0;
 
         error = clazz->node_init( node, query, cache );
--- /dev/null
+++ b/src/cache/ftccmap.c
@@ -1,0 +1,391 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftccmap.c                                                              */
+/*                                                                         */
+/*    FreeType CharMap cache                                               */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_CACHE_H
+#include FT_CACHE_CHARMAP_H
+#include FT_CACHE_MANAGER_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+
+ /* each FTC_CMapNode contains a simple array used to map a  */
+ /* range of character codes to equivalent glyph indices     */
+ /*                                                          */
+ /* for now, the implementation is very basic: each node     */
+ /* maps a range of 128 consecutive character codes to their */
+ /* correspondingglyph indices..                             */
+ /*                                                          */
+ /* we could do more complex things, but I don't think it's  */
+ /* really very useful..                                     */
+ /*                                                          */
+
+ /* number of glyph indices / character code per node */
+#define  FTC_CMAP_INDICES_MAX  128
+
+
+  typedef struct FTC_CMapNodeRec_
+  {
+    FTC_NodeRec  node;
+    FT_UInt32    first;         /* first character in node      */
+    FT_UInt16    indices[ FTC_CMAP_INDICES_MAX ];  /* array of glyph indices */
+
+  } FTC_CMapNodeRec, *FTC_CMapNode;
+
+#define  FTC_CMAP_NODE( x )       ((FTC_CMapNode)( x ))
+
+ /* compute node hash value from cmap family and "requested" glyph index */
+#define  FTC_CMAP_HASH(cfam,cquery)   \
+              ((cfam)->hash + ((cquery)->char_code/FTC_CMAP_INDICES_MAX))
+
+
+ /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
+ /* glyph indices hasn't been queried through @FT_Get_Glyph_Index yet..   */
+ /*                                                                       */
+#define  FTC_CMAP_UNKNOWN  ((FT_UInt16)-1)
+
+
+  /* the charmap query */
+  typedef struct FTC_CMapQueryRec_
+  {
+    FTC_QueryRec  query;
+    FTC_CMapDesc  desc;
+    FT_UInt32     char_code;
+
+  } FTC_CMapQueryRec, *FTC_CMapQuery;
+
+#define  FTC_CMAP_QUERY( x )  ((FTC_CMapQuery)( x ))
+
+
+  /* the charmap family */
+  typedef struct FTC_CMapFamilyRec_
+  {
+    FTC_FamilyRec    family;
+    FT_UInt32        hash;
+    FTC_CMapDescRec  desc;
+    FT_UInt          index;
+
+  } FTC_CMapFamilyRec, *FTC_CMapFamily;
+
+#define  FTC_CMAP_FAMILY( x )           ((FTC_CMapFamily)( x ))
+#define  FTC_CMAP_FAMILY_MEMORY( x )     FTC_FAMILY(x)->memory
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        CHARMAP NODES                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* no need for specific finalizer, we'll use "ftc_node_done" directly */
+
+  /* initialize a new cmap node */
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_cmap_node_init( FTC_CMapNode   cnode,
+                      FTC_CMapQuery  cquery,
+                      FTC_Cache      cache )
+  {
+    FTC_CMapFamily  cfam = FTC_CMAP_FAMILY( FTC_QUERY(cquery)->family );
+    FT_UInt32       first;
+    FT_UInt         n;
+
+
+    first = (cquery->char_code / FTC_CMAP_INDICES_MAX) * FTC_CMAP_INDICES_MAX;
+
+    cnode->first = first;
+    for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
+      cnode->indices[n] = FTC_CMAP_UNKNOWN;
+
+    return 0;
+  }
+
+
+ /* compute the weight of a given cmap node */
+  FT_CALLBACK_DEF( FT_ULong )
+  ftc_cmap_node_weight( FTC_CMapNode  cnode )
+  {
+    return sizeof(*cnode);
+  }
+
+
+ /* compare a cmap node to a given query */
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_cmap_node_compare( FTC_CMapNode   cnode,
+                         FTC_CMapQuery  cquery )
+  {
+    FT_UInt32  offset = (FT_UInt32)( cquery->char_code - cnode->first );
+
+
+    return ( offset < FTC_CMAP_INDICES_MAX );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    CHARMAP FAMILY                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_cmap_family_init( FTC_CMapFamily  cfam,
+                        FTC_CMapQuery   cquery,
+                        FTC_Cache       cache )
+  {
+    FTC_Manager   manager = cache->manager;
+    FTC_CMapDesc  desc = cquery->desc;
+    FT_UInt32     hash;
+    FT_Error      error;
+    FT_Face       face;
+
+
+    /* setup charmap descriptor */
+    cfam->desc = *desc;
+
+    /* let's see if the rest is correct too */
+    error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
+    if ( !error )
+    {
+      FT_UInt      count = face->num_charmaps;
+      FT_UInt      index = count;
+      FT_CharMap*  cur   = face->charmaps;
+      
+      switch ( desc->type )
+      {
+        case FTC_CMAP_BY_INDEX:
+          {
+            index = desc->u.index;
+            hash  = index*33;
+            break;
+          }
+
+
+        case FTC_CMAP_BY_ENCODING:
+          {
+            for ( index = 0; index < count; index++, cur++ )
+              if ( cur[0]->encoding == desc->u.encoding )
+                break;
+            
+            hash = index*67;
+            break;
+          }
+
+
+        case FTC_CMAP_BY_ID:
+          {
+            for ( index = 0; index < count; index++, cur++ )
+            {
+              if ( (FT_UInt) cur[0]->platform_id == desc->u.id.platform &&
+                   (FT_UInt) cur[0]->encoding_id == desc->u.id.encoding )
+              {
+                hash = ((desc->u.id.platform << 8) | desc->u.id.encoding)*7;
+                break;
+              }
+            }
+            break;
+          }
+
+        default:
+          ;
+      }
+
+      if ( index >= count )
+        goto Bad_Descriptor;
+
+      /* compute hash value, both in family and query */
+      cfam->index             = index;
+      cfam->hash              = hash ^ FTC_FACE_ID_HASH(desc->face_id);
+      FTC_QUERY(cquery)->hash = FTC_CMAP_HASH(cfam,cquery);
+
+      error = ftc_family_init( FTC_FAMILY(cfam), FTC_QUERY(cquery), cache );
+    }
+    
+    return error;
+
+
+  Bad_Descriptor:
+    FT_ERROR(( "FreeType.cache.cmap.lookup: invalid charmap descriptor\n" ));
+    return FT_Err_Invalid_Argument;
+  }
+
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_cmap_family_compare( FTC_CMapFamily  cfam,
+                           FTC_CMapQuery   cquery )
+  {
+    FT_Int  result = 0;
+
+
+    /* first, compare face id and type */
+    if ( cfam->desc.face_id != cquery->desc->face_id ||
+         cfam->desc.type    != cquery->desc->type    )
+      goto Exit;
+
+    switch ( cfam->desc.type )
+    {
+      case FTC_CMAP_BY_INDEX:
+        result = ( cfam->desc.u.index == cquery->desc->u.index );
+        break;
+
+      case FTC_CMAP_BY_ENCODING:
+        result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
+        break;
+
+      case FTC_CMAP_BY_ID:
+        result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
+                   cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
+        break;
+
+      default:
+        ;
+    }
+
+    if (result)
+    {
+      /* when found, update the 'family' and 'hash' field of the query */
+      FTC_QUERY(cquery)->family = FTC_FAMILY(cfam);
+      FTC_QUERY(cquery)->hash   = FTC_CMAP_HASH(cfam,cquery);
+    }
+
+  Exit:
+    return FT_BOOL(result);
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GLYPH IMAGE CACHE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FTC_Cache_ClassRec  ftc_cmap_cache_class =
+  {
+    sizeof( FTC_CacheRec ),
+    (FTC_Cache_InitFunc)       ftc_cache_init,
+    (FTC_Cache_ClearFunc)      ftc_cache_clear,
+    (FTC_Cache_DoneFunc)       ftc_cache_done,
+
+    sizeof( FTC_CMapFamilyRec ),
+    (FTC_Family_InitFunc)      ftc_cmap_family_init,
+    (FTC_Family_CompareFunc)   ftc_cmap_family_compare,
+    (FTC_Family_DoneFunc)      ftc_family_done,
+
+    sizeof( FTC_CMapNodeRec ),
+    (FTC_Node_InitFunc)        ftc_cmap_node_init,
+    (FTC_Node_WeightFunc)      ftc_cmap_node_weight,
+    (FTC_Node_CompareFunc)     ftc_cmap_node_compare,
+    (FTC_Node_DoneFunc)        ftc_node_done
+  };
+
+
+  /* documentation is in ftccmap.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_CMapCache_New( FTC_Manager     manager,
+                     FTC_CMapCache  *acache )
+  {
+    return FTC_Manager_Register_Cache(
+             manager,
+             (FTC_Cache_Class)&ftc_cmap_cache_class,
+             FTC_CACHE_P( acache ) );
+  }
+
+
+  /* documentation is in ftccmap.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FTC_CMapCache_Lookup( FTC_CMapCache  cache,
+                        FTC_CMapDesc   desc,
+                        FT_UInt32      char_code )
+  {
+    FTC_CMapQueryRec  cquery;
+    FTC_CMapNode      node;
+    FT_Error          error;
+    FT_UInt           gindex;
+
+    if ( !cache || !desc )
+    {
+      FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0 !!\n" ));
+      return 0;
+    }
+
+    cquery.desc      = desc;
+    cquery.char_code = char_code;
+
+    error = ftc_cache_lookup( FTC_CACHE(cache),
+                              FTC_QUERY(&cquery),
+                              (FTC_Node*) &node );
+    if ( !error )
+    {
+      FT_UInt  offset = (FT_UInt)( char_code - node->first );
+
+      gindex = node->indices[offset];
+      if ( gindex == FTC_CMAP_UNKNOWN )
+      {
+        FT_Face     face;
+        FT_CharMap  old, cmap, limit;
+
+        /* we need to use @FT_Get_Char_Index */
+        gindex = 0;
+
+        error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
+                                         desc->face_id,
+                                         &face );
+        if (!error)
+        {
+          FT_CharMap   old, cmap  = NULL;
+          FT_UInt      cmap_index;
+
+          /* save old charmap, select new one */
+          old        = face->charmap;
+          cmap_index = FTC_CMAP_FAMILY( FTC_QUERY(&cquery)->family )->index;
+          cmap       = face->charmaps[cmap_index];
+
+          FT_Set_Charmap( face, cmap );
+
+          /* perform lookup */
+          gindex                = FT_Get_Char_Index( face, char_code );
+          node->indices[offset] = gindex;
+
+          /* restore old charmap */
+          FT_Set_Charmap( face, old );
+        }
+      }
+    }
+
+    return gindex;
+  }
+
+
+
+/* END */
--- a/src/cache/ftcglyph.c
+++ b/src/cache/ftcglyph.c
@@ -39,9 +39,7 @@
     FT_UInt    start = FTC_GLYPH_FAMILY_START(gfam,gindex);
 
 
-    gnode->node.fam_index = (FT_UShort) gfam->family.fam_index;
-    gnode->node.hash      = FTC_GLYPH_FAMILY_HASH(gfam,gindex);
-    gnode->item_start     = (FT_UShort) start;
+    gnode->item_start = (FT_UShort) start;
 
     len = gfam->item_total - start;
     if ( len > gfam->item_count )
@@ -68,12 +66,10 @@
   ftc_glyph_node_compare( FTC_GlyphNode    gnode,
                           FTC_GlyphQuery   gquery )
   {
-    FT_UInt  fam_index = (FT_UInt) FTC_NODE(gnode)->fam_index;
     FT_UInt  start     = (FT_UInt) gnode->item_start;
     FT_UInt  count     = (FT_UInt) gnode->item_count;
 
-    return FT_BOOL( (FT_UInt)(gquery->gindex - start) < count &&
-                     gquery->query.family->fam_index == fam_index );
+    return FT_BOOL( (FT_UInt)(gquery->gindex - start) < count );
   }
 
 
@@ -103,7 +99,7 @@
       gfam->hash       = hash;
       gfam->item_total = item_total;
       gfam->item_count = item_count;
-
+      
       FTC_GLYPH_FAMILY_FOUND(gfam,gquery);
     }
 
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -261,7 +261,6 @@
     FT_Bool  result;
 
 
-    /* we must set iquery.glyph.gfam for faster glyph node comparisons */
     result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &ifam->desc, &iquery->desc ) );
     if ( result )
       FTC_GLYPH_FAMILY_FOUND(ifam,iquery);
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -120,19 +120,19 @@
 
 
   static FT_Error
-  ftc_sbit_node_load( FTC_SBitNode  snode,
-                      FTC_Manager   manager,
-                      FT_UInt       gindex,
-                      FT_ULong     *asize )
+  ftc_sbit_node_load( FTC_SBitNode   snode,
+                      FTC_Manager    manager,
+                      FTC_SBitFamily sfam,
+                      FT_UInt        gindex,
+                      FT_ULong      *asize )
   {
-    FT_Error       error;
-    FTC_GlyphNode  gnode = FTC_GLYPH_NODE(snode);
-    FTC_GlyphFamily   gfam;
-    FTC_SBitFamily    sfam;
-    FT_Memory      memory;
-    FT_Face        face;
-    FT_Size        size;
-    FTC_SBit       sbit;
+    FT_Error          error;
+    FTC_GlyphNode     gnode = FTC_GLYPH_NODE(snode);
+    FTC_GlyphFamily   gfam  = FTC_GLYPH_FAMILY(sfam);
+    FT_Memory         memory;
+    FT_Face           face;
+    FT_Size           size;
+    FTC_SBit          sbit;
 
     if ( gindex <  (FT_UInt)gnode->item_start                     ||
          gindex >= (FT_UInt)gnode->item_start + gnode->item_count )
@@ -141,8 +141,6 @@
       return FTC_Err_Invalid_Argument;
     }
 
-    gfam   = FTC_GLYPH_FAMILY( manager->families.entries[ gnode->node.fam_index ].family );
-    sfam   = FTC_SBIT_FAMILY(gfam);
     memory = manager->library->memory;
 
     sbit = snode->sbits + (gindex - gnode->item_start);
@@ -275,7 +273,11 @@
                          gquery->gindex,
                          FTC_GLYPH_FAMILY(gquery->query.family) );
 
-    error = ftc_sbit_node_load( snode, cache->manager, gquery->gindex, NULL );
+    error = ftc_sbit_node_load( snode,
+                                cache->manager,
+                                FTC_SBIT_FAMILY( FTC_QUERY(gquery)->family ),
+                                gquery->gindex,
+                                NULL );
     if ( error )
       ftc_glyph_node_done( FTC_GLYPH_NODE(snode), cache );
 
@@ -336,7 +338,13 @@
       {
         FT_ULong  size;
 
-        ftc_sbit_node_load( snode, cache->manager, gindex, &size );
+        /* yes, it's safe to ignore errors here */
+        ftc_sbit_node_load( snode,
+                            cache->manager,
+                            FTC_SBIT_FAMILY( FTC_QUERY(squery)->family ),
+                            gindex,
+                            &size );
+
         cache->manager->cur_weight += size;
       }
     }
--- a/src/cache/rules.mk
+++ b/src/cache/rules.mk
@@ -33,7 +33,8 @@
                  $(CACHE_DIR_)ftccache.c \
                  $(CACHE_DIR_)ftcglyph.c \
                  $(CACHE_DIR_)ftcsbits.c \
-                 $(CACHE_DIR_)ftcimage.c
+                 $(CACHE_DIR_)ftcimage.c \
+                 $(CACHE_DIR_)ftccmap.c
 
 # Cache driver headers
 #