diff options
author | David Turner <david@freetype.org> | 2000-09-19 01:11:11 +0000 |
---|---|---|
committer | David Turner <david@freetype.org> | 2000-09-19 01:11:11 +0000 |
commit | ebdce8344a089963635473c73cb7cbc967bc6a7e (patch) | |
tree | 4b0454128443c6a4cd2dfb2b9aedfea7a367389f /src/cache/ftcimage.c | |
parent | 58e932157b02295427db073e19a36cbae33213e6 (diff) |
updated the cache sub-system. Major internal rewrite
please be aware that major bug persist..
Diffstat (limited to 'src/cache/ftcimage.c')
-rw-r--r-- | src/cache/ftcimage.c | 609 |
1 files changed, 143 insertions, 466 deletions
diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c index 5ea6ea37..5f044e06 100644 --- a/src/cache/ftcimage.c +++ b/src/cache/ftcimage.c @@ -1,146 +1,58 @@ -/***************************************************************************/ -/* */ -/* ftcimage.c */ -/* */ -/* FreeType Image 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 <cache/ftcimage.h> -#include <freetype/fterrors.h> -#include <freetype/internal/ftobjs.h> -#include <freetype/internal/ftlist.h> -#include <freetype/fterrors.h> - - - /**************************************************************************/ - /**************************************************************************/ - /***** *****/ - /***** IMAGE NODE MANAGEMENT *****/ - /***** *****/ - /***** For now, we simply ALLOC/FREE the FTC_ImageNode. However, it *****/ - /***** certainly is a good idea to use a chunk manager in the future *****/ - /***** in order to reduce memory waste resp. fragmentation. *****/ - /***** *****/ - /**************************************************************************/ - /**************************************************************************/ +#ifdef FT_FLAT_COMPILE +# include "ftcimage.h" +#else +# include <cache/ftcimage.h> +#endif + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ - - static - FT_Error FTC_ImageNode_New( FTC_Image_Cache cache, - FTC_ImageNode* anode ) - { - FT_Error error; - FT_Memory memory = cache->memory; - FTC_ImageNode node; - - - *anode = 0; - if ( !ALLOC( node, sizeof ( *node ) ) ) - *anode = node; - - return error; - } - - - static - void FTC_ImageNode_Done( FTC_Image_Cache cache, - FTC_ImageNode node ) - { - /* for now, we simply discard the node; we may later add a chunk */ - /* manager to the image cache. */ - FT_Memory memory = cache->memory; - - - FREE( node ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GLYPH IMAGE QUEUES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - + /* this is a simple glyph image destructor, which is called exclusively */ + /* from the CacheQueue object */ LOCAL_FUNC_X - void ftc_done_glyph_image( FTC_Image_Queue queue, - FTC_ImageNode node ) + void ftc_glyph_image_node_destroy( FTC_GlyphNode node, + FTC_Glyph_Queue queue ) { - FT_UNUSED( queue ); - - FT_Done_Glyph( FTC_IMAGENODE_GET_GLYPH( node ) ); - } - - - LOCAL_FUNC_X - FT_ULong ftc_size_bitmap_image( FTC_Image_Queue queue, - FTC_ImageNode node ) - { - FT_Long pitch; - FT_BitmapGlyph glyph; - - FT_UNUSED( queue ); - - - glyph = (FT_BitmapGlyph)FTC_IMAGENODE_GET_GLYPH(node); - pitch = glyph->bitmap.pitch; - if ( pitch < 0 ) - pitch = -pitch; - - return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) ); - } - - - LOCAL_FUNC_X - FT_ULong ftc_size_outline_image( FTC_Image_Queue queue, - FTC_ImageNode node ) - { - FT_OutlineGlyph glyph; - FT_Outline* outline; + FT_Memory memory = queue->memory; - FT_UNUSED( queue ); - - - glyph = (FT_OutlineGlyph)FTC_IMAGENODE_GET_GLYPH( node ); - outline = &glyph->outline; - - return (FT_ULong)( - outline->n_points * ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) + - outline->n_contours * sizeof ( FT_Short ) + - sizeof( *glyph ) ); + FT_Done_Glyph( FTC_GLYPHNODE_GET_GLYPH( node ) ); + FREE( node ); } LOCAL_FUNC_X - FT_Error ftc_init_glyph_image( FTC_Image_Queue queue, - FTC_ImageNode node ) + FT_Error ftc_glyph_image_node_new( FTC_Glyph_Queue queue, + FT_UInt glyph_index, + FTC_GlyphNode *anode ) { - FT_Face face; - FT_Size size; - FT_Error error; + FT_Memory memory = queue->memory; + FTC_Image_Queue imageq = (FTC_Image_Queue)queue; + FT_Error error; + FTC_GlyphNode node = 0; + FT_Face face; + FT_Size size; + /* allocate node */ + if ( ALLOC( node, sizeof(*node) ) ) + goto Exit; + + /* init its inner fields */ + FTC_GlyphNode_Init( node, queue, glyph_index ); + /* we will now load the glyph image */ error = FTC_Manager_Lookup_Size( queue->manager, - &queue->descriptor.size, + &imageq->description.font, &face, &size ); if ( !error ) { - FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node ); + FT_UInt glyph_index = node->glyph_index; FT_UInt load_flags = FT_LOAD_DEFAULT; - FT_UInt image_type = queue->descriptor.image_type; + FT_UInt image_type = imageq->description.image_type; if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap ) { @@ -179,372 +91,133 @@ error = FT_Get_Glyph( face->glyph, &glyph ); if ( !error ) - FTC_IMAGENODE_SET_GLYPH( node, glyph ); + FTC_GLYPHNODE_SET_GLYPH( node, glyph ); } else error = FT_Err_Invalid_Argument; } } - return error; - } - - - FT_CPLUSPLUS( const FTC_Image_Class ) ftc_bitmap_image_class = - { - ftc_init_glyph_image, - ftc_done_glyph_image, - ftc_size_bitmap_image - }; - - FT_CPLUSPLUS( const FTC_Image_Class ) ftc_outline_image_class = - { - ftc_init_glyph_image, - ftc_done_glyph_image, - ftc_size_outline_image - }; - - - static - FT_Error FTC_Image_Queue_New( FTC_Image_Cache cache, - FTC_Image_Desc* desc, - FTC_Image_Queue* aqueue ) - { - FT_Error error; - FT_Memory memory = cache->memory; - FTC_Manager manager = cache->manager; - FTC_Image_Queue queue = 0; - - const FTC_Image_Class* clazz; - - - *aqueue = 0; - if ( ALLOC( queue, sizeof ( *queue ) ) ) - goto Exit; - - queue->cache = cache; - queue->manager = manager; - queue->memory = memory; - queue->descriptor = *desc; - queue->hash_size = 64; - - if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) ) - goto Exit; - - switch ( FTC_IMAGE_FORMAT( desc->image_type ) ) - { - case ftc_image_format_bitmap: - clazz = &ftc_bitmap_image_class; - break; - - case ftc_image_format_outline: - clazz = &ftc_outline_image_class; - break; - - default: - /* invalid image type! */ - error = FT_Err_Invalid_Argument; - goto Exit; - } - - queue->clazz = (FTC_Image_Class*)clazz; - *aqueue = queue; - Exit: - if ( error ) - FREE( queue ); + if (error && node) + FREE(node); + *anode = node; return error; - } + } - static - void FTC_Image_Queue_Done( FTC_Image_Queue queue ) + /* this function is important, because it is both part of */ + /* a FTC_Glyph_Queue_Class and a FTC_CacheNode_Class */ + /* */ + LOCAL_FUNC_X + FT_ULong ftc_glyph_image_node_size( FTC_GlyphNode node ) { - FTC_Image_Cache cache = queue->cache; - FT_List glyphs_lru = &cache->glyphs_lru; - FT_List bucket = queue->buckets; - FT_List bucket_limit = bucket + queue->hash_size; - FT_Memory memory = cache->memory; + FT_ULong size = 0; + FT_Glyph glyph = FTC_GLYPHNODE_GET_GLYPH(node); - - /* for each bucket, free the list of image nodes */ - for ( ; bucket < bucket_limit; bucket++ ) + switch (glyph->format) { - FT_ListNode node = bucket->head; - FT_ListNode next = 0; - FT_ListNode lrunode; - FTC_ImageNode inode; - - - for ( ; node; node = next ) - { - next = node->next; - inode = (FTC_ImageNode)node; - lrunode = FTC_IMAGENODE_TO_LISTNODE( inode ); - - cache->num_bytes -= queue->clazz->size_image( queue, inode ) + - sizeof( FTC_ImageNodeRec ); + case ft_glyph_format_bitmap: + { + FT_BitmapGlyph bitg; + + bitg = (FT_BitmapGlyph)glyph; + size = bitg->bitmap.rows * labs(bitg->bitmap.pitch) + + sizeof(*bitg); + } + break; - queue->clazz->done_image( queue, inode ); - FT_List_Remove( glyphs_lru, lrunode ); + 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; - FTC_ImageNode_Done( cache, inode ); - } - - bucket->head = bucket->tail = 0; - } - - FREE( queue->buckets ); - FREE( queue ); - } - - - static - FT_Error FTC_Image_Queue_Lookup_Node( FTC_Image_Queue queue, - FT_UInt glyph_index, - FTC_ImageNode* anode ) - { - FTC_Image_Cache cache = queue->cache; - FT_UInt hash_index = glyph_index % queue->hash_size; - FT_List bucket = queue->buckets + hash_index; - FT_ListNode node; - FT_Error error; - FTC_ImageNode inode; - - - *anode = 0; - for ( node = bucket->head; node; node = node->next ) - { - FT_UInt gindex; - - inode = (FTC_ImageNode)node; - gindex = FTC_IMAGENODE_GET_GINDEX( inode ); - - if ( gindex == glyph_index ) - { - /* we found it! -- move glyph to start of the list */ - FT_List_Up( bucket, node ); - FT_List_Up( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) ); - *anode = inode; - return 0; - } - } - - /* we didn't found the glyph image, we will now create a new one */ - error = FTC_ImageNode_New( queue->cache, &inode ); - if ( error ) - goto Exit; - - /* set the glyph and queue indices in the image node */ - FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index ); - - error = queue->clazz->init_image( queue, inode ); - if ( error ) - { - FTC_ImageNode_Done( queue->cache, inode ); - goto Exit; + default: + ; } - - /* insert the node at the start of our bucket list */ - FT_List_Insert( bucket, (FT_ListNode)inode ); - - /* insert the node at the start the global LRU glyph list */ - FT_List_Insert( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) ); - - cache->num_bytes += queue->clazz->size_image( queue, inode ) + - sizeof( FTC_ImageNodeRec ); - - *anode = inode; - - Exit: - return error; + size += sizeof(*node); + return size; } - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** IMAGE CACHE CALLBACKS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define FTC_QUEUE_LRU_GET_CACHE( lru ) \ - ( (FTC_Image_Cache)(lru)->user_data ) -#define FTC_QUEUE_LRU_GET_MANAGER( lru ) \ - FTC_QUEUE_LRU_GET_CACHE( lru )->manager -#define FTC_LRUNODE_QUEUE( node ) \ - ( (FTC_Image_Queue)(node)->root.data ) + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE QUEUES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ LOCAL_FUNC_X - FT_Error ftc_image_cache_init_queue( FT_Lru lru, - FT_LruNode node ) + FT_Error ftc_image_queue_init( FTC_Image_Queue queue, + FTC_Image_Desc* type ) { - FTC_Image_Cache cache = FTC_QUEUE_LRU_GET_CACHE( lru ); - FTC_Image_Desc* desc = (FTC_Image_Desc*)node->key; - FT_Error error; - FTC_Image_Queue queue; - - - error = FTC_Image_Queue_New( cache, desc, &queue ); - if ( !error ) - { - /* good, now set the queue index within the queue object */ - queue->index = node - lru->nodes; - node->root.data = queue; - } - - return error; + queue->description = *type; + return 0; } LOCAL_FUNC_X - void ftc_image_cache_done_queue( FT_Lru lru, - FT_LruNode node ) + FT_Bool ftc_image_queue_compare( FTC_Image_Queue queue, + FTC_Image_Desc* type ) { - FTC_Image_Queue queue = FTC_LRUNODE_QUEUE( node ); - - FT_UNUSED( lru ); - - - FTC_Image_Queue_Done( queue ); + return !memcmp( &queue->description, type, sizeof(*type) ); } + - - LOCAL_FUNC_X - FT_Bool ftc_image_cache_compare_queue( FT_LruNode node, - FT_LruKey key ) + FT_CPLUSPLUS(const FTC_Glyph_Queue_Class) ftc_glyph_image_queue_class = { - FTC_Image_Queue queue = FTC_LRUNODE_QUEUE( node ); - FTC_Image_Desc* desc2 = (FTC_Image_Desc*)key; - FTC_Image_Desc* desc1 = &queue->descriptor; + sizeof( FTC_Image_QueueRec ), - - return ( desc1->size.face_id == desc2->size.face_id && - desc1->size.pix_width == desc2->size.pix_width && - desc1->size.pix_height == desc2->size.pix_height && - desc1->image_type == desc2->image_type ); - } - - - FT_CPLUSPLUS( const FT_Lru_Class ) ftc_image_queue_lru_class = - { - sizeof( FT_LruRec ), - ftc_image_cache_init_queue, - ftc_image_cache_done_queue, - 0, /* no flush */ - ftc_image_cache_compare_queue + (FTC_Glyph_Queue_InitFunc) ftc_image_queue_init, + (FTC_Glyph_Queue_DoneFunc) 0, + (FTC_Glyph_Queue_CompareFunc) ftc_image_queue_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 }; - /* compress image cache if necessary, i.e., discard all old glyph images */ - /* until `cache.num_bytes' is less than `cache.max_bytes'. Note that */ - /* this function will avoid to remove `new_node'. */ - static - void FTC_Image_Cache_Compress( FTC_Image_Cache cache, - FTC_ImageNode new_node ) - { - while ( cache->num_bytes > cache->max_bytes ) - { - FT_ListNode cur; - FTC_Image_Queue queue; - FT_UInt glyph_index; - FT_UInt hash_index; - FT_UInt queue_index; - FT_ULong size; - FTC_ImageNode inode; - + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE CACHE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ - /* exit our loop if there isn't any glyph image left, or if */ - /* we reached the newly created node (which happens always at the */ - /* start of the list) */ - - cur = cache->glyphs_lru.tail; - inode = FTC_LISTNODE_TO_IMAGENODE( cur ); - if ( !cur || inode == new_node ) - break; - - glyph_index = FTC_IMAGENODE_GET_GINDEX( inode ); - queue_index = FTC_IMAGENODE_GET_QINDEX( inode ); - queue = (FTC_Image_Queue)cache->queues_lru-> - nodes[queue_index].root.data; - hash_index = glyph_index % queue->hash_size; - size = queue->clazz->size_image( queue, inode ) + - sizeof(FTC_ImageNodeRec); - - FT_List_Remove( &cache->glyphs_lru, cur ); - FT_List_Remove( queue->buckets + hash_index, (FT_ListNode)inode ); - queue->clazz->done_image( queue, inode ); - FTC_ImageNode_Done( cache, inode ); - - cache->num_bytes -= size; - } - } - FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager, - FT_ULong max_bytes, - FTC_Image_Cache* acache ) + FT_CPLUSPLUS(const FTC_Glyph_Cache_Class) ftc_glyph_image_cache_class = { - FT_Error error; - FT_Memory memory; - FTC_Image_Cache cache; - - - if ( !manager ) - return FT_Err_Invalid_Cache_Handle; - - if ( !acache || !manager->library ) - return FT_Err_Invalid_Argument; - - *acache = 0; - memory = manager->library->memory; - - if ( ALLOC( cache, sizeof ( *cache ) ) ) - goto Exit; - - cache->manager = manager; - cache->memory = manager->library->memory; - cache->max_bytes = max_bytes; - - error = FT_Lru_New( &ftc_image_queue_lru_class, - FTC_MAX_IMAGE_QUEUES, - cache, - memory, - 1, /* pre_alloc == TRUE */ - &cache->queues_lru ); - if ( error ) - goto Exit; - - *acache = cache; - - Exit: - if ( error ) - FREE( cache ); - - return error; - } + { + sizeof( FTC_Glyph_CacheRec ), + (FTC_Cache_InitFunc) FTC_Glyph_Cache_Init, + (FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done + }, + (FTC_Glyph_Queue_Class*) &ftc_glyph_image_queue_class + }; - FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache ) + FT_EXPORT_FUNC( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager, + FTC_Image_Cache* acache ) { - FT_Memory memory; - - - if ( !cache ) - return; - - memory = cache->memory; - - /* discard image queues */ - FT_Lru_Done( cache->queues_lru ); - - /* discard cache */ - FREE( cache ); + return FTC_Manager_Register_Cache( + manager, + (FTC_Cache_Class*)&ftc_glyph_image_cache_class, + (FTC_Cache*)acache ); } - + FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_Lookup( FTC_Image_Cache cache, @@ -553,43 +226,47 @@ FT_Glyph* aglyph ) { FT_Error error; - FTC_Image_Queue queue; - FTC_ImageNode inode; + FTC_Glyph_Queue queue; + FTC_GlyphNode inode; + FTC_Manager manager; + FTC_Image_Queue img_queue; /* check for valid `desc' delayed to FT_Lru_Lookup() */ if ( !cache || !aglyph ) return FT_Err_Invalid_Argument; - *aglyph = 0; - queue = cache->last_queue; - if ( !queue || - queue->descriptor.size.face_id != desc->size.face_id || - queue->descriptor.size.pix_width != desc->size.pix_width || - queue->descriptor.size.pix_height != desc->size.pix_height || - queue->descriptor.image_type != desc->image_type ) + *aglyph = 0; + queue = cache->root.last_queue; + img_queue = (FTC_Image_Queue)queue; + if ( !queue || memcmp( &img_queue->description, desc, sizeof(*desc) ) ) { - error = FT_Lru_Lookup( cache->queues_lru, + error = FT_Lru_Lookup( cache->root.queues_lru, (FT_LruKey)desc, (FT_Pointer*)&queue ); - cache->last_queue = queue; + cache->root.last_queue = queue; if ( error ) goto Exit; } - error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode ); + error = FTC_Glyph_Queue_Lookup_Node( queue, gindex, &inode ); if ( error ) goto Exit; - if (cache->num_bytes > cache->max_bytes) - FTC_Image_Cache_Compress( cache, inode ); + /* now compress the manager's cache pool if needed */ + manager = cache->root.root.manager; + if (manager->num_bytes > manager->max_bytes) + { + FTC_GlyphNode_Ref(inode); + FTC_Manager_Compress( manager ); + FTC_GlyphNode_Unref(inode); + } - *aglyph = FTC_IMAGENODE_GET_GLYPH( inode ); + *aglyph = FTC_GLYPHNODE_GET_GLYPH( inode ); Exit: return error; } -/* END */ |