_major_ re-design of the caching sub-system. Still using the same API
though :-)
This commit is contained in:
parent
ae340bbfec
commit
cd605b6302
@ -1,3 +1,12 @@
|
||||
2001-10-26 David Turner <david@freetype.org>
|
||||
|
||||
* include/freetype/ftcache.h, include/freetype/cache/*.h,
|
||||
src/cache/*.c: Major re-design of the cache sub-system to provide
|
||||
better performance as well as an "Acquire"/"Release" API..
|
||||
|
||||
seems to work well here.. but probably needs a bit more testing..
|
||||
|
||||
|
||||
2001-10-26 Leonard Rosenthol <leonardr@lazerware.com>
|
||||
|
||||
* updated Mac OS README (builds/mac/) to reflect my taking over
|
||||
|
168
include/freetype/cache/ftcchunk.h
vendored
168
include/freetype/cache/ftcchunk.h
vendored
@ -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_
|
||||
/* a chunk set is used to categorize chunks of a given type */
|
||||
typedef struct FTC_ChunkSetRec_
|
||||
{
|
||||
FT_UInt cset_byte_size;
|
||||
|
||||
FTC_ChunkSet_InitFunc init;
|
||||
FTC_ChunkSet_DoneFunc done;
|
||||
FTC_ChunkSet_CompareFunc compare;
|
||||
FTC_ChunkSet_SizesFunc sizes;
|
||||
|
||||
FTC_ChunkSet_NewNodeFunc new_node;
|
||||
FTC_ChunkSet_SizeNodeFunc size_node;
|
||||
FTC_ChunkSet_DestroyNodeFunc destroy_node;
|
||||
|
||||
} FTC_ChunkSet_Class;
|
||||
|
||||
|
||||
typedef struct FTC_ChunkSetRec_
|
||||
{
|
||||
FTC_Chunk_Cache cache;
|
||||
FTC_Manager manager;
|
||||
FT_Memory memory;
|
||||
FTC_ChunkSet_Class* clazz;
|
||||
FT_UInt cset_index; /* index in parent cache */
|
||||
|
||||
FT_UInt element_max; /* maximum number of elements */
|
||||
FT_UInt element_size; /* element size in bytes */
|
||||
FT_UInt element_count; /* number of elements per chunk */
|
||||
|
||||
FT_UInt num_chunks;
|
||||
FTC_ChunkNode* chunks;
|
||||
|
||||
FT_LruNodeRec lru;
|
||||
FT_UFast hash;
|
||||
FTC_ChunkCache ccache;
|
||||
FT_Fast num_chunks;
|
||||
FT_UInt item_total; /* total number of glyphs in set */
|
||||
FT_UInt item_size; /* size of each glyph item in set */
|
||||
FT_UInt item_count; /* number of glyph items per chunk */
|
||||
|
||||
} FTC_ChunkSetRec;
|
||||
|
||||
#define FTC_CHUNK_SET(x) ((FTC_ChunkSet)(x))
|
||||
|
||||
/* the abstract chunk cache class */
|
||||
typedef struct FTC_Chunk_Cache_Class_
|
||||
#define FTC_CHUNK_SET_MEMORY(x) ((x)->ccache->cache.memory)
|
||||
|
||||
/* the abstract chunk cache class */
|
||||
typedef struct FTC_ChunkCacheRec_
|
||||
{
|
||||
FTC_Cache_Class root;
|
||||
FTC_ChunkSet_Class* cset_class;
|
||||
FTC_CacheRec cache;
|
||||
FT_LruList cset_lru; /* LRU list of chunk sets */
|
||||
|
||||
} FTC_ChunkCacheRec;
|
||||
|
||||
} FTC_Chunk_Cache_Class;
|
||||
#define FTC_CHUNK_CACHE(x) ((FTC_ChunkCache)(x))
|
||||
|
||||
|
||||
/* the abstract chunk cache object */
|
||||
typedef struct FTC_Chunk_CacheRec_
|
||||
typedef struct FTC_ChunkQueryRec_
|
||||
{
|
||||
FTC_CacheRec root;
|
||||
FT_Lru csets_lru; /* static chunk set lru list */
|
||||
FTC_ChunkSet last_cset; /* small cache :-) */
|
||||
FTC_ChunkSet_CompareFunc compare; /* useful shortcut */
|
||||
/* input */
|
||||
FT_UInt gindex; /* glyph index */
|
||||
|
||||
} FTC_Chunk_CacheRec;
|
||||
/* output */
|
||||
FTC_ChunkSet cset;
|
||||
|
||||
} FTC_ChunkQueryRec, *FTC_ChunkQuery;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
@ -173,52 +121,44 @@ FT_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
|
||||
|
||||
|
187
include/freetype/cache/ftcglyph.h
vendored
187
include/freetype/cache/ftcglyph.h
vendored
@ -64,107 +64,83 @@
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
/* maximum number of glyph sets per glyph cache; must be < 256 */
|
||||
#define FTC_MAX_GLYPH_SETS 16
|
||||
#define FTC_GSET_HASH_SIZE_DEFAULT 64
|
||||
|
||||
|
||||
/* each glyph set is caracterized by a "glyph set type" which must be */
|
||||
/* defined by sub-classes.. */
|
||||
typedef struct FTC_GlyphSetRec_* FTC_GlyphSet;
|
||||
typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode;
|
||||
typedef struct FTC_Glyph_CacheRec_* FTC_Glyph_Cache;
|
||||
|
||||
typedef struct FTC_GlyphNodeRec_
|
||||
/* handle to a glyph cache node */
|
||||
typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode;
|
||||
|
||||
/* a glyph cache, its nodes are all glyph-specific */
|
||||
typedef struct FTC_GlyphCacheRec_* FTC_GlyphCache;
|
||||
|
||||
/* glyph sets class handle */
|
||||
typedef const struct FTC_GlyphSet_ClassRec_* FTC_GlyphSet_Class;
|
||||
|
||||
|
||||
/* size should be 24 bytes on 32-bit machines */
|
||||
/* note that the node's hash is ((gset->hash << 16) | glyph_index) */
|
||||
/* this _must_ be set properly by the glyph node initializer */
|
||||
/* */
|
||||
typedef struct FTC_GlyphNodeRec_
|
||||
{
|
||||
FTC_CacheNodeRec root;
|
||||
FTC_GlyphNode gset_next; /* next in glyph set's bucket list */
|
||||
FT_UShort glyph_index;
|
||||
FT_UShort gset_index;
|
||||
FTC_NodeRec node;
|
||||
FTC_GlyphSet gset;
|
||||
|
||||
} FTC_GlyphNodeRec;
|
||||
|
||||
|
||||
#define FTC_GLYPHNODE( x ) ( (FTC_GlyphNode)( x ) )
|
||||
#define FTC_GLYPHNODE_TO_LRUNODE( n ) ( (FT_ListNode)( n ) )
|
||||
#define FTC_LRUNODE_TO_GLYPHNODE( n ) ( (FTC_GlyphNode)( n ) )
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* Glyph set methods. */
|
||||
/* */
|
||||
|
||||
typedef FT_Error
|
||||
(*FTC_GlyphSet_InitFunc)( FTC_GlyphSet gset,
|
||||
FT_Pointer type );
|
||||
|
||||
typedef void
|
||||
(*FTC_GlyphSet_DoneFunc)( FTC_GlyphSet gset );
|
||||
|
||||
typedef FT_Bool
|
||||
(*FTC_GlyphSet_CompareFunc)( FTC_GlyphSet gset,
|
||||
FT_Pointer type );
|
||||
|
||||
|
||||
typedef FT_Error
|
||||
(*FTC_GlyphSet_NewNodeFunc)( FTC_GlyphSet gset,
|
||||
FT_UInt gindex,
|
||||
FTC_GlyphNode* anode );
|
||||
|
||||
typedef void
|
||||
(*FTC_GlyphSet_DestroyNodeFunc)( FTC_GlyphNode node,
|
||||
FTC_GlyphSet gset );
|
||||
|
||||
typedef FT_ULong
|
||||
(*FTC_GlyphSet_SizeNodeFunc)( FTC_GlyphNode node,
|
||||
FTC_GlyphSet gset );
|
||||
|
||||
|
||||
typedef struct FTC_GlyphSet_Class_
|
||||
{
|
||||
FT_UInt gset_byte_size;
|
||||
|
||||
FTC_GlyphSet_InitFunc init;
|
||||
FTC_GlyphSet_DoneFunc done;
|
||||
FTC_GlyphSet_CompareFunc compare;
|
||||
|
||||
FTC_GlyphSet_NewNodeFunc new_node;
|
||||
FTC_GlyphSet_SizeNodeFunc size_node;
|
||||
FTC_GlyphSet_DestroyNodeFunc destroy_node;
|
||||
|
||||
} FTC_GlyphSet_Class;
|
||||
#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 root;
|
||||
FT_Lru gsets_lru; /* static sets lru list */
|
||||
FTC_GlyphSet last_gset; /* small cache :-) */
|
||||
FTC_GlyphSet_CompareFunc compare; /* useful shortcut */
|
||||
FTC_CacheRec cache;
|
||||
FT_LruList gset_lru; /* LRU list of glyph sets */
|
||||
|
||||
} FTC_Glyph_CacheRec;
|
||||
} FTC_GlyphCacheRec;
|
||||
|
||||
#define FTC_GLYPH_CACHE(x) ((FTC_GlyphCache)(x))
|
||||
#define FTC_GLYPH_CACHE_P(x) ((FTC_GlyphCache*)(x))
|
||||
|
||||
|
||||
typedef struct FTC_GlyphQueryRec_
|
||||
{
|
||||
/* input */
|
||||
FT_UInt gindex;
|
||||
|
||||
/* output */
|
||||
FTC_GlyphSet gset;
|
||||
|
||||
} FTC_GlyphQueryRec, *FTC_GlyphQuery;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
@ -174,44 +150,41 @@ 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 );
|
||||
|
||||
|
||||
/* can be used as a FTC_Cache_DoneFunc or called by sub-classes */
|
||||
FT_EXPORT( void )
|
||||
ftc_glyph_cache_done( FTC_GlyphCache cache );
|
||||
|
||||
/* must be called in a FTC_Cache_InitFunc !! */
|
||||
FT_EXPORT( FT_Error )
|
||||
FTC_GlyphSet_New( FTC_Glyph_Cache cache,
|
||||
FT_Pointer type,
|
||||
FTC_GlyphSet *aset );
|
||||
ftc_glyph_cache_init( FTC_GlyphCache cache,
|
||||
FT_LruList_Class gset_class );
|
||||
|
||||
/* can be called directly or from sub-classes */
|
||||
FT_EXPORT( FT_Error )
|
||||
FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
|
||||
FT_UInt glyph_index,
|
||||
FTC_GlyphNode *anode );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache cache,
|
||||
FT_Pointer type,
|
||||
FT_UInt gindex,
|
||||
FTC_GlyphNode *anode );
|
||||
ftc_glyph_cache_lookup( FTC_GlyphCache cache,
|
||||
FTC_GlyphQuery query,
|
||||
FTC_GlyphNode *anode );
|
||||
|
||||
|
||||
FT_END_HEADER
|
||||
|
9
include/freetype/cache/ftcimage.h
vendored
9
include/freetype/cache/ftcimage.h
vendored
@ -29,7 +29,6 @@
|
||||
|
||||
#include <ft2build.h>
|
||||
#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) )
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
|
317
include/freetype/cache/ftcmanag.h
vendored
317
include/freetype/cache/ftcmanag.h
vendored
@ -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;
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
@ -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 )
|
||||
|
||||
#define FTC_LIST_TO_CACHENODE( n ) ( (FTC_CacheNode)(n) )
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <FuncType> */
|
||||
/* FTC_CacheNode_SizeFunc */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A function used to compute the total size in bytes of a given */
|
||||
/* cache node. It is used by the cache manager to compute the number */
|
||||
/* of old nodes to flush when the cache is full. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* node :: A handle to the target cache node. */
|
||||
/* */
|
||||
/* cache_data :: A generic pointer passed to the destructor. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The size of a given cache node in bytes. */
|
||||
/* */
|
||||
typedef FT_ULong
|
||||
(*FTC_CacheNode_SizeFunc)( FTC_CacheNode node,
|
||||
FT_Pointer cache_data );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <FuncType> */
|
||||
/* FTC_CacheNode_DestroyFunc */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A function used to destroy a given cache node. It is called by */
|
||||
/* the manager when the cache is full and old nodes need to be */
|
||||
/* flushed out. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* node :: A handle to the target cache node. */
|
||||
/* */
|
||||
/* cache_data :: A generic pointer passed to the destructor. */
|
||||
/* */
|
||||
typedef void
|
||||
(*FTC_CacheNode_DestroyFunc)( FTC_CacheNode node,
|
||||
FT_Pointer cache_data );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* FTC_CacheNode_Class */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple structure used to describe a cache node's class to */
|
||||
/* the cache manager. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* size_node :: A function used to size the node. */
|
||||
/* */
|
||||
/* destroy_node :: A function used to destroy the node. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* The cache node class doesn't include a `new_node' function because */
|
||||
/* the cache manager never allocates cache node directly; it */
|
||||
/* delegates this task to its cache objects. */
|
||||
/* */
|
||||
typedef struct FTC_CacheNode_Class_
|
||||
{
|
||||
FTC_CacheNode_SizeFunc size_node;
|
||||
FTC_CacheNode_DestroyFunc destroy_node;
|
||||
|
||||
} FTC_CacheNode_Class;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** CACHE DEFINITIONS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <FuncType> */
|
||||
/* FTC_Cache_InitFunc */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A function used to initialize a given cache object. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* cache :: A handle to the new cache. */
|
||||
/* */
|
||||
typedef FT_Error
|
||||
(*FTC_Cache_InitFunc)( FTC_Cache cache );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <FuncType> */
|
||||
/* FTC_Cache_DoneFunc */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A function to finalize a given cache object. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* cache :: A handle to the target cache. */
|
||||
/* */
|
||||
typedef void
|
||||
(*FTC_Cache_DoneFunc)( FTC_Cache cache );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* FTC_Cache_Class */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure used to describe a given cache object class to the */
|
||||
/* cache manager. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* cache_byte_size :: The size of the cache object in bytes. */
|
||||
/* */
|
||||
/* init_cache :: The cache object initializer. */
|
||||
/* */
|
||||
/* done_cache :: The cache object finalizer. */
|
||||
/* */
|
||||
struct FTC_Cache_Class_
|
||||
{
|
||||
FT_UInt cache_byte_size;
|
||||
FTC_Cache_InitFunc init_cache;
|
||||
FTC_Cache_DoneFunc done_cache;
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* FTC_CacheRec */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure used to describe an abstract cache object. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* manager :: A handle to the parent cache manager. */
|
||||
/* */
|
||||
/* memory :: A handle to the memory manager. */
|
||||
/* */
|
||||
/* clazz :: A pointer to the cache class. */
|
||||
/* */
|
||||
/* node_clazz :: A pointer to the cache's node class. */
|
||||
/* */
|
||||
/* cache_index :: An index of the cache in the manager's table. */
|
||||
/* */
|
||||
/* cache_data :: Data passed to the cache node */
|
||||
/* constructor/finalizer. */
|
||||
/* */
|
||||
/* each cache really implements a dynamic hash table to manage its nodes */
|
||||
typedef struct FTC_CacheRec_
|
||||
{
|
||||
FTC_Manager manager;
|
||||
FT_Memory memory;
|
||||
FTC_Cache_Class* clazz;
|
||||
FTC_CacheNode_Class* node_clazz;
|
||||
FTC_Manager manager;
|
||||
FT_Memory memory;
|
||||
FTC_Cache_Class clazz;
|
||||
|
||||
FT_UInt cache_index; /* in manager's table */
|
||||
FT_Pointer cache_data; /* passed to cache node methods */
|
||||
FT_UInt cache_index; /* in manager's table */
|
||||
FT_Pointer cache_data; /* used by cache node methods */
|
||||
|
||||
FT_UFast nodes;
|
||||
FT_UFast size;
|
||||
FTC_Node* buckets;
|
||||
|
||||
} FTC_CacheRec;
|
||||
|
||||
|
||||
#define FTC_CACHE(x) ((FTC_Cache)(x))
|
||||
#define FTC_CACHE_P(x) ((FTC_Cache*)(x))
|
||||
|
||||
|
||||
/* initialize a given cache */
|
||||
typedef FT_Error
|
||||
(*FTC_Cache_InitFunc)( FTC_Cache cache );
|
||||
|
||||
/* finalize a given cache */
|
||||
typedef void
|
||||
(*FTC_Cache_DoneFunc)( FTC_Cache cache );
|
||||
|
||||
/* initialize a new cache node */
|
||||
typedef FT_Error
|
||||
(*FTC_Node_InitFunc)( FTC_Node node,
|
||||
FT_Pointer type,
|
||||
FTC_Cache cache );
|
||||
|
||||
/* compute the weight of a given cache node */
|
||||
typedef FT_ULong
|
||||
(*FTC_Node_WeightFunc)( FTC_Node node,
|
||||
FTC_Cache cache );
|
||||
|
||||
/* compare a node to a given key pair */
|
||||
typedef FT_Bool
|
||||
(*FTC_Node_CompareFunc)( FTC_Node node,
|
||||
FT_Pointer key,
|
||||
FTC_Cache cache );
|
||||
|
||||
/* finalize a given cache node */
|
||||
typedef void
|
||||
(*FTC_Node_DoneFunc)( FTC_Node node,
|
||||
FTC_Cache cache );
|
||||
|
||||
typedef struct FTC_Cache_ClassRec_
|
||||
{
|
||||
FT_UInt cache_size;
|
||||
FTC_Cache_InitFunc cache_init;
|
||||
FTC_Cache_DoneFunc cache_done;
|
||||
|
||||
FT_UInt node_size;
|
||||
FTC_Node_InitFunc node_init;
|
||||
FTC_Node_WeightFunc node_weight;
|
||||
FTC_Node_CompareFunc node_compare;
|
||||
FTC_Node_DoneFunc node_done;
|
||||
|
||||
} FTC_Cache_ClassRec;
|
||||
|
||||
/* */
|
||||
|
||||
#define FTC_CACHE_RESIZE_TEST(c) \
|
||||
( (c)->nodes*3 < (c)->size || \
|
||||
(c)->size*3 < (c)->nodes )
|
||||
|
||||
|
||||
/* this must be used internally for the moment */
|
||||
FT_EXPORT( FT_Error )
|
||||
FTC_Manager_Register_Cache( FTC_Manager manager,
|
||||
FTC_Cache_Class clazz,
|
||||
FTC_Cache *acache );
|
||||
|
||||
|
||||
/* can be used directory as FTC_Cache_DoneFunc, or called by custom */
|
||||
/* cache finalizers.. */
|
||||
FT_EXPORT( void )
|
||||
ftc_cache_done( FTC_Cache cache );
|
||||
|
||||
/* initalize the hash table within the cache */
|
||||
FT_EXPORT( FT_Error )
|
||||
ftc_cache_init( FTC_Cache cache );
|
||||
|
||||
/* can be used when FTC_CACHE_RESIZE_TEST returns TRUE after a node */
|
||||
/* insertion.. */
|
||||
FT_EXPORT(void)
|
||||
ftc_cache_resize( FTC_Cache cache );
|
||||
|
||||
|
||||
/* can be called when the key's hash value has been computed */
|
||||
FT_EXPORT(FT_Error)
|
||||
ftc_cache_lookup_node( FTC_Cache cache,
|
||||
FT_UFast key_hash,
|
||||
FT_Pointer key,
|
||||
FTC_Node *anode );
|
||||
|
||||
/* can be called to increment a node's reference count */
|
||||
FT_EXPORT(void)
|
||||
ftc_node_ref( FTC_Node node,
|
||||
FTC_Cache cache );
|
||||
|
||||
/* can be called to decrement a node's reference count */
|
||||
FT_EXPORT(void)
|
||||
ftc_node_unref( FTC_Node node,
|
||||
FTC_Cache cache );
|
||||
|
||||
/* */
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
|
1
include/freetype/cache/ftcsbits.h
vendored
1
include/freetype/cache/ftcsbits.h
vendored
@ -22,7 +22,6 @@
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_CACHE_H
|
||||
#include FT_CACHE_INTERNAL_CHUNK_H
|
||||
#include FT_CACHE_IMAGE_H
|
||||
|
||||
|
||||
|
173
include/freetype/cache/ftlru.h
vendored
173
include/freetype/cache/ftlru.h
vendored
@ -66,117 +66,130 @@
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
/* generic key type */
|
||||
/* generic list key type */
|
||||
typedef FT_Pointer FT_LruKey;
|
||||
|
||||
/* a list list handle */
|
||||
typedef struct FT_LruListRec_* FT_LruList;
|
||||
|
||||
/* an lru node -- root.data points to the element */
|
||||
/* list class handle */
|
||||
typedef const struct FT_LruList_ClassRec_* FT_LruList_Class;
|
||||
|
||||
/* an list node handle */
|
||||
typedef struct FT_LruNodeRec_* FT_LruNode;
|
||||
|
||||
/* the list node structure */
|
||||
typedef struct FT_LruNodeRec_
|
||||
{
|
||||
FT_ListNodeRec root;
|
||||
FT_LruKey key;
|
||||
FT_LruNode next;
|
||||
FT_LruKey key;
|
||||
|
||||
} FT_LruNodeRec, *FT_LruNode;
|
||||
} FT_LruNodeRec;
|
||||
|
||||
|
||||
/* forward declaration */
|
||||
typedef struct FT_LruRec_* FT_Lru;
|
||||
|
||||
|
||||
/* LRU class */
|
||||
typedef struct FT_Lru_Class_
|
||||
/* the list structure */
|
||||
typedef struct FT_LruListRec_
|
||||
{
|
||||
FT_UInt lru_size; /* object size in bytes */
|
||||
FT_Memory memory;
|
||||
FT_LruList_Class clazz;
|
||||
FT_LruNode nodes;
|
||||
FT_UInt max_nodes;
|
||||
FT_UInt num_nodes;
|
||||
FT_Pointer user_data;
|
||||
|
||||
/* this method is used to initialize a new list element node */
|
||||
FT_Error
|
||||
(*init_element)( FT_Lru lru,
|
||||
FT_LruNode node );
|
||||
} FT_LruListRec;
|
||||
|
||||
/* this method is used to finalize a given list element node */
|
||||
void
|
||||
(*done_element)( FT_Lru lru,
|
||||
FT_LruNode node );
|
||||
|
||||
/* If defined, this method is called when the list if full */
|
||||
/* during the lookup process -- it is used to change the contents */
|
||||
/* of a list element node, instead of calling `done_element()', */
|
||||
/* then `init_element'. Set it to 0 for default behaviour. */
|
||||
FT_Error
|
||||
(*flush_element)( FT_Lru lru,
|
||||
FT_LruNode node,
|
||||
FT_LruKey new_key );
|
||||
/* initialize a list list */
|
||||
typedef FT_Error (*FT_LruList_InitFunc)( FT_LruList list );
|
||||
|
||||
/* finalize a list list */
|
||||
typedef void (*FT_LruList_DoneFunc)( FT_LruList list );
|
||||
|
||||
/* If defined, this method is used to compare a list element node */
|
||||
/* with a given key during a lookup. If set to 0, the `key' */
|
||||
/* fields will be directly compared instead. */
|
||||
FT_Bool
|
||||
(*compare_element)( FT_LruNode node,
|
||||
FT_LruKey key );
|
||||
/* this method is used to initialize a new list element node */
|
||||
typedef FT_Error (*FT_LruNode_InitFunc)( FT_LruNode node,
|
||||
FT_LruKey key,
|
||||
FT_LruList list );
|
||||
|
||||
} FT_Lru_Class;
|
||||
/* this method is used to finalize a given list element node */
|
||||
typedef void (*FT_LruNode_DoneFunc)( FT_LruNode node,
|
||||
FT_LruList list );
|
||||
|
||||
/* If defined, this method is called when the list if full */
|
||||
/* during the lookup process -- it is used to change the contents */
|
||||
/* of a list element node, instead of calling `done_element()', */
|
||||
/* then `init_element'. Set it to 0 for default behaviour. */
|
||||
typedef FT_Error (*FT_LruNode_FlushFunc)( FT_LruNode node,
|
||||
FT_LruKey new_key,
|
||||
FT_LruList list );
|
||||
|
||||
/* If defined, this method is used to compare a list element node */
|
||||
/* with a given key during a lookup. If set to 0, the `key' */
|
||||
/* fields will be directly compared instead. */
|
||||
typedef FT_Bool (*FT_LruNode_CompareFunc)( FT_LruNode node,
|
||||
FT_LruKey key,
|
||||
FT_LruList list );
|
||||
|
||||
/* A selector is used to indicate whether a given list element node */
|
||||
/* is part of a selection for FT_Lru_Remove_Selection(). The function */
|
||||
/* is part of a selection for FT_LruList_Remove_Selection(). The function */
|
||||
/* must return true (i.e., non-null) to indicate that the node is part */
|
||||
/* of it. */
|
||||
typedef FT_Bool
|
||||
(*FT_Lru_Selector)( FT_Lru lru,
|
||||
FT_LruNode node,
|
||||
FT_Pointer data );
|
||||
typedef FT_Bool (*FT_LruNode_SelectFunc)( FT_LruNode node,
|
||||
FT_Pointer data,
|
||||
FT_LruList list );
|
||||
|
||||
|
||||
typedef struct FT_LruRec_
|
||||
/* LRU class */
|
||||
typedef struct FT_LruList_ClassRec_
|
||||
{
|
||||
FT_Lru_Class* clazz;
|
||||
FT_UInt max_elements;
|
||||
FT_UInt num_elements;
|
||||
FT_ListRec elements;
|
||||
FT_Memory memory;
|
||||
FT_Pointer user_data;
|
||||
FT_UInt list_size;
|
||||
FT_LruList_InitFunc list_init; /* optional */
|
||||
FT_LruList_DoneFunc list_done; /* optional */
|
||||
|
||||
FT_UInt node_size;
|
||||
FT_LruNode_InitFunc node_init; /* MANDATORY */
|
||||
FT_LruNode_DoneFunc node_done; /* optional */
|
||||
FT_LruNode_FlushFunc node_flush; /* optional */
|
||||
FT_LruNode_CompareFunc node_compare; /* optional */
|
||||
|
||||
/* the following fields are only meaningful for static lru containers */
|
||||
FT_ListRec free_nodes;
|
||||
FT_LruNode nodes;
|
||||
} FT_LruList_ClassRec;
|
||||
|
||||
} FT_LruRec;
|
||||
|
||||
/* the following functions must be exported in the case where applications */
|
||||
/* would want to write their own cache classes.. */
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_LruList_New( FT_LruList_Class clazz,
|
||||
FT_UInt max_elements,
|
||||
FT_Pointer user_data,
|
||||
FT_Memory memory,
|
||||
FT_LruList *alist );
|
||||
|
||||
FT_EXPORT( void )
|
||||
FT_LruList_Reset( FT_LruList list );
|
||||
|
||||
|
||||
FT_EXPORT( void )
|
||||
FT_LruList_Destroy ( FT_LruList list );
|
||||
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Lru_New( const FT_Lru_Class* clazz,
|
||||
FT_UInt max_elements,
|
||||
FT_Pointer user_data,
|
||||
FT_Memory memory,
|
||||
FT_Bool pre_alloc,
|
||||
FT_Lru *anlru );
|
||||
FT_LruList_Lookup( FT_LruList list,
|
||||
FT_LruKey key,
|
||||
FT_LruNode *anode );
|
||||
|
||||
|
||||
FT_EXPORT( void )
|
||||
FT_Lru_Reset( FT_Lru lru );
|
||||
FT_LruList_Remove( FT_LruList list,
|
||||
FT_LruNode node );
|
||||
|
||||
|
||||
FT_EXPORT( void )
|
||||
FT_Lru_Done ( FT_Lru lru );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Lru_Lookup_Node( FT_Lru lru,
|
||||
FT_LruKey key,
|
||||
FT_LruNode *anode );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Lru_Lookup( FT_Lru lru,
|
||||
FT_LruKey key,
|
||||
FT_Pointer *anobject );
|
||||
|
||||
FT_EXPORT( void )
|
||||
FT_Lru_Remove_Node( FT_Lru lru,
|
||||
FT_LruNode node );
|
||||
|
||||
FT_EXPORT( void )
|
||||
FT_Lru_Remove_Selection( FT_Lru lru,
|
||||
FT_Lru_Selector selector,
|
||||
FT_Pointer data );
|
||||
|
||||
FT_LruList_Remove_Selection( FT_LruList list,
|
||||
FT_LruNode_SelectFunc select_func,
|
||||
FT_Pointer select_data );
|
||||
|
||||
/* */
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
#endif /* __FTLRU_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 );
|
||||
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_CONFIG_CONFIG_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
#include FT_INTERNAL_MEMORY_H
|
||||
#include FT_SYSTEM_H
|
||||
#include FT_ERRORS_H
|
||||
#include FT_TYPES_H
|
||||
@ -173,7 +174,7 @@
|
||||
if ( new_buckets == NULL )
|
||||
return;
|
||||
|
||||
memset( new_buckets, 0, sizeof(FT_MemNode)*new_size );
|
||||
MEM_Set( new_buckets, 0, sizeof(FT_MemNode)*new_size );
|
||||
|
||||
for ( i = 0; i < table->size; i++ )
|
||||
{
|
||||
@ -211,7 +212,7 @@
|
||||
table = memory->alloc( memory, sizeof(*table) );
|
||||
if ( table == NULL ) goto Exit;
|
||||
|
||||
memset( table, 0, sizeof(*table) );
|
||||
MEM_Set( table, 0, sizeof(*table) );
|
||||
|
||||
table->size = FT_MEM_SIZE_MIN;
|
||||
table->nodes = 0;
|
||||
@ -226,7 +227,7 @@
|
||||
|
||||
table->buckets = memory->alloc( memory, table->size * sizeof(FT_MemNode) );
|
||||
if ( table->buckets )
|
||||
memset( table->buckets, 0, sizeof(FT_MemNode)*table->size );
|
||||
MEM_Set( table->buckets, 0, sizeof(FT_MemNode)*table->size );
|
||||
else
|
||||
{
|
||||
memory->free( memory, table );
|
||||
@ -408,7 +409,7 @@
|
||||
|
||||
/* we simply invert the node's size to indicate that the node */
|
||||
/* was freed. We also change its content.. */
|
||||
memset( address, 0xF3, node->size );
|
||||
MEM_Set( address, 0xF3, node->size );
|
||||
|
||||
table->alloc_current -= node->size;
|
||||
node->size = -node->size;
|
||||
|
440
src/cache/ftcchunk.c
vendored
440
src/cache/ftcchunk.c
vendored
@ -34,73 +34,62 @@
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
#define FTC_CSET_HASH(cset,start) \
|
||||
((FT_UFast)(((cset)->hash << 16) | ((start) & 0xFFFF)))
|
||||
|
||||
/* create a new chunk node, setting its cache index and ref count */
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_ChunkNode_Init( FTC_ChunkNode node,
|
||||
FTC_ChunkSet cset,
|
||||
FT_UInt index,
|
||||
FT_Bool alloc )
|
||||
ftc_chunk_node_init( FTC_ChunkNode cnode,
|
||||
FTC_ChunkSet cset,
|
||||
FT_UInt gindex,
|
||||
FT_Bool alloc )
|
||||
{
|
||||
FTC_Chunk_Cache cache = cset->cache;
|
||||
FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root );
|
||||
FT_Error error = 0;
|
||||
FTC_ChunkCache ccache = cset->ccache;
|
||||
FT_Error error = 0;
|
||||
FT_UInt len;
|
||||
FT_UInt start = (gindex / cset->item_count) * cset->item_count;
|
||||
|
||||
cnode->cset = cset;
|
||||
cnode->node.hash = FTC_CSET_HASH(cset,start);
|
||||
cnode->item_start = start;
|
||||
|
||||
data->cache_index = (FT_UShort)cache->root.cache_index;
|
||||
data->ref_count = (FT_Short) 0;
|
||||
node->cset = cset;
|
||||
node->cset_index = (FT_UShort)index;
|
||||
node->num_elements = (unsigned short)(
|
||||
( index + 1 < cset->num_chunks )
|
||||
? cset->element_count
|
||||
: cset->element_max - cset->element_count*index );
|
||||
len = cset->item_total - start;
|
||||
if ( len > cset->item_count )
|
||||
len = cset->item_count;
|
||||
|
||||
cnode->item_count = len;
|
||||
|
||||
if ( alloc )
|
||||
{
|
||||
/* allocate elements array */
|
||||
FT_Memory memory;
|
||||
|
||||
|
||||
memory = cache->root.memory;
|
||||
error = MEM_Alloc( node->elements,
|
||||
cset->element_size * cset->element_count );
|
||||
FT_Memory memory = ccache->cache.memory;
|
||||
|
||||
error = MEM_Alloc( cnode->items, cset->item_size * cnode->item_count );
|
||||
}
|
||||
|
||||
if (!error )
|
||||
cset->num_chunks++;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_ChunkNode_Destroy( FTC_ChunkNode node )
|
||||
ftc_chunk_node_done( FTC_ChunkNode cnode )
|
||||
{
|
||||
FTC_ChunkSet cset = node->cset;
|
||||
|
||||
|
||||
/* remove from parent set table */
|
||||
cset->chunks[node->cset_index] = 0;
|
||||
FTC_ChunkSet cset = cnode->cset;
|
||||
FT_Memory memory = cset->ccache->cache.memory;
|
||||
|
||||
/* destroy the node */
|
||||
cset->clazz->destroy_node( node );
|
||||
FREE( cnode->items );
|
||||
cnode->item_count = 0;
|
||||
cnode->item_start = 0;
|
||||
|
||||
/* remove from parent set table - eventually destroy the set */
|
||||
if ( --cset->num_chunks <= 0 )
|
||||
FT_LruList_Remove( cset->ccache->cset_lru, (FT_LruNode) cset );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_ULong )
|
||||
FTC_ChunkNode_Size( FTC_ChunkNode node )
|
||||
{
|
||||
FTC_ChunkSet cset = node->cset;
|
||||
|
||||
|
||||
return cset->clazz->size_node( node );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_CacheNode_Class ftc_chunk_cache_node_class =
|
||||
{
|
||||
(FTC_CacheNode_SizeFunc) FTC_ChunkNode_Size,
|
||||
(FTC_CacheNode_DestroyFunc)FTC_ChunkNode_Destroy
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
@ -112,339 +101,88 @@
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_ChunkSet_New( FTC_Chunk_Cache cache,
|
||||
FT_Pointer type,
|
||||
FTC_ChunkSet *aset )
|
||||
ftc_chunk_set_init( FTC_ChunkSet cset,
|
||||
FT_UInt item_size,
|
||||
FT_UInt item_count,
|
||||
FT_UInt item_total,
|
||||
FTC_ChunkCache cache )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory = cache->root.memory;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FTC_ChunkSet cset = 0;
|
||||
cset->ccache = cache;
|
||||
cset->num_chunks = 0;
|
||||
|
||||
FTC_Chunk_Cache_Class* ccache_class;
|
||||
FTC_ChunkSet_Class* clazz;
|
||||
cset->item_total = item_total;
|
||||
cset->item_size = item_size;
|
||||
cset->item_count = item_count;
|
||||
|
||||
|
||||
ccache_class = (FTC_Chunk_Cache_Class*)cache->root.clazz;
|
||||
clazz = ccache_class->cset_class;
|
||||
|
||||
*aset = 0;
|
||||
|
||||
if ( ALLOC( cset, clazz->cset_byte_size ) )
|
||||
goto Exit;
|
||||
|
||||
cset->cache = cache;
|
||||
cset->manager = manager;
|
||||
cset->memory = memory;
|
||||
cset->clazz = clazz;
|
||||
|
||||
/* now compute element_max, element_count and element_size */
|
||||
error = clazz->sizes( cset, type );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* compute maximum number of nodes */
|
||||
cset->num_chunks = ( cset->element_max + cset->element_count - 1 ) /
|
||||
cset->element_count;
|
||||
|
||||
/* allocate chunk pointers table */
|
||||
if ( ALLOC_ARRAY( cset->chunks, cset->num_chunks, FTC_ChunkNode ) )
|
||||
goto Exit;
|
||||
|
||||
/* initialize set by type if needed */
|
||||
if ( clazz->init )
|
||||
{
|
||||
error = clazz->init( cset, type );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
*aset = cset;
|
||||
|
||||
Exit:
|
||||
if ( error && cset )
|
||||
{
|
||||
FREE( cset->chunks );
|
||||
FREE( cset );
|
||||
}
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_ChunkSet_Destroy( FTC_ChunkSet cset )
|
||||
ftc_chunk_set_done( FTC_ChunkSet cset )
|
||||
{
|
||||
FTC_Chunk_Cache cache = cset->cache;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FT_List glyphs_lru = &manager->global_lru;
|
||||
FTC_ChunkNode* bucket = cset->chunks;
|
||||
FTC_ChunkNode* bucket_limit = bucket + cset->num_chunks;
|
||||
FT_Memory memory = cache->root.memory;
|
||||
|
||||
FTC_ChunkSet_Class* clazz = cset->clazz;
|
||||
/* nothing for now */
|
||||
FT_UNUSED( cset );
|
||||
}
|
||||
|
||||
|
||||
/* for each bucket, free the list of glyph nodes */
|
||||
for ( ; bucket < bucket_limit; bucket++ )
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** CHUNK CACHES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
ftc_chunk_cache_done( FTC_ChunkCache ccache )
|
||||
{
|
||||
ftc_cache_done( FTC_CACHE(ccache) );
|
||||
|
||||
/* simply delete all remaining glyph sets */
|
||||
if ( ccache->cset_lru )
|
||||
{
|
||||
FTC_ChunkNode node = bucket[0];
|
||||
FT_ListNode lrunode;
|
||||
|
||||
|
||||
if ( node )
|
||||
{
|
||||
lrunode = FTC_CHUNKNODE_TO_LRUNODE( node );
|
||||
|
||||
manager->num_bytes -= clazz->size_node( node );
|
||||
manager->num_nodes--;
|
||||
|
||||
FT_List_Remove( glyphs_lru, lrunode );
|
||||
|
||||
clazz->destroy_node( node );
|
||||
|
||||
bucket[0] = 0;
|
||||
}
|
||||
FT_LruList_Destroy( ccache->cset_lru );
|
||||
ccache->cset_lru = NULL;
|
||||
}
|
||||
|
||||
if ( clazz->done )
|
||||
clazz->done( cset );
|
||||
|
||||
FREE( cset->chunks );
|
||||
FREE( cset );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset,
|
||||
FT_UInt glyph_index,
|
||||
FTC_ChunkNode *anode,
|
||||
FT_UInt *anindex )
|
||||
ftc_chunk_cache_init( FTC_ChunkCache ccache,
|
||||
FT_LruList_Class cset_class )
|
||||
{
|
||||
FTC_Chunk_Cache cache = cset->cache;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FT_Error error = 0;
|
||||
FT_Error error;
|
||||
|
||||
FTC_ChunkSet_Class* clazz = cset->clazz;
|
||||
|
||||
|
||||
*anode = 0;
|
||||
|
||||
if ( glyph_index >= cset->element_max )
|
||||
error = FTC_Err_Invalid_Argument;
|
||||
else
|
||||
{
|
||||
FT_UInt chunk_size = cset->element_count;
|
||||
FT_UInt chunk_index = glyph_index / chunk_size;
|
||||
FTC_ChunkNode* pnode = cset->chunks + chunk_index;
|
||||
FTC_ChunkNode node = *pnode;
|
||||
|
||||
|
||||
if ( !node )
|
||||
{
|
||||
/* we didn't found the glyph image; we will now create a new one */
|
||||
error = clazz->new_node( cset, chunk_index, &node );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* store the new chunk in the cset's table */
|
||||
*pnode = node;
|
||||
|
||||
/* insert the node at the start the global LRU glyph list */
|
||||
FT_List_Insert( &manager->global_lru,
|
||||
FTC_CHUNKNODE_TO_LRUNODE( node ) );
|
||||
|
||||
manager->num_bytes += clazz->size_node( node );
|
||||
manager->num_nodes++;
|
||||
|
||||
if ( manager->num_bytes > manager->max_bytes )
|
||||
{
|
||||
FTC_ChunkNode_Ref ( node );
|
||||
FTC_Manager_Compress( manager );
|
||||
FTC_ChunkNode_Unref ( node );
|
||||
}
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
*anindex = glyph_index - chunk_index * chunk_size;
|
||||
}
|
||||
error = ftc_cache_init( FTC_CACHE(ccache) );
|
||||
if (error) goto Exit;
|
||||
|
||||
error = FT_LruList_New( cset_class, 0, ccache,
|
||||
ccache->cache.memory,
|
||||
&ccache->cset_lru );
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** CHUNK SETS LRU CALLBACKS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
#define FTC_CSET_LRU_GET_CACHE( lru ) \
|
||||
( (FTC_Chunk_Cache)((lru)->user_data) )
|
||||
|
||||
#define FTC_CSET_LRU_GET_MANAGER( lru ) \
|
||||
FTC_CSET_LRU_GET_CACHE( lru )->manager
|
||||
|
||||
#define FTC_LRUNODE_CSET( node ) \
|
||||
( (FTC_ChunkSet)(node)->root.data )
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_chunk_set_lru_init( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
ftc_chunk_cache_lookup( FTC_ChunkCache ccache,
|
||||
FTC_ChunkQuery query,
|
||||
FTC_ChunkNode *anode )
|
||||
{
|
||||
FTC_Chunk_Cache cache = FTC_CSET_LRU_GET_CACHE( lru );
|
||||
FT_Error error;
|
||||
FTC_ChunkSet cset;
|
||||
|
||||
|
||||
error = FTC_ChunkSet_New( cache,
|
||||
(FT_Pointer)node->key,
|
||||
&cset );
|
||||
FT_LruNode node;
|
||||
FT_Error error;
|
||||
|
||||
error = FT_LruList_Lookup( ccache->cset_lru, query, &node );
|
||||
if ( !error )
|
||||
{
|
||||
/* good, now set the set index within the set object */
|
||||
cset->cset_index = (FT_UInt)( node - lru->nodes );
|
||||
node->root.data = cset;
|
||||
FTC_ChunkSet cset = FTC_CHUNK_SET(node);
|
||||
FT_UFast hash = FTC_CSET_HASH( cset, query->gindex );
|
||||
|
||||
error = ftc_cache_lookup_node( FTC_CACHE(ccache), hash, query,
|
||||
FTC_NODE_P(anode) );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( void )
|
||||
ftc_chunk_set_lru_done( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
{
|
||||
FTC_ChunkSet cset = FTC_LRUNODE_CSET( node );
|
||||
|
||||
FT_UNUSED( lru );
|
||||
|
||||
|
||||
FTC_ChunkSet_Destroy( cset );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Bool )
|
||||
ftc_chunk_set_lru_compare( FT_LruNode node,
|
||||
FT_LruKey key )
|
||||
{
|
||||
FTC_ChunkSet cset = FTC_LRUNODE_CSET( node );
|
||||
|
||||
|
||||
return cset->clazz->compare( cset, (FT_Pointer)key );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FT_Lru_Class ftc_chunk_set_lru_class =
|
||||
{
|
||||
sizeof( FT_LruRec ),
|
||||
ftc_chunk_set_lru_init,
|
||||
ftc_chunk_set_lru_done,
|
||||
0, /* no flush */
|
||||
ftc_chunk_set_lru_compare
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** CHUNK CACHE OBJECTS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache )
|
||||
{
|
||||
FT_Memory memory = cache->root.memory;
|
||||
FT_Error error;
|
||||
|
||||
FTC_Chunk_Cache_Class* ccache_clazz;
|
||||
|
||||
|
||||
/* set up root node_class to be used by manager */
|
||||
cache->root.node_clazz =
|
||||
(FTC_CacheNode_Class*)&ftc_chunk_cache_node_class;
|
||||
|
||||
/* setup `compare' shortcut */
|
||||
ccache_clazz = (FTC_Chunk_Cache_Class*)cache->root.clazz;
|
||||
cache->compare = ccache_clazz->cset_class->compare;
|
||||
|
||||
error = FT_Lru_New( &ftc_chunk_set_lru_class,
|
||||
FTC_MAX_CHUNK_SETS,
|
||||
cache,
|
||||
memory,
|
||||
1, /* pre_alloc == TRUE */
|
||||
&cache->csets_lru );
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache )
|
||||
{
|
||||
/* discard glyph sets */
|
||||
FT_Lru_Done( cache->csets_lru );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache cache,
|
||||
FT_Pointer type,
|
||||
FT_UInt gindex,
|
||||
FTC_ChunkNode *anode,
|
||||
FT_UInt *aindex )
|
||||
{
|
||||
FT_Error error;
|
||||
FTC_ChunkSet cset;
|
||||
FTC_ChunkNode node;
|
||||
FT_UInt cindex;
|
||||
FTC_Manager manager;
|
||||
|
||||
|
||||
/* check for valid `desc' delayed to FT_Lru_Lookup() */
|
||||
|
||||
if ( !cache || !anode || !aindex )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
*anode = 0;
|
||||
*aindex = 0;
|
||||
cset = cache->last_cset;
|
||||
|
||||
if ( !cset || !cache->compare( cset, type ) )
|
||||
{
|
||||
error = FT_Lru_Lookup( cache->csets_lru,
|
||||
(FT_LruKey)type,
|
||||
(FT_Pointer*)&cset );
|
||||
cache->last_cset = cset;
|
||||
if ( error )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* now compress the manager's cache pool if needed */
|
||||
manager = cache->root.manager;
|
||||
if ( manager->num_bytes > manager->max_bytes )
|
||||
{
|
||||
FTC_ChunkNode_Ref ( node );
|
||||
FTC_Manager_Compress( manager );
|
||||
FTC_ChunkNode_Unref ( node );
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
*aindex = cindex;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
453
src/cache/ftcglyph.c
vendored
453
src/cache/ftcglyph.c
vendored
@ -35,21 +35,19 @@
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
#define FTC_GSET_HASH(gset,gindex) \
|
||||
((FT_UFast)(((gset)->hash << 16) | ((gindex) & 0xFFFF)))
|
||||
|
||||
|
||||
/* create a new glyph node, setting its cache index and ref count */
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_GlyphNode_Init( FTC_GlyphNode node,
|
||||
FTC_GlyphSet gset,
|
||||
FT_UInt gindex )
|
||||
ftc_glyph_node_init( FTC_GlyphNode gnode,
|
||||
FT_UInt gindex,
|
||||
FTC_GlyphSet gset )
|
||||
{
|
||||
FTC_Glyph_Cache cache = gset->cache;
|
||||
FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root );
|
||||
|
||||
|
||||
data->cache_index = (FT_UShort)cache->root.cache_index;
|
||||
data->ref_count = (FT_Short) 0;
|
||||
node->gset_index = (FT_UShort)gset->gset_index;
|
||||
node->glyph_index = (FT_UShort)gindex;
|
||||
gnode->gset = gset;
|
||||
gnode->node.hash = FTC_GSET_HASH( gset, gindex );
|
||||
gset->num_glyphs++;
|
||||
}
|
||||
|
||||
|
||||
@ -61,71 +59,15 @@
|
||||
/* will happen! */
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_GlyphNode_Destroy( FTC_GlyphNode node,
|
||||
FTC_Glyph_Cache cache )
|
||||
ftc_glyph_node_done( FTC_GlyphNode gnode )
|
||||
{
|
||||
FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index;
|
||||
FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data;
|
||||
FT_UInt hash = node->glyph_index % gset->hash_size;
|
||||
|
||||
|
||||
/* remove the node from its gset's bucket list */
|
||||
{
|
||||
FTC_GlyphNode* pnode = gset->buckets + hash;
|
||||
FTC_GlyphNode cur;
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
cur = *pnode;
|
||||
if ( !cur )
|
||||
{
|
||||
/* this should never happen */
|
||||
FT_ERROR(( "FTC_GlyphNode_Destroy:"
|
||||
" trying to delete an unlisted node!" ));
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cur == node )
|
||||
{
|
||||
*pnode = cur->gset_next;
|
||||
break;
|
||||
}
|
||||
pnode = &cur->gset_next;
|
||||
}
|
||||
}
|
||||
|
||||
/* destroy the node */
|
||||
gset->clazz->destroy_node( node, gset );
|
||||
FTC_GlyphSet gset = gnode->gset;
|
||||
|
||||
if ( --gset->num_glyphs <= 0 )
|
||||
FT_LruList_Remove( gset->gcache->gset_lru, (FT_LruNode) gset );
|
||||
}
|
||||
|
||||
|
||||
/* Important: This function is called from the cache manager to */
|
||||
/* size a given cache node during `cache compression'. The */
|
||||
/* second argument is always `cache.user_data'. Thus be */
|
||||
/* certain that the function FTC_Glyph_Cache_New() does indeed */
|
||||
/* set its `user_data' field correctly, otherwise bad things */
|
||||
/* will happen! */
|
||||
|
||||
FT_EXPORT_DEF( FT_ULong )
|
||||
FTC_GlyphNode_Size( FTC_GlyphNode node,
|
||||
FTC_Glyph_Cache cache )
|
||||
{
|
||||
FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index;
|
||||
FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data;
|
||||
|
||||
|
||||
return gset->clazz->size_node( node, gset );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_CacheNode_Class ftc_glyph_cache_node_class =
|
||||
{
|
||||
(FTC_CacheNode_SizeFunc) FTC_GlyphNode_Size,
|
||||
(FTC_CacheNode_DestroyFunc)FTC_GlyphNode_Destroy
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
@ -135,347 +77,88 @@
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_GlyphSet_New( FTC_Glyph_Cache cache,
|
||||
FT_Pointer type,
|
||||
FTC_GlyphSet *aset )
|
||||
ftc_glyph_set_init( FTC_GlyphSet gset,
|
||||
FT_LruList lru )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory = cache->root.memory;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FTC_GlyphSet gset = 0;
|
||||
|
||||
FTC_Glyph_Cache_Class* gcache_class;
|
||||
FTC_GlyphSet_Class* clazz;
|
||||
|
||||
|
||||
gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
|
||||
clazz = gcache_class->gset_class;
|
||||
|
||||
*aset = 0;
|
||||
|
||||
if ( ALLOC( gset, clazz->gset_byte_size ) )
|
||||
goto Exit;
|
||||
|
||||
gset->cache = cache;
|
||||
gset->manager = manager;
|
||||
gset->memory = memory;
|
||||
gset->hash_size = FTC_GSET_HASH_SIZE_DEFAULT;
|
||||
gset->clazz = clazz;
|
||||
|
||||
/* allocate buckets table */
|
||||
if ( ALLOC_ARRAY( gset->buckets, gset->hash_size, FTC_GlyphNode ) )
|
||||
goto Exit;
|
||||
|
||||
/* initialize gset by type if needed */
|
||||
if ( clazz->init )
|
||||
{
|
||||
error = clazz->init( gset, type );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
*aset = gset;
|
||||
|
||||
Exit:
|
||||
if ( error && gset )
|
||||
{
|
||||
FREE( gset->buckets );
|
||||
FREE( gset );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
FTC_GlyphCache gcache = lru->user_data;
|
||||
|
||||
gset->gcache = gcache;
|
||||
gset->num_glyphs = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_GlyphSet_Destroy( FTC_GlyphSet gset )
|
||||
ftc_glyph_set_done( FTC_GlyphSet gset )
|
||||
{
|
||||
FTC_Glyph_Cache cache = gset->cache;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FT_List glyphs_lru = &manager->global_lru;
|
||||
FTC_GlyphNode* bucket = gset->buckets;
|
||||
FTC_GlyphNode* bucket_limit = bucket + gset->hash_size;
|
||||
FT_Memory memory = cache->root.memory;
|
||||
|
||||
FTC_GlyphSet_Class* clazz = gset->clazz;
|
||||
/* for now, nothing to be done here */
|
||||
FT_UNUSED(gset);
|
||||
}
|
||||
|
||||
|
||||
/* for each bucket, free the list of glyph nodes */
|
||||
for ( ; bucket < bucket_limit; bucket++ )
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH CACHES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
ftc_glyph_cache_done( FTC_GlyphCache gcache )
|
||||
{
|
||||
/* remove all nodes in the cache */
|
||||
ftc_cache_done( &gcache->cache );
|
||||
|
||||
/* simply delete all remaining glyph sets */
|
||||
if ( gcache->gset_lru )
|
||||
{
|
||||
FTC_GlyphNode node = bucket[0];
|
||||
FTC_GlyphNode next = 0;
|
||||
FT_ListNode lrunode;
|
||||
|
||||
|
||||
for ( ; node; node = next )
|
||||
{
|
||||
next = node->gset_next;
|
||||
lrunode = FTC_GLYPHNODE_TO_LRUNODE( node );
|
||||
|
||||
manager->num_bytes -= clazz->size_node( node, gset );
|
||||
manager->num_nodes--;
|
||||
|
||||
FT_List_Remove( glyphs_lru, lrunode );
|
||||
|
||||
clazz->destroy_node( node, gset );
|
||||
}
|
||||
|
||||
bucket[0] = 0;
|
||||
FT_LruList_Destroy( gcache->gset_lru );
|
||||
gcache->gset_lru = NULL;
|
||||
}
|
||||
|
||||
if ( clazz->done )
|
||||
clazz->done( gset );
|
||||
|
||||
FREE( gset->buckets );
|
||||
FREE( gset );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
|
||||
FT_UInt glyph_index,
|
||||
FTC_GlyphNode *anode )
|
||||
ftc_glyph_cache_init( FTC_GlyphCache gcache,
|
||||
FT_LruList_Class gset_class )
|
||||
{
|
||||
FTC_Glyph_Cache cache = gset->cache;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FT_UInt hash_index = glyph_index % gset->hash_size;
|
||||
FTC_GlyphNode* bucket = gset->buckets + hash_index;
|
||||
FTC_GlyphNode* pnode = bucket;
|
||||
FTC_GlyphNode node;
|
||||
FT_Error error;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH SETS LRU CALLBACKS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
#define FTC_GSET_LRU_GET_CACHE( lru ) \
|
||||
( (FTC_Glyph_Cache)(lru)->user_data )
|
||||
|
||||
#define FTC_GSET_LRU_GET_MANAGER( lru ) \
|
||||
FTC_GSET_LRU_GET_CACHE( lru )->manager
|
||||
|
||||
#define FTC_LRUNODE_GSET( node ) \
|
||||
( (FTC_GlyphSet)(node)->root.data )
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_glyph_set_lru_init( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
ftc_glyph_cache_lookup( FTC_GlyphCache gcache,
|
||||
FTC_GlyphQuery query,
|
||||
FTC_GlyphNode *anode )
|
||||
{
|
||||
FTC_Glyph_Cache cache = FTC_GSET_LRU_GET_CACHE( lru );
|
||||
FT_Error error;
|
||||
FTC_GlyphSet gset;
|
||||
|
||||
|
||||
error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset );
|
||||
FT_LruNode node;
|
||||
FT_Error error;
|
||||
|
||||
error = FT_LruList_Lookup( gcache->gset_lru, query, &node );
|
||||
if ( !error )
|
||||
{
|
||||
/* good, now set the gset index within the gset object */
|
||||
gset->gset_index = (FT_UInt)( node - lru->nodes );
|
||||
node->root.data = gset;
|
||||
FTC_GlyphSet gset = (FTC_GlyphSet) node;
|
||||
FT_UFast hash = FTC_GSET_HASH( gset, query->gindex );
|
||||
|
||||
error = ftc_cache_lookup_node( FTC_CACHE(gcache), hash, query,
|
||||
FTC_NODE_P(anode) );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( void )
|
||||
ftc_glyph_set_lru_done( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
{
|
||||
FTC_GlyphSet gset = FTC_LRUNODE_GSET( node );
|
||||
|
||||
FT_UNUSED( lru );
|
||||
|
||||
|
||||
FTC_GlyphSet_Destroy( gset );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Bool )
|
||||
ftc_glyph_set_lru_compare( FT_LruNode node,
|
||||
FT_LruKey key )
|
||||
{
|
||||
FTC_GlyphSet gset = FTC_LRUNODE_GSET( node );
|
||||
|
||||
|
||||
return gset->clazz->compare( gset, (FT_Pointer)key );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FT_Lru_Class ftc_glyph_set_lru_class =
|
||||
{
|
||||
sizeof( FT_LruRec ),
|
||||
ftc_glyph_set_lru_init,
|
||||
ftc_glyph_set_lru_done,
|
||||
0, /* no flush */
|
||||
ftc_glyph_set_lru_compare
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH CACHE OBJECTS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache )
|
||||
{
|
||||
FT_Memory memory = cache->root.memory;
|
||||
FT_Error error;
|
||||
|
||||
FTC_Glyph_Cache_Class* gcache_clazz;
|
||||
|
||||
|
||||
/* set up root node_class to be used by manager */
|
||||
cache->root.node_clazz =
|
||||
(FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
|
||||
|
||||
/* setup the `compare' shortcut */
|
||||
gcache_clazz = (FTC_Glyph_Cache_Class*)cache->root.clazz;
|
||||
cache->compare = gcache_clazz->gset_class->compare;
|
||||
|
||||
/* The following is extremely important for ftc_destroy_glyph_image() */
|
||||
/* to work properly, as the second parameter that is sent to it */
|
||||
/* through the cache manager is `cache_data' and must be set to */
|
||||
/* `cache' here. */
|
||||
/* */
|
||||
cache->root.cache_data = cache;
|
||||
|
||||
error = FT_Lru_New( &ftc_glyph_set_lru_class,
|
||||
FTC_MAX_GLYPH_SETS,
|
||||
cache,
|
||||
memory,
|
||||
1, /* pre_alloc == TRUE */
|
||||
&cache->gsets_lru );
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache )
|
||||
{
|
||||
/* discard glyph sets */
|
||||
FT_Lru_Done( cache->gsets_lru );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache cache,
|
||||
FT_Pointer type,
|
||||
FT_UInt gindex,
|
||||
FTC_GlyphNode *anode )
|
||||
{
|
||||
FT_Error error;
|
||||
FTC_GlyphSet gset;
|
||||
FTC_GlyphNode node;
|
||||
FTC_Manager manager;
|
||||
|
||||
|
||||
/* check for valid `desc' delayed to FT_Lru_Lookup() */
|
||||
|
||||
if ( !cache || !anode )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
*anode = 0;
|
||||
gset = cache->last_gset;
|
||||
|
||||
if ( !gset || !cache->compare( gset, type ) )
|
||||
{
|
||||
error = FT_Lru_Lookup( cache->gsets_lru,
|
||||
(FT_LruKey)type,
|
||||
(FT_Pointer*)&gset );
|
||||
cache->last_gset = gset;
|
||||
if ( error )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
error = FTC_GlyphSet_Lookup_Node( gset, gindex, &node );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* now compress the manager's cache pool if needed */
|
||||
manager = cache->root.manager;
|
||||
if ( manager->num_bytes > manager->max_bytes )
|
||||
{
|
||||
FTC_GlyphNode_Ref ( node );
|
||||
FTC_Manager_Compress( manager );
|
||||
FTC_GlyphNode_Unref ( node );
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* END */
|
||||
|
252
src/cache/ftcimage.c
vendored
252
src/cache/ftcimage.c
vendored
@ -19,6 +19,7 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_CACHE_H
|
||||
#include FT_CACHE_IMAGE_H
|
||||
#include FT_CACHE_INTERNAL_GLYPH_H
|
||||
#include FT_INTERNAL_MEMORY_H
|
||||
|
||||
#include "ftcerror.h"
|
||||
@ -27,30 +28,36 @@
|
||||
#include <stdlib.h> /* labs() */
|
||||
|
||||
|
||||
/* the FT_Glyph image `glyph node' type */
|
||||
typedef struct FTC_GlyphImageRec_
|
||||
/* the FT_Glyph image node type */
|
||||
typedef struct FTC_ImageNodeRec_
|
||||
{
|
||||
FTC_GlyphNodeRec root;
|
||||
FT_Glyph ft_glyph;
|
||||
FTC_GlyphNodeRec gnode;
|
||||
FT_Glyph glyph;
|
||||
|
||||
} FTC_GlyphImageRec, *FTC_GlyphImage;
|
||||
} FTC_ImageNodeRec, *FTC_ImageNode;
|
||||
|
||||
#define FTC_IMAGE_NODE(x) ((FTC_ImageNode)(x))
|
||||
#define FTC_IMAGE_NODE_GINDEX(x) FTC_GLYPH_NODE_GINDEX(x)
|
||||
|
||||
/* the glyph image queue type */
|
||||
/* the glyph image set type */
|
||||
typedef struct FTC_ImageSetRec_
|
||||
{
|
||||
FTC_GlyphSetRec root;
|
||||
FTC_GlyphSetRec gset;
|
||||
FTC_Image_Desc description;
|
||||
|
||||
} FTC_ImageSetRec, *FTC_ImageSet;
|
||||
|
||||
#define FTC_IMAGE_SET(x) ((FTC_ImageSet)(x))
|
||||
|
||||
typedef struct FTC_Image_CacheRec_
|
||||
#define FTC_IMAGE_SET_MEMORY(x) FTC_GLYPH_SET_MEMORY(&(x)->gset)
|
||||
|
||||
|
||||
typedef struct FTC_ImageQueryRec_
|
||||
{
|
||||
FTC_Glyph_CacheRec root;
|
||||
|
||||
} FTC_Image_CacheRec;
|
||||
|
||||
FTC_GlyphQueryRec glyph;
|
||||
FTC_Image_Desc desc;
|
||||
|
||||
} FTC_ImageQueryRec, *FTC_ImageQuery;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
@ -62,47 +69,41 @@
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
/* finalize a given glyph image node */
|
||||
FT_CALLBACK_DEF( void )
|
||||
ftc_glyph_image_node_destroy( FTC_GlyphImage node,
|
||||
FTC_GlyphSet gset )
|
||||
ftc_image_node_done( FTC_ImageNode inode )
|
||||
{
|
||||
FT_Memory memory = gset->memory;
|
||||
|
||||
|
||||
FT_Done_Glyph( node->ft_glyph );
|
||||
FREE( node );
|
||||
if (inode->glyph)
|
||||
{
|
||||
FT_Done_Glyph( inode->glyph );
|
||||
inode->glyph = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* initialize a new glyph image node */
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_glyph_image_node_new( FTC_GlyphSet gset,
|
||||
FT_UInt glyph_index,
|
||||
FTC_GlyphImage *anode )
|
||||
ftc_image_node_init( FTC_ImageNode inode,
|
||||
FTC_GlyphQuery query )
|
||||
{
|
||||
FT_Memory memory = gset->memory;
|
||||
FTC_ImageSet imageset = (FTC_ImageSet)gset;
|
||||
FTC_ImageSet iset = FTC_IMAGE_SET( query->gset );
|
||||
FT_Memory memory = FTC_IMAGE_SET_MEMORY( iset );
|
||||
FT_Error error;
|
||||
FTC_GlyphImage node = 0;
|
||||
FT_Face face;
|
||||
FT_Size size;
|
||||
|
||||
|
||||
/* allocate node */
|
||||
if ( ALLOC( node, sizeof ( *node ) ) )
|
||||
goto Exit;
|
||||
|
||||
/* initialize its inner fields */
|
||||
FTC_GlyphNode_Init( FTC_GLYPHNODE( node ), gset, glyph_index );
|
||||
ftc_glyph_node_init( FTC_GLYPH_NODE(inode), query->gindex, query->gset );
|
||||
|
||||
/* we will now load the glyph image */
|
||||
error = FTC_Manager_Lookup_Size( gset->manager,
|
||||
&imageset->description.font,
|
||||
error = FTC_Manager_Lookup_Size( iset->gset.gcache->cache.manager,
|
||||
&iset->description.font,
|
||||
&face, &size );
|
||||
if ( !error )
|
||||
{
|
||||
FT_UInt gindex = node->root.glyph_index;
|
||||
FT_UInt gindex = FTC_GLYPH_NODE_GINDEX(inode);
|
||||
FT_UInt load_flags = FT_LOAD_DEFAULT;
|
||||
FT_UInt image_type = imageset->description.image_type;
|
||||
FT_UInt image_type = iset->description.image_type;
|
||||
|
||||
|
||||
if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
|
||||
@ -142,31 +143,29 @@
|
||||
|
||||
error = FT_Get_Glyph( face->glyph, &glyph );
|
||||
if ( !error )
|
||||
node->ft_glyph = glyph;
|
||||
{
|
||||
inode->glyph = glyph;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
error = FTC_Err_Invalid_Argument;
|
||||
}
|
||||
}
|
||||
|
||||
/* in case of error */
|
||||
ftc_glyph_node_done( FTC_GLYPH_NODE(inode) );
|
||||
|
||||
Exit:
|
||||
if ( error && node )
|
||||
FREE( node );
|
||||
|
||||
*anode = node;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* this function is important because it is both part of */
|
||||
/* an FTC_GlyphSet_Class and an FTC_CacheNode_Class */
|
||||
/* */
|
||||
FT_CALLBACK_DEF( FT_ULong )
|
||||
ftc_glyph_image_node_size( FTC_GlyphImage node )
|
||||
ftc_image_node_weight( FTC_ImageNode inode )
|
||||
{
|
||||
FT_ULong size = 0;
|
||||
FT_Glyph glyph = node->ft_glyph;
|
||||
|
||||
FT_Glyph glyph = inode->glyph;
|
||||
|
||||
switch ( glyph->format )
|
||||
{
|
||||
@ -198,11 +197,27 @@
|
||||
;
|
||||
}
|
||||
|
||||
size += sizeof ( *node );
|
||||
size += sizeof ( *inode );
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/* this function assumes that the desired node's glyph set has been */
|
||||
/* set by a previous call to ftc_image_set_compare.. */
|
||||
/* */
|
||||
FT_CALLBACK_DEF( FT_Bool )
|
||||
ftc_image_node_compare( FTC_ImageNode inode,
|
||||
FTC_ImageQuery iquery )
|
||||
{
|
||||
FTC_ImageSet iset = FTC_IMAGE_SET(inode->gnode.gset);
|
||||
|
||||
/* only if same glyph index and image set description */
|
||||
return FT_BOOL( iquery->glyph.gindex == FTC_IMAGE_NODE_GINDEX(inode) &&
|
||||
iquery->glyph.gset == inode->gnode.gset );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
@ -214,33 +229,47 @@
|
||||
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_image_set_init( FTC_ImageSet iset,
|
||||
FTC_Image_Desc* type )
|
||||
FTC_ImageQuery query,
|
||||
FT_LruList lru )
|
||||
{
|
||||
iset->description = *type;
|
||||
ftc_glyph_set_init( &iset->gset, lru );
|
||||
iset->description = query->desc;
|
||||
|
||||
/* now compute hash from description - this is _very_ important */
|
||||
iset->gset.hash = FTC_IMAGE_DESC_HASH(&query->desc);
|
||||
query->glyph.gset = FTC_GLYPH_SET(iset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Bool )
|
||||
ftc_image_set_compare( FTC_ImageSet iset,
|
||||
FTC_Image_Desc* type )
|
||||
ftc_image_set_compare( FTC_ImageSet iset,
|
||||
FTC_ImageQuery iquery )
|
||||
{
|
||||
return FT_BOOL( !memcmp( &iset->description, type, sizeof ( *type ) ) );
|
||||
FT_Bool result;
|
||||
|
||||
/* we must set iquery.glyph.gset for faster glyph node comparisons */
|
||||
result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &iset->description, &iquery->desc ) );
|
||||
if ( result )
|
||||
iquery->glyph.gset = &iset->gset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_GlyphSet_Class ftc_glyph_image_set_class =
|
||||
const FT_LruList_ClassRec ftc_image_set_class =
|
||||
{
|
||||
sizeof( FT_LruListRec ),
|
||||
(FT_LruList_InitFunc) NULL,
|
||||
(FT_LruList_DoneFunc) NULL,
|
||||
|
||||
sizeof( FTC_ImageSetRec ),
|
||||
|
||||
(FTC_GlyphSet_InitFunc) ftc_image_set_init,
|
||||
(FTC_GlyphSet_DoneFunc) 0,
|
||||
(FTC_GlyphSet_CompareFunc) ftc_image_set_compare,
|
||||
|
||||
(FTC_GlyphSet_NewNodeFunc) ftc_glyph_image_node_new,
|
||||
(FTC_GlyphSet_SizeNodeFunc) ftc_glyph_image_node_size,
|
||||
(FTC_GlyphSet_DestroyNodeFunc)ftc_glyph_image_node_destroy
|
||||
(FT_LruNode_InitFunc) ftc_image_set_init,
|
||||
(FT_LruNode_DoneFunc) ftc_glyph_set_init,
|
||||
(FT_LruNode_FlushFunc) NULL,
|
||||
(FT_LruNode_CompareFunc) ftc_image_set_compare
|
||||
};
|
||||
|
||||
|
||||
@ -253,15 +282,25 @@
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_Glyph_Cache_Class ftc_glyph_image_cache_class =
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_image_cache_init( FTC_Image_Cache cache )
|
||||
{
|
||||
{
|
||||
sizeof( FTC_Image_CacheRec ),
|
||||
(FTC_Cache_InitFunc) FTC_Glyph_Cache_Init,
|
||||
(FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done
|
||||
},
|
||||
(FTC_GlyphSet_Class*) &ftc_glyph_image_set_class
|
||||
return ftc_glyph_cache_init( (FTC_GlyphCache) cache, &ftc_image_set_class );
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_Cache_ClassRec ftc_image_cache_class =
|
||||
{
|
||||
sizeof( FTC_GlyphCacheRec ),
|
||||
(FTC_Cache_InitFunc) ftc_image_cache_init,
|
||||
(FTC_Cache_DoneFunc) ftc_glyph_cache_done,
|
||||
|
||||
sizeof( FTC_ImageNodeRec ),
|
||||
(FTC_Node_InitFunc) ftc_image_node_init,
|
||||
(FTC_Node_WeightFunc) ftc_image_node_weight,
|
||||
(FTC_Node_CompareFunc) ftc_image_node_compare,
|
||||
(FTC_Node_DoneFunc) ftc_image_node_done
|
||||
};
|
||||
|
||||
|
||||
@ -273,36 +312,73 @@
|
||||
{
|
||||
return FTC_Manager_Register_Cache(
|
||||
manager,
|
||||
(FTC_Cache_Class*)&ftc_glyph_image_cache_class,
|
||||
(FTC_Cache*)acache );
|
||||
(FTC_Cache_Class) &ftc_image_cache_class,
|
||||
FTC_CACHE_P(acache) );
|
||||
}
|
||||
|
||||
|
||||
/* documentation is in ftcimage.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_Image_Cache_Lookup( FTC_Image_Cache cache,
|
||||
FTC_Image_Cache_Acquire( FTC_Image_Cache cache,
|
||||
FTC_Image_Desc* desc,
|
||||
FT_UInt gindex,
|
||||
FT_Glyph *aglyph,
|
||||
FTC_Node *anode )
|
||||
{
|
||||
FTC_ImageQueryRec query;
|
||||
FTC_ImageNode node;
|
||||
FT_Error error;
|
||||
|
||||
/* some argument checks are delayed to ftc_glyph_cache_lookup */
|
||||
if ( !cache || !desc || !aglyph )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
*aglyph = NULL;
|
||||
|
||||
if ( anode )
|
||||
*anode = NULL;
|
||||
|
||||
query.glyph.gindex = gindex;
|
||||
query.glyph.gset = NULL;
|
||||
query.desc = *desc;
|
||||
error = ftc_glyph_cache_lookup( FTC_GLYPH_CACHE(cache),
|
||||
&query.glyph,
|
||||
(FTC_GlyphNode*) &node );
|
||||
if (!error)
|
||||
{
|
||||
*aglyph = node->glyph;
|
||||
|
||||
if (anode)
|
||||
{
|
||||
*anode = (FTC_Node) node;
|
||||
FTC_NODE(node)->ref_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FTC_Image_Cache_Release( FTC_Image_Cache icache,
|
||||
FTC_Node node )
|
||||
{
|
||||
ftc_node_unref( node, FTC_CACHE(icache) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FTC_Image_Cache_Lookup( FTC_Image_Cache icache,
|
||||
FTC_Image_Desc* desc,
|
||||
FT_UInt gindex,
|
||||
FT_Glyph *aglyph )
|
||||
{
|
||||
FT_Error error;
|
||||
FTC_GlyphNode node;
|
||||
|
||||
|
||||
/* some argument checks are delayed to FTC_Glyph_Cache_Lookup */
|
||||
|
||||
if ( !aglyph )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
error = FTC_Glyph_Cache_Lookup( (FTC_Glyph_Cache)cache,
|
||||
desc, gindex, &node );
|
||||
|
||||
if ( !error )
|
||||
*aglyph = ((FTC_GlyphImage)node)->ft_glyph;
|
||||
|
||||
return error;
|
||||
return FTC_Image_Cache_Acquire( icache, desc, gindex, aglyph, NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* END */
|
||||
|
895
src/cache/ftcmanag.c
vendored
895
src/cache/ftcmanag.c
vendored
File diff suppressed because it is too large
Load Diff
404
src/cache/ftcsbits.c
vendored
404
src/cache/ftcsbits.c
vendored
@ -19,6 +19,7 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_CACHE_H
|
||||
#include FT_CACHE_SMALL_BITMAPS_H
|
||||
#include FT_CACHE_INTERNAL_CHUNK_H
|
||||
#include FT_INTERNAL_OBJECTS_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
#include FT_ERRORS_H
|
||||
@ -28,23 +29,31 @@
|
||||
#include <string.h> /* memcmp() */
|
||||
|
||||
|
||||
#define FTC_SBITSET_ELEMENT_COUNT 16
|
||||
#define FTC_SBIT_ITEMS_PER_NODE 16
|
||||
|
||||
|
||||
/* handle to sbit set */
|
||||
typedef struct FTC_SBitSetRec_* FTC_SBitSet;
|
||||
|
||||
/* sbit set structure */
|
||||
typedef struct FTC_SBitSetRec_
|
||||
{
|
||||
FTC_ChunkSetRec root;
|
||||
FTC_ChunkSetRec cset;
|
||||
FTC_Image_Desc desc;
|
||||
|
||||
} FTC_SBitSetRec, *FTC_SBitSet;
|
||||
} FTC_SBitSetRec;
|
||||
|
||||
#define FTC_SBIT_SET(x) ((FTC_SBitSet)(x))
|
||||
|
||||
#define FTC_SBIT_SET_MEMORY(x) FTC_CHUNK_SET_MEMORY(&(x)->cset)
|
||||
|
||||
|
||||
typedef struct FTC_SBit_CacheRec_
|
||||
typedef struct FTC_SBitQueryRec_
|
||||
{
|
||||
FTC_Chunk_CacheRec root;
|
||||
|
||||
} FTC_SBit_CacheRec;
|
||||
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;
|
||||
|
||||
error = FT_Load_Glyph( face, gindex, load_flags );
|
||||
if ( !error )
|
||||
{
|
||||
/* by default, indicates a `missing' glyph */
|
||||
sbit->buffer = 0;
|
||||
|
||||
error = FT_Load_Glyph( face, glyph_index, load_flags );
|
||||
if ( !error )
|
||||
{
|
||||
FT_Int temp;
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
FT_Bitmap* bitmap = &slot->bitmap;
|
||||
FT_Int xadvance, yadvance;
|
||||
FT_Int temp;
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
FT_Bitmap* bitmap = &slot->bitmap;
|
||||
FT_Int xadvance, yadvance;
|
||||
|
||||
|
||||
/* check that our values fit into 8-bit containers! */
|
||||
/* If this is not the case, our bitmap is too large */
|
||||
/* and we will leave it as `missing' with sbit.buffer = 0 */
|
||||
/* check that our values fit into 8-bit containers! */
|
||||
/* If this is not the case, our bitmap is too large */
|
||||
/* and we will leave it as `missing' with sbit.buffer = 0 */
|
||||
|
||||
#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
|
||||
#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
|
||||
|
||||
/* XXX: FIXME: add support for vertical layouts maybe */
|
||||
/* XXX: FIXME: add support for vertical layouts maybe */
|
||||
|
||||
/* horizontal advance in pixels */
|
||||
xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
|
||||
yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
|
||||
/* horizontal advance in pixels */
|
||||
xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
|
||||
yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
|
||||
|
||||
if ( CHECK_BYTE( bitmap->rows ) &&
|
||||
CHECK_BYTE( bitmap->width ) &&
|
||||
CHECK_CHAR( bitmap->pitch ) &&
|
||||
CHECK_CHAR( slot->bitmap_left ) &&
|
||||
CHECK_CHAR( slot->bitmap_top ) &&
|
||||
CHECK_CHAR( xadvance ) &&
|
||||
CHECK_CHAR( yadvance ) )
|
||||
if ( CHECK_BYTE( bitmap->rows ) &&
|
||||
CHECK_BYTE( bitmap->width ) &&
|
||||
CHECK_CHAR( bitmap->pitch ) &&
|
||||
CHECK_CHAR( slot->bitmap_left ) &&
|
||||
CHECK_CHAR( slot->bitmap_top ) &&
|
||||
CHECK_CHAR( xadvance ) &&
|
||||
CHECK_CHAR( yadvance ) )
|
||||
{
|
||||
sbit->width = (FT_Byte) bitmap->width;
|
||||
sbit->height = (FT_Byte) bitmap->rows;
|
||||
sbit->pitch = (FT_Char) bitmap->pitch;
|
||||
sbit->left = (FT_Char) slot->bitmap_left;
|
||||
sbit->top = (FT_Char) slot->bitmap_top;
|
||||
sbit->xadvance = (FT_Char) xadvance;
|
||||
sbit->yadvance = (FT_Char) yadvance;
|
||||
sbit->format = (FT_Byte) bitmap->pixel_mode;
|
||||
|
||||
/* grab the bitmap when possible - this is a hack !! */
|
||||
if ( slot->flags & ft_glyph_own_bitmap )
|
||||
{
|
||||
sbit->width = (FT_Byte)bitmap->width;
|
||||
sbit->height = (FT_Byte)bitmap->rows;
|
||||
sbit->pitch = (FT_Char)bitmap->pitch;
|
||||
sbit->left = (FT_Char)slot->bitmap_left;
|
||||
sbit->top = (FT_Char)slot->bitmap_top;
|
||||
sbit->xadvance = (FT_Char)xadvance;
|
||||
sbit->yadvance = (FT_Char)yadvance;
|
||||
sbit->format = (FT_Byte)bitmap->pixel_mode;
|
||||
|
||||
/* grab the bitmap when possible */
|
||||
if ( slot->flags & ft_glyph_own_bitmap )
|
||||
{
|
||||
slot->flags &= ~ft_glyph_own_bitmap;
|
||||
sbit->buffer = bitmap->buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* copy the bitmap into a new buffer -- ignore error */
|
||||
ftc_bitmap_copy( memory, bitmap, sbit );
|
||||
}
|
||||
slot->flags &= ~ft_glyph_own_bitmap;
|
||||
sbit->buffer = bitmap->buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* copy the bitmap into a new buffer -- ignore error */
|
||||
error = ftc_sbit_set_bitmap( sbit, bitmap, memory );
|
||||
}
|
||||
|
||||
/* now, compute size */
|
||||
if ( asize )
|
||||
*asize = sizeof( FTC_SBitRec ) + ABS(sbit->pitch) * sbit->height;
|
||||
|
||||
} /* glyph dimensions ok */
|
||||
|
||||
} /* glyph loading successful */
|
||||
|
||||
/* ignore the errors that might have occurred -- */
|
||||
/* we recognize unloaded glyphs with `sbit.buffer == 0' */
|
||||
error = 0;
|
||||
/* and 'width == 255', 'height == 0' */
|
||||
/* */
|
||||
if ( error )
|
||||
{
|
||||
sbit->width = 255;
|
||||
error = 0;
|
||||
/* sbit->buffer == NULL too !! */
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
if ( error && node )
|
||||
{
|
||||
FREE( node->elements );
|
||||
FREE( node );
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_sbit_node_init( FTC_ChunkNode cnode,
|
||||
FTC_ChunkQuery query )
|
||||
{
|
||||
FT_Error error;
|
||||
|
||||
error = ftc_chunk_node_init( cnode,
|
||||
query->cset,
|
||||
query->gindex,
|
||||
TRUE );
|
||||
if ( !error )
|
||||
{
|
||||
error = ftc_sbit_node_load( cnode, query->gindex, NULL );
|
||||
|
||||
if ( error )
|
||||
ftc_chunk_node_done( cnode );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* this function is important because it is both part of */
|
||||
/* an FTC_ChunkSet_Class and an FTC_CacheNode_Class */
|
||||
/* */
|
||||
FT_CALLBACK_DEF( FT_ULong )
|
||||
ftc_sbit_chunk_node_size( FTC_ChunkNode node )
|
||||
ftc_sbit_node_weight( FTC_ChunkNode cnode )
|
||||
{
|
||||
FT_ULong size;
|
||||
FTC_ChunkSet cset = node->cset;
|
||||
FT_UInt count = node->num_elements;
|
||||
FTC_ChunkSet cset = cnode->cset;
|
||||
FT_UInt count = cnode->item_count;
|
||||
FT_Int pitch;
|
||||
FTC_SBit sbit = (FTC_SBit)node->elements;
|
||||
FTC_SBit sbit = (FTC_SBit) cnode->items;
|
||||
|
||||
|
||||
/* the node itself */
|
||||
size = sizeof ( *node );
|
||||
size = sizeof ( *cnode );
|
||||
|
||||
/* the sbit records */
|
||||
size += cset->element_count * sizeof ( FTC_SBitRec );
|
||||
size += cnode->item_count * sizeof ( FTC_SBitRec );
|
||||
|
||||
for ( ; count > 0; count--, sbit++ )
|
||||
{
|
||||
@ -273,6 +307,34 @@
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Bool )
|
||||
ftc_sbit_node_compare( FTC_ChunkNode cnode,
|
||||
FTC_SBitQuery query,
|
||||
FTC_Cache cache )
|
||||
{
|
||||
FTC_ChunkQuery creq = &query->chunk;
|
||||
FT_UInt gindex = query->chunk.gindex;
|
||||
FT_UInt offset = (FT_UInt)(gindex - cnode->item_start);
|
||||
FT_Bool result;
|
||||
|
||||
result = FT_BOOL( offset < (FT_UInt)cnode->item_count &&
|
||||
creq->cset == cnode->cset );
|
||||
if ( result )
|
||||
{
|
||||
/* check if we need to load the glyph bitmap now */
|
||||
FTC_SBit sbit = (FTC_SBit)cnode->items + offset;
|
||||
|
||||
if ( sbit->buffer == NULL && sbit->width != 255 )
|
||||
{
|
||||
FT_ULong size;
|
||||
ftc_sbit_node_load( cnode, gindex, &size );
|
||||
cache->manager->cur_weight += size;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
@ -283,60 +345,74 @@
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_sbit_chunk_set_sizes( FTC_ChunkSet cset,
|
||||
FTC_Image_Desc* desc )
|
||||
ftc_sbit_set_init( FTC_SBitSet sset,
|
||||
FTC_SBitQuery query,
|
||||
FT_LruList lru )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Face face;
|
||||
FTC_ChunkCache ccache = lru->user_data;
|
||||
FTC_Manager manager = ccache->cache.manager;
|
||||
FT_Error error;
|
||||
FT_Face face;
|
||||
|
||||
sset->desc = query->desc;
|
||||
|
||||
cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
|
||||
cset->element_size = sizeof ( FTC_SBitRec );
|
||||
|
||||
/* lookup the FT_Face to obtain the number of glyphs */
|
||||
error = FTC_Manager_Lookup_Face( cset->manager,
|
||||
desc->font.face_id, &face );
|
||||
/* we need to compute "cquery.item_total" now */
|
||||
error = FTC_Manager_Lookup_Face( manager,
|
||||
query->desc.font.face_id,
|
||||
&face );
|
||||
if ( !error )
|
||||
cset->element_max = face->num_glyphs;
|
||||
{
|
||||
ftc_chunk_set_init( FTC_CHUNK_SET(sset),
|
||||
sizeof( FTC_SBitRec ),
|
||||
FTC_SBIT_ITEMS_PER_NODE,
|
||||
face->num_glyphs,
|
||||
FTC_CHUNK_CACHE(lru->user_data) );
|
||||
|
||||
/* now compute hash from description - this is _very_ important */
|
||||
/* for good performance.. */
|
||||
sset->cset.hash = FTC_IMAGE_DESC_HASH( &sset->desc );
|
||||
query->chunk.cset = &sset->cset;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_sbit_chunk_set_init( FTC_SBitSet sset,
|
||||
FTC_Image_Desc* type )
|
||||
{
|
||||
sset->desc = *type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( FT_Bool )
|
||||
ftc_sbit_chunk_set_compare( FTC_SBitSet sset,
|
||||
FTC_Image_Desc* type )
|
||||
ftc_sbit_set_compare( FTC_SBitSet sset,
|
||||
FTC_SBitQuery query )
|
||||
{
|
||||
return FT_BOOL( !memcmp( &sset->desc, type, sizeof ( *type ) ) );
|
||||
FT_Bool result;
|
||||
|
||||
/* we need to set the "cquery.cset" field or our query for */
|
||||
/* faster glyph comparisons in ftc_sbit_node_compare.. */
|
||||
/* */
|
||||
result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &sset->desc, &query->desc ) );
|
||||
if ( result )
|
||||
query->chunk.cset = &sset->cset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_ChunkSet_Class ftc_sbit_chunk_set_class =
|
||||
const FT_LruList_ClassRec ftc_sbit_set_class =
|
||||
{
|
||||
sizeof( FT_LruListRec ),
|
||||
(FT_LruList_InitFunc) NULL,
|
||||
(FT_LruList_DoneFunc) NULL,
|
||||
|
||||
sizeof( FTC_SBitSetRec ),
|
||||
|
||||
(FTC_ChunkSet_InitFunc) ftc_sbit_chunk_set_init,
|
||||
(FTC_ChunkSet_DoneFunc) 0,
|
||||
(FTC_ChunkSet_CompareFunc) ftc_sbit_chunk_set_compare,
|
||||
(FTC_ChunkSet_SizesFunc) ftc_sbit_chunk_set_sizes,
|
||||
|
||||
(FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new,
|
||||
(FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size,
|
||||
(FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy
|
||||
(FT_LruNode_InitFunc) ftc_sbit_set_init,
|
||||
(FT_LruNode_DoneFunc) ftc_chunk_set_done,
|
||||
(FT_LruNode_FlushFunc) NULL,
|
||||
(FT_LruNode_CompareFunc) ftc_sbit_set_compare,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
@ -346,15 +422,25 @@
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_Chunk_Cache_Class ftc_sbit_cache_class =
|
||||
FT_CALLBACK_DEF( FT_Error )
|
||||
ftc_sbit_cache_init( FTC_SBit_Cache scache )
|
||||
{
|
||||
{
|
||||
sizeof( FTC_SBit_CacheRec ),
|
||||
(FTC_Cache_InitFunc)FTC_Chunk_Cache_Init,
|
||||
(FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done
|
||||
},
|
||||
(FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class
|
||||
return ftc_chunk_cache_init( FTC_CHUNK_CACHE(scache),
|
||||
&ftc_sbit_set_class );
|
||||
}
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const FTC_Cache_ClassRec ftc_sbit_cache_class =
|
||||
{
|
||||
sizeof( FTC_ChunkCacheRec ),
|
||||
(FTC_Cache_InitFunc) ftc_sbit_cache_init,
|
||||
(FTC_Cache_DoneFunc) ftc_chunk_cache_done,
|
||||
|
||||
sizeof( FTC_ChunkNodeRec ),
|
||||
(FTC_Node_InitFunc) ftc_sbit_node_init,
|
||||
(FTC_Node_WeightFunc) ftc_sbit_node_weight,
|
||||
(FTC_Node_CompareFunc) ftc_sbit_node_compare,
|
||||
(FTC_Node_DoneFunc) ftc_sbit_node_done
|
||||
};
|
||||
|
||||
|
||||
@ -366,8 +452,8 @@
|
||||
{
|
||||
return FTC_Manager_Register_Cache(
|
||||
manager,
|
||||
(FTC_Cache_Class*)&ftc_sbit_cache_class,
|
||||
(FTC_Cache*)acache );
|
||||
&ftc_sbit_cache_class,
|
||||
(FTC_Cache*) acache );
|
||||
}
|
||||
|
||||
|
||||
@ -379,21 +465,27 @@
|
||||
FT_UInt gindex,
|
||||
FTC_SBit *ansbit )
|
||||
{
|
||||
FT_Error error;
|
||||
FTC_ChunkNode node;
|
||||
FT_UInt cindex;
|
||||
FT_Error error;
|
||||
FTC_ChunkCache ccache = (FTC_ChunkCache) cache;
|
||||
FTC_ChunkNode node;
|
||||
FTC_SBitQueryRec query;
|
||||
|
||||
|
||||
/* argument checks delayed to FTC_Chunk_Cache_Lookup */
|
||||
if ( !ansbit )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
*ansbit = 0;
|
||||
error = FTC_Chunk_Cache_Lookup( &cache->root, desc, gindex,
|
||||
&node, &cindex );
|
||||
if ( !error )
|
||||
*ansbit = (FTC_SBit)node->elements + cindex;
|
||||
*ansbit = NULL;
|
||||
|
||||
query.chunk.gindex = gindex;
|
||||
query.chunk.cset = NULL;
|
||||
query.desc = *desc;
|
||||
|
||||
error = ftc_chunk_cache_lookup( ccache, &query.chunk, &node );
|
||||
if ( !error )
|
||||
{
|
||||
*ansbit = (FTC_SBit) node->items + (gindex - node->item_start);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
450
src/cache/ftlru.c
vendored
450
src/cache/ftlru.c
vendored
@ -25,326 +25,308 @@
|
||||
#include "ftcerror.h"
|
||||
|
||||
|
||||
static void
|
||||
lru_build_free_list( FT_LruNode nodes,
|
||||
FT_UInt count,
|
||||
FT_List free_list )
|
||||
{
|
||||
FT_LruNode node = nodes;
|
||||
FT_LruNode limit = node + count;
|
||||
|
||||
|
||||
free_list->head = free_list->tail = 0;
|
||||
for ( ; node < limit; node++ )
|
||||
FT_List_Add( free_list, (FT_ListNode)node );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Lru_New( const FT_Lru_Class* clazz,
|
||||
FT_UInt max_elements,
|
||||
FT_Pointer user_data,
|
||||
FT_Memory memory,
|
||||
FT_Bool pre_alloc,
|
||||
FT_Lru *anlru )
|
||||
FT_LruList_New( FT_LruList_Class clazz,
|
||||
FT_UInt max_nodes,
|
||||
FT_Pointer user_data,
|
||||
FT_Memory memory,
|
||||
FT_LruList *alist )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Lru lru;
|
||||
FT_Error error;
|
||||
FT_LruList list;
|
||||
|
||||
|
||||
if ( !anlru )
|
||||
if ( !alist || !clazz )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
*anlru = 0;
|
||||
if ( !ALLOC( lru, sizeof ( *lru ) ) )
|
||||
*alist = NULL;
|
||||
if ( !ALLOC( list, clazz->list_size ) )
|
||||
{
|
||||
if ( pre_alloc )
|
||||
{
|
||||
/* allocate static array of lru list nodes */
|
||||
if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
|
||||
{
|
||||
FREE( lru );
|
||||
goto Exit;
|
||||
}
|
||||
/* initialize common fields */
|
||||
list->clazz = clazz;
|
||||
list->memory = memory;
|
||||
list->max_nodes = max_nodes;
|
||||
list->user_data = user_data;
|
||||
|
||||
/* build the `free_nodes' list from the array */
|
||||
lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
|
||||
if ( clazz->list_init )
|
||||
{
|
||||
error = clazz->list_init( list );
|
||||
if ( error )
|
||||
{
|
||||
if ( clazz->list_done )
|
||||
clazz->list_done( list );
|
||||
|
||||
FREE( list );
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize common fields */
|
||||
lru->clazz = (FT_Lru_Class*)clazz;
|
||||
lru->max_elements = max_elements;
|
||||
lru->memory = memory;
|
||||
lru->user_data = user_data;
|
||||
|
||||
*anlru = lru;
|
||||
*alist = list;
|
||||
}
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FT_Lru_Reset( FT_Lru lru )
|
||||
FT_LruList_Destroy( FT_LruList list )
|
||||
{
|
||||
FT_ListNode node;
|
||||
FT_Lru_Class* clazz;
|
||||
FT_Memory memory;
|
||||
FT_Memory memory;
|
||||
FT_LruList_Class clazz;
|
||||
|
||||
|
||||
if ( !lru )
|
||||
if ( !list )
|
||||
return;
|
||||
|
||||
node = lru->elements.head;
|
||||
clazz = lru->clazz;
|
||||
memory = lru->memory;
|
||||
memory = list->memory;
|
||||
clazz = list->clazz;
|
||||
|
||||
while ( node )
|
||||
{
|
||||
FT_ListNode next = node->next;
|
||||
FT_LruList_Reset( list );
|
||||
|
||||
if ( clazz->list_done )
|
||||
clazz->list_done( list );
|
||||
|
||||
clazz->done_element( lru, (FT_LruNode)node );
|
||||
if ( !lru->nodes )
|
||||
FREE( node );
|
||||
|
||||
node = next;
|
||||
}
|
||||
|
||||
/* rebuild free list if necessary */
|
||||
if ( lru->nodes )
|
||||
lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes );
|
||||
|
||||
lru->elements.head = lru->elements.tail = 0;
|
||||
lru->num_elements = 0;
|
||||
FREE( list );
|
||||
}
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FT_Lru_Done( FT_Lru lru )
|
||||
FT_LruList_Reset( FT_LruList list )
|
||||
{
|
||||
FT_Memory memory;
|
||||
FT_LruNode node;
|
||||
FT_LruList_Class clazz;
|
||||
FT_Memory memory;
|
||||
|
||||
|
||||
if ( !lru )
|
||||
if ( !list )
|
||||
return;
|
||||
|
||||
memory = lru->memory;
|
||||
node = list->nodes;
|
||||
clazz = list->clazz;
|
||||
memory = list->memory;
|
||||
|
||||
FT_Lru_Reset( lru );
|
||||
while ( node )
|
||||
{
|
||||
FT_LruNode next = node->next;
|
||||
|
||||
FREE( lru->nodes );
|
||||
FREE( lru );
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( node, list );
|
||||
|
||||
FREE( node );
|
||||
node = next;
|
||||
}
|
||||
|
||||
list->nodes = NULL;
|
||||
list->num_nodes = 0;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Lru_Lookup_Node( FT_Lru lru,
|
||||
FT_LruKey key,
|
||||
FT_LruNode *anode )
|
||||
FT_LruList_Lookup( FT_LruList list,
|
||||
FT_LruKey key,
|
||||
FT_LruNode *anode )
|
||||
{
|
||||
FT_Error error = 0;
|
||||
FT_ListNode node;
|
||||
FT_Lru_Class* clazz;
|
||||
FT_LruNode found = 0;
|
||||
FT_Memory memory;
|
||||
FT_Error error = 0;
|
||||
FT_LruNode node, *pnode;
|
||||
FT_LruList_Class clazz;
|
||||
FT_LruNode* plast;
|
||||
FT_LruNode result = NULL;
|
||||
FT_Memory memory;
|
||||
|
||||
|
||||
if ( !lru || !key || !anode )
|
||||
if ( !list || !key || !anode )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
node = lru->elements.head;
|
||||
clazz = lru->clazz;
|
||||
memory = lru->memory;
|
||||
pnode = &list->nodes;
|
||||
plast = pnode;
|
||||
node = NULL;
|
||||
clazz = list->clazz;
|
||||
memory = list->memory;
|
||||
|
||||
if ( clazz->compare_element )
|
||||
if ( clazz->node_compare )
|
||||
{
|
||||
for ( ; node; node = node->next )
|
||||
if ( clazz->compare_element( (FT_LruNode)node, key ) )
|
||||
{
|
||||
found = (FT_LruNode)node;
|
||||
for (;;)
|
||||
{
|
||||
node = *pnode;
|
||||
if ( node == NULL )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( clazz->node_compare( node, key, list ) )
|
||||
break;
|
||||
|
||||
plast = pnode;
|
||||
pnode = &(*pnode)->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( ; node; node = node->next )
|
||||
if ( ((FT_LruNode)node)->key == key )
|
||||
{
|
||||
found = (FT_LruNode)node;
|
||||
for (;;)
|
||||
{
|
||||
node = *pnode;
|
||||
if ( node == NULL )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( node->key == key )
|
||||
break;
|
||||
|
||||
plast = pnode;
|
||||
pnode = &(*pnode)->next;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found )
|
||||
if ( node )
|
||||
{
|
||||
/* move element to top of list */
|
||||
FT_List_Up( &lru->elements, node );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we haven't found the relevant element. We will now try */
|
||||
/* to create a new one. */
|
||||
if ( lru->num_elements >= lru->max_elements )
|
||||
if ( list->nodes != node )
|
||||
{
|
||||
/* this lru list is full; we will now flush */
|
||||
/* the oldest node */
|
||||
FT_LruNode lru_node;
|
||||
*pnode = node->next;
|
||||
node->next = list->nodes;
|
||||
list->nodes = node;
|
||||
}
|
||||
result = node;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* we haven't found the relevant element. We will now try */
|
||||
/* to create a new one. */
|
||||
/* */
|
||||
|
||||
node = lru->elements.tail;
|
||||
lru_node = (FT_LruNode)node;
|
||||
found = lru_node;
|
||||
/* first, check if our list if full, when appropriate */
|
||||
if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
|
||||
{
|
||||
/* this list list is full; we will now flush */
|
||||
/* the oldest node, if there's one !! */
|
||||
FT_LruNode last = *plast;
|
||||
|
||||
if ( clazz->flush_element )
|
||||
error = clazz->flush_element( lru, lru_node, key );
|
||||
if ( last )
|
||||
{
|
||||
if ( clazz->node_flush )
|
||||
{
|
||||
error = clazz->node_flush( last, key, list );
|
||||
}
|
||||
else
|
||||
{
|
||||
clazz->done_element( lru, lru_node );
|
||||
lru_node->key = key;
|
||||
node->data = 0;
|
||||
error = clazz->init_element( lru, lru_node );
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( last, list );
|
||||
|
||||
last->key = key;
|
||||
error = clazz->node_init( last, key, list );
|
||||
}
|
||||
|
||||
if ( !error )
|
||||
{
|
||||
/* now, move element to top of list */
|
||||
FT_List_Up( &lru->elements, node );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* in case of error, the node must be discarded */
|
||||
FT_List_Remove( &lru->elements, node );
|
||||
lru->num_elements--;
|
||||
/* move it to the top of the list */
|
||||
*plast = NULL;
|
||||
last->next = list->nodes;
|
||||
list->nodes = last;
|
||||
|
||||
if ( lru->nodes )
|
||||
FT_List_Insert( &lru->free_nodes, node );
|
||||
else
|
||||
FREE( lru_node );
|
||||
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FT_LruNode lru_node;
|
||||
|
||||
|
||||
/* create a new lru list node, then the element for it */
|
||||
if ( lru->nodes )
|
||||
{
|
||||
node = lru->free_nodes.head;
|
||||
lru_node = (FT_LruNode)node;
|
||||
lru_node->key = key;
|
||||
|
||||
error = clazz->init_element( lru, lru_node );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
FT_List_Remove( &lru->free_nodes, node );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ALLOC( lru_node, sizeof ( *lru_node ) ) )
|
||||
goto Exit;
|
||||
|
||||
lru_node->key = key;
|
||||
error = clazz->init_element( lru, lru_node );
|
||||
if ( error )
|
||||
{
|
||||
FREE( lru_node );
|
||||
goto Exit;
|
||||
}
|
||||
result = last;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
found = lru_node;
|
||||
node = (FT_ListNode)lru_node;
|
||||
FT_List_Insert( &lru->elements, node );
|
||||
lru->num_elements++;
|
||||
/* in case of error during the flush or done/init cycle, */
|
||||
/* we need to discard the node.. */
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( last, list );
|
||||
|
||||
*plast = NULL;
|
||||
list->num_nodes--;
|
||||
|
||||
FREE( last );
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* otherwise, simply allocate a new node */
|
||||
if ( ALLOC( node, clazz->node_size ) )
|
||||
goto Exit;
|
||||
|
||||
node->key = key;
|
||||
error = clazz->node_init( node, key, list );
|
||||
if ( error )
|
||||
{
|
||||
FREE( node );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
result = node;
|
||||
node->next = list->nodes;
|
||||
list->nodes = node;
|
||||
list->num_nodes++;
|
||||
|
||||
Exit:
|
||||
*anode = found;
|
||||
*anode = result;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Lru_Lookup( FT_Lru lru,
|
||||
FT_LruKey key,
|
||||
FT_Pointer *anobject )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_LruNode node;
|
||||
|
||||
|
||||
/* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
|
||||
|
||||
if ( !anobject )
|
||||
return FTC_Err_Invalid_Argument;
|
||||
|
||||
*anobject = 0;
|
||||
error = FT_Lru_Lookup_Node( lru, key, &node );
|
||||
if ( !error )
|
||||
*anobject = node->root.data;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FT_Lru_Remove_Node( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
FT_LruList_Remove( FT_LruList list,
|
||||
FT_LruNode node )
|
||||
{
|
||||
if ( !lru || !node )
|
||||
FT_LruNode *pnode;
|
||||
|
||||
if ( !list || !node )
|
||||
return;
|
||||
|
||||
if ( lru->num_elements > 0 )
|
||||
pnode = &list->nodes;
|
||||
for (;;)
|
||||
{
|
||||
FT_List_Remove( &lru->elements, (FT_ListNode)node );
|
||||
lru->clazz->done_element( lru, node );
|
||||
|
||||
if ( lru->nodes )
|
||||
FT_List_Insert( &lru->free_nodes, (FT_ListNode)node );
|
||||
else
|
||||
if ( *pnode == node )
|
||||
{
|
||||
FT_Memory memory = lru->memory;
|
||||
FT_Memory memory = list->memory;
|
||||
FT_LruList_Class clazz = list->clazz;
|
||||
|
||||
*pnode = node->next;
|
||||
node->next = NULL;
|
||||
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( node, list );
|
||||
|
||||
FREE( node );
|
||||
list->num_nodes--;
|
||||
break;
|
||||
}
|
||||
|
||||
pnode = &(*pnode)->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FT_LruList_Remove_Selection( FT_LruList list,
|
||||
FT_LruNode_SelectFunc select_func,
|
||||
FT_Pointer select_data )
|
||||
{
|
||||
FT_LruNode *pnode, node;
|
||||
FT_LruList_Class clazz;
|
||||
FT_Memory memory;
|
||||
|
||||
if ( !list || !select_func )
|
||||
return;
|
||||
|
||||
memory = list->memory;
|
||||
clazz = list->clazz;
|
||||
pnode = &list->nodes;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
node = *pnode;
|
||||
if ( node == NULL )
|
||||
break;
|
||||
|
||||
if ( select_func( node, select_data, list ) )
|
||||
{
|
||||
*pnode = node->next;
|
||||
node->next = NULL;
|
||||
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( node, list );
|
||||
|
||||
FREE( node );
|
||||
}
|
||||
|
||||
lru->num_elements--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FT_Lru_Remove_Selection( FT_Lru lru,
|
||||
FT_Lru_Selector selector,
|
||||
FT_Pointer data )
|
||||
{
|
||||
if ( !lru || !selector )
|
||||
return;
|
||||
|
||||
if ( lru->num_elements > 0 )
|
||||
{
|
||||
FT_ListNode node = lru->elements.head;
|
||||
FT_ListNode next;
|
||||
|
||||
|
||||
while ( node )
|
||||
{
|
||||
next = node->next;
|
||||
if ( selector( lru, (FT_LruNode)node, data ) )
|
||||
{
|
||||
/* remove this element from the list, and destroy it */
|
||||
FT_Lru_Remove_Node( lru, (FT_LruNode)node );
|
||||
}
|
||||
node = next;
|
||||
}
|
||||
else
|
||||
pnode = &(*pnode)->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user