From 09adc1c1b3bbaf3a0477e675d029e1bf115460fd Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 26 Oct 2001 16:58:27 +0000 Subject: [PATCH] _major_ re-design of the caching sub-system. Still using the same API though :-) --- ChangeLog | 9 + include/freetype/cache/ftcchunk.h | 168 ++---- include/freetype/cache/ftcglyph.h | 179 +++--- include/freetype/cache/ftcimage.h | 9 +- include/freetype/cache/ftcmanag.h | 287 ++++------ include/freetype/cache/ftcsbits.h | 1 - include/freetype/cache/ftlru.h | 171 +++--- include/freetype/ftcache.h | 26 +- src/base/ftdbgmem.c | 9 +- src/cache/ftcchunk.c | 420 +++----------- src/cache/ftcglyph.c | 439 ++------------- src/cache/ftcimage.c | 242 +++++--- src/cache/ftcmanag.c | 889 ++++++++++++++++++++++++------ src/cache/ftcsbits.c | 400 ++++++++------ src/cache/ftlru.c | 414 +++++++------- 15 files changed, 1835 insertions(+), 1828 deletions(-) diff --git a/ChangeLog b/ChangeLog index 50a559dc3..a9421d8f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2001-10-26 David Turner + + * 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 * 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 47fed6efa..e799123de 100644 --- a/include/freetype/cache/ftcchunk.h +++ b/include/freetype/cache/ftcchunk.h @@ -60,109 +60,57 @@ FT_BEGIN_HEADER 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_ - { - 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_ + /* a chunk set is used to categorize chunks of a given type */ + 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_BEGIN_HEADER /* */ 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 a8af44a2d..c92e4fa29 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_ - { - FTC_CacheNodeRec root; - FTC_GlyphNode gset_next; /* next in glyph set's bucket list */ - FT_UShort glyph_index; - FT_UShort gset_index; - - } 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 ) ) - - - /*************************************************************************/ - /* */ - /* 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 ); + /* handle to a glyph cache node */ + typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode; - 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 ); + /* a glyph cache, its nodes are all glyph-specific */ + typedef struct FTC_GlyphCacheRec_* FTC_GlyphCache; - typedef FT_ULong - (*FTC_GlyphSet_SizeNodeFunc)( FTC_GlyphNode node, - FTC_GlyphSet gset ); + /* glyph sets class handle */ + typedef const struct FTC_GlyphSet_ClassRec_* FTC_GlyphSet_Class; - typedef struct 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_ { - FT_UInt gset_byte_size; + FTC_NodeRec node; + FTC_GlyphSet gset; - 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_GlyphNodeRec; - } FTC_GlyphSet_Class; +#define FTC_GLYPH_NODE(x) ((FTC_GlyphNode)(x)) +#define FTC_GLYPH_NODE_P(x) ((FTC_GlyphNode*)(x)) + /* 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 cache; + FT_LruList gset_lru; /* LRU list of glyph sets */ + + } FTC_GlyphCacheRec; + +#define FTC_GLYPH_CACHE(x) ((FTC_GlyphCache)(x)) +#define FTC_GLYPH_CACHE_P(x) ((FTC_GlyphCache*)(x)) + + + typedef struct FTC_GlyphQueryRec_ { - FTC_CacheRec root; - FT_Lru gsets_lru; /* static sets lru list */ - FTC_GlyphSet last_gset; /* small cache :-) */ - FTC_GlyphSet_CompareFunc compare; /* useful shortcut */ + /* input */ + FT_UInt gindex; + + /* output */ + FTC_GlyphSet gset; - } FTC_Glyph_CacheRec; + } FTC_GlyphQueryRec, *FTC_GlyphQuery; /*************************************************************************/ @@ -174,44 +150,41 @@ FT_BEGIN_HEADER /* 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 ); - -#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-- - + ftc_glyph_node_init( FTC_GlyphNode node, + FT_UInt gindex, /* glyph index for node */ + FTC_GlyphSet gset ); + /* 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 ); - FT_EXPORT( FT_Error ) - FTC_GlyphSet_New( FTC_Glyph_Cache cache, - FT_Pointer type, - FTC_GlyphSet *aset ); + /* 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_Lookup_Node( FTC_GlyphSet gset, - FT_UInt glyph_index, - FTC_GlyphNode *anode ); + 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_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 376aeab66..a82cf8aa8 100644 --- a/include/freetype/cache/ftcimage.h +++ b/include/freetype/cache/ftcimage.h @@ -29,7 +29,6 @@ #include #include FT_CACHE_H -#include FT_CACHE_INTERNAL_GLYPH_H FT_BEGIN_HEADER @@ -96,6 +95,14 @@ FT_BEGIN_HEADER } 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 2d97fad3a..0aa1086db 100644 --- a/include/freetype/cache/ftcmanag.h +++ b/include/freetype/cache/ftcmanag.h @@ -81,12 +81,23 @@ FT_BEGIN_HEADER #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; + + + /*************************************************************************/ /* */ /* */ @@ -125,13 +136,15 @@ FT_BEGIN_HEADER 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 @@ FT_BEGIN_HEADER /* 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 ) + /* 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; -#define FTC_LIST_TO_CACHENODE( n ) ( (FTC_CacheNode)(n) ) + 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_CacheNode_SizeFunc */ - /* */ - /* */ - /* 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. */ - /* */ - /* */ - /* node :: A handle to the target cache node. */ - /* */ - /* cache_data :: A generic pointer passed to the destructor. */ - /* */ - /* */ - /* The size of a given cache node in bytes. */ - /* */ - typedef FT_ULong - (*FTC_CacheNode_SizeFunc)( FTC_CacheNode node, - FT_Pointer cache_data ); + } FTC_CacheRec; - /*************************************************************************/ - /* */ - /* */ - /* FTC_CacheNode_DestroyFunc */ - /* */ - /* */ - /* 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. */ - /* */ - /* */ - /* node :: A handle to the target cache node. */ - /* */ - /* cache_data :: A generic pointer passed to the destructor. */ - /* */ +#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_CacheNode_DestroyFunc)( FTC_CacheNode node, - FT_Pointer cache_data ); + (*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 ); - /*************************************************************************/ - /* */ - /* */ - /* FTC_CacheNode_Class */ - /* */ - /* */ - /* A very simple structure used to describe a cache node's class to */ - /* the cache manager. */ - /* */ - /* */ - /* size_node :: A function used to size the node. */ - /* */ - /* destroy_node :: A function used to destroy the node. */ - /* */ - /* */ - /* 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; + /* compute the weight of a given cache node */ + typedef FT_ULong + (*FTC_Node_WeightFunc)( FTC_Node node, + FTC_Cache cache ); - } FTC_CacheNode_Class; + /* 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 ); - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ + 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; + /* */ - /*************************************************************************/ - /* */ - /* */ - /* FTC_Cache_InitFunc */ - /* */ - /* */ - /* A function used to initialize a given cache object. */ - /* */ - /* */ - /* cache :: A handle to the new cache. */ - /* */ - typedef FT_Error - (*FTC_Cache_InitFunc)( FTC_Cache cache ); +#define FTC_CACHE_RESIZE_TEST(c) \ + ( (c)->nodes*3 < (c)->size || \ + (c)->size*3 < (c)->nodes ) - /*************************************************************************/ - /* */ - /* */ - /* FTC_Cache_DoneFunc */ - /* */ - /* */ - /* A function to finalize a given cache object. */ - /* */ - /* */ - /* cache :: A handle to the target cache. */ - /* */ - typedef void - (*FTC_Cache_DoneFunc)( FTC_Cache 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 ); - /*************************************************************************/ - /* */ - /* */ - /* FTC_Cache_Class */ - /* */ - /* */ - /* A structure used to describe a given cache object class to the */ - /* cache manager. */ - /* */ - /* */ - /* 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; - }; + /* 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 ); - /*************************************************************************/ - /* */ - /* */ - /* FTC_CacheRec */ - /* */ - /* */ - /* A structure used to describe an abstract cache object. */ - /* */ - /* */ - /* 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. */ - /* */ - typedef struct FTC_CacheRec_ - { - FTC_Manager manager; - FT_Memory memory; - FTC_Cache_Class* clazz; - FTC_CacheNode_Class* node_clazz; + /* can be used when FTC_CACHE_RESIZE_TEST returns TRUE after a node */ + /* insertion.. */ + FT_EXPORT(void) + ftc_cache_resize( FTC_Cache cache ); - FT_UInt cache_index; /* in manager's table */ - FT_Pointer cache_data; /* passed to cache node methods */ - } FTC_CacheRec; + /* 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 aba87c8e6..1a30846d7 100644 --- a/include/freetype/cache/ftcsbits.h +++ b/include/freetype/cache/ftcsbits.h @@ -22,7 +22,6 @@ #include #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 787443879..27fdcf186 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_LruNodeRec, *FT_LruNode; - + FT_LruNode next; + FT_LruKey key; - /* forward declaration */ - typedef struct FT_LruRec_* FT_Lru; + } FT_LruNodeRec; - /* LRU class */ - typedef struct FT_Lru_Class_ + /* the list structure */ + typedef struct FT_LruListRec_ { - FT_UInt lru_size; /* object size in bytes */ - - /* this method is used to initialize a new list element node */ - FT_Error - (*init_element)( FT_Lru lru, - FT_LruNode node ); - - /* 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 ); - - /* 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 ); - - } FT_Lru_Class; - + FT_Memory memory; + FT_LruList_Class clazz; + FT_LruNode nodes; + FT_UInt max_nodes; + FT_UInt num_nodes; + FT_Pointer user_data; + + } FT_LruListRec; + + + /* 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 ); + + /* 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 ); + + /* 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_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_elements, + FT_Pointer user_data, + FT_Memory memory, + FT_LruList *alist ); FT_EXPORT( void ) - FT_Lru_Reset( FT_Lru lru ); + FT_LruList_Reset( FT_LruList list ); + FT_EXPORT( void ) - FT_Lru_Done ( FT_Lru lru ); + FT_LruList_Destroy ( FT_LruList list ); - 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_LruList_Lookup( FT_LruList list, + FT_LruKey key, + FT_LruNode *anode ); - 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_LruList_Remove( FT_LruList list, + FT_LruNode node ); + FT_EXPORT( void ) + FT_LruList_Remove_Selection( FT_LruList list, + FT_LruNode_SelectFunc select_func, + FT_Pointer select_data ); + + /* */ + FT_END_HEADER #endif /* __FTLRU_H__ */ diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h index fc15956f8..8fcbd1998 100644 --- a/include/freetype/ftcache.h +++ b/include/freetype/ftcache.h @@ -142,6 +142,19 @@ FT_BEGIN_HEADER } 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_BEGIN_HEADER 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 048df3eb0..42ccc9726 100644 --- a/src/base/ftdbgmem.c +++ b/src/base/ftdbgmem.c @@ -1,6 +1,7 @@ #include #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 7e603931b..9fc08af65 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; - - - 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 ); - if ( alloc ) - { - /* allocate elements array */ - FT_Memory memory; + 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; - memory = cache->root.memory; - error = MEM_Alloc( node->elements, - cset->element_size * cset->element_count ); + len = cset->item_total - start; + if ( len > cset->item_count ) + len = cset->item_count; + + cnode->item_count = len; + + if ( alloc ) + { + 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; - - FT_EXPORT_DEF( FT_ULong ) - FTC_ChunkNode_Size( FTC_ChunkNode node ) - { - FTC_ChunkSet cset = node->cset; - - - return cset->clazz->size_node( node ); + /* 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_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_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; - - - /* for each bucket, free the list of glyph nodes */ - for ( ; bucket < bucket_limit; bucket++ ) - { - 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; - } - } - - 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_set_done( FTC_ChunkSet cset ) { - FTC_Chunk_Cache cache = cset->cache; - FTC_Manager manager = cache->root.manager; - FT_Error error = 0; - - FTC_ChunkSet_Class* clazz = cset->clazz; - - - *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; - } - - Exit: - return error; + /* nothing for now */ + FT_UNUSED( cset ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ - /***** CHUNK SETS LRU CALLBACKS *****/ + /***** CHUNK CACHES *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ -#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( void ) + ftc_chunk_cache_done( FTC_ChunkCache ccache ) { - FTC_Chunk_Cache cache = FTC_CSET_LRU_GET_CACHE( lru ); - FT_Error error; - FTC_ChunkSet cset; - + ftc_cache_done( FTC_CACHE(ccache) ); - error = FTC_ChunkSet_New( cache, - (FT_Pointer)node->key, - &cset ); - if ( !error ) + /* simply delete all remaining glyph sets */ + if ( ccache->cset_lru ) { - /* good, now set the set index within the set object */ - cset->cset_index = (FT_UInt)( node - lru->nodes ); - node->root.data = cset; + FT_LruList_Destroy( ccache->cset_lru ); + ccache->cset_lru = NULL; } - - 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 ) + ftc_chunk_cache_init( FTC_ChunkCache ccache, + FT_LruList_Class cset_class ) { - FT_Memory memory = cache->root.memory; - FT_Error error; - - FTC_Chunk_Cache_Class* ccache_clazz; + FT_Error error; + error = ftc_cache_init( FTC_CACHE(ccache) ); + if (error) goto Exit; - /* 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 ); + error = FT_LruList_New( cset_class, 0, ccache, + ccache->cache.memory, + &ccache->cset_lru ); + Exit: 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 ) + ftc_chunk_cache_lookup( FTC_ChunkCache ccache, + FTC_ChunkQuery query, + FTC_ChunkNode *anode ) { - 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 ) ) + FT_LruNode node; + FT_Error error; + + error = FT_LruList_Lookup( ccache->cset_lru, query, &node ); + if ( !error ) { - error = FT_Lru_Lookup( cache->csets_lru, - (FT_LruKey)type, - (FT_Pointer*)&cset ); - cache->last_cset = cset; - if ( error ) - goto Exit; - } + FTC_ChunkSet cset = FTC_CHUNK_SET(node); + FT_UFast hash = FTC_CSET_HASH( cset, query->gindex ); - 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 ); + error = ftc_cache_lookup_node( FTC_CACHE(ccache), hash, query, + FTC_NODE_P(anode) ); } - - *anode = node; - *aindex = cindex; - - Exit: return error; } diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c index c524b53cb..6519fd26b 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 each bucket, free the list of glyph nodes */ - for ( ; bucket < bucket_limit; bucket++ ) - { - 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; - } - - 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 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; - - 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; - - Exit: - return error; + /* for now, nothing to be done here */ + FT_UNUSED(gset); } /*************************************************************************/ /*************************************************************************/ /***** *****/ - /***** GLYPH SETS LRU CALLBACKS *****/ + /***** GLYPH CACHES *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ -#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( void ) + ftc_glyph_cache_done( FTC_GlyphCache gcache ) { - 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 ); - if ( !error ) + /* remove all nodes in the cache */ + ftc_cache_done( &gcache->cache ); + + /* simply delete all remaining glyph sets */ + if ( gcache->gset_lru ) { - /* good, now set the gset index within the gset object */ - gset->gset_index = (FT_UInt)( node - lru->nodes ); - node->root.data = gset; + FT_LruList_Destroy( gcache->gset_lru ); + gcache->gset_lru = NULL; } - - 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 ) + ftc_glyph_cache_init( FTC_GlyphCache gcache, + FT_LruList_Class gset_class ) { - 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 ); + FT_Error error; + + 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; } - 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 ) + ftc_glyph_cache_lookup( FTC_GlyphCache gcache, + FTC_GlyphQuery query, + 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 ) + FT_LruNode node; + FT_Error error; + + error = FT_LruList_Lookup( gcache->gset_lru, query, &node ); + if ( !error ) { - FTC_GlyphNode_Ref ( node ); - FTC_Manager_Compress( manager ); - FTC_GlyphNode_Unref ( node ); + 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) ); } - - *anode = node; - - Exit: return error; } + /* END */ diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c index 2c93a23d9..c635ae9bf 100644 --- a/src/cache/ftcimage.c +++ b/src/cache/ftcimage.c @@ -19,6 +19,7 @@ #include #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 /* 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_ - { - FTC_Glyph_CacheRec root; +#define FTC_IMAGE_SET_MEMORY(x) FTC_GLYPH_SET_MEMORY(&(x)->gset) - } FTC_Image_CacheRec; + typedef struct FTC_ImageQueryRec_ + { + 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_DEF( FT_Error ) + ftc_image_cache_init( FTC_Image_Cache cache ) + { + return ftc_glyph_cache_init( (FTC_GlyphCache) cache, &ftc_image_set_class ); + } + + FT_CALLBACK_TABLE_DEF - const FTC_Glyph_Cache_Class ftc_glyph_image_cache_class = + const FTC_Cache_ClassRec ftc_image_cache_class = { - { - 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 + 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_Desc* desc, - FT_UInt gindex, - FT_Glyph *aglyph ) + FTC_Image_Cache_Acquire( FTC_Image_Cache cache, + FTC_Image_Desc* desc, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) { - FT_Error error; - FTC_GlyphNode node; + 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++; + } + } - /* some argument checks are delayed to FTC_Glyph_Cache_Lookup */ + return error; + } - if ( !aglyph ) - return FTC_Err_Invalid_Argument; - error = FTC_Glyph_Cache_Lookup( (FTC_Glyph_Cache)cache, - desc, gindex, &node ); + FT_EXPORT_DEF( void ) + FTC_Image_Cache_Release( FTC_Image_Cache icache, + FTC_Node node ) + { + ftc_node_unref( node, FTC_CACHE(icache) ); + } - if ( !error ) - *aglyph = ((FTC_GlyphImage)node)->ft_glyph; - return error; + + + FT_EXPORT_DEF( FT_Error ) + FTC_Image_Cache_Lookup( FTC_Image_Cache icache, + FTC_Image_Desc* desc, + FT_UInt gindex, + FT_Glyph *aglyph ) + { + return FTC_Image_Cache_Acquire( icache, desc, gindex, aglyph, NULL ); } + /* END */ diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c index 707630585..08fe20270 100644 --- a/src/cache/ftcmanag.c +++ b/src/cache/ftcmanag.c @@ -19,6 +19,7 @@ #include #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 = + { + sizeof( FT_LruListRec ), + (FT_LruList_InitFunc) 0, + (FT_LruList_DoneFunc) 0, + + 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_UShort width; - FT_UShort height; + FT_Face face; + FT_UInt width; + FT_UInt height; + + } FTC_SizeQueryRec, *FTC_SizeQuery; - } FTC_FontRequest; 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_Face face = query->face; + FT_Size size; + FT_Error error; - FT_UNUSED( lru ); - - 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_UNUSED( node ); - + FT_Size size = node->size; - 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,69 +670,56 @@ FT_EXPORT_DEF( void ) FTC_Manager_Compress( FTC_Manager manager ) { - FT_ListNode node; + FTC_Node node, first; + if ( !manager ) + return; - node = manager->global_lru.tail; - while ( manager->num_bytes > manager->max_bytes && node ) - { - FTC_CacheNode cache_node = FTC_LIST_TO_CACHENODE( node ); - FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( cache_node ); - FTC_Cache cache; - FT_ListNode prev = node->prev; + first = manager->nodes_list; +#if 0 + FTC_Manager_Check( manager ); - if ( data->ref_count <= 0 ) - { - /* ok, we are going to remove this node */ - FT_List_Remove( &manager->global_lru, node ); + FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n", + manager->cur_weight, manager->max_weight, manager->num_nodes )); +#endif - /* finalize cache node */ - cache = manager->caches[data->cache_index]; - if ( cache ) - { - FTC_CacheNode_Class* clazz = cache->node_clazz; + if ( manager->cur_weight < manager->max_weight || first == NULL ) + return; - manager->num_bytes -= clazz->size_node( cache_node, - cache->cache_data ); + /* go to last node - it's a circular list */ + node = first->mru_prev; + do + { + FTC_Node prev = node->mru_prev; - clazz->destroy_node( cache_node, cache->cache_data ); - } - else - { - /* this should never happen! */ - FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted!\n" )); - } + prev = ( node == first ) ? NULL : node->mru_prev; + + if ( node->ref_count <= 0 ) + ftc_node_destroy( node, manager ); - /* 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 ); + + 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; - if ( error ) - FREE( cache ); - else - manager->caches[index] = *acache = cache; + 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 4b7d25da9..871c20c84 100644 --- a/src/cache/ftcsbits.c +++ b/src/cache/ftcsbits.c @@ -19,6 +19,7 @@ #include #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 /* 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)) - typedef struct FTC_SBit_CacheRec_ - { - FTC_Chunk_CacheRec root; +#define FTC_SBIT_SET_MEMORY(x) FTC_CHUNK_SET_MEMORY(&(x)->cset) - } FTC_SBit_CacheRec; + typedef struct FTC_SBitQueryRec_ + { + FTC_ChunkQueryRec chunk; + FTC_Image_Desc desc; + + } 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; + /* 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; + error = FT_Load_Glyph( face, gindex, load_flags ); + if ( !error ) + { + 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 ) + return error; + } + + + 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 ) { - FREE( node->elements ); - FREE( node ); - } + error = ftc_sbit_node_load( cnode, query->gindex, NULL ); - *anode = node; + 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; - cset->element_count = FTC_SBITSET_ELEMENT_COUNT; - cset->element_size = sizeof ( FTC_SBitRec ); + sset->desc = query->desc; - /* 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( 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, + sizeof( FT_LruListRec ), + (FT_LruList_InitFunc) NULL, + (FT_LruList_DoneFunc) NULL, - (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new, - (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size, - (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy + sizeof( FTC_SBitSetRec ), + (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_DEF( FT_Error ) + ftc_sbit_cache_init( FTC_SBit_Cache scache ) + { + return ftc_chunk_cache_init( FTC_CHUNK_CACHE(scache), + &ftc_sbit_set_class ); + } + FT_CALLBACK_TABLE_DEF - const FTC_Chunk_Cache_Class ftc_sbit_cache_class = + const FTC_Cache_ClassRec ftc_sbit_cache_class = { - { - 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 + 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 2838847a7..eed41f5ce 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 ) + /* initialize common fields */ + list->clazz = clazz; + list->memory = memory; + list->max_nodes = max_nodes; + list->user_data = user_data; + + if ( clazz->list_init ) { - /* allocate static array of lru list nodes */ - if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) ) + error = clazz->list_init( list ); + if ( error ) { - FREE( lru ); - goto Exit; - } + if ( clazz->list_done ) + clazz->list_done( list ); - /* build the `free_nodes' list from the array */ - lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes ); + 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; - - while ( node ) - { - FT_ListNode next = node->next; - - - clazz->done_element( lru, (FT_LruNode)node ); - if ( !lru->nodes ) - FREE( node ); + memory = list->memory; + clazz = list->clazz; - node = next; - } + FT_LruList_Reset( list ); - /* rebuild free list if necessary */ - if ( lru->nodes ) - lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes ); + if ( clazz->list_done ) + clazz->list_done( list ); - 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; + + while ( node ) + { + FT_LruNode next = node->next; - FT_Lru_Reset( lru ); + if ( clazz->node_done ) + clazz->node_done( node, list ); + + FREE( node ); + node = next; + } - FREE( lru->nodes ); - FREE( lru ); + 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; + } - node = lru->elements.tail; - lru_node = (FT_LruNode)node; - found = lru_node; + /* we haven't found the relevant element. We will now try */ + /* to create a new one. */ + /* */ - if ( clazz->flush_element ) - error = clazz->flush_element( lru, lru_node, key ); - else - { - clazz->done_element( lru, lru_node ); - lru_node->key = key; - node->data = 0; - error = clazz->init_element( lru, 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 ( !error ) + if ( last ) + { + if ( clazz->node_flush ) { - /* now, move element to top of list */ - FT_List_Up( &lru->elements, node ); + error = clazz->node_flush( last, key, list ); } else { - /* in case of error, the node must be discarded */ - FT_List_Remove( &lru->elements, node ); - lru->num_elements--; - - if ( lru->nodes ) - FT_List_Insert( &lru->free_nodes, node ); - else - FREE( lru_node ); + if ( clazz->node_done ) + clazz->node_done( last, list ); - found = 0; + last->key = key; + error = clazz->node_init( last, key, list ); } - } - else - { - FT_LruNode lru_node; - - /* create a new lru list node, then the element for it */ - if ( lru->nodes ) + if ( !error ) { - 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; + /* move it to the top of the list */ + *plast = NULL; + last->next = list->nodes; + list->nodes = last; - 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++; - } - } - - Exit: - *anode = found; - return error; - } - + /* 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 ); - FT_EXPORT_DEF( FT_Error ) - FT_Lru_Lookup( FT_Lru lru, - FT_LruKey key, - FT_Pointer *anobject ) - { - FT_Error error; - FT_LruNode node; + *plast = NULL; + list->num_nodes--; + FREE( last ); + goto Exit; + } + } - /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */ + /* otherwise, simply allocate a new node */ + if ( ALLOC( node, clazz->node_size ) ) + goto Exit; - if ( !anobject ) - return FTC_Err_Invalid_Argument; + node->key = key; + error = clazz->node_init( node, key, list ); + if ( error ) + { + FREE( node ); + goto Exit; + } - *anobject = 0; - error = FT_Lru_Lookup_Node( lru, key, &node ); - if ( !error ) - *anobject = node->root.data; + result = node; + node->next = list->nodes; + list->nodes = node; + list->num_nodes++; + Exit: + *anode = result; 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; } - lru->num_elements--; + pnode = &(*pnode)->next; } } + FT_EXPORT_DEF( void ) - FT_Lru_Remove_Selection( FT_Lru lru, - FT_Lru_Selector selector, - FT_Pointer data ) + FT_LruList_Remove_Selection( FT_LruList list, + FT_LruNode_SelectFunc select_func, + FT_Pointer select_data ) { - if ( !lru || !selector ) + FT_LruNode *pnode, node; + FT_LruList_Class clazz; + FT_Memory memory; + + if ( !list || !select_func ) return; - if ( lru->num_elements > 0 ) - { - FT_ListNode node = lru->elements.head; - FT_ListNode next; + memory = list->memory; + clazz = list->clazz; + pnode = &list->nodes; + for (;;) + { + node = *pnode; + if ( node == NULL ) + break; - while ( node ) + if ( select_func( node, select_data, list ) ) { - 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; + *pnode = node->next; + node->next = NULL; + + if ( clazz->node_done ) + clazz->node_done( node, list ); + + FREE( node ); } + else + pnode = &(*pnode)->next; } }