From 3b2c50eb3b7863131ea18350a3ae5d48fbc567b9 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 23 Aug 2000 21:11:13 +0000 Subject: [PATCH] completing the FreeType Cache subsystem files --- CHANGES | 4 + include/freetype/ftcache.h | 451 ++++++++++++++++++++++++++++++ src/cache/ftcache.c | 36 +++ src/cache/ftcimage.c | 545 +++++++++++++++++++++++++++++++++++-- src/cache/ftcimage.h | 67 ++--- src/cache/ftcmanag.c | 31 ++- src/cache/ftcmanag.h | 45 +-- src/cache/ftlru.c | 2 + src/cache/ftlru.h | 5 + src/cache/rules.mk | 70 +++++ 10 files changed, 1141 insertions(+), 115 deletions(-) create mode 100644 include/freetype/ftcache.h create mode 100644 src/cache/ftcache.c create mode 100644 src/cache/rules.mk diff --git a/CHANGES b/CHANGES index aaa7de5e6..339d5b451 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ LATEST CHANGES + - added the cache sub-system. See as well as the + sources in "src/cache". Note that it compiles but is still untested + for now .. + - updated "docs/docmaker.py", a draft API reference is available at http://www.freetype.org/ft2api.html diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h new file mode 100644 index 000000000..37ec8adab --- /dev/null +++ b/include/freetype/ftcache.h @@ -0,0 +1,451 @@ +/***************************************************************************/ +/* */ +/* ftcache.h */ +/* */ +/* FreeType Cache subsystem */ +/* */ +/* Copyright 1996-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 FTCACHE_H +#define FTCACHE_H + +#include + + + + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + /***** *****/ + /***** BASIC TYPE DEFINITIONS *****/ + /***** *****/ + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + + + + /************************************************************************** + * + * + * FTC_FaceID + * + * + * a generic pointer type that is used to identity face objects. + * the content of such objects is application-dependent + * + **************************************************************************/ + + typedef FT_Pointer FTC_FaceID; + + + + /************************************************************************** + * + * + * FTC_Face_Requester + * + * + * a callback function provided by client applications. It is used + * to translate a given FTC_FaceID into a new valid FT_Face object + * + * + * face_id :: the face id to resolve + * library :: handle to a FreeType library object + * data :: application-provided request data + * + * + * aface :: a new FT_Face handle + * + * + * Error code. 0 means success + * + **************************************************************************/ + + typedef FT_Error (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface ); + + + /************************************************************************** + * + * + * FTC_SizeRec + * + * + * A simple structure used to describe a given "font size" to the + * cache manager + * + * + * face_id :: id of face to use + * pix_width :: character width in integer pixels + * pix_height :: character height in integer pixels + * + **************************************************************************/ + + typedef struct FTC_SizeRec_ + { + FTC_FaceID face_id; + FT_UShort pix_width; + FT_UShort pix_height; + + } FTC_SizeRec; + + + /************************************************************************** + * + * + * FTC_SizeID + * + * + * A simple handle to a FTC_SizeRec structure + * + **************************************************************************/ + + typedef FTC_SizeRec* FTC_SizeID; + + + + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + /***** *****/ + /***** CACHE MANAGER OBJECT *****/ + /***** *****/ + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + + + + + /************************************************************************** + * + * + * FTC_Manager + * + * + * This object is used to cache one or more FT_Face object, along with + * corresponding FT_Size objects. + * + **************************************************************************/ + + typedef struct FTC_ManagerRec_* FTC_Manager; + + + /************************************************************************** + * + * + * FTC_Manager_New + * + * + * Create a new cache manager. + * + * + * library :: the parent FreeType library handle to use + * + * requester :: an application-provided callback used to translate + * face IDs into real FT_Face objects + * + * req_data :: a generic pointer that is passed to the requester + * each time it is called (see FTC_Face_Requester) + * + * + * amanager :: handle to new manager object. 0 in case of failure + * + * + * Error code. 0 means success + * + **************************************************************************/ + + FT_EXPORT_DEF( FT_Error ) FTC_Manager_New( FT_Library library, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager* amanager ); + + + + /************************************************************************** + * + * + * FTC_Manager_Reset + * + * + * Empty a given cache manager. This simply gets rid of all the + * currently cached FT_Face & FT_Size objects within the manager + * + * + * manager :: handle to manager + * + **************************************************************************/ + + FT_EXPORT_DEF( void ) FTC_Manager_Reset( FTC_Manager manager ); + + + /************************************************************************** + * + * + * FTC_Manager_Done + * + * + * destroys a given manager after emptying it.. + * + * + * manager :: handle to target cache manager object + * + **************************************************************************/ + + FT_EXPORT_DEF( void ) FTC_Manager_Done( FTC_Manager manager ); + + + /************************************************************************** + * + * + * FTC_Manager_Lookup_Face + * + * + * retrieves the FT_Face that corresponds to a given face ID through + * a cache manager. + * + * + * manager :: handle to cache manager + * face_id :: ID of face object + * + * + * aface :: handle to face object + * + * + * Error code. 0 means success + * + * + * The returned FT_Face object is always owned by the manager, you + * should never try to discard it yourself.. + * + * The FT_Face object doesn't necessarily have a current size object + * (i.e. face->size can be 0). If you need a specific "font size", + * use FTC_Manager_Lookup_Size instead.. + * + * Never change the face's transform (i.e. NEVER CALL FT_Set_Transform) + * on a returned face. If you need to transform glyphs, do it yourself + * after glyph loading.. + * + **************************************************************************/ + + FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face* aface ); + + + /************************************************************************** + * + * + * FTC_Manager_Lookup_Size + * + * + * retrieves the FT_Face & FT_Size that correspond to a given + * FTC_SizeID + * + * + * manager :: handle to cache manager. + * size_id :: ID of the "font size" to use + * + * + * aface :: ptr to handle to face object. Set to 0 if you don't need it + * asize :: ptr to handle to size object. Set to 0 if you don't need it + * + * + * Error code. 0 means success + * + * + * The returned FT_Face object is always owned by the manager, you + * should never try to discard it yourself.. + * + * Never change the face's transform (i.e. NEVER CALL FT_Set_Transform) + * on a returned face. If you need to transform glyphs, do it yourself + * after glyph loading.. + * + * The returned FT_Size object is always owned by the manager, you + * should never try to discard it, NEVER CHANGE ITS SETTINGS THROUGH + * FT_Set_Pixel_Sizes OR FT_Set_Char_Size !! + * + * The returned size object is the face's current size, which means + * that you can call FT_Load_Glyph with the face if you need to.. + * + **************************************************************************/ + + FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_SizeID size_id, + FT_Face* aface, + FT_Size* asize ); + + + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + + + /************************************************************************** + * + * + * FTC_Image_Type + * + * + * An enumeration used to list the types of glyph images found in a + * glyph image cache. + * + * + * ftc_image_mono :: monochrome bitmap glyphs + * ftc_image_grays :: anti-aliased bitmap glyphs + * ftc_image_outline :: scaled (and hinted) outline glyphs + * ftc_master_outline :: unscaled original outline glyphs + * + * + * other types may be defined in the future + * + **************************************************************************/ + + typedef enum FTC_Image_Type_ + { + ftc_image_mono = 0, /* monochrome bitmap */ + ftc_image_grays, /* anti-aliased bitmap */ + ftc_image_outline, /* scaled outline */ + ftc_image_master_outline /* original outline */ + + } FTC_Image_Type; + + + /************************************************************************** + * + * + * FTC_Image_Desc + * + * + * A simple structure used to describe a given glyph image category + * + * + * size :: a FTC_SizeRec used to describe the glyph's face & size + * image_type :: the glyph image's type + * + **************************************************************************/ + + typedef struct FTC_Image_Desc_ + { + FTC_SizeRec size; + FT_UInt image_type; + + } FTC_Image_Desc; + + + + /************************************************************************** + * + * + * FTC_Image_Cache + * + * + * A handle to an glyph image cache object.. They are designed to + * hold many distinct glyph images, while not exceeding a certain + * memory threshold.. + * + **************************************************************************/ + + typedef struct FTC_Image_CacheRec_* FTC_Image_Cache; + + + + /************************************************************************** + * + * + * FTC_Image_Cache_New + * + * + * Create a new glyph image cache. + * + * + * manager :: parent manager for the image cache + * + * max_bytes :: the maximum amount of memory that will be used to + * store glyph images + * + * + * acache :: handle to new glyph image cache object + * + * + * Error code. 0 means success + * + **************************************************************************/ + + FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager, + FT_ULong max_bytes, + FTC_Image_Cache* acache ); + + /************************************************************************** + * + * + * FTC_Image_Cache_Done + * + * + * Destroys a given glyph image cache (and all glyphs within it). + * + * + * manager :: parent manager for the image cache + * + **************************************************************************/ + + FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache ); + + + /************************************************************************** + * + * + * FTC_Image_Cache_Lookup + * + * + * Retrieve a given glyph image from a glyph image cache. + * + * + * cache :: handle to source glyph image cache + * desc :: pointer to a glyph image descriptor + * gindex :: index of glyph to retrieve + * + * + * aglyph :: the corresponding FT_Glyph object. 0 in case of failure + * + * + * Error code. 0 means success + * + * + * the returned glyph is owned and manager by the glyph image cache, + * never try to transform or discard it manually. You can however + * create a copy with FT_Glyph_Copy and modify the new one at will. + * + * Because the glyph image cache limits the total amount of memory + * 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 ); + + +#endif /* FTCACHE_H */ diff --git a/src/cache/ftcache.c b/src/cache/ftcache.c new file mode 100644 index 000000000..a56e47625 --- /dev/null +++ b/src/cache/ftcache.c @@ -0,0 +1,36 @@ +/***************************************************************************/ +/* */ +/* ftcache.c */ +/* */ +/* The FreeType Caching sub-system */ +/* */ +/* Copyright 1996-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. */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef FT_FLAT_COMPILE + +#include "ftlru.c" +#include "ftcmanag.c" +#include "ftcimage.c" + +#else + +#include +#include +#include + +#endif + + +/* END */ diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c index d2df6a6c0..e73b9da7a 100644 --- a/src/cache/ftcimage.c +++ b/src/cache/ftcimage.c @@ -17,6 +17,59 @@ #include +#include +#include +#include + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** 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/fragmentation *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + 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 *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + static void ftc_done_glyph_image( FTC_Image_Queue queue, @@ -43,7 +96,7 @@ if ( pitch < 0 ) pitch = -pitch; - return (FT_ULong)(pitch * glyph->bitmap->rows + sizeof ( *glyph ) ); + return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) ); } @@ -51,7 +104,6 @@ FT_ULong ftc_size_outline_image( FTC_Image_Queue queue, FTC_ImageNode node ) { - FT_Long pitch; FT_OutlineGlyph glyph; FT_Outline* outline; @@ -68,14 +120,6 @@ } - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** MONOCHROME BITMAP CALLBACKS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - static FT_Error ftc_init_mono_image( FTC_Image_Queue queue, FTC_ImageNode node ) @@ -84,20 +128,19 @@ FT_Size size; FT_Error error; - error = FTC_Manager_Lookup_Size( queue->manager, - &queue->size_rec, + &queue->descriptor.size, &face, &size ); if ( !error ) { - FT_UInt glyph_index = FTC_IMAGENODE_GINDEX( node ); + FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node ); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME ); if ( !error ) { - if ( face->glyph->format != ft_image_format_bitmap || + if ( face->glyph->format != ft_glyph_format_bitmap || face->glyph->bitmap.pixel_mode != ft_pixel_mode_mono ) { /* there is no monochrome glyph for this font! */ @@ -129,21 +172,21 @@ error = FTC_Manager_Lookup_Size( queue->manager, - &queue->size_rec, + &queue->descriptor.size, &face, &size ); if ( !error ) { - FT_UInt glyph_index = FTC_IMAGENODE_GINDEX( node ); + FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node ); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER ); if ( !error ) { - if ( face->glyph->format != ft_image_format_bitmap || + if ( face->glyph->format != ft_glyph_format_bitmap || face->glyph->bitmap.pixel_mode != ft_pixel_mode_grays ) { - /* there is no monochrome glyph for this font! */ + /* there is no anti-aliased glyph for this font! */ error = FT_Err_Invalid_Glyph_Index; } else @@ -162,4 +205,470 @@ } + static + FT_Error ftc_init_outline_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_Face face; + FT_Size size; + FT_Error error; + + + error = FTC_Manager_Lookup_Size( queue->manager, + &queue->descriptor.size, + &face, &size ); + if ( !error ) + { + FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node ); + + + error = FT_Load_Glyph( face, glyph_index, + FT_LOAD_NO_BITMAP ); + if ( !error ) + { + if ( face->glyph->format != ft_glyph_format_outline ) + { + /* there is no outline glyph for this font! */ + error = FT_Err_Invalid_Glyph_Index; + } + else + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if ( !error ) + FTC_IMAGENODE_SET_GLYPH( node, glyph ); + } + } + } + return error; + } + + + + static + FT_Error ftc_init_master_outline_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_Face face; + FT_Size size; + FT_Error error; + + + error = FTC_Manager_Lookup_Size( queue->manager, + &queue->descriptor.size, + &face, &size ); + if ( !error ) + { + FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node ); + + + error = FT_Load_Glyph( face, glyph_index, + FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); + if ( !error ) + { + if ( face->glyph->format != ft_glyph_format_outline ) + { + /* there is no outline glyph for this font! */ + error = FT_Err_Invalid_Glyph_Index; + } + else + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if ( !error ) + FTC_IMAGENODE_SET_GLYPH( node, glyph ); + } + } + } + return error; + } + + + static + const FTC_Image_Class ftc_mono_image_class = + { + ftc_init_mono_image, + ftc_done_glyph_image, + ftc_size_bitmap_image + }; + + static + const FTC_Image_Class ftc_gray_image_class = + { + ftc_init_gray_image, + ftc_done_glyph_image, + ftc_size_bitmap_image + }; + + static + const FTC_Image_Class ftc_outline_image_class = + { + ftc_init_outline_image, + ftc_done_glyph_image, + ftc_size_outline_image + }; + + static + const FTC_Image_Class ftc_master_outline_image_class = + { + ftc_init_master_outline_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 = 32; + + if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) ) + goto Exit; + + switch (desc->image_type) + { + case ftc_image_mono: + clazz = &ftc_mono_image_class; + break; + + case ftc_image_grays: + clazz = &ftc_gray_image_class; + break; + + case ftc_image_outline: + clazz = &ftc_outline_image_class; + break; + + case ftc_image_master_outline: + clazz = &ftc_master_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 ); + + return error; + } + + + static + void FTC_Image_Queue_Done( FTC_Image_Queue queue ) + { + 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; + + /* for each bucket, free the list of image nodes */ + for ( ; bucket < bucket_limit; bucket++ ) + { + 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); + + queue->clazz->done_image( queue, inode ); + FT_List_Remove( glyphs_lru, lrunode ); + + 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, next; + FT_Error error; + FTC_ImageNode inode; + + *anode = 0; + for ( node = bucket->head; node; node = next ) + { + inode = (FTC_ImageNode)node; + + if ( FTC_IMAGENODE_GET_GINDEX(inode) == glyph_index ) + { + /* we found it !! - move glyph to start of the list */ + FT_List_Up( bucket, node ); + *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; + + error = queue->clazz->init_image( queue, inode ); + if (error) + { + FTC_ImageNode_Done( queue->cache, inode ); + goto Exit; + } + + /* set the glyph and queue indices in the image node */ + FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index ); + + /* 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); + + *anode = inode; + + Exit: + return error; + } + + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** 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) + + static + FT_Error ftc_image_cache_init_queue( FT_Lru lru, + FT_LruNode node ) + { + 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; + } + + + static + void ftc_image_cache_done_queue( FT_Lru lru, + FT_LruNode node ) + { + FTC_Image_Queue queue = FTC_LRUNODE_QUEUE(node); + + FT_UNUSED(lru); + FTC_Image_Queue_Done(queue); + } + + + static + FT_Bool ftc_image_cache_compare_queue( FT_LruNode node, + FT_LruKey key ) + { + FTC_Image_Queue queue = FTC_LRUNODE_QUEUE(node); + FTC_Image_Desc* desc2 = (FTC_Image_Desc*)key; + FTC_Image_Desc* desc1 = &queue->descriptor; + + 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 ); + } + + + + static + 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 + }; + + + + + + /* compress image cache if it needs it.. i.e. discards all old glyph images */ + /* until "cache.num_bytes" is under "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 = cache->glyphs_lru.tail; + FTC_Image_Queue queue; + FT_UInt glyph_index; + FT_UInt hash_index; + FT_UInt queue_index; + FT_ULong size; + FTC_ImageNode inode; + + /* exit our loop if there isn't any glyph image left, or if */ + /* we reached the newly created node (which is always at the */ + /* start of the list..) */ + + 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 ); + + 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_Error error; + FT_Memory memory; + FTC_Image_Cache cache; + + + *acache = 0; + memory = manager->library->memory; + + if ( ALLOC( cache, sizeof(*cache) ) ) + goto Exit; + + cache->manager = manager; + 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; + } + + + + FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache ) + { + FT_Memory memory = cache->memory; + + + /* discard image queues */ + FT_Lru_Done( cache->queues_lru ); + + /* discard cache */ + FREE( cache ); + } + + + + 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_Image_Queue queue; + FTC_ImageNode inode; + + *aglyph = 0; + error = FT_Lru_Lookup( cache->queues_lru, + (FT_LruKey)desc, + (FT_Pointer*)&queue ); + if (error) + goto Exit; + + error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode ); + if (error) + goto Exit; + + FTC_Image_Cache_Compress( cache, inode ); + *aglyph = FTC_IMAGENODE_GET_GLYPH(inode); + + Exit: + return error; + } + + /* END */ diff --git a/src/cache/ftcimage.h b/src/cache/ftcimage.h index 5a4d17ff6..11eb96e5f 100644 --- a/src/cache/ftcimage.h +++ b/src/cache/ftcimage.h @@ -21,40 +21,18 @@ #include #include - +#include #ifdef __cplusplus extern "C" { #endif +#define FTC_MAX_IMAGE_QUEUES 16 typedef struct FTC_Image_QueueRec_* FTC_Image_Queue; - typedef struct FTC_Image_CacheRec_* FTC_Image_Cache; typedef struct FTC_ImageNodeRec_* FTC_ImageNode; - /* types of glyph images */ - typedef enum FTC_Image_Type_ - { - ftc_image_mono = 0, /* monochrome bitmap */ - ftc_image_grays, /* anti-aliased bitmap */ - ftc_image_outline, /* scaled outline */ - ftc_image_master_outline, /* original outline */ - - } FTC_Image_Type; - - - /* a descriptor used to describe all glyphs in a given queue */ - typedef struct FTC_Image_Desc_ - { - FTC_FaceID face_id; - FT_UInt pix_width; - FT_UInt pix_height; - FT_UInt image_type; - - } FTC_Image_Desc; - - /* macros used to pack a glyph index and a queue index in a single ptr */ #define FTC_PTR_TO_GINDEX( p ) ( (FT_UInt)( (FT_ULong)(p) >> 16 ) ) #define FTC_PTR_TO_QINDEX( p ) ( (FT_UInt)( (FT_ULong)(p) & 0xFFFF ) ) @@ -76,13 +54,26 @@ /* macros to read/set the glyph & queue index in a FTC_ImageNode */ #define FTC_IMAGENODE_GET_GINDEX( n ) FTC_PTR_TO_GINDEX( (n)->root2.data ) #define FTC_IMAGENODE_GET_QINDEX( n ) FTC_PTR_TO_QINDEX( (n)->root2.data ) -#define FTC_IMAGENODE_SET_INDICES( g, q ) \ +#define FTC_IMAGENODE_GET_GLYPH(n) ((FT_Glyph)(n)->root1.data) +#define FTC_IMAGENODE_SET_GLYPH(n,g) do { (n)->root1.data = g; } while (0) +#define FTC_IMAGENODE_SET_INDICES( n, g, q ) \ do \ { \ (n)->root2.data = FTC_INDICES_TO_PTR( g, q ); \ } while ( 0 ) + /* this macro is used to extract a handle to the global LRU list node */ + /* corresponding to a given image node.. */ +#define FTC_IMAGENODE_TO_LISTNODE(n) \ + ((FT_ListNode)&(n)->root2) + + /* this macro is used to extract a handle to a given image node from */ + /* the corresponding LRU glyph list node. That's a bit hackish.. */ +#define FTC_LISTNODE_TO_IMAGENODE(p) \ + ((FTC_ImageNode)((char*)(p) - offsetof(FTC_ImageNodeRec,root2))) + + typedef struct FTC_Image_CacheRec_ { FTC_Manager manager; @@ -91,22 +82,23 @@ FT_ULong max_bytes; /* maximum size of cache in bytes */ FT_ULong num_bytes; /* current size of cache in bytes */ - FT_Lru queues_lru; /* static queues lru list */ + FT_Lru queues_lru; /* static queues lru list */ + FT_ListRec glyphs_lru; /* global lru list of glyph images */ - } FTC_Image_Cache; + } FTC_Image_CacheRec; /* a table of functions used to generate/manager glyph images */ typedef struct FTC_Image_Class_ { FT_Error (*init_image)( FTC_Image_Queue queue, - FTC_Image_Node node ); + FTC_ImageNode node ); void (*done_image)( FTC_Image_Queue queue, - FTC_Image_Node node ); + FTC_ImageNode node ); FT_ULong (*size_image)( FTC_Image_Queue queue, - FTC_Image_Node node ); + FTC_ImageNode node ); } FTC_Image_Class; @@ -120,22 +112,11 @@ FTC_Image_Desc descriptor; FT_UInt hash_size; FT_List buckets; + FT_UInt index; /* index in parent cache */ - } FTC_Image_SubCacheRec; + } FTC_Image_QueueRec; - FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager, - FT_ULong max_bytes, - FTC_Image_Cache* acache ); - - FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache ); - - 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/ftcmanag.c b/src/cache/ftcmanag.c index d9af7693b..3a9a0d382 100644 --- a/src/cache/ftcmanag.c +++ b/src/cache/ftcmanag.c @@ -20,7 +20,7 @@ #include -#define FTC_LRU_GET_MANAGER( lru ) ((FTC_Manager_Lru)lru)->manager +#define FTC_LRU_GET_MANAGER( lru ) (FTC_Manager)lru->user_data /**************************************************************************/ @@ -40,6 +40,7 @@ error = manager->request_face( (FTC_FaceID)node->key, + manager->library, manager->request_data, (FT_Face*)&node->root.data ); if ( !error ) @@ -179,7 +180,7 @@ static const FT_Lru_Class ftc_face_lru_class = { - sizeof ( FTC_Manager_LruRec ), + sizeof ( FT_LruRec ), ftc_manager_init_face, ftc_manager_done_face, 0, @@ -190,7 +191,7 @@ static const FT_Lru_Class ftc_size_lru_class = { - sizeof ( FTC_Manager_LruRec ), + sizeof ( FT_LruRec ), ftc_manager_init_size, ftc_manager_done_size, ftc_manager_flush_size, @@ -213,6 +214,7 @@ error = FT_Lru_New( &ftc_face_lru_class, FTC_MAX_FACES, + manager, memory, 1, /* pre_alloc = TRUE */ (FT_Lru*)&manager->faces_lru ); @@ -221,15 +223,13 @@ error = FT_Lru_New( &ftc_size_lru_class, FTC_MAX_SIZES, + manager, memory, 1, /* pre_alloc = TRUE */ (FT_Lru*)&manager->sizes_lru ); if ( error ) goto Exit; - ((FTC_Manager_Lru)manager->faces_lru)->manager = manager; - ((FTC_Manager_Lru)manager->sizes_lru)->manager = manager; - manager->library = library; manager->request_face = requester; manager->request_data = req_data; @@ -275,6 +275,7 @@ } + FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager, FTC_SizeID size_id, FT_Face* aface, @@ -285,24 +286,34 @@ FT_Face face; - *aface = 0; - *asize = 0; + if (aface) + *aface = 0; + + if (asize) + *asize = 0; error = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face ); if ( !error ) { + FT_Size size; + req.face = face; req.width = size_id->pix_width; req.height = size_id->pix_height; error = FT_Lru_Lookup( manager->sizes_lru, (FT_LruKey)&req, - (FT_Pointer*)asize ); + (FT_Pointer*)&size ); if ( !error ) { /* select the size as the current one for this face */ face->size = *asize; - *aface = face; + + if (asize) + *asize = size; + + if (aface) + *aface = face; } } diff --git a/src/cache/ftcmanag.h b/src/cache/ftcmanag.h index b765ed4c1..fa28eb668 100644 --- a/src/cache/ftcmanag.h +++ b/src/cache/ftcmanag.h @@ -19,6 +19,7 @@ #ifndef FTCMANAG_H #define FTCMANAG_H +#include #include @@ -31,32 +32,6 @@ #define FTC_MAX_SIZES 8 - typedef FT_Pointer FTC_FaceID; - - typedef struct FTC_SizeRec_ - { - FTC_FaceID face_id; - FT_UShort pix_width; - FT_UShort pix_height; - - } FTC_SizeRec, *FTC_SizeID; - - - typedef FT_Error (*FTC_Face_Requester)( FTC_FaceID face_id, - FT_Pointer data, - FT_Face* aface ); - - - typedef struct FTC_ManagerRec_* FTC_Manager; - - typedef struct FTC_Manager_LruRec_ - { - FT_LruRec root; - FTC_Manager manager; - - } FTC_Manager_LruRec, *FTC_Manager_Lru; - - typedef struct FTC_ManagerRec_ { FT_Library library; @@ -69,24 +44,6 @@ } FTC_ManagerRec; - FT_EXPORT_DEF( FT_Error ) FTC_Manager_New( FT_Library library, - FTC_Face_Requester requester, - FT_Pointer req_data, - FTC_Manager* amanager ); - - FT_EXPORT_DEF( void ) FTC_Manager_Done( FTC_Manager manager ); - - FT_EXPORT_DEF( void ) FTC_Manager_Reset( FTC_Manager manager ); - - FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Face( FTC_Manager manager, - FTC_FaceID face_id, - FT_Face* aface ); - - FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager, - FTC_SizeID size_id, - FT_Face* aface, - FT_Size* asize ); - #ifdef __cplusplus } diff --git a/src/cache/ftlru.c b/src/cache/ftlru.c index c830b964f..e4e60a938 100644 --- a/src/cache/ftlru.c +++ b/src/cache/ftlru.c @@ -38,6 +38,7 @@ FT_EXPORT_FUNC( 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* alru ) @@ -66,6 +67,7 @@ lru->clazz = (FT_Lru_Class*)clazz; lru->max_elements = max_elements; lru->memory = memory; + lru->user_data = user_data; *alru = lru; } diff --git a/src/cache/ftlru.h b/src/cache/ftlru.h index 28054c859..300b72a1d 100644 --- a/src/cache/ftlru.h +++ b/src/cache/ftlru.h @@ -40,6 +40,8 @@ typedef struct FT_LruRec_* FT_Lru; + + typedef struct FT_Lru_Class_ { FT_UInt lru_size; /* object size in bytes */ @@ -60,6 +62,7 @@ } FT_Lru_Class; + typedef FT_Bool (*FT_Lru_Selector)( FT_Lru lru, FT_LruNode node, FT_Pointer data ); @@ -72,6 +75,7 @@ FT_UInt num_elements; FT_ListRec elements; FT_Memory memory; + FT_Pointer user_data; /* the following fields are only meaningful for static lru containers */ FT_ListRec free_nodes; @@ -82,6 +86,7 @@ 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* alru ); diff --git a/src/cache/rules.mk b/src/cache/rules.mk new file mode 100644 index 000000000..62b7cddbf --- /dev/null +++ b/src/cache/rules.mk @@ -0,0 +1,70 @@ +# +# FreeType 2 Cache configuration rules +# + + +# Copyright 1996-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. + + +# Cache driver directory +# +Cache_DIR := $(SRC_)cache +Cache_DIR_ := $(Cache_DIR)$(SEP) + + +# compilation flags for the driver +# +Cache_COMPILE := $(FT_COMPILE) + + +# Cache driver sources (i.e., C files) +# +Cache_DRV_SRC := $(Cache_DIR_)ftlru.c \ + $(Cache_DIR_)ftcmanag.c \ + $(Cache_DIR_)ftcimage.c + +# Cache driver headers +# +Cache_DRV_H := $(Cache_DRV_SRC:%c=%h) + + +# Cache driver object(s) +# +# Cache_DRV_OBJ_M is used during `multi' builds. +# Cache_DRV_OBJ_S is used during `single' builds. +# +Cache_DRV_OBJ_M := $(Cache_DRV_SRC:$(Cache_DIR_)%.c=$(OBJ_)%.$O) +Cache_DRV_OBJ_S := $(OBJ_)ftcache.$O + +# Cache driver source file for single build +# +Cache_DRV_SRC_S := $(Cache_DIR_)ftcache.c + + +# Cache driver - single object +# +$(Cache_DRV_OBJ_S): $(Cache_DRV_SRC_S) $(Cache_DRV_SRC) \ + $(FREETYPE_H) $(Cache_DRV_H) + $(Cache_COMPILE) $T$@ $(Cache_DRV_SRC_S) + + +# Cache driver - multiple objects +# +$(OBJ_)%.$O: $(Cache_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H) + $(Cache_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(Cache_DRV_OBJ_S) +DRV_OBJS_M += $(Cache_DRV_OBJ_M) + + +# EOF