1b695849c97766bc54b13e31ef5e9352cb346998
[framework/graphics/freetype.git] / src / cache / ftccache.h
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftccache.h                                                             */
4 /*                                                                         */
5 /*    FreeType internal cache interface (specification).                   */
6 /*                                                                         */
7 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 by */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #ifndef __FTCCACHE_H__
20 #define __FTCCACHE_H__
21
22
23 #include "ftcmru.h"
24
25 FT_BEGIN_HEADER
26
27   /* handle to cache object */
28   typedef struct FTC_CacheRec_*  FTC_Cache;
29
30   /* handle to cache class */
31   typedef const struct FTC_CacheClassRec_*  FTC_CacheClass;
32
33
34   /*************************************************************************/
35   /*************************************************************************/
36   /*****                                                               *****/
37   /*****                   CACHE NODE DEFINITIONS                      *****/
38   /*****                                                               *****/
39   /*************************************************************************/
40   /*************************************************************************/
41
42   /*************************************************************************/
43   /*                                                                       */
44   /* Each cache controls one or more cache nodes.  Each node is part of    */
45   /* the global_lru list of the manager.  Its `data' field however is used */
46   /* as a reference count for now.                                         */
47   /*                                                                       */
48   /* A node can be anything, depending on the type of information held by  */
49   /* the cache.  It can be an individual glyph image, a set of bitmaps     */
50   /* glyphs for a given size, some metrics, etc.                           */
51   /*                                                                       */
52   /*************************************************************************/
53
54   /* structure size should be 20 bytes on 32-bits machines */
55   typedef struct  FTC_NodeRec_
56   {
57     FTC_MruNodeRec  mru;          /* circular mru list pointer           */
58     FTC_Node        link;         /* used for hashing                    */
59     FT_UInt32       hash;         /* used for hashing too                */
60     FT_UShort       cache_index;  /* index of cache the node belongs to  */
61     FT_Short        ref_count;    /* reference count for this node       */
62
63   } FTC_NodeRec;
64
65
66 #define FTC_NODE( x )    ( (FTC_Node)(x) )
67 #define FTC_NODE_P( x )  ( (FTC_Node*)(x) )
68
69 #define FTC_NODE__NEXT( x )  FTC_NODE( (x)->mru.next )
70 #define FTC_NODE__PREV( x )  FTC_NODE( (x)->mru.prev )
71
72
73 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
74   FT_BASE( void )
75   ftc_node_destroy( FTC_Node     node,
76                     FTC_Manager  manager );
77 #endif
78
79
80   /*************************************************************************/
81   /*************************************************************************/
82   /*****                                                               *****/
83   /*****                       CACHE DEFINITIONS                       *****/
84   /*****                                                               *****/
85   /*************************************************************************/
86   /*************************************************************************/
87
88   /* initialize a new cache node */
89   typedef FT_Error
90   (*FTC_Node_NewFunc)( FTC_Node    *pnode,
91                        FT_Pointer   query,
92                        FTC_Cache    cache );
93
94   typedef FT_Offset
95   (*FTC_Node_WeightFunc)( FTC_Node   node,
96                           FTC_Cache  cache );
97
98   /* compare a node to a given key pair */
99   typedef FT_Bool
100   (*FTC_Node_CompareFunc)( FTC_Node    node,
101                            FT_Pointer  key,
102                            FTC_Cache   cache );
103
104
105   typedef void
106   (*FTC_Node_FreeFunc)( FTC_Node   node,
107                         FTC_Cache  cache );
108
109   typedef FT_Error
110   (*FTC_Cache_InitFunc)( FTC_Cache  cache );
111
112   typedef void
113   (*FTC_Cache_DoneFunc)( FTC_Cache  cache );
114
115
116   typedef struct  FTC_CacheClassRec_
117   {
118     FTC_Node_NewFunc      node_new;
119     FTC_Node_WeightFunc   node_weight;
120     FTC_Node_CompareFunc  node_compare;
121     FTC_Node_CompareFunc  node_remove_faceid;
122     FTC_Node_FreeFunc     node_free;
123
124     FT_Offset             cache_size;
125     FTC_Cache_InitFunc    cache_init;
126     FTC_Cache_DoneFunc    cache_done;
127
128   } FTC_CacheClassRec;
129
130
131   /* each cache really implements a dynamic hash table to manage its nodes */
132   typedef struct  FTC_CacheRec_
133   {
134     FT_UFast           p;
135     FT_UFast           mask;
136     FT_Long            slack;
137     FTC_Node*          buckets;
138
139     FTC_CacheClassRec  clazz;       /* local copy, for speed  */
140
141     FTC_Manager        manager;
142     FT_Memory          memory;
143     FT_UInt            index;       /* in manager's table     */
144
145     FTC_CacheClass     org_class;   /* original class pointer */
146
147   } FTC_CacheRec;
148
149
150 #define FTC_CACHE( x )    ( (FTC_Cache)(x) )
151 #define FTC_CACHE_P( x )  ( (FTC_Cache*)(x) )
152
153
154   /* default cache initialize */
155   FT_LOCAL( FT_Error )
156   FTC_Cache_Init( FTC_Cache  cache );
157
158   /* default cache finalizer */
159   FT_LOCAL( void )
160   FTC_Cache_Done( FTC_Cache  cache );
161
162   /* Call this function to lookup the cache.  If no corresponding
163    * node is found, a new one is automatically created.  This function
164    * is capable of flushing the cache adequately to make room for the
165    * new cache object.
166    */
167
168 #ifndef FTC_INLINE
169   FT_LOCAL( FT_Error )
170   FTC_Cache_Lookup( FTC_Cache   cache,
171                     FT_UInt32   hash,
172                     FT_Pointer  query,
173                     FTC_Node   *anode );
174 #endif
175
176   FT_LOCAL( FT_Error )
177   FTC_Cache_NewNode( FTC_Cache   cache,
178                      FT_UInt32   hash,
179                      FT_Pointer  query,
180                      FTC_Node   *anode );
181
182   /* Remove all nodes that relate to a given face_id.  This is useful
183    * when un-installing fonts.  Note that if a cache node relates to
184    * the face_id, but is locked (i.e., has `ref_count > 0'), the node
185    * will _not_ be destroyed, but its internal face_id reference will
186    * be modified.
187    *
188    * The final result will be that the node will never come back
189    * in further lookup requests, and will be flushed on demand from
190    * the cache normally when its reference count reaches 0.
191    */
192   FT_LOCAL( void )
193   FTC_Cache_RemoveFaceID( FTC_Cache   cache,
194                           FTC_FaceID  face_id );
195
196
197 #ifdef FTC_INLINE
198
199 #define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \
200   FT_BEGIN_STMNT                                                         \
201     FTC_Node             *_bucket, *_pnode, _node;                       \
202     FTC_Cache             _cache   = FTC_CACHE(cache);                   \
203     FT_UInt32             _hash    = (FT_UInt32)(hash);                  \
204     FTC_Node_CompareFunc  _nodcomp = (FTC_Node_CompareFunc)(nodecmp);    \
205     FT_UFast              _idx;                                          \
206                                                                          \
207                                                                          \
208     error = FTC_Err_Ok;                                                  \
209     node  = NULL;                                                        \
210     _idx  = _hash & _cache->mask;                                        \
211     if ( _idx < _cache->p )                                              \
212       _idx = _hash & ( _cache->mask*2 + 1 );                             \
213                                                                          \
214     _bucket = _pnode = _cache->buckets + _idx;                           \
215     for (;;)                                                             \
216     {                                                                    \
217       _node = *_pnode;                                                   \
218       if ( _node == NULL )                                               \
219         goto _NewNode;                                                   \
220                                                                          \
221       if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) )    \
222         break;                                                           \
223                                                                          \
224       _pnode = &_node->link;                                             \
225     }                                                                    \
226                                                                          \
227     if ( _node != *_bucket )                                             \
228     {                                                                    \
229       *_pnode     = _node->link;                                         \
230       _node->link = *_bucket;                                            \
231       *_bucket    = _node;                                               \
232     }                                                                    \
233                                                                          \
234     {                                                                    \
235       FTC_Manager  _manager = _cache->manager;                           \
236       void*        _nl      = &_manager->nodes_list;                     \
237                                                                          \
238                                                                          \
239       if ( _node != _manager->nodes_list )                               \
240         FTC_MruNode_Up( (FTC_MruNode*)_nl,                               \
241                         (FTC_MruNode)_node );                            \
242     }                                                                    \
243     goto _Ok;                                                            \
244                                                                          \
245   _NewNode:                                                              \
246     error = FTC_Cache_NewNode( _cache, _hash, query, &_node );           \
247                                                                          \
248   _Ok:                                                                   \
249     node = _node;                                                        \
250   FT_END_STMNT
251
252 #else /* !FTC_INLINE */
253
254 #define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \
255   FT_BEGIN_STMNT                                                         \
256     error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query,           \
257                               (FTC_Node*)&(node) );                      \
258   FT_END_STMNT
259
260 #endif /* !FTC_INLINE */
261
262
263   /*
264    * This macro, together with FTC_CACHE_TRYLOOP_END, defines a retry
265    * loop to flush the cache repeatedly in case of memory overflows.
266    *
267    * It is used when creating a new cache node, or within a lookup
268    * that needs to allocate data (e.g., the sbit cache lookup).
269    *
270    * Example:
271    *
272    *   {
273    *     FTC_CACHE_TRYLOOP( cache )
274    *       error = load_data( ... );
275    *     FTC_CACHE_TRYLOOP_END()
276    *   }
277    *
278    */
279 #define FTC_CACHE_TRYLOOP( cache )                           \
280   {                                                          \
281     FTC_Manager  _try_manager = FTC_CACHE( cache )->manager; \
282     FT_UInt      _try_count   = 4;                           \
283                                                              \
284                                                              \
285     for (;;)                                                 \
286     {                                                        \
287       FT_UInt  _try_done;
288
289
290 #define FTC_CACHE_TRYLOOP_END()                                   \
291       if ( !error || error != FTC_Err_Out_Of_Memory )             \
292         break;                                                    \
293                                                                   \
294       _try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \
295       if ( _try_done == 0 )                                       \
296         break;                                                    \
297                                                                   \
298       if ( _try_done == _try_count )                              \
299       {                                                           \
300         _try_count *= 2;                                          \
301         if ( _try_count < _try_done              ||               \
302             _try_count > _try_manager->num_nodes )                \
303           _try_count = _try_manager->num_nodes;                   \
304       }                                                           \
305     }                                                             \
306   }
307
308  /* */
309
310 FT_END_HEADER
311
312
313 #endif /* __FTCCACHE_H__ */
314
315
316 /* END */