The FreeType Caching Subsystem - first lines of code
beware, this code is not tested, and probably doesn't compile correctly.. more information will follow..
This commit is contained in:
parent
a39acf55f7
commit
b466a7650c
147
src/cache/ftcimage.c
vendored
Normal file
147
src/cache/ftcimage.c
vendored
Normal file
@ -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 *****/
|
||||
/***** *****/
|
||||
/*******************************************************************/
|
||||
/*******************************************************************/
|
||||
|
||||
|
104
src/cache/ftcimage.h
vendored
Normal file
104
src/cache/ftcimage.h
vendored
Normal file
@ -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 */
|
280
src/cache/ftcmanag.c
vendored
Normal file
280
src/cache/ftcmanag.c
vendored
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
65
src/cache/ftcmanag.h
vendored
Normal file
65
src/cache/ftcmanag.h
vendored
Normal file
@ -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 */
|
263
src/cache/ftlru.c
vendored
Normal file
263
src/cache/ftlru.c
vendored
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
83
src/cache/ftlru.h
vendored
Normal file
83
src/cache/ftlru.h
vendored
Normal file
@ -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
Block a user