parent
119de2aaa3
commit
040616a116
28 changed files with 2883 additions and 3444 deletions
@ -0,0 +1,143 @@ |
||||
/***************************************************************************/ |
||||
/* */ |
||||
/* ftcmru.h */ |
||||
/* */ |
||||
/* Simple MRU list-cache (specification). */ |
||||
/* */ |
||||
/* Copyright 2000-2001, 2003 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. */ |
||||
/* */ |
||||
/***************************************************************************/ |
||||
|
||||
|
||||
/*************************************************************************/ |
||||
/* */ |
||||
/* An MRU is a list that cannot hold more than a certain number of */ |
||||
/* elements (`max_elements'). All elements in the list are sorted in */ |
||||
/* least-recently-used order, i.e., the `oldest' element is at the tail */ |
||||
/* of the list. */ |
||||
/* */ |
||||
/* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ |
||||
/* the list is searched for an element with the corresponding key. If */ |
||||
/* it is found, the element is moved to the head of the list and is */ |
||||
/* returned. */ |
||||
/* */ |
||||
/* If no corresponding element is found, the lookup routine will try to */ |
||||
/* obtain a new element with the relevant key. If the list is already */ |
||||
/* full, the oldest element from the list is discarded and replaced by a */ |
||||
/* new one; a new element is added to the list otherwise. */ |
||||
/* */ |
||||
/* Note that it is possible to pre-allocate the element list nodes. */ |
||||
/* This is handy if `max_elements' is sufficiently small, as it saves */ |
||||
/* allocations/releases during the lookup process. */ |
||||
/* */ |
||||
/*************************************************************************/ |
||||
|
||||
|
||||
#ifndef __FTCMRU_H__ |
||||
#define __FTCMRU_H__ |
||||
|
||||
|
||||
#include <ft2build.h> |
||||
#include FT_FREETYPE_H |
||||
|
||||
#ifdef FREETYPE_H |
||||
#error "freetype.h of FreeType 1 has been loaded!" |
||||
#error "Please fix the directory search order for header files" |
||||
#error "so that freetype.h of FreeType 2 is found first." |
||||
#endif |
||||
|
||||
|
||||
FT_BEGIN_HEADER |
||||
|
||||
typedef struct FTC_MruListRec_* FTC_MruList; |
||||
|
||||
typedef struct FTC_MruNodeRec_* FTC_MruNode; |
||||
|
||||
typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; |
||||
|
||||
typedef struct FTC_MruNodeRec_ |
||||
{ |
||||
FTC_MruNode next; |
||||
|
||||
} FTC_MruNodeRec; |
||||
|
||||
typedef FT_Int (*FTC_MruNode_CompareFunc)( FTC_MruNode node, |
||||
FT_Pointer key ); |
||||
|
||||
typedef FT_Error (*FTC_MruNode_InitFunc)( FTC_MruNode node, |
||||
FT_Pointer key, |
||||
FT_Pointer data ); |
||||
|
||||
typedef FT_Error (*FTC_MruNode_ResetFunc)( FTC_MruNode node, |
||||
FT_Pointer key, |
||||
FT_Pointer data ); |
||||
|
||||
typedef void (*FTC_MruNode_DoneFunc)( FTC_MruNode node, |
||||
FT_Pointer data ); |
||||
|
||||
typedef struct FTC_MruListClassRec_ |
||||
{ |
||||
FT_UInt node_size; |
||||
FTC_MruNode_CompareFunc node_compare; |
||||
FTC_MruNode_InitFunc node_init; |
||||
FTC_MruNode_ResetFunc node_reset; |
||||
FTC_MruNode_DoneFunc node_done; |
||||
|
||||
} FTC_MruListClassRec; |
||||
|
||||
typedef struct FTC_MruListRec_ |
||||
{ |
||||
FT_UInt num_nodes; |
||||
FT_UInt max_nodes; |
||||
FTC_MruNode nodes; |
||||
FT_Pointer data; |
||||
FTC_MruListClassRec clazz; |
||||
FT_Memory memory; |
||||
|
||||
} FTC_MruListRec; |
||||
|
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_Init( FTC_MruList list, |
||||
FTC_MruListClass clazz, |
||||
FT_UInt max_nodes, |
||||
FT_Pointer data, |
||||
FT_Memory memory ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_Reset( FTC_MruList list ); |
||||
|
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_Done( FTC_MruList list ); |
||||
|
||||
|
||||
FT_EXPORT( FT_Error ) |
||||
FTC_MruList_Lookup( FTC_MruList list, |
||||
FT_Pointer key, |
||||
FTC_MruNode *pnode ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_Remove( FTC_MruList list, |
||||
FTC_MruNode node ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_RemoveSelection( FTC_MruList list, |
||||
FTC_MruNode_CompareFunc select, |
||||
FT_Pointer key ); |
||||
/* */ |
||||
|
||||
FT_END_HEADER |
||||
|
||||
|
||||
#endif /* __FTCMRU_H__ */ |
||||
|
||||
|
||||
/* END */ |
@ -1,208 +0,0 @@ |
||||
/***************************************************************************/ |
||||
/* */ |
||||
/* ftlru.h */ |
||||
/* */ |
||||
/* Simple LRU list-cache (specification). */ |
||||
/* */ |
||||
/* Copyright 2000-2001, 2003 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. */ |
||||
/* */ |
||||
/***************************************************************************/ |
||||
|
||||
|
||||
/*************************************************************************/ |
||||
/* */ |
||||
/* An LRU is a list that cannot hold more than a certain number of */ |
||||
/* elements (`max_elements'). All elements in the list are sorted in */ |
||||
/* least-recently-used order, i.e., the `oldest' element is at the tail */ |
||||
/* of the list. */ |
||||
/* */ |
||||
/* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ |
||||
/* the list is searched for an element with the corresponding key. If */ |
||||
/* it is found, the element is moved to the head of the list and is */ |
||||
/* returned. */ |
||||
/* */ |
||||
/* If no corresponding element is found, the lookup routine will try to */ |
||||
/* obtain a new element with the relevant key. If the list is already */ |
||||
/* full, the oldest element from the list is discarded and replaced by a */ |
||||
/* new one; a new element is added to the list otherwise. */ |
||||
/* */ |
||||
/* Note that it is possible to pre-allocate the element list nodes. */ |
||||
/* This is handy if `max_elements' is sufficiently small, as it saves */ |
||||
/* allocations/releases during the lookup process. */ |
||||
/* */ |
||||
/*************************************************************************/ |
||||
|
||||
|
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/********* *********/ |
||||
/********* WARNING, THIS IS BETA CODE. *********/ |
||||
/********* *********/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
/*************************************************************************/ |
||||
|
||||
|
||||
#ifndef __FTLRU_H__ |
||||
#define __FTLRU_H__ |
||||
|
||||
|
||||
#include <ft2build.h> |
||||
#include FT_FREETYPE_H |
||||
|
||||
#ifdef FREETYPE_H |
||||
#error "freetype.h of FreeType 1 has been loaded!" |
||||
#error "Please fix the directory search order for header files" |
||||
#error "so that freetype.h of FreeType 2 is found first." |
||||
#endif |
||||
|
||||
|
||||
FT_BEGIN_HEADER |
||||
|
||||
|
||||
/* generic list key type */ |
||||
typedef FT_Pointer FT_LruKey; |
||||
|
||||
/* a list list handle */ |
||||
typedef struct FT_LruListRec_* FT_LruList; |
||||
|
||||
/* a list class handle */ |
||||
typedef const struct FT_LruList_ClassRec_* FT_LruList_Class; |
||||
|
||||
/* a list node handle */ |
||||
typedef struct FT_LruNodeRec_* FT_LruNode; |
||||
|
||||
/* the list node structure */ |
||||
typedef struct FT_LruNodeRec_ |
||||
{ |
||||
FT_LruNode next; |
||||
FT_LruKey key; |
||||
|
||||
} FT_LruNodeRec; |
||||
|
||||
|
||||
/* the list structure */ |
||||
typedef struct FT_LruListRec_ |
||||
{ |
||||
FT_Memory memory; |
||||
FT_LruList_Class clazz; |
||||
FT_LruNode nodes; |
||||
FT_UInt max_nodes; |
||||
FT_UInt num_nodes; |
||||
FT_Pointer data; |
||||
|
||||
} FT_LruListRec; |
||||
|
||||
|
||||
/* initialize a list list */ |
||||
typedef FT_Error |
||||
(*FT_LruList_InitFunc)( FT_LruList list ); |
||||
|
||||
/* finalize a list list */ |
||||
typedef void |
||||
(*FT_LruList_DoneFunc)( FT_LruList list ); |
||||
|
||||
/* this method is used to initialize a new list element node */ |
||||
typedef FT_Error |
||||
(*FT_LruNode_InitFunc)( FT_LruNode node, |
||||
FT_LruKey key, |
||||
FT_Pointer data ); |
||||
|
||||
/* this method is used to finalize a given list element node */ |
||||
typedef void |
||||
(*FT_LruNode_DoneFunc)( FT_LruNode node, |
||||
FT_Pointer data ); |
||||
|
||||
/* If defined, this method is called when the list if full */ |
||||
/* during the lookup process -- it is used to change the contents */ |
||||
/* of a list element node instead of calling `done_element()', */ |
||||
/* then `init_element()'. Set it to 0 for default behaviour. */ |
||||
typedef FT_Error |
||||
(*FT_LruNode_FlushFunc)( FT_LruNode node, |
||||
FT_LruKey new_key, |
||||
FT_Pointer data ); |
||||
|
||||
/* If defined, this method is used to compare a list element node */ |
||||
/* with a given key during a lookup. If set to 0, the `key' */ |
||||
/* fields will be directly compared instead. */ |
||||
typedef FT_Bool |
||||
(*FT_LruNode_CompareFunc)( FT_LruNode node, |
||||
FT_LruKey key, |
||||
FT_Pointer data ); |
||||
|
||||
/* A selector is used to indicate whether a given list element node */ |
||||
/* is part of a selection for FT_LruList_Remove_Selection(). The */ |
||||
/* functrion must return true (i.e., non-null) to indicate that the */ |
||||
/* node is part of it. */ |
||||
typedef FT_Bool |
||||
(*FT_LruNode_SelectFunc)( FT_LruNode node, |
||||
FT_Pointer data, |
||||
FT_Pointer list_data ); |
||||
|
||||
/* LRU class */ |
||||
typedef struct FT_LruList_ClassRec_ |
||||
{ |
||||
FT_UInt list_size; |
||||
FT_LruList_InitFunc list_init; /* optional */ |
||||
FT_LruList_DoneFunc list_done; /* optional */ |
||||
|
||||
FT_UInt node_size; |
||||
FT_LruNode_InitFunc node_init; /* MANDATORY */ |
||||
FT_LruNode_DoneFunc node_done; /* optional */ |
||||
FT_LruNode_FlushFunc node_flush; /* optional */ |
||||
FT_LruNode_CompareFunc node_compare; /* optional */ |
||||
|
||||
} FT_LruList_ClassRec; |
||||
|
||||
|
||||
/* The following functions must be exported in the case where */ |
||||
/* applications would want to write their own cache classes. */ |
||||
|
||||
FT_EXPORT( FT_Error ) |
||||
FT_LruList_New( FT_LruList_Class clazz, |
||||
FT_UInt max_elements, |
||||
FT_Pointer user_data, |
||||
FT_Memory memory, |
||||
FT_LruList *alist ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FT_LruList_Reset( FT_LruList list ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FT_LruList_Destroy ( FT_LruList list ); |
||||
|
||||
FT_EXPORT( FT_Error ) |
||||
FT_LruList_Lookup( FT_LruList list, |
||||
FT_LruKey key, |
||||
FT_LruNode *anode ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FT_LruList_Remove( FT_LruList list, |
||||
FT_LruNode node ); |
||||
|
||||
FT_EXPORT( void ) |
||||
FT_LruList_Remove_Selection( FT_LruList list, |
||||
FT_LruNode_SelectFunc select_func, |
||||
FT_Pointer select_data ); |
||||
|
||||
/* */ |
||||
|
||||
FT_END_HEADER |
||||
|
||||
|
||||
#endif /* __FTLRU_H__ */ |
||||
|
||||
|
||||
/* END */ |
@ -0,0 +1,380 @@ |
||||
#include <ft2build.h> |
||||
#include FT_CACHE_H |
||||
#include FT_CACHE_INTERNAL_GLYPH_H |
||||
#include FT_CACHE_INTERNAL_IMAGE_H |
||||
#include FT_CACHE_INTERNAL_SBITS_H |
||||
#include FT_INTERNAL_MEMORY_H |
||||
|
||||
#include "ftcerror.h" |
||||
|
||||
|
||||
/*
|
||||
* Basic Families |
||||
* |
||||
* |
||||
*/ |
||||
typedef struct FTC_BasicAttrRec_ |
||||
{ |
||||
FTC_ScalerRec scaler; |
||||
FT_UInt load_flags; |
||||
|
||||
} FTC_BasicAttrRec, *FTC_BasicAttrs; |
||||
|
||||
#define FTC_BASIC_ATTR_COMPARE(a,b) \ |
||||
( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
|
||||
(a)->load_flags == (b)->load_flags ) |
||||
|
||||
#define FTC_BASIC_ATTR_HASH(a) \ |
||||
( FTC_SCALER_HASH(&(a)->scaler) + 31*(a)->load_flags ) |
||||
|
||||
|
||||
typedef struct FTC_BasicQueryRec_ |
||||
{ |
||||
FTC_GQueryRec gquery; |
||||
FTC_BasicAttrRec attrs; |
||||
|
||||
} FTC_BasicQueryRec, *FTC_BasicQuery; |
||||
|
||||
|
||||
|
||||
typedef struct FTC_BasicFamilyRec_ |
||||
{ |
||||
FTC_FamilyRec family; |
||||
FTC_BasicAttrRec attrs; |
||||
|
||||
} FTC_BasicFamilyRec, *FTC_BasicFamily; |
||||
|
||||
|
||||
static FT_Bool |
||||
ftc_basic_family_compare( FTC_BasicFamily family, |
||||
FTC_BasicQuery query ) |
||||
{ |
||||
return FT_BOOL( FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ) ); |
||||
} |
||||
|
||||
static FT_Error |
||||
ftc_basic_family_init( FTC_BasicFamily family, |
||||
FTC_BasicQuery query, |
||||
FTC_Cache cache ) |
||||
{ |
||||
ftc_family_init( FTC_FAMILY( family ), cache ); |
||||
family->attrs = query->attrs; |
||||
return 0; |
||||
} |
||||
|
||||
static FT_Error |
||||
ftc_basic_family_reset( FTC_BasicFamily family, |
||||
FTC_BasicQuery query ) |
||||
{ |
||||
family->attrs = query->attrs; |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static FT_Bool |
||||
ftc_basic_gnode_compare_faceid( FTC_GNode gnode, |
||||
FTC_FaceID face_id, |
||||
FTC_Cache cache ) |
||||
{ |
||||
FTC_BasicFamily family = (FTC_BasicFamily) gnode->family; |
||||
FT_Bool result; |
||||
|
||||
result = FT_BOOL( family->attrs.scaler.face_id == face_id ); |
||||
if ( result ) |
||||
{ |
||||
/* we must call this function to avoid this node from appearing
|
||||
* in later lookups with the same face_id !! |
||||
*/ |
||||
FTC_GNode_UnselectFamily( gnode, cache ); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
|
||||
static FT_UInt |
||||
ftc_basic_family_get_count( FTC_BasicFamily family, |
||||
FTC_Manager manager ) |
||||
{ |
||||
FT_Error error; |
||||
FT_Face face; |
||||
FT_UInt result = 0; |
||||
|
||||
error = FTC_Manager_LookupFace( manager, &family->attrs.scaler.face_id, |
||||
&face ); |
||||
if ( !error ) |
||||
result = face->num_glyphs; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
static FT_Error |
||||
ftc_basic_family_load_bitmap( FTC_BasicFamily family, |
||||
FT_UInt gindex, |
||||
FTC_Manager manager, |
||||
FT_Face *aface ) |
||||
{ |
||||
FT_Error error; |
||||
FT_Size size; |
||||
|
||||
error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size ); |
||||
if ( !error ) |
||||
{ |
||||
FT_Face face = size->face; |
||||
|
||||
error = FT_Load_Glyph( face, gindex, family->attrs.load_flags | |
||||
FT_LOAD_RENDER ); |
||||
if ( !error ) |
||||
*aface = face; |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
|
||||
static FT_Error |
||||
ftc_basic_family_load_glyph( FTC_BasicFamily family, |
||||
FT_UInt gindex, |
||||
FTC_Cache cache, |
||||
FT_Glyph *aglyph ) |
||||
{ |
||||
FT_Error error; |
||||
FTC_Scaler scaler = &family->attrs.scaler; |
||||
FT_Face face; |
||||
FT_Size size; |
||||
|
||||
/* we will now load the glyph image */ |
||||
error = FTC_Manager_LookupSize( cache->manager, |
||||
scaler, |
||||
&size ); |
||||
if ( !error ) |
||||
{ |
||||
face = size->face; |
||||
|
||||
error = FT_Load_Glyph( face, gindex, family->attrs.load_flags ); |
||||
if ( !error ) |
||||
{ |
||||
if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || |
||||
face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) |
||||
{ |
||||
/* ok, copy it */ |
||||
FT_Glyph glyph; |
||||
|
||||
|
||||
error = FT_Get_Glyph( face->glyph, &glyph ); |
||||
if ( !error ) |
||||
{ |
||||
*aglyph = glyph; |
||||
goto Exit; |
||||
} |
||||
} |
||||
else |
||||
error = FTC_Err_Invalid_Argument; |
||||
} |
||||
} |
||||
Exit: |
||||
return error; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* |
||||
* basic image cache |
||||
* |
||||
*/ |
||||
|
||||
static const FTC_IFamilyClassRec ftc_basic_image_family_class = |
||||
{ |
||||
{ |
||||
sizeof( FTC_BasicFamilyRec ), |
||||
(FTC_MruNode_CompareFunc) ftc_basic_family_compare, |
||||
(FTC_MruNode_InitFunc) ftc_basic_family_init, |
||||
(FTC_MruNode_ResetFunc) ftc_basic_family_reset, |
||||
(FTC_MruNode_DoneFunc) NULL |
||||
}, |
||||
(FTC_IFamily_LoadGlyphFunc) ftc_basic_family_load_glyph |
||||
}; |
||||
|
||||
|
||||
|
||||
static const FTC_GCacheClassRec ftc_basic_image_cache_class = |
||||
{ |
||||
{ |
||||
(FTC_Node_NewFunc) FTC_INode_New, |
||||
(FTC_Node_WeightFunc) FTC_INode_Weight, |
||||
(FTC_Node_CompareFunc) FTC_GNode_Compare, |
||||
(FTC_Node_CompareFunc) ftc_basic_gnode_compare_faceid, |
||||
(FTC_Node_FreeFunc) FTC_INode_Free, |
||||
|
||||
sizeof( FTC_GCacheRec ), |
||||
(FTC_Cache_InitFunc) FTC_GCache_Init, |
||||
(FTC_Cache_DoneFunc) FTC_GCache_Done |
||||
}, |
||||
(FTC_MruListClass) & ftc_basic_image_family_class |
||||
}; |
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) |
||||
FTC_ImageCache_New( FTC_Manager manager, |
||||
FTC_ImageCache *acache ) |
||||
{ |
||||
return FTC_GCache_New( manager, & ftc_basic_image_cache_class, |
||||
(FTC_GCache*) acache ); |
||||
} |
||||
|
||||
|
||||
/* documentation is in ftcimage.h */ |
||||
|
||||
FT_EXPORT_DEF( FT_Error ) |
||||
FTC_ImageCache_Lookup( FTC_ImageCache cache, |
||||
FTC_ImageType type, |
||||
FT_UInt gindex, |
||||
FT_Glyph *aglyph, |
||||
FTC_Node *anode ) |
||||
{ |
||||
FTC_BasicQueryRec query; |
||||
FTC_INode node; |
||||
FT_Error error; |
||||
FT_UInt32 hash; |
||||
|
||||
|
||||
/* some argument checks are delayed to FTC_Cache_Lookup */ |
||||
if ( !aglyph ) |
||||
{ |
||||
error = FTC_Err_Invalid_Argument; |
||||
goto Exit; |
||||
} |
||||
|
||||
*aglyph = NULL; |
||||
if ( anode ) |
||||
*anode = NULL; |
||||
|
||||
query.attrs.scaler.face_id = type->face_id; |
||||
query.attrs.scaler.width = type->width; |
||||
query.attrs.scaler.height = type->height; |
||||
query.attrs.scaler.pixel = 1; |
||||
query.attrs.load_flags = type->flags; |
||||
|
||||
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) ^ (gindex << 8); |
||||
|
||||
error = FTC_GCache_Lookup( FTC_GCACHE( cache ), |
||||
hash, gindex, |
||||
FTC_GQUERY( &query ), |
||||
(FTC_Node*) &node ); |
||||
if ( !error ) |
||||
{ |
||||
*aglyph = FTC_INODE(node)->glyph; |
||||
|
||||
if ( anode ) |
||||
{ |
||||
*anode = FTC_NODE(node); |
||||
FTC_NODE(node)->ref_count++; |
||||
} |
||||
} |
||||
|
||||
Exit: |
||||
return error; |
||||
} |
||||
|
||||
|
||||
|
||||
/*
|
||||
* |
||||
* basic small bitmap cache |
||||
* |
||||
*/ |
||||
|
||||
|
||||
static const FTC_SFamilyClassRec ftc_basic_sbit_family_class = |
||||
{ |
||||
{ |
||||
sizeof( FTC_BasicFamilyRec ), |
||||
(FTC_MruNode_CompareFunc) ftc_basic_family_compare, |
||||
(FTC_MruNode_InitFunc) ftc_basic_family_init, |
||||
(FTC_MruNode_ResetFunc) ftc_basic_family_reset, |
||||
(FTC_MruNode_DoneFunc) NULL |
||||
}, |
||||
(FTC_SFamily_GetCountFunc) ftc_basic_family_get_count, |
||||
(FTC_SFamily_LoadGlyphFunc) ftc_basic_family_load_bitmap |
||||
}; |
||||
|
||||
|
||||
static const FTC_GCacheClassRec ftc_basic_sbit_cache_class = |
||||
{ |
||||
{ |
||||
(FTC_Node_NewFunc) FTC_SNode_New, |
||||
(FTC_Node_WeightFunc) FTC_SNode_Weight, |
||||
(FTC_Node_CompareFunc) FTC_SNode_Compare, |
||||
(FTC_Node_CompareFunc) ftc_basic_gnode_compare_faceid, |
||||
(FTC_Node_FreeFunc) FTC_SNode_Free, |
||||
|
||||
sizeof( FTC_GCacheRec ), |
||||
(FTC_Cache_InitFunc) FTC_GCache_Init, |
||||
(FTC_Cache_DoneFunc) FTC_GCache_Done |
||||
}, |
||||
(FTC_MruListClass) & ftc_basic_sbit_family_class |
||||
}; |
||||
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) |
||||
FTC_SBitCache_New( FTC_Manager manager, |
||||
FTC_SBitCache *acache ) |
||||
{ |
||||
return FTC_GCache_New( manager, & ftc_basic_sbit_cache_class, |
||||
(FTC_GCache*) acache ); |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) |
||||
FTC_SBitCache_Lookup( FTC_SBitCache cache, |
||||
FTC_ImageType type, |
||||
FT_UInt gindex, |
||||
FTC_SBit *ansbit, |
||||
FTC_Node *anode ) |
||||
{ |
||||
FT_Error error; |
||||
FTC_BasicQueryRec query; |
||||
FTC_SNode node; |
||||
FT_UInt32 hash; |
||||
|
||||
if ( anode ) |
||||
*anode = NULL; |
||||
|
||||
/* other argument checks delayed to FTC_Cache_Lookup */ |
||||
if ( !ansbit ) |
||||
return FTC_Err_Invalid_Argument; |
||||
|
||||
*ansbit = NULL; |
||||
|
||||
query.attrs.scaler.face_id = type->face_id; |
||||
query.attrs.scaler.width = type->width; |
||||
query.attrs.scaler.height = type->height; |
||||
query.attrs.scaler.pixel = 1; |
||||
query.attrs.load_flags = type->flags; |
||||
|
||||
/* beware, the hash must be the same for all glyph ranges !!
|
||||
*/ |
||||
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) ^ |
||||
(gindex/FTC_SBIT_ITEMS_PER_NODE); |
||||
|
||||
error = FTC_GCache_Lookup( FTC_GCACHE( cache ), |
||||
hash, |
||||
gindex, |
||||
FTC_GQUERY( &query ), |
||||
(FTC_Node*) &node ); |
||||
if ( error ) |
||||
goto Exit; |
||||
|
||||
*ansbit = node->sbits + ( gindex - FTC_GNODE(node)->gindex ); |
||||
|
||||
if ( anode ) |
||||
{ |
||||
*anode = FTC_NODE( node ); |
||||
FTC_NODE( node )->ref_count++; |
||||
} |
||||
|
||||
Exit: |
||||
return error; |
||||
} |
||||
|
@ -0,0 +1,204 @@ |
||||
#include <ft2build.h> |
||||
#include FT_CACHE_H |
||||
#include FT_CACHE_INTERNAL_MRU_H |
||||
#include FT_INTERNAL_OBJECTS_H |
||||
#include FT_INTERNAL_DEBUG_H |
||||
|
||||
#include "ftcerror.h" |
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FTC_MruList_Init( FTC_MruList list, |
||||
FTC_MruListClass clazz, |
||||
FT_UInt max_nodes, |
||||
FT_Pointer data, |
||||
FT_Memory memory ) |
||||
{ |
||||
list->num_nodes = 0; |
||||
list->max_nodes = max_nodes; |
||||
list->nodes = NULL; |
||||
list->clazz = *clazz; |
||||
list->data = data; |
||||
list->memory = memory; |
||||
} |
||||
|
||||
|
||||
static void |
||||
ftc_mrulist_free_nodes( FTC_MruList list, |
||||
FTC_MruNode *plist ) |
||||
{ |
||||
FT_Memory memory = list->memory; |
||||
|
||||
while ( *plist ) |
||||
{ |
||||
FTC_MruNode node = *plist; |
||||
|
||||
*plist = node->next; |
||||
|
||||
if ( list->clazz.node_done ) |
||||
list->clazz.node_done( node, list->data ); |
||||
|
||||
FT_FREE( node ); |
||||
} |
||||
} |
||||
|
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_Reset( FTC_MruList list ) |
||||
{ |
||||
ftc_mrulist_free_nodes( list, &list->nodes ); |
||||
list->num_nodes = 0; |
||||
} |
||||
|
||||
|
||||
FT_EXPORT( void ) |
||||
FTC_MruList_Done( FTC_MruList list ) |
||||
{ |
||||
FTC_MruList_Reset( list ); |
||||
} |
||||
|
||||
|
||||
FT_EXPORT( FT_Error ) |
||||
FTC_MruList_Lookup( FTC_MruList list, |
||||
FT_Pointer key, |
||||
FTC_MruNode *anode ) |
||||
{ |
||||
FT_Memory memory = list->memory; |
||||
FTC_MruNode_CompareFunc compare = list->clazz.node_compare; |
||||
FTC_MruNode *plast, *pnode, *pfirst; |
||||
FTC_MruNode node; |
||||
FT_Error error = 0; |
||||
|
||||
pfirst = &list->nodes; |
||||
plast = pnode = pfirst; |
||||
|
||||
for (;;) |
||||
{ |
||||
node = *pnode; |
||||
if ( node == NULL ) |
||||
goto NewNode; |
||||
if ( compare( node, key ) ) |
||||
break; |
||||
plast = pnode; |
||||
pnode = &node->next; |
||||
} |
||||
|
||||
if ( node != *pfirst ) |
||||
{ |
||||
*pnode = node->next; |
||||
node->next = *pfirst; |
||||
*pfirst = node; |
||||
} |
||||
goto Exit; |
||||
|
||||
NewNode: |
||||
if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes ) |
||||
{ |
||||
node = *plast; |
||||
|
||||
if ( node ) |
||||
{ |
||||
*plast = NULL; |
||||
list->num_nodes--; |
||||
|
||||
if ( list->clazz.node_reset ) |
||||
{ |
||||
error = list->clazz.node_reset( node, key, list->data ); |
||||
if ( !error ) goto AddNode; |
||||
} |
||||
|
||||
list->clazz.node_done( node, list->data ); |
||||
} |
||||
} |
||||
else if ( FT_ALLOC( node, list->clazz.node_size ) ) |
||||
goto Exit; |
||||
|
||||
error = list->clazz.node_init( node, key, list->data ); |
||||
if ( error ) |
||||
{ |
||||
if ( list->clazz.node_done ) |
||||
list->clazz.node_done( node, list->data ); |
||||
|
||||
FT_FREE( node ); |
||||
goto Exit; |
||||
} |
||||
|
||||
AddNode: |
||||
node->next = list->nodes; |
||||
list->nodes = node; |
||||
list->num_nodes++; |
||||
|
||||
Exit: |
||||
*anode = node; |
||||
return error; |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FTC_MruList_Remove( FTC_MruList list, |
||||
FTC_MruNode node ) |
||||
{ |
||||
FTC_MruNode *pnode = &list->nodes; |
||||
|
||||
for ( ;; ) |
||||
{ |
||||
if ( *pnode == NULL ) /* should not happen !! */ |
||||
{ |
||||
FT_ERROR(( "%s: trying to remove unknown node !!\n", |
||||
"FTC_MruList_Remove" )); |
||||
return; |
||||
} |
||||
|
||||
if ( *pnode == node ) |
||||
break; |
||||
|
||||
pnode = &node->next; |
||||
} |
||||
|
||||
*pnode = node->next; |
||||
node->next = NULL; |
||||
list->num_nodes--; |
||||
|
||||
{ |
||||
FT_Memory memory = list->memory; |
||||
|
||||
if ( list->clazz.node_done ) |
||||
list->clazz.node_done( node, list->data ); |
||||
|
||||
FT_FREE( node ); |
||||
} |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FTC_MruList_RemoveSelection( FTC_MruList list, |
||||
FTC_MruNode_CompareFunc select, |
||||
FT_Pointer key ) |
||||
{ |
||||
FTC_MruNode *pnode = &list->nodes; |
||||
FTC_MruNode node, free = NULL;; |
||||
|
||||
if ( select ) |
||||
{ |
||||
for (;;) |
||||
{ |
||||
FTC_MruNode node = *pnode; |
||||
|
||||
if ( node == NULL ) |
||||
break; |
||||
|
||||
if ( select( node, key ) ) |
||||
{ |
||||
*pnode = node->next; |
||||
node->next = free; |
||||
free = node; |
||||
} |
||||
else |
||||
pnode = &node->next; |
||||
} |
||||
} |
||||
|
||||
ftc_mrulist_free_nodes( list, &free ); |
||||
} |
||||
|
||||
/* END */ |
||||
|
@ -1,390 +0,0 @@ |
||||
/***************************************************************************/ |
||||
/* */ |
||||
/* ftlru.c */ |
||||
/* */ |
||||
/* Simple LRU list-cache (body). */ |
||||
/* */ |
||||
/* Copyright 2000-2001, 2002, 2003 by */ |
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
||||
/* */ |
||||
/* This file is part of the FreeType project, and may only be used, */ |
||||
/* modified, and distributed under the terms of the FreeType project */ |
||||
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
||||
/* this file you indicate that you have read the license and */ |
||||
/* understand and accept it fully. */ |
||||
/* */ |
||||
/***************************************************************************/ |
||||
|
||||
|
||||
#include <ft2build.h> |
||||
#include FT_CACHE_H |
||||
#include FT_CACHE_INTERNAL_LRU_H |
||||
#include FT_LIST_H |
||||
#include FT_INTERNAL_OBJECTS_H |
||||
#include FT_INTERNAL_DEBUG_H |
||||
|
||||
#include "ftcerror.h" |
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) |
||||
FT_LruList_New( FT_LruList_Class clazz, |
||||
FT_UInt max_nodes, |
||||
FT_Pointer user_data, |
||||
FT_Memory memory, |
||||
FT_LruList *alist ) |
||||
{ |
||||
FT_Error error; |
||||
FT_LruList list; |
||||
|
||||
|
||||
if ( !alist || !clazz ) |
||||
return FTC_Err_Invalid_Argument; |
||||
|
||||
*alist = NULL; |
||||
if ( !FT_ALLOC( list, clazz->list_size ) ) |
||||
{ |
||||
/* initialize common fields */ |
||||
list->clazz = clazz; |
||||
list->memory = memory; |
||||
list->max_nodes = max_nodes; |
||||
list->data = user_data; |
||||
|
||||
if ( clazz->list_init ) |
||||
{ |
||||
error = clazz->list_init( list ); |
||||
if ( error ) |
||||
{ |
||||
if ( clazz->list_done ) |
||||
clazz->list_done( list ); |
||||
|
||||
FT_FREE( list ); |
||||
} |
||||
} |
||||
|
||||
*alist = list; |
||||
} |
||||
|
||||
return error; |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FT_LruList_Destroy( FT_LruList list ) |
||||
{ |
||||
FT_Memory memory; |
||||
FT_LruList_Class clazz; |
||||
|
||||
|
||||
if ( !list ) |
||||
return; |
||||
|
||||
memory = list->memory; |
||||
clazz = list->clazz; |
||||
|
||||
FT_LruList_Reset( list ); |
||||
|
||||
if ( clazz->list_done ) |
||||
clazz->list_done( list ); |
||||
|
||||
FT_FREE( list ); |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FT_LruList_Reset( FT_LruList list ) |
||||
{ |
||||
FT_LruNode node; |
||||
FT_LruList_Class clazz; |
||||
FT_Memory memory; |
||||
|
||||
|
||||
if ( !list ) |
||||
return; |
||||
|
||||
node = list->nodes; |
||||
clazz = list->clazz; |
||||
memory = list->memory; |
||||
|
||||
while ( node ) |
||||
{ |
||||
FT_LruNode next = node->next; |
||||
|
||||
|
||||
if ( clazz->node_done ) |
||||
clazz->node_done( node, list->data ); |
||||
|
||||
FT_FREE( node ); |
||||
node = next; |
||||
} |
||||
|
||||
list->nodes = NULL; |
||||
list->num_nodes = 0; |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) |
||||
FT_LruList_Lookup( FT_LruList list, |
||||
FT_LruKey key, |
||||
FT_LruNode *anode ) |
||||
{ |
||||
FT_Error error = 0; |
||||
FT_LruNode node, *pnode; |
||||
FT_LruList_Class clazz; |
||||
FT_LruNode result = NULL; |
||||
FT_Memory memory; |
||||
|
||||
|
||||
if ( !list || !key || !anode ) |
||||
return FTC_Err_Invalid_Argument; |
||||
|
||||
pnode = &list->nodes; |
||||
node = NULL; |
||||
clazz = list->clazz; |
||||
memory = list->memory; |
||||
|
||||
if ( clazz->node_compare ) |
||||
{ |
||||
for (;;) |
||||
{ |
||||
node = *pnode; |
||||
if ( node == NULL ) |
||||
break; |
||||
|
||||
if ( clazz->node_compare( node, key, list->data ) ) |
||||
break; |
||||
|
||||
pnode = &(*pnode)->next; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for (;;) |
||||
{ |
||||
node = *pnode; |
||||
if ( node == NULL ) |
||||
break; |
||||
|
||||
if ( node->key == key ) |
||||
break; |
||||
|
||||
pnode = &(*pnode)->next; |
||||
} |
||||
} |
||||
|
||||
if ( node ) |
||||
{ |
||||
/* move element to top of list */ |
||||
if ( list->nodes != node ) |
||||
{ |
||||
*pnode = node->next; |
||||
node->next = list->nodes; |
||||
list->nodes = node; |
||||
} |
||||
result = node; |
||||
goto Exit; |
||||
} |
||||
|
||||
/* Since we haven't found the relevant element in our LRU list,
|
||||
* we're going to "create" a new one. |
||||
* |
||||
* The following code is a bit special, because it tries to handle |
||||
* out-of-memory conditions (OOM) in an intelligent way. |
||||
* |
||||
* More precisely, if not enough memory is available to create a |
||||
* new node or "flush" an old one, we need to remove the oldest |
||||
* elements from our list, and try again. Since several tries may |
||||
* be necessary, a loop is needed. |
||||
* |
||||
* This loop will only exit when: |
||||
* |
||||
* - a new node was successfully created, or an old node flushed |
||||
* - an error other than FTC_Err_Out_Of_Memory is detected |
||||
* - the list of nodes is empty, and it isn't possible to create |
||||
* new nodes |
||||
* |
||||
* On each unsuccessful attempt, one node will be removed from the list. |
||||
* |
||||
*/ |
||||
|
||||
{ |
||||
FT_Int drop_last = ( list->max_nodes > 0 &&
|
||||
list->num_nodes >= list->max_nodes ); |
||||
|
||||
for (;;) |
||||
{ |
||||
node = NULL; |
||||
|
||||
/* If "drop_last" is true, we should free the last node in
|
||||
* the list to make room for a new one. Note that we reuse |
||||
* its memory block to save allocation calls. |
||||
*/ |
||||
if ( drop_last ) |
||||
{ |
||||
/* find the last node in the list
|
||||
*/ |
||||
pnode = &list->nodes; |
||||
node = *pnode; |
||||
|
||||
if ( node == NULL ) |
||||
{ |
||||
FT_ASSERT( list->num_nodes == 0 ); |
||||
error = FTC_Err_Out_Of_Memory; |
||||
goto Exit; |
||||
} |
||||
|
||||
FT_ASSERT( list->num_nodes > 0 ); |
||||
|
||||
while ( node->next ) |
||||
{ |
||||
pnode = &node->next; |
||||
node = *pnode; |
||||
} |
||||
|
||||
/* Remove it from the list, and try to "flush" it. Doing this will
|
||||
* save a significant number of dynamic allocations compared to |
||||
* a classic destroy/create cycle. |
||||
*/ |
||||
*pnode = NULL; |
||||
list->num_nodes--; |
||||
|
||||
if ( clazz->node_flush ) |
||||
{ |
||||
error = clazz->node_flush( node, key, list->data ); |
||||
if ( !error ) |
||||
goto Success; |
||||
|
||||
/* Note that if an error occured during the flush, we need to
|
||||
* finalize it since it is potentially in incomplete state. |
||||
*/ |
||||
} |
||||
|
||||
/* We finalize, but do not destroy the last node, we
|
||||
* simply reuse its memory block! |
||||
*/ |
||||
if ( clazz->node_done ) |
||||
clazz->node_done( node, list->data ); |
||||
|
||||
FT_MEM_ZERO( node, clazz->node_size ); |
||||
} |
||||
else |
||||
{ |
||||
/* Try to allocate a new node when "drop_last" is not TRUE.
|
||||
* This usually happens on the first pass, when the LRU list |
||||
* is not already full. |
||||
*/ |
||||
if ( FT_ALLOC( node, clazz->node_size ) ) |
||||
goto Fail; |
||||
} |
||||
|
||||
FT_ASSERT( node != NULL ); |
||||
|
||||
node->key = key; |
||||
error = clazz->node_init( node, key, list->data ); |
||||
if ( error ) |
||||
{ |
||||
if ( clazz->node_done ) |
||||
clazz->node_done( node, list->data ); |
||||
|
||||
FT_FREE( node ); |
||||
goto Fail; |
||||
} |
||||
|
||||
Success: |
||||
result = node; |
||||
|
||||
node->next = list->nodes; |
||||
list->nodes = node; |
||||
list->num_nodes++; |
||||
goto Exit; |
||||
|
||||
Fail: |
||||
if ( error != FTC_Err_Out_Of_Memory ) |
||||
goto Exit; |
||||
|
||||
drop_last = 1; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
Exit: |
||||
*anode = result; |
||||
return error; |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FT_LruList_Remove( FT_LruList list, |
||||
FT_LruNode node ) |
||||
{ |
||||
FT_LruNode *pnode; |
||||
|
||||
|
||||
if ( !list || !node ) |
||||
return; |
||||
|
||||
pnode = &list->nodes; |
||||
for (;;) |
||||
{ |
||||
if ( *pnode == node ) |
||||
{ |
||||
FT_Memory memory = list->memory; |
||||
FT_LruList_Class clazz = list->clazz; |
||||
|
||||
|
||||
*pnode = node->next; |
||||
node->next = NULL; |
||||
|
||||
if ( clazz->node_done ) |
||||
clazz->node_done( node, list->data ); |
||||
|
||||
FT_FREE( node ); |
||||
list->num_nodes--; |
||||
break; |
||||
} |
||||
|
||||
pnode = &(*pnode)->next; |
||||
} |
||||
} |
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) |
||||
FT_LruList_Remove_Selection( FT_LruList list, |
||||
FT_LruNode_SelectFunc select_func, |
||||
FT_Pointer select_data ) |
||||
{ |
||||
FT_LruNode *pnode, node; |
||||
FT_LruList_Class clazz; |
||||
FT_Memory memory; |
||||
|
||||
|
||||
if ( !list || !select_func ) |
||||
return; |
||||
|
||||
memory = list->memory; |
||||
clazz = list->clazz; |
||||
pnode = &list->nodes; |
||||
|
||||
for (;;) |
||||
{ |
||||
node = *pnode; |
||||
if ( node == NULL ) |
||||
break; |
||||
|
||||
if ( select_func( node, select_data, list->data ) ) |
||||
{ |
||||
*pnode = node->next; |
||||
node->next = NULL; |
||||
|
||||
if ( clazz->node_done ) |
||||
clazz->node_done( node, list ); |
||||
|
||||
FT_FREE( node ); |
||||
list->num_nodes--; |
||||
} |
||||
else |
||||
pnode = &(*pnode)->next; |
||||
} |
||||
} |
||||
|
||||
|
||||
/* END */ |
Loading…
Reference in new issue