ref: 7fa30ee8793030afc912d84fdf8df9a843498e02
dir: /src/cache/ftccache.h/
/***************************************************************************/ /* */ /* ftccache.h */ /* */ /* FreeType internal cache interface (specification). */ /* */ /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007 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 "ftcmru.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 ) #ifdef FT_CONFIG_OPTION_OLD_INTERNALS FT_BASE( void ) ftc_node_destroy( FTC_Node node, FTC_Manager manager ); #endif /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** 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_LOCAL( FT_Error ) FTC_Cache_Init( FTC_Cache cache ); /* default cache finalizer */ FT_LOCAL( 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. */ #ifndef FTC_INLINE FT_LOCAL( FT_Error ) FTC_Cache_Lookup( FTC_Cache cache, FT_UInt32 hash, FT_Pointer query, FTC_Node *anode ); #endif FT_LOCAL( 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 final 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_LOCAL( void ) FTC_Cache_RemoveFaceID( FTC_Cache cache, FTC_FaceID face_id ); #ifdef FTC_INLINE #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; \ node = NULL; \ _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; \ void* _nl = &_manager->nodes_list; \ \ \ if ( _node != _manager->nodes_list ) \ FTC_MruNode_Up( (FTC_MruNode*)_nl, \ (FTC_MruNode)_node ); \ } \ goto _Ok; \ \ _NewNode: \ error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ \ _Ok: \ _pnode = (FTC_Node*)(void*)&(node); \ *_pnode = _node; \ FT_END_STMNT #else /* !FTC_INLINE */ #define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ FT_BEGIN_STMNT \ error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, \ (FTC_Node*)&(node) ); \ FT_END_STMNT #endif /* !FTC_INLINE */ /* * This macro, together with FTC_CACHE_TRYLOOP_END, defines a retry * loop to flush the cache repeatedly in case of memory overflows. * * It is used when creating a new cache node, or within a lookup * that needs to allocate data (e.g., the sbit cache lookup). * * Example: * * { * FTC_CACHE_TRYLOOP( cache ) * error = load_data( ... ); * FTC_CACHE_TRYLOOP_END() * } * */ #define FTC_CACHE_TRYLOOP( cache ) \ { \ FTC_Manager _try_manager = FTC_CACHE( cache )->manager; \ FT_UInt _try_count = 4; \ \ \ for (;;) \ { \ FT_UInt _try_done; #define FTC_CACHE_TRYLOOP_END() \ if ( !error || error != FT_Err_Out_Of_Memory ) \ break; \ \ _try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \ if ( _try_done == 0 ) \ break; \ \ if ( _try_done == _try_count ) \ { \ _try_count *= 2; \ if ( _try_count < _try_done || \ _try_count > _try_manager->num_nodes ) \ _try_count = _try_manager->num_nodes; \ } \ } \ } /* */ FT_END_HEADER #endif /* __FTCCACHE_H__ */ /* END */