+++ /dev/null
-/***************************************************************************/
-/* */
-/* ftcglyph.c */
-/* */
-/* FreeType Glyph Image (FT_Glyph) cache (body). */
-/* */
-/* Copyright 2000-2001 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 <ft2build.h>
-#include FT_CACHE_H
-#include FT_CACHE_INTERNAL_GLYPH_H
-#include FT_ERRORS_H
-#include FT_LIST_H
-#include FT_INTERNAL_OBJECTS_H
-#include FT_INTERNAL_DEBUG_H
-
-#include "ftcerror.h"
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** GLYPH NODES *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
- /* 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_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;
- }
-
-
- /* Important: This function is called from the cache manager to */
- /* destroy a given cache node during `cache compression'. The */
- /* second argument is always `cache.cache_data'. Thus be */
- /* certain that the function FTC_Glyph_Cache_New() does indeed */
- /* set its `cache_data' field correctly, otherwise bad things */
- /* will happen! */
-
- FT_EXPORT_DEF( void )
- FTC_GlyphNode_Destroy( 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;
- 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 );
- }
-
-
- /* 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
- };
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** GLYPH SETS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
- FT_EXPORT_DEF( 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_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;
- }
-
-
- FT_EXPORT_DEF( void )
- FTC_GlyphSet_Destroy( FTC_GlyphSet gset )
- {
- FTC_Glyph_Cache cache = gset->cache;
- FTC_Manager manager = cache->root.manager;
- FT_List glyphs_lru = &manager->global_lru;
- FTC_GlyphNode* bucket = gset->buckets;
- FTC_GlyphNode* bucket_limit = bucket + gset->hash_size;
- FT_Memory memory = cache->root.memory;
-
- FTC_GlyphSet_Class* clazz = gset->clazz;
-
-
- /* for each bucket, free the list of glyph nodes */
- for ( ; bucket < bucket_limit; bucket++ )
- {
- FTC_GlyphNode node = bucket[0];
- FTC_GlyphNode next = 0;
- FT_ListNode lrunode;
-
-
- for ( ; node; node = next )
- {
- next = node->gset_next;
- lrunode = FTC_GLYPHNODE_TO_LRUNODE( node );
-
- manager->num_bytes -= clazz->size_node( node, gset );
- manager->num_nodes--;
-
- FT_List_Remove( glyphs_lru, lrunode );
-
- clazz->destroy_node( node, gset );
- }
-
- bucket[0] = 0;
- }
-
- if ( clazz->done )
- clazz->done( gset );
-
- FREE( gset->buckets );
- FREE( gset );
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
- FT_UInt glyph_index,
- FTC_GlyphNode *anode )
- {
- FTC_Glyph_Cache cache = gset->cache;
- FTC_Manager manager = cache->root.manager;
- FT_UInt hash_index = glyph_index % gset->hash_size;
- FTC_GlyphNode* bucket = gset->buckets + hash_index;
- FTC_GlyphNode* pnode = bucket;
- FTC_GlyphNode node;
- FT_Error error;
-
- FTC_GlyphSet_Class* clazz = gset->clazz;
-
-
- *anode = 0;
-
- for ( ;; )
- {
- node = *pnode;
- if ( !node )
- break;
-
- if ( (FT_UInt)node->glyph_index == glyph_index )
- {
- /* we found it! -- move glyph to start of the lists */
- *pnode = node->gset_next;
- node->gset_next = bucket[0];
- bucket[0] = node;
-
- FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
- *anode = node;
- return 0;
- }
- /* go to next node in bucket */
- pnode = &node->gset_next;
- }
-
- /* we didn't found the glyph image, we will now create a new one */
- error = clazz->new_node( gset, glyph_index, &node );
- if ( error )
- goto Exit;
-
- /* insert the node at the start of our bucket list */
- node->gset_next = bucket[0];
- bucket[0] = node;
-
- /* insert the node at the start the global LRU glyph list */
- FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
-
- manager->num_bytes += clazz->size_node( node, gset );
- manager->num_nodes++;
-
- if ( manager->num_bytes > manager->max_bytes )
- {
- FTC_GlyphNode_Ref ( node );
- FTC_Manager_Compress( manager );
- FTC_GlyphNode_Unref ( node );
- }
-
- *anode = node;
-
- Exit:
- return error;
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** 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 )
- {
- FTC_Glyph_Cache cache = FTC_GSET_LRU_GET_CACHE( lru );
- FT_Error error;
- FTC_GlyphSet gset;
-
-
- error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset );
- if ( !error )
- {
- /* good, now set the gset index within the gset object */
- gset->gset_index = (FT_UInt)( node - lru->nodes );
- node->root.data = gset;
- }
-
- 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 */