beware, this code is not tested, and probably doesn't compile correctly.. more information will follow..VER-2-0-4-PATCH
parent
de3f4a73c8
commit
ba600671f1
6 changed files with 942 additions and 0 deletions
@ -0,0 +1,147 @@ |
||||
#include <cache/ftcimage.h> |
||||
|
||||
static |
||||
void ftc_done_glyph_image( FTC_Image_Queue queue, |
||||
FTC_ImageNode node ) |
||||
{ |
||||
FT_UNUSED(queue); |
||||
FT_Done_Glyph( FTC_IMAGENODE_GET_GLYPH(node) ); |
||||
} |
||||
|
||||
static |
||||
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)); |
||||
} |
||||
|
||||
static |
||||
FT_ULong ftc_size_outline_image( FTC_Image_Queue queue, |
||||
FTC_ImageNode node ) |
||||
{ |
||||
FT_Long pitch; |
||||
FT_OutlineGlyph glyph; |
||||
FT_Outline* outline; |
||||
|
||||
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) ); |
||||
} |
||||
|
||||
/*******************************************************************/ |
||||
/*******************************************************************/ |
||||
/***** *****/ |
||||
/***** MONOCHROME BITMAP CALLBACKS *****/ |
||||
/***** *****/ |
||||
/*******************************************************************/ |
||||
/*******************************************************************/ |
||||
|
||||
static |
||||
FT_Error ftc_init_mono_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->size_rec, |
||||
&face, &size ); |
||||
if (!error) |
||||
{ |
||||
FT_UInt glyph_index = FTC_IMAGENODE_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 || |
||||
face->glyph->bitmap.pixel_mode != ft_pixel_mode_mono ) |
||||
{ |
||||
/* there is no monochrome 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_gray_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->size_rec, |
||||
&face, &size ); |
||||
if (!error) |
||||
{ |
||||
FT_UInt glyph_index = FTC_IMAGENODE_GINDEX(node); |
||||
|
||||
|
||||
error = FT_Load_Glyph( face, glyph_index, |
||||
FT_LOAD_RENDER ); |
||||
if (!error) |
||||
{ |
||||
if ( face->glyph->format != ft_image_format_bitmap || |
||||
face->glyph->bitmap.pixel_mode != ft_pixel_mode_grays ) |
||||
{ |
||||
/* there is no monochrome 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; |
||||
} |
||||
|
||||
|
||||
/*******************************************************************/ |
||||
/*******************************************************************/ |
||||
/***** *****/ |
||||
/***** MONOCHROME BITMAP CALLBACKS *****/ |
||||
/***** *****/ |
||||
/*******************************************************************/ |
||||
/*******************************************************************/ |
||||
|
||||
|
@ -0,0 +1,104 @@ |
||||
#ifndef FTCIMAGE_H |
||||
#define FTCIMAGE_H |
||||
|
||||
#include <cache/ftcmanag.h> |
||||
#include <freetype/ftglyph.h> |
||||
|
||||
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)) |
||||
#define FTC_INDICES_TO_PTR(g,q) ((FT_Pointer)(((FT_ULong)(g) << 16) | \ |
||||
((FT_ULong)(q) & 0xFFFF))) |
||||
|
||||
typedef struct FTC_ImageNodeRec_ |
||||
{ |
||||
FT_ListNodeRec root1; /* root1.data contains a FT_Glyph handle */ |
||||
FT_ListNodeRec root2; /* root2.data contains a glyph index + queue index */ |
||||
|
||||
} FTC_ImageNodeRec; |
||||
|
||||
/* 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) \ |
||||
do { (n)->root2.data = FTC_INDICES_TO_PTR(g,q); } while (0) |
||||
|
||||
|
||||
typedef struct FTC_Image_CacheRec_ |
||||
{ |
||||
FTC_Manager manager; |
||||
FT_Memory memory; |
||||
|
||||
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 */ |
||||
|
||||
} FTC_Image_Cache; |
||||
|
||||
|
||||
/* 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 ); |
||||
|
||||
void (*done_image)( FTC_Image_Queue queue, |
||||
FTC_Image_Node node ); |
||||
|
||||
FT_ULong (*size_image)( FTC_Image_Queue queue, |
||||
FTC_Image_Node node ); |
||||
|
||||
} FTC_Image_Class; |
||||
|
||||
|
||||
typedef struct FTC_Image_QueueRec_ |
||||
{ |
||||
FTC_Image_Cache cache; |
||||
FTC_Manager manager; |
||||
FT_Memory memory; |
||||
FTC_Image_Class* clazz; |
||||
FTC_Image_Desc descriptor; |
||||
FT_UInt hash_size; |
||||
FT_List buckets; |
||||
|
||||
} FTC_Image_SubCacheRec; |
||||
|
||||
|
||||
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 ); |
||||
|
||||
#endif /* FTCIMAGE_H */ |
@ -0,0 +1,280 @@ |
||||
#include <cache/ftcmanag.h> |
||||
#include <freetype/internal/ftobjs.h> |
||||
|
||||
#define FTC_LRU_GET_MANAGER(lru) ((FTC_Manager_Lru)lru)->manager |
||||
|
||||
/*******************************************************************/ |
||||
/*******************************************************************/ |
||||
/***** *****/ |
||||
/***** FACE & SIZE LRU CALLBACKS *****/ |
||||
/***** *****/ |
||||
/*******************************************************************/ |
||||
/*******************************************************************/ |
||||
|
||||
static |
||||
FT_Error ftc_manager_init_face( FT_Lru lru, |
||||
FT_LruNode node ) |
||||
{ |
||||
FTC_Manager manager = FTC_LRU_GET_MANAGER(lru); |
||||
FT_Error error; |
||||
|
||||
error = manager->request_face( (FTC_FaceID)node->key, |
||||
manager->request_data, |
||||
(FT_Face*)&node->root.data ); |
||||
if (!error) |
||||
{ |
||||
/* destroy initial size object, it will be re-created later */ |
||||
FT_Face face = (FT_Face)node->root.data; |
||||
FT_Done_Size( face->size ); |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
|
||||
/* helper function for ftc_manager_done_face */ |
||||
static |
||||
FT_Bool ftc_manager_size_selector( FT_Lru lru, |
||||
FT_LruNode node, |
||||
FT_Pointer data ) |
||||
{ |
||||
FT_UNUSED(lru); |
||||
return ((FT_Size)node->root.data)->face == (FT_Face)data; |
||||
} |
||||
|
||||
static |
||||
void ftc_manager_done_face( FT_Lru lru, |
||||
FT_LruNode node ) |
||||
{ |
||||
FTC_Manager manager = FTC_LRU_GET_MANAGER(lru); |
||||
FT_Face face = (FT_Face)node->root.data; |
||||
|
||||
/* we must begin by removing all sizes for the target face */ |
||||
/* from the manager's list.. */ |
||||
FT_Lru_Remove_Selection( manager->sizes_lru, |
||||
ftc_manager_size_selector, |
||||
face ); |
||||
|
||||
/* all right, we can discard the face now */
|
||||
FT_Done_Face( face ); |
||||
node->root.data = 0; |
||||
} |
||||
|
||||
|
||||
typedef struct FTC_SizeRequest_ |
||||
{ |
||||
FT_Face face; |
||||
FT_UShort width; |
||||
FT_UShort height; |
||||
|
||||
} FTC_SizeRequest; |
||||
|
||||
|
||||
static |
||||
FT_Error ftc_manager_init_size( FT_Lru lru, |
||||
FT_LruNode node ) |
||||
{ |
||||
FTC_SizeRequest* size_req = (FTC_SizeRequest*)node->key; |
||||
FT_Size size; |
||||
FT_Error error; |
||||
|
||||
FT_UNUSED(lru); |
||||
|
||||
node->root.data = 0; |
||||
error = FT_New_Size( size_req->face, &size ); |
||||
if (!error) |
||||
{ |
||||
error = FT_Set_Pixel_Sizes( size_req->face, |
||||
size_req->width, |
||||
size_req->height ); |
||||
if (error) |
||||
FT_Done_Size(size); |
||||
else |
||||
node->root.data = size; |
||||
} |
||||
return error;
|
||||
} |
||||
|
||||
|
||||
static |
||||
void ftc_manager_done_size( FT_Lru lru, |
||||
FT_LruNode node ) |
||||
{ |
||||
FT_UNUSED(lru); |
||||
FT_Done_Size( (FT_Size)node->root.data ); |
||||
}
|
||||
|
||||
|
||||
|
||||
static |
||||
FT_Error ftc_manager_flush_size( FT_Lru lru, |
||||
FT_LruNode node, |
||||
FT_LruKey key ) |
||||
{ |
||||
FTC_SizeRequest* req = (FTC_SizeRequest*)key; |
||||
FT_Size size = (FT_Size)node->root.data; |
||||
FT_Error error; |
||||
|
||||
if ( size->face == req->face ) |
||||
{ |
||||
size->face->size = size; /* set current size */ |
||||
error = FT_Set_Pixel_Sizes( req->face, req->width, req->height ); |
||||
if (error) |
||||
FT_Done_Size( size ); |
||||
} |
||||
else |
||||
{ |
||||
FT_Done_Size(size); |
||||
node->key = key; |
||||
error = ftc_manager_init_size( lru, node ); |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
|
||||
static |
||||
FT_Bool ftc_manager_compare_size( FT_LruNode node, |
||||
FT_LruKey key ) |
||||
{ |
||||
FTC_SizeRequest* req = (FTC_SizeRequest*)key; |
||||
FT_Size size = (FT_Size)node->root.data; |
||||
|
||||
FT_UNUSED(node); |
||||
return ( size->face == req->face && |
||||
size->metrics.x_ppem == req->width && |
||||
size->metrics.y_ppem == req->height ); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
static |
||||
const FT_Lru_Class ftc_face_lru_class = |
||||
{ |
||||
sizeof( FTC_Manager_LruRec ), |
||||
ftc_manager_init_face, |
||||
ftc_manager_done_face, |
||||
0, |
||||
0 |
||||
}; |
||||
|
||||
|
||||
static |
||||
const FT_Lru_Class ftc_size_lru_class = |
||||
{ |
||||
sizeof( FTC_Manager_LruRec ), |
||||
ftc_manager_init_size, |
||||
ftc_manager_done_size, |
||||
ftc_manager_flush_size, |
||||
ftc_manager_compare_size |
||||
}; |
||||
|
||||
|
||||
|
||||
FT_EXPORT_FUNC(FT_Error) FTC_Manager_New ( FT_Library library, |
||||
FTC_Face_Requester requester, |
||||
FT_Pointer req_data, |
||||
FTC_Manager *amanager ) |
||||
{ |
||||
FT_Error error; |
||||
FT_Memory memory = library->memory; |
||||
FTC_Manager manager = 0; |
||||
|
||||
|
||||
if ( ALLOC( manager, sizeof(*manager) ) ) |
||||
goto Exit; |
||||
|
||||
error = FT_Lru_New( &ftc_face_lru_class, |
||||
FTC_MAX_FACES, |
||||
memory, |
||||
1, /* pre_alloc = TRUE */ |
||||
(FT_Lru*)&manager->faces_lru ); |
||||
if (error) |
||||
goto Exit; |
||||
|
||||
error = FT_Lru_New( &ftc_size_lru_class, |
||||
FTC_MAX_SIZES, |
||||
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; |
||||
*amanager = manager; |
||||
|
||||
Exit: |
||||
if (error && manager) |
||||
{ |
||||
FT_Lru_Done( manager->sizes_lru ); |
||||
FT_Lru_Done( manager->faces_lru ); |
||||
FREE( manager ); |
||||
} |
||||
|
||||
return error; |
||||
} |
||||
|
||||
FT_EXPORT_DEF(void) FTC_Manager_Done ( FTC_Manager manager ) |
||||
{ |
||||
FT_Memory memory = manager->library->memory; |
||||
|
||||
FT_Lru_Done( manager->sizes_lru ); |
||||
FT_Lru_Done( manager->faces_lru ); |
||||
FREE( manager ); |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF(void) FTC_Manager_Reset( FTC_Manager manager ) |
||||
{ |
||||
FT_Lru_Reset( manager->sizes_lru ); |
||||
FT_Lru_Reset( manager->faces_lru ); |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF(FT_Error) FTC_Manager_Lookup_Face( FTC_Manager manager, |
||||
FTC_FaceID face_id, |
||||
FT_Face *aface ) |
||||
{ |
||||
return FT_Lru_Lookup( manager->faces_lru, |
||||
(FT_LruKey)face_id,
|
||||
(FT_Pointer*)aface ); |
||||
} |
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF(FT_Error) FTC_Manager_Lookup_Size( FTC_Manager manager, |
||||
FTC_SizeID size_id, |
||||
FT_Face *aface, |
||||
FT_Size *asize ) |
||||
{ |
||||
FTC_SizeRequest req; |
||||
FT_Error error; |
||||
FT_Face face; |
||||
|
||||
*aface = 0; |
||||
*asize = 0; |
||||
error = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face );
|
||||
if (!error) |
||||
{ |
||||
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 ); |
||||
if (!error) |
||||
{ |
||||
/* select the size as the current one for this face */ |
||||
face->size = *asize; |
||||
*aface = face; |
||||
} |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
|
@ -0,0 +1,65 @@ |
||||
#ifndef FTCMANAG_H |
||||
#define FTCMANAG_H |
||||
|
||||
#include <cache/ftlru.h> |
||||
|
||||
#define FTC_MAX_FACES 4 |
||||
#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; |
||||
FT_Lru faces_lru; |
||||
FT_Lru sizes_lru; |
||||
|
||||
FT_Pointer request_data; |
||||
FTC_Face_Requester request_face; |
||||
|
||||
} 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 ); |
||||
|
||||
#endif /* FTCMANAG_H */ |
@ -0,0 +1,263 @@ |
||||
#include <cache/ftlru.h> |
||||
#include <freetype/internal/ftobjs.h> |
||||
#include <freetype/internal/ftlist.h> |
||||
|
||||
static |
||||
void lru_build_free_list( FT_LruNode nodes, |
||||
FT_UInt count, |
||||
FT_List free_list ) |
||||
{ |
||||
FT_LruNode node = nodes; |
||||
FT_LruNode limit = node + count; |
||||
|
||||
free_list->head = free_list->tail = 0; |
||||
for ( ; node < limit; node++ ) |
||||
FT_List_Add( free_list, (FT_ListNode)node ); |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_FUNC(FT_Error) FT_Lru_New ( const FT_Lru_Class* clazz, |
||||
FT_UInt max_elements, |
||||
FT_Memory memory, |
||||
FT_Bool pre_alloc, |
||||
FT_Lru *alru ) |
||||
{ |
||||
FT_Error error; |
||||
FT_Lru lru; |
||||
|
||||
*alru = 0; |
||||
if ( !ALLOC( lru, sizeof(*lru) ) ) |
||||
{ |
||||
if (pre_alloc) |
||||
{ |
||||
/* allocate static array of lru list nodes */ |
||||
if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) ) |
||||
{ |
||||
FREE( lru ); |
||||
goto Exit; |
||||
} |
||||
|
||||
/* build the 'free_nodes' list from the array */ |
||||
lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes ); |
||||
} |
||||
|
||||
/* initialize common fields */ |
||||
lru->clazz = (FT_Lru_Class*)clazz; |
||||
lru->max_elements = max_elements; |
||||
lru->memory = memory; |
||||
*alru = lru; |
||||
} |
||||
Exit: |
||||
return error; |
||||
} |
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF(void) FT_Lru_Reset ( FT_Lru lru ) |
||||
{ |
||||
FT_ListNode node = lru->elements.head; |
||||
FT_Lru_Class* clazz = lru->clazz; |
||||
FT_Memory memory = lru->memory; |
||||
|
||||
while (node) |
||||
{ |
||||
FT_ListNode next = node->next; |
||||
|
||||
clazz->done_element( lru, (FT_LruNode)node ); |
||||
if (!lru->nodes) |
||||
FREE(node); |
||||
|
||||
node = next; |
||||
} |
||||
|
||||
/* rebuild free list if necessary */ |
||||
if (lru->nodes) |
||||
lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes ); |
||||
lru->elements.head = lru->elements.tail = 0; |
||||
lru->num_elements = 0; |
||||
} |
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF(void) FT_Lru_Done ( FT_Lru lru ) |
||||
{ |
||||
FT_Memory memory = lru->memory; |
||||
|
||||
FT_Lru_Reset(lru); |
||||
FREE(lru); |
||||
} |
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup_Node( FT_Lru lru, |
||||
FT_LruKey key, |
||||
FT_LruNode* anode ) |
||||
{ |
||||
FT_Error error = 0; |
||||
FT_ListNode node = lru->elements.head; |
||||
FT_Lru_Class* clazz = lru->clazz; |
||||
FT_LruNode found = 0;
|
||||
FT_Memory memory = lru->memory; |
||||
|
||||
if (clazz->compare_element) |
||||
{ |
||||
for ( ; node; node = node->next ) |
||||
if (clazz->compare_element( (FT_LruNode)node, key )) |
||||
{ |
||||
found = (FT_LruNode)node; |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for ( ; node; node = node->next ) |
||||
if (((FT_LruNode)node)->key == key) |
||||
{ |
||||
found = (FT_LruNode)node; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!found) |
||||
{ |
||||
/* we didn't find the relevant element. We will now try */ |
||||
/* to create a new one.. */ |
||||
if ( lru->num_elements >= lru->max_elements ) |
||||
{ |
||||
/* this lru list is full, we will now flush */ |
||||
/* the oldest node */ |
||||
FT_LruNode lru_node; |
||||
|
||||
|
||||
node = lru->elements.tail; |
||||
lru_node = (FT_LruNode)node; |
||||
|
||||
if (clazz->flush_element) |
||||
error = clazz->flush_element( lru, lru_node, key ); |
||||
else |
||||
{ |
||||
clazz->done_element( lru, lru_node ); |
||||
lru_node->key = key; |
||||
node->data = 0; |
||||
error = clazz->init_element( lru, lru_node ); |
||||
} |
||||
|
||||
if (!error) |
||||
{ |
||||
/* now, move element to top of list */ |
||||
FT_List_Up( &lru->elements, node ); |
||||
} |
||||
else |
||||
{ |
||||
/* in case of error, the node must be discarded */ |
||||
FT_List_Remove( &lru->elements, node ); |
||||
lru->num_elements--; |
||||
|
||||
if (lru->nodes) |
||||
FT_List_Insert( &lru->free_nodes, node ); |
||||
else |
||||
FREE( lru_node ); |
||||
} |
||||
} |
||||
else |
||||
{
|
||||
FT_LruNode lru_node; |
||||
|
||||
/* create a new lru list node, then the element for it */ |
||||
if (lru->nodes) |
||||
{ |
||||
node = lru->free_nodes.head; |
||||
lru_node = (FT_LruNode)node; |
||||
lru_node->key = key; |
||||
|
||||
error = clazz->init_element( lru, lru_node ); |
||||
if (error) |
||||
goto Exit; |
||||
|
||||
FT_List_Remove( &lru->free_nodes, node ); |
||||
} |
||||
else |
||||
{ |
||||
if ( ALLOC( lru_node, sizeof(*lru_node) ) ) |
||||
goto Exit; |
||||
|
||||
lru_node->key = key; |
||||
error = clazz->init_element( lru, lru_node ); |
||||
if (error) |
||||
{ |
||||
FREE( lru_node ); |
||||
goto Exit; |
||||
} |
||||
} |
||||
|
||||
found = lru_node;
|
||||
node = (FT_ListNode)lru_node; |
||||
FT_List_Insert( &lru->elements, node ); |
||||
lru->num_elements++; |
||||
} |
||||
} |
||||
|
||||
Exit:
|
||||
*anode = found; |
||||
return error;
|
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup( FT_Lru lru, |
||||
FT_LruKey key, |
||||
FT_Pointer *aobject ) |
||||
{ |
||||
FT_Error error; |
||||
FT_LruNode node; |
||||
|
||||
*aobject = 0; |
||||
error = FT_Lru_Lookup_Node( lru, key, &node ); |
||||
if (!error) |
||||
*aobject = node->root.data; |
||||
|
||||
return error; |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_FUNC(void) FT_Lru_Remove_Node( FT_Lru lru, |
||||
FT_LruNode node ) |
||||
{ |
||||
if (lru->num_elements > 0) |
||||
{ |
||||
FT_List_Remove( &lru->elements, (FT_ListNode)node ); |
||||
lru->clazz->done_element( lru, node ); |
||||
|
||||
if (lru->nodes) |
||||
FT_List_Insert( &lru->free_nodes, (FT_ListNode)node ); |
||||
else |
||||
{ |
||||
FT_Memory memory = lru->memory; |
||||
FREE(node); |
||||
} |
||||
lru->num_elements--; |
||||
} |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_FUNC(void) FT_Lru_Remove_Selection( FT_Lru lru, |
||||
FT_Lru_Selector selector, |
||||
FT_Pointer data ) |
||||
{ |
||||
if (lru->num_elements > 0) |
||||
{ |
||||
FT_ListNode node = lru->elements.head; |
||||
FT_ListNode next; |
||||
|
||||
while (node) |
||||
{ |
||||
next = node->next; |
||||
if ( selector( lru, (FT_LruNode)node, data ) ) |
||||
{ |
||||
/* remove this element from the list, and destroy it */ |
||||
FT_Lru_Remove_Node( lru, (FT_LruNode)node ); |
||||
} |
||||
node = next; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,83 @@ |
||||
#ifndef FTLRU_H |
||||
#define FTLRU_H |
||||
|
||||
#include <freetype/freetype.h> |
||||
|
||||
|
||||
typedef FT_Pointer FT_LruKey; |
||||
|
||||
|
||||
typedef struct FT_LruNodeRec_ |
||||
{ |
||||
FT_ListNodeRec root; |
||||
FT_LruKey key; |
||||
|
||||
} FT_LruNodeRec, *FT_LruNode; |
||||
|
||||
|
||||
typedef struct FT_LruRec_* FT_Lru; |
||||
|
||||
typedef struct FT_Lru_Class_ |
||||
{ |
||||
FT_UInt lru_size; /* object size in bytes */ |
||||
|
||||
FT_Error (*init_element)( FT_Lru lru, |
||||
FT_LruNode node ); |
||||
|
||||
void (*done_element)( FT_Lru lru, |
||||
FT_LruNode node ); |
||||
|
||||
FT_Error (*flush_element)( FT_Lru lru, |
||||
FT_LruNode node, |
||||
FT_LruKey new_key );
|
||||
|
||||
FT_Bool (*compare_element)( FT_LruNode node, |
||||
FT_LruKey key ); |
||||
} FT_Lru_Class; |
||||
|
||||
|
||||
typedef FT_Bool (*FT_Lru_Selector)( FT_Lru lru, |
||||
FT_LruNode node, |
||||
FT_Pointer data ); |
||||
|
||||
typedef struct FT_LruRec_ |
||||
{ |
||||
FT_Lru_Class* clazz; |
||||
FT_UInt max_elements; |
||||
FT_UInt num_elements; |
||||
FT_ListRec elements; |
||||
FT_Memory memory; |
||||
|
||||
/* the following fields are only meaningful for static lru containers */ |
||||
FT_ListRec free_nodes; |
||||
FT_LruNode nodes; |
||||
|
||||
} FT_LruRec; |
||||
|
||||
|
||||
FT_EXPORT_DEF(FT_Error) FT_Lru_New ( const FT_Lru_Class* clazz, |
||||
FT_UInt max_elements, |
||||
FT_Memory memory, |
||||
FT_Bool pre_alloc, |
||||
FT_Lru *alru ); |
||||
|
||||
FT_EXPORT_DEF(void) FT_Lru_Reset ( FT_Lru lru );
|
||||
|
||||
FT_EXPORT_DEF(void) FT_Lru_Done ( FT_Lru lru );
|
||||
|
||||
FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup_Node( FT_Lru lru, |
||||
FT_LruKey key, |
||||
FT_LruNode* anode ); |
||||
|
||||
FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup( FT_Lru lru, |
||||
FT_LruKey key, |
||||
FT_Pointer *aobject ); |
||||
|
||||
FT_EXPORT_DEF(void) FT_Lru_Remove_Node( FT_Lru lru, |
||||
FT_LruNode node );
|
||||
|
||||
FT_EXPORT_DEF(void) FT_Lru_Remove_Selection( FT_Lru lru, |
||||
FT_Lru_Selector selector, |
||||
FT_Pointer data ); |
||||
|
||||
#endif /* FTLRU_H */ |
Loading…
Reference in new issue