diff --git a/include/freetype/cache/ftccache.h b/include/freetype/cache/ftccache.h index b6294595c..ef4027e54 100644 --- a/include/freetype/cache/ftccache.h +++ b/include/freetype/cache/ftccache.h @@ -1,193 +1,251 @@ -/***************************************************************************/ -/* */ -/* ftccache.h */ -/* */ -/* FreeType internal cache interface (specification). */ -/* */ -/* Copyright 2000-2001, 2002 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 __FTCCACHE_H__ -#define __FTCCACHE_H__ - - -#include FT_CACHE_INTERNAL_MRU_H - -FT_BEGIN_HEADER - - /* handle to cache object */ - typedef struct FTC_CacheRec_* FTC_Cache; - - /* handle to cache class */ - typedef const struct FTC_CacheClassRec_* FTC_CacheClass; - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE NODE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* Each cache controls one or more cache nodes. Each node is part of */ - /* the global_lru list of the manager. Its `data' field however is used */ - /* as a reference count for now. */ - /* */ - /* A node can be anything, depending on the type of information held by */ - /* the cache. It can be an individual glyph image, a set of bitmaps */ - /* glyphs for a given size, some metrics, etc. */ - /* */ - /*************************************************************************/ - - /* structure size should be 20 bytes on 32-bits machines */ - typedef struct FTC_NodeRec_ - { - FTC_MruNodeRec mru; /* circular mru list pointer */ - FTC_Node link; /* used for hashing */ - FT_UInt32 hash; /* used for hashing too */ - FT_UShort cache_index; /* index of cache the node belongs to */ - FT_Short ref_count; /* reference count for this node */ - - } FTC_NodeRec; - - -#define FTC_NODE( x ) ( (FTC_Node)(x) ) -#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) - -#define FTC_NODE__NEXT(x) FTC_NODE( (x)->mru.next ) -#define FTC_NODE__PREV(x) FTC_NODE( (x)->mru.prev ) - - /*************************************************************************/ - /* */ - /* These functions are exported so that they can be called from */ - /* user-provided cache classes; otherwise, they are really part of the */ - /* cache sub-system internals. */ - /* */ - - /* reserved for manager's use */ - FT_EXPORT( void ) - ftc_node_destroy( FTC_Node node, - FTC_Manager manager ); - - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* initialize a new cache node */ - typedef FT_Error (*FTC_Node_NewFunc)( FTC_Node *pnode, - FT_Pointer query, - FTC_Cache cache ); - - typedef FT_ULong (*FTC_Node_WeightFunc)( FTC_Node node, - FTC_Cache cache ); - - /* compare a node to a given key pair */ - typedef FT_Bool (*FTC_Node_CompareFunc)( FTC_Node node, - FT_Pointer key, - FTC_Cache cache ); - - - typedef void (*FTC_Node_FreeFunc)( FTC_Node node, - FTC_Cache cache ); - - typedef FT_Error (*FTC_Cache_InitFunc)( FTC_Cache cache ); - - typedef void (*FTC_Cache_DoneFunc)( FTC_Cache cache ); - - - typedef struct FTC_CacheClassRec_ - { - FTC_Node_NewFunc node_new; - FTC_Node_WeightFunc node_weight; - FTC_Node_CompareFunc node_compare; - FTC_Node_CompareFunc node_remove_faceid; - FTC_Node_FreeFunc node_free; - - FT_UInt cache_size; - FTC_Cache_InitFunc cache_init; - FTC_Cache_DoneFunc cache_done; - - } FTC_CacheClassRec; - - /* each cache really implements a dynamic hash table to manage its nodes */ - typedef struct FTC_CacheRec_ - { - FT_UFast p; - FT_UFast mask; - FT_Long slack; - FTC_Node* buckets; - - FTC_CacheClassRec clazz; /* local copy, for speed */ - - FTC_Manager manager; - FT_Memory memory; - FT_UInt index; /* in manager's table */ - - FTC_CacheClass org_class; /* original class pointer */ - - } FTC_CacheRec; - - -#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) -#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) - - - /* default cache initialize */ - FT_EXPORT( FT_Error ) - FTC_Cache_Init( FTC_Cache cache ); - - /* default cache finalizer */ - FT_EXPORT( void ) - FTC_Cache_Done( FTC_Cache cache ); - - /* call this function to lookup the cache. if no corresponding - * node is found, a new one is automatically created. This function - * is capable of flushing the cache adequately to make room for the - * new cache object. - */ - FT_EXPORT( FT_Error ) - FTC_Cache_Lookup( FTC_Cache cache, - FT_UInt32 hash, - FT_Pointer query, - FTC_Node *anode ); - - /* remove all nodes that relate to a given face_id. This is useful - * when un-installing fonts. Note that if a cache node relates to - * the face_id, but is locked (i.e. has 'ref_count > 0'), the node - * will _not_ be destroyed, but its internal face_id reference will - * be modified. - * - * the end result will be that the node will never come back - * in further lookup requests, and will be flushed on demand from - * the cache normally when its reference count reaches 0 - */ - FT_EXPORT( void ) - FTC_Cache_RemoveFaceID( FTC_Cache cache, - FTC_FaceID face_id ); - - /* */ - -FT_END_HEADER - - -#endif /* __FTCCACHE_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftccache.h */ +/* */ +/* FreeType internal cache interface (specification). */ +/* */ +/* Copyright 2000-2001, 2002 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 __FTCCACHE_H__ +#define __FTCCACHE_H__ + + +#include FT_CACHE_INTERNAL_MRU_H + +FT_BEGIN_HEADER + + /* handle to cache object */ + typedef struct FTC_CacheRec_* FTC_Cache; + + /* handle to cache class */ + typedef const struct FTC_CacheClassRec_* FTC_CacheClass; + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Each cache controls one or more cache nodes. Each node is part of */ + /* the global_lru list of the manager. Its `data' field however is used */ + /* as a reference count for now. */ + /* */ + /* A node can be anything, depending on the type of information held by */ + /* the cache. It can be an individual glyph image, a set of bitmaps */ + /* glyphs for a given size, some metrics, etc. */ + /* */ + /*************************************************************************/ + + /* structure size should be 20 bytes on 32-bits machines */ + typedef struct FTC_NodeRec_ + { + FTC_MruNodeRec mru; /* circular mru list pointer */ + FTC_Node link; /* used for hashing */ + FT_UInt32 hash; /* used for hashing too */ + FT_UShort cache_index; /* index of cache the node belongs to */ + FT_Short ref_count; /* reference count for this node */ + + } FTC_NodeRec; + + +#define FTC_NODE( x ) ( (FTC_Node)(x) ) +#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) + +#define FTC_NODE__NEXT(x) FTC_NODE( (x)->mru.next ) +#define FTC_NODE__PREV(x) FTC_NODE( (x)->mru.prev ) + + /*************************************************************************/ + /* */ + /* These functions are exported so that they can be called from */ + /* user-provided cache classes; otherwise, they are really part of the */ + /* cache sub-system internals. */ + /* */ + + /* reserved for manager's use */ + FT_EXPORT( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* initialize a new cache node */ + typedef FT_Error (*FTC_Node_NewFunc)( FTC_Node *pnode, + FT_Pointer query, + FTC_Cache cache ); + + typedef FT_ULong (*FTC_Node_WeightFunc)( FTC_Node node, + FTC_Cache cache ); + + /* compare a node to a given key pair */ + typedef FT_Bool (*FTC_Node_CompareFunc)( FTC_Node node, + FT_Pointer key, + FTC_Cache cache ); + + + typedef void (*FTC_Node_FreeFunc)( FTC_Node node, + FTC_Cache cache ); + + typedef FT_Error (*FTC_Cache_InitFunc)( FTC_Cache cache ); + + typedef void (*FTC_Cache_DoneFunc)( FTC_Cache cache ); + + + typedef struct FTC_CacheClassRec_ + { + FTC_Node_NewFunc node_new; + FTC_Node_WeightFunc node_weight; + FTC_Node_CompareFunc node_compare; + FTC_Node_CompareFunc node_remove_faceid; + FTC_Node_FreeFunc node_free; + + FT_UInt cache_size; + FTC_Cache_InitFunc cache_init; + FTC_Cache_DoneFunc cache_done; + + } FTC_CacheClassRec; + + /* each cache really implements a dynamic hash table to manage its nodes */ + typedef struct FTC_CacheRec_ + { + FT_UFast p; + FT_UFast mask; + FT_Long slack; + FTC_Node* buckets; + + FTC_CacheClassRec clazz; /* local copy, for speed */ + + FTC_Manager manager; + FT_Memory memory; + FT_UInt index; /* in manager's table */ + + FTC_CacheClass org_class; /* original class pointer */ + + } FTC_CacheRec; + + +#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) +#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) + + + /* default cache initialize */ + FT_EXPORT( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ); + + /* default cache finalizer */ + FT_EXPORT( void ) + FTC_Cache_Done( FTC_Cache cache ); + + /* call this function to lookup the cache. if no corresponding + * node is found, a new one is automatically created. This function + * is capable of flushing the cache adequately to make room for the + * new cache object. + */ + FT_EXPORT( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ); + + FT_EXPORT( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ); + + /* remove all nodes that relate to a given face_id. This is useful + * when un-installing fonts. Note that if a cache node relates to + * the face_id, but is locked (i.e. has 'ref_count > 0'), the node + * will _not_ be destroyed, but its internal face_id reference will + * be modified. + * + * the end result will be that the node will never come back + * in further lookup requests, and will be flushed on demand from + * the cache normally when its reference count reaches 0 + */ + FT_EXPORT( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ); + + + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_Node *_bucket, *_pnode, _node; \ + FTC_Cache _cache = FTC_CACHE(cache); \ + FT_UInt32 _hash = (FT_UInt32)(hash); \ + FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ + FT_UInt _idx; \ + \ + error = 0; \ + _idx = _hash & _cache->mask; \ + if ( _idx < _cache->p ) \ + _idx = _hash & (_cache->mask*2 + 1); \ + \ + _bucket = _pnode = _cache->buckets + _idx; \ + for (;;) \ + { \ + _node = *_pnode; \ + if ( _node == NULL ) \ + goto _NewNode; \ + \ + if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) ) \ + break; \ + \ + _pnode = &_node->link; \ + } \ + \ + if ( _node != *_bucket ) \ + { \ + *_pnode = _node->link; \ + _node->link = *_bucket; \ + *_bucket = _node; \ + } \ + \ + { \ + FTC_Manager _manager = _cache->manager; \ + \ + if ( _node != _manager->nodes_list ) \ + FTC_MruNode_Up( (FTC_MruNode*)&_manager->nodes_list, \ + (FTC_MruNode)_node ); \ + } \ + goto _Ok; \ + \ + _NewNode: \ + error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ + \ + _Ok: \ + *(FTC_Node*)&(node) = _node; \ + FT_END_STMNT + + + /* */ + +FT_END_HEADER + + +#endif /* __FTCCACHE_H__ */ + + +/* END */ diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h index 2b42bda04..1a7874b21 100644 --- a/include/freetype/cache/ftcglyph.h +++ b/include/freetype/cache/ftcglyph.h @@ -1,266 +1,295 @@ -/***************************************************************************/ -/* */ -/* ftcglyph.h */ -/* */ -/* FreeType abstract glyph 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. */ -/* */ -/***************************************************************************/ - - - /* - * - * FTC_GCache is an _abstract_ cache object optimized to store glyph - * data. It works as follows: - * - * - it manages FTC_GNode objects. Each one of them can hold one or more - * glyph "items". Item types are not specified in the FTC_GCache but in - * classes that extend it - * - * - glyph attributes, like face_id, character size, render mode, etc.. - * can be grouped in abstract "glyph families". This avoids storing - * the attributes within the FTC_GCache, since it is likely that many - * FTC_GNodes will belong to the same family in typical uses - * - * - each FTC_GNode is thus a FTC_Node with two additionnal fields: - * - * * gindex :: a glyph index, or the first index in a glyph range - * * family :: a pointer to a glyph "family" - * - * - Family types are not fully specific in the FTC_Family type, but - * by classes that extend it. - * - * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. They - * share an FTC_Family sub-class called FTC_BasicFamily which is used to - * store the following data: face_id, pixel/point sizes, load flags. - * for more details, see the file "src/cache/ftcbasic.c" - * - * Client applications can extend FTC_GNode with their own FTC_GNode - * and FTC_Family sub-classes to implement more complex caches (e.g. - * handling automatic synthetis, like obliquing & emboldening, colored - * glyphs, etc...) - * - * See also the FTC_ICache & FTC_SCache classes in "ftcimage.h" and - * "ftcsbits.h", which both extend FTC_GCache with additionnal - * optimizations. - * - * - * a typical FTC_GCache implementation must provide at least the following: - * - * - FTC_GNode sub-class, e.g. MyNode, with relevant methods, i.e: - * my_node_new ( must call FTC_GNode_Init ) - * my_node_free ( must call FTC_GNode_Done ) - * my_node_compare ( must call FTC_GNode_Compare ) - * my_node_remove_faceid ( must call ftc_gnode_unselect in case - * of match ) - * - * - * - FTC_Family sub-class, e.g. MyFamily, with relevant methods, e.g.: - * my_family_compare - * my_family_init - * my_family_reset (optional) - * my_family_done - * - * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query - * data. - * - * - provide constant structures for a FTC_GNodeClass - * - * - MyCacheNew() can be implemented easily as a call to the convenience - * function FTC_GCache_New - * - * - implement MyCacheLookup with a call to FTC_GCache_Lookup. This - * function will automatically: - * - * - search for the corresponding family in the cache, or create - * a new one if necessary. put it in FTC_GQUERY(myquery).family - * - * - call FTC_Cache_Lookup - * - * if it returns NULL, you should create a new node, then call - * ftc_cache_add as usual. - */ - - /*************************************************************************/ - /* */ - /* Important: The functions defined in this file are only used to */ - /* implement an abstract glyph cache class. You need to */ - /* provide additional logic to implement a complete cache. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /********* *********/ - /********* WARNING, THIS IS BETA CODE. *********/ - /********* *********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - -#ifndef __FTCGLYPH_H__ -#define __FTCGLYPH_H__ - - -#include -#include FT_CACHE_INTERNAL_MANAGER_H - - -FT_BEGIN_HEADER - - - /* - * we can group glyph in "families". Each family correspond to a - * given face id, character size, transform, etc... - * - * families are implemented as MRU list nodes. They are reference-counted - */ - - typedef struct FTC_FamilyRec_ - { - FTC_MruNodeRec mrunode; - FT_UInt num_nodes; /* current number of nodes in this family */ - FTC_Cache cache; - FTC_MruListClass clazz; - - } FTC_FamilyRec, *FTC_Family; - -#define FTC_FAMILY(x) ( (FTC_Family)(x) ) -#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) - - - typedef struct FTC_GNodeRec_ - { - FTC_NodeRec node; - FTC_Family family; - FT_UInt gindex; - - } FTC_GNodeRec, *FTC_GNode; - -#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) -#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) - - - typedef struct FTC_GQueryRec_ - { - FT_UInt gindex; - FTC_Family family; - - } FTC_GQueryRec, *FTC_GQuery; - -#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) - - - - - /*************************************************************************/ - /* */ - /* These functions are exported so that they can be called from */ - /* user-provided cache classes; otherwise, they are really part of the */ - /* cache sub-system internals. */ - /* */ - - /* must be called by derived FTC_Node_InitFunc routines */ - FT_EXPORT( void ) - FTC_GNode_Init( FTC_GNode node, - FT_UInt gindex, /* glyph index for node */ - FTC_Family family ); - - /* returns TRUE iff the query's glyph index correspond to the node; */ - /* this assumes that the "family" and "hash" fields of the query are */ - /* already correctly set */ - FT_EXPORT( FT_Bool ) - FTC_GNode_Compare( FTC_GNode gnode, - FTC_GQuery gquery ); - - /* call this function to clear a node's family. this is necessary - * to implement the "node_remove_faceid" cache method correctly - */ - FT_EXPORT( void ) - FTC_GNode_UnselectFamily( FTC_GNode gnode, - FTC_Cache cache ); - - /* must be called by derived FTC_Node_DoneFunc routines */ - FT_EXPORT( void ) - FTC_GNode_Done( FTC_GNode node, - FTC_Cache cache ); - - - FT_EXPORT( void ) - FTC_Family_Init( FTC_Family family, - FTC_Cache cache ); - - typedef struct FTC_GCacheRec_ - { - FTC_CacheRec cache; - FTC_MruListRec families; - - } FTC_GCacheRec, *FTC_GCache; - - -#define FTC_GCACHE(x) ((FTC_GCache)(x)) - - - /* can be used as @FTC_Cache_InitFunc */ - FT_EXPORT( FT_Error ) - FTC_GCache_Init( FTC_GCache cache ); - - - /* can be used as @FTC_Cache_DoneFunc */ - FT_EXPORT( void ) - FTC_GCache_Done( FTC_GCache cache ); - - - /* the glyph cache class adds fields for the family implementation */ - typedef struct FTC_GCacheClassRec_ - { - FTC_CacheClassRec clazz; - FTC_MruListClass family_class; - - } FTC_GCacheClassRec; - - typedef const FTC_GCacheClassRec* FTC_GCacheClass; - -#define FTC_GCACHE_CLASS(x) ((FTC_GCacheClass)(x)) - -#define FTC_CACHE__GCACHE_CLASS(x) FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class ) -#define FTC_CACHE__FAMILY_CLASS(x) ((FTC_MruListClass) FTC_CACHE__GCACHE_CLASS(x)->family_class) - - - /* convenience function. use instead of FTC_Manager_Register_Cache */ - FT_EXPORT( FT_Error ) - FTC_GCache_New( FTC_Manager manager, - FTC_GCacheClass clazz, - FTC_GCache *acache ); - - FT_EXPORT( FT_Error ) - FTC_GCache_Lookup( FTC_GCache cache, - FT_UInt32 hash, - FT_UInt gindex, - FTC_GQuery query, - FTC_Node *anode ); - - /* */ - -FT_END_HEADER - - -#endif /* __FTCGLYPH_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftcglyph.h */ +/* */ +/* FreeType abstract glyph 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. */ +/* */ +/***************************************************************************/ + + + /* + * + * FTC_GCache is an _abstract_ cache object optimized to store glyph + * data. It works as follows: + * + * - it manages FTC_GNode objects. Each one of them can hold one or more + * glyph "items". Item types are not specified in the FTC_GCache but in + * classes that extend it + * + * - glyph attributes, like face_id, character size, render mode, etc.. + * can be grouped in abstract "glyph families". This avoids storing + * the attributes within the FTC_GCache, since it is likely that many + * FTC_GNodes will belong to the same family in typical uses + * + * - each FTC_GNode is thus a FTC_Node with two additionnal fields: + * + * * gindex :: a glyph index, or the first index in a glyph range + * * family :: a pointer to a glyph "family" + * + * - Family types are not fully specific in the FTC_Family type, but + * by classes that extend it. + * + * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. They + * share an FTC_Family sub-class called FTC_BasicFamily which is used to + * store the following data: face_id, pixel/point sizes, load flags. + * for more details, see the file "src/cache/ftcbasic.c" + * + * Client applications can extend FTC_GNode with their own FTC_GNode + * and FTC_Family sub-classes to implement more complex caches (e.g. + * handling automatic synthetis, like obliquing & emboldening, colored + * glyphs, etc...) + * + * See also the FTC_ICache & FTC_SCache classes in "ftcimage.h" and + * "ftcsbits.h", which both extend FTC_GCache with additionnal + * optimizations. + * + * + * a typical FTC_GCache implementation must provide at least the following: + * + * - FTC_GNode sub-class, e.g. MyNode, with relevant methods, i.e: + * my_node_new ( must call FTC_GNode_Init ) + * my_node_free ( must call FTC_GNode_Done ) + * my_node_compare ( must call FTC_GNode_Compare ) + * my_node_remove_faceid ( must call ftc_gnode_unselect in case + * of match ) + * + * + * - FTC_Family sub-class, e.g. MyFamily, with relevant methods, e.g.: + * my_family_compare + * my_family_init + * my_family_reset (optional) + * my_family_done + * + * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query + * data. + * + * - provide constant structures for a FTC_GNodeClass + * + * - MyCacheNew() can be implemented easily as a call to the convenience + * function FTC_GCache_New + * + * - implement MyCacheLookup with a call to FTC_GCache_Lookup. This + * function will automatically: + * + * - search for the corresponding family in the cache, or create + * a new one if necessary. put it in FTC_GQUERY(myquery).family + * + * - call FTC_Cache_Lookup + * + * if it returns NULL, you should create a new node, then call + * ftc_cache_add as usual. + */ + + /*************************************************************************/ + /* */ + /* Important: The functions defined in this file are only used to */ + /* implement an abstract glyph cache class. You need to */ + /* provide additional logic to implement a complete cache. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef __FTCGLYPH_H__ +#define __FTCGLYPH_H__ + + +#include +#include FT_CACHE_INTERNAL_MANAGER_H + + +FT_BEGIN_HEADER + + + /* + * we can group glyph in "families". Each family correspond to a + * given face id, character size, transform, etc... + * + * families are implemented as MRU list nodes. They are reference-counted + */ + + typedef struct FTC_FamilyRec_ + { + FTC_MruNodeRec mrunode; + FT_UInt num_nodes; /* current number of nodes in this family */ + FTC_Cache cache; + FTC_MruListClass clazz; + + } FTC_FamilyRec, *FTC_Family; + +#define FTC_FAMILY(x) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) + + + typedef struct FTC_GNodeRec_ + { + FTC_NodeRec node; + FTC_Family family; + FT_UInt gindex; + + } FTC_GNodeRec, *FTC_GNode; + +#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) +#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) + + + typedef struct FTC_GQueryRec_ + { + FT_UInt gindex; + FTC_Family family; + + } FTC_GQueryRec, *FTC_GQuery; + +#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) + + + + + /*************************************************************************/ + /* */ + /* These functions are exported so that they can be called from */ + /* user-provided cache classes; otherwise, they are really part of the */ + /* cache sub-system internals. */ + /* */ + + /* must be called by derived FTC_Node_InitFunc routines */ + FT_EXPORT( void ) + FTC_GNode_Init( FTC_GNode node, + FT_UInt gindex, /* glyph index for node */ + FTC_Family family ); + + /* returns TRUE iff the query's glyph index correspond to the node; */ + /* this assumes that the "family" and "hash" fields of the query are */ + /* already correctly set */ + FT_EXPORT( FT_Bool ) + FTC_GNode_Compare( FTC_GNode gnode, + FTC_GQuery gquery ); + + /* call this function to clear a node's family. this is necessary + * to implement the "node_remove_faceid" cache method correctly + */ + FT_EXPORT( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ); + + /* must be called by derived FTC_Node_DoneFunc routines */ + FT_EXPORT( void ) + FTC_GNode_Done( FTC_GNode node, + FTC_Cache cache ); + + + FT_EXPORT( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ); + + typedef struct FTC_GCacheRec_ + { + FTC_CacheRec cache; + FTC_MruListRec families; + + } FTC_GCacheRec, *FTC_GCache; + + +#define FTC_GCACHE(x) ((FTC_GCache)(x)) + + + /* can be used as @FTC_Cache_InitFunc */ + FT_EXPORT( FT_Error ) + FTC_GCache_Init( FTC_GCache cache ); + + + /* can be used as @FTC_Cache_DoneFunc */ + FT_EXPORT( void ) + FTC_GCache_Done( FTC_GCache cache ); + + + /* the glyph cache class adds fields for the family implementation */ + typedef struct FTC_GCacheClassRec_ + { + FTC_CacheClassRec clazz; + FTC_MruListClass family_class; + + } FTC_GCacheClassRec; + + typedef const FTC_GCacheClassRec* FTC_GCacheClass; + +#define FTC_GCACHE_CLASS(x) ((FTC_GCacheClass)(x)) + +#define FTC_CACHE__GCACHE_CLASS(x) FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class ) +#define FTC_CACHE__FAMILY_CLASS(x) ((FTC_MruListClass) FTC_CACHE__GCACHE_CLASS(x)->family_class) + + + /* convenience function. use instead of FTC_Manager_Register_Cache */ + FT_EXPORT( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ); + + FT_EXPORT( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_UInt32 hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ); + + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_GCache _gcache = FTC_GCACHE( cache ); \ + FTC_Family _family; \ + FTC_GQuery _gquery = (FTC_GQuery)( query ); \ + FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ + \ + _gquery->gindex = (gindex); \ + \ + FTC_MRULIST_LOOP( &_gcache->families, _family ) \ + { \ + if ( _fcompare( (FTC_MruNode)_family, _gquery ) ) \ + { \ + _gquery->family = _family; \ + goto _FamilyFound; \ + } \ + } \ + FTC_MRULIST_LOOP_END(); \ + \ + error = FTC_MruList_New( &_gcache->families, \ + _gquery, \ + (FTC_MruNode*)&_gquery->family ); \ + if ( !error ) \ + { \ + _FamilyFound: \ + FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ + } \ + FT_END_STMNT + /* */ + +FT_END_HEADER + + +#endif /* __FTCGLYPH_H__ */ + + +/* END */ diff --git a/include/freetype/cache/ftcmru.h b/include/freetype/cache/ftcmru.h index 5b329f1a3..85849aa06 100644 --- a/include/freetype/cache/ftcmru.h +++ b/include/freetype/cache/ftcmru.h @@ -1,165 +1,227 @@ -/***************************************************************************/ -/* */ -/* 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 -#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 - -#define xxFT_DEBUG_ERROR - -FT_BEGIN_HEADER - - typedef struct FTC_MruNodeRec_* FTC_MruNode; - - typedef struct FTC_MruNodeRec_ - { - FTC_MruNode next; - FTC_MruNode prev; - - } FTC_MruNodeRec; - - FT_EXPORT( void ) - FTC_MruNode_Prepend( FTC_MruNode *plist, - FTC_MruNode node ); - - FT_EXPORT( void ) - FTC_MruNode_Up( FTC_MruNode *plist, - FTC_MruNode node ); - - FT_EXPORT( void ) - FTC_MruNode_Remove( FTC_MruNode *plist, - FTC_MruNode node ); - - typedef struct FTC_MruListRec_* FTC_MruList; - - typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; - - 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( FTC_MruNode ) - FTC_MruList_Find( FTC_MruList list, - FT_Pointer key ); - - FT_EXPORT( FT_Error ) - FTC_MruList_New( FTC_MruList list, - FT_Pointer key, - FTC_MruNode *anode ); - - 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 */ +/***************************************************************************/ +/* */ +/* 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 +#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 + +#define xxFT_DEBUG_ERROR +#define FTC_INLINE + +FT_BEGIN_HEADER + + typedef struct FTC_MruNodeRec_* FTC_MruNode; + + typedef struct FTC_MruNodeRec_ + { + FTC_MruNode next; + FTC_MruNode prev; + + } FTC_MruNodeRec; + + FT_EXPORT( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_EXPORT( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_EXPORT( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ); + + typedef struct FTC_MruListRec_* FTC_MruList; + + typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; + + 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( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ); + + FT_EXPORT( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ); + + 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 ); + + +#ifdef FTC_INLINE + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + FT_BEGIN_STMNT \ + FTC_MruNode_CompareFunc _compare = (list)->clazz.node_compare; \ + FTC_MruNode _first, _node; \ + \ + error = 0; \ + _first = (list)->nodes; \ + _node = NULL; \ + \ + if ( _first ) \ + { \ + _node = _first; \ + do \ + { \ + if ( _compare( _node, (key) ) ) \ + { \ + *(FTC_MruNode*)&(node) = _node; \ + goto _Ok; \ + } \ + _node = _node->next; \ + } \ + while ( _node != _first) ; \ + } \ + \ + error = FTC_MruList_New( (list), (key), (FTC_MruNode*)&(node) ); \ + _Ok: \ + ; \ + FT_END_STMNT + +#else /* !FTC_INLINE */ + +#define FTC_MRULIST_LOOKUP_CMP( list, key, node, error ) \ + error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) ) + +#endif /* !FTC_INLINE */ + + +#define FTC_MRULIST_LOOP( list, node ) \ + FT_BEGIN_STMNT \ + FTC_MruNode _first = (list)->nodes; \ + \ + if ( _first ) \ + { \ + FTC_MruNode _node = _first; \ + do \ + { \ + *(FTC_MruNode*)&(node) = _node; + + +#define FTC_MRULIST_LOOP_END() \ + _node = _node->next; \ + } \ + while ( _node != _first ); \ + } \ + FT_END_STMNT + + /* */ + +FT_END_HEADER + + +#endif /* __FTCMRU_H__ */ + + +/* END */ diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c index b1f825ed7..3f8954830 100644 --- a/src/cache/ftcbasic.c +++ b/src/cache/ftcbasic.c @@ -1,373 +1,393 @@ -#include -#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_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; - } - - - 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; - } - - - - /* - * - * 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) NULL, - (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; - - 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) NULL, - (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; - } - +#include +#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_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; + } + + + 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; + } + + + + /* + * + * 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) NULL, + (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; + +#if 1 /* inlining is about 50% faster !! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + FTC_GNode_Compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, gindex, + FTC_GQUERY( &query ), + (FTC_Node*) &node ); +#endif + 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) NULL, + (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); + +#if 1 /* inlining is about 50% faster !! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + FTC_SNode_Compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, + gindex, + FTC_GQUERY( &query ), + (FTC_Node*) &node ); +#endif + 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; + } + diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c index e3b5bfcae..4db40a232 100644 --- a/src/cache/ftccache.c +++ b/src/cache/ftccache.c @@ -1,565 +1,578 @@ -/***************************************************************************/ -/* */ -/* ftccache.c */ -/* */ -/* The FreeType internal cache interface (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 -#include FT_CACHE_INTERNAL_MANAGER_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H - -#include "ftcerror.h" - - -#define FTC_HASH_MAX_LOAD 2 -#define FTC_HASH_MIN_LOAD 1 -#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD ) - -/* this one _must_ be a power of 2! */ -#define FTC_HASH_INITIAL_SIZE 8 - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE NODE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* add a new node to the head of the manager's circular MRU list */ - static void - ftc_node_mru_link( FTC_Node node, - FTC_Manager manager ) - { - FTC_MruNode_Prepend( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); - manager->num_nodes++; - } - - - /* remove a node from the manager's MRU list */ - static void - ftc_node_mru_unlink( FTC_Node node, - FTC_Manager manager ) - { - FTC_MruNode_Remove( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); - manager->num_nodes--; - } - - - /* move a node to the head of the manager's MRU list */ - static void - ftc_node_mru_up( FTC_Node node, - FTC_Manager manager ) - { - FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); - } - - - /* note that this function cannot fail. If we cannot re-size the - * buckets array appropriately, we simply degrade the hash table's - * performance !! - */ - static void - ftc_cache_resize( FTC_Cache cache ) - { - for (;;) - { - FTC_Node node, *pnode; - FT_UInt p = cache->p; - FT_UInt mask = cache->mask; - FT_UInt count = mask + p + 1; /* number of buckets */ - - /* do we need to shrink the buckets array ? - */ - if ( cache->slack < 0 ) - { - FTC_Node new_list = NULL; - - /* try to expand the buckets array _before_ splitting - * the bucket lists - */ - if ( p >= mask ) - { - FT_Memory memory = cache->memory; - - /* if we can't expand the array, leave immediately */ - if ( FT_MEM_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) ) - break; - } - - /* split a single bucket */ - pnode = cache->buckets + p; - - for (;;) - { - node = *pnode; - if ( node == NULL ) - break; - - if ( node->hash & ( mask + 1 ) ) - { - *pnode = node->link; - node->link = new_list; - new_list = node; - } - else - pnode = &node->link; - } - - cache->buckets[p + mask + 1] = new_list; - - cache->slack += FTC_HASH_MAX_LOAD; - - if ( p >= mask ) - { - cache->mask = 2 * mask + 1; - cache->p = 0; - } - else - cache->p = p + 1; - } - /* do we need to expand the buckets array ? - */ - else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD ) - { - FT_UInt old_index = p + mask; - FTC_Node* pold; - - if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE ) - break; - - if ( p == 0 ) - { - FT_Memory memory = cache->memory; - - /* if we can't shrink the array, leave immediately */ - if ( FT_MEM_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) ) - break; - - cache->mask >>= 1; - p = cache->mask; - } - else - p--; - - pnode = cache->buckets + p; - while ( *pnode ) - pnode = &(*pnode)->link; - - pold = cache->buckets + old_index; - *pnode = *pold; - *pold = NULL; - - cache->slack -= FTC_HASH_MAX_LOAD; - cache->p = p; - } - else /* the hash table is balanced */ - break; - } - } - - - - /* remove a node from its cache's hash table */ - static void - ftc_node_hash_unlink( FTC_Node node0, - FTC_Cache cache ) - { - FTC_Node *pnode; - FT_UInt idx; - - - idx = (FT_UInt)( node0->hash & cache->mask ); - if ( idx < cache->p ) - idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) ); - - pnode = cache->buckets + idx; - - for (;;) - { - FTC_Node node = *pnode; - - if ( node == NULL ) - { - FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" )); - return; - } - - if ( node == node0 ) - break; - - pnode = &(*pnode)->link; - } - - *pnode = node0->link; - node0->link = NULL; - - cache->slack++; - ftc_cache_resize( cache ); - } - - - - /* add a node to the "top" of its cache's hash table */ - static void - ftc_node_hash_link( FTC_Node node, - FTC_Cache cache ) - { - FTC_Node *pnode; - FT_UInt idx; - - - idx = (FT_UInt)( node->hash & cache->mask ); - if ( idx < cache->p ) - idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) ); - - pnode = cache->buckets + idx; - - node->link = *pnode; - *pnode = node; - - cache->slack--; - ftc_cache_resize( cache ); - } - - - - - /* remove a node from the cache manager */ - FT_EXPORT_DEF( void ) - ftc_node_destroy( FTC_Node node, - FTC_Manager manager ) - { - FTC_Cache cache; - - -#ifdef FT_DEBUG_ERROR - /* find node's cache */ - if ( node->cache_index >= manager->num_caches ) - { - FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); - return; - } -#endif - - cache = manager->caches[ node->cache_index ]; - -#ifdef FT_DEBUG_ERROR - if ( cache == NULL ) - { - FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); - return; - } -#endif - - manager->cur_weight -= cache->clazz.node_weight( node, cache ); - - /* remove node from mru list */ - ftc_node_mru_unlink( node, manager ); - - /* remove node from cache's hash table */ - ftc_node_hash_unlink( node, cache ); - - /* now finalize it */ - cache->clazz.node_free( node, cache ); - -#if 0 - /* check, just in case of general corruption :-) */ - if ( manager->num_nodes == 0 ) - FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n", - manager->num_nodes )); -#endif - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** ABSTRACT CACHE CLASS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_EXPORT( FT_Error ) - FTC_Cache_Init( FTC_Cache cache ) - { - FT_Memory memory = cache->memory; - - cache->p = 0; - cache->mask = FTC_HASH_INITIAL_SIZE - 1; - cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; - - return ( FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) ); - } - - - - FT_EXPORT_DEF( void ) - FTC_Cache_Clear( FTC_Cache cache ) - { - if ( cache ) - { - FTC_Manager manager = cache->manager; - FT_UFast i; - FT_UInt count; - - count = cache->p + cache->mask + 1; - - for ( i = 0; i < count; i++ ) - { - FTC_Node *pnode = cache->buckets + i, next, node = *pnode; - - - while ( node ) - { - next = node->link; - node->link = NULL; - - /* remove node from mru list */ - ftc_node_mru_unlink( node, manager ); - - /* now finalize it */ - manager->cur_weight -= cache->clazz.node_weight( node, cache ); - - cache->clazz.node_free( node, cache ); - node = next; - } - cache->buckets[i] = NULL; - } - ftc_cache_resize( cache ); - } - } - - - FT_EXPORT( void ) - FTC_Cache_Done( FTC_Cache cache ) - { - if ( cache->memory ) - { - FT_Memory memory = cache->memory; - - FTC_Cache_Clear( cache ); - - FT_FREE( cache->buckets ); - cache->mask = 0; - cache->p = 0; - cache->slack = 0; - - cache->memory = NULL; - } - } - - - - static void - ftc_cache_add( FTC_Cache cache, - FT_UInt32 hash, - FTC_Node node ) - { - node->hash = hash; - node->cache_index = (FT_UInt16) cache->index; - node->ref_count = 0; - - ftc_node_hash_link( node, cache ); - ftc_node_mru_link( node, cache->manager ); - - { - FTC_Manager manager = cache->manager; - - manager->cur_weight += cache->clazz.node_weight( node, cache ); - - if ( manager->cur_weight >= manager->max_weight ) - { - node->ref_count++; - FTC_Manager_Compress( manager ); - node->ref_count--; - } - } - } - - - FT_EXPORT( FT_Error ) - FTC_Cache_Lookup( FTC_Cache cache, - FT_UInt32 hash, - FT_Pointer query, - FTC_Node *anode ) - { - FT_UFast idx; - FTC_Node* bucket; - FTC_Node* pnode; - FTC_Node node; - FT_Error error = 0; - - FTC_Node_CompareFunc compare = cache->clazz.node_compare; - - - if ( cache == NULL || anode == NULL ) - return FT_Err_Invalid_Argument; - - idx = hash & cache->mask; - if ( idx < cache->p ) - idx = hash & ( cache->mask * 2 + 1 ); - - bucket = cache->buckets + idx; - pnode = bucket; - for (;;) - { - node = *pnode; - if ( node == NULL ) - goto NewNode; - - if ( node->hash == hash && compare( node, query, cache ) ) - break; - - pnode = &node->link; - } - - if ( node != *bucket ) - { - *pnode = node->link; - node->link = *bucket; - *bucket = node; - } - - /* move to head of MRU list */ - { - FTC_Manager manager = cache->manager; - - if ( node != manager->nodes_list ) - ftc_node_mru_up( node, manager ); - } - goto Exit; - - NewNode: - - /* - * try to allocate a new cache node. Note that in case of - * out-of-memory error (OOM), we'll flush the cache a bit, - * then try again. - * - * on each try, the "tries" variable gives the number - * of old nodes we want to flush from the manager's global list - * before the next allocation attempt. it barely doubles on - * each iteration - * - */ - error = cache->clazz.node_new( &node, query, cache ); - if ( error ) - goto FlushCache; - - AddNode: - /* don't assume that the cache has the same number of buckets, since - * our allocation request might have triggered global cache flushing - */ - ftc_cache_add( cache, hash, node ); - - Exit: - *anode = node; - return error; - - FlushCache: - node = NULL; - if ( error != FT_Err_Out_Of_Memory ) - goto Exit; - - { - FTC_Manager manager = cache->manager; - FT_UInt count, tries = 1; - - for (;;) - { - error = cache->clazz.node_new( &node, query, cache ); - if ( !error ) - break; - - node = NULL; - if ( error != FT_Err_Out_Of_Memory ) - goto Exit; - - count = FTC_Manager_FlushN( manager, tries ); - if ( count == 0 ) - goto Exit; - - if ( count == tries ) - { - count = tries*2; - if ( count < tries || count > manager->num_nodes ) - count = manager->num_nodes; - } - tries = count; - } - } - goto AddNode; - } - - - - - FT_EXPORT( void ) - FTC_Cache_RemoveFaceID( FTC_Cache cache, - FTC_FaceID face_id ) - { - FT_UFast i, count; - FTC_Manager manager = cache->manager; - FTC_Node free = NULL; - - count = cache->p + cache->mask; - for ( i = 0; i < count; i++ ) - { - FTC_Node* bucket = cache->buckets + i; - FTC_Node* pnode = bucket; - - for ( ;; ) - { - FTC_Node node = *pnode; - - if ( node == NULL ) - break; - - if ( cache->clazz.node_remove_faceid( node, face_id, cache ) ) - { - *pnode = node->link; - node->link = free; - free = node; - } - else - pnode = &node->link; - } - } - - /* remove all nodes in the free list - */ - while ( free ) - { - FTC_Node node; - - node = free; - free = node->link; - - manager->cur_weight -= cache->clazz.node_weight( node, cache ); - ftc_node_mru_unlink( node, manager ); - - cache->clazz.node_free( node, cache ); - - cache->slack ++; - } - - ftc_cache_resize( cache ); - } - -/* END */ +/***************************************************************************/ +/* */ +/* ftccache.c */ +/* */ +/* The FreeType internal cache interface (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 +#include FT_CACHE_INTERNAL_MANAGER_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H + +#include "ftcerror.h" + + +#define FTC_HASH_MAX_LOAD 2 +#define FTC_HASH_MIN_LOAD 1 +#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD ) + +/* this one _must_ be a power of 2! */ +#define FTC_HASH_INITIAL_SIZE 8 + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* add a new node to the head of the manager's circular MRU list */ + static void + ftc_node_mru_link( FTC_Node node, + FTC_Manager manager ) + { + FTC_MruNode_Prepend( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); + manager->num_nodes++; + } + + + /* remove a node from the manager's MRU list */ + static void + ftc_node_mru_unlink( FTC_Node node, + FTC_Manager manager ) + { + FTC_MruNode_Remove( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); + manager->num_nodes--; + } + + + /* move a node to the head of the manager's MRU list */ + static void + ftc_node_mru_up( FTC_Node node, + FTC_Manager manager ) + { + FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); + } + + + /* note that this function cannot fail. If we cannot re-size the + * buckets array appropriately, we simply degrade the hash table's + * performance !! + */ + static void + ftc_cache_resize( FTC_Cache cache ) + { + for (;;) + { + FTC_Node node, *pnode; + FT_UInt p = cache->p; + FT_UInt mask = cache->mask; + FT_UInt count = mask + p + 1; /* number of buckets */ + + /* do we need to shrink the buckets array ? + */ + if ( cache->slack < 0 ) + { + FTC_Node new_list = NULL; + + /* try to expand the buckets array _before_ splitting + * the bucket lists + */ + if ( p >= mask ) + { + FT_Memory memory = cache->memory; + + /* if we can't expand the array, leave immediately */ + if ( FT_MEM_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) ) + break; + } + + /* split a single bucket */ + pnode = cache->buckets + p; + + for (;;) + { + node = *pnode; + if ( node == NULL ) + break; + + if ( node->hash & ( mask + 1 ) ) + { + *pnode = node->link; + node->link = new_list; + new_list = node; + } + else + pnode = &node->link; + } + + cache->buckets[p + mask + 1] = new_list; + + cache->slack += FTC_HASH_MAX_LOAD; + + if ( p >= mask ) + { + cache->mask = 2 * mask + 1; + cache->p = 0; + } + else + cache->p = p + 1; + } + /* do we need to expand the buckets array ? + */ + else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD ) + { + FT_UInt old_index = p + mask; + FTC_Node* pold; + + if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE ) + break; + + if ( p == 0 ) + { + FT_Memory memory = cache->memory; + + /* if we can't shrink the array, leave immediately */ + if ( FT_MEM_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) ) + break; + + cache->mask >>= 1; + p = cache->mask; + } + else + p--; + + pnode = cache->buckets + p; + while ( *pnode ) + pnode = &(*pnode)->link; + + pold = cache->buckets + old_index; + *pnode = *pold; + *pold = NULL; + + cache->slack -= FTC_HASH_MAX_LOAD; + cache->p = p; + } + else /* the hash table is balanced */ + break; + } + } + + + + /* remove a node from its cache's hash table */ + static void + ftc_node_hash_unlink( FTC_Node node0, + FTC_Cache cache ) + { + FTC_Node *pnode; + FT_UInt idx; + + + idx = (FT_UInt)( node0->hash & cache->mask ); + if ( idx < cache->p ) + idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) ); + + pnode = cache->buckets + idx; + + for (;;) + { + FTC_Node node = *pnode; + + if ( node == NULL ) + { + FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" )); + return; + } + + if ( node == node0 ) + break; + + pnode = &(*pnode)->link; + } + + *pnode = node0->link; + node0->link = NULL; + + cache->slack++; + ftc_cache_resize( cache ); + } + + + + /* add a node to the "top" of its cache's hash table */ + static void + ftc_node_hash_link( FTC_Node node, + FTC_Cache cache ) + { + FTC_Node *pnode; + FT_UInt idx; + + + idx = (FT_UInt)( node->hash & cache->mask ); + if ( idx < cache->p ) + idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) ); + + pnode = cache->buckets + idx; + + node->link = *pnode; + *pnode = node; + + cache->slack--; + ftc_cache_resize( cache ); + } + + + + + /* remove a node from the cache manager */ + FT_EXPORT_DEF( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ) + { + FTC_Cache cache; + + +#ifdef FT_DEBUG_ERROR + /* find node's cache */ + if ( node->cache_index >= manager->num_caches ) + { + FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + cache = manager->caches[ node->cache_index ]; + +#ifdef FT_DEBUG_ERROR + if ( cache == NULL ) + { + FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* remove node from cache's hash table */ + ftc_node_hash_unlink( node, cache ); + + /* now finalize it */ + cache->clazz.node_free( node, cache ); + +#if 0 + /* check, just in case of general corruption :-) */ + if ( manager->num_nodes == 0 ) + FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n", + manager->num_nodes )); +#endif + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ABSTRACT CACHE CLASS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_EXPORT_DEF( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + + cache->p = 0; + cache->mask = FTC_HASH_INITIAL_SIZE - 1; + cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; + + return ( FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) ); + } + + + + FT_EXPORT_DEF( void ) + FTC_Cache_Clear( FTC_Cache cache ) + { + if ( cache ) + { + FTC_Manager manager = cache->manager; + FT_UFast i; + FT_UInt count; + + count = cache->p + cache->mask + 1; + + for ( i = 0; i < count; i++ ) + { + FTC_Node *pnode = cache->buckets + i, next, node = *pnode; + + + while ( node ) + { + next = node->link; + node->link = NULL; + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* now finalize it */ + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + cache->clazz.node_free( node, cache ); + node = next; + } + cache->buckets[i] = NULL; + } + ftc_cache_resize( cache ); + } + } + + + FT_EXPORT_DEF( void ) + FTC_Cache_Done( FTC_Cache cache ) + { + if ( cache->memory ) + { + FT_Memory memory = cache->memory; + + FTC_Cache_Clear( cache ); + + FT_FREE( cache->buckets ); + cache->mask = 0; + cache->p = 0; + cache->slack = 0; + + cache->memory = NULL; + } + } + + + + static void + ftc_cache_add( FTC_Cache cache, + FT_UInt32 hash, + FTC_Node node ) + { + node->hash = hash; + node->cache_index = (FT_UInt16) cache->index; + node->ref_count = 0; + + ftc_node_hash_link( node, cache ); + ftc_node_mru_link( node, cache->manager ); + + { + FTC_Manager manager = cache->manager; + + manager->cur_weight += cache->clazz.node_weight( node, cache ); + + if ( manager->cur_weight >= manager->max_weight ) + { + node->ref_count++; + FTC_Manager_Compress( manager ); + node->ref_count--; + } + } + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ) + { + FT_Error error; + FTC_Node node; + + /* + * try to allocate a new cache node. Note that in case of + * out-of-memory error (OOM), we'll flush the cache a bit, + * then try again. + * + * on each try, the "tries" variable gives the number + * of old nodes we want to flush from the manager's global list + * before the next allocation attempt. it barely doubles on + * each iteration + * + */ + error = cache->clazz.node_new( &node, query, cache ); + if ( error ) + goto FlushCache; + + AddNode: + /* don't assume that the cache has the same number of buckets, since + * our allocation request might have triggered global cache flushing + */ + ftc_cache_add( cache, hash, node ); + + Exit: + *anode = node; + return error; + + FlushCache: + node = NULL; + if ( error != FT_Err_Out_Of_Memory ) + goto Exit; + + { + FTC_Manager manager = cache->manager; + FT_UInt count, tries = 1; + + for (;;) + { + error = cache->clazz.node_new( &node, query, cache ); + if ( !error ) + break; + + node = NULL; + if ( error != FT_Err_Out_Of_Memory ) + goto Exit; + + count = FTC_Manager_FlushN( manager, tries ); + if ( count == 0 ) + goto Exit; + + if ( count == tries ) + { + count = tries*2; + if ( count < tries || count > manager->num_nodes ) + count = manager->num_nodes; + } + tries = count; + } + } + goto AddNode; + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ) + { + FT_UFast idx; + FTC_Node* bucket; + FTC_Node* pnode; + FTC_Node node; + FT_Error error = 0; + + FTC_Node_CompareFunc compare = cache->clazz.node_compare; + + + if ( cache == NULL || anode == NULL ) + return FT_Err_Invalid_Argument; + + idx = hash & cache->mask; + if ( idx < cache->p ) + idx = hash & ( cache->mask * 2 + 1 ); + + bucket = cache->buckets + idx; + pnode = bucket; + for (;;) + { + node = *pnode; + if ( node == NULL ) + goto NewNode; + + if ( node->hash == hash && compare( node, query, cache ) ) + break; + + pnode = &node->link; + } + + if ( node != *bucket ) + { + *pnode = node->link; + node->link = *bucket; + *bucket = node; + } + + /* move to head of MRU list */ + { + FTC_Manager manager = cache->manager; + + if ( node != manager->nodes_list ) + ftc_node_mru_up( node, manager ); + } + *anode = node; + return error; + + NewNode: + return FTC_Cache_NewNode( cache, hash, query, anode ); + } + + + + + FT_EXPORT_DEF( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ) + { + FT_UFast i, count; + FTC_Manager manager = cache->manager; + FTC_Node free = NULL; + + count = cache->p + cache->mask; + for ( i = 0; i < count; i++ ) + { + FTC_Node* bucket = cache->buckets + i; + FTC_Node* pnode = bucket; + + for ( ;; ) + { + FTC_Node node = *pnode; + + if ( node == NULL ) + break; + + if ( cache->clazz.node_remove_faceid( node, face_id, cache ) ) + { + *pnode = node->link; + node->link = free; + free = node; + } + else + pnode = &node->link; + } + } + + /* remove all nodes in the free list + */ + while ( free ) + { + FTC_Node node; + + node = free; + free = node->link; + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + ftc_node_mru_unlink( node, manager ); + + cache->clazz.node_free( node, cache ); + + cache->slack ++; + } + + ftc_cache_resize( cache ); + } + +/* END */ diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c index 034ab24b3..51855983c 100644 --- a/src/cache/ftccmap.c +++ b/src/cache/ftccmap.c @@ -1,266 +1,271 @@ -/***************************************************************************/ -/* */ -/* ftccmap.c */ -/* */ -/* FreeType CharMap 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 -#include FT_FREETYPE_H -#include FT_CACHE_H -#include FT_CACHE_INTERNAL_MANAGER_H -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_DEBUG_H -#include FT_TRUETYPE_IDS_H - -#include "ftcerror.h" - -#undef FT_COMPONENT -#define FT_COMPONENT trace_cache - - /*************************************************************************/ - /* */ - /* Each FTC_CMapNode contains a simple array to map a range of character */ - /* codes to equivalent glyph indices. */ - /* */ - /* For now, the implementation is very basic: Each node maps a range of */ - /* 128 consecutive character codes to their corresponding glyph indices. */ - /* */ - /* We could do more complex things, but I don't think it is really very */ - /* useful. */ - /* */ - /*************************************************************************/ - - - /* number of glyph indices / character code per node */ -#define FTC_CMAP_INDICES_MAX 128 - - /* compute a query/node hash */ -#define FTC_CMAP_HASH( faceid, index, charcode ) \ - ( FTC_FACE_ID_HASH( faceid ) + 211*( index ) + ((char_code) / FTC_CMAP_INDICES_MAX) ) - - /* the charmap query */ - typedef struct FTC_CMapQueryRec_ - { - FTC_FaceID face_id; - FT_UInt cmap_index; - FT_UInt32 char_code; - - } FTC_CMapQueryRec, *FTC_CMapQuery; - -#define FTC_CMAP_QUERY(x) ((FTC_CMapQuery)(x)) -#define FTC_CMAP_QUERY_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code ) - - /* the cmap cache node */ - typedef struct FTC_CMapNodeRec_ - { - FTC_NodeRec node; - FTC_FaceID face_id; - FT_UInt cmap_index; - FT_UInt32 first; /* first character in node */ - FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ - - } FTC_CMapNodeRec, *FTC_CMapNode; - -#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) -#define FTC_CMAP_NODE_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first ) - - /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ - /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ -#define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 ) - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CHARMAP NODES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - /* no need for specific finalizer; we use "ftc_node_done" directly */ - - FT_CALLBACK_DEF( void ) - ftc_cmap_node_free( FTC_CMapNode node, - FTC_Cache cache ) - { - FT_Memory memory = cache->memory; - - FT_FREE( node ); - } - - - /* initialize a new cmap node */ - FT_CALLBACK_DEF( FT_Error ) - ftc_cmap_node_new( FTC_CMapNode *anode, - FTC_CMapQuery query, - FTC_Cache cache ) - { - FT_Error error; - FT_Memory memory = cache->memory; - FTC_CMapNode node; - FT_UInt nn; - - if ( !FT_NEW( node ) ) - { - node->face_id = query->face_id; - node->cmap_index = query->cmap_index; - node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * - FTC_CMAP_INDICES_MAX; - - for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) - node->indices[nn] = FTC_CMAP_UNKNOWN; - } - - *anode = node; - return error; - } - - - /* compute the weight of a given cmap node */ - FT_CALLBACK_DEF( FT_ULong ) - ftc_cmap_node_weight( FTC_CMapNode cnode ) - { - FT_UNUSED( cnode ); - - return sizeof ( *cnode ); - } - - - /* compare a cmap node to a given query */ - FT_CALLBACK_DEF( FT_Bool ) - ftc_cmap_node_compare( FTC_CMapNode node, - FTC_CMapQuery query ) - { - if ( node->face_id == query->face_id && - node->cmap_index == query->cmap_index ) - { - FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); - - return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); - } - return 0; - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_cmap_node_remove_faceid( FTC_CMapNode node, - FTC_FaceID face_id ) - { - return FT_BOOL( node->face_id == face_id ); - } - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GLYPH IMAGE CACHE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_CALLBACK_TABLE_DEF - const FTC_CacheClassRec ftc_cmap_cache_class = - { - (FTC_Node_NewFunc) ftc_cmap_node_new, - (FTC_Node_WeightFunc) ftc_cmap_node_weight, - (FTC_Node_CompareFunc) ftc_cmap_node_compare, - (FTC_Node_CompareFunc) ftc_cmap_node_remove_faceid, - (FTC_Node_FreeFunc) ftc_cmap_node_free, - - sizeof ( FTC_CacheRec ), - (FTC_Cache_InitFunc) FTC_Cache_Init, - (FTC_Cache_DoneFunc) FTC_Cache_Done, - }; - - /* documentation is in ftccmap.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_CMapCache_New( FTC_Manager manager, - FTC_CMapCache *acache ) - { - return FTC_Manager_RegisterCache( manager, - & ftc_cmap_cache_class, - FTC_CACHE_P( acache ) ); - } - /* documentation is in ftccmap.h */ - - FT_EXPORT_DEF( FT_UInt ) - FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, - FTC_FaceID face_id, - FT_Int cmap_index, - FT_UInt32 char_code ) - { - FTC_Cache cache = FTC_CACHE( cmap_cache ); - FTC_CMapQueryRec query; - FTC_CMapNode node; - FT_Error error; - FT_UInt gindex = 0; - FT_UInt32 hash; - - - if ( !cache ) - { - FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" )); - return 0; - } - - query.face_id = face_id; - query.cmap_index = (FT_UInt)cmap_index; - query.char_code = char_code; - - hash = FTC_CMAP_HASH( face_id, cmap_index, char_code ); - - error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node ); - if ( error ) - goto Exit; - - FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX ); - - gindex = node->indices[ char_code - node->first ]; - if ( gindex == FTC_CMAP_UNKNOWN ) - { - FT_Face face; - - gindex = 0; - - error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face ); - if ( error ) - goto Exit; - - if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps ) - { - FT_CharMap old, cmap = NULL; - - old = face->charmap; - cmap = face->charmaps[ cmap_index ]; - - if (old != cmap) - FT_Set_Charmap( face, cmap ); - - gindex = FT_Get_Char_Index( face, char_code ); - - if (old != cmap) - FT_Set_Charmap( face, old ); - } - - node->indices[ char_code - node->first ] = gindex; - } - - Exit: - return gindex; - } - -/* END */ +/***************************************************************************/ +/* */ +/* ftccmap.c */ +/* */ +/* FreeType CharMap 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 +#include FT_FREETYPE_H +#include FT_CACHE_H +#include FT_CACHE_INTERNAL_MANAGER_H +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_DEBUG_H +#include FT_TRUETYPE_IDS_H + +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT trace_cache + + /*************************************************************************/ + /* */ + /* Each FTC_CMapNode contains a simple array to map a range of character */ + /* codes to equivalent glyph indices. */ + /* */ + /* For now, the implementation is very basic: Each node maps a range of */ + /* 128 consecutive character codes to their corresponding glyph indices. */ + /* */ + /* We could do more complex things, but I don't think it is really very */ + /* useful. */ + /* */ + /*************************************************************************/ + + + /* number of glyph indices / character code per node */ +#define FTC_CMAP_INDICES_MAX 128 + + /* compute a query/node hash */ +#define FTC_CMAP_HASH( faceid, index, charcode ) \ + ( FTC_FACE_ID_HASH( faceid ) + 211*( index ) + ((char_code) / FTC_CMAP_INDICES_MAX) ) + + /* the charmap query */ + typedef struct FTC_CMapQueryRec_ + { + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 char_code; + + } FTC_CMapQueryRec, *FTC_CMapQuery; + +#define FTC_CMAP_QUERY(x) ((FTC_CMapQuery)(x)) +#define FTC_CMAP_QUERY_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code ) + + /* the cmap cache node */ + typedef struct FTC_CMapNodeRec_ + { + FTC_NodeRec node; + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 first; /* first character in node */ + FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ + + } FTC_CMapNodeRec, *FTC_CMapNode; + +#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) +#define FTC_CMAP_NODE_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first ) + + /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ + /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ +#define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHARMAP NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* no need for specific finalizer; we use "ftc_node_done" directly */ + + FT_CALLBACK_DEF( void ) + ftc_cmap_node_free( FTC_CMapNode node, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + + FT_FREE( node ); + } + + + /* initialize a new cmap node */ + FT_CALLBACK_DEF( FT_Error ) + ftc_cmap_node_new( FTC_CMapNode *anode, + FTC_CMapQuery query, + FTC_Cache cache ) + { + FT_Error error; + FT_Memory memory = cache->memory; + FTC_CMapNode node; + FT_UInt nn; + + if ( !FT_NEW( node ) ) + { + node->face_id = query->face_id; + node->cmap_index = query->cmap_index; + node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * + FTC_CMAP_INDICES_MAX; + + for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) + node->indices[nn] = FTC_CMAP_UNKNOWN; + } + + *anode = node; + return error; + } + + + /* compute the weight of a given cmap node */ + FT_CALLBACK_DEF( FT_ULong ) + ftc_cmap_node_weight( FTC_CMapNode cnode ) + { + FT_UNUSED( cnode ); + + return sizeof ( *cnode ); + } + + + /* compare a cmap node to a given query */ + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_compare( FTC_CMapNode node, + FTC_CMapQuery query ) + { + if ( node->face_id == query->face_id && + node->cmap_index == query->cmap_index ) + { + FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); + + return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); + } + return 0; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_remove_faceid( FTC_CMapNode node, + FTC_FaceID face_id ) + { + return FT_BOOL( node->face_id == face_id ); + } + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE CACHE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_TABLE_DEF + const FTC_CacheClassRec ftc_cmap_cache_class = + { + (FTC_Node_NewFunc) ftc_cmap_node_new, + (FTC_Node_WeightFunc) ftc_cmap_node_weight, + (FTC_Node_CompareFunc) ftc_cmap_node_compare, + (FTC_Node_CompareFunc) ftc_cmap_node_remove_faceid, + (FTC_Node_FreeFunc) ftc_cmap_node_free, + + sizeof ( FTC_CacheRec ), + (FTC_Cache_InitFunc) FTC_Cache_Init, + (FTC_Cache_DoneFunc) FTC_Cache_Done, + }; + + /* documentation is in ftccmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ) + { + return FTC_Manager_RegisterCache( manager, + & ftc_cmap_cache_class, + FTC_CACHE_P( acache ) ); + } + /* documentation is in ftccmap.h */ + + FT_EXPORT_DEF( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ) + { + FTC_Cache cache = FTC_CACHE( cmap_cache ); + FTC_CMapQueryRec query; + FTC_CMapNode node; + FT_Error error; + FT_UInt gindex = 0; + FT_UInt32 hash; + + + if ( !cache ) + { + FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" )); + return 0; + } + + query.face_id = face_id; + query.cmap_index = (FT_UInt)cmap_index; + query.char_code = char_code; + + hash = FTC_CMAP_HASH( face_id, cmap_index, char_code ); + +#if 1 + FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query, + node, error ); +#else + error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node ); +#endif + if ( error ) + goto Exit; + + FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX ); + + gindex = node->indices[ char_code - node->first ]; + if ( gindex == FTC_CMAP_UNKNOWN ) + { + FT_Face face; + + gindex = 0; + + error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face ); + if ( error ) + goto Exit; + + if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps ) + { + FT_CharMap old, cmap = NULL; + + old = face->charmap; + cmap = face->charmaps[ cmap_index ]; + + if (old != cmap) + FT_Set_Charmap( face, cmap ); + + gindex = FT_Get_Char_Index( face, char_code ); + + if (old != cmap) + FT_Set_Charmap( face, old ); + } + + node->indices[ char_code - node->first ] = gindex; + } + + Exit: + return gindex; + } + +/* END */ diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c index d0a3777c9..a09d81549 100644 --- a/src/cache/ftcglyph.c +++ b/src/cache/ftcglyph.c @@ -1,153 +1,152 @@ -/***************************************************************************/ -/* */ -/* ftcglyph.c */ -/* */ -/* FreeType Glyph Image (FT_Glyph) cache (body). */ -/* */ -/* Copyright 2000-2001 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 -#include FT_CACHE_H -#include FT_CACHE_INTERNAL_GLYPH_H -#include FT_ERRORS_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H - -#include "ftcerror.h" - - - /* create a new chunk node, setting its cache index and ref count */ - FT_EXPORT_DEF( void ) - FTC_GNode_Init( FTC_GNode gnode, - FT_UInt gindex, - FTC_Family family ) - { - gnode->family = family; - gnode->gindex = gindex; - family->num_nodes++; - } - - - FT_EXPORT_DEF( void ) - FTC_GNode_UnselectFamily( FTC_GNode gnode, - FTC_Cache cache ) - { - FTC_Family family = gnode->family; - - gnode->family = NULL; - if ( family && --family->num_nodes <= 0 ) - { - FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family ); - } - } - - - FT_EXPORT_DEF( void ) - FTC_GNode_Done( FTC_GNode gnode, - FTC_Cache cache ) - { - /* finalize the node */ - gnode->gindex = 0; - - FTC_GNode_UnselectFamily( gnode, cache ); - } - - - FT_EXPORT_DEF( FT_Bool ) - FTC_GNode_Compare( FTC_GNode gnode, - FTC_GQuery gquery ) - { - return FT_BOOL( gnode->family == gquery->family && - gnode->gindex == gquery->gindex ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CHUNK SETS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_EXPORT_DEF( void ) - FTC_Family_Init( FTC_Family family, - FTC_Cache cache ) - { - FTC_GCacheClass clazz = FTC_CACHE__GCACHE_CLASS(cache); - - family->clazz = clazz->family_class; - family->num_nodes = 0; - family->cache = cache; - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_GCache_Init( FTC_GCache cache ) - { - FT_Error error; - - error = FTC_Cache_Init( FTC_CACHE(cache) ); - if ( !error ) - { - FTC_GCacheClass clazz = (FTC_GCacheClass) FTC_CACHE(cache)->org_class; - - FTC_MruList_Init( &cache->families, - clazz->family_class, - 0, /* no maximum here !! */ - cache, - FTC_CACHE(cache)->memory ); - } - return error; - } - - - FT_EXPORT_DEF( void ) - FTC_GCache_Done( FTC_GCache cache ) - { - FTC_Cache_Done( (FTC_Cache)cache ); - FTC_MruList_Done( &cache->families ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_GCache_New( FTC_Manager manager, - FTC_GCacheClass clazz, - FTC_GCache *acache ) - { - return FTC_Manager_RegisterCache( manager, (FTC_CacheClass) clazz, - (FTC_Cache*) acache ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_GCache_Lookup( FTC_GCache cache, - FT_UInt32 hash, - FT_UInt gindex, - FTC_GQuery query, - FTC_Node *anode ) - { - FT_Error error; - - query->gindex = gindex; - - error = FTC_MruList_Lookup( &cache->families, query, - (FTC_MruNode*) &query->family ); - if ( !error ) - error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, anode ); - - return error; - } - - -/* END */ +/***************************************************************************/ +/* */ +/* ftcglyph.c */ +/* */ +/* FreeType Glyph Image (FT_Glyph) cache (body). */ +/* */ +/* Copyright 2000-2001 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 +#include FT_CACHE_H +#include FT_CACHE_INTERNAL_GLYPH_H +#include FT_ERRORS_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H + +#include "ftcerror.h" + + + /* create a new chunk node, setting its cache index and ref count */ + FT_EXPORT_DEF( void ) + FTC_GNode_Init( FTC_GNode gnode, + FT_UInt gindex, + FTC_Family family ) + { + gnode->family = family; + gnode->gindex = gindex; + family->num_nodes++; + } + + + FT_EXPORT_DEF( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ) + { + FTC_Family family = gnode->family; + + gnode->family = NULL; + if ( family && --family->num_nodes <= 0 ) + { + FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family ); + } + } + + + FT_EXPORT_DEF( void ) + FTC_GNode_Done( FTC_GNode gnode, + FTC_Cache cache ) + { + /* finalize the node */ + gnode->gindex = 0; + + FTC_GNode_UnselectFamily( gnode, cache ); + } + + + FT_EXPORT_DEF( FT_Bool ) + FTC_GNode_Compare( FTC_GNode gnode, + FTC_GQuery gquery ) + { + return FT_BOOL( gnode->family == gquery->family && + gnode->gindex == gquery->gindex ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHUNK SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_EXPORT_DEF( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ) + { + FTC_GCacheClass clazz = FTC_CACHE__GCACHE_CLASS(cache); + + family->clazz = clazz->family_class; + family->num_nodes = 0; + family->cache = cache; + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_GCache_Init( FTC_GCache cache ) + { + FT_Error error; + + error = FTC_Cache_Init( FTC_CACHE(cache) ); + if ( !error ) + { + FTC_GCacheClass clazz = (FTC_GCacheClass) FTC_CACHE(cache)->org_class; + + FTC_MruList_Init( &cache->families, + clazz->family_class, + 0, /* no maximum here !! */ + cache, + FTC_CACHE(cache)->memory ); + } + return error; + } + + + FT_EXPORT_DEF( void ) + FTC_GCache_Done( FTC_GCache cache ) + { + FTC_Cache_Done( (FTC_Cache)cache ); + FTC_MruList_Done( &cache->families ); + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ) + { + return FTC_Manager_RegisterCache( manager, (FTC_CacheClass) clazz, + (FTC_Cache*) acache ); + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_UInt32 hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ) + { + FT_Error error; + + query->gindex = gindex; + + FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error ); + if ( !error ) + error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, anode ); + + return error; + } + + +/* END */ diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c index 769075d0a..52b9a841c 100644 --- a/src/cache/ftcmanag.c +++ b/src/cache/ftcmanag.c @@ -1,623 +1,645 @@ -/***************************************************************************/ -/* */ -/* ftcmanag.c */ -/* */ -/* FreeType Cache Manager (body). */ -/* */ -/* Copyright 2000-2001, 2002 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 -#include FT_CACHE_H -#include FT_CACHE_INTERNAL_MANAGER_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_SIZES_H - -#include "ftcerror.h" - - -#undef FT_COMPONENT -#define FT_COMPONENT trace_cache - -#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data ) - - - static FT_Error - ftc_scaler_lookup_size( FTC_Manager manager, - FTC_Scaler scaler, - FT_Size *asize ) - { - FT_Face face; - FT_Size size = NULL; - FT_Error error; - - error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); - if ( error ) goto Exit; - - error = FT_New_Size( face, &size ); - if ( error ) goto Exit; - - FT_Activate_Size( size ); - - if ( scaler->pixel ) - error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); - else - error = FT_Set_Char_Size( face, scaler->width, scaler->height, - scaler->x_res, scaler->y_res ); - if ( error ) - { - FT_Done_Size( size ); - size = NULL; - } - - Exit: - *asize = size; - return error; - } - - - typedef struct FTC_SizeNodeRec_ - { - FTC_MruNodeRec node; - FT_Size size; - FTC_ScalerRec scaler; - - } FTC_SizeNodeRec, *FTC_SizeNode; - - - FT_CALLBACK_DEF( void ) - ftc_size_node_done( FTC_SizeNode node ) - { - FT_Size size = node->size; - - if ( size ) - FT_Done_Size( size ); - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_size_node_compare( FTC_SizeNode node, - FTC_Scaler scaler ) - { - FTC_Scaler scaler0 = &node->scaler; - - return FTC_SCALER_COMPARE( scaler0, scaler ); - } - - - - FT_CALLBACK_DEF( FT_Error ) - ftc_size_node_init( FTC_SizeNode node, - FTC_Scaler scaler, - FTC_Manager manager ) - { - node->scaler = scaler[0]; - - return ftc_scaler_lookup_size( manager, scaler, &node->size ); - } - - - FT_CALLBACK_DEF( FT_Error ) - ftc_size_node_reset( FTC_SizeNode node, - FTC_Scaler scaler, - FTC_Manager manager ) - { - FT_Done_Size( node->size ); - - node->scaler = scaler[0]; - - return ftc_scaler_lookup_size( manager, scaler, &node->size ); - } - - - static const FTC_MruListClassRec ftc_size_list_class = - { - sizeof( FTC_SizeNodeRec ), - (FTC_MruNode_CompareFunc) ftc_size_node_compare, - (FTC_MruNode_InitFunc) ftc_size_node_init, - (FTC_MruNode_ResetFunc) ftc_size_node_reset, - (FTC_MruNode_DoneFunc) ftc_size_node_done - }; - - - /* helper function used by ftc_face_node_done */ - static FT_Bool - ftc_size_node_compare_faceid( FTC_SizeNode node, - FTC_FaceID face_id ) - { - return FT_BOOL( node->scaler.face_id == face_id ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_Manager_LookupSize( FTC_Manager manager, - FTC_Scaler scaler, - FT_Size *asize ) - { - FT_Error error; - FTC_SizeNode node; - - - if ( asize == NULL ) - return FTC_Err_Bad_Argument; - - *asize = NULL; - - if ( !manager ) - return FTC_Err_Invalid_Cache_Handle; - - error = FTC_MruList_Lookup( &manager->sizes, - scaler, - (FTC_MruNode*) &node ); - if ( !error ) - *asize = node->size; - - return error; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FACE MRU IMPLEMENTATION *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - typedef struct FTC_FaceNodeRec_ - { - FTC_MruNodeRec node; - FTC_FaceID face_id; - FT_Face face; - - } FTC_FaceNodeRec, *FTC_FaceNode; - - - - FT_CALLBACK_DEF( FT_Error ) - ftc_face_node_init( FTC_FaceNode node, - FTC_FaceID face_id, - FTC_Manager manager ) - { - FT_Error error; - - node->face_id = face_id; - - error = manager->request_face( face_id, - manager->library, - manager->request_data, - &node->face ); - if ( !error ) - { - /* destroy initial size object; it will be re-created later */ - if ( node->face->size ) - FT_Done_Size( node->face->size ); - } - return error; - } - - - FT_CALLBACK_DEF( void ) - ftc_face_node_done( FTC_FaceNode node, - FTC_Manager manager ) - { - /* we must begin by removing all scalers for the target face */ - /* from the manager's list */ - FTC_MruList_RemoveSelection( - & manager->sizes, - (FTC_MruNode_CompareFunc) ftc_size_node_compare_faceid, - node->face_id ); - - /* all right, we can discard the face now */ - FT_Done_Face( node->face ); - node->face = NULL; - node->face_id = NULL; - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_face_node_compare( FTC_FaceNode node, - FTC_FaceID face_id ) - { - return FT_BOOL( node->face_id == face_id ); - } - - - static const FTC_MruListClassRec ftc_face_list_class = - { - sizeof( FTC_FaceNodeRec), - - (FTC_MruNode_CompareFunc) ftc_face_node_compare, - (FTC_MruNode_InitFunc) ftc_face_node_init, - (FTC_MruNode_ResetFunc) NULL, - (FTC_MruNode_DoneFunc) ftc_face_node_done - }; - - - - /* documentation is in ftcache.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_Manager_LookupFace( FTC_Manager manager, - FTC_FaceID face_id, - FT_Face *aface ) - { - FT_Error error; - FTC_FaceNode node; - - - if ( aface == NULL ) - return FTC_Err_Bad_Argument; - - *aface = NULL; - - if ( !manager ) - return FTC_Err_Invalid_Cache_Handle; - - error = FTC_MruList_Lookup( &manager->faces, - face_id, - (FTC_MruNode*) &node ); - if ( !error ) - *aface = node->face; - - return error; - } - - - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE MANAGER ROUTINES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - /* documentation is in ftcache.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_Manager_New( FT_Library library, - FT_UInt max_faces, - FT_UInt max_sizes, - FT_ULong max_bytes, - FTC_Face_Requester requester, - FT_Pointer req_data, - FTC_Manager *amanager ) - { - FT_Error error; - FT_Memory memory; - FTC_Manager manager = 0; - - - if ( !library ) - return FTC_Err_Invalid_Library_Handle; - - memory = library->memory; - - if ( FT_NEW( manager ) ) - goto Exit; - - if ( max_faces == 0 ) - max_faces = FTC_MAX_FACES_DEFAULT; - - if ( max_sizes == 0 ) - max_sizes = FTC_MAX_SIZES_DEFAULT; - - if ( max_bytes == 0 ) - max_bytes = FTC_MAX_BYTES_DEFAULT; - - manager->library = library; - manager->memory = memory; - manager->max_weight = max_bytes; - - manager->request_face = requester; - manager->request_data = req_data; - - FTC_MruList_Init( &manager->faces, - &ftc_face_list_class, - max_faces, - manager, - memory ); - - FTC_MruList_Init( &manager->sizes, - &ftc_size_list_class, - max_sizes, - manager, - memory ); - - *amanager = manager; - - Exit: - return error; - } - - - /* documentation is in ftcache.h */ - - FT_EXPORT_DEF( void ) - FTC_Manager_Done( FTC_Manager manager ) - { - FT_Memory memory; - FT_UInt idx; - - - if ( !manager || !manager->library ) - return; - - memory = manager->memory; - - /* now discard all caches */ - for (idx = manager->num_caches; idx-- > 0; ) - { - FTC_Cache cache = manager->caches[idx]; - - if ( cache ) - { - cache->clazz.cache_done( cache ); - FT_FREE( cache ); - manager->caches[idx] = NULL; - } - } - manager->num_caches = 0; - - /* discard faces and sizes */ - FTC_MruList_Done( &manager->sizes ); - FTC_MruList_Done( &manager->faces ); - - manager->library = NULL; - manager->memory = NULL; - - FT_FREE( manager ); - } - - - /* documentation is in ftcache.h */ - - FT_EXPORT_DEF( void ) - FTC_Manager_Reset( FTC_Manager manager ) - { - if ( manager ) - { - FTC_MruList_Reset( &manager->sizes ); - FTC_MruList_Reset( &manager->faces ); - } - /* XXX: FIXME: flush the caches? */ - } - - -#ifdef FT_DEBUG_ERROR - - FT_EXPORT_DEF( void ) - FTC_Manager_Check( FTC_Manager manager ) - { - FTC_Node node, first; - - - first = manager->nodes_list; - - /* check node weights */ - if ( first ) - { - FT_ULong weight = 0; - - - node = first; - - do - { - FTC_Cache cache = manager->caches[ node->cache_index ]; - - if ( (FT_UInt)node->cache_index >= manager->num_caches ) - FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n", - node->cache_index )); - else - { - weight += cache->clazz.node_weight( node, cache ); - } - - node = FTC_NODE__NEXT(node); - - } while ( node != first ); - - if ( weight != manager->cur_weight ) - FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n", - manager->cur_weight, weight )); - } - - /* check circular list */ - if ( first ) - { - FT_UFast count = 0; - - - node = first; - do - { - count++; - node = FTC_NODE__NEXT(node); - - } while ( node != first ); - - if ( count != manager->num_nodes ) - FT_ERROR(( - "FTC_Manager_Check: invalid cache node count %d instead of %d\n", - manager->num_nodes, count )); - } - } - -#endif /* FT_DEBUG_ERROR */ - - - /* `Compress' the manager's data, i.e., get rid of old cache nodes */ - /* that are not referenced anymore in order to limit the total */ - /* memory used by the cache. */ - - /* documentation is in ftcmanag.h */ - - FT_EXPORT_DEF( void ) - FTC_Manager_Compress( FTC_Manager manager ) - { - FTC_Node node, first; - - - if ( !manager ) - return; - - first = manager->nodes_list; - -#ifdef FT_DEBUG_ERROR - FTC_Manager_Check( manager ); - - FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n", - manager->cur_weight, manager->max_weight, - manager->num_nodes )); -#endif - - if ( manager->cur_weight < manager->max_weight || first == NULL ) - return; - - /* go to last node - it's a circular list */ - node = FTC_NODE__PREV(first); - do - { - FTC_Node prev; - - - prev = ( node == first ) ? NULL : FTC_NODE__PREV(node); - - if ( node->ref_count <= 0 ) - ftc_node_destroy( node, manager ); - - node = prev; - - } while ( node && manager->cur_weight > manager->max_weight ); - } - - - /* documentation is in ftcmanag.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_Manager_RegisterCache( FTC_Manager manager, - FTC_CacheClass clazz, - FTC_Cache *acache ) - { - FT_Error error = FTC_Err_Invalid_Argument; - FTC_Cache cache = NULL; - - - if ( manager && clazz && acache ) - { - FT_Memory memory = manager->memory; - - if ( manager->num_caches >= FTC_MAX_CACHES ) - { - error = FTC_Err_Too_Many_Caches; - FT_ERROR(( "%s: too many registered caches\n", - "FTC_Manager_Register_Cache" )); - goto Exit; - } - - if ( !FT_ALLOC( cache, clazz->cache_size ) ) - { - cache->manager = manager; - cache->memory = memory; - cache->clazz = clazz[0]; - cache->org_class = clazz; - - /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ - /* IF IT IS NOT SET CORRECTLY */ - cache->index = manager->num_caches; - - error = clazz->cache_init( cache ); - if ( error ) - { - clazz->cache_done( cache ); - FT_FREE( cache ); - goto Exit; - } - - manager->caches[ manager->num_caches++ ] = cache; - } - } - - Exit: - *acache = cache; - return error; - } - - - FT_EXPORT_DEF( FT_UInt ) - FTC_Manager_FlushN( FTC_Manager manager, - FT_UInt count ) - { - FTC_Node first = manager->nodes_list; - FTC_Node node; - FT_UInt result; - - /* try to remove "count" nodes from the list */ - if ( first == NULL ) /* empty list! */ - return 0; - - /* go to last node - it's a circular list */ - node = FTC_NODE__PREV(first); - for ( result = 0; result < count; ) - { - FTC_Node prev = FTC_NODE__PREV(node); - - - /* don't touch locked nodes */ - if ( node->ref_count <= 0 ) - { - ftc_node_destroy( node, manager ); - result++; - } - - if ( prev == manager->nodes_list ) - break; - - node = prev; - } - return result; - } - - - FT_EXPORT_DEF( void ) - FTC_Manager_RemoveFaceID( FTC_Manager manager, - FTC_FaceID face_id ) - { - FT_UInt nn; - - /* this will remove all FTC_SizeNode that correspond to - * the face_id as well - */ - FTC_MruList_RemoveSelection( &manager->faces, NULL, face_id ); - - for ( nn = 0; nn < manager->num_caches; nn++ ) - FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); - } - - - /* documentation is in ftcmanag.h */ - - FT_EXPORT_DEF( void ) - FTC_Node_Unref( FTC_Node node, - FTC_Manager manager ) - { - if ( node && (FT_UInt)node->cache_index < manager->num_caches ) - node->ref_count--; - } - - -/* END */ +/***************************************************************************/ +/* */ +/* ftcmanag.c */ +/* */ +/* FreeType Cache Manager (body). */ +/* */ +/* Copyright 2000-2001, 2002 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 +#include FT_CACHE_H +#include FT_CACHE_INTERNAL_MANAGER_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H +#include FT_SIZES_H + +#include "ftcerror.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT trace_cache + +#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data ) + + + static FT_Error + ftc_scaler_lookup_size( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Face face; + FT_Size size = NULL; + FT_Error error; + + error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); + if ( error ) goto Exit; + + error = FT_New_Size( face, &size ); + if ( error ) goto Exit; + + FT_Activate_Size( size ); + + if ( scaler->pixel ) + error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); + else + error = FT_Set_Char_Size( face, scaler->width, scaler->height, + scaler->x_res, scaler->y_res ); + if ( error ) + { + FT_Done_Size( size ); + size = NULL; + } + + Exit: + *asize = size; + return error; + } + + + typedef struct FTC_SizeNodeRec_ + { + FTC_MruNodeRec node; + FT_Size size; + FTC_ScalerRec scaler; + + } FTC_SizeNodeRec, *FTC_SizeNode; + + + FT_CALLBACK_DEF( void ) + ftc_size_node_done( FTC_SizeNode node ) + { + FT_Size size = node->size; + + if ( size ) + FT_Done_Size( size ); + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_size_node_compare( FTC_SizeNode node, + FTC_Scaler scaler ) + { + FTC_Scaler scaler0 = &node->scaler; + + return FTC_SCALER_COMPARE( scaler0, scaler ); + } + + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_init( FTC_SizeNode node, + FTC_Scaler scaler, + FTC_Manager manager ) + { + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_reset( FTC_SizeNode node, + FTC_Scaler scaler, + FTC_Manager manager ) + { + FT_Done_Size( node->size ); + + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } + + + static const FTC_MruListClassRec ftc_size_list_class = + { + sizeof( FTC_SizeNodeRec ), + (FTC_MruNode_CompareFunc) ftc_size_node_compare, + (FTC_MruNode_InitFunc) ftc_size_node_init, + (FTC_MruNode_ResetFunc) ftc_size_node_reset, + (FTC_MruNode_DoneFunc) ftc_size_node_done + }; + + + /* helper function used by ftc_face_node_done */ + static FT_Bool + ftc_size_node_compare_faceid( FTC_SizeNode node, + FTC_FaceID face_id ) + { + return FT_BOOL( node->scaler.face_id == face_id ); + } + + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Error error; + FTC_SizeNode node; + + + if ( asize == NULL ) + return FTC_Err_Bad_Argument; + + *asize = NULL; + + if ( !manager ) + return FTC_Err_Invalid_Cache_Handle; + + /* we break encapsulation for the sake of speed */ + + error = 0; + FTC_MRULIST_LOOP( &manager->sizes, node ) + { + FTC_Scaler scaler0 = &node->scaler; + + if ( FTC_SCALER_COMPARE( scaler0, scaler ) ) + goto Found; + } + FTC_MRULIST_LOOP_END(); + + error = FTC_MruList_New( &manager->sizes, scaler, (FTC_MruNode*)&node ); + + Found: + if ( !error ) + *asize = node->size; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE MRU IMPLEMENTATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct FTC_FaceNodeRec_ + { + FTC_MruNodeRec node; + FTC_FaceID face_id; + FT_Face face; + + } FTC_FaceNodeRec, *FTC_FaceNode; + + + + FT_CALLBACK_DEF( FT_Error ) + ftc_face_node_init( FTC_FaceNode node, + FTC_FaceID face_id, + FTC_Manager manager ) + { + FT_Error error; + + node->face_id = face_id; + + error = manager->request_face( face_id, + manager->library, + manager->request_data, + &node->face ); + if ( !error ) + { + /* destroy initial size object; it will be re-created later */ + if ( node->face->size ) + FT_Done_Size( node->face->size ); + } + return error; + } + + + FT_CALLBACK_DEF( void ) + ftc_face_node_done( FTC_FaceNode node, + FTC_Manager manager ) + { + /* we must begin by removing all scalers for the target face */ + /* from the manager's list */ + FTC_MruList_RemoveSelection( + & manager->sizes, + (FTC_MruNode_CompareFunc) ftc_size_node_compare_faceid, + node->face_id ); + + /* all right, we can discard the face now */ + FT_Done_Face( node->face ); + node->face = NULL; + node->face_id = NULL; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_face_node_compare( FTC_FaceNode node, + FTC_FaceID face_id ) + { + return FT_BOOL( node->face_id == face_id ); + } + + + static const FTC_MruListClassRec ftc_face_list_class = + { + sizeof( FTC_FaceNodeRec), + + (FTC_MruNode_CompareFunc) ftc_face_node_compare, + (FTC_MruNode_InitFunc) ftc_face_node_init, + (FTC_MruNode_ResetFunc) NULL, + (FTC_MruNode_DoneFunc) ftc_face_node_done + }; + + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) + { + FT_Error error; + FTC_FaceNode node; + + + if ( aface == NULL ) + return FTC_Err_Bad_Argument; + + *aface = NULL; + + if ( !manager ) + return FTC_Err_Invalid_Cache_Handle; + + /* we break encapsulation for the sake of speed */ + + error = 0; + FTC_MRULIST_LOOP( &manager->faces, node ) + { + if ( node->face_id == face_id ) + goto Found; + } + FTC_MRULIST_LOOP_END(); + + error = FTC_MruList_New( &manager->faces, face_id, (FTC_MruNode*)&node ); + + Found: + if ( !error ) + *aface = node->face; + + return error; + } + + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ) + { + FT_Error error; + FT_Memory memory; + FTC_Manager manager = 0; + + + if ( !library ) + return FTC_Err_Invalid_Library_Handle; + + memory = library->memory; + + if ( FT_NEW( manager ) ) + goto Exit; + + if ( max_faces == 0 ) + max_faces = FTC_MAX_FACES_DEFAULT; + + if ( max_sizes == 0 ) + max_sizes = FTC_MAX_SIZES_DEFAULT; + + if ( max_bytes == 0 ) + max_bytes = FTC_MAX_BYTES_DEFAULT; + + manager->library = library; + manager->memory = memory; + manager->max_weight = max_bytes; + + manager->request_face = requester; + manager->request_data = req_data; + + FTC_MruList_Init( &manager->faces, + &ftc_face_list_class, + max_faces, + manager, + memory ); + + FTC_MruList_Init( &manager->sizes, + &ftc_size_list_class, + max_sizes, + manager, + memory ); + + *amanager = manager; + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Done( FTC_Manager manager ) + { + FT_Memory memory; + FT_UInt idx; + + + if ( !manager || !manager->library ) + return; + + memory = manager->memory; + + /* now discard all caches */ + for (idx = manager->num_caches; idx-- > 0; ) + { + FTC_Cache cache = manager->caches[idx]; + + if ( cache ) + { + cache->clazz.cache_done( cache ); + FT_FREE( cache ); + manager->caches[idx] = NULL; + } + } + manager->num_caches = 0; + + /* discard faces and sizes */ + FTC_MruList_Done( &manager->sizes ); + FTC_MruList_Done( &manager->faces ); + + manager->library = NULL; + manager->memory = NULL; + + FT_FREE( manager ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Reset( FTC_Manager manager ) + { + if ( manager ) + { + FTC_MruList_Reset( &manager->sizes ); + FTC_MruList_Reset( &manager->faces ); + } + /* XXX: FIXME: flush the caches? */ + } + + +#ifdef FT_DEBUG_ERROR + + FT_EXPORT_DEF( void ) + FTC_Manager_Check( FTC_Manager manager ) + { + FTC_Node node, first; + + + first = manager->nodes_list; + + /* check node weights */ + if ( first ) + { + FT_ULong weight = 0; + + + node = first; + + do + { + FTC_Cache cache = manager->caches[ node->cache_index ]; + + if ( (FT_UInt)node->cache_index >= manager->num_caches ) + FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n", + node->cache_index )); + else + { + weight += cache->clazz.node_weight( node, cache ); + } + + node = FTC_NODE__NEXT(node); + + } while ( node != first ); + + if ( weight != manager->cur_weight ) + FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n", + manager->cur_weight, weight )); + } + + /* check circular list */ + if ( first ) + { + FT_UFast count = 0; + + + node = first; + do + { + count++; + node = FTC_NODE__NEXT(node); + + } while ( node != first ); + + if ( count != manager->num_nodes ) + FT_ERROR(( + "FTC_Manager_Check: invalid cache node count %d instead of %d\n", + manager->num_nodes, count )); + } + } + +#endif /* FT_DEBUG_ERROR */ + + + /* `Compress' the manager's data, i.e., get rid of old cache nodes */ + /* that are not referenced anymore in order to limit the total */ + /* memory used by the cache. */ + + /* documentation is in ftcmanag.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Compress( FTC_Manager manager ) + { + FTC_Node node, first; + + + if ( !manager ) + return; + + first = manager->nodes_list; + +#ifdef FT_DEBUG_ERROR + FTC_Manager_Check( manager ); + + FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n", + manager->cur_weight, manager->max_weight, + manager->num_nodes )); +#endif + + if ( manager->cur_weight < manager->max_weight || first == NULL ) + return; + + /* go to last node - it's a circular list */ + node = FTC_NODE__PREV(first); + do + { + FTC_Node prev; + + + prev = ( node == first ) ? NULL : FTC_NODE__PREV(node); + + if ( node->ref_count <= 0 ) + ftc_node_destroy( node, manager ); + + node = prev; + + } while ( node && manager->cur_weight > manager->max_weight ); + } + + + /* documentation is in ftcmanag.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ) + { + FT_Error error = FTC_Err_Invalid_Argument; + FTC_Cache cache = NULL; + + + if ( manager && clazz && acache ) + { + FT_Memory memory = manager->memory; + + if ( manager->num_caches >= FTC_MAX_CACHES ) + { + error = FTC_Err_Too_Many_Caches; + FT_ERROR(( "%s: too many registered caches\n", + "FTC_Manager_Register_Cache" )); + goto Exit; + } + + if ( !FT_ALLOC( cache, clazz->cache_size ) ) + { + cache->manager = manager; + cache->memory = memory; + cache->clazz = clazz[0]; + cache->org_class = clazz; + + /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ + /* IF IT IS NOT SET CORRECTLY */ + cache->index = manager->num_caches; + + error = clazz->cache_init( cache ); + if ( error ) + { + clazz->cache_done( cache ); + FT_FREE( cache ); + goto Exit; + } + + manager->caches[ manager->num_caches++ ] = cache; + } + } + + Exit: + *acache = cache; + return error; + } + + + FT_EXPORT_DEF( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ) + { + FTC_Node first = manager->nodes_list; + FTC_Node node; + FT_UInt result; + + /* try to remove "count" nodes from the list */ + if ( first == NULL ) /* empty list! */ + return 0; + + /* go to last node - it's a circular list */ + node = FTC_NODE__PREV(first); + for ( result = 0; result < count; ) + { + FTC_Node prev = FTC_NODE__PREV(node); + + + /* don't touch locked nodes */ + if ( node->ref_count <= 0 ) + { + ftc_node_destroy( node, manager ); + result++; + } + + if ( prev == manager->nodes_list ) + break; + + node = prev; + } + return result; + } + + + FT_EXPORT_DEF( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ) + { + FT_UInt nn; + + /* this will remove all FTC_SizeNode that correspond to + * the face_id as well + */ + FTC_MruList_RemoveSelection( &manager->faces, NULL, face_id ); + + for ( nn = 0; nn < manager->num_caches; nn++ ) + FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); + } + + + /* documentation is in ftcmanag.h */ + + FT_EXPORT_DEF( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ) + { + if ( node && (FT_UInt)node->cache_index < manager->num_caches ) + node->ref_count--; + } + + +/* END */