ref: dd33561ecb0cb0cf7459e49d11d53a55199f3891
dir: /src/cache/ftcchunk.c/
/***************************************************************************/ /* */ /* 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 <freetype/cache/ftcchunk.h> #include <freetype/fterrors.h> #include <freetype/internal/ftobjs.h> #include <freetype/internal/ftlist.h> #include <freetype/fterrors.h> /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GLYPH NODES *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* create a new chunk node, setting its cache index and ref count */ FT_EXPORT_FUNC( FT_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 ); FT_Error error = 0; data->cache_index = (FT_UShort) cache->root.cache_index; data->ref_count = (FT_Short) 0; node->cset = cset; node->cset_index = (FT_UShort) index; node->num_elements = (index+1 < cset->num_chunks) ? cset->element_count : cset->element_max - cset->element_count*index; if (alloc) { /* allocate elements array */ FT_Memory memory; memory = cache->root.memory; error = MEM_Alloc( node->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 ); } 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, 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( 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; } 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->chunks; FTC_ChunkNode* bucket_limit = bucket + cset->num_chunks; FT_Memory memory = cache->root.memory; FTC_ChunkSet_Class* clazz = cset->clazz; /* for each bucket, free the list of glyph nodes */ for ( ; bucket < bucket_limit; bucket++ ) { FTC_ChunkNode node = bucket[0]; FT_ListNode lrunode; lrunode = FTC_CHUNKNODE_TO_LRUNODE( node ); manager->num_bytes -= clazz->size_node( node ); manager->num_nodes --; FT_List_Remove( glyphs_lru, lrunode ); clazz->destroy_node( node ); bucket[0] = 0; } if ( clazz->done ) clazz->done( cset ); FREE( cset->chunks ); FREE( cset ); } FT_EXPORT_FUNC( FT_Error ) FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset, FT_UInt glyph_index, FTC_ChunkNode *anode, FT_UInt *aindex ) { FTC_Chunk_Cache cache = cset->cache; FTC_Manager manager = cache->root.manager; FT_Error error = 0; FTC_ChunkSet_Class* clazz = cset->clazz; *anode = 0; if (glyph_index >= cset->element_max) error = FT_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; *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 = cset; } 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; 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_FUNC( void ) FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache ) { /* discard glyph sets */ FT_Lru_Done( cache->csets_lru ); }