_major_ re-design of the caching sub-system. Still using the same API
though :-)
diff --git a/ChangeLog b/ChangeLog
index 50a559d..a9421d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2001-10-26 David Turner <david@freetype.org>
+
+ * include/freetype/ftcache.h, include/freetype/cache/*.h,
+ src/cache/*.c: Major re-design of the cache sub-system to provide
+ better performance as well as an "Acquire"/"Release" API..
+
+ seems to work well here.. but probably needs a bit more testing..
+
+
2001-10-26 Leonard Rosenthol <leonardr@lazerware.com>
* updated Mac OS README (builds/mac/) to reflect my taking over
diff --git a/include/freetype/cache/ftcchunk.h b/include/freetype/cache/ftcchunk.h
index 47fed6e..e799123 100644
--- a/include/freetype/cache/ftcchunk.h
+++ b/include/freetype/cache/ftcchunk.h
@@ -60,109 +60,57 @@
typedef struct FTC_ChunkNodeRec_* FTC_ChunkNode;
typedef struct FTC_ChunkSetRec_* FTC_ChunkSet;
- typedef struct FTC_Chunk_CacheRec_* FTC_Chunk_Cache;
+ typedef struct FTC_ChunkCacheRec_* FTC_ChunkCache;
typedef struct FTC_ChunkNodeRec_
{
- FTC_CacheNodeRec root;
- FTC_ChunkSet cset;
- FT_UShort cset_index;
- FT_UShort num_elements;
- FT_Byte* elements;
+ FTC_NodeRec node;
+ FTC_ChunkSet cset;
+ FT_UShort item_count;
+ FT_UShort item_start;
+ FT_Byte* items;
} FTC_ChunkNodeRec;
+#define FTC_CHUNK_NODE(x) ((FTC_ChunkNode)(x))
-#define FTC_CHUNKNODE_TO_LRUNODE( x ) ((FT_ListNode)( x ))
-#define FTC_LRUNODE_TO_CHUNKNODE( x ) ((FTC_ChunkNode)( x ))
-
-
- /*************************************************************************/
- /* */
- /* chunk set methods */
- /* */
-
- /* used to set "element_max", "element_count" and "element_size" */
- typedef FT_Error
- (*FTC_ChunkSet_SizesFunc)( FTC_ChunkSet cset,
- FT_Pointer type );
-
- typedef FT_Error
- (*FTC_ChunkSet_InitFunc)( FTC_ChunkSet cset,
- FT_Pointer type );
-
- typedef void
- (*FTC_ChunkSet_DoneFunc)( FTC_ChunkSet cset );
-
- typedef FT_Bool
- (*FTC_ChunkSet_CompareFunc)( FTC_ChunkSet cset,
- FT_Pointer type );
-
-
- typedef FT_Error
- (*FTC_ChunkSet_NewNodeFunc)( FTC_ChunkSet cset,
- FT_UInt index,
- FTC_ChunkNode* anode );
-
- typedef void
- (*FTC_ChunkSet_DestroyNodeFunc)( FTC_ChunkNode node );
-
- typedef FT_ULong
- (*FTC_ChunkSet_SizeNodeFunc)( FTC_ChunkNode node );
-
-
- typedef struct FTC_ChunkSet_Class_
+ /* a chunk set is used to categorize chunks of a given type */
+ typedef struct FTC_ChunkSetRec_
{
- FT_UInt cset_byte_size;
-
- FTC_ChunkSet_InitFunc init;
- FTC_ChunkSet_DoneFunc done;
- FTC_ChunkSet_CompareFunc compare;
- FTC_ChunkSet_SizesFunc sizes;
-
- FTC_ChunkSet_NewNodeFunc new_node;
- FTC_ChunkSet_SizeNodeFunc size_node;
- FTC_ChunkSet_DestroyNodeFunc destroy_node;
-
- } FTC_ChunkSet_Class;
-
-
- typedef struct FTC_ChunkSetRec_
- {
- FTC_Chunk_Cache cache;
- FTC_Manager manager;
- FT_Memory memory;
- FTC_ChunkSet_Class* clazz;
- FT_UInt cset_index; /* index in parent cache */
-
- FT_UInt element_max; /* maximum number of elements */
- FT_UInt element_size; /* element size in bytes */
- FT_UInt element_count; /* number of elements per chunk */
-
- FT_UInt num_chunks;
- FTC_ChunkNode* chunks;
-
+ FT_LruNodeRec lru;
+ FT_UFast hash;
+ FTC_ChunkCache ccache;
+ FT_Fast num_chunks;
+ FT_UInt item_total; /* total number of glyphs in set */
+ FT_UInt item_size; /* size of each glyph item in set */
+ FT_UInt item_count; /* number of glyph items per chunk */
+
} FTC_ChunkSetRec;
+#define FTC_CHUNK_SET(x) ((FTC_ChunkSet)(x))
- /* the abstract chunk cache class */
- typedef struct FTC_Chunk_Cache_Class_
+#define FTC_CHUNK_SET_MEMORY(x) ((x)->ccache->cache.memory)
+
+ /* the abstract chunk cache class */
+ typedef struct FTC_ChunkCacheRec_
{
- FTC_Cache_Class root;
- FTC_ChunkSet_Class* cset_class;
+ FTC_CacheRec cache;
+ FT_LruList cset_lru; /* LRU list of chunk sets */
+
+ } FTC_ChunkCacheRec;
- } FTC_Chunk_Cache_Class;
+#define FTC_CHUNK_CACHE(x) ((FTC_ChunkCache)(x))
- /* the abstract chunk cache object */
- typedef struct FTC_Chunk_CacheRec_
+ typedef struct FTC_ChunkQueryRec_
{
- FTC_CacheRec root;
- FT_Lru csets_lru; /* static chunk set lru list */
- FTC_ChunkSet last_cset; /* small cache :-) */
- FTC_ChunkSet_CompareFunc compare; /* useful shortcut */
+ /* input */
+ FT_UInt gindex; /* glyph index */
- } FTC_Chunk_CacheRec;
+ /* output */
+ FTC_ChunkSet cset;
+
+ } FTC_ChunkQueryRec, *FTC_ChunkQuery;
/*************************************************************************/
@@ -173,52 +121,44 @@
/* */
FT_EXPORT( FT_Error )
- FTC_ChunkNode_Init( FTC_ChunkNode node,
- FTC_ChunkSet cset,
- FT_UInt index,
- FT_Bool alloc );
-
-#define FTC_ChunkNode_Ref( n ) \
- FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count++
-
-#define FTC_ChunkNode_Unref( n ) \
- FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count--
-
+ ftc_chunk_node_init( FTC_ChunkNode node,
+ FTC_ChunkSet cset,
+ FT_UInt index,
+ FT_Bool alloc );
/* chunk set objects */
FT_EXPORT( void )
- FTC_ChunkNode_Destroy( FTC_ChunkNode node );
+ ftc_chunk_node_done( FTC_ChunkNode node );
FT_EXPORT( FT_Error )
- FTC_ChunkSet_New( FTC_Chunk_Cache cache,
- FT_Pointer type,
- FTC_ChunkSet *aset );
+ ftc_chunk_set_init( FTC_ChunkSet cset,
+ FT_UInt item_size,
+ FT_UInt item_count,
+ FT_UInt item_total,
+ FTC_ChunkCache cache );
-
- FT_EXPORT( FT_Error )
- FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset,
- FT_UInt glyph_index,
- FTC_ChunkNode* anode,
- FT_UInt *anindex );
+ FT_EXPORT( void )
+ ftc_chunk_set_done( FTC_ChunkSet cset );
/* chunk cache objects */
FT_EXPORT( FT_Error )
- FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache );
+ ftc_chunk_cache_init( FTC_ChunkCache cache,
+ FT_LruList_Class cset_class );
FT_EXPORT( void )
- FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache );
+ ftc_chunk_cache_done( FTC_ChunkCache cache );
+
FT_EXPORT( FT_Error )
- FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache cache,
- FT_Pointer type,
- FT_UInt gindex,
- FTC_ChunkNode *anode,
- FT_UInt *aindex );
+ ftc_chunk_cache_lookup( FTC_ChunkCache cache,
+ FTC_ChunkQuery query,
+ FTC_ChunkNode *anode );
+ /* */
FT_END_HEADER
diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h
index a8af44a..c92e4fa 100644
--- a/include/freetype/cache/ftcglyph.h
+++ b/include/freetype/cache/ftcglyph.h
@@ -64,107 +64,83 @@
FT_BEGIN_HEADER
- /* maximum number of glyph sets per glyph cache; must be < 256 */
-#define FTC_MAX_GLYPH_SETS 16
-#define FTC_GSET_HASH_SIZE_DEFAULT 64
-
-
+ /* each glyph set is caracterized by a "glyph set type" which must be */
+ /* defined by sub-classes.. */
typedef struct FTC_GlyphSetRec_* FTC_GlyphSet;
- typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode;
- typedef struct FTC_Glyph_CacheRec_* FTC_Glyph_Cache;
- typedef struct FTC_GlyphNodeRec_
+ /* handle to a glyph cache node */
+ typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode;
+
+ /* a glyph cache, its nodes are all glyph-specific */
+ typedef struct FTC_GlyphCacheRec_* FTC_GlyphCache;
+
+ /* glyph sets class handle */
+ typedef const struct FTC_GlyphSet_ClassRec_* FTC_GlyphSet_Class;
+
+
+ /* size should be 24 bytes on 32-bit machines */
+ /* note that the node's hash is ((gset->hash << 16) | glyph_index) */
+ /* this _must_ be set properly by the glyph node initializer */
+ /* */
+ typedef struct FTC_GlyphNodeRec_
{
- FTC_CacheNodeRec root;
- FTC_GlyphNode gset_next; /* next in glyph set's bucket list */
- FT_UShort glyph_index;
- FT_UShort gset_index;
+ FTC_NodeRec node;
+ FTC_GlyphSet gset;
} FTC_GlyphNodeRec;
-
-#define FTC_GLYPHNODE( x ) ( (FTC_GlyphNode)( x ) )
-#define FTC_GLYPHNODE_TO_LRUNODE( n ) ( (FT_ListNode)( n ) )
-#define FTC_LRUNODE_TO_GLYPHNODE( n ) ( (FTC_GlyphNode)( n ) )
+#define FTC_GLYPH_NODE(x) ((FTC_GlyphNode)(x))
+#define FTC_GLYPH_NODE_P(x) ((FTC_GlyphNode*)(x))
- /*************************************************************************/
- /* */
- /* Glyph set methods. */
- /* */
-
- typedef FT_Error
- (*FTC_GlyphSet_InitFunc)( FTC_GlyphSet gset,
- FT_Pointer type );
-
- typedef void
- (*FTC_GlyphSet_DoneFunc)( FTC_GlyphSet gset );
-
- typedef FT_Bool
- (*FTC_GlyphSet_CompareFunc)( FTC_GlyphSet gset,
- FT_Pointer type );
-
-
- typedef FT_Error
- (*FTC_GlyphSet_NewNodeFunc)( FTC_GlyphSet gset,
- FT_UInt gindex,
- FTC_GlyphNode* anode );
-
- typedef void
- (*FTC_GlyphSet_DestroyNodeFunc)( FTC_GlyphNode node,
- FTC_GlyphSet gset );
-
- typedef FT_ULong
- (*FTC_GlyphSet_SizeNodeFunc)( FTC_GlyphNode node,
- FTC_GlyphSet gset );
-
-
- typedef struct FTC_GlyphSet_Class_
- {
- FT_UInt gset_byte_size;
-
- FTC_GlyphSet_InitFunc init;
- FTC_GlyphSet_DoneFunc done;
- FTC_GlyphSet_CompareFunc compare;
-
- FTC_GlyphSet_NewNodeFunc new_node;
- FTC_GlyphSet_SizeNodeFunc size_node;
- FTC_GlyphSet_DestroyNodeFunc destroy_node;
-
- } FTC_GlyphSet_Class;
-
-
+ /* the glyph set structure. each glyph set is used to model a set of */
+ /* glyphs of the same "type". The type itself is defined in sub-classes */
+ /* */
+ /* for example, the "image cache" uses face_id + character_pixel_sizes + */
+ /* image_format to characterize glyph sets.. */
+ /* */
+ /* a pure "master outlines" cache would only use face_id, etc.. */
+ /* */
typedef struct FTC_GlyphSetRec_
{
- FTC_Glyph_Cache cache;
- FTC_Manager manager;
- FT_Memory memory;
- FTC_GlyphSet_Class* clazz;
- FT_UInt hash_size;
- FTC_GlyphNode* buckets;
- FT_UInt gset_index; /* index in parent cache */
+ FT_LruNodeRec lru; /* glyph sets are LRU nodes within */
+ FTC_GlyphCache gcache; /* parent cache.. */
+ FT_UFast hash; /* must be set by initializer !! */
+ FT_Fast num_glyphs; /* destroyed when 0.. */
} FTC_GlyphSetRec;
+#define FTC_GLYPH_SET(x) ((FTC_GlyphSet)(x))
+#define FTC_GLYPH_SET_P(x) ((FTC_GlyphSet*)(x))
- /* the abstract glyph cache class */
- typedef struct FTC_Glyph_Cache_Class_
- {
- FTC_Cache_Class root;
- FTC_GlyphSet_Class* gset_class;
+#define FTC_GLYPH_SET_MEMORY(x) ((x)->gcache->cache.memory)
- } FTC_Glyph_Cache_Class;
+/* retrieve glyph index of glyph node */
+#define FTC_GLYPH_NODE_GINDEX(x) \
+ ((FT_UInt)(FTC_GLYPH_NODE(x)->node.hash & 0xFFFF))
/* the abstract glyph cache object */
- typedef struct FTC_Glyph_CacheRec_
+ typedef struct FTC_GlyphCacheRec_
{
- FTC_CacheRec root;
- FT_Lru gsets_lru; /* static sets lru list */
- FTC_GlyphSet last_gset; /* small cache :-) */
- FTC_GlyphSet_CompareFunc compare; /* useful shortcut */
+ FTC_CacheRec cache;
+ FT_LruList gset_lru; /* LRU list of glyph sets */
- } FTC_Glyph_CacheRec;
+ } FTC_GlyphCacheRec;
+
+#define FTC_GLYPH_CACHE(x) ((FTC_GlyphCache)(x))
+#define FTC_GLYPH_CACHE_P(x) ((FTC_GlyphCache*)(x))
+
+
+ typedef struct FTC_GlyphQueryRec_
+ {
+ /* input */
+ FT_UInt gindex;
+
+ /* output */
+ FTC_GlyphSet gset;
+
+ } FTC_GlyphQueryRec, *FTC_GlyphQuery;
/*************************************************************************/
@@ -174,44 +150,41 @@
/* cache sub-system internals. */
/* */
+ /* must be called by derived FTC_Node_InitFunc routines */
FT_EXPORT( void )
- FTC_GlyphNode_Init( FTC_GlyphNode node,
- FTC_GlyphSet gset,
- FT_UInt gindex );
+ ftc_glyph_node_init( FTC_GlyphNode node,
+ FT_UInt gindex, /* glyph index for node */
+ FTC_GlyphSet gset );
-#define FTC_GlyphNode_Ref( n ) \
- FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count++
-
-#define FTC_GlyphNode_Unref( n ) \
- FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count--
-
-
+ /* must be called by derived FTC_Node_DoneFunc routines */
FT_EXPORT( void )
- FTC_GlyphNode_Destroy( FTC_GlyphNode node,
- FTC_Glyph_Cache cache );
+ ftc_glyph_node_done( FTC_GlyphNode node );
+
+ /* can be used as a FTC_LruNode_InitFunc or called by sub-classes */
FT_EXPORT( FT_Error )
- FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache );
+ ftc_glyph_set_init( FTC_GlyphSet gset,
+ FT_LruList list );
+ /* can be used as a FTC_LruNode_DoneFunc or called by sub-classes */
FT_EXPORT( void )
- FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache );
+ ftc_glyph_set_done( FTC_GlyphSet gset );
+ /* can be used as a FTC_Cache_DoneFunc or called by sub-classes */
+ FT_EXPORT( void )
+ ftc_glyph_cache_done( FTC_GlyphCache cache );
+
+ /* must be called in a FTC_Cache_InitFunc !! */
FT_EXPORT( FT_Error )
- FTC_GlyphSet_New( FTC_Glyph_Cache cache,
- FT_Pointer type,
- FTC_GlyphSet *aset );
+ ftc_glyph_cache_init( FTC_GlyphCache cache,
+ FT_LruList_Class gset_class );
+ /* can be called directly or from sub-classes */
FT_EXPORT( FT_Error )
- FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
- FT_UInt glyph_index,
- FTC_GlyphNode *anode );
-
- FT_EXPORT( FT_Error )
- FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache cache,
- FT_Pointer type,
- FT_UInt gindex,
- FTC_GlyphNode *anode );
+ ftc_glyph_cache_lookup( FTC_GlyphCache cache,
+ FTC_GlyphQuery query,
+ FTC_GlyphNode *anode );
FT_END_HEADER
diff --git a/include/freetype/cache/ftcimage.h b/include/freetype/cache/ftcimage.h
index 376aeab..a82cf8a 100644
--- a/include/freetype/cache/ftcimage.h
+++ b/include/freetype/cache/ftcimage.h
@@ -29,7 +29,6 @@
#include <ft2build.h>
#include FT_CACHE_H
-#include FT_CACHE_INTERNAL_GLYPH_H
FT_BEGIN_HEADER
@@ -96,6 +95,14 @@
} FTC_Image_Desc;
+ /* */
+#define FTC_IMAGE_DESC_COMPARE( d1, d2 ) \
+ ( FTC_FONT_COMPARE( &(d1)->font, &(d2)->font ) && \
+ (d1)->image_type == (d2)->image_type )
+
+#define FTC_IMAGE_DESC_HASH(d) \
+ (FT_UFast)( FTC_FONT_HASH(&(d)->font) ^ \
+ ((d)->image_type << 4) )
/*************************************************************************/
/* */
diff --git a/include/freetype/cache/ftcmanag.h b/include/freetype/cache/ftcmanag.h
index 2d97fad..0aa1086 100644
--- a/include/freetype/cache/ftcmanag.h
+++ b/include/freetype/cache/ftcmanag.h
@@ -81,12 +81,23 @@
#define FTC_MAX_FACES_DEFAULT 2
#define FTC_MAX_SIZES_DEFAULT 4
-#define FTC_MAX_BYTES_DEFAULT 200000L /* 200kByte by default! */
+#define FTC_MAX_BYTES_DEFAULT 100000L /* 200kByte by default! */
/* maximum number of caches registered in a single manager */
#define FTC_MAX_CACHES 16
+ /* handle to cache object */
+ typedef struct FTC_CacheRec_* FTC_Cache;
+
+ /* handle to cache class */
+ typedef const struct FTC_Cache_ClassRec_* FTC_Cache_Class;
+
+ /* handle to cache node */
+ typedef struct FTC_NodeRec_* FTC_Node;
+
+
+
/*************************************************************************/
/* */
/* <Struct> */
@@ -125,13 +136,15 @@
typedef struct FTC_ManagerRec_
{
FT_Library library;
- FT_Lru faces_lru;
- FT_Lru sizes_lru;
+ FT_LruList faces_list;
+ FT_LruList sizes_list;
- FT_ULong max_bytes;
- FT_ULong num_bytes;
+ FT_ULong max_weight;
+ FT_ULong cur_weight;
+
FT_UInt num_nodes;
- FT_ListRec global_lru;
+ FTC_Node nodes_list;
+
FTC_Cache caches[FTC_MAX_CACHES];
FT_Pointer request_data;
@@ -185,197 +198,135 @@
/* glyphs for a given size, some metrics, etc. */
/* */
- typedef FT_ListNodeRec FTC_CacheNodeRec;
- typedef FTC_CacheNodeRec* FTC_CacheNode;
-
- /* the field `cachenode.data' is typecast to this type */
- typedef struct FTC_CacheNode_Data_
+ /* structure size should be 20 bytes on 32-bits machines */
+ typedef struct FTC_NodeRec_
{
- FT_UShort cache_index;
- FT_Short ref_count;
+ FTC_Node mru_next; /* circular mru list pointer */
+ FTC_Node mru_prev; /* circular mru list pointer */
+ FTC_Node link; /* used for hashing.. */
+ FT_UInt32 hash; /* used for hashing too.. */
+ FT_UShort cache_index; /* index of cache this node belongs to */
+ FT_Short ref_count; /* reference count for this node.. */
+
+ } FTC_NodeRec;
- } FTC_CacheNode_Data;
+#define FTC_NODE(x) ((FTC_Node)(x))
+#define FTC_NODE_P(x) ((FTC_Node*)(x))
- /* return a pointer to FTC_CacheNode_Data contained in a */
- /* CacheNode's `data' field */
-#define FTC_CACHENODE_TO_DATA_P( n ) \
- ( (FTC_CacheNode_Data*)&(n)->data )
-
-#define FTC_LIST_TO_CACHENODE( n ) ( (FTC_CacheNode)(n) )
-
-
- /*************************************************************************/
- /* */
- /* <FuncType> */
- /* FTC_CacheNode_SizeFunc */
- /* */
- /* <Description> */
- /* A function used to compute the total size in bytes of a given */
- /* cache node. It is used by the cache manager to compute the number */
- /* of old nodes to flush when the cache is full. */
- /* */
- /* <Input> */
- /* node :: A handle to the target cache node. */
- /* */
- /* cache_data :: A generic pointer passed to the destructor. */
- /* */
- /* <Return> */
- /* The size of a given cache node in bytes. */
- /* */
- typedef FT_ULong
- (*FTC_CacheNode_SizeFunc)( FTC_CacheNode node,
- FT_Pointer cache_data );
-
-
- /*************************************************************************/
- /* */
- /* <FuncType> */
- /* FTC_CacheNode_DestroyFunc */
- /* */
- /* <Description> */
- /* A function used to destroy a given cache node. It is called by */
- /* the manager when the cache is full and old nodes need to be */
- /* flushed out. */
- /* */
- /* <Input> */
- /* node :: A handle to the target cache node. */
- /* */
- /* cache_data :: A generic pointer passed to the destructor. */
- /* */
- typedef void
- (*FTC_CacheNode_DestroyFunc)( FTC_CacheNode node,
- FT_Pointer cache_data );
-
-
- /*************************************************************************/
- /* */
- /* <Struct> */
- /* FTC_CacheNode_Class */
- /* */
- /* <Description> */
- /* A very simple structure used to describe a cache node's class to */
- /* the cache manager. */
- /* */
- /* <Fields> */
- /* size_node :: A function used to size the node. */
- /* */
- /* destroy_node :: A function used to destroy the node. */
- /* */
- /* <Note> */
- /* The cache node class doesn't include a `new_node' function because */
- /* the cache manager never allocates cache node directly; it */
- /* delegates this task to its cache objects. */
- /* */
- typedef struct FTC_CacheNode_Class_
- {
- FTC_CacheNode_SizeFunc size_node;
- FTC_CacheNode_DestroyFunc destroy_node;
-
- } FTC_CacheNode_Class;
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** CACHE DEFINITIONS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* <FuncType> */
- /* FTC_Cache_InitFunc */
- /* */
- /* <Description> */
- /* A function used to initialize a given cache object. */
- /* */
- /* <Input> */
- /* cache :: A handle to the new cache. */
- /* */
- typedef FT_Error
- (*FTC_Cache_InitFunc)( FTC_Cache cache );
-
-
- /*************************************************************************/
- /* */
- /* <FuncType> */
- /* FTC_Cache_DoneFunc */
- /* */
- /* <Description> */
- /* A function to finalize a given cache object. */
- /* */
- /* <Input> */
- /* cache :: A handle to the target cache. */
- /* */
- typedef void
- (*FTC_Cache_DoneFunc)( FTC_Cache cache );
-
-
- /*************************************************************************/
- /* */
- /* <Struct> */
- /* FTC_Cache_Class */
- /* */
- /* <Description> */
- /* A structure used to describe a given cache object class to the */
- /* cache manager. */
- /* */
- /* <Fields> */
- /* cache_byte_size :: The size of the cache object in bytes. */
- /* */
- /* init_cache :: The cache object initializer. */
- /* */
- /* done_cache :: The cache object finalizer. */
- /* */
- struct FTC_Cache_Class_
- {
- FT_UInt cache_byte_size;
- FTC_Cache_InitFunc init_cache;
- FTC_Cache_DoneFunc done_cache;
- };
-
-
- /*************************************************************************/
- /* */
- /* <Struct> */
- /* FTC_CacheRec */
- /* */
- /* <Description> */
- /* A structure used to describe an abstract cache object. */
- /* */
- /* <Fields> */
- /* manager :: A handle to the parent cache manager. */
- /* */
- /* memory :: A handle to the memory manager. */
- /* */
- /* clazz :: A pointer to the cache class. */
- /* */
- /* node_clazz :: A pointer to the cache's node class. */
- /* */
- /* cache_index :: An index of the cache in the manager's table. */
- /* */
- /* cache_data :: Data passed to the cache node */
- /* constructor/finalizer. */
- /* */
+ /* each cache really implements a dynamic hash table to manage its nodes */
typedef struct FTC_CacheRec_
{
- FTC_Manager manager;
- FT_Memory memory;
- FTC_Cache_Class* clazz;
- FTC_CacheNode_Class* node_clazz;
+ FTC_Manager manager;
+ FT_Memory memory;
+ FTC_Cache_Class clazz;
- FT_UInt cache_index; /* in manager's table */
- FT_Pointer cache_data; /* passed to cache node methods */
+ FT_UInt cache_index; /* in manager's table */
+ FT_Pointer cache_data; /* used by cache node methods */
+
+ FT_UFast nodes;
+ FT_UFast size;
+ FTC_Node* buckets;
} FTC_CacheRec;
+#define FTC_CACHE(x) ((FTC_Cache)(x))
+#define FTC_CACHE_P(x) ((FTC_Cache*)(x))
+
+
+ /* initialize a given cache */
+ typedef FT_Error
+ (*FTC_Cache_InitFunc)( FTC_Cache cache );
+
+ /* finalize a given cache */
+ typedef void
+ (*FTC_Cache_DoneFunc)( FTC_Cache cache );
+
+ /* initialize a new cache node */
+ typedef FT_Error
+ (*FTC_Node_InitFunc)( FTC_Node node,
+ FT_Pointer type,
+ FTC_Cache cache );
+
+ /* compute the weight of a given cache node */
+ typedef FT_ULong
+ (*FTC_Node_WeightFunc)( FTC_Node node,
+ FTC_Cache cache );
+
+ /* compare a node to a given key pair */
+ typedef FT_Bool
+ (*FTC_Node_CompareFunc)( FTC_Node node,
+ FT_Pointer key,
+ FTC_Cache cache );
+
+ /* finalize a given cache node */
+ typedef void
+ (*FTC_Node_DoneFunc)( FTC_Node node,
+ FTC_Cache cache );
+
+ typedef struct FTC_Cache_ClassRec_
+ {
+ FT_UInt cache_size;
+ FTC_Cache_InitFunc cache_init;
+ FTC_Cache_DoneFunc cache_done;
+
+ FT_UInt node_size;
+ FTC_Node_InitFunc node_init;
+ FTC_Node_WeightFunc node_weight;
+ FTC_Node_CompareFunc node_compare;
+ FTC_Node_DoneFunc node_done;
+
+ } FTC_Cache_ClassRec;
+
/* */
+#define FTC_CACHE_RESIZE_TEST(c) \
+ ( (c)->nodes*3 < (c)->size || \
+ (c)->size*3 < (c)->nodes )
+
+
+ /* this must be used internally for the moment */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_Register_Cache( FTC_Manager manager,
+ FTC_Cache_Class clazz,
+ FTC_Cache *acache );
+
+
+ /* can be used directory as FTC_Cache_DoneFunc, or called by custom */
+ /* cache finalizers.. */
+ FT_EXPORT( void )
+ ftc_cache_done( FTC_Cache cache );
+
+ /* initalize the hash table within the cache */
+ FT_EXPORT( FT_Error )
+ ftc_cache_init( FTC_Cache cache );
+
+ /* can be used when FTC_CACHE_RESIZE_TEST returns TRUE after a node */
+ /* insertion.. */
+ FT_EXPORT(void)
+ ftc_cache_resize( FTC_Cache cache );
+
+
+ /* can be called when the key's hash value has been computed */
+ FT_EXPORT(FT_Error)
+ ftc_cache_lookup_node( FTC_Cache cache,
+ FT_UFast key_hash,
+ FT_Pointer key,
+ FTC_Node *anode );
+
+ /* can be called to increment a node's reference count */
+ FT_EXPORT(void)
+ ftc_node_ref( FTC_Node node,
+ FTC_Cache cache );
+
+ /* can be called to decrement a node's reference count */
+ FT_EXPORT(void)
+ ftc_node_unref( FTC_Node node,
+ FTC_Cache cache );
+
+ /* */
FT_END_HEADER
diff --git a/include/freetype/cache/ftcsbits.h b/include/freetype/cache/ftcsbits.h
index aba87c8..1a30846 100644
--- a/include/freetype/cache/ftcsbits.h
+++ b/include/freetype/cache/ftcsbits.h
@@ -22,7 +22,6 @@
#include <ft2build.h>
#include FT_CACHE_H
-#include FT_CACHE_INTERNAL_CHUNK_H
#include FT_CACHE_IMAGE_H
diff --git a/include/freetype/cache/ftlru.h b/include/freetype/cache/ftlru.h
index 7874438..27fdcf1 100644
--- a/include/freetype/cache/ftlru.h
+++ b/include/freetype/cache/ftlru.h
@@ -66,117 +66,130 @@
FT_BEGIN_HEADER
- /* generic key type */
+ /* generic list key type */
typedef FT_Pointer FT_LruKey;
+ /* a list list handle */
+ typedef struct FT_LruListRec_* FT_LruList;
- /* an lru node -- root.data points to the element */
+ /* list class handle */
+ typedef const struct FT_LruList_ClassRec_* FT_LruList_Class;
+
+ /* an list node handle */
+ typedef struct FT_LruNodeRec_* FT_LruNode;
+
+ /* the list node structure */
typedef struct FT_LruNodeRec_
{
- FT_ListNodeRec root;
- FT_LruKey key;
+ FT_LruNode next;
+ FT_LruKey key;
- } FT_LruNodeRec, *FT_LruNode;
+ } FT_LruNodeRec;
- /* forward declaration */
- typedef struct FT_LruRec_* FT_Lru;
-
-
- /* LRU class */
- typedef struct FT_Lru_Class_
+ /* the list structure */
+ typedef struct FT_LruListRec_
{
- FT_UInt lru_size; /* object size in bytes */
+ FT_Memory memory;
+ FT_LruList_Class clazz;
+ FT_LruNode nodes;
+ FT_UInt max_nodes;
+ FT_UInt num_nodes;
+ FT_Pointer user_data;
- /* this method is used to initialize a new list element node */
- FT_Error
- (*init_element)( FT_Lru lru,
- FT_LruNode node );
+ } FT_LruListRec;
- /* this method is used to finalize a given list element node */
- void
- (*done_element)( FT_Lru lru,
- FT_LruNode node );
- /* If defined, this method is called when the list if full */
- /* during the lookup process -- it is used to change the contents */
- /* of a list element node, instead of calling `done_element()', */
- /* then `init_element'. Set it to 0 for default behaviour. */
- FT_Error
- (*flush_element)( FT_Lru lru,
- FT_LruNode node,
- FT_LruKey new_key );
+ /* initialize a list list */
+ typedef FT_Error (*FT_LruList_InitFunc)( FT_LruList list );
+
+ /* finalize a list list */
+ typedef void (*FT_LruList_DoneFunc)( FT_LruList list );
- /* If defined, this method is used to compare a list element node */
- /* with a given key during a lookup. If set to 0, the `key' */
- /* fields will be directly compared instead. */
- FT_Bool
- (*compare_element)( FT_LruNode node,
- FT_LruKey key );
+ /* this method is used to initialize a new list element node */
+ typedef FT_Error (*FT_LruNode_InitFunc)( FT_LruNode node,
+ FT_LruKey key,
+ FT_LruList list );
- } FT_Lru_Class;
+ /* this method is used to finalize a given list element node */
+ typedef void (*FT_LruNode_DoneFunc)( FT_LruNode node,
+ FT_LruList list );
+ /* If defined, this method is called when the list if full */
+ /* during the lookup process -- it is used to change the contents */
+ /* of a list element node, instead of calling `done_element()', */
+ /* then `init_element'. Set it to 0 for default behaviour. */
+ typedef FT_Error (*FT_LruNode_FlushFunc)( FT_LruNode node,
+ FT_LruKey new_key,
+ FT_LruList list );
+
+ /* If defined, this method is used to compare a list element node */
+ /* with a given key during a lookup. If set to 0, the `key' */
+ /* fields will be directly compared instead. */
+ typedef FT_Bool (*FT_LruNode_CompareFunc)( FT_LruNode node,
+ FT_LruKey key,
+ FT_LruList list );
/* A selector is used to indicate whether a given list element node */
- /* is part of a selection for FT_Lru_Remove_Selection(). The function */
+ /* is part of a selection for FT_LruList_Remove_Selection(). The function */
/* must return true (i.e., non-null) to indicate that the node is part */
/* of it. */
- typedef FT_Bool
- (*FT_Lru_Selector)( FT_Lru lru,
- FT_LruNode node,
- FT_Pointer data );
+ typedef FT_Bool (*FT_LruNode_SelectFunc)( FT_LruNode node,
+ FT_Pointer data,
+ FT_LruList list );
-
- typedef struct FT_LruRec_
+ /* LRU class */
+ typedef struct FT_LruList_ClassRec_
{
- FT_Lru_Class* clazz;
- FT_UInt max_elements;
- FT_UInt num_elements;
- FT_ListRec elements;
- FT_Memory memory;
- FT_Pointer user_data;
+ FT_UInt list_size;
+ FT_LruList_InitFunc list_init; /* optional */
+ FT_LruList_DoneFunc list_done; /* optional */
+
+ FT_UInt node_size;
+ FT_LruNode_InitFunc node_init; /* MANDATORY */
+ FT_LruNode_DoneFunc node_done; /* optional */
+ FT_LruNode_FlushFunc node_flush; /* optional */
+ FT_LruNode_CompareFunc node_compare; /* optional */
- /* the following fields are only meaningful for static lru containers */
- FT_ListRec free_nodes;
- FT_LruNode nodes;
+ } FT_LruList_ClassRec;
- } FT_LruRec;
+
+ /* the following functions must be exported in the case where applications */
+ /* would want to write their own cache classes.. */
+
+ FT_EXPORT( FT_Error )
+ FT_LruList_New( FT_LruList_Class clazz,
+ FT_UInt max_elements,
+ FT_Pointer user_data,
+ FT_Memory memory,
+ FT_LruList *alist );
+
+ FT_EXPORT( void )
+ FT_LruList_Reset( FT_LruList list );
+
+
+ FT_EXPORT( void )
+ FT_LruList_Destroy ( FT_LruList list );
FT_EXPORT( FT_Error )
- FT_Lru_New( const FT_Lru_Class* clazz,
- FT_UInt max_elements,
- FT_Pointer user_data,
- FT_Memory memory,
- FT_Bool pre_alloc,
- FT_Lru *anlru );
+ FT_LruList_Lookup( FT_LruList list,
+ FT_LruKey key,
+ FT_LruNode *anode );
+
FT_EXPORT( void )
- FT_Lru_Reset( FT_Lru lru );
+ FT_LruList_Remove( FT_LruList list,
+ FT_LruNode node );
+
FT_EXPORT( void )
- FT_Lru_Done ( FT_Lru lru );
+ FT_LruList_Remove_Selection( FT_LruList list,
+ FT_LruNode_SelectFunc select_func,
+ FT_Pointer select_data );
- FT_EXPORT( FT_Error )
- FT_Lru_Lookup_Node( FT_Lru lru,
- FT_LruKey key,
- FT_LruNode *anode );
-
- FT_EXPORT( FT_Error )
- FT_Lru_Lookup( FT_Lru lru,
- FT_LruKey key,
- FT_Pointer *anobject );
-
- FT_EXPORT( void )
- FT_Lru_Remove_Node( FT_Lru lru,
- FT_LruNode node );
-
- FT_EXPORT( void )
- FT_Lru_Remove_Selection( FT_Lru lru,
- FT_Lru_Selector selector,
- FT_Pointer data );
-
-
+ /* */
+
FT_END_HEADER
#endif /* __FTLRU_H__ */
diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h
index fc15956..8fcbd19 100644
--- a/include/freetype/ftcache.h
+++ b/include/freetype/ftcache.h
@@ -142,6 +142,19 @@
} FTC_FontRec;
+ /* */
+
+#define FTC_FONT_COMPARE(f1,f2) \
+ ( (f1)->face_id == (f2)->face_id && \
+ (f1)->pix_width == (f2)->pix_width && \
+ (f1)->pix_height == (f2)->pix_height )
+
+#define FTC_FACE_ID_HASH(i) ((FT_UInt32)(FT_Pointer)(i))
+
+#define FTC_FONT_HASH(f) \
+ (FT_UInt32)( FTC_FACE_ID_HASH((f)->face_id) ^ \
+ ((f)->pix_width << 8) ^ \
+ ((f)->pix_height) )
/*************************************************************************/
/* */
@@ -334,19 +347,6 @@
FT_Face *aface,
FT_Size *asize );
-
- /* a cache class is used to describe a unique cache type to the manager */
- typedef struct FTC_Cache_Class_ FTC_Cache_Class;
- typedef struct FTC_CacheRec_* FTC_Cache;
-
-
- /* this must be used internally for the moment */
- FT_EXPORT( FT_Error )
- FTC_Manager_Register_Cache( FTC_Manager manager,
- FTC_Cache_Class* clazz,
- FTC_Cache *acache );
-
-
/* */
diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c
index 048df3e..42ccc97 100644
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -1,6 +1,7 @@
#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
#include FT_SYSTEM_H
#include FT_ERRORS_H
#include FT_TYPES_H
@@ -173,7 +174,7 @@
if ( new_buckets == NULL )
return;
- memset( new_buckets, 0, sizeof(FT_MemNode)*new_size );
+ MEM_Set( new_buckets, 0, sizeof(FT_MemNode)*new_size );
for ( i = 0; i < table->size; i++ )
{
@@ -211,7 +212,7 @@
table = memory->alloc( memory, sizeof(*table) );
if ( table == NULL ) goto Exit;
- memset( table, 0, sizeof(*table) );
+ MEM_Set( table, 0, sizeof(*table) );
table->size = FT_MEM_SIZE_MIN;
table->nodes = 0;
@@ -226,7 +227,7 @@
table->buckets = memory->alloc( memory, table->size * sizeof(FT_MemNode) );
if ( table->buckets )
- memset( table->buckets, 0, sizeof(FT_MemNode)*table->size );
+ MEM_Set( table->buckets, 0, sizeof(FT_MemNode)*table->size );
else
{
memory->free( memory, table );
@@ -408,7 +409,7 @@
/* we simply invert the node's size to indicate that the node */
/* was freed. We also change its content.. */
- memset( address, 0xF3, node->size );
+ MEM_Set( address, 0xF3, node->size );
table->alloc_current -= node->size;
node->size = -node->size;
diff --git a/src/cache/ftcchunk.c b/src/cache/ftcchunk.c
index 7e60393..9fc08af 100644
--- a/src/cache/ftcchunk.c
+++ b/src/cache/ftcchunk.c
@@ -34,73 +34,62 @@
/*************************************************************************/
/*************************************************************************/
+#define FTC_CSET_HASH(cset,start) \
+ ((FT_UFast)(((cset)->hash << 16) | ((start) & 0xFFFF)))
/* create a new chunk node, setting its cache index and ref count */
FT_EXPORT_DEF( FT_Error )
- FTC_ChunkNode_Init( FTC_ChunkNode node,
- FTC_ChunkSet cset,
- FT_UInt index,
- FT_Bool alloc )
+ ftc_chunk_node_init( FTC_ChunkNode cnode,
+ FTC_ChunkSet cset,
+ FT_UInt gindex,
+ FT_Bool alloc )
{
- FTC_Chunk_Cache cache = cset->cache;
- FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root );
- FT_Error error = 0;
+ FTC_ChunkCache ccache = cset->ccache;
+ FT_Error error = 0;
+ FT_UInt len;
+ FT_UInt start = (gindex / cset->item_count) * cset->item_count;
+ cnode->cset = cset;
+ cnode->node.hash = FTC_CSET_HASH(cset,start);
+ cnode->item_start = start;
- data->cache_index = (FT_UShort)cache->root.cache_index;
- data->ref_count = (FT_Short) 0;
- node->cset = cset;
- node->cset_index = (FT_UShort)index;
- node->num_elements = (unsigned short)(
- ( index + 1 < cset->num_chunks )
- ? cset->element_count
- : cset->element_max - cset->element_count*index );
+ len = cset->item_total - start;
+ if ( len > cset->item_count )
+ len = cset->item_count;
+
+ cnode->item_count = len;
+
if ( alloc )
{
- /* allocate elements array */
- FT_Memory memory;
-
-
- memory = cache->root.memory;
- error = MEM_Alloc( node->elements,
- cset->element_size * cset->element_count );
+ FT_Memory memory = ccache->cache.memory;
+
+ error = MEM_Alloc( cnode->items, cset->item_size * cnode->item_count );
}
+ if (!error )
+ cset->num_chunks++;
+
return error;
}
FT_EXPORT_DEF( void )
- FTC_ChunkNode_Destroy( FTC_ChunkNode node )
+ ftc_chunk_node_done( FTC_ChunkNode cnode )
{
- FTC_ChunkSet cset = node->cset;
-
-
- /* remove from parent set table */
- cset->chunks[node->cset_index] = 0;
+ FTC_ChunkSet cset = cnode->cset;
+ FT_Memory memory = cset->ccache->cache.memory;
/* destroy the node */
- cset->clazz->destroy_node( node );
+ FREE( cnode->items );
+ cnode->item_count = 0;
+ cnode->item_start = 0;
+
+ /* remove from parent set table - eventually destroy the set */
+ if ( --cset->num_chunks <= 0 )
+ FT_LruList_Remove( cset->ccache->cset_lru, (FT_LruNode) cset );
}
- FT_EXPORT_DEF( FT_ULong )
- FTC_ChunkNode_Size( FTC_ChunkNode node )
- {
- FTC_ChunkSet cset = node->cset;
-
-
- return cset->clazz->size_node( node );
- }
-
-
- FT_CALLBACK_TABLE_DEF
- const FTC_CacheNode_Class ftc_chunk_cache_node_class =
- {
- (FTC_CacheNode_SizeFunc) FTC_ChunkNode_Size,
- (FTC_CacheNode_DestroyFunc)FTC_ChunkNode_Destroy
- };
-
/*************************************************************************/
/*************************************************************************/
@@ -112,339 +101,88 @@
FT_EXPORT_DEF( FT_Error )
- FTC_ChunkSet_New( FTC_Chunk_Cache cache,
- FT_Pointer type,
- FTC_ChunkSet *aset )
+ ftc_chunk_set_init( FTC_ChunkSet cset,
+ FT_UInt item_size,
+ FT_UInt item_count,
+ FT_UInt item_total,
+ FTC_ChunkCache cache )
{
- FT_Error error;
- FT_Memory memory = cache->root.memory;
- FTC_Manager manager = cache->root.manager;
- FTC_ChunkSet cset = 0;
+ cset->ccache = cache;
+ cset->num_chunks = 0;
- FTC_Chunk_Cache_Class* ccache_class;
- FTC_ChunkSet_Class* clazz;
+ cset->item_total = item_total;
+ cset->item_size = item_size;
+ cset->item_count = item_count;
-
- ccache_class = (FTC_Chunk_Cache_Class*)cache->root.clazz;
- clazz = ccache_class->cset_class;
-
- *aset = 0;
-
- if ( ALLOC( cset, clazz->cset_byte_size ) )
- goto Exit;
-
- cset->cache = cache;
- cset->manager = manager;
- cset->memory = memory;
- cset->clazz = clazz;
-
- /* now compute element_max, element_count and element_size */
- error = clazz->sizes( cset, type );
- if ( error )
- goto Exit;
-
- /* compute maximum number of nodes */
- cset->num_chunks = ( cset->element_max + cset->element_count - 1 ) /
- cset->element_count;
-
- /* allocate chunk pointers table */
- if ( ALLOC_ARRAY( cset->chunks, cset->num_chunks, FTC_ChunkNode ) )
- goto Exit;
-
- /* initialize set by type if needed */
- if ( clazz->init )
- {
- error = clazz->init( cset, type );
- if ( error )
- goto Exit;
- }
-
- *aset = cset;
-
- Exit:
- if ( error && cset )
- {
- FREE( cset->chunks );
- FREE( cset );
- }
-
- return error;
+ return 0;
}
FT_EXPORT_DEF( void )
- FTC_ChunkSet_Destroy( FTC_ChunkSet cset )
+ ftc_chunk_set_done( FTC_ChunkSet cset )
{
- FTC_Chunk_Cache cache = cset->cache;
- FTC_Manager manager = cache->root.manager;
- FT_List glyphs_lru = &manager->global_lru;
- FTC_ChunkNode* bucket = cset->chunks;
- FTC_ChunkNode* bucket_limit = bucket + cset->num_chunks;
- FT_Memory memory = cache->root.memory;
-
- FTC_ChunkSet_Class* clazz = cset->clazz;
+ /* nothing for now */
+ FT_UNUSED( cset );
+ }
- /* for each bucket, free the list of glyph nodes */
- for ( ; bucket < bucket_limit; bucket++ )
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHUNK CACHES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( void )
+ ftc_chunk_cache_done( FTC_ChunkCache ccache )
+ {
+ ftc_cache_done( FTC_CACHE(ccache) );
+
+ /* simply delete all remaining glyph sets */
+ if ( ccache->cset_lru )
{
- FTC_ChunkNode node = bucket[0];
- FT_ListNode lrunode;
-
-
- if ( node )
- {
- lrunode = FTC_CHUNKNODE_TO_LRUNODE( node );
-
- manager->num_bytes -= clazz->size_node( node );
- manager->num_nodes--;
-
- FT_List_Remove( glyphs_lru, lrunode );
-
- clazz->destroy_node( node );
-
- bucket[0] = 0;
- }
+ FT_LruList_Destroy( ccache->cset_lru );
+ ccache->cset_lru = NULL;
}
-
- if ( clazz->done )
- clazz->done( cset );
-
- FREE( cset->chunks );
- FREE( cset );
}
FT_EXPORT_DEF( FT_Error )
- FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset,
- FT_UInt glyph_index,
- FTC_ChunkNode *anode,
- FT_UInt *anindex )
+ ftc_chunk_cache_init( FTC_ChunkCache ccache,
+ FT_LruList_Class cset_class )
{
- FTC_Chunk_Cache cache = cset->cache;
- FTC_Manager manager = cache->root.manager;
- FT_Error error = 0;
+ FT_Error error;
- FTC_ChunkSet_Class* clazz = cset->clazz;
+ error = ftc_cache_init( FTC_CACHE(ccache) );
+ if (error) goto Exit;
-
- *anode = 0;
-
- if ( glyph_index >= cset->element_max )
- error = FTC_Err_Invalid_Argument;
- else
- {
- FT_UInt chunk_size = cset->element_count;
- FT_UInt chunk_index = glyph_index / chunk_size;
- FTC_ChunkNode* pnode = cset->chunks + chunk_index;
- FTC_ChunkNode node = *pnode;
-
-
- if ( !node )
- {
- /* we didn't found the glyph image; we will now create a new one */
- error = clazz->new_node( cset, chunk_index, &node );
- if ( error )
- goto Exit;
-
- /* store the new chunk in the cset's table */
- *pnode = node;
-
- /* insert the node at the start the global LRU glyph list */
- FT_List_Insert( &manager->global_lru,
- FTC_CHUNKNODE_TO_LRUNODE( node ) );
-
- manager->num_bytes += clazz->size_node( node );
- manager->num_nodes++;
-
- if ( manager->num_bytes > manager->max_bytes )
- {
- FTC_ChunkNode_Ref ( node );
- FTC_Manager_Compress( manager );
- FTC_ChunkNode_Unref ( node );
- }
- }
-
- *anode = node;
- *anindex = glyph_index - chunk_index * chunk_size;
- }
-
+ error = FT_LruList_New( cset_class, 0, ccache,
+ ccache->cache.memory,
+ &ccache->cset_lru );
Exit:
return error;
}
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** CHUNK SETS LRU CALLBACKS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
-#define FTC_CSET_LRU_GET_CACHE( lru ) \
- ( (FTC_Chunk_Cache)((lru)->user_data) )
-
-#define FTC_CSET_LRU_GET_MANAGER( lru ) \
- FTC_CSET_LRU_GET_CACHE( lru )->manager
-
-#define FTC_LRUNODE_CSET( node ) \
- ( (FTC_ChunkSet)(node)->root.data )
-
-
- FT_CALLBACK_DEF( FT_Error )
- ftc_chunk_set_lru_init( FT_Lru lru,
- FT_LruNode node )
+ FT_EXPORT_DEF( FT_Error )
+ ftc_chunk_cache_lookup( FTC_ChunkCache ccache,
+ FTC_ChunkQuery query,
+ FTC_ChunkNode *anode )
{
- FTC_Chunk_Cache cache = FTC_CSET_LRU_GET_CACHE( lru );
- FT_Error error;
- FTC_ChunkSet cset;
-
-
- error = FTC_ChunkSet_New( cache,
- (FT_Pointer)node->key,
- &cset );
+ FT_LruNode node;
+ FT_Error error;
+
+ error = FT_LruList_Lookup( ccache->cset_lru, query, &node );
if ( !error )
{
- /* good, now set the set index within the set object */
- cset->cset_index = (FT_UInt)( node - lru->nodes );
- node->root.data = cset;
+ FTC_ChunkSet cset = FTC_CHUNK_SET(node);
+ FT_UFast hash = FTC_CSET_HASH( cset, query->gindex );
+
+ error = ftc_cache_lookup_node( FTC_CACHE(ccache), hash, query,
+ FTC_NODE_P(anode) );
}
-
- return error;
- }
-
-
- FT_CALLBACK_DEF( void )
- ftc_chunk_set_lru_done( FT_Lru lru,
- FT_LruNode node )
- {
- FTC_ChunkSet cset = FTC_LRUNODE_CSET( node );
-
- FT_UNUSED( lru );
-
-
- FTC_ChunkSet_Destroy( cset );
- }
-
-
- FT_CALLBACK_DEF( FT_Bool )
- ftc_chunk_set_lru_compare( FT_LruNode node,
- FT_LruKey key )
- {
- FTC_ChunkSet cset = FTC_LRUNODE_CSET( node );
-
-
- return cset->clazz->compare( cset, (FT_Pointer)key );
- }
-
-
- FT_CALLBACK_TABLE_DEF
- const FT_Lru_Class ftc_chunk_set_lru_class =
- {
- sizeof( FT_LruRec ),
- ftc_chunk_set_lru_init,
- ftc_chunk_set_lru_done,
- 0, /* no flush */
- ftc_chunk_set_lru_compare
- };
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** CHUNK CACHE OBJECTS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
- FT_EXPORT_DEF( FT_Error )
- FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache )
- {
- FT_Memory memory = cache->root.memory;
- FT_Error error;
-
- FTC_Chunk_Cache_Class* ccache_clazz;
-
-
- /* set up root node_class to be used by manager */
- cache->root.node_clazz =
- (FTC_CacheNode_Class*)&ftc_chunk_cache_node_class;
-
- /* setup `compare' shortcut */
- ccache_clazz = (FTC_Chunk_Cache_Class*)cache->root.clazz;
- cache->compare = ccache_clazz->cset_class->compare;
-
- error = FT_Lru_New( &ftc_chunk_set_lru_class,
- FTC_MAX_CHUNK_SETS,
- cache,
- memory,
- 1, /* pre_alloc == TRUE */
- &cache->csets_lru );
- return error;
- }
-
-
- FT_EXPORT_DEF( void )
- FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache )
- {
- /* discard glyph sets */
- FT_Lru_Done( cache->csets_lru );
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache cache,
- FT_Pointer type,
- FT_UInt gindex,
- FTC_ChunkNode *anode,
- FT_UInt *aindex )
- {
- FT_Error error;
- FTC_ChunkSet cset;
- FTC_ChunkNode node;
- FT_UInt cindex;
- FTC_Manager manager;
-
-
- /* check for valid `desc' delayed to FT_Lru_Lookup() */
-
- if ( !cache || !anode || !aindex )
- return FTC_Err_Invalid_Argument;
-
- *anode = 0;
- *aindex = 0;
- cset = cache->last_cset;
-
- if ( !cset || !cache->compare( cset, type ) )
- {
- error = FT_Lru_Lookup( cache->csets_lru,
- (FT_LruKey)type,
- (FT_Pointer*)&cset );
- cache->last_cset = cset;
- if ( error )
- goto Exit;
- }
-
- error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
- if ( error )
- goto Exit;
-
- /* now compress the manager's cache pool if needed */
- manager = cache->root.manager;
- if ( manager->num_bytes > manager->max_bytes )
- {
- FTC_ChunkNode_Ref ( node );
- FTC_Manager_Compress( manager );
- FTC_ChunkNode_Unref ( node );
- }
-
- *anode = node;
- *aindex = cindex;
-
- Exit:
return error;
}
diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c
index c524b53..6519fd2 100644
--- a/src/cache/ftcglyph.c
+++ b/src/cache/ftcglyph.c
@@ -35,21 +35,19 @@
/*************************************************************************/
/*************************************************************************/
+#define FTC_GSET_HASH(gset,gindex) \
+ ((FT_UFast)(((gset)->hash << 16) | ((gindex) & 0xFFFF)))
+
/* create a new glyph node, setting its cache index and ref count */
FT_EXPORT_DEF( void )
- FTC_GlyphNode_Init( FTC_GlyphNode node,
- FTC_GlyphSet gset,
- FT_UInt gindex )
+ ftc_glyph_node_init( FTC_GlyphNode gnode,
+ FT_UInt gindex,
+ FTC_GlyphSet gset )
{
- FTC_Glyph_Cache cache = gset->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->gset_index = (FT_UShort)gset->gset_index;
- node->glyph_index = (FT_UShort)gindex;
+ gnode->gset = gset;
+ gnode->node.hash = FTC_GSET_HASH( gset, gindex );
+ gset->num_glyphs++;
}
@@ -61,71 +59,15 @@
/* will happen! */
FT_EXPORT_DEF( void )
- FTC_GlyphNode_Destroy( FTC_GlyphNode node,
- FTC_Glyph_Cache cache )
+ ftc_glyph_node_done( FTC_GlyphNode gnode )
{
- FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index;
- FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data;
- FT_UInt hash = node->glyph_index % gset->hash_size;
-
-
- /* remove the node from its gset's bucket list */
- {
- FTC_GlyphNode* pnode = gset->buckets + hash;
- FTC_GlyphNode cur;
-
-
- for (;;)
- {
- cur = *pnode;
- if ( !cur )
- {
- /* this should never happen */
- FT_ERROR(( "FTC_GlyphNode_Destroy:"
- " trying to delete an unlisted node!" ));
- return;
- }
-
- if ( cur == node )
- {
- *pnode = cur->gset_next;
- break;
- }
- pnode = &cur->gset_next;
- }
- }
-
- /* destroy the node */
- gset->clazz->destroy_node( node, gset );
+ FTC_GlyphSet gset = gnode->gset;
+
+ if ( --gset->num_glyphs <= 0 )
+ FT_LruList_Remove( gset->gcache->gset_lru, (FT_LruNode) gset );
}
- /* 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'. Thus be */
- /* certain that the function FTC_Glyph_Cache_New() does indeed */
- /* set its `user_data' field correctly, otherwise bad things */
- /* will happen! */
-
- FT_EXPORT_DEF( FT_ULong )
- FTC_GlyphNode_Size( FTC_GlyphNode node,
- FTC_Glyph_Cache cache )
- {
- FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index;
- FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data;
-
-
- return gset->clazz->size_node( node, gset );
- }
-
-
- FT_CALLBACK_TABLE_DEF
- const FTC_CacheNode_Class ftc_glyph_cache_node_class =
- {
- (FTC_CacheNode_SizeFunc) FTC_GlyphNode_Size,
- (FTC_CacheNode_DestroyFunc)FTC_GlyphNode_Destroy
- };
-
/*************************************************************************/
/*************************************************************************/
@@ -135,347 +77,88 @@
/*************************************************************************/
/*************************************************************************/
-
FT_EXPORT_DEF( FT_Error )
- FTC_GlyphSet_New( FTC_Glyph_Cache cache,
- FT_Pointer type,
- FTC_GlyphSet *aset )
+ ftc_glyph_set_init( FTC_GlyphSet gset,
+ FT_LruList lru )
{
- FT_Error error;
- FT_Memory memory = cache->root.memory;
- FTC_Manager manager = cache->root.manager;
- FTC_GlyphSet gset = 0;
-
- FTC_Glyph_Cache_Class* gcache_class;
- FTC_GlyphSet_Class* clazz;
-
-
- gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
- clazz = gcache_class->gset_class;
-
- *aset = 0;
-
- if ( ALLOC( gset, clazz->gset_byte_size ) )
- goto Exit;
-
- gset->cache = cache;
- gset->manager = manager;
- gset->memory = memory;
- gset->hash_size = FTC_GSET_HASH_SIZE_DEFAULT;
- gset->clazz = clazz;
-
- /* allocate buckets table */
- if ( ALLOC_ARRAY( gset->buckets, gset->hash_size, FTC_GlyphNode ) )
- goto Exit;
-
- /* initialize gset by type if needed */
- if ( clazz->init )
- {
- error = clazz->init( gset, type );
- if ( error )
- goto Exit;
- }
-
- *aset = gset;
-
- Exit:
- if ( error && gset )
- {
- FREE( gset->buckets );
- FREE( gset );
- }
-
- return error;
- }
+ FTC_GlyphCache gcache = lru->user_data;
+
+ gset->gcache = gcache;
+ gset->num_glyphs = 0;
+
+ return 0;
+ }
FT_EXPORT_DEF( void )
- FTC_GlyphSet_Destroy( FTC_GlyphSet gset )
+ ftc_glyph_set_done( FTC_GlyphSet gset )
{
- FTC_Glyph_Cache cache = gset->cache;
- FTC_Manager manager = cache->root.manager;
- FT_List glyphs_lru = &manager->global_lru;
- FTC_GlyphNode* bucket = gset->buckets;
- FTC_GlyphNode* bucket_limit = bucket + gset->hash_size;
- FT_Memory memory = cache->root.memory;
-
- FTC_GlyphSet_Class* clazz = gset->clazz;
+ /* for now, nothing to be done here */
+ FT_UNUSED(gset);
+ }
- /* for each bucket, free the list of glyph nodes */
- for ( ; bucket < bucket_limit; bucket++ )
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH CACHES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( void )
+ ftc_glyph_cache_done( FTC_GlyphCache gcache )
+ {
+ /* remove all nodes in the cache */
+ ftc_cache_done( &gcache->cache );
+
+ /* simply delete all remaining glyph sets */
+ if ( gcache->gset_lru )
{
- FTC_GlyphNode node = bucket[0];
- FTC_GlyphNode next = 0;
- FT_ListNode lrunode;
-
-
- for ( ; node; node = next )
- {
- next = node->gset_next;
- lrunode = FTC_GLYPHNODE_TO_LRUNODE( node );
-
- manager->num_bytes -= clazz->size_node( node, gset );
- manager->num_nodes--;
-
- FT_List_Remove( glyphs_lru, lrunode );
-
- clazz->destroy_node( node, gset );
- }
-
- bucket[0] = 0;
+ FT_LruList_Destroy( gcache->gset_lru );
+ gcache->gset_lru = NULL;
}
-
- if ( clazz->done )
- clazz->done( gset );
-
- FREE( gset->buckets );
- FREE( gset );
}
FT_EXPORT_DEF( FT_Error )
- FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
- FT_UInt glyph_index,
- FTC_GlyphNode *anode )
+ ftc_glyph_cache_init( FTC_GlyphCache gcache,
+ FT_LruList_Class gset_class )
{
- FTC_Glyph_Cache cache = gset->cache;
- FTC_Manager manager = cache->root.manager;
- FT_UInt hash_index = glyph_index % gset->hash_size;
- FTC_GlyphNode* bucket = gset->buckets + hash_index;
- FTC_GlyphNode* pnode = bucket;
- FTC_GlyphNode node;
- FT_Error error;
+ FT_Error error;
- FTC_GlyphSet_Class* clazz = gset->clazz;
-
-
- *anode = 0;
-
- for ( ;; )
- {
- node = *pnode;
- if ( !node )
- break;
-
- if ( (FT_UInt)node->glyph_index == glyph_index )
- {
- /* we found it! -- move glyph to start of the lists */
- *pnode = node->gset_next;
- node->gset_next = bucket[0];
- bucket[0] = node;
-
- FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
- *anode = node;
- return 0;
- }
- /* go to next node in bucket */
- pnode = &node->gset_next;
- }
-
- /* we didn't found the glyph image, we will now create a new one */
- error = clazz->new_node( gset, glyph_index, &node );
- if ( error )
- goto Exit;
-
- /* insert the node at the start of our bucket list */
- node->gset_next = bucket[0];
- bucket[0] = node;
-
- /* insert the node at the start the global LRU glyph list */
- FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
-
- manager->num_bytes += clazz->size_node( node, gset );
- manager->num_nodes++;
-
- if ( manager->num_bytes > manager->max_bytes )
- {
- FTC_GlyphNode_Ref ( node );
- FTC_Manager_Compress( manager );
- FTC_GlyphNode_Unref ( node );
- }
-
- *anode = node;
-
+ error = ftc_cache_init( FTC_CACHE(gcache) );
+ if (error) goto Exit;
+
+ error = FT_LruList_New( gset_class, 0, gcache,
+ gcache->cache.memory,
+ &gcache->gset_lru );
Exit:
return error;
}
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** GLYPH SETS LRU CALLBACKS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
-#define FTC_GSET_LRU_GET_CACHE( lru ) \
- ( (FTC_Glyph_Cache)(lru)->user_data )
-
-#define FTC_GSET_LRU_GET_MANAGER( lru ) \
- FTC_GSET_LRU_GET_CACHE( lru )->manager
-
-#define FTC_LRUNODE_GSET( node ) \
- ( (FTC_GlyphSet)(node)->root.data )
-
-
- FT_CALLBACK_DEF( FT_Error )
- ftc_glyph_set_lru_init( FT_Lru lru,
- FT_LruNode node )
+ FT_EXPORT_DEF( FT_Error )
+ ftc_glyph_cache_lookup( FTC_GlyphCache gcache,
+ FTC_GlyphQuery query,
+ FTC_GlyphNode *anode )
{
- FTC_Glyph_Cache cache = FTC_GSET_LRU_GET_CACHE( lru );
- FT_Error error;
- FTC_GlyphSet gset;
-
-
- error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset );
+ FT_LruNode node;
+ FT_Error error;
+
+ error = FT_LruList_Lookup( gcache->gset_lru, query, &node );
if ( !error )
{
- /* good, now set the gset index within the gset object */
- gset->gset_index = (FT_UInt)( node - lru->nodes );
- node->root.data = gset;
+ FTC_GlyphSet gset = (FTC_GlyphSet) node;
+ FT_UFast hash = FTC_GSET_HASH( gset, query->gindex );
+
+ error = ftc_cache_lookup_node( FTC_CACHE(gcache), hash, query,
+ FTC_NODE_P(anode) );
}
-
return error;
}
- FT_CALLBACK_DEF( void )
- ftc_glyph_set_lru_done( FT_Lru lru,
- FT_LruNode node )
- {
- FTC_GlyphSet gset = FTC_LRUNODE_GSET( node );
-
- FT_UNUSED( lru );
-
-
- FTC_GlyphSet_Destroy( gset );
- }
-
-
- FT_CALLBACK_DEF( FT_Bool )
- ftc_glyph_set_lru_compare( FT_LruNode node,
- FT_LruKey key )
- {
- FTC_GlyphSet gset = FTC_LRUNODE_GSET( node );
-
-
- return gset->clazz->compare( gset, (FT_Pointer)key );
- }
-
-
- FT_CALLBACK_TABLE_DEF
- const FT_Lru_Class ftc_glyph_set_lru_class =
- {
- sizeof( FT_LruRec ),
- ftc_glyph_set_lru_init,
- ftc_glyph_set_lru_done,
- 0, /* no flush */
- ftc_glyph_set_lru_compare
- };
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** GLYPH CACHE OBJECTS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
- FT_EXPORT_DEF( FT_Error )
- FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache )
- {
- FT_Memory memory = cache->root.memory;
- FT_Error error;
-
- FTC_Glyph_Cache_Class* gcache_clazz;
-
-
- /* set up root node_class to be used by manager */
- cache->root.node_clazz =
- (FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
-
- /* setup the `compare' shortcut */
- gcache_clazz = (FTC_Glyph_Cache_Class*)cache->root.clazz;
- cache->compare = gcache_clazz->gset_class->compare;
-
- /* 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 `cache_data' and must be set to */
- /* `cache' here. */
- /* */
- cache->root.cache_data = cache;
-
- error = FT_Lru_New( &ftc_glyph_set_lru_class,
- FTC_MAX_GLYPH_SETS,
- cache,
- memory,
- 1, /* pre_alloc == TRUE */
- &cache->gsets_lru );
- return error;
- }
-
-
- FT_EXPORT_DEF( void )
- FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache )
- {
- /* discard glyph sets */
- FT_Lru_Done( cache->gsets_lru );
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache cache,
- FT_Pointer type,
- FT_UInt gindex,
- FTC_GlyphNode *anode )
- {
- FT_Error error;
- FTC_GlyphSet gset;
- FTC_GlyphNode node;
- FTC_Manager manager;
-
-
- /* check for valid `desc' delayed to FT_Lru_Lookup() */
-
- if ( !cache || !anode )
- return FTC_Err_Invalid_Argument;
-
- *anode = 0;
- gset = cache->last_gset;
-
- if ( !gset || !cache->compare( gset, type ) )
- {
- error = FT_Lru_Lookup( cache->gsets_lru,
- (FT_LruKey)type,
- (FT_Pointer*)&gset );
- cache->last_gset = gset;
- if ( error )
- goto Exit;
- }
-
- error = FTC_GlyphSet_Lookup_Node( gset, gindex, &node );
- if ( error )
- goto Exit;
-
- /* now compress the manager's cache pool if needed */
- manager = cache->root.manager;
- if ( manager->num_bytes > manager->max_bytes )
- {
- FTC_GlyphNode_Ref ( node );
- FTC_Manager_Compress( manager );
- FTC_GlyphNode_Unref ( node );
- }
-
- *anode = node;
-
- Exit:
- return error;
- }
-
/* END */
diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c
index 2c93a23..c635ae9 100644
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -19,6 +19,7 @@
#include <ft2build.h>
#include FT_CACHE_H
#include FT_CACHE_IMAGE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
#include FT_INTERNAL_MEMORY_H
#include "ftcerror.h"
@@ -27,30 +28,36 @@
#include <stdlib.h> /* labs() */
- /* the FT_Glyph image `glyph node' type */
- typedef struct FTC_GlyphImageRec_
+ /* the FT_Glyph image node type */
+ typedef struct FTC_ImageNodeRec_
{
- FTC_GlyphNodeRec root;
- FT_Glyph ft_glyph;
+ FTC_GlyphNodeRec gnode;
+ FT_Glyph glyph;
- } FTC_GlyphImageRec, *FTC_GlyphImage;
+ } FTC_ImageNodeRec, *FTC_ImageNode;
+#define FTC_IMAGE_NODE(x) ((FTC_ImageNode)(x))
+#define FTC_IMAGE_NODE_GINDEX(x) FTC_GLYPH_NODE_GINDEX(x)
- /* the glyph image queue type */
+ /* the glyph image set type */
typedef struct FTC_ImageSetRec_
{
- FTC_GlyphSetRec root;
+ FTC_GlyphSetRec gset;
FTC_Image_Desc description;
} FTC_ImageSetRec, *FTC_ImageSet;
+#define FTC_IMAGE_SET(x) ((FTC_ImageSet)(x))
- typedef struct FTC_Image_CacheRec_
+#define FTC_IMAGE_SET_MEMORY(x) FTC_GLYPH_SET_MEMORY(&(x)->gset)
+
+
+ typedef struct FTC_ImageQueryRec_
{
- FTC_Glyph_CacheRec root;
-
- } FTC_Image_CacheRec;
-
+ FTC_GlyphQueryRec glyph;
+ FTC_Image_Desc desc;
+
+ } FTC_ImageQueryRec, *FTC_ImageQuery;
/*************************************************************************/
@@ -62,47 +69,41 @@
/*************************************************************************/
+ /* finalize a given glyph image node */
FT_CALLBACK_DEF( void )
- ftc_glyph_image_node_destroy( FTC_GlyphImage node,
- FTC_GlyphSet gset )
+ ftc_image_node_done( FTC_ImageNode inode )
{
- FT_Memory memory = gset->memory;
-
-
- FT_Done_Glyph( node->ft_glyph );
- FREE( node );
+ if (inode->glyph)
+ {
+ FT_Done_Glyph( inode->glyph );
+ inode->glyph = NULL;
+ }
}
+ /* initialize a new glyph image node */
FT_CALLBACK_DEF( FT_Error )
- ftc_glyph_image_node_new( FTC_GlyphSet gset,
- FT_UInt glyph_index,
- FTC_GlyphImage *anode )
+ ftc_image_node_init( FTC_ImageNode inode,
+ FTC_GlyphQuery query )
{
- FT_Memory memory = gset->memory;
- FTC_ImageSet imageset = (FTC_ImageSet)gset;
+ FTC_ImageSet iset = FTC_IMAGE_SET( query->gset );
+ FT_Memory memory = FTC_IMAGE_SET_MEMORY( iset );
FT_Error error;
- FTC_GlyphImage node = 0;
FT_Face face;
FT_Size size;
-
- /* allocate node */
- if ( ALLOC( node, sizeof ( *node ) ) )
- goto Exit;
-
/* initialize its inner fields */
- FTC_GlyphNode_Init( FTC_GLYPHNODE( node ), gset, glyph_index );
+ ftc_glyph_node_init( FTC_GLYPH_NODE(inode), query->gindex, query->gset );
/* we will now load the glyph image */
- error = FTC_Manager_Lookup_Size( gset->manager,
- &imageset->description.font,
+ error = FTC_Manager_Lookup_Size( iset->gset.gcache->cache.manager,
+ &iset->description.font,
&face, &size );
if ( !error )
{
- FT_UInt gindex = node->root.glyph_index;
+ FT_UInt gindex = FTC_GLYPH_NODE_GINDEX(inode);
FT_UInt load_flags = FT_LOAD_DEFAULT;
- FT_UInt image_type = imageset->description.image_type;
+ FT_UInt image_type = iset->description.image_type;
if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
@@ -142,31 +143,29 @@
error = FT_Get_Glyph( face->glyph, &glyph );
if ( !error )
- node->ft_glyph = glyph;
+ {
+ inode->glyph = glyph;
+ goto Exit;
+ }
}
else
error = FTC_Err_Invalid_Argument;
}
}
+
+ /* in case of error */
+ ftc_glyph_node_done( FTC_GLYPH_NODE(inode) );
Exit:
- if ( error && node )
- FREE( node );
-
- *anode = node;
return error;
}
- /* this function is important because it is both part of */
- /* an FTC_GlyphSet_Class and an FTC_CacheNode_Class */
- /* */
FT_CALLBACK_DEF( FT_ULong )
- ftc_glyph_image_node_size( FTC_GlyphImage node )
+ ftc_image_node_weight( FTC_ImageNode inode )
{
FT_ULong size = 0;
- FT_Glyph glyph = node->ft_glyph;
-
+ FT_Glyph glyph = inode->glyph;
switch ( glyph->format )
{
@@ -198,11 +197,27 @@
;
}
- size += sizeof ( *node );
+ size += sizeof ( *inode );
return size;
}
+ /* this function assumes that the desired node's glyph set has been */
+ /* set by a previous call to ftc_image_set_compare.. */
+ /* */
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_image_node_compare( FTC_ImageNode inode,
+ FTC_ImageQuery iquery )
+ {
+ FTC_ImageSet iset = FTC_IMAGE_SET(inode->gnode.gset);
+
+ /* only if same glyph index and image set description */
+ return FT_BOOL( iquery->glyph.gindex == FTC_IMAGE_NODE_GINDEX(inode) &&
+ iquery->glyph.gset == inode->gnode.gset );
+ }
+
+
+
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -214,33 +229,47 @@
FT_CALLBACK_DEF( FT_Error )
ftc_image_set_init( FTC_ImageSet iset,
- FTC_Image_Desc* type )
+ FTC_ImageQuery query,
+ FT_LruList lru )
{
- iset->description = *type;
+ ftc_glyph_set_init( &iset->gset, lru );
+ iset->description = query->desc;
+
+ /* now compute hash from description - this is _very_ important */
+ iset->gset.hash = FTC_IMAGE_DESC_HASH(&query->desc);
+ query->glyph.gset = FTC_GLYPH_SET(iset);
+
return 0;
}
FT_CALLBACK_DEF( FT_Bool )
- ftc_image_set_compare( FTC_ImageSet iset,
- FTC_Image_Desc* type )
+ ftc_image_set_compare( FTC_ImageSet iset,
+ FTC_ImageQuery iquery )
{
- return FT_BOOL( !memcmp( &iset->description, type, sizeof ( *type ) ) );
+ FT_Bool result;
+
+ /* we must set iquery.glyph.gset for faster glyph node comparisons */
+ result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &iset->description, &iquery->desc ) );
+ if ( result )
+ iquery->glyph.gset = &iset->gset;
+
+ return result;
}
FT_CALLBACK_TABLE_DEF
- const FTC_GlyphSet_Class ftc_glyph_image_set_class =
+ const FT_LruList_ClassRec ftc_image_set_class =
{
+ sizeof( FT_LruListRec ),
+ (FT_LruList_InitFunc) NULL,
+ (FT_LruList_DoneFunc) NULL,
+
sizeof( FTC_ImageSetRec ),
-
- (FTC_GlyphSet_InitFunc) ftc_image_set_init,
- (FTC_GlyphSet_DoneFunc) 0,
- (FTC_GlyphSet_CompareFunc) ftc_image_set_compare,
-
- (FTC_GlyphSet_NewNodeFunc) ftc_glyph_image_node_new,
- (FTC_GlyphSet_SizeNodeFunc) ftc_glyph_image_node_size,
- (FTC_GlyphSet_DestroyNodeFunc)ftc_glyph_image_node_destroy
+ (FT_LruNode_InitFunc) ftc_image_set_init,
+ (FT_LruNode_DoneFunc) ftc_glyph_set_init,
+ (FT_LruNode_FlushFunc) NULL,
+ (FT_LruNode_CompareFunc) ftc_image_set_compare
};
@@ -253,15 +282,25 @@
/*************************************************************************/
- FT_CALLBACK_TABLE_DEF
- const FTC_Glyph_Cache_Class ftc_glyph_image_cache_class =
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_image_cache_init( FTC_Image_Cache cache )
{
- {
- sizeof( FTC_Image_CacheRec ),
- (FTC_Cache_InitFunc) FTC_Glyph_Cache_Init,
- (FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done
- },
- (FTC_GlyphSet_Class*) &ftc_glyph_image_set_class
+ return ftc_glyph_cache_init( (FTC_GlyphCache) cache, &ftc_image_set_class );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Cache_ClassRec ftc_image_cache_class =
+ {
+ sizeof( FTC_GlyphCacheRec ),
+ (FTC_Cache_InitFunc) ftc_image_cache_init,
+ (FTC_Cache_DoneFunc) ftc_glyph_cache_done,
+
+ sizeof( FTC_ImageNodeRec ),
+ (FTC_Node_InitFunc) ftc_image_node_init,
+ (FTC_Node_WeightFunc) ftc_image_node_weight,
+ (FTC_Node_CompareFunc) ftc_image_node_compare,
+ (FTC_Node_DoneFunc) ftc_image_node_done
};
@@ -273,36 +312,73 @@
{
return FTC_Manager_Register_Cache(
manager,
- (FTC_Cache_Class*)&ftc_glyph_image_cache_class,
- (FTC_Cache*)acache );
+ (FTC_Cache_Class) &ftc_image_cache_class,
+ FTC_CACHE_P(acache) );
}
/* documentation is in ftcimage.h */
FT_EXPORT_DEF( FT_Error )
- FTC_Image_Cache_Lookup( FTC_Image_Cache cache,
+ FTC_Image_Cache_Acquire( FTC_Image_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FT_Glyph *aglyph,
+ FTC_Node *anode )
+ {
+ FTC_ImageQueryRec query;
+ FTC_ImageNode node;
+ FT_Error error;
+
+ /* some argument checks are delayed to ftc_glyph_cache_lookup */
+ if ( !cache || !desc || !aglyph )
+ return FTC_Err_Invalid_Argument;
+
+ *aglyph = NULL;
+
+ if ( anode )
+ *anode = NULL;
+
+ query.glyph.gindex = gindex;
+ query.glyph.gset = NULL;
+ query.desc = *desc;
+ error = ftc_glyph_cache_lookup( FTC_GLYPH_CACHE(cache),
+ &query.glyph,
+ (FTC_GlyphNode*) &node );
+ if (!error)
+ {
+ *aglyph = node->glyph;
+
+ if (anode)
+ {
+ *anode = (FTC_Node) node;
+ FTC_NODE(node)->ref_count++;
+ }
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Image_Cache_Release( FTC_Image_Cache icache,
+ FTC_Node node )
+ {
+ ftc_node_unref( node, FTC_CACHE(icache) );
+ }
+
+
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Image_Cache_Lookup( FTC_Image_Cache icache,
FTC_Image_Desc* desc,
FT_UInt gindex,
FT_Glyph *aglyph )
{
- FT_Error error;
- FTC_GlyphNode node;
-
-
- /* some argument checks are delayed to FTC_Glyph_Cache_Lookup */
-
- if ( !aglyph )
- return FTC_Err_Invalid_Argument;
-
- error = FTC_Glyph_Cache_Lookup( (FTC_Glyph_Cache)cache,
- desc, gindex, &node );
-
- if ( !error )
- *aglyph = ((FTC_GlyphImage)node)->ft_glyph;
-
- return error;
+ return FTC_Image_Cache_Acquire( icache, desc, gindex, aglyph, NULL );
}
+
/* END */
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c
index 7076305..08fe202 100644
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -19,6 +19,7 @@
#include <ft2build.h>
#include FT_CACHE_H
#include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_LRU_H
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include FT_LIST_H
@@ -30,187 +31,225 @@
#undef FT_COMPONENT
#define FT_COMPONENT trace_cache
-#define FTC_LRU_GET_MANAGER( lru ) (FTC_Manager)lru->user_data
+#define FTC_LRU_GET_MANAGER( lru ) ((FTC_Manager)(lru)->user_data)
/*************************************************************************/
/*************************************************************************/
/***** *****/
- /***** FACE & SIZE LRU CALLBACKS *****/
+ /***** FACE LRU IMPLEMENTATION *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
+ typedef struct FTC_FaceNodeRec_* FTC_FaceNode;
+
+ typedef struct FTC_SizeNodeRec_* FTC_SizeNode;
+
+ typedef struct FTC_FaceNodeRec_
+ {
+ FT_LruNodeRec lru;
+ FT_Face face;
+
+ } FTC_FaceNodeRec;
+
+
+ typedef struct FTC_SizeNodeRec_
+ {
+ FT_LruNodeRec lru;
+ FT_Size size;
+
+ } FTC_SizeNodeRec;
+
+
FT_CALLBACK_DEF( FT_Error )
- ftc_manager_init_face( FT_Lru lru,
- FT_LruNode node )
+ ftc_face_node_init( FTC_FaceNode node,
+ FTC_FaceID face_id,
+ FT_LruList list )
{
- FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
+ FTC_Manager manager = FTC_LRU_GET_MANAGER(list);
FT_Error error;
- FT_Face face;
- error = manager->request_face( (FTC_FaceID)node->key,
+ error = manager->request_face( face_id,
manager->library,
manager->request_data,
- (FT_Face*)&node->root.data );
+ &node->face );
if ( !error )
{
/* destroy initial size object; it will be re-created later */
- face = (FT_Face)node->root.data;
- if ( face->size )
- FT_Done_Size( face->size );
+ if ( node->face->size )
+ FT_Done_Size( node->face->size );
}
return error;
}
- /* helper function for ftc_manager_done_face() */
- FT_CALLBACK_DEF( FT_Bool )
- ftc_manager_size_selector( FT_Lru lru,
- FT_LruNode node,
- FT_Pointer data )
- {
- FT_UNUSED( lru );
-
- return FT_BOOL( ((FT_Size)node->root.data)->face == (FT_Face)data );
- }
+ /* helper function for ftc_manager_done_face() */
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_size_node_select( FTC_SizeNode node,
+ FT_Face face )
+ {
+ return FT_BOOL( node->size->face == face );
+ }
FT_CALLBACK_DEF( void )
- ftc_manager_done_face( FT_Lru lru,
- FT_LruNode node )
+ ftc_face_node_done( FTC_FaceNode node,
+ FT_LruList list )
{
- FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
- FT_Face face = (FT_Face)node->root.data;
+ FTC_Manager manager = FTC_LRU_GET_MANAGER(list);
+ FT_Face face = node->face;
/* we must begin by removing all sizes for the target face */
/* from the manager's list */
- FT_Lru_Remove_Selection( manager->sizes_lru,
- ftc_manager_size_selector,
- face );
+ FT_LruList_Remove_Selection( manager->sizes_list,
+ (FT_LruNode_SelectFunc) ftc_size_node_select,
+ face );
/* all right, we can discard the face now */
FT_Done_Face( face );
- node->root.data = 0;
+ node->face = NULL;
}
- typedef struct FTC_FontRequest_
+ FT_CALLBACK_TABLE_DEF
+ const FT_LruList_ClassRec ftc_face_list_class =
{
- FT_Face face;
- FT_UShort width;
- FT_UShort height;
+ sizeof( FT_LruListRec ),
+ (FT_LruList_InitFunc) 0,
+ (FT_LruList_DoneFunc) 0,
- } FTC_FontRequest;
+ sizeof( FTC_FaceNodeRec ),
+ (FT_LruNode_InitFunc) ftc_face_node_init,
+ (FT_LruNode_DoneFunc) ftc_face_node_done,
+ (FT_LruNode_FlushFunc) 0, /* no flushing needed.. */
+ (FT_LruNode_CompareFunc) 0, /* direct comparison of FTC_FaceID handles */
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SIZES LRU IMPLEMENTATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ typedef struct FTC_SizeQueryRec_
+ {
+ FT_Face face;
+ FT_UInt width;
+ FT_UInt height;
+
+ } FTC_SizeQueryRec, *FTC_SizeQuery;
+
FT_CALLBACK_DEF( FT_Error )
- ftc_manager_init_size( FT_Lru lru,
- FT_LruNode node )
+ ftc_size_node_init( FTC_SizeNode node,
+ FTC_SizeQuery query )
{
- FTC_FontRequest* font_req = (FTC_FontRequest*)node->key;
- FT_Size size;
- FT_Error error;
- FT_Face face = font_req->face;
-
- FT_UNUSED( lru );
+ FT_Face face = query->face;
+ FT_Size size;
+ FT_Error error;
- node->root.data = 0;
+ node->size = NULL;
error = FT_New_Size( face, &size );
if ( !error )
{
FT_Activate_Size( size );
- error = FT_Set_Pixel_Sizes( face,
- font_req->width,
- font_req->height );
+ error = FT_Set_Pixel_Sizes( query->face,
+ query->width,
+ query->height );
if ( error )
FT_Done_Size( size );
else
- node->root.data = size;
+ node->size = size;
}
return error;
}
FT_CALLBACK_DEF( void )
- ftc_manager_done_size( FT_Lru lru,
- FT_LruNode node )
+ ftc_size_node_done( FTC_SizeNode node )
{
- FT_UNUSED( lru );
-
- FT_Done_Size( (FT_Size)node->root.data );
- node->root.data = 0;
+ if (node->size)
+ {
+ FT_Done_Size( node->size );
+ node->size = NULL;
+ }
}
FT_CALLBACK_DEF( FT_Error )
- ftc_manager_flush_size( FT_Lru lru,
- FT_LruNode node,
- FT_LruKey key )
+ ftc_size_node_flush( FTC_SizeNode node,
+ FTC_SizeQuery query )
{
- FTC_FontRequest* req = (FTC_FontRequest*)key;
- FT_Size size = (FT_Size)node->root.data;
- FT_Error error;
+ FT_Size size = node->size;
+ FT_Error error;
- if ( size->face == req->face )
+ if ( size->face == query->face )
{
FT_Activate_Size( size );
- error = FT_Set_Pixel_Sizes( req->face, req->width, req->height );
+ error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
if ( error )
+ {
FT_Done_Size( size );
+ node->size = NULL;
+ }
}
else
{
FT_Done_Size( size );
- node->key = key;
- error = ftc_manager_init_size( lru, node );
+ node->size = NULL;
+
+ error = ftc_size_node_init( node, query );
}
return error;
}
FT_CALLBACK_DEF( FT_Bool )
- ftc_manager_compare_size( FT_LruNode node,
- FT_LruKey key )
+ ftc_size_node_compare( FTC_SizeNode node,
+ FTC_SizeQuery query )
{
- FTC_FontRequest* req = (FTC_FontRequest*)key;
- FT_Size size = (FT_Size)node->root.data;
+ FT_Size size = node->size;
- FT_UNUSED( node );
-
-
- return FT_BOOL( size->face == req->face &&
- size->metrics.x_ppem == req->width &&
- size->metrics.y_ppem == req->height );
+ return FT_BOOL( size->face == query->face &&
+ (FT_UInt) size->metrics.x_ppem == query->width &&
+ (FT_UInt) size->metrics.y_ppem == query->height );
}
FT_CALLBACK_TABLE_DEF
- const FT_Lru_Class ftc_face_lru_class =
+ const FT_LruList_ClassRec ftc_size_list_class =
{
- sizeof ( FT_LruRec ),
- ftc_manager_init_face,
- ftc_manager_done_face,
- 0,
- 0
+ sizeof ( FT_LruListRec ),
+ (FT_LruList_InitFunc) 0,
+ (FT_LruList_DoneFunc) 0,
+
+ sizeof( FTC_SizeNodeRec ),
+ (FT_LruNode_InitFunc) ftc_size_node_init,
+ (FT_LruNode_DoneFunc) ftc_size_node_done,
+ (FT_LruNode_FlushFunc) ftc_size_node_flush,
+ (FT_LruNode_CompareFunc) ftc_size_node_compare
};
- FT_CALLBACK_TABLE_DEF
- const FT_Lru_Class ftc_size_lru_class =
- {
- sizeof ( FT_LruRec ),
- ftc_manager_init_size,
- ftc_manager_done_size,
- ftc_manager_flush_size,
- ftc_manager_compare_size
- };
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE MANAGER ROUTINES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
/* documentation is in ftcache.h */
@@ -246,26 +285,25 @@
if ( max_bytes == 0 )
max_bytes = FTC_MAX_BYTES_DEFAULT;
- error = FT_Lru_New( &ftc_face_lru_class,
- max_faces,
- manager,
- memory,
- 1, /* pre_alloc = TRUE */
- (FT_Lru*)&manager->faces_lru );
+ error = FT_LruList_New( &ftc_face_list_class,
+ max_faces,
+ manager,
+ memory,
+ &manager->faces_list );
if ( error )
goto Exit;
- error = FT_Lru_New( &ftc_size_lru_class,
- max_sizes,
- manager,
- memory,
- 1, /* pre_alloc = TRUE */
- (FT_Lru*)&manager->sizes_lru );
+ error = FT_LruList_New( &ftc_size_list_class,
+ max_sizes,
+ manager,
+ memory,
+ &manager->sizes_list );
if ( error )
goto Exit;
manager->library = library;
- manager->max_bytes = max_bytes;
+ manager->max_weight = max_bytes;
+ manager->cur_weight = 0;
manager->request_face = requester;
manager->request_data = req_data;
@@ -274,8 +312,8 @@
Exit:
if ( error && manager )
{
- FT_Lru_Done( manager->faces_lru );
- FT_Lru_Done( manager->sizes_lru );
+ FT_LruList_Destroy( manager->faces_list );
+ FT_LruList_Destroy( manager->sizes_list );
FREE( manager );
}
@@ -305,18 +343,18 @@
if ( cache )
{
- cache->clazz->done_cache( cache );
+ cache->clazz->cache_done( cache );
FREE( cache );
manager->caches[index] = 0;
}
}
/* discard faces and sizes */
- FT_Lru_Done( manager->faces_lru );
- manager->faces_lru = 0;
+ FT_LruList_Destroy( manager->faces_list );
+ manager->faces_list = 0;
- FT_Lru_Done( manager->sizes_lru );
- manager->sizes_lru = 0;
+ FT_LruList_Destroy( manager->sizes_list );
+ manager->sizes_list = 0;
FREE( manager );
}
@@ -329,8 +367,8 @@
{
if (manager )
{
- FT_Lru_Reset( manager->sizes_lru );
- FT_Lru_Reset( manager->faces_lru );
+ FT_LruList_Reset( manager->sizes_list );
+ FT_LruList_Reset( manager->faces_list );
}
/* XXX: FIXME: flush the caches? */
}
@@ -343,12 +381,24 @@
FTC_FaceID face_id,
FT_Face *aface )
{
+ FT_Error error;
+ FTC_FaceNode node;
+
+ if ( aface == NULL )
+ return FTC_Err_Bad_Argument;
+
+ *aface = NULL;
+
if ( !manager )
return FTC_Err_Invalid_Cache_Handle;
- return FT_Lru_Lookup( manager->faces_lru,
- (FT_LruKey)face_id,
- (FT_Pointer*)aface );
+ error = FT_LruList_Lookup( manager->faces_list,
+ (FT_LruKey) face_id,
+ (FT_LruNode*) &node );
+ if (!error)
+ *aface = node->face;
+
+ return error;
}
@@ -360,12 +410,10 @@
FT_Face *aface,
FT_Size *asize )
{
- FTC_FontRequest req;
- FT_Error error;
+ FT_Error error;
/* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
-
if ( aface )
*aface = 0;
@@ -375,23 +423,24 @@
error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
if ( !error )
{
- FT_Size size;
+ FTC_SizeQueryRec query;
+ FTC_SizeNode node;
- req.face = *aface;
- req.width = font->pix_width;
- req.height = font->pix_height;
+ query.face = *aface;
+ query.width = font->pix_width;
+ query.height = font->pix_height;
- error = FT_Lru_Lookup( manager->sizes_lru,
- (FT_LruKey)&req,
- (FT_Pointer*)&size );
+ error = FT_LruList_Lookup( manager->sizes_list,
+ (FT_LruKey) &query,
+ (FT_LruNode*) &node );
if ( !error )
{
/* select the size as the current one for this face */
- (*aface)->size = size;
+ FT_Activate_Size( node->size );
if ( asize )
- *asize = size;
+ *asize = node->size;
}
}
@@ -399,6 +448,219 @@
}
+
+ /* add a new node to the head of the manager's circular MRU list */
+ static void
+ ftc_node_mru_link( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Node first = manager->nodes_list;
+
+ if (first)
+ {
+ node->mru_prev = first->mru_prev;
+ node->mru_next = first;
+
+ first->mru_prev->mru_next = node;
+ first->mru_prev = node;
+ }
+ else
+ {
+ node->mru_next = node;
+ node->mru_prev = node;
+ }
+ manager->nodes_list = node;
+ manager->num_nodes++;
+ }
+
+
+ /* remove a node from the manager's MRU list */
+ static void
+ ftc_node_mru_unlink( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Node prev = node->mru_prev;
+ FTC_Node next = node->mru_next;
+ FTC_Node first = manager->nodes_list;
+
+ prev->mru_next = next;
+ next->mru_prev = prev;
+
+ if ( node->mru_next == first )
+ {
+ /* this is the last node in the list, update its head pointer */
+ if ( node == first )
+ manager->nodes_list = NULL;
+ else
+ first->mru_prev = prev;
+ }
+
+ node->mru_next = NULL;
+ node->mru_prev = NULL;
+ manager->num_nodes--;
+ }
+
+
+ /* move a node to the head of the manager's MRU list */
+ static void
+ ftc_node_mru_up( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Node first = manager->nodes_list;
+
+ if ( node != first )
+ {
+ ftc_node_mru_unlink( node, manager );
+ ftc_node_mru_link( node, manager );
+ }
+ }
+
+
+ /* remove a node from its cache's hash table */
+ static void
+ ftc_node_hash_unlink( FTC_Node node,
+ FTC_Cache cache )
+ {
+ FTC_Node *pnode = cache->buckets + (node->hash % cache->size);
+
+ for (;;)
+ {
+ if ( *pnode == NULL )
+ {
+ FT_ERROR(( "FreeType.cache.hash_unlink: unknown node !!\n" ));
+ return;
+ }
+
+ if ( *pnode == node )
+ {
+ *pnode = node->link;
+ node->link = NULL;
+
+ cache->nodes--;
+ return;
+ }
+
+ pnode = &(*pnode)->link;
+ }
+ }
+
+
+ /* add a node to the "top" of its cache's hash table */
+ static void
+ ftc_node_hash_link( FTC_Node node,
+ FTC_Cache cache )
+ {
+ FTC_Node *pnode = cache->buckets + (node->hash % cache->size);
+
+ node->link = *pnode;
+ *pnode = node;
+
+ cache->nodes++;
+ }
+
+
+
+
+ /* remove a node from the cache manager */
+ static void
+ ftc_node_destroy( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FT_Memory memory = manager->library->memory;
+ FTC_Cache cache;
+ FTC_Cache_Class clazz;
+
+#ifdef FT_DEBUG_ERROR
+ /* find node's cache */
+ if ( node->cache_index >= FTC_MAX_CACHES )
+ {
+ FT_ERROR(( "FreeType.cache.node_destroy: invalid node handle\n" ));
+ return;
+ }
+#endif
+
+ cache = manager->caches[ node->cache_index ];
+
+#ifdef FT_DEBUG_ERROR
+ if ( cache == NULL )
+ {
+ FT_ERROR(( "FreeType.cache.node_destroy: invalid node handle\n" ));
+ return;
+ }
+#endif
+
+ clazz = cache->clazz;
+
+ manager->cur_weight -= clazz->node_weight( node, cache );
+
+ /* remove node from mru list */
+ ftc_node_mru_unlink( node, manager );
+
+ /* remove node from cache's hash table */
+ ftc_node_hash_unlink( node, cache );
+
+ /* now finalize it */
+
+ if ( clazz->node_done )
+ clazz->node_done( node, cache );
+
+ FREE( node );
+
+ /* check, just in case of general corruption :-) */
+ if ( manager->num_nodes <= 0 )
+ FT_ERROR(( "FTC_Manager_Compress: Invalid cache node count! = %d\n",
+ manager->num_nodes ));
+ }
+
+
+
+ FT_EXPORT_DEF(void)
+ FTC_Manager_Check( FTC_Manager manager )
+ {
+ FTC_Node node, first;
+
+ first = manager->nodes_list;
+
+ /* check node weights */
+ if (first)
+ {
+ FT_ULong weight = 0;
+
+ node = first;
+ do
+ {
+ FTC_Cache cache = manager->caches[node->cache_index];
+
+ weight += cache->clazz->node_weight( node, cache );
+ node = node->mru_next;
+ }
+ while (node != first);
+
+ if ( weight != manager->cur_weight )
+ FT_ERROR(( "FTC_Manager_Compress: invalid weight %ld instead of %ld\n",
+ manager->cur_weight, weight ));
+ }
+
+ /* check circular list */
+ if (first)
+ {
+ FT_UFast count = 0;
+
+ node = first;
+ do
+ {
+ count++;
+ node = node->mru_next;
+ }
+ while (node != first);
+
+ if ( count != manager->num_nodes )
+ FT_ERROR(( "FTC_Manager_Compress: invalid cache node count %d instead of %d\n",
+ manager->num_nodes, count ));
+ }
+ }
+
+
/* `Compress' the manager's data, i.e., get rid of old cache nodes */
/* that are not referenced anymore in order to limit the total */
/* memory used by the cache. */
@@ -408,70 +670,57 @@
FT_EXPORT_DEF( void )
FTC_Manager_Compress( FTC_Manager manager )
{
- FT_ListNode node;
+ FTC_Node node, first;
+
+ if ( !manager )
+ return;
+
+ first = manager->nodes_list;
+
+#if 0
+ FTC_Manager_Check( manager );
+
+ FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
+ manager->cur_weight, manager->max_weight, manager->num_nodes ));
+#endif
- node = manager->global_lru.tail;
- while ( manager->num_bytes > manager->max_bytes && node )
+ if ( manager->cur_weight < manager->max_weight || first == NULL )
+ return;
+
+ /* go to last node - it's a circular list */
+ node = first->mru_prev;
+ do
{
- 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;
+ FTC_Node prev = node->mru_prev;
+ prev = ( node == first ) ? NULL : node->mru_prev;
- if ( data->ref_count <= 0 )
- {
- /* ok, we are going to remove this node */
- FT_List_Remove( &manager->global_lru, node );
+ if ( node->ref_count <= 0 )
+ ftc_node_destroy( node, manager );
- /* 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_data );
-
- clazz->destroy_node( cache_node, cache->cache_data );
- }
- else
- {
- /* this should never happen! */
- FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted!\n" ));
- }
-
- /* check, just in case of general corruption :-) */
- if ( manager->num_nodes <= 0 )
- FT_ERROR(( "FTC_Manager_Compress: Invalid cache node count!\n" ));
- else
- manager->num_nodes--;
- }
node = prev;
}
+ while ( node && manager->cur_weight > manager->max_weight );
}
+
FT_EXPORT_DEF( FT_Error )
- FTC_Manager_Register_Cache( FTC_Manager manager,
- FTC_Cache_Class* clazz,
- FTC_Cache *acache )
+ FTC_Manager_Register_Cache( FTC_Manager manager,
+ FTC_Cache_Class clazz,
+ FTC_Cache *acache )
{
- FT_Error error = FTC_Err_Invalid_Argument;
+ FT_Error error = FTC_Err_Invalid_Argument;
+ FTC_Cache cache = NULL;
if ( manager && clazz && acache )
{
FT_Memory memory = manager->library->memory;
- FTC_Cache cache;
- FT_UInt index = 0;
+ 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++ )
{
@@ -488,7 +737,7 @@
goto Exit;
}
- if ( !ALLOC( cache, clazz->cache_byte_size ) )
+ if ( !ALLOC( cache, clazz->cache_size ) )
{
cache->manager = manager;
cache->memory = memory;
@@ -498,19 +747,313 @@
/* IF IT IS NOT SET CORRECTLY */
cache->cache_index = index;
- if ( clazz->init_cache )
- error = clazz->init_cache( cache );
+ if ( clazz->cache_init )
+ {
+ error = clazz->cache_init( cache );
+ if ( error )
+ {
+ if ( clazz->cache_done )
+ clazz->cache_done( cache );
- if ( error )
- FREE( cache );
- else
- manager->caches[index] = *acache = cache;
+ FREE( cache );
+ goto Exit;
+ }
+ }
+
+ manager->caches[index] = cache;
}
}
Exit:
+ *acache = cache;
return error;
}
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** ABSTRACT CACHE CLASS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define FTC_PRIMES_MIN 7
+#define FTC_PRIMES_MAX 13845163
+
+ static const FT_UInt ftc_primes[] =
+ {
+ 7,
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+ 9371,
+ 14057,
+ 21089,
+ 31627,
+ 47431,
+ 71143,
+ 106721,
+ 160073,
+ 240101,
+ 360163,
+ 540217,
+ 810343,
+ 1215497,
+ 1823231,
+ 2734867,
+ 4102283,
+ 6153409,
+ 9230113,
+ 13845163,
+ };
+
+
+ static FT_UFast
+ ftc_prime_closest( FT_UFast num )
+ {
+ FT_UInt i;
+
+ for ( i = 0; i < sizeof(ftc_primes)/sizeof(ftc_primes[0]); i++ )
+ if ( ftc_primes[i] > num )
+ return ftc_primes[i];
+
+ return FTC_PRIMES_MAX;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_cache_resize( FTC_Cache cache )
+ {
+ FT_UFast new_size;
+
+ new_size = ftc_prime_closest( cache->nodes );
+ if ( new_size != cache->size )
+ {
+ FT_Memory memory = cache->memory;
+ FT_Error error;
+ FTC_Node* new_buckets ;
+ FT_ULong i;
+
+ if ( ALLOC_ARRAY( new_buckets, new_size, FTC_Node ) )
+ return;
+
+ for ( i = 0; i < cache->size; i++ )
+ {
+ FTC_Node node, next, *pnode;
+ FT_UFast hash;
+
+ node = cache->buckets[i];
+ while (node)
+ {
+ next = node->link;
+ hash = node->hash % new_size;
+ pnode = new_buckets + hash;
+
+ node->link = pnode[0];
+ pnode[0] = node;
+
+ node = next;
+ }
+ }
+
+ if ( cache->buckets )
+ FREE( cache->buckets );
+
+ cache->buckets = new_buckets;
+ cache->size = new_size;
+ }
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ ftc_cache_init( FTC_Cache cache )
+ {
+ FT_Memory memory = cache->memory;
+ FT_Error error;
+
+ cache->nodes = 0;
+ cache->size = FTC_PRIMES_MIN;
+
+ if ( ALLOC_ARRAY( cache->buckets, cache->size, FTC_Node ) )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+
+ FT_EXPORT_DEF( void )
+ ftc_cache_done( FTC_Cache cache )
+ {
+ if ( cache )
+ {
+ FT_Memory memory = cache->memory;
+ FTC_Cache_Class clazz = cache->clazz;
+ FTC_Manager manager = cache->manager;
+ FT_UFast i;
+
+ for ( i = 0; i < cache->size; i++ )
+ {
+ FTC_Node *pnode = cache->buckets + i, next, node = *pnode;
+
+ while (node)
+ {
+ next = node->link;
+ node->link = NULL;
+
+ /* remove node from mru list */
+ ftc_node_mru_unlink( node, manager );
+
+ /* now finalize it */
+ manager->cur_weight -= clazz->node_weight( node, cache );
+
+ if ( clazz->node_done )
+ clazz->node_done( node, cache );
+
+ FREE( node );
+ node = next;
+ }
+ cache->buckets[i] = NULL;
+ }
+
+ FREE( cache->buckets );
+
+ cache->nodes = 0;
+ cache->size = 0;
+ }
+ }
+
+
+
+ /* lookup a node in "top" of its cache's hash table */
+ /* if not found, create a new node.. */
+ /* */
+ FT_EXPORT_DEF(FT_Error)
+ ftc_cache_lookup_node( FTC_Cache cache,
+ FT_UFast key_hash,
+ FT_Pointer key,
+ FTC_Node *anode )
+ {
+ FT_Error error = 0;
+ FTC_Node result = NULL;
+ FTC_Node* bucket = cache->buckets + (key_hash % cache->size);
+
+ if ( *bucket )
+ {
+ FTC_Node* pnode = bucket;
+ FTC_Node_CompareFunc compare = cache->clazz->node_compare;
+
+ for ( ;; )
+ {
+ FTC_Node node;
+
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( compare( node, key, cache ) )
+ {
+ /* move to head of bucket list */
+ if ( pnode != bucket )
+ {
+ *pnode = node->link;
+ node->link = *bucket;
+ *bucket = node;
+ }
+
+ /* move to head of MRU list */
+ if ( node != cache->manager->nodes_list )
+ ftc_node_mru_up( node, cache->manager );
+
+ result = node;
+ goto Exit;
+ }
+
+ pnode = &(*pnode)->link;
+ }
+ }
+
+ /* didn't find a node, create a new one */
+ {
+ FTC_Cache_Class clazz = cache->clazz;
+ FTC_Manager manager = cache->manager;
+ FT_Memory memory = cache->memory;
+ FTC_Node node;
+
+ if ( ALLOC( node, clazz->node_size ) )
+ goto Exit;
+
+ /* node initializer must set 'hash' field */
+
+ node->cache_index = cache->cache_index;
+ node->ref_count = 0;
+
+ error = clazz->node_init( node, key, cache );
+ if ( error )
+ {
+ FREE( node );
+ goto Exit;
+ }
+
+ ftc_node_hash_link( node, cache );
+ ftc_node_mru_link( node, cache->manager );
+
+ cache->manager->cur_weight += clazz->node_weight( node, cache );
+
+ /* now try to compress the node pool when necessary */
+ if ( manager->cur_weight >= manager->max_weight )
+ {
+ node->ref_count++;
+ FTC_Manager_Compress( manager );
+ node->ref_count--;
+ }
+
+ /* try to resize the hash table when appropriate */
+ if ( FTC_CACHE_RESIZE_TEST(cache) )
+ ftc_cache_resize( cache );
+
+ result = node;
+ }
+
+ Exit:
+ *anode = result;
+ return error;
+ }
+
+
+ /* maybe these functions will disappear later */
+
+ FT_EXPORT_DEF(void)
+ ftc_node_ref( FTC_Node node,
+ FTC_Cache cache )
+ {
+ if ( node && cache && (FT_UInt)node->cache_index == cache->cache_index )
+ node->ref_count++;
+ }
+
+
+
+ FT_EXPORT_DEF(void)
+ ftc_node_unref( FTC_Node node,
+ FTC_Cache cache )
+ {
+ if ( node && cache && (FT_UInt)node->cache_index == cache->cache_index )
+ node->ref_count--;
+ }
+
+
/* END */
diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c
index 4b7d25d..871c20c 100644
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -19,6 +19,7 @@
#include <ft2build.h>
#include FT_CACHE_H
#include FT_CACHE_SMALL_BITMAPS_H
+#include FT_CACHE_INTERNAL_CHUNK_H
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include FT_ERRORS_H
@@ -28,23 +29,31 @@
#include <string.h> /* memcmp() */
-#define FTC_SBITSET_ELEMENT_COUNT 16
+#define FTC_SBIT_ITEMS_PER_NODE 16
+ /* handle to sbit set */
+ typedef struct FTC_SBitSetRec_* FTC_SBitSet;
+
+ /* sbit set structure */
typedef struct FTC_SBitSetRec_
{
- FTC_ChunkSetRec root;
+ FTC_ChunkSetRec cset;
FTC_Image_Desc desc;
- } FTC_SBitSetRec, *FTC_SBitSet;
+ } FTC_SBitSetRec;
+
+#define FTC_SBIT_SET(x) ((FTC_SBitSet)(x))
+
+#define FTC_SBIT_SET_MEMORY(x) FTC_CHUNK_SET_MEMORY(&(x)->cset)
- typedef struct FTC_SBit_CacheRec_
+ typedef struct FTC_SBitQueryRec_
{
- FTC_Chunk_CacheRec root;
+ FTC_ChunkQueryRec chunk;
+ FTC_Image_Desc desc;
- } FTC_SBit_CacheRec;
-
+ } FTC_SBitQueryRec, *FTC_SBitQuery;
/*************************************************************************/
@@ -57,77 +66,78 @@
FT_CALLBACK_DEF( void )
- ftc_sbit_chunk_node_destroy( FTC_ChunkNode node )
+ ftc_sbit_node_done( FTC_ChunkNode cnode )
{
- FTC_ChunkSet cset = node->cset;
- FT_Memory memory = cset->memory;
- FT_UInt count = node->num_elements;
- FTC_SBit sbit = (FTC_SBit)node->elements;
+ FTC_ChunkSet cset = cnode->cset;
+ FT_Memory memory = cset->ccache->cache.memory;
+ FT_UInt count = cnode->item_count;
+ FTC_SBit sbit = (FTC_SBit) cnode->items;
+ if ( sbit )
+ {
+ for ( ; count > 0; sbit++, count-- )
+ FREE( sbit->buffer );
- for ( ; count > 0; sbit++, count-- )
- FREE( sbit->buffer );
+ FREE( cnode->items );
+ }
- FREE( node->elements );
- FREE( node );
+ ftc_chunk_node_done( cnode );
}
- FT_CALLBACK_DEF( FT_Error )
- ftc_bitmap_copy( FT_Memory memory,
- FT_Bitmap* source,
- FTC_SBit target )
+ static FT_Error
+ ftc_sbit_set_bitmap( FTC_SBit sbit,
+ FT_Bitmap* bitmap,
+ FT_Memory memory )
{
FT_Error error;
- FT_Int pitch = source->pitch;
+ FT_Int pitch = bitmap->pitch;
FT_ULong size;
if ( pitch < 0 )
pitch = -pitch;
- size = (FT_ULong)( pitch * source->rows );
+ size = (FT_ULong)( pitch * bitmap->rows );
- if ( !ALLOC( target->buffer, size ) )
- MEM_Copy( target->buffer, source->buffer, size );
+ if ( !ALLOC( sbit->buffer, size ) )
+ MEM_Copy( sbit->buffer, bitmap->buffer, size );
return error;
}
- FT_CALLBACK_DEF( FT_Error )
- ftc_sbit_chunk_node_new( FTC_ChunkSet cset,
- FT_UInt index,
- FTC_ChunkNode *anode )
+
+ static FT_Error
+ ftc_sbit_node_load( FTC_ChunkNode cnode,
+ FT_UInt gindex,
+ FT_ULong *asize )
{
FT_Error error;
- FT_Memory memory = cset->memory;
- FTC_SBitSet sbitset = (FTC_SBitSet)cset;
- FTC_ChunkNode node = 0;
+ FTC_ChunkSet cset = cnode->cset;
+ FTC_SBitSet sbitset = FTC_SBIT_SET(cset);
+ FT_Memory memory = FTC_SBIT_SET_MEMORY(sbitset);
FT_Face face;
FT_Size size;
+ FTC_SBit sbit;
- /* allocate node */
- if ( ALLOC( node, sizeof ( *node ) ) )
- goto Exit;
+ if ( gindex < (FT_UInt)cnode->item_start ||
+ gindex >= (FT_UInt)cnode->item_start + cnode->item_count )
+ {
+ FT_ERROR(( "FreeType.cache.sbit_load: invalid glyph index" ));
+ return FTC_Err_Invalid_Argument;
+ }
- /* initialize its inner fields */
- error = FTC_ChunkNode_Init( node, cset, index, 1 );
- if ( error )
- goto Exit;
+ sbit = (FTC_SBit)cnode->items + (gindex - cnode->item_start);
- /* we will now load all glyph images for this chunk */
- error = FTC_Manager_Lookup_Size( cset->manager,
+ error = FTC_Manager_Lookup_Size( cset->ccache->cache.manager,
&sbitset->desc.font,
&face, &size );
if ( !error )
{
- FT_UInt glyph_index = index * cset->element_count;
FT_UInt load_flags = FT_LOAD_DEFAULT;
FT_UInt image_type = sbitset->desc.image_type;
- FT_UInt count = node->num_elements;
- FTC_SBit sbit = (FTC_SBit)node->elements;
/* determine load flags, depending on the font description's */
@@ -144,7 +154,7 @@
}
else
{
- FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in an"
+ FT_ERROR(( "FreeType.cache.sbit_load: cannot load scalable glyphs in an"
" sbit cache, please check your arguments!\n" ));
error = FTC_Err_Invalid_Argument;
goto Exit;
@@ -159,102 +169,126 @@
if ( image_type & ftc_image_flag_autohinted )
load_flags |= FT_LOAD_FORCE_AUTOHINT;
- /* load a chunk of small bitmaps in a row */
- for ( ; count > 0; count--, glyph_index++, sbit++ )
+ /* by default, indicates a `missing' glyph */
+ sbit->buffer = 0;
+
+ error = FT_Load_Glyph( face, gindex, load_flags );
+ if ( !error )
{
- /* by default, indicates a `missing' glyph */
- sbit->buffer = 0;
-
- error = FT_Load_Glyph( face, glyph_index, load_flags );
- if ( !error )
- {
- FT_Int temp;
- FT_GlyphSlot slot = face->glyph;
- FT_Bitmap* bitmap = &slot->bitmap;
- FT_Int xadvance, yadvance;
+ FT_Int temp;
+ FT_GlyphSlot slot = face->glyph;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ FT_Int xadvance, yadvance;
- /* check that our values fit into 8-bit containers! */
- /* If this is not the case, our bitmap is too large */
- /* and we will leave it as `missing' with sbit.buffer = 0 */
+ /* check that our values fit into 8-bit containers! */
+ /* If this is not the case, our bitmap is too large */
+ /* and we will leave it as `missing' with sbit.buffer = 0 */
#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
- /* XXX: FIXME: add support for vertical layouts maybe */
+ /* XXX: FIXME: add support for vertical layouts maybe */
- /* horizontal advance in pixels */
- xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
- yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
+ /* horizontal advance in pixels */
+ xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
+ yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
- if ( CHECK_BYTE( bitmap->rows ) &&
- CHECK_BYTE( bitmap->width ) &&
- CHECK_CHAR( bitmap->pitch ) &&
- CHECK_CHAR( slot->bitmap_left ) &&
- CHECK_CHAR( slot->bitmap_top ) &&
- CHECK_CHAR( xadvance ) &&
- CHECK_CHAR( yadvance ) )
+ if ( CHECK_BYTE( bitmap->rows ) &&
+ CHECK_BYTE( bitmap->width ) &&
+ CHECK_CHAR( bitmap->pitch ) &&
+ CHECK_CHAR( slot->bitmap_left ) &&
+ CHECK_CHAR( slot->bitmap_top ) &&
+ CHECK_CHAR( xadvance ) &&
+ CHECK_CHAR( yadvance ) )
+ {
+ sbit->width = (FT_Byte) bitmap->width;
+ sbit->height = (FT_Byte) bitmap->rows;
+ sbit->pitch = (FT_Char) bitmap->pitch;
+ sbit->left = (FT_Char) slot->bitmap_left;
+ sbit->top = (FT_Char) slot->bitmap_top;
+ sbit->xadvance = (FT_Char) xadvance;
+ sbit->yadvance = (FT_Char) yadvance;
+ sbit->format = (FT_Byte) bitmap->pixel_mode;
+
+ /* grab the bitmap when possible - this is a hack !! */
+ if ( slot->flags & ft_glyph_own_bitmap )
{
- sbit->width = (FT_Byte)bitmap->width;
- sbit->height = (FT_Byte)bitmap->rows;
- sbit->pitch = (FT_Char)bitmap->pitch;
- sbit->left = (FT_Char)slot->bitmap_left;
- sbit->top = (FT_Char)slot->bitmap_top;
- sbit->xadvance = (FT_Char)xadvance;
- sbit->yadvance = (FT_Char)yadvance;
- sbit->format = (FT_Byte)bitmap->pixel_mode;
-
- /* grab the bitmap when possible */
- if ( slot->flags & ft_glyph_own_bitmap )
- {
- slot->flags &= ~ft_glyph_own_bitmap;
- sbit->buffer = bitmap->buffer;
- }
- else
- {
- /* copy the bitmap into a new buffer -- ignore error */
- ftc_bitmap_copy( memory, bitmap, sbit );
- }
+ slot->flags &= ~ft_glyph_own_bitmap;
+ sbit->buffer = bitmap->buffer;
}
- }
- }
+ else
+ {
+ /* copy the bitmap into a new buffer -- ignore error */
+ error = ftc_sbit_set_bitmap( sbit, bitmap, memory );
+ }
+
+ /* now, compute size */
+ if ( asize )
+ *asize = sizeof( FTC_SBitRec ) + ABS(sbit->pitch) * sbit->height;
+
+ } /* glyph dimensions ok */
+
+ } /* glyph loading successful */
/* ignore the errors that might have occurred -- */
/* we recognize unloaded glyphs with `sbit.buffer == 0' */
- error = 0;
+ /* and 'width == 255', 'height == 0' */
+ /* */
+ if ( error )
+ {
+ sbit->width = 255;
+ error = 0;
+ /* sbit->buffer == NULL too !! */
+ }
}
Exit:
- if ( error && node )
- {
- FREE( node->elements );
- FREE( node );
- }
+ return error;
+ }
- *anode = node;
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_node_init( FTC_ChunkNode cnode,
+ FTC_ChunkQuery query )
+ {
+ FT_Error error;
+
+ error = ftc_chunk_node_init( cnode,
+ query->cset,
+ query->gindex,
+ TRUE );
+ if ( !error )
+ {
+ error = ftc_sbit_node_load( cnode, query->gindex, NULL );
+
+ if ( error )
+ ftc_chunk_node_done( cnode );
+ }
return error;
}
+
/* this function is important because it is both part of */
/* an FTC_ChunkSet_Class and an FTC_CacheNode_Class */
/* */
FT_CALLBACK_DEF( FT_ULong )
- ftc_sbit_chunk_node_size( FTC_ChunkNode node )
+ ftc_sbit_node_weight( FTC_ChunkNode cnode )
{
FT_ULong size;
- FTC_ChunkSet cset = node->cset;
- FT_UInt count = node->num_elements;
+ FTC_ChunkSet cset = cnode->cset;
+ FT_UInt count = cnode->item_count;
FT_Int pitch;
- FTC_SBit sbit = (FTC_SBit)node->elements;
+ FTC_SBit sbit = (FTC_SBit) cnode->items;
/* the node itself */
- size = sizeof ( *node );
+ size = sizeof ( *cnode );
/* the sbit records */
- size += cset->element_count * sizeof ( FTC_SBitRec );
+ size += cnode->item_count * sizeof ( FTC_SBitRec );
for ( ; count > 0; count--, sbit++ )
{
@@ -273,6 +307,34 @@
}
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_sbit_node_compare( FTC_ChunkNode cnode,
+ FTC_SBitQuery query,
+ FTC_Cache cache )
+ {
+ FTC_ChunkQuery creq = &query->chunk;
+ FT_UInt gindex = query->chunk.gindex;
+ FT_UInt offset = (FT_UInt)(gindex - cnode->item_start);
+ FT_Bool result;
+
+ result = FT_BOOL( offset < (FT_UInt)cnode->item_count &&
+ creq->cset == cnode->cset );
+ if ( result )
+ {
+ /* check if we need to load the glyph bitmap now */
+ FTC_SBit sbit = (FTC_SBit)cnode->items + offset;
+
+ if ( sbit->buffer == NULL && sbit->width != 255 )
+ {
+ FT_ULong size;
+ ftc_sbit_node_load( cnode, gindex, &size );
+ cache->manager->cur_weight += size;
+ }
+ }
+ return result;
+ }
+
+
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -283,60 +345,74 @@
FT_CALLBACK_DEF( FT_Error )
- ftc_sbit_chunk_set_sizes( FTC_ChunkSet cset,
- FTC_Image_Desc* desc )
+ ftc_sbit_set_init( FTC_SBitSet sset,
+ FTC_SBitQuery query,
+ FT_LruList lru )
{
- FT_Error error;
- FT_Face face;
+ FTC_ChunkCache ccache = lru->user_data;
+ FTC_Manager manager = ccache->cache.manager;
+ FT_Error error;
+ FT_Face face;
+ sset->desc = query->desc;
- cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
- cset->element_size = sizeof ( FTC_SBitRec );
-
- /* lookup the FT_Face to obtain the number of glyphs */
- error = FTC_Manager_Lookup_Face( cset->manager,
- desc->font.face_id, &face );
+ /* we need to compute "cquery.item_total" now */
+ error = FTC_Manager_Lookup_Face( manager,
+ query->desc.font.face_id,
+ &face );
if ( !error )
- cset->element_max = face->num_glyphs;
+ {
+ ftc_chunk_set_init( FTC_CHUNK_SET(sset),
+ sizeof( FTC_SBitRec ),
+ FTC_SBIT_ITEMS_PER_NODE,
+ face->num_glyphs,
+ FTC_CHUNK_CACHE(lru->user_data) );
+
+ /* now compute hash from description - this is _very_ important */
+ /* for good performance.. */
+ sset->cset.hash = FTC_IMAGE_DESC_HASH( &sset->desc );
+ query->chunk.cset = &sset->cset;
+ }
return error;
}
- FT_CALLBACK_DEF( FT_Error )
- ftc_sbit_chunk_set_init( FTC_SBitSet sset,
- FTC_Image_Desc* type )
- {
- sset->desc = *type;
-
- return 0;
- }
-
FT_CALLBACK_DEF( FT_Bool )
- ftc_sbit_chunk_set_compare( FTC_SBitSet sset,
- FTC_Image_Desc* type )
+ ftc_sbit_set_compare( FTC_SBitSet sset,
+ FTC_SBitQuery query )
{
- return FT_BOOL( !memcmp( &sset->desc, type, sizeof ( *type ) ) );
+ FT_Bool result;
+
+ /* we need to set the "cquery.cset" field or our query for */
+ /* faster glyph comparisons in ftc_sbit_node_compare.. */
+ /* */
+ result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &sset->desc, &query->desc ) );
+ if ( result )
+ query->chunk.cset = &sset->cset;
+
+ return result;
}
+
FT_CALLBACK_TABLE_DEF
- const FTC_ChunkSet_Class ftc_sbit_chunk_set_class =
+ const FT_LruList_ClassRec ftc_sbit_set_class =
{
+ sizeof( FT_LruListRec ),
+ (FT_LruList_InitFunc) NULL,
+ (FT_LruList_DoneFunc) NULL,
+
sizeof( FTC_SBitSetRec ),
-
- (FTC_ChunkSet_InitFunc) ftc_sbit_chunk_set_init,
- (FTC_ChunkSet_DoneFunc) 0,
- (FTC_ChunkSet_CompareFunc) ftc_sbit_chunk_set_compare,
- (FTC_ChunkSet_SizesFunc) ftc_sbit_chunk_set_sizes,
-
- (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new,
- (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size,
- (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy
+ (FT_LruNode_InitFunc) ftc_sbit_set_init,
+ (FT_LruNode_DoneFunc) ftc_chunk_set_done,
+ (FT_LruNode_FlushFunc) NULL,
+ (FT_LruNode_CompareFunc) ftc_sbit_set_compare,
};
+
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -346,15 +422,25 @@
/*************************************************************************/
- FT_CALLBACK_TABLE_DEF
- const FTC_Chunk_Cache_Class ftc_sbit_cache_class =
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_cache_init( FTC_SBit_Cache scache )
{
- {
- sizeof( FTC_SBit_CacheRec ),
- (FTC_Cache_InitFunc)FTC_Chunk_Cache_Init,
- (FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done
- },
- (FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class
+ return ftc_chunk_cache_init( FTC_CHUNK_CACHE(scache),
+ &ftc_sbit_set_class );
+ }
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Cache_ClassRec ftc_sbit_cache_class =
+ {
+ sizeof( FTC_ChunkCacheRec ),
+ (FTC_Cache_InitFunc) ftc_sbit_cache_init,
+ (FTC_Cache_DoneFunc) ftc_chunk_cache_done,
+
+ sizeof( FTC_ChunkNodeRec ),
+ (FTC_Node_InitFunc) ftc_sbit_node_init,
+ (FTC_Node_WeightFunc) ftc_sbit_node_weight,
+ (FTC_Node_CompareFunc) ftc_sbit_node_compare,
+ (FTC_Node_DoneFunc) ftc_sbit_node_done
};
@@ -366,8 +452,8 @@
{
return FTC_Manager_Register_Cache(
manager,
- (FTC_Cache_Class*)&ftc_sbit_cache_class,
- (FTC_Cache*)acache );
+ &ftc_sbit_cache_class,
+ (FTC_Cache*) acache );
}
@@ -379,21 +465,27 @@
FT_UInt gindex,
FTC_SBit *ansbit )
{
- FT_Error error;
- FTC_ChunkNode node;
- FT_UInt cindex;
+ FT_Error error;
+ FTC_ChunkCache ccache = (FTC_ChunkCache) cache;
+ FTC_ChunkNode node;
+ FTC_SBitQueryRec query;
/* argument checks delayed to FTC_Chunk_Cache_Lookup */
if ( !ansbit )
return FTC_Err_Invalid_Argument;
- *ansbit = 0;
- error = FTC_Chunk_Cache_Lookup( &cache->root, desc, gindex,
- &node, &cindex );
- if ( !error )
- *ansbit = (FTC_SBit)node->elements + cindex;
+ *ansbit = NULL;
+ query.chunk.gindex = gindex;
+ query.chunk.cset = NULL;
+ query.desc = *desc;
+
+ error = ftc_chunk_cache_lookup( ccache, &query.chunk, &node );
+ if ( !error )
+ {
+ *ansbit = (FTC_SBit) node->items + (gindex - node->item_start);
+ }
return error;
}
diff --git a/src/cache/ftlru.c b/src/cache/ftlru.c
index 2838847..eed41f5 100644
--- a/src/cache/ftlru.c
+++ b/src/cache/ftlru.c
@@ -25,326 +25,308 @@
#include "ftcerror.h"
- static void
- lru_build_free_list( FT_LruNode nodes,
- FT_UInt count,
- FT_List free_list )
- {
- FT_LruNode node = nodes;
- FT_LruNode limit = node + count;
-
-
- free_list->head = free_list->tail = 0;
- for ( ; node < limit; node++ )
- FT_List_Add( free_list, (FT_ListNode)node );
- }
-
-
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 *anlru )
+ FT_LruList_New( FT_LruList_Class clazz,
+ FT_UInt max_nodes,
+ FT_Pointer user_data,
+ FT_Memory memory,
+ FT_LruList *alist )
{
- FT_Error error;
- FT_Lru lru;
+ FT_Error error;
+ FT_LruList list;
-
- if ( !anlru )
+ if ( !alist || !clazz )
return FTC_Err_Invalid_Argument;
- *anlru = 0;
- if ( !ALLOC( lru, sizeof ( *lru ) ) )
+ *alist = NULL;
+ if ( !ALLOC( list, clazz->list_size ) )
{
- if ( pre_alloc )
- {
- /* allocate static array of lru list nodes */
- if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
- {
- FREE( lru );
- goto Exit;
- }
+ /* initialize common fields */
+ list->clazz = clazz;
+ list->memory = memory;
+ list->max_nodes = max_nodes;
+ list->user_data = user_data;
- /* build the `free_nodes' list from the array */
- lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
+ if ( clazz->list_init )
+ {
+ error = clazz->list_init( list );
+ if ( error )
+ {
+ if ( clazz->list_done )
+ clazz->list_done( list );
+
+ FREE( list );
+ }
}
- /* initialize common fields */
- lru->clazz = (FT_Lru_Class*)clazz;
- lru->max_elements = max_elements;
- lru->memory = memory;
- lru->user_data = user_data;
-
- *anlru = lru;
+ *alist = list;
}
- Exit:
return error;
}
FT_EXPORT_DEF( void )
- FT_Lru_Reset( FT_Lru lru )
+ FT_LruList_Destroy( FT_LruList list )
{
- FT_ListNode node;
- FT_Lru_Class* clazz;
- FT_Memory memory;
+ FT_Memory memory;
+ FT_LruList_Class clazz;
-
- if ( !lru )
+ if ( !list )
return;
- node = lru->elements.head;
- clazz = lru->clazz;
- memory = lru->memory;
+ memory = list->memory;
+ clazz = list->clazz;
- while ( node )
- {
- FT_ListNode next = node->next;
+ FT_LruList_Reset( list );
+ if ( clazz->list_done )
+ clazz->list_done( list );
- clazz->done_element( lru, (FT_LruNode)node );
- if ( !lru->nodes )
- FREE( node );
-
- node = next;
- }
-
- /* rebuild free list if necessary */
- if ( lru->nodes )
- lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes );
-
- lru->elements.head = lru->elements.tail = 0;
- lru->num_elements = 0;
+ FREE( list );
}
+
FT_EXPORT_DEF( void )
- FT_Lru_Done( FT_Lru lru )
+ FT_LruList_Reset( FT_LruList list )
{
- FT_Memory memory;
+ FT_LruNode node;
+ FT_LruList_Class clazz;
+ FT_Memory memory;
- if ( !lru )
+ if ( !list )
return;
- memory = lru->memory;
+ node = list->nodes;
+ clazz = list->clazz;
+ memory = list->memory;
- FT_Lru_Reset( lru );
+ while ( node )
+ {
+ FT_LruNode next = node->next;
- FREE( lru->nodes );
- FREE( lru );
+ if ( clazz->node_done )
+ clazz->node_done( node, list );
+
+ FREE( node );
+ node = next;
+ }
+
+ list->nodes = NULL;
+ list->num_nodes = 0;
}
FT_EXPORT_DEF( FT_Error )
- FT_Lru_Lookup_Node( FT_Lru lru,
- FT_LruKey key,
- FT_LruNode *anode )
+ FT_LruList_Lookup( FT_LruList list,
+ FT_LruKey key,
+ FT_LruNode *anode )
{
- FT_Error error = 0;
- FT_ListNode node;
- FT_Lru_Class* clazz;
- FT_LruNode found = 0;
- FT_Memory memory;
+ FT_Error error = 0;
+ FT_LruNode node, *pnode;
+ FT_LruList_Class clazz;
+ FT_LruNode* plast;
+ FT_LruNode result = NULL;
+ FT_Memory memory;
- if ( !lru || !key || !anode )
+ if ( !list || !key || !anode )
return FTC_Err_Invalid_Argument;
- node = lru->elements.head;
- clazz = lru->clazz;
- memory = lru->memory;
+ pnode = &list->nodes;
+ plast = pnode;
+ node = NULL;
+ clazz = list->clazz;
+ memory = list->memory;
- if ( clazz->compare_element )
+ if ( clazz->node_compare )
{
- for ( ; node; node = node->next )
- if ( clazz->compare_element( (FT_LruNode)node, key ) )
- {
- found = (FT_LruNode)node;
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
break;
- }
+
+ if ( clazz->node_compare( node, key, list ) )
+ break;
+
+ plast = pnode;
+ pnode = &(*pnode)->next;
+ }
}
else
{
- for ( ; node; node = node->next )
- if ( ((FT_LruNode)node)->key == key )
- {
- found = (FT_LruNode)node;
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
break;
- }
+
+ if ( node->key == key )
+ break;
+
+ plast = pnode;
+ pnode = &(*pnode)->next;
+ }
}
- if ( found )
+ if ( node )
{
/* move element to top of list */
- FT_List_Up( &lru->elements, node );
- }
- else
- {
- /* we haven't found the relevant element. We will now try */
- /* to create a new one. */
- if ( lru->num_elements >= lru->max_elements )
+ if ( list->nodes != node )
{
- /* this lru list is full; we will now flush */
- /* the oldest node */
- FT_LruNode lru_node;
+ *pnode = node->next;
+ node->next = list->nodes;
+ list->nodes = node;
+ }
+ result = node;
+ goto Exit;
+ }
+ /* we haven't found the relevant element. We will now try */
+ /* to create a new one. */
+ /* */
- node = lru->elements.tail;
- lru_node = (FT_LruNode)node;
- found = lru_node;
+ /* first, check if our list if full, when appropriate */
+ if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
+ {
+ /* this list list is full; we will now flush */
+ /* the oldest node, if there's one !! */
+ FT_LruNode last = *plast;
- if ( clazz->flush_element )
- error = clazz->flush_element( lru, lru_node, key );
+ if ( last )
+ {
+ if ( clazz->node_flush )
+ {
+ error = clazz->node_flush( last, key, list );
+ }
else
{
- clazz->done_element( lru, lru_node );
- lru_node->key = key;
- node->data = 0;
- error = clazz->init_element( lru, lru_node );
+ if ( clazz->node_done )
+ clazz->node_done( last, list );
+
+ last->key = key;
+ error = clazz->node_init( last, key, list );
}
if ( !error )
{
- /* now, move element to top of list */
- FT_List_Up( &lru->elements, node );
- }
- else
- {
- /* in case of error, the node must be discarded */
- FT_List_Remove( &lru->elements, node );
- lru->num_elements--;
+ /* move it to the top of the list */
+ *plast = NULL;
+ last->next = list->nodes;
+ list->nodes = last;
- if ( lru->nodes )
- FT_List_Insert( &lru->free_nodes, node );
- else
- FREE( lru_node );
-
- found = 0;
- }
- }
- else
- {
- FT_LruNode lru_node;
-
-
- /* create a new lru list node, then the element for it */
- if ( lru->nodes )
- {
- node = lru->free_nodes.head;
- lru_node = (FT_LruNode)node;
- lru_node->key = key;
-
- error = clazz->init_element( lru, lru_node );
- if ( error )
- goto Exit;
-
- FT_List_Remove( &lru->free_nodes, node );
- }
- else
- {
- if ( ALLOC( lru_node, sizeof ( *lru_node ) ) )
- goto Exit;
-
- lru_node->key = key;
- error = clazz->init_element( lru, lru_node );
- if ( error )
- {
- FREE( lru_node );
- goto Exit;
- }
+ result = last;
+ goto Exit;
}
- found = lru_node;
- node = (FT_ListNode)lru_node;
- FT_List_Insert( &lru->elements, node );
- lru->num_elements++;
+ /* in case of error during the flush or done/init cycle, */
+ /* we need to discard the node.. */
+ if ( clazz->node_done )
+ clazz->node_done( last, list );
+
+ *plast = NULL;
+ list->num_nodes--;
+
+ FREE( last );
+ goto Exit;
}
}
+ /* otherwise, simply allocate a new node */
+ if ( ALLOC( node, clazz->node_size ) )
+ goto Exit;
+
+ node->key = key;
+ error = clazz->node_init( node, key, list );
+ if ( error )
+ {
+ FREE( node );
+ goto Exit;
+ }
+
+ result = node;
+ node->next = list->nodes;
+ list->nodes = node;
+ list->num_nodes++;
+
Exit:
- *anode = found;
+ *anode = result;
return error;
}
- FT_EXPORT_DEF( FT_Error )
- FT_Lru_Lookup( FT_Lru lru,
- FT_LruKey key,
- FT_Pointer *anobject )
- {
- FT_Error error;
- FT_LruNode node;
-
-
- /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
-
- if ( !anobject )
- return FTC_Err_Invalid_Argument;
-
- *anobject = 0;
- error = FT_Lru_Lookup_Node( lru, key, &node );
- if ( !error )
- *anobject = node->root.data;
-
- return error;
- }
-
FT_EXPORT_DEF( void )
- FT_Lru_Remove_Node( FT_Lru lru,
- FT_LruNode node )
+ FT_LruList_Remove( FT_LruList list,
+ FT_LruNode node )
{
- if ( !lru || !node )
+ FT_LruNode *pnode;
+
+ if ( !list || !node )
return;
- if ( lru->num_elements > 0 )
+ pnode = &list->nodes;
+ for (;;)
{
- FT_List_Remove( &lru->elements, (FT_ListNode)node );
- lru->clazz->done_element( lru, node );
-
- if ( lru->nodes )
- FT_List_Insert( &lru->free_nodes, (FT_ListNode)node );
- else
+ if ( *pnode == node )
{
- FT_Memory memory = lru->memory;
+ FT_Memory memory = list->memory;
+ FT_LruList_Class clazz = list->clazz;
+ *pnode = node->next;
+ node->next = NULL;
+
+ if ( clazz->node_done )
+ clazz->node_done( node, list );
+
+ FREE( node );
+ list->num_nodes--;
+ break;
+ }
+
+ pnode = &(*pnode)->next;
+ }
+ }
+
+
+
+ FT_EXPORT_DEF( void )
+ FT_LruList_Remove_Selection( FT_LruList list,
+ FT_LruNode_SelectFunc select_func,
+ FT_Pointer select_data )
+ {
+ FT_LruNode *pnode, node;
+ FT_LruList_Class clazz;
+ FT_Memory memory;
+
+ if ( !list || !select_func )
+ return;
+
+ memory = list->memory;
+ clazz = list->clazz;
+ pnode = &list->nodes;
+
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( select_func( node, select_data, list ) )
+ {
+ *pnode = node->next;
+ node->next = NULL;
+
+ if ( clazz->node_done )
+ clazz->node_done( node, list );
FREE( node );
}
-
- lru->num_elements--;
- }
- }
-
-
- FT_EXPORT_DEF( void )
- FT_Lru_Remove_Selection( FT_Lru lru,
- FT_Lru_Selector selector,
- FT_Pointer data )
- {
- if ( !lru || !selector )
- return;
-
- if ( lru->num_elements > 0 )
- {
- FT_ListNode node = lru->elements.head;
- FT_ListNode next;
-
-
- while ( node )
- {
- next = node->next;
- if ( selector( lru, (FT_LruNode)node, data ) )
- {
- /* remove this element from the list, and destroy it */
- FT_Lru_Remove_Node( lru, (FT_LruNode)node );
- }
- node = next;
- }
+ else
+ pnode = &(*pnode)->next;
}
}