diff --git a/include/freetype/cache/ftcchunk.h b/include/freetype/cache/ftcchunk.h new file mode 100644 index 000000000..a36772c95 --- /dev/null +++ b/include/freetype/cache/ftcchunk.h @@ -0,0 +1,208 @@ +/***************************************************************************/ +/* */ +/* ftcchunk.h */ +/* */ +/* FreeType chunk cache (specification). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Important: The functions defined in this file are only used to */ + /* implement an abstract chunk cache class. You need to */ + /* provide additional logic to implement a complete cache. */ + /* For example, see `ftcmetrx.h' and `ftcmetrx.c' which */ + /* implement a glyph metrics cache based on this code. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS ALPHA CODE, THIS API *********/ + /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ + /********* FREETYPE DEVELOPMENT TEAM *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef FTCCHUNK_H +#define FTCCHUNK_H + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + +/* maximum number of chunk sets in a given chunk cache */ +#define FTC_MAX_CHUNK_SETS 16 + + + typedef struct FTC_ChunkRec_* FTC_Chunk; + typedef struct FTC_ChunkSetRec_* FTC_ChunkSet; + typedef struct FTC_Chunk_CacheRec_* FTC_Chunk_Cache; + + typedef struct FTC_ChunkRec_ + { + FTC_CacheNodeRec root; + FTC_ChunkSet cset; + FT_UShort cset_index; + FT_UShort num_elements; + FT_Byte* elements; + + } FTC_ChunkRec; + + + /*************************************************************************/ + /* */ + /* chunk set methods */ + /* */ + + typedef FT_Error (*FTC_ChunkSet_InitFunc) ( FTC_ChunkSet cset, + FT_Pointer type ); + + + typedef void (*FTC_ChunkSet_DoneFunc) ( FTC_ChunkSet cset ); + + typedef FT_Bool (*FTC_ChunkSet_CompareFunc)( FTC_ChunkSet cset, + FT_Pointer type ); + + + + typedef FT_Error (*FTC_ChunkSet_NewNodeFunc)( FTC_ChunkSet cset, + FT_UInt index, + FTC_ChunkNode* anode ); + + typedef void (*FTC_ChunkSet_DestroyNodeFunc)( FTC_ChunkNode node ); + + typedef FT_ULong (*FTC_ChunkSet_SizeNodeFunc) ( FTC_ChunkNode node ); + + + typedef struct FTC_ChunkSet_Class_ + { + FT_UInt cset_size; + + FTC_ChunkSet_InitFunc init; + FTC_ChunkSet_DoneFunc done; + FTC_ChunkSet_CompareFunc compare; + + 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; + + } FTC_ChunkSetRec; + + + /* the abstract chunk cache class */ + typedef struct FTC_Chunk_Cache_Class_ + { + FTC_Cache_Class root; + FTC_ChunkSet_Class* cset_class; + + } FTC_Chunk_Cache_Class; + + + /* the abstract chunk cache object */ + typedef struct FTC_Chunk_CacheRec_ + { + FTC_CacheRec root; + FT_Lru csets_lru; /* static chunk set lru list */ + FTC_ChunkSet last_cset; /* small cache :-) */ + + } FTC_Chunk_CacheRec; + + /*************************************************************************/ + /* */ + /* These functions are exported so that they can be called from */ + /* user-provided cache classes; otherwise, they are really parts of the */ + /* cache sub-system internals. */ + /* */ + + FT_EXPORT_FUNC( NV_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-- + + + FT_EXPORT_DEF( void ) + FTC_ChunkNode_Destroy( FTC_ChunkNode node ); + + + + FT_EXPORT_DEF( FT_Error ) + FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache ); + + + FT_EXPORT_DEF( void ) + FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache ); + + + + + FT_EXPORT_DEF( FT_Error ) + FTC_ChunkSet_New( FTC_Chunk_Cache cache, + FT_Pointer type, + FT_UInt num_elements, + FT_UInt element_size, + FT_UInt chunk_size, + FTC_ChunkSet *aset ) + + + FT_EXPORT_DEF( FT_Error ) + FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset, + FT_UInt glyph_index, + FTC_ChunkNode *anode, + FT_UInt *aindex ); + +#ifdef __cplusplus + } +#endif + + +#endif /* FTCCHUNK_H */ + +/* END */ diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h index 9d49ac8ad..b0a4ea7e7 100644 --- a/include/freetype/cache/ftcglyph.h +++ b/include/freetype/cache/ftcglyph.h @@ -57,21 +57,20 @@ #endif - /* maximum number of queues per glyph cache; must be < 256 */ -#define FTC_MAX_GLYPH_QUEUES 16 + /* maximum number of glyph sets per glyph cache; must be < 256 */ +#define FTC_MAX_GLYPH_SETS 16 +#define FTC_GSET_HASH_SIZE_DEFAULT 64 -#define FTC_QUEUE_HASH_SIZE_DEFAULT 64 - - typedef struct FTC_Glyph_QueueRec_* FTC_Glyph_Queue; + typedef struct FTC_GlyphSetRec_* FTC_GlyphSet; typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode; typedef struct FTC_Glyph_CacheRec_* FTC_Glyph_Cache; - typedef struct FTC_GlyphNodeRec_ + typedef struct FTC_GlyphNodeRec_ { FTC_CacheNodeRec root; - FTC_GlyphNode queue_next; /* next in queue's bucket list */ + FTC_GlyphNode gset_next; /* next in glyph set's bucket list */ FT_UShort glyph_index; - FT_UShort queue_index; + FT_UShort gset_index; } FTC_GlyphNodeRec; @@ -83,62 +82,62 @@ /*************************************************************************/ /* */ - /* Glyph queue methods. */ + /* Glyph set methods. */ /* */ - typedef FT_Error (*FTC_Glyph_Queue_InitFunc)( FTC_Glyph_Queue queue, - FT_Pointer type ); + typedef FT_Error (*FTC_GlyphSet_InitFunc) ( FTC_GlyphSet gset, + FT_Pointer type ); - typedef void (*FTC_Glyph_Queue_DoneFunc)( FTC_Glyph_Queue queue ); + typedef void (*FTC_GlyphSet_DoneFunc) ( FTC_GlyphSet gset ); - typedef FT_Bool (*FTC_Glyph_Queue_CompareFunc)( FTC_Glyph_Queue queue, - FT_Pointer type ); - - typedef FT_Error (*FTC_Glyph_Queue_NewNodeFunc)( FTC_Glyph_Queue queue, - FT_UInt gindex, - FTC_GlyphNode* anode ); - - typedef void (*FTC_Glyph_Queue_DestroyNodeFunc)( FTC_GlyphNode node, - FTC_Glyph_Queue queue ); - - typedef FT_ULong (*FTC_Glyph_Queue_SizeNodeFunc)( FTC_GlyphNode node, - FTC_Glyph_Queue queue ); + typedef FT_Bool (*FTC_GlyphSet_CompareFunc)( FTC_GlyphSet gset, + FT_Pointer type ); - typedef struct FTC_Glyph_Queue_Class_ + 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 queue_byte_size; + FT_UInt gset_byte_size; - FTC_Glyph_Queue_InitFunc init; - FTC_Glyph_Queue_DoneFunc done; - FTC_Glyph_Queue_CompareFunc compare; + FTC_GlyphSet_InitFunc init; + FTC_GlyphSet_DoneFunc done; + FTC_GlyphSet_CompareFunc compare; - FTC_Glyph_Queue_NewNodeFunc new_node; - FTC_Glyph_Queue_SizeNodeFunc size_node; - FTC_Glyph_Queue_DestroyNodeFunc destroy_node; + FTC_GlyphSet_NewNodeFunc new_node; + FTC_GlyphSet_SizeNodeFunc size_node; + FTC_GlyphSet_DestroyNodeFunc destroy_node; - } FTC_Glyph_Queue_Class; + } FTC_GlyphSet_Class; - typedef struct FTC_Glyph_QueueRec_ + typedef struct FTC_GlyphSetRec_ { - FTC_Glyph_Cache cache; - FTC_Manager manager; - FT_Memory memory; - FTC_Glyph_Queue_Class* clazz; - FTC_Image_Desc descriptor; - FT_UInt hash_size; - FTC_GlyphNode* buckets; - FT_UInt queue_index; /* index in parent cache */ + 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 */ - } FTC_Glyph_QueueRec; + } FTC_GlyphSetRec; /* the abstract glyph cache class */ typedef struct FTC_Glyph_Cache_Class_ { - FTC_Cache_Class root; - FTC_Glyph_Queue_Class* queue_class; + FTC_Cache_Class root; + FTC_GlyphSet_Class* gset_class; } FTC_Glyph_Cache_Class; @@ -146,9 +145,9 @@ /* the abstract glyph cache object */ typedef struct FTC_Glyph_CacheRec_ { - FTC_CacheRec root; - FT_Lru queues_lru; /* static queues lru list */ - FTC_Glyph_Queue last_queue; /* small cache :-) */ + FTC_CacheRec root; + FT_Lru gsets_lru; /* static sets lru list */ + FTC_GlyphSet last_gset; /* small cache :-) */ } FTC_Glyph_CacheRec; @@ -161,9 +160,9 @@ /* */ FT_EXPORT_FUNC( void ) - FTC_GlyphNode_Init( FTC_GlyphNode node, - FTC_Glyph_Queue queue, - FT_UInt gindex ); + 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++ @@ -173,8 +172,8 @@ FT_EXPORT_DEF( void ) - FTC_Destroy_Glyph_Node( FTC_GlyphNode node, - FTC_Glyph_Cache cache ); + FTC_GlyphNode_Destroy( FTC_GlyphNode node, + FTC_Glyph_Cache cache ); @@ -189,15 +188,15 @@ FT_EXPORT_DEF( FT_Error ) - FTC_Glyph_Queue_New( FTC_Glyph_Cache cache, - FT_Pointer type, - FTC_Glyph_Queue* aqueue ); + FTC_GlyphSet_New( FTC_Glyph_Cache cache, + FT_Pointer type, + FTC_GlyphSet *aset ); FT_EXPORT_DEF( FT_Error ) - FTC_Glyph_Queue_Lookup_Node( FTC_Glyph_Queue queue, - FT_UInt glyph_index, - FTC_GlyphNode* anode ); + FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset, + FT_UInt glyph_index, + FTC_GlyphNode *anode ); #ifdef __cplusplus @@ -205,6 +204,6 @@ #endif -#endif /* FTCIMAGE_H */ +#endif /* FTCGLYPH_H */ /* END */ diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h index 97df18781..b7657e71d 100644 --- a/include/freetype/ftcache.h +++ b/include/freetype/ftcache.h @@ -450,7 +450,7 @@ /* failure. */ /* */ /* */ - /* FreType error code. 0 means success. */ + /* error code, 0 means success */ /* */ /* */ /* the returned glyph is owned and manager by the glyph image cache. */ @@ -461,11 +461,11 @@ /* taken by the glyphs it holds, the returned glyph might disappear */ /* on a later invocation of this function! It's a cache after all... */ /* */ - FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_Lookup( - FTC_Image_Cache cache, - FTC_Image_Desc* desc, - FT_UInt gindex, - FT_Glyph* aglyph ); + FT_EXPORT_DEF( FT_Error ) + FTC_Image_Cache_Lookup( FTC_Image_Cache cache, + FTC_Image_Desc* desc, + FT_UInt gindex, + FT_Glyph* aglyph ); #ifdef __cplusplus diff --git a/src/cache/ftcchunk.c b/src/cache/ftcchunk.c new file mode 100644 index 000000000..2dc5b2439 --- /dev/null +++ b/src/cache/ftcchunk.c @@ -0,0 +1,373 @@ +/***************************************************************************/ +/* */ +/* ftcchunk.c */ +/* */ +/* FreeType chunk cache cache (body). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include +#include +#include +#include +#include + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + + /* create a new chunk node, setting its cache index and ref count */ + FT_EXPORT_FUNC( NV_Error ) + FTC_ChunkNode_Init( FTC_ChunkNode node, + FTC_ChunkSet cset, + FT_UInt index, + FT_Bool alloc ) + { + FTC_Chunk_Cache cache = cset->cache; + FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root ); + NV_Error error = 0; + + + data->cache_index = (FT_UShort) cache->root.cache_index; + data->ref_count = (FT_Short) 0; + node->cset_index = (FT_UShort) index; + + node->num_elements = (index+1 < cset->chunk_count) + ? cset->chunk_size + : cset->element_max - cset->chunk_count*index; + if (alloc) + { + /* allocate elements array */ + memory = cache->root.memory; + error = MEM_ALLOC( cache->elements, cset->element_size * + cset->element_count ); + } + return error; + } + + + FT_EXPORT_FUNC( void ) FTC_ChunkNode_Destroy( FTC_ChunkNode node ) + { + FTC_ChunkSet cset = node->cset; + + /* remove from parent set table */ + cset->chunks[ node->cset_index ] = 0; + + /* destroy the node */ + cset->clazz->destroy_node( node ); + } + + + FT_EXPORT_FUNC( FT_ULong ) FTC_ChunkNode_Size( FTC_ChunkNode node ) + { + FTC_ChunkSet cset = node->cset; + + + return cset->clazz->size_node( node, cset ); + } + + + FT_CPLUSPLUS( const FTC_CacheNode_Class ) ftc_chunk_cache_node_class = + { + (FTC_CacheNode_SizeFunc) FTC_ChunkNode_Size, + (FTC_CacheNode_DestroyFunc) FTC_ChunkNode_Destroy + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHUNK SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_EXPORT_FUNC( FT_Error ) + FTC_ChunkSet_New( FTC_Chunk_Cache cache, + FT_Pointer type, + FT_UInt num_elements, + FT_UInt element_size, + FT_UInt chunk_size, + FTC_ChunkSet *aset ) + { + FT_Error error; + FT_Memory memory = cache->root.memory; + FTC_Manager manager = cache->root.manager; + FTC_ChunkSet cset = 0; + + FTC_Chunk_Cache_Class* ccache_class; + FTC_ChunkSet_Class* clazz; + + + ccache_class = (FTC_Chunk_Cache_Class*)cache->root.clazz; + clazz = ccache_class->cset_class; + + *aset = 0; + + if ( ALLOC( set, clazz->cset_byte_size ) ) + goto Exit; + + cset->cache = cache; + cset->manager = manager; + cset->memory = memory; + cset->element_max = num_elements; + cset->element_size = element_size; + cset->element_count = chunk_size; + cset->clazz = clazz; + + /* compute maximum number of nodes */ + cset->num_chunks = (num_elements + (chunk_size-1))/chunk_size; + + /* 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; + } + + + FT_EXPORT_FUNC( void ) FTC_ChunkSet_Destroy( FTC_ChunkSet cset ) + { + FTC_Chunk_Cache cache = cset->cache; + FTC_Manager manager = cache->root.manager; + FT_List glyphs_lru = &manager->global_lru; + FTC_ChunkNode* bucket = cset->chunk; + FTC_ChunkNode* bucket_limit = bucket + cset->num_chunks; + FT_Memory memory = cache->root.memory; + + FTC_ChunkSet_Class* clazz = cset->clazz; + + + /* for each bucket, free the list of glyph nodes */ + for ( ; bucket < bucket_limit; bucket++ ) + { + FTC_ChunkNode node = bucket[0]; + FT_ListNode lrunode; + + lrunode = FTC_CHUNKNODE_TO_LRUNODE( node ); + + manager->num_bytes -= clazz->size_node( node ); + + FT_List_Remove( glyphs_lru, lrunode ); + + clazz->destroy_node( node ); + + bucket[0] = 0; + } + + if ( clazz->done ) + clazz->done( cset ); + + FREE( cset->chunks ); + FREE( cset ); + } + + + FT_EXPORT_FUNC( FT_Error ) + FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset, + FT_UInt glyph_index, + FTC_ChunkNode *anode, + FTC_UInt *index ) + { + FTC_Glyph_Cache cache = cset->cache; + FTC_Manager manager = cache->root.manager; + FT_Error error = 0; + + FTC_GlyphSet_Class* clazz = cset->clazz; + + + *anode = 0; + if (glyph_index >= cset->elements_max) + error = FT_Err_Invalid_Argument; + else + { + FT_UInt chunk_size = cset->chunk_size; + 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, glyph_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, gset ); + + if (manager->num_bytes > manager->max_bytes) + { + FTC_ChunkNode_Ref ( node ); + FTC_Manager_Compress( manager ); + FTC_ChunkNode_Unref ( node ); + } + } + + *anode = node; + *aindex = glyph_index - chunk_index*chunk_size; + } + + 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 ) + + + LOCAL_FUNC_X + FT_Error ftc_chunk_set_lru_init( FT_Lru lru, + FT_LruNode node ) + { + 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 ); + if ( !error ) + { + /* good, now set the set index within the set object */ + cset->cset_index = node - lru->nodes; + node->root.data = set; + } + + return error; + } + + + LOCAL_FUNC_X + 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 ); + } + + + LOCAL_FUNC_X + 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_CPLUSPLUS( 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_FUNC( FT_Error ) FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache ) + { + FT_Memory memory = cache->root.memory; + FT_Error error; + + + /* set up root node_class to be used by manager */ + cache->root.node_clazz = + (FTC_CacheNode_Class*)&ftc_chunk_cache_node_class; + + /* 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 `user_data' and must be set to */ + /* `cache' here. */ + /* */ + cache->root.cache_user = cache; + + error = FT_Lru_New( &ftc_chunk_set_lru_class, + FTC_MAX_GLYPH_CSETS, + cache, + memory, + 1, /* pre_alloc == TRUE */ + &cache->csets_lru ); + return error; + } + + + FT_EXPORT_FUNC( void ) FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache ) + { + /* discard glyph sets */ + FT_Lru_Done( cache->csets_lru ); + } + + diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c index 400739c5b..6f897c831 100644 --- a/src/cache/ftcglyph.c +++ b/src/cache/ftcglyph.c @@ -16,16 +16,6 @@ /***************************************************************************/ - /*************************************************************************/ - /* */ - /* Note: The implementation of glyph queues is rather generic in this */ - /* code. This will allow other glyph node/cache types to be */ - /* easily included in the future. For now, we only cache glyph */ - /* images. */ - /* */ - /*************************************************************************/ - - #include #include #include @@ -42,22 +32,18 @@ /*************************************************************************/ - /* In the future, we might provide a better scheme for managing glyph */ - /* node elements. For the moment, we simply use FT_Alloc()/FT_Free(). */ - - /* create a new glyph node, setting its cache index and ref count */ - FT_EXPORT_FUNC( void ) FTC_GlyphNode_Init( FTC_GlyphNode node, - FTC_Glyph_Queue queue, - FT_UInt gindex ) + FT_EXPORT_FUNC( void ) FTC_GlyphNode_Init( FTC_GlyphNode node, + FTC_GlyphSet gset, + FT_UInt gindex ) { - FTC_Glyph_Cache cache = queue->cache; + 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->queue_index = (FT_UShort)queue->queue_index; + node->gset_index = (FT_UShort)gset->gset_index; node->glyph_index = (FT_UShort)gindex; } @@ -72,13 +58,13 @@ FT_EXPORT_FUNC( void ) FTC_GlyphNode_Destroy( FTC_GlyphNode node, FTC_Glyph_Cache cache ) { - FT_LruNode queue_lru = cache->queues_lru->nodes + node->queue_index; - FTC_Glyph_Queue queue = (FTC_Glyph_Queue)queue_lru->root.data; - FT_UInt hash = node->glyph_index % queue->hash_size; + 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 queue's bucket list */ + /* remove the node from its gset's bucket list */ { - FTC_GlyphNode* pnode = queue->buckets + hash; + FTC_GlyphNode* pnode = gset->buckets + hash; FTC_GlyphNode cur; for (;;) @@ -94,15 +80,15 @@ if (cur == node) { - *pnode = cur->queue_next; + *pnode = cur->gset_next; break; } - pnode = &cur->queue_next; + pnode = &cur->gset_next; } } /* destroy the node */ - queue->clazz->destroy_node( node, queue ); + gset->clazz->destroy_node( node, gset ); } @@ -116,18 +102,18 @@ FT_EXPORT_FUNC( FT_ULong ) FTC_GlyphNode_Size( FTC_GlyphNode node, FTC_Glyph_Cache cache ) { - FT_LruNode queue_lru = cache->queues_lru->nodes + node->queue_index; - FTC_Glyph_Queue queue = (FTC_Glyph_Queue)queue_lru->root.data; + FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index; + FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data; - return queue->clazz->size_node( node, queue ); + return gset->clazz->size_node( node, gset ); } FT_CPLUSPLUS( const FTC_CacheNode_Class ) ftc_glyph_cache_node_class = { - (FTC_CacheNode_SizeFunc) FTC_GlyphNode_Size, - (FTC_CacheNode_DestroyFunc)FTC_GlyphNode_Destroy + (FTC_CacheNode_SizeFunc) FTC_GlyphNode_Size, + (FTC_CacheNode_DestroyFunc) FTC_GlyphNode_Destroy }; @@ -140,68 +126,68 @@ /*************************************************************************/ - FT_EXPORT_FUNC( FT_Error ) FTC_Glyph_Queue_New( FTC_Glyph_Cache cache, - FT_Pointer type, - FTC_Glyph_Queue* aqueue ) + FT_EXPORT_FUNC( FT_Error ) FTC_GlyphSet_New( FTC_Glyph_Cache cache, + FT_Pointer type, + FTC_GlyphSet *aset ) { - FT_Error error; - FT_Memory memory = cache->root.memory; - FTC_Manager manager = cache->root.manager; - FTC_Glyph_Queue queue = 0; + 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_Glyph_Queue_Class* clazz; + FTC_GlyphSet_Class* clazz; gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz; - clazz = gcache_class->queue_class; + clazz = gcache_class->gset_class; - *aqueue = 0; + *aset = 0; - if ( ALLOC( queue, clazz->queue_byte_size ) ) + if ( ALLOC( gset, clazz->gset_byte_size ) ) goto Exit; - queue->cache = cache; - queue->manager = manager; - queue->memory = memory; - queue->hash_size = FTC_QUEUE_HASH_SIZE_DEFAULT; - queue->clazz = clazz; + 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( queue->buckets, queue->hash_size, FTC_GlyphNode ) ) + if ( ALLOC_ARRAY( gset->buckets, gset->hash_size, FTC_GlyphNode ) ) goto Exit; - /* initialize queue by type if needed */ + /* initialize gset by type if needed */ if ( clazz->init ) { - error = clazz->init( queue, type ); + error = clazz->init( gset, type ); if ( error ) goto Exit; } - *aqueue = queue; + *aset = gset; Exit: - if ( error && queue ) + if ( error && gset ) { - FREE( queue->buckets ); - FREE( queue ); + FREE( gset->buckets ); + FREE( gset ); } return error; } - FT_EXPORT_FUNC( void ) FTC_Glyph_Queue_Done( FTC_Glyph_Queue queue ) + FT_EXPORT_FUNC( void ) FTC_GlyphSet_Destroy( FTC_GlyphSet gset ) { - FTC_Glyph_Cache cache = queue->cache; + FTC_Glyph_Cache cache = gset->cache; FTC_Manager manager = cache->root.manager; FT_List glyphs_lru = &manager->global_lru; - FTC_GlyphNode* bucket = queue->buckets; - FTC_GlyphNode* bucket_limit = bucket + queue->hash_size; + FTC_GlyphNode* bucket = gset->buckets; + FTC_GlyphNode* bucket_limit = bucket + gset->hash_size; FT_Memory memory = cache->root.memory; - FTC_Glyph_Queue_Class* clazz = queue->clazz; + FTC_GlyphSet_Class* clazz = gset->clazz; /* for each bucket, free the list of glyph nodes */ @@ -214,41 +200,41 @@ for ( ; node; node = next ) { - next = node->queue_next; + next = node->gset_next; lrunode = FTC_GLYPHNODE_TO_LRUNODE( node ); - manager->num_bytes -= clazz->size_node( node, queue ); + manager->num_bytes -= clazz->size_node( node, gset ); FT_List_Remove( glyphs_lru, lrunode ); - clazz->destroy_node( node, queue ); + clazz->destroy_node( node, gset ); } bucket[0] = 0; } if ( clazz->done ) - clazz->done( queue ); + clazz->done( gset ); - FREE( queue->buckets ); - FREE( queue ); + FREE( gset->buckets ); + FREE( gset ); } FT_EXPORT_FUNC( FT_Error ) - FTC_Glyph_Queue_Lookup_Node( FTC_Glyph_Queue queue, - FT_UInt glyph_index, - FTC_GlyphNode* anode ) + FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset, + FT_UInt glyph_index, + FTC_GlyphNode *anode ) { - FTC_Glyph_Cache cache = queue->cache; + FTC_Glyph_Cache cache = gset->cache; FTC_Manager manager = cache->root.manager; - FT_UInt hash_index = glyph_index % queue->hash_size; - FTC_GlyphNode* bucket = queue->buckets + hash_index; + 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_Glyph_Queue_Class* clazz = queue->clazz; + FTC_GlyphSet_Class* clazz = gset->clazz; *anode = 0; @@ -262,34 +248,38 @@ if ( node->glyph_index == glyph_index ) { /* we found it! -- move glyph to start of the lists */ - *pnode = node->queue_next; - node->queue_next = bucket[0]; - bucket[0] = node; + *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->queue_next; + pnode = &node->gset_next; } /* we didn't found the glyph image, we will now create a new one */ - error = clazz->new_node( queue, glyph_index, &node ); + error = clazz->new_node( gset, glyph_index, &node ); if ( error ) goto Exit; /* insert the node at the start of our bucket list */ - node->queue_next = bucket[0]; - bucket[0] = node; + 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, queue ); + manager->num_bytes += clazz->size_node( node, gset ); if (manager->num_bytes > manager->max_bytes) + { + FTC_GlyphNode_Ref ( node ); FTC_Manager_Compress( manager ); + FTC_GlyphNode_Unref ( node ); + } *anode = node; @@ -301,39 +291,37 @@ /*************************************************************************/ /*************************************************************************/ /***** *****/ - /***** GLYPH QUEUES LRU CALLBACKS *****/ + /***** GLYPH SETS LRU CALLBACKS *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ -#define FTC_QUEUE_LRU_GET_CACHE( lru ) \ +#define FTC_GSET_LRU_GET_CACHE( lru ) \ ( (FTC_Glyph_Cache)(lru)->user_data ) -#define FTC_QUEUE_LRU_GET_MANAGER( lru ) \ - FTC_QUEUE_LRU_GET_CACHE( lru )->manager +#define FTC_GSET_LRU_GET_MANAGER( lru ) \ + FTC_GSET_LRU_GET_CACHE( lru )->manager -#define FTC_LRUNODE_QUEUE( node ) \ - ( (FTC_Glyph_Queue)(node)->root.data ) +#define FTC_LRUNODE_GSET( node ) \ + ( (FTC_GlyphSet)(node)->root.data ) LOCAL_FUNC_X - FT_Error ftc_glyph_queue_lru_init( FT_Lru lru, - FT_LruNode node ) + FT_Error ftc_glyph_set_lru_init( FT_Lru lru, + FT_LruNode node ) { - FTC_Glyph_Cache cache = FTC_QUEUE_LRU_GET_CACHE( lru ); + FTC_Glyph_Cache cache = FTC_GSET_LRU_GET_CACHE( lru ); FT_Error error; - FTC_Glyph_Queue queue; + FTC_GlyphSet gset; - error = FTC_Glyph_Queue_New( cache, - (FT_Pointer)node->key, - &queue ); + error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset ); if ( !error ) { - /* good, now set the queue index within the queue object */ - queue->queue_index = node - lru->nodes; - node->root.data = queue; + /* good, now set the gset index within the gset object */ + gset->gset_index = node - lru->nodes; + node->root.data = gset; } return error; @@ -341,36 +329,36 @@ LOCAL_FUNC_X - void ftc_glyph_queue_lru_done( FT_Lru lru, - FT_LruNode node ) + void ftc_glyph_set_lru_done( FT_Lru lru, + FT_LruNode node ) { - FTC_Glyph_Queue queue = FTC_LRUNODE_QUEUE( node ); + FTC_GlyphSet gset = FTC_LRUNODE_GSET( node ); FT_UNUSED( lru ); - FTC_Glyph_Queue_Done( queue ); + FTC_GlyphSet_Destroy( gset ); } LOCAL_FUNC_X - FT_Bool ftc_glyph_queue_lru_compare( FT_LruNode node, - FT_LruKey key ) + FT_Bool ftc_glyph_set_lru_compare( FT_LruNode node, + FT_LruKey key ) { - FTC_Glyph_Queue queue = FTC_LRUNODE_QUEUE( node ); + FTC_GlyphSet gset = FTC_LRUNODE_GSET( node ); - return queue->clazz->compare( queue, (FT_Pointer)key ); + return gset->clazz->compare( gset, (FT_Pointer)key ); } - FT_CPLUSPLUS( const FT_Lru_Class ) ftc_glyph_queue_lru_class = + FT_CPLUSPLUS( const FT_Lru_Class ) ftc_glyph_set_lru_class = { sizeof( FT_LruRec ), - ftc_glyph_queue_lru_init, - ftc_glyph_queue_lru_done, + ftc_glyph_set_lru_init, + ftc_glyph_set_lru_done, 0, /* no flush */ - ftc_glyph_queue_lru_compare + ftc_glyph_set_lru_compare }; @@ -400,20 +388,20 @@ /* */ cache->root.cache_user = cache; - error = FT_Lru_New( &ftc_glyph_queue_lru_class, - FTC_MAX_GLYPH_QUEUES, + error = FT_Lru_New( &ftc_glyph_set_lru_class, + FTC_MAX_GLYPH_SETS, cache, memory, 1, /* pre_alloc == TRUE */ - &cache->queues_lru ); + &cache->gsets_lru ); return error; } FT_EXPORT_FUNC( void ) FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache ) { - /* discard glyph queues */ - FT_Lru_Done( cache->queues_lru ); + /* discard glyph sets */ + FT_Lru_Done( cache->gsets_lru ); } diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c index 2e8db1b75..50d0a0706 100644 --- a/src/cache/ftcimage.c +++ b/src/cache/ftcimage.c @@ -36,13 +36,11 @@ /*************************************************************************/ - /* this is a simple glyph image destructor, which is called exclusively */ - /* from the CacheQueue object */ LOCAL_FUNC_X - void ftc_glyph_image_node_destroy( FTC_GlyphImage node, - FTC_Glyph_Queue queue ) + void ftc_glyph_image_node_destroy( FTC_GlyphImage node, + FTC_GlyphSet gset ) { - FT_Memory memory = queue->memory; + FT_Memory memory = gset->memory; FT_Done_Glyph( node->ft_glyph ); @@ -51,12 +49,12 @@ LOCAL_FUNC_X - FT_Error ftc_glyph_image_node_new( FTC_Glyph_Queue queue, - FT_UInt glyph_index, - FTC_GlyphImage *anode ) + FT_Error ftc_glyph_image_node_new( FTC_GlyphSet gset, + FT_UInt glyph_index, + FTC_GlyphImage *anode ) { - FT_Memory memory = queue->memory; - FTC_Image_Queue imageq = (FTC_Image_Queue)queue; + FT_Memory memory = gset->memory; + FTC_ImageSet imageset = (FTC_ImageSet)gset; FT_Error error; FTC_GlyphImage node = 0; FT_Face face; @@ -68,17 +66,17 @@ goto Exit; /* init its inner fields */ - FTC_GlyphNode_Init( FTC_GLYPHNODE(node), queue, glyph_index ); + FTC_GlyphNode_Init( FTC_GLYPHNODE(node), gset, glyph_index ); /* we will now load the glyph image */ - error = FTC_Manager_Lookup_Size( queue->manager, - &imageq->description.font, + error = FTC_Manager_Lookup_Size( gset->manager, + &imageset->description.font, &face, &size ); if ( !error ) { FT_UInt glyph_index = node->root.glyph_index; FT_UInt load_flags = FT_LOAD_DEFAULT; - FT_UInt image_type = imageq->description.image_type; + FT_UInt image_type = imageset->description.image_type; if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap ) @@ -135,7 +133,7 @@ /* this function is important because it is both part of */ - /* a FTC_Glyph_Queue_Class and a FTC_CacheNode_Class */ + /* a FTC_GlyphSet_Class and a FTC_CacheNode_Class */ /* */ LOCAL_FUNC_X FT_ULong ftc_glyph_image_node_size( FTC_GlyphImage node ) @@ -189,33 +187,33 @@ LOCAL_FUNC_X - FT_Error ftc_image_queue_init( FTC_Image_Queue queue, - FTC_Image_Desc* type ) + FT_Error ftc_image_set_init( FTC_ImageSet iset, + FTC_Image_Desc* type ) { - queue->description = *type; + iset->description = *type; return 0; } LOCAL_FUNC_X - FT_Bool ftc_image_queue_compare( FTC_Image_Queue queue, - FTC_Image_Desc* type ) + FT_Bool ftc_image_set_compare( FTC_ImageSet iset, + FTC_Image_Desc* type ) { - return !memcmp( &queue->description, type, sizeof ( *type ) ); + return !memcmp( &iset->description, type, sizeof ( *type ) ); } - FT_CPLUSPLUS( const FTC_Glyph_Queue_Class ) ftc_glyph_image_queue_class = + FT_CPLUSPLUS( const FTC_GlyphSet_Class ) ftc_glyph_image_set_class = { - sizeof( FTC_Image_QueueRec ), + sizeof( FTC_ImageSetRec ), - (FTC_Glyph_Queue_InitFunc) ftc_image_queue_init, - (FTC_Glyph_Queue_DoneFunc) 0, - (FTC_Glyph_Queue_CompareFunc) ftc_image_queue_compare, + (FTC_GlyphSet_InitFunc) ftc_image_set_init, + (FTC_GlyphSet_DoneFunc) 0, + (FTC_GlyphSet_CompareFunc) ftc_image_set_compare, - (FTC_Glyph_Queue_NewNodeFunc) ftc_glyph_image_node_new, - (FTC_Glyph_Queue_SizeNodeFunc) ftc_glyph_image_node_size, - (FTC_Glyph_Queue_DestroyNodeFunc)ftc_glyph_image_node_destroy + (FTC_GlyphSet_NewNodeFunc) ftc_glyph_image_node_new, + (FTC_GlyphSet_SizeNodeFunc) ftc_glyph_image_node_size, + (FTC_GlyphSet_DestroyNodeFunc)ftc_glyph_image_node_destroy }; @@ -231,11 +229,11 @@ FT_CPLUSPLUS( const FTC_Glyph_Cache_Class ) ftc_glyph_image_cache_class = { { - sizeof( FTC_Glyph_CacheRec ), - (FTC_Cache_InitFunc)FTC_Glyph_Cache_Init, - (FTC_Cache_DoneFunc)FTC_Glyph_Cache_Done + sizeof( FTC_Image_CacheRec ), + (FTC_Cache_InitFunc) FTC_Glyph_Cache_Init, + (FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done }, - (FTC_Glyph_Queue_Class*)&ftc_glyph_image_queue_class + (FTC_GlyphSet_Class*) &ftc_glyph_image_set_class }; @@ -255,12 +253,12 @@ FT_UInt gindex, FT_Glyph* aglyph ) { - FT_Error error; - FTC_Glyph_Queue queue; - FTC_GlyphNode node; - FTC_Manager manager; + FT_Error error; + FTC_GlyphSet gset; + FTC_GlyphNode node; + FTC_Manager manager; - FTC_Image_Queue img_queue; + FTC_ImageSet img_set; /* check for valid `desc' delayed to FT_Lru_Lookup() */ @@ -268,20 +266,20 @@ if ( !cache || !aglyph ) return FT_Err_Invalid_Argument; - *aglyph = 0; - queue = cache->root.last_queue; - img_queue = (FTC_Image_Queue)queue; - if ( !queue || memcmp( &img_queue->description, desc, sizeof ( *desc ) ) ) + *aglyph = 0; + gset = cache->root.last_gset; + img_set = (FTC_ImageSet)gset; + if ( !gset || memcmp( &img_set->description, desc, sizeof ( *desc ) ) ) { - error = FT_Lru_Lookup( cache->root.queues_lru, + error = FT_Lru_Lookup( cache->root.gsets_lru, (FT_LruKey)desc, - (FT_Pointer*)&queue ); - cache->root.last_queue = queue; + (FT_Pointer*)&gset ); + cache->root.last_gset = gset; if ( error ) goto Exit; } - error = FTC_Glyph_Queue_Lookup_Node( queue, gindex, &node ); + error = FTC_GlyphSet_Lookup_Node( gset, gindex, &node ); if ( error ) goto Exit; diff --git a/src/cache/ftcimage.h b/src/cache/ftcimage.h index 7fc967859..fbb2406c4 100644 --- a/src/cache/ftcimage.h +++ b/src/cache/ftcimage.h @@ -38,12 +38,12 @@ /* the glyph image queue type */ - typedef struct FTC_Image_QueueRec_ + typedef struct FTC_ImageSetRec_ { - FTC_Glyph_QueueRec root; - FTC_Image_Desc description; + FTC_GlyphSetRec root; + FTC_Image_Desc description; - } FTC_Image_QueueRec, *FTC_Image_Queue; + } FTC_ImageSetRec, *FTC_ImageSet; typedef struct FTC_Image_CacheRec_ diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c new file mode 100644 index 000000000..ab897d83b --- /dev/null +++ b/src/cache/ftcsbits.c @@ -0,0 +1,346 @@ +#include + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + LOCAL_FUNC_X + void ftc_sbit_chunk_node_destroy( FTC_ChunkNode node ) + { + FTC_ChunkSet cset = node->cset; + FT_Memory memory = cset->memory; + FT_UInt count = node->num_elements; + FTC_SBit sbit = (FTC_SBit)node->elements; + + for ( ; count > 0; sbit++, count-- ) + FREE( sbit->buffer ); + + FREE( node ); + } + + + static + FT_Error ftc_bitmap_copy( FT_Memory memory, + FT_Bitmap* source, + FTC_SBit target ) + { + FT_Error error; + FT_Int pitch = source->pitch; + FT_ULong size; + + if ( pitch < 0 ) + pitch = -pitch; + + size = (FT_ULong)( pitch * source->rows ); + + if ( !ALLOC( target->buffer, size ) ) + MEM_Copy( target->buffer, source->buffer, size ); + + return error; + } + + + LOCAL_FUNC_X + FT_Error ftc_sbit_chunk_node_new( FTC_ChunkSet cset, + FT_UInt index, + FTC_SBitChunk *anode ) + { + FT_Error error; + FT_Memory memory = cset->memory; + FTC_SBitSet sbitset = (FTC_SBitSet)cset; + FTC_SBitChunk node = 0; + FT_Face face; + FT_Size size; + + + /* allocate node */ + if ( ALLOC( node, sizeof ( *node ) ) ) + goto Exit; + + /* init its inner fields */ + error = FTC_ChunkNode_Init( FTC_CHUNKNODE(node), cset, index, 1 ); + if (error) + goto Exit; + + /* we will now load all glyph images */ + error = FTC_Manager_Lookup_Size( cset->manager, + &sbitset->description.font, + &face, &size ); + if ( !error ) + { + FT_UInt glyph_index = index * cset->chunk_size; + FT_UInt load_flags = FT_LOAD_DEFAULT; + FT_UInt image_type = sbitset->description.image_type; + FT_UInt count = node->num_elements; + FTC_SBit sbit = (FTC_SBit)node->elements; + + + if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap ) + { + if ( image_type & ftc_image_flag_monochrome ) + load_flags |= FT_LOAD_MONOCHROME; + + /* disable embedded bitmaps loading if necessary */ + if ( image_type & ftc_image_flag_no_sbits ) + load_flags |= FT_LOAD_NO_BITMAP; + } + else if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_outline ) + { + /* disable embedded bitmaps loading */ + load_flags |= FT_LOAD_NO_BITMAP; + + if ( image_type & ftc_image_flag_unscaled ) + { + FT_ERROR(( "FTC_SBit_Cache: cannot load vector outlines in a" + " sbit cache, please check your arguments !!\n" )); + error = FT_Err_Bad_Argument; + goto Exit; + } + } + + /* always render glyphs to bitmaps */ + load_flags |= FT_LOAD_RENDER; + + if ( image_type & ftc_image_flag_unhinted ) + load_flags |= FT_LOAD_NO_HINTING; + + 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++ ) + { + 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 advance; + + /* check that our values fit in 8-bit containers !! */ +#define CHECK_SCHAR(d) ( temp = (FT_SChar)d, temp == d ) +#define CHECK_BYTE(d) ( temp = (FT_Byte) d, temp == d ) + + advance = (slot->metrics.horiAdvance+32) >> 6; + + if ( CHECK_BYTE ( bitmap->rows ) && + CHECK_BYTE ( bitmap->width ) && + CHECK_SCHAR( bitmap->pitch ) && + CHECK_SCHAR( slot->bitmap_left ) && + CHECK_SCHAR( slot->bitmap_top ) && + CHECK_SCHAR( advance ) ) + { + sbit->width = (FT_Byte) bitmap->width; + sbit->height = (FT_Byte) bitmap->height; + sbit->pitch = (FT_SChar)bitmap->pitch; + sbit->left = (FT_SChar)slot->bitmap_left; + sbit->top = (FT_SChar)slot->bitmap_top; + sbit->advance = (FT_SChar)advance; + + /* 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 ); + } + } + } + else + sbit->buffer = 0; + } + + /* ignore the errors that might have occured there */ + /* we recognize unloaded glyphs with "sbit.buffer == 0" */ + error = 0; + } + + Exit: + if ( error && node ) + { + FREE( node->elements ); + FREE( node ); + } + + *anode = node; + return error; + } + + + /* this function is important because it is both part of */ + /* a FTC_ChunkSet_Class and a FTC_CacheNode_Class */ + /* */ + LOCAL_FUNC_X + FT_ULong ftc_sbit_chunk_node_size( FTC_SBitChunk node ) + { + FT_ULong size = 0; + FT_Glyph glyph = node->ft_glyph; + + + switch ( glyph->format ) + { + case ft_glyph_format_bitmap: + { + FT_BitmapGlyph bitg; + + + bitg = (FT_BitmapGlyph)glyph; + size = bitg->bitmap.rows * labs( bitg->bitmap.pitch ) + + sizeof ( *bitg ); + } + break; + + case ft_glyph_format_outline: + { + FT_OutlineGlyph outg; + + + outg = (FT_OutlineGlyph)glyph; + size = outg->outline.n_points * + ( sizeof( FT_Vector ) + sizeof ( FT_Byte ) ) + + outg->outline.n_contours * sizeof ( FT_Short ) + + sizeof ( *outg ); + } + break; + + default: + ; + } + + size += sizeof ( *node ); + return size; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE QUEUES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + LOCAL_FUNC_X + FT_Error ftc_image_set_init( FTC_ImageSet iset, + FTC_Image_Desc* type ) + { + iset->description = *type; + return 0; + } + + + LOCAL_FUNC_X + FT_Bool ftc_image_set_compare( FTC_ImageSet iset, + FTC_Image_Desc* type ) + { + return !memcmp( &iset->description, type, sizeof ( *type ) ); + } + + + FT_CPLUSPLUS( const FTC_ChunkSet_Class ) ftc_sbit_chunk_set_class = + { + sizeof( FTC_ImageSetRec ), + + (FTC_ChunkSet_InitFunc) ftc_image_set_init, + (FTC_ChunkSet_DoneFunc) 0, + (FTC_ChunkSet_CompareFunc) ftc_image_set_compare, + + (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new, + (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size, + (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE CACHE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CPLUSPLUS( const FTC_Glyph_Cache_Class ) ftc_sbit_chunk_cache_class = + { + { + sizeof( FTC_Image_CacheRec ), + (FTC_Cache_InitFunc) FTC_Glyph_Cache_Init, + (FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done + }, + (FTC_ChunkSet_Class*) &ftc_sbit_chunk_set_class + }; + + + FT_EXPORT_FUNC( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager, + FTC_Image_Cache* acache ) + { + return FTC_Manager_Register_Cache( + manager, + (FTC_Cache_Class*)&ftc_sbit_chunk_cache_class, + (FTC_Cache*)acache ); + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_Image_Cache_Lookup( FTC_Image_Cache cache, + FTC_Image_Desc* desc, + FT_UInt gindex, + FT_Glyph* aglyph ) + { + FT_Error error; + FTC_ChunkSet gset; + FTC_GlyphNode node; + FTC_Manager manager; + + FTC_ImageSet img_set; + + + /* check for valid `desc' delayed to FT_Lru_Lookup() */ + + if ( !cache || !aglyph ) + return FT_Err_Invalid_Argument; + + *aglyph = 0; + gset = cache->root.last_gset; + img_set = (FTC_ImageSet)gset; + if ( !gset || memcmp( &img_set->description, desc, sizeof ( *desc ) ) ) + { + error = FT_Lru_Lookup( cache->root.gsets_lru, + (FT_LruKey)desc, + (FT_Pointer*)&gset ); + cache->root.last_gset = gset; + if ( error ) + goto Exit; + } + + error = FTC_ChunkSet_Lookup_Node( gset, gindex, &node ); + if ( error ) + goto Exit; + + /* now compress the manager's cache pool if needed */ + manager = cache->root.root.manager; + if ( manager->num_bytes > manager->max_bytes ) + { + FTC_GlyphNode_Ref ( node ); + FTC_Manager_Compress( manager ); + FTC_GlyphNode_Unref ( node ); + } + + *aglyph = ((FTC_SBitChunk)node)->ft_glyph; + + Exit: + return error; + } + diff --git a/src/cache/ftcsbits.h b/src/cache/ftcsbits.h new file mode 100644 index 000000000..9e395ec1e --- /dev/null +++ b/src/cache/ftcsbits.h @@ -0,0 +1,97 @@ +/***************************************************************************/ +/* */ +/* ftcsbits.h */ +/* */ +/* a small-bitmaps cache (specification). */ +/* */ +/* Copyright 2000 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef FTCSBITS_H +#define FTCSBITS_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + /* handle to small bitmap */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /* handle to small bitmap cache */ + typedef struct FTC_SBit_CacheRec_* FTC_SBit_Cache; + + + /* format of small bitmaps */ + typedef enum FTC_SBit_Format_ + { + ftc_sbit_format_mono = 0, + ftc_sbit_format_aa256 = 1, + + } FTC_SBit_Format; + + + /* a compact structure used to hold a single small bitmap */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_SChar left; + FT_SChar top; + + FT_Byte format; + FT_SChar pitch; + FT_SChar xadvance; + FT_SChar yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + typedef struct FTC_SBitSetRec_ + { + FTC_ChunkSetRec root; + FTC_Image_Desc desc; + + } FTC_SBitSet; + + + typedef struct FTC_SBit_CacheRec_ + { + FTC_Chunk_CacheRec root; + + } FTC_SBit_CacheRec; + + + + FT_EXPORT_DEF( FT_Error ) + FTC_SBit_Cache_New( FTC_Manager manager, + FTC_SBit_Cache *acache ); + + + FT_EXPORT_DEF( FT_Error ) + FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache, + FTC_Image_Desc* desc, + FTC_SBit *sbit ); + + +#ifdef __cplusplus + } +#endif + + +#endif /* FTCSBITS_H */ + +/* END */ +